/* 
**
** Service Control Management Entity.
**
*/

#include    "../include/includes.h"
#include    "../include/ppsm.h"
#include    "../include/ramdata.h"
#include    "../include/ppsinf.h"
#include    "../include/message.h"
#include    "../include/iofunc.h"
#include    "../include/crypt.h"
#include    "../include/mfunc.h"
#include    "../include/version.h"
#include    "../include/ppsoid.h"
#include    "../include/config.h"
#include    "../include/param.h"
#include    "../include/report.h"
#include    "../include/precard.h"
#include    "../include/pps_public.h"
#include	 "../include/mfunc.h"

#include	"../include/callingCard.h"
#include 	"../include/gprs.h"

#include    "../include/plat_inc.h"
#include    "../../../../plat/scf/src/include/scfmsg.h"
#include    "../../../../plat/scf/src/include/scfpub.h"
#include    "../../../../plat/public/src/include/license_id.h"

#include    "../../../../plat/diameter/include/gy_message.h"
#include    "../../../../plat/tcp/src/include/tcp_if.h"
#include    <pthread.h>
#ifdef OCS_USE_REDIS_DB
#include "../include/pps_redis.h"
#endif

// fix multiple definition====================================
_debug_mib  debugmib;
//

/*------------------------------------------------*/
extern int	logMsgFlag;
extern char	logMsisdn[18];
extern int	pps_peer_hb_flag ;
/*------------------------------------------------*/
#define	CONVERT_16DIGIT_CARD	0
/*------------------------------------------------*/


static int	smshm_id;
static int	ramshm_id;
static int	blf_shmid;
_state_machine	*smshm_ptr;
_tariff_private	*blf_shmp;
_ram_data	*ramshm_ptr;
char		prog_name[12];
int		ipsem_id;
int		hbsem_id;
int		first_flag=TRUE;
int		subSystemID;
u_char		alarm_code[2]={0x00,0x00};
u_char		version_id[3];
u_char		peer_version_id[3];

int		csta_now_instance = 0, csta_old_instance = 0;
int		cdr_head_ptr = 0, cdr_tail_ptr = 0; //0x7FFFFFFF;
_load_file	load_file; /* 0,1=user data/tariff data */
static	u_char	chargeID = 0; 
u_long		primary_data_server = 0x00;
u_long		second_data_server = 0x00;
struct		timeval tvnow;
int		time_now[7];

extern	PPSParamStruct	ppsParam;

u_char		stopPeriodicSync = 0;

u_long		LOCAL_IP;
extern u_long	peer_server_ip;
u_short		debug_messages=0;
char		serialNumber[9]="";						
int		stopReceivePeriodicSyncFlag = 0;
int		totalPeriodSyncPackets = 0;

static int ramInitFlag = 0;
char masterFlag = 0;
int data_source = _SRC_NO_SRC;
int systemCapability,msisdn_head_num=0;
char stoprunning_flag = 0;
/* second server, if 1 primary server determined by Sync module */

extern u_char	uploadUserStatus[6]; /* status for upload */
extern u_char	uploadPrecardStatus[6];
extern DWORD	PPS_OID_THIRDPARTY[];
extern char	peer_server_in_init;

unsigned short send_activitytest_timer = SEND_ACTIVITYTEST_PERIODIC;
pthread_mutex_t pps_mtx = PTHREAD_MUTEX_INITIALIZER;
int                    realSyncTcpSap = -1;
int                    realSyncTcpPid = -1;

#ifdef OCS_USE_REDIS_DB
extern int RedisInit(u32 localip, u32 peerip);
#endif

/*------------------------------------------------*/
extern int ppsDebugCapMsg();
extern int decode_initialDP();
extern int decode_initialDPSMS();
extern int IsMNPCalledNumber(char *number);
extern char* GetCapError(); 
extern int pps_refund_data_volume(_state_data *shmp);
/*------------------------------------------------*/
extern int findTariffIDByAPNName(char *apn_name);
int SendMNP_ATI(unsigned short portid);
int SetIndexMessAlamFlag();
int  pps_ro_call_wait_first_cca(u16 port);
int	pps_ro_adaptor_call_init(u16 port);
int	CheckCRDRingBackSericeKey(int serviceKey);
int	pps_ro_voice_process(u_short pid);
int pps_get_ro_voice_quota(_state_data *shmp);
void	SaveSubsData();
extern int resetAccessTimeout(_state_data *shmp);
/*------------------------------------------------*/
extern int ImportBillSMS(FILE *fp);
extern int SendScfTcEND();
extern int UpdateBalanceForRecharge();
extern int ImportGprsTariff(FILE *fp);
extern int ImportVasMmsSendTariff(FILE *fp);
extern int ImportVasMmsRetrieveTariff(FILE *fp);
extern int ImportVasEmailTariff(FILE *fp);
extern void freeServiceDaysDeduct(u_short head,u_short tail);
extern int SendAccountInfoBySMPP();
extern int log_warning();
extern int SendScfUError();
extern int sendConnectForCRDService();
extern int CheckWetherRoamingUser();
extern int GetAccountZoneIDByLocationInfo();
extern int CheckWetherFavoriteNumber();
extern int GetAccountMTZoneID();
extern int CheckWetherRoamingMTUser();
extern int GetAccountMTZoneIDByLocationInfo();
extern int pps_send_map_open();
extern int pps_send_mnp_ati();
extern int pps_mt_play_voice_flag();
extern int pps_get_adaptor_vcs_flag();
extern int pps_get_ocs_proxy_nai_flag();
extern int gx_release_port_for_timerout(unsigned short pid);
extern int SendConnectForVMSService();
extern int SendPreWarningRequestBCSMEvent();
extern int CheckSeriveIdentification();
extern int CheckSRFResource();
extern int SendEstablishTemporaryConnection();
extern int xap_roaming_rule_get_routing_home_flag(char *vlr_number);
extern int pps_get_answer_timer_out();
extern int SendAccountBalanceBySrf();
extern int CheckPINValidity();
extern int GetAccountFavoriteNumberCounter();
extern int StoreAccountFavoriteNumber();
extern int IncreaseFavoriteNumberChangeCounter();
extern int BillingFavoriteNumberChange();
extern int GetAccountFavoriteNumber();
extern int SendFavPromptAndCollectUserInfo();
extern int UpdateAccountDefaultLanguageType();
extern int UpdateAccountPIN();
extern int ppsMapState();
extern int CreatePPSSubsIndexTable();
extern int CreateQuenceList();
extern int ReadSyncMessageForInit();
extern int ppsDebugRt();
extern int srfActivityMonitor();
extern void ppsCheckParameterAutoSaveFlag();
extern int pps_send_routing_home_prn(u_short portid);
extern int GetMSISDNOfSSN ( BYTE ssn, BYTE * msisdn );
extern int sendSMSRechargeNegativeResponse(_state_data *shmp, u_char error_code);
extern	int initSNMP();
extern 	void init_radius_gsn();
extern 	int vasProcess(u_short portid);
extern int gx_send_ccr_from_client(struct gy_msg *gy_ptr);
extern BOOL isAccessTimeout(_state_data 		*shmp);
extern long pps_get_quota_per_request();
extern int allocate_ps_data_volume_quota(_state_data 	*shmp, char *failReason);
extern int tcpRealSyncProc(WORD usr_port, BYTE *pdata, WORD datalen, DWORD db_type, DWORD instance, DWORD ocode);
extern int gx_handle_cca_from_server(struct gy_msg *gy_ptr);
extern int pps_get_gy_postpaid_flag();
extern int ocs_get_gy_report_data_metohd();
extern int callingCardProc(u_short portid);
extern int pps_charge_postpaid_data(_state_data *shmp, long consumed_volume, long *uncharged_volume);
void 	SaveTariffPlan();
extern int ocs_get_threshold_supported();
extern int pps_get_gprs_inactive_timer(_state_data *shmp);
extern int pps_get_control_state();
extern int pps_get_gy_delay_timer(int flag);
extern int pps_get_max_call_duration_in_second();
extern int pps_gprs_process(u_short portid);
extern void SyncMessageProc();
extern int pps_rest_recv_proxy();

/*------------------------------------------------*/
char callTypeName[13][64]=
{
"","",
"Normal MO call",
"Normal MT call",
"Normal MF call",
"Normal MO SMS",
"Call hotline",
"Inquiry account",
"Scratch card recharge"
"Credit card recharge",
"Third party recharge",
"One time input recharge",
"Call distribution"
};

#define	CHECK_MSISDN_LOG_LEVEL() do {\
	if(logMsgFlag & 0x08) \
	{ \
		if(strstr((char *)shmp->caller_info.number,logMsisdn)){ \
			shmp->process_info.logMsisdn = 0x01;   \
		}  \
		if(strstr((char *)shmp->called_info.number,logMsisdn)){  \
			shmp->process_info.logMsisdn = 0x01;\
		} \
	} \
}while(0)	
/*------------------------------------------------*/


void
SetLoadFileFlag(int dataID)
{   
   char  timebuf[64]={""};
   FILE  *fpTmp = NULL;

    PutLogFunID("SetLoadFileFlag");

   switch(dataID)
   {
     case 0x01: /* user data */
	   load_file.log_fp[_FILE_ID_USER_DATA]  = fopen(USER_LOG_FILE,"w");
	   load_file.fp[_FILE_ID_USER_DATA] = fopen(USER_FILE_NAME,"rb");

	   uploadUserStatus[3] = 0x00;
	   uploadUserStatus[4] = 0x00;
	   uploadUserStatus[5] = 0x00;
	   
	   if(load_file.log_fp[_FILE_ID_USER_DATA] != NULL)
	   {
	   fprintf(load_file.log_fp[_FILE_ID_USER_DATA],"# PPS  User Data Loading Log File\n\n" );
   	   getdate(timebuf);
       fprintf(load_file.log_fp[_FILE_ID_USER_DATA],"Time created:      %s ",timebuf);
	   GetTimeHMS(timebuf);
	   fprintf(load_file.log_fp[_FILE_ID_USER_DATA],"%s\n",timebuf);
	   fprintf(load_file.log_fp[_FILE_ID_USER_DATA],"Total record:      %d\n",
	     uploadUserStatus[0]*65536 + \
		 uploadUserStatus[1]*256 + uploadUserStatus[2]);
       }
       if(load_file.fp[_FILE_ID_USER_DATA] == NULL)
	   {
	     load_file.flag[_FILE_ID_USER_DATA] = 0x00;
         ppsParam.fileOperation.uploadUserData = 0x04; 
#if DEBUG
 if(logMsgFlag & 0x01)
  DebugMsg(debugmib.display.asciiOut,
  "Load user data file  failed! --- No file named %s found.",USER_FILE_NAME);
#endif
         fprintf(load_file.log_fp[_FILE_ID_USER_DATA],
		 "\nError:\n    Load user data file  failed! --- No file named %s found.", USER_FILE_NAME);
	     fclose(load_file.log_fp[_FILE_ID_USER_DATA]);
	   }
	   else
	   {
         ppsParam.fileOperation.uploadUserData = 0x02; /* being importing */
#if DEBUG
if(logMsgFlag & 0x04)
  DebugMsg(debugmib.display.asciiOut,"Start to read user data file(%s)...",USER_FILE_NAME);
#endif		 
         fprintf(load_file.log_fp[_FILE_ID_USER_DATA],
		 "\nStart to read user data from %s\n",USER_FILE_NAME);
		 load_file.flag[_FILE_ID_USER_DATA] = 0x01;
	   }
	 break;
	 case 0x02: /* prepaid card */
	   load_file.fp[_FILE_ID_PREPAID_CARD] = fopen(PREPAID_CARD_FILE,"r");
	   load_file.log_fp[_FILE_ID_PREPAID_CARD]  = fopen(PREPAID_CARD_LOG_FILE,"w");
	   if(load_file.fp[_FILE_ID_PREPAID_CARD] == NULL )
	   {
	      load_file.flag[_FILE_ID_PREPAID_CARD] = 0x00;
		  ppsParam.fileOperation.uploadPrepaidCard = 0x04; /* failed */
         fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
		 "\nError:\n    Load prepaid card file  failed! --- No file named %s found.", PREPAID_CARD_FILE);
	     fclose(load_file.log_fp[_FILE_ID_PREPAID_CARD]);

	      return ;
	   }
	   load_file.flag[_FILE_ID_PREPAID_CARD] = 0x01;
	   fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],"# PPS  Prepaid Card Loading Log File\n\n" );
   	   getdate(timebuf);
       fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],"Time created:      %s ",timebuf);
	   GetTimeHMS(timebuf);
	   fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],"%s\n",timebuf);
	   fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],"Total record:      %d\n",
	  
	   uploadPrecardStatus[0]*65536 + \
	   uploadPrecardStatus[1]*256 + uploadPrecardStatus[2]);

       ppsParam.fileOperation.uploadPrepaidCard = 0x02; /* being importing	   */
#if DEBUG
  DebugMsg(debugmib.display.asciiOut,"Start to read prepaid card data file(%s)...",PREPAID_CARD_FILE);
#endif		 
       fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
		 "\nStart to read prepaid card data from %s\n",PREPAID_CARD_FILE);


	 break;
 	 case 0x03:/* tariff data */
	   load_file.fp[_FILE_ID_COMM_TARIFF] = fopen(COMM_TARIFF_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_COMM_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_COMM_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
		  
	      //return ;
	   }
	   else
	   	       load_file.flag[_FILE_ID_COMM_TARIFF] = 0x01;

	   load_file.fp[_FILE_ID_RENT_TARIFF] = fopen(RENT_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_RENT_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_RENT_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	     // return ;
	   }
	   else
	   	load_file.flag[_FILE_ID_RENT_TARIFF] = 0x01;

	   load_file.fp[_FILE_ID_BILL_TARIFF] = fopen(TARIFF_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_BILL_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_BILL_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
	       load_file.flag[_FILE_ID_BILL_TARIFF] = 0x01;
	   	
	   load_file.fp[_FILE_ID_MT_TARIFF] = fopen(MT_TARIFF_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_MT_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_MT_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
		load_file.flag[_FILE_ID_MT_TARIFF] = 0x01;
		   	
	   load_file.fp[_FILE_ID_DISCOUNT] = fopen(DISCOUNT_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_DISCOUNT] == NULL )
	   {
	      load_file.flag[_FILE_ID_DISCOUNT] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
   	          load_file.flag[_FILE_ID_DISCOUNT] = 0x01;

	   load_file.fp[_FILE_ID_HOLIDY] = fopen(HOLIDAY_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_HOLIDY] == NULL )
	   {
	      load_file.flag[_FILE_ID_HOLIDY] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
		   load_file.flag[_FILE_ID_HOLIDY] = 0x01;
	   	
	   load_file.fp[_FILE_ID_BILL_SMS] = fopen(BILL_SMS_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_BILL_SMS] == NULL )
	   {
	      load_file.flag[_FILE_ID_BILL_SMS] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
		   load_file.flag[_FILE_ID_BILL_SMS] = 0x01;
	   	
	   load_file.fp[_FILE_ID_GPRS_TARIFF] = fopen(BILL_GPRS_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_GPRS_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_GPRS_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
		   load_file.flag[_FILE_ID_GPRS_TARIFF] = 0x01;
	   	
	   load_file.fp[_FILE_ID_VAS_MMS_SEND_TARIFF] = fopen(BILL_VAS_MMS_SEND_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_VAS_MMS_SEND_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_VAS_MMS_SEND_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
		   load_file.flag[_FILE_ID_VAS_MMS_SEND_TARIFF] = 0x01;
	   	
	   load_file.fp[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF] = fopen(BILL_VAS_MMS_RETRIEVE_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else
		   load_file.flag[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF] = 0x01;
	   	
	   load_file.fp[_FILE_ID_VAS_MMS_EMAIL_TARIFF] = fopen(BILL_VAS_MMS_EMAIL_FILE_NAME,"r");
	   if(load_file.fp[_FILE_ID_VAS_MMS_EMAIL_TARIFF] == NULL )
	   {
	      load_file.flag[_FILE_ID_VAS_MMS_EMAIL_TARIFF] = 0x00;
		  ppsParam.fileOperation.uploadTariffPlan = 0x04; /* failed */
	      //return ;
	   }
	   else   
		load_file.flag[_FILE_ID_VAS_MMS_EMAIL_TARIFF] = 0x01;
		
	   ppsParam.fileOperation.uploadTariffPlan = 0x03; /* finished */
	   fpTmp=fopen("../log/tariff.log","a+");
	   if(fpTmp != NULL)
	       fprintf(fpTmp,"Update tariff @ 20%02d-%02d-%02d %02d:%02d:%02d\n",
			time_now[0],time_now[1],time_now[2],
			time_now[3],time_now[4],time_now[5]);
	   fclose(fpTmp);
	   memset(&ramshm_ptr->tariff_data,0,sizeof(_tariff_data)); /* clear old tariff */
//	   memset(&ramshm_ptr->tariff_data.bill_discount,100,
//			sizeof(_bill_discount)*MAX_DISCOUNT_ID*24);
	 break;
	 default:
	 break;
   }
}

int  ReadUserDataFromFile()
{
   static int recordnum=0;
   char       record[512]={""};
   int		  loop;

	PutLogFunID("ReadUserDataFromFile");

   for(loop=0;loop<MAX_READFILE_NUM;loop++)
   {
     if(fgets(record,512,load_file.fp[_FILE_ID_USER_DATA]) != (char *)0) 
	 {

	   if(record[0]=='#' || record[0]=='\n') continue;
	   ImportUserData(record);
	   recordnum++;
	   uploadUserStatus[3] = recordnum / 65536;
	   uploadUserStatus[4] = recordnum / 256;
	   uploadUserStatus[5] = recordnum % 256;
     }
	 else
	 {	   
	   ppsParam.fileOperation.uploadUserData = 0x03; /* complete loading user data from ftp file */
#if DEBUG
  DebugMsg(debugmib.display.asciiOut,
  "Loading user data file(%s) completed!",USER_FILE_NAME);
#endif
       if(load_file.log_fp[_FILE_ID_USER_DATA] != NULL)
	   {
 	     fprintf(load_file.log_fp[_FILE_ID_USER_DATA],
		 "\nReading user data file(%s) completed!\n",USER_FILE_NAME);
	     if(recordnum !=
	      uploadUserStatus[0]*65536+
		  uploadUserStatus[1]*256+uploadUserStatus[2])
         {
           fprintf(load_file.log_fp[_FILE_ID_USER_DATA],
		   "\nWarning:\n    records read(%d) != Total record(%d)",
		      recordnum,
	   	      uploadUserStatus[0]*65536+
		      uploadUserStatus[1]*256+uploadUserStatus[2]);

	     }
		 fclose(load_file.log_fp[_FILE_ID_USER_DATA]);
       }
	   
	   recordnum = 0;
	   return 1;
	 }
   }
   return 0;
}

int  ReadTariffDataFromFile(int  tbindex)
{
   PutLogFunID("ReadTariffDataFromFile");

   switch(tbindex)
   {
    case _FILE_ID_COMM_TARIFF:
	    ImportCommTariffData(load_file.fp[_FILE_ID_COMM_TARIFF]);
	break;
    case _FILE_ID_RENT_TARIFF:
	    ImportRentTariffData(load_file.fp[_FILE_ID_RENT_TARIFF]);
	break;
	case _FILE_ID_BILL_TARIFF:
	    ImportBasicTariffData(load_file.fp[_FILE_ID_BILL_TARIFF]);
	break;
	case _FILE_ID_MT_TARIFF:
		ImportMTTariff(load_file.fp[_FILE_ID_MT_TARIFF]);
	break;
	case _FILE_ID_DISCOUNT:
	    ImportDiscountTariffData(load_file.fp[_FILE_ID_DISCOUNT]);
	break;
	case _FILE_ID_HOLIDY:
	    ImportHolidayTariffData(load_file.fp[_FILE_ID_HOLIDY]);
	break;
	case _FILE_ID_BILL_SMS:
		ImportBillSMS(load_file.fp[_FILE_ID_BILL_SMS]);
	break;
	case _FILE_ID_GPRS_TARIFF:
		ImportGprsTariff(load_file.fp[_FILE_ID_GPRS_TARIFF]);
	break;
	case _FILE_ID_VAS_MMS_SEND_TARIFF:
		ImportVasMmsSendTariff(load_file.fp[_FILE_ID_VAS_MMS_SEND_TARIFF]);
	break;
	case _FILE_ID_VAS_MMS_RETRIEVE_TARIFF:
		ImportVasMmsRetrieveTariff(load_file.fp[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF]);
	break;
	case  _FILE_ID_VAS_MMS_EMAIL_TARIFF:
		ImportVasEmailTariff(load_file.fp[_FILE_ID_VAS_MMS_EMAIL_TARIFF]);
	break;
    default:
	break;
   }
  return 1;
}

int  ReadPrepaidCardDataFromFile()
{
   static int recordnum=0;
   char       record[512]={""};
   int		  loop;

	PutLogFunID("ReadPrepaidCardDataFromFile");

   for(loop=0;loop<MAX_READFILE_NUM;loop++)
   {
     if(fgets(record,512,load_file.fp[_FILE_ID_PREPAID_CARD]) != (char *)0) 
	 {
	   if(record[0]=='#' || record[0]=='\n') continue;
	   ImportPrepaidCardData(record);
	   recordnum++;
	   uploadPrecardStatus[3] = recordnum / 65536;
	   uploadPrecardStatus[4] = recordnum / 256;
	   uploadPrecardStatus[5] = recordnum % 256;
     }
	 else
	 {	   
	   ppsParam.fileOperation.uploadPrepaidCard = 0x03; /* complete loading user data from ftp file */
#if DEBUG
  DebugMsg(debugmib.display.asciiOut,
           "Loading prepaid data file(%s) completed!",
           PREPAID_CARD_FILE);
#endif
       if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
	   {
     if(recordnum !=
	      uploadPrecardStatus[0]*65536+
		  uploadPrecardStatus[1]*256+uploadPrecardStatus[2])
         {
           fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
		   "\nWarning:\n    records read(%d) != Total record(%d)",
		      recordnum,
	   	      uploadPrecardStatus[0]*65536+
		      uploadPrecardStatus[1]*256+uploadPrecardStatus[2]);

	     }	   	   
 	     fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
		         "\nReading prepaid card data file(%s) completed!\n",
				 PREPAID_CARD_FILE);
		 fclose(load_file.log_fp[_FILE_ID_PREPAID_CARD]);
       }
	
	   recordnum = 0;
	   return 1;
	 }
   }
   return 0;
}

void
CheckLoadFile()
{
   	int 	loop;
	BOOL	saveFlag = FALSE;
	
	PutLogFunID("CheckLoadFile");

   for(loop=0;loop<MAX_LOADFILE_NUM;loop++)
   {
      if(load_file.flag[loop])
	  {
	    switch(loop)
		{
		  case _FILE_ID_USER_DATA: /* user data */
			//stopPeriodicSync = 1;
		   if(ReadUserDataFromFile())
		   {
    		 stopPeriodicSync = 0;
		     load_file.flag[loop] = 0x00;
			 fclose(load_file.fp[loop]);
			 remove(USER_FILE_NAME);
		//	 saveFlag = TRUE;

	 		  SaveSubsData();

		   }
		  break;
		  case _FILE_ID_PREPAID_CARD: /* prepaid card */
		   //stopPeriodicSync = 1;
		   if(ReadPrepaidCardDataFromFile())
		   {
			 stopPeriodicSync = 0;
		     load_file.flag[loop] = 0x00;
			 fclose(load_file.fp[_FILE_ID_PREPAID_CARD]);
			 remove(PREPAID_CARD_FILE);
			//  saveFlag = TRUE;
		   }		    
		  break;
		  case _FILE_ID_COMM_TARIFF:
		    if(ReadTariffDataFromFile(_FILE_ID_COMM_TARIFF))
			{
		      load_file.flag[_FILE_ID_COMM_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_COMM_TARIFF]);
			  //remove(COMM_TARIFF_FILE_NMAE); /* set status */
			   saveFlag = TRUE;
			}
		  break;
		  case _FILE_ID_RENT_TARIFF: /* param tariff data */
		    if(ReadTariffDataFromFile(_FILE_ID_RENT_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_RENT_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_RENT_TARIFF]);
			  //remove(TPARAM_FILE_NAME); /* set status */
			   saveFlag = TRUE;
		    }
		  break;
		  case _FILE_ID_BILL_TARIFF: /* bill tariff data */
		    if(ReadTariffDataFromFile(_FILE_ID_BILL_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_BILL_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_BILL_TARIFF]);
			  //remove(TARIFF_FILE_NAME);
			   saveFlag = TRUE;
		    }
		  break;
		  case _FILE_ID_MT_TARIFF:
		    if(ReadTariffDataFromFile(_FILE_ID_MT_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_MT_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_MT_TARIFF]);
			  //remove(TARIFF_FILE_NAME);
			   saveFlag = TRUE;
		    }
		  break;
		  case _FILE_ID_DISCOUNT: /* discount data */
		    if(ReadTariffDataFromFile(_FILE_ID_DISCOUNT))
		    {  
		      load_file.flag[_FILE_ID_DISCOUNT] = 0x00;
			  fclose(load_file.fp[_FILE_ID_DISCOUNT]);
			   saveFlag = TRUE;
		    }
		  break;
		  case _FILE_ID_HOLIDY: /* holiday data */
		    if(ReadTariffDataFromFile(_FILE_ID_HOLIDY))
		    {  
		      load_file.flag[_FILE_ID_HOLIDY] = 0x00;
			  fclose(load_file.fp[_FILE_ID_HOLIDY]);
			  //rename(HOLIDAY_FILE_NAME,HOLIDAY_CSV);
			   saveFlag = TRUE;
		    }
		  break;
		  case _FILE_ID_BILL_SMS:
		    if(ReadTariffDataFromFile(_FILE_ID_BILL_SMS))
		    {  
		      load_file.flag[_FILE_ID_BILL_SMS] = 0x00;
			  fclose(load_file.fp[_FILE_ID_BILL_SMS]);
			   saveFlag = TRUE;
		    }
		  break;
		  case _FILE_ID_GPRS_TARIFF:
			if(ReadTariffDataFromFile(_FILE_ID_GPRS_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_GPRS_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_GPRS_TARIFF]);
			   saveFlag = TRUE;
		    }
		  break;
		case _FILE_ID_VAS_MMS_SEND_TARIFF:
			if(ReadTariffDataFromFile(_FILE_ID_VAS_MMS_SEND_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_VAS_MMS_SEND_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_VAS_MMS_SEND_TARIFF]);
			   saveFlag = TRUE;
		    }
		break;
  		case _FILE_ID_VAS_MMS_RETRIEVE_TARIFF:
			if(ReadTariffDataFromFile(_FILE_ID_VAS_MMS_RETRIEVE_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_VAS_MMS_RETRIEVE_TARIFF]);
			   saveFlag = TRUE;
		    }
		break;
  		case _FILE_ID_VAS_MMS_EMAIL_TARIFF:
			if(ReadTariffDataFromFile(_FILE_ID_VAS_MMS_EMAIL_TARIFF))
		    {  
		      load_file.flag[_FILE_ID_VAS_MMS_EMAIL_TARIFF] = 0x00;
			  fclose(load_file.fp[_FILE_ID_VAS_MMS_EMAIL_TARIFF]);
			   saveFlag = TRUE;
		    }
		break;
		default:
		   load_file.flag[loop] = 0x00;
		break;
		}/* switch */
	  }/* if */
   }/* for */
   if(saveFlag == TRUE)
   {
   		saveFlag= FALSE;
  	 	SaveTariffPlan();
   }
}



void
ReleaseAll(u_short portid)
{
	_state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("ReleaseAll");

	shmp += portid;

	if(shmp->process_info.tcend)
		SendScfTcEND(portid);

	ReleasePortStatus(portid);

	pthread_mutex_lock( &pps_mtx );// mutex lock=================
	shmp->process_info.sub_state = S_IDLE;
	shmp->context_info.new_flag = 0;
	shmp->process_info.tcend = 0;
	memset(shmp, 0, sizeof(_state_data));
	pthread_mutex_unlock( &pps_mtx );// mutex unlock==============
	/* clear process and context info */
}


void
TariffPlanProc()
{
    _proc_data    *shmp=NULL;
	u_long next_update_tariff = ppsParam.fileOperation.nextTariffStartTime;
	static	int	  tariffCounter=0;

	PutLogFunID("TariffPlanProc");

	shmp=&smshm_ptr->proc_data[STATE_UPDATE_TARIFF];
    switch(shmp->state_i) {
        case 0:
			if(tariffCounter++>=CYCLE_STATE_INTERVAL)
			{
				tariffCounter = 0;
				shmp->state_i = 2;
			}
			break;
        case 1:
		   load_tariff_main();
 #if DEBUG
	if(logMsgFlag & 0x04)
            DebugMsg(debugmib.display.asciiOut, "Tariff plan take affect at %d", 
                           next_update_tariff);
#endif
            shmp->state_i = 0;
            break;
        default:
            shmp->state_i = 
                    (next_update_tariff - tvnow.tv_sec);
            if (shmp->state_i < 0 ) shmp->state_i = 0 ;
            break;
    }
}

int
BeatTrans()
{
	static int	counter = 0;
//	static int	recreate_index_counter = -3;
	/* offset 30seconds for importing subs. data file progress */
	
	if(counter++ ==10*CYCLE_STATE_INTERVAL)
	{
		counter = 0;
		ppsSendHeartBeating();

		peer_server_in_init = 0;
		
		/*
		if((debugmib.display.sysState == _SYS_STATE_NORMAL) &&
			(debugmib.display.peer_state == 0x10 ))
		{
			if(debugmib.measurement.peer_usernumber != 
				debugmib.measurement.usernumber)
			{
				if((recreate_index_counter++ % 330)==0) // about 330 *10seconds 
				{
					CreatePPSDataIndexForAll();
				}
//				recreate_index_counter ++;
			}
			else
			{
				recreate_index_counter = -30;
				
			}

		}
		*/
		if(debugmib.display.peer_state_counter++>=2)
		{
			debugmib.display.peer_state = 0x00;
		}
	}

	return SUCCESS;
}


void
PeriodicChargeProc()
{
    _proc_data    *shmp=NULL;
    int                 loop=PC_LOOP_NUM;
    int                 id=0, type=0,totalid=0,flag=1,tariff_id=0;
    int                 head=0, tail=0, i, favorite_rent_id=0,sms_send_flag=0;
    int                 charge = 0;
    _prepaid_info	*shmp_ptr = NULL;

    PutLogFunID("PeriodicChargeProc");

    shmp = &smshm_ptr->proc_data[STATE_PERIODIC_TARIFF];
    switch(shmp->state_i)
    {
        case 0:
            if (PERIODIC_CHARGE_HOUR == GetTmHour()
                    && PERIODIC_CHARGE_MINUTE == GetTmMinute()
                    && 8 < GetTmSecond()
                    && 10 > GetTmSecond()
                    && chargeID == 1)
            {
                shmp->count = 0;
                shmp->state_i = 1 ;
            }
        break;
        case 1:
            while(loop-- > 0)
            {
                head = (int) (shmp->count / UNIT_STORE_ACCOUNT);
                tail = (int) (shmp->count % UNIT_STORE_ACCOUNT);
                sms_send_flag=0;
                if (shmp->count++ >=MSISDN_HEAD_NUM*UNIT_STORE_ACCOUNT)
                {
                    shmp->state_i = 0;
                    return;
                }

 
                if(IsEnablePeriodicAction(head,tail) == TRUE)
                {
                    freeServiceDaysDeduct(head, tail);
                    resetPoolSlaveDaily(head,tail);
                   SendAccountRealSync(head*UNIT_STORE_ACCOUNT+tail,0.0,0.0,OMC_OCODE_EDIT);
                }
				
                if (IsEnablePeriodicCharge(head, tail) ) 
                {					
                
                    totalid = GetUserType(head, tail);  /* user type */
                    tariff_id = GetMOTariffIDWithFreeServiceControl(head,tail);
                    if(tariff_id>=MAX_ZONE_NUM || tariff_id<0) 
                        tariff_id = 0;

                    shmp_ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
                    if(shmp_ptr->favorite_plan_id>0 && shmp_ptr->favorite_plan_state == 0)
                    {
                        favorite_rent_id = 
                        	ppsParam.ppsTables.cosTable[shmp_ptr->cos_id].friendFamilyControl[0].friendFamilyPlan[shmp_ptr->favorite_plan_id-1].rentID-1;
                    }
                    
                    for(i=0;i<8;i++)
                    {
                        flag = 1;
                        if(!((flag<<i) & totalid))
	                    continue;
                        id = i;
                        type = GetPeriodicTariffType(tariff_id,id);
#if DEBUG
                        if(logMsgFlag & 0x04)
                            DebugMsg(debugmib.display.asciiOut, "PCP count: %d head: [%d][%d],tariff:%d rent id: %d type: %d", 
                                    shmp->count, head, tail, tariff_id,id, type);
#endif
                        switch(type)
                        {
                            case 0: /* daily */
                                charge = GetPeriodicTariffFee(tariff_id,id);
                                if (charge != 0) 
                                {
                                    UpdateAccountBalance(head, tail, -charge);
                                    SendAccountRealSync(head*UNIT_STORE_ACCOUNT+tail,-charge,0.0,OMC_OCODE_EDIT);
                                    SendPeriodicChargeCDR(head,tail, charge, CT_RENT_CHARGE_TYPE0+id);
                                }
                            break;
                            case 1: /* monthly */
                                if (time_now[2] == GetPeriodicChargeDate(tariff_id,id)) 
                                {
                                    charge = GetPeriodicTariffFee(tariff_id,id);
			               if(favorite_rent_id == id) // to clear F&F number
			                {
			                    if(CheckClearFriendFamilyNumber(head, tail, charge, id))
			                    {
			                        charge = 0;			                        
			                    }
			               }
                                    if (charge != 0)
                                    {
                                        UpdateAccountBalance(head, tail, -charge);                                       
                                        SendPeriodicChargeCDR(head,tail, charge, CT_RENT_CHARGE_TYPE0+id);
                                        if(ppsParam.ppsTables.cosTable[shmp_ptr->cos_id].smsNotificationInquiry[0].smsNotificationWhenRentCharge)
                                        {
                                             if(sms_send_flag==0)
						   {
						       sendPPSNotificationMessage(head, tail, SMS_RENT_CHARGE);                                                                              
						       sms_send_flag = 1;
                                             }
                                        }
                                    }
                                     SendAccountRealSync(head*UNIT_STORE_ACCOUNT+tail,-charge,0.0,OMC_OCODE_EDIT);
                                }
                            break;
                        } /* switch(type) */						
                    }/* for */					
                } /*  if (...) */	
            }
        break;
        default:
            shmp->state_i = 0;
        break;
    }
}

int RechargeFailedUpdateAccountData(u_short portid)
{
    int maxThreshold=0, instance;
    _account_info	pInfo;
    _state_data    *shmp;


    PutLogFunID("RechargeFailedUpdateAccountData");

    if(portid>=MAX_FSM_PROCESS)
    	return 0;
    
    shmp=(_state_data *)&smshm_ptr->state_data;
    shmp += portid;
    
    if(shmp->process_info.rechargeByOther)
    {
        memcpy(&pInfo,&shmp->caller_info,sizeof(_account_info));
        memcpy(&shmp->caller_info,&shmp->recharge_info,sizeof(_account_info));
    }

    SendRechargeCDR(portid, CT_RECHARGE_FAIL, 0);

    UpdateAccountRechargeFail(shmp->caller_info.head,
            shmp->caller_info.tail);

    maxThreshold = GetParamRechargeAttemptLimit();
    if ( maxThreshold>0 && 
            maxThreshold< GetAccountRechargeFail(shmp->caller_info.head, shmp->caller_info.tail))
    {
        UpdateAccountStatus(shmp->caller_info.head, shmp->caller_info.tail, T_BLACKLIST);
        ResetAccountRechargeFail(shmp->caller_info.head, shmp->caller_info.tail);
    }

    instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
				 + shmp->caller_info.tail;
    SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);

    if(shmp->process_info.rechargeByOther)
    {
        memcpy(&shmp->caller_info,&pInfo,sizeof(_account_info));
    }
    return 1;
}

int CheckWetherValidRechargeCard(u_short portid, char *card_pwd, int *result)
{
    int    retval = 1;

    PutLogFunID("CheckWetherValidRechargeCard");

    if(portid>=MAX_FSM_PROCESS)
    	return 0;

    if(RechargeCardRequest(portid,card_pwd,result) != 1)
    {	
        RechargeFailedUpdateAccountData(portid);
        retval = 0;
    }    
    return retval;
}


int RechargeRequestProc(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;
    //shmp->process_info.state = S_IDLE;	

    if(shmp->process_info.rechargeByOther ==1)
    {
        memcpy(&tmp_info, &shmp->caller_info, sizeof(_account_info));
        memcpy(&shmp->caller_info, &shmp->recharge_info, sizeof(_account_info));
    }

    UpdateBalanceForRecharge(&shmp->caller_info, GetRechargeCardFaceValue(shmp));
    UpdateRechargeCard(portid, CARD_USED);
    SendRechargeCDR( portid, CT_RECHARGE_SUCCESS, GetRechargeCardFaceValue(shmp));

    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);
        UpdateExpirationFirstCharge(shmp);
    }
    else
    {
        UpdateExpiration(shmp);
        UpdateAccountStatus(shmp->caller_info.head, shmp->caller_info.tail, T_NORMAL);
    }

    // promotion 
    cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
    if(IsPromotionTime(cosTableItem,tvnow))
    {
        promo_balance = GetPromotionAmount(cosTableItem,GetRechargeCardFaceValue(shmp));
        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,GetRechargeCardFaceValue(shmp))
            );
            SendRechargeCDR( portid, CT_RECHARGE_SUCCESS,
            GetPromotionAmount(cosTableItem,GetRechargeCardFaceValue(shmp)));
        }
    }
	
    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,GetRechargeCardFaceValue(shmp),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);   
    }
    
    if(shmp->process_info.rechargeByOther ==1)
    {
        memcpy(&shmp->caller_info, &tmp_info, sizeof(_account_info));
    }

    return retval;
}


int IdleProc(u_short invoke_id) 
{
    _state_data      *shmp;//, *ptr;
    int              retval;
	shmp=(_state_data *)&smshm_ptr->state_data;	
    shmp += invoke_id;
    retval = shmp->process_info.state;
    
	if (shmp->context_info.new_flag == NO ){
		return retval;
	}
    
    shmp->context_info.new_flag = NO;
    switch(shmp->context_info.mtype) {
		case CAP_O_OPEN:
		  retval = S_WAITING_INITIALDP;
		break;
        default:
			ReleasePortStatus(invoke_id);
            retval = S_IDLE;
        break;
    }
    
    return retval;
}

int
WaitingForInitialDP(u_short portid)
{
	int           			retval, dlgid, msglen;
	int           			caller_status,called_status;
	CosServiceControl	 	*serviceControlItem;
	_state_data    			*shmp=(_state_data *)&smshm_ptr->state_data;
	CAP_Message   			capmsg;
	CapArg        			capArg;
	char					buf[BUFSIZE],msisdn[64];
	COSTable				*cosTableItem;


	retval = shmp->process_info.state;
	shmp += portid;
	dlgid  = shmp->context_info.dialogue_id;
	shmp->process_info.portid = portid;
	PutLogFunID("WaitingForInitialDP");
	if(shmp->process_info.funnel ++ >(ONE_MINUTE_STATE_TIME))
	{			
		log_warning("Wait InitialDP(First operation) timeout!",portid);
		retval = S_RELEASE_ALL;
		return retval;
	}

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}


	shmp->process_info.funnel = 0;

	msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
	
	capArg.version = shmp->context_info.acn_ver;
	
	if(decode_capmsg((char *)&capmsg.msgContent[5],
				msglen,
				capmsg.msgOperaCode,
				CAP_CONFIRM,
				&capArg)<0)
	{
		retval = S_RELEASE_ALL;
		return retval;
	}
	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_AssistRequestInstructions:
			#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				ppsDebugCapMsg(&capmsg,0);
			}
			#endif

			ppsBcdToAsciiR(buf,
						&capArg.msg_list.assistRequestInstructionsArg.correlationID[4],
						4);

			shmp->process_info.correlationID = atoi(buf);
			retval = S_SEND_PLAY_ANNOUNCEMENT;
			AddPPSStatistics(MIBPPS_AST_INS,shmp->process_info.dir);
			return retval;
		 break;
		 case CAP_OC_InitialDP:
			#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				ppsDebugCapMsg(&capmsg,0);
			}
			#endif

			AddPPSStatistics(MIBPPS_INITIALDP,shmp->process_info.dir);	    
			if(!decode_initialDP(shmp,portid,capArg))
			{			
				log_warning("\33[31m %04d Invalid InitialDP Message\33[0m",portid);

				SendReleaseCall(portid);
				retval = S_RELEASE_ALL;
				return retval;			  
			}	    

			shmp->cdr_info.seizuretime = tvnow.tv_sec;
   			shmp->cdr_info.answertime = tvnow.tv_sec;

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

			switch(shmp->context_info.callType)
			{
				case CT_MO_CALL:
					shmp->process_info.serviceType = SRV_NORMAL_MO_CALL;
					SetCallType(shmp, CT_NDD_CALL_OUT);
				break;
				case CT_MT_CALL:
					shmp->process_info.serviceType = SRV_NORMAL_MT_CALL;
					SetCallType(shmp, CT_LOCAL_CALL_IN);					
				break;
				case CT_MF_CALL:
					shmp->process_info.serviceType = SRV_NORMAL_MF_CALL;
					SetCallType(shmp, CT_NDD_CALL_OUT);
				break;
			}

			shmp->process_info.routing_home_flag = 0;

			if(pps_get_adaptor_flag())
			{
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)							
				{
					DebugMsg(debugmib.display.asciiOut," [%04d] Call type: <%s>", portid,
							callTypeName[shmp->process_info.serviceType]);
					DebugMsg(debugmib.display.asciiOut," Caller : <%s>, Called : <%s>", 
							shmp->caller_info.number, shmp->called_info.number);
					
				}

				if(shmp->context_info.callType == CT_MO_CALL)
				{
					int routing_home_flag = 0;

					routing_home_flag = xap_roaming_rule_get_routing_home_flag(shmp->cdr_info.locationNumber);
					if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)							
					{
						DebugMsg(debugmib.display.asciiOut," [%04d] check routing home : %d", portid, routing_home_flag);
						
					}

					if(routing_home_flag>0)
					{
						shmp->process_info.routing_home_flag = 1;

					}
					else
					{
						shmp->process_info.routing_home_flag = 0;
					}

					shmp->process_info.serviceType = GetServiceType(shmp);
					switch(shmp->process_info.serviceType)
					{
						case SRV_INQUIRY:
						case SRV_SCRATCH_CARD_RECHARGE:
						case SRV_FEE_TRANSFER:
							if(shmp->context_info.acn_ver<1)
							{
								shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
								SendReleaseCall(portid);
								return (retval= S_RELEASE_ALL);
							
							}

							shmp->process_info.promptAndCollectUserInfo = 1;
							return (retval = S_REQUEST_EVENTS);
						break;
						default:
						break;
					}
				
				}					

				shmp->process_info.state = S_RO_ADAPTOR_CALL_INIT;
				
				return S_RO_ADAPTOR_CALL_INIT;	
			}
			
			GetAccountPos(&shmp->caller_info);
			GetAccountPos(&shmp->called_info);
			
			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); 
			}

			if(shmp->called_info.head<MSISDN_HEAD_NUM)
			{
				shmp->called_info.cos_id = GetAccountCosID(&shmp->called_info);
				shmp->called_info.cug_id = GetAccountCUG(&shmp->called_info); 
			}
			
			caller_status = GetAccountStatus(&shmp->caller_info);
			shmp->caller_info.status = caller_status;
			called_status = GetAccountStatus(&shmp->called_info);
			shmp->called_info.status = called_status;

			//shmp->process_info.logMsisdn = 0x00;
				

			#if DEBUG
			if(shmp->process_info.logMsisdn && logMsgFlag != 0xff)
			{  
				ppsDebugCapMsg(&capmsg,0);
			}
			#endif

			shmp->process_info.callConnected = 0;
			switch(shmp->context_info.callType)
			{
				case CT_MO_CALL:
				case CT_MF_CALL:
					SetIndexMessAlamFlag(0);
					
					shmp->process_info.serviceType = GetServiceType(shmp);

					if(shmp->caller_info.status == T_EXTERNAL)
					{
						if(	shmp->process_info.serviceType == SRV_OTHER_VMS_MAITENANCE 
							||
							shmp->process_info.serviceType == SRV_VMS_DEPOSIT
							//|| 
							//shmp->process_info.serviceType == SRV_CRD
							)
						{
							shmp->process_info.promptAndCollectUserInfo = 1;
							return (retval = S_REQUEST_EVENTS);
						}
						else if(shmp->process_info.serviceType == SRV_CRD)
						{ /* for OMT roaming postpaid subs to access VMS */
							if(GetCRDDestination((char *)shmp->caller_info.number,
													msisdn,
													SRV_CRD-SRV_CRD))
							{
								shmp->process_info.serviceType = 
										SRV_NORMAL_MO_CALL;
								shmp->process_info.callConnected = 1;
							}
							else
							{
								shmp->process_info.promptAndCollectUserInfo = 1;
								return (retval = S_REQUEST_EVENTS);
							}
						}
						else if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL)				
						{
							if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)							
								DebugMsg(debugmib.display.asciiOut,
									"\33[31mcaller <%s> is not Prepaid subs \33[0m",
									shmp->caller_info.number);

							shmp->process_info.tcend = 1;
							if(CheckCRDRingBackSericeKey(shmp->process_info.serviceKey))
							{
								if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)							
									DebugMsg(debugmib.display.asciiOut,
										"\33[31m Postpaid VMS ring bak call, let it gooo \33[0m");
								SendContinue(portid);
								SendScfTcEND(portid);
							}
							else
							{
								shmp->process_info.tcos = UNALLOCATED_NUMBER;
								shmp->process_info.u_error = CAP_ERR_MISSING_CUSTOMER_RECORD;
								shmp->process_info.oc = CAP_OC_InitialDP;
								SendScfUError(portid);
								//SendScfUAbort(portid);
								//SendReleaseCall(portid);
							}
							return (retval = S_RELEASE_ALL);
						}
					}//if t_external
					SetIndexMessAlamFlag(2);
					
					//CheckPromotionLatchFlag(&shmp->caller_info);

					switch(shmp->process_info.serviceType)
					{
						case SRV_CALL_HOTLINE:
						case SRV_INQUIRY:
						case SRV_SCRATCH_CARD_RECHARGE:
						case SRV_CREDIT_CARD_RECHARGE:
						case SRV_THIRD_PARTY_RECHARGE:
						case SRV_RECHARGE_2TYPES:
						case SRV_CALLINGCARD_MANAGE:/*calling card		*/	
						case SRV_FEE_TRANSFER:
						case SRV_POOL_ACCOUNT:
							if(shmp->context_info.acn_ver<1)
							{
								shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
								SendReleaseCall(portid);
								return (retval= S_RELEASE_ALL);
							
							}

							shmp->process_info.promptAndCollectUserInfo = 1;
							return (retval = S_REQUEST_EVENTS);
						break;
						case SRV_RECHARGE_ONE_INPUT:
							shmp->process_info.chargeFrom = 2;

							if( (caller_status != T_RELEASED  && 	caller_status != T_BLACKLIST )
								||
								(caller_status == T_EXTERNAL && shmp->process_info.palim_auto_register )	)
							{
								//int result;

								shmp->process_info.sub_state = 1;
								/*
								if(CheckWetherValidRechargeCard(portid,shmp->called_info.number,&result))
								{
									RechargeRequestProc(portid);
									shmp->process_info.sub_state = 1;
								}
								else
									shmp->process_info.sub_state = 2;
								*/
							}
	
							if(shmp->context_info.acn_ver<1)
							{
								shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
								SendReleaseCall(portid);
								return (retval= S_RELEASE_ALL);
							
							}
							
							shmp->process_info.promptAndCollectUserInfo = 1;
							return (retval = S_REQUEST_EVENTS);
						break;
						case SRV_CRD:
							shmp->process_info.serviceType = SRV_NORMAL_MO_CALL;
							shmp->process_info.callConnected = 1;
						break;
					}

					if(caller_status == T_BLACKLIST &&
						(strlen((char *)ppsParam.ppsTables.serviceNumber[CustomerCareCenterNumberPosition].number)>=3))
					{
						shmp->process_info.callConnected = 1;
						strcpy(shmp->process_info.tmpDigits,
								(char *)ppsParam.ppsTables.serviceNumber[CustomerCareCenterNumberPosition].number);
						sendConnectForCRDService(portid);
						SendScfTcEND(portid);
						return (retval = S_RELEASE_ALL);
					}

					serviceControlItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id].serviceControl[0];
					cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
					
					shmp->caller_info.location = 
							GetTariffLacInfo(shmp->cdr_info.cgi);
					if(cosTableItem->tariff[0].chargeBy)
					{
						pps_print_event(shmp->process_info.logMsisdn,"%s charged by cgi",shmp->caller_info.number);
						if(shmp->caller_info.location<0)
						{
							pps_print_error(shmp->process_info.logMsisdn,"%s isn't matched by cgi,so charged by cos",shmp->caller_info.number);
							shmp->caller_info.location = 
								GetAccountZoneID(shmp->caller_info.head, 
										shmp->caller_info.tail);	
						}
						else
						{
							CheckWetherRoamingUser(shmp);
							shmp->caller_info.location = 
								GetAccountZoneIDByLocationInfo(shmp->caller_info.location);	
						}
					}
					else
					{
						pps_print_event(shmp->process_info.logMsisdn,"%s charged by cos",shmp->caller_info.number);
						if(shmp->caller_info.location>=0)
						{
							CheckWetherRoamingUser(shmp);
							if(shmp->process_info.roamingFlag)
							{
								pps_print_event(shmp->process_info.logMsisdn,"%s is roaming,so charged by cgi",shmp->caller_info.number);
								shmp->caller_info.location = 
									GetAccountZoneIDByLocationInfo(shmp->caller_info.location);	
							}
							else
							{
								shmp->caller_info.location = 
									GetAccountZoneID(shmp->caller_info.head, 
										shmp->caller_info.tail);				
							}
						}
						else
						{
							shmp->caller_info.location = 
								GetAccountZoneID(shmp->caller_info.head, 
										shmp->caller_info.tail);				

						}
					}
				
					if(cosTableItem->friendFamilyControl[0].friendFamilyFlag)
						shmp->process_info.favoriteCall = 
							CheckWetherFavoriteNumber(&shmp->caller_info,shmp->called_info.number);
					if(serviceControlItem->poolAccountFlag)
					{
						if(getPoolAccountRole(portid) != MASTER_SLAVE_NONE)
							shmp->process_info.poolCall = 
								CheckWetherPoolNumber(&shmp->caller_info,&shmp->called_info);
					}
					
					if(serviceControlItem->closeUserGroupService)
					if(shmp->caller_info.cug_id !=NOT_CUG_ACCOUNT &&
					  (shmp->caller_info.cug_id == shmp->called_info.cug_id))
						shmp->process_info.cugCall = 1;

					if(shmp->context_info.callType == CT_MO_CALL)
					{
							shmp->process_info.routing_home_flag =
								xap_roaming_rule_get_routing_home_flag(shmp->cdr_info.locationNumber);
					}					

					
				break; //callType
				default: //mt call
					SetIndexMessAlamFlag(0);
					if(shmp->called_info.head>=MSISDN_HEAD_NUM)
					{
						DebugMsg(debugmib.display.asciiOut,
							"\33[31mCalled number <%s> is not Prepaid subs.\33[0m",
							shmp->called_info.number);
		
						shmp->process_info.tcos = DESTINATION_OUT_OF_ORDER;
						shmp->process_info.u_error = CAP_ERR_MISSING_CUSTOMER_RECORD;
						shmp->process_info.oc =	CAP_OC_InitialDP;
						SendScfUError(portid);
						//SendScfUAbort(portid);
						//SendReleaseCall(portid);
						shmp->process_info.tcend = 1;
						
						return (retval = S_RELEASE_ALL);
					}
					SetIndexMessAlamFlag(2);
					
					//CheckPromotionLatchFlag(&shmp->called_info);
					
					cosTableItem = &ppsParam.ppsTables.cosTable[shmp->called_info.cos_id];
					serviceControlItem = &cosTableItem->serviceControl[0];

					if(cosTableItem->friendFamilyControl[0].friendFamilyFlag)			
					shmp->process_info.favoriteCall = 
						CheckWetherFavoriteNumber(&shmp->called_info,shmp->caller_info.number);			

					if(serviceControlItem->poolAccountFlag)
					{
						if(getPoolAccountRole(portid) != MASTER_SLAVE_NONE)
							shmp->process_info.poolCall = 
								CheckWetherPoolNumber(&shmp->called_info,&shmp->caller_info);
					}
					
					if(serviceControlItem->closeUserGroupService)
					if(shmp->caller_info.cug_id !=NOT_CUG_ACCOUNT 
						&&
						(shmp->caller_info.cug_id == shmp->called_info.cug_id))
						shmp->process_info.cugCall = 1;

					shmp->called_info.location = 
							GetTariffLacInfo(shmp->cdr_info.cgi);
					if(cosTableItem->tariff[0].chargeBy)
					{
						pps_print_event(shmp->process_info.logMsisdn,"%s charged by cgi",shmp->called_info.number);
						if(shmp->called_info.location<0)
						{
							pps_print_error(shmp->process_info.logMsisdn,"%s isn't matched by cgi,so charged by cos",shmp->called_info.number);
							shmp->called_info.location = 
								GetAccountMTZoneID(shmp->called_info.head, 
										shmp->called_info.tail);	
						}
						else
						{
							CheckWetherRoamingMTUser(shmp);
							shmp->called_info.location = 
								GetAccountMTZoneIDByLocationInfo(shmp->called_info.location);	
						}
					}
					else
					{
						pps_print_event(shmp->process_info.logMsisdn,"%s charged by cos",shmp->called_info.number);
						if(shmp->called_info.location>=0)
						{
							CheckWetherRoamingMTUser(shmp);
							if(shmp->process_info.roamingFlag)
							{
								pps_print_event(shmp->process_info.logMsisdn,"%s is roaming,so charged by cgi",shmp->called_info.number);
								shmp->called_info.location = 
									GetAccountMTZoneIDByLocationInfo(shmp->called_info.location);	
							}
							else
							{
								shmp->called_info.location = 
									GetAccountMTZoneID(shmp->called_info.head, 
										shmp->called_info.tail);				
							}
						}
						else
						{
							shmp->called_info.location = 
								GetAccountMTZoneID(shmp->called_info.head, 
										shmp->called_info.tail);				

						}
					}
				break;
			}


			shmp->caller_info.charge = 0;
			shmp->caller_info.fee = 0;
			shmp->called_info.charge = 0;
			shmp->called_info.fee = 0;
			if(shmp->process_info.tcos != SRVICE_NOT_SUBSCRIBERED) /* this judgement is used for COS based service number */
				    shmp->process_info.tcos = NORMAL_CLEARING;
			//check called mnp status here
			//mt call not implemented ,2006-03-20
			if(shmp->context_info.callType != CT_MT_CALL)
				shmp->process_info.mnp_status =
					 IsMNPCalledNumber((char *)shmp->called_info.number);

			if(OCS_with_external_CRM())//query tariff from CRM database
			{
				if(shmp->context_info.callType != CT_MT_CALL)
				{
					pps_send_query_tariff_req(portid);		
				}
			}
			
			if(shmp->process_info.mnp_status)
			{
				return S_SEND_MNP_ATI;
			}
			else
				return S_CHECK_CALL_VALIDITY;
			
		break;
		case  CAP_OC_InitialDPSMS:
			AddPPSStatistics(MIBPPS_INITIALDP_SMS,shmp->process_info.dir);
			#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
			   debug_messages ++;
			   ppsDebugCapMsg(&capmsg,0);

			}
			#endif
		   if(!decode_initialDPSMS(shmp,portid,capArg))
		   {
			#if DEBUG
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				DebugMsg(debugmib.display.asciiOut,
					"\33[31m %s Send MO SMS failed, no route for %s\33[0m",
					shmp->caller_info.number,
					shmp->called_info.number);
			}
			#endif
				  SendReleaseSMS(portid);
				  retval = S_RELEASE_ALL;
				  return retval;			  
		   }
		   

			shmp->cdr_info.seizuretime = tvnow.tv_sec;
   			shmp->cdr_info.answertime = tvnow.tv_sec;
			shmp->cdr_info.releasetime = tvnow.tv_sec;

			SetCallType(shmp,CT_MO_SM);

			if(pps_get_adaptor_flag())
			{
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)							
				{
					DebugMsg(debugmib.display.asciiOut," Call type: <%s>", 
							callTypeName[shmp->process_info.serviceType]);
					DebugMsg(debugmib.display.asciiOut," Caller : <%s>, Called : <%s>", 
							shmp->caller_info.number, shmp->called_info.number);
					
				}

				shmp->process_info.state = S_RO_ADAPTOR_SMS_INIT;
				
				return S_RO_ADAPTOR_SMS_INIT;	
			}

			SetIndexMessAlamFlag(0);
		       GetAccountPos(&shmp->caller_info);
			if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
			{
				if(shmp->process_info.serviceKey != 11)//service key=11 is used for postpaid
				{
					DebugMsg(debugmib.display.asciiOut,
							"%s doesn't register Prepaid service, can't send SMS.",
						shmp->caller_info.number);
					SendReleaseSMS(portid);
					return (retval = S_RELEASE_ALL);
				}
			}
			
			SetIndexMessAlamFlag(2);
			
			GetAccountPos(&shmp->called_info);
			caller_status = GetAccountStatus(&shmp->caller_info);
			called_status = GetAccountStatus(&shmp->called_info);
			shmp->caller_info.status = caller_status;
			shmp->called_info.status = called_status;
			shmp->caller_info.cug_id = GetAccountCUG(&shmp->caller_info); 
			shmp->called_info.cug_id = GetAccountCUG(&shmp->called_info); 

			if(shmp->caller_info.head<MSISDN_HEAD_NUM)
			{
				//shmp->caller_info.cos_id = GetAccountCosID(&shmp->caller_info);
				shmp->caller_info.cos_id = GetCosIDByAccount(&shmp->caller_info);
				shmp->caller_info.cug_id = GetAccountCUG(&shmp->caller_info); 
			}
			else
			{
				shmp->caller_info.cos_id = 0;
			}
			
			shmp->process_info.serviceType = GetServiceType(shmp);

                     cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
			serviceControlItem = &cosTableItem->serviceControl[0];

			if(cosTableItem->friendFamilyControl[0].friendFamilyFlag)			
				shmp->process_info.favoriteCall = 
						CheckWetherFavoriteNumber(&shmp->caller_info,shmp->called_info.number);			

			//CheckPromotionLatchFlag(&shmp->caller_info);

			#if DEBUG
				if(strstr((char *)shmp->caller_info.number,logMsisdn)){
					 shmp->process_info.logMsisdn = 0x01;
				}
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,"MO SMS");
					DebugMsg(debugmib.display.asciiOut,
						"caller: %s caller pos: %d %d caller status: %d, cos: %d, balance:%.4f", 
						shmp->caller_info.number, 
						shmp->caller_info.head, 
						shmp->caller_info.tail, 
						caller_status,
						shmp->caller_info.cos_id,
						GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail));
					DebugMsg(debugmib.display.asciiOut,
						"called: %s called pos: %d %d called status: %d", 
						shmp->called_info.number, 
						shmp->called_info.head, 
						shmp->called_info.tail, 
						called_status);
				}
			#endif
		   shmp->caller_info.charge = 0;
		   shmp->caller_info.fee = 0;
		   shmp->called_info.charge = 0;
		   shmp->called_info.fee = 0;
		   shmp->context_info.callType = CT_MO_SM;
		   shmp->process_info.tcos = NORMAL_CLEARING;

		  if(shmp->process_info.serviceKey == 11 && shmp->caller_info.status == T_EXTERNAL)
		  {
		   	return S_SMS_CHECK_VALIDITY;	
		  } 
		  
		   switch (caller_status) {
			  case T_NORMAL:
				SetCallType(shmp,CT_MO_SM);
			  break;
			  case T_FRESH:
			  case T_SUSPEND:
				if(shmp->process_info.serviceType == SRV_SCRATCH_CARD_RECHARGE ||
					shmp->process_info.serviceType == SRV_INQUIRY)
				{
					SetCallType(shmp,CT_MO_SM);	
					break;	
				}			  
			  default:
				shmp->process_info.tcos = UNALLOCATED_NUMBER;
				SendReleaseSMS(portid);
				retval = S_RELEASE_ALL;
			#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x01) ){
				   debug_messages ++;
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"Error status: %d Send SM failed!",caller_status);
				}
			#endif
				return retval;
			  break;
		   }
			cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
			shmp->caller_info.location = 
				GetTariffLacInfo(shmp->cdr_info.cgi);
			if(cosTableItem->tariff[0].chargeBy)
			{
				pps_print_event(shmp->process_info.logMsisdn,"%s charged by cgi",shmp->caller_info.number);
				if(shmp->caller_info.location<0)
				{
					pps_print_error(shmp->process_info.logMsisdn,"%s isn't matched by cgi,so charged by cos",shmp->caller_info.number);					
					shmp->caller_info.location = GetMOTariffIDWithFreeServiceControl(shmp->caller_info.head,shmp->caller_info.tail);
				}
				else
				{
					CheckWetherRoamingUser(shmp);
					shmp->caller_info.location = 
						GetAccountZoneIDByLocationInfo(shmp->caller_info.location);	
				}
			}
			else
			{
				pps_print_event(shmp->process_info.logMsisdn,"%s charged by cos",shmp->caller_info.number);
				if(shmp->caller_info.location>=0)
				{
					CheckWetherRoamingUser(shmp);
					if(shmp->process_info.roamingFlag)
					{						
						pps_print_event(shmp->process_info.logMsisdn,"%s is roaming,so charged by cgi",shmp->caller_info.number);
						shmp->caller_info.location = 
							GetAccountZoneIDByLocationInfo(shmp->caller_info.location);	
					}
					else
					{
						shmp->caller_info.location = GetMOTariffIDWithFreeServiceControl(shmp->caller_info.head,shmp->caller_info.tail);									
					}
				}
				else
				{
					shmp->caller_info.location = GetMOTariffIDWithFreeServiceControl(shmp->caller_info.head,shmp->caller_info.tail);						
				}
			}
			
			//check mnp status here
			shmp->process_info.mnp_status =
					 IsMNPCalledNumber((char *)shmp->called_info.number);

			if(OCS_with_external_CRM())//query tariff from CRM database
				pps_send_query_tariff_req(portid);
			
			if(shmp->process_info.mnp_status)
			{	
				return S_SEND_SMS_MNP_ATI;								
			}
			else
				return S_SMS_CHECK_VALIDITY;		
		break;
		default:
			/*
			#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x01) ){
			   debug_messages ++;
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,
					"[%04d] Receive Error Message! (Waiting InitialDPx)",
				portid);
			}
			if(logMsgFlag & 0x04 || logMsgFlag & 0x01){
			   debug_messages ++;
				ppsDebugCapMsg(&capmsg,0);
			}
			#endif
			*/
			retval = S_RELEASE_ALL;
		break;
	}
	return retval;   
}

static int SendCallMNP_ATI(u_short portid)
{
	int		retval = 0;
	
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("SendMNP_ATI");
		
	shmp += portid;

	shmp->process_info.mnp_status = 0;
	SendMNP_ATI(portid);
	shmp->process_info.funnel = 0;
				
	return (retval = S_WAIT_MNP_ATI_RES);
		
}

int  SendMNP_ATI(u_short portid)
{
	int		retval = 0;
	
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("SendMNP_ATI");
		
	shmp += portid;

	shmp->context_info.acn = AC_anyTimeInfoEnquiry;
	
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[36m================== MNP call, MNP_ATI ===============\33[0m");
	}	
	pps_send_map_open(portid);
	
	pps_send_mnp_ati(portid);
	
	retval = 1;
	return retval;
}

static int WaitingForMNP_ATI_Res(u_short portid)
{
	int 			retval = 0 ;
	int				len = 0;
	char			data_flow[256];
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;
    MapComSrv_struct 	com_data;
    //MapOprData_struct	opr_data;
    MapOprSrv_struct    opr_srv;
    struct MapATI_Res   *ati_res;
    struct MnpInfoRes	*mnpInfoRes;
    
	PutLogFunID("WaitingForMNP_ATI_Res");

	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 ,did: %d, wait ATI_Res timeout\33[0m",
				portid,shmp->context_info.map_did);
		}		
		pps_send_map_close(portid);
		return -1;
	}
	
	if(map_get_oprdata((u8 *)data_flow,shmp->context_info.map_did))
	{
		u_char	msglen;
		msglen = data_flow[0] * 256 + data_flow[1];
		if((data_flow[9] != AnyTimeInter) || msglen<14)
		{
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d ,did: %d, wait ATI_Res 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>, ATI response \33[0m",
				portid,shmp->context_info.map_did,
				data_flow[9]);			
			pps_debug_map_msg(data_flow,0);
		}
		
						
		//if(map_opr_ftos(&opr_srva,data_flow)<=0)	
		opr_srv.version = 3;	
		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],
			(u8 *)&data_flow[16])<=0)
		{
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31mportid: %d ,did: %d, decode ATI_Res failed \33[0m",
					portid,shmp->context_info.map_did);
			}		
			return -1;
		}
		
		ati_res = &opr_srv.msg_list.ati_res;
	
	
		if(ati_res->param_flag & 0x01)
		{
			if(ati_res->sub_info.param_flag & 0x80)
			{
				mnpInfoRes = &ati_res->sub_info.mnp_info_res;
				
				if(mnpInfoRes->param_flag & 0x04)/* msisdn */
				{
					
				}
				/* check msisdn here */
				if(mnpInfoRes->param_flag & 0x08)
				{
					shmp->process_info.mnp_status = 
						mnpInfoRes->mnp_status;
						/*

						typedef enum NumberPortabilityStatus
						{
						    //notKnownToBePorted = 0,
						    //ownNumberPortedOut = 1,
						    //foreignNumberPortedToForeignNetwork = 2,
						    ownNumberNotPortedOut = 4,
						    foreignNumberPortedIn = 5
						}NumberPortabilityStatus;												
						*/
											
					if(shmp->process_info.mnp_status == 1 ||
					   shmp->process_info.mnp_status == 2 ||
					   shmp->process_info.mnp_status == 5)
					 {
					 	
					 	if(mnpInfoRes->param_flag & 0x01)
						{
							len = mnpInfoRes->routing_number[0]%(ISDN_LEN+1);
							ppsBcdToAsciiR(shmp->process_info.routing_number,
								&mnpInfoRes->routing_number[2],
								(len-1)*2);
							StringCut(shmp->process_info.routing_number,'F');
							
							if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
							{
								DebugMsg(debugmib.display.asciiOut,
								"[p-did,%d.%d] ATI_Res:ported status: %d, RN=%s",
								portid,shmp->context_info.map_did,
								shmp->process_info.mnp_status,
								shmp->process_info.routing_number);
							}															
						}
						else
						{
							if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
							{
								DebugMsg(debugmib.display.asciiOut,
								"\33[31m %d.%d error ATI_Res (ported subs. but no RN)\33[0m",
								portid,shmp->context_info.map_did);
							}
							shmp->process_info.mnp_status = 0;				
							return -1;
						}
					 }//status
					 else
					 {
					 	if((logMsgFlag ==  0xff) || shmp->process_info.logMsisdn)
						{
							DebugMsg(debugmib.display.asciiOut,
							"p-did: %d.%d ATI_Res received, subs. not ported",
							portid,shmp->context_info.map_did);
						}
						shmp->process_info.mnp_status = 0;										
					 }
				}//	has status								
			}//has mnp res info
			else
			{
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31m portid: %d ,did: %d, ATI_Res received, but no mnp info. \33[0m",
						portid,shmp->context_info.map_did);
				}		
				//pps_send_map_close(portid);
				return -1;
			}
		}//has parameter
		else
		{
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\33[31m portid: %d ,did: %d, ATI_Res, error <%d> \33[0m",
					portid,shmp->context_info.map_did,
					ati_res->user_error);
			}		
			//pps_send_map_close(portid);
			return -1;
		}
		retval = 1;
	}
	if(map_get_comdata_struct(&com_data,shmp->context_info.map_did))
	{		
		
		if(com_data.message_type == MAP_OPEN)
		{
			if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, Get Map Open Res. @ %ld.%ld",
					portid,shmp->context_info.map_did,
					tvnow.tv_sec,tvnow.tv_usec);
				map_com_stof(&com_data, (u8 *)data_flow, 0);
				pps_debug_map_msg(data_flow,0);
			}			
		}
		else 
		{
			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, (u8 *)data_flow, 0);
				pps_debug_map_msg(data_flow,0);
			}			
			retval = 1;
		}				
	}
	return retval;
}

static int
CheckCallValidity(u_short portid)
{
	int retval,rst;
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("CheckCallValidity");

	shmp += portid;
	retval = shmp->process_info.state;

	if(OCS_with_external_CRM())//query tariff from CRM database
	{
		if(shmp->context_info.callType != CT_MT_CALL)
		{
			if((shmp->process_info.funnel ++ < SSHORT_DELAY_TIMER) && shmp->process_info.rest_if.query_tariff_status == 1)//5S
				return retval;
		}
		BillingProc_crm(shmp, TRUE);
		
	}
	else
		BillingProc(shmp, TRUE);
	
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
   {  
        debug_messages ++;
		DebugMsg(debugmib.display.asciiOut," \n============== number info ==============");
					
		if(shmp->context_info.callType == CT_MO_CALL)
		{
			DebugMsg(debugmib.display.asciiOut," Call type: MO call <%s>", 
					callTypeName[shmp->process_info.serviceType]);
		}
		else if(shmp->context_info.callType == CT_MF_CALL)
		{
			DebugMsg(debugmib.display.asciiOut," Call type: MF call <%s>", 
					callTypeName[shmp->process_info.serviceType]);
		}
		else
		{
			DebugMsg(debugmib.display.asciiOut," Call type: MT call");
		}

		
		if(shmp->process_info.serviceKey==1)
		{
			DebugMsg(debugmib.display.asciiOut," ServiceKey = 1, charge on reported time");
		}
		else
		{
			DebugMsg(debugmib.display.asciiOut," ServiceKey = %d, real time charge",
				shmp->process_info.serviceKey);
		}

		if(shmp->process_info.roamingFlag)
			DebugMsg(debugmib.display.asciiOut," roaming call.");		
		DebugMsg(debugmib.display.asciiOut,"Caller valid_time: %d calltype: %d fee: %.04f", 
                 shmp->caller_info.valid_time,
                 shmp->process_info.call_type,
                 shmp->caller_info.fee);
		DebugMsg(debugmib.display.asciiOut,"Caller info : %s (%d %d) status:%d,cosid:%d,balance: %.04f", 
                 shmp->caller_info.number,
                 shmp->caller_info.head,
                 shmp->caller_info.tail,
				 shmp->caller_info.status,
				 shmp->caller_info.cos_id,
                 GetBalance(&shmp->caller_info));
		DebugMsg(debugmib.display.asciiOut,"Called valid_time: %d calltype: %d fee: %.04f ", 
                 shmp->called_info.valid_time,
                 shmp->process_info.call_type,
                 shmp->called_info.fee);
		DebugMsg(debugmib.display.asciiOut,"Called info: %s (%d %d) status: %d,cosid:%d, balance: %.04f", 
                 shmp->called_info.number,
                 shmp->called_info.head,
                 shmp->called_info.tail,
				 shmp->called_info.status,
				 shmp->called_info.cos_id,
                 GetBalance(&shmp->called_info));
		DebugMsg(debugmib.display.asciiOut,
			"Vlr number: %s , CGI: %02X%02X%02X%02X%02X%02X%02X, tariff id:%d",
				shmp->cdr_info.locationNumber,
				shmp->cdr_info.cgi[0],
				shmp->cdr_info.cgi[1],
				shmp->cdr_info.cgi[2],
				shmp->cdr_info.cgi[3],
				shmp->cdr_info.cgi[4],
				shmp->cdr_info.cgi[5],
				shmp->cdr_info.cgi[6],
				(shmp->context_info.callType == CT_MO_CALL) ?
					shmp->caller_info.location : shmp->called_info.location
				
				);
		
		DebugMsg(debugmib.display.asciiOut,
                "Tariff :(%s) %s CT:%d DI:%d FreeTime:%d unit_time:%d Miniunit:%d Adj:%.04f ,CapFlag%d, Discount: %d",
				 shmp->charge_info.number,
				 shmp->process_info.tariff.bill_id,
				 shmp->process_info.tariff.call_type,
			     shmp->process_info.tariff.discountID,
                 shmp->process_info.tariff.free_time,
                 shmp->process_info.tariff.unit_time,
                 shmp->process_info.tariff.mini_unit,                
                 shmp->process_info.tariff.adjustment,
                 shmp->process_info.tariff.cap_flag,
                 GetDiscount(tvnow.tv_sec,shmp->process_info.tariff.discountID));
		DebugMsg(debugmib.display.asciiOut,
				 "tierInfo:L-%d,A-(units:%d,bf:%.04f,lf:%.04f),B-(units:%d,bf:%.04f,lf:%.04f),C-(units:%d,bf:%.04f,lf:%.04f)",				
				shmp->process_info.tariff.tierRating.tierNumber,
				shmp->process_info.tariff.tierRating.rating[0].units,
				shmp->process_info.tariff.tierRating.rating[0].base_fee,
				shmp->process_info.tariff.tierRating.rating[0].long_distance_fee,
				shmp->process_info.tariff.tierRating.rating[1].units,
				shmp->process_info.tariff.tierRating.rating[1].base_fee,
				shmp->process_info.tariff.tierRating.rating[1].long_distance_fee,
				shmp->process_info.tariff.tierRating.rating[2].units,
				shmp->process_info.tariff.tierRating.rating[2].base_fee,
				shmp->process_info.tariff.tierRating.rating[2].long_distance_fee);
	}
#endif
	shmp->process_info.playAnnouncement = 0;
	shmp->process_info.promptAndCollectUserInfo = 0;
	if (!IsEnableToCall(portid) ) 
	{
		/* no voice for CAP V1 */
		if(shmp->context_info.acn_ver<1)
		{
			shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
			SendReleaseCall(portid);
			return (retval= S_RELEASE_ALL);
		
		}

		if(shmp->process_info.serviceKey == 1)
		{
			shmp->process_info.pre_warning = 0;
			shmp->process_info.playAnnouncement = 0;
			SendReleaseCall(portid);
			return (retval= S_RELEASE_ALL);
		}
		
		if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL &&
			shmp->process_info.callConnected == 1 &&
			!ppsParam.serviceControl.vms_allways_go)
		{
			shmp->process_info.pre_warning = 0;
			shmp->process_info.playAnnouncement = 0;
			shmp->process_info.promptAndCollectUserInfo = 0;
			if(shmp->caller_info.status == T_EXTERNAL)
			{
				return (retval = S_SEND_CONTINUE);
			}
			return (retval = S_REQUEST_EVENTS);
		}
		/* edit for mt voice , 2005-11-30 */

		shmp->process_info.pre_warning = 0;
		shmp->process_info.playAnnouncement = 1;

		if(OCS_with_external_CRM())//SUSPENDED FOR EXPIRED CAN RECEIVE CALL
		{
			if(shmp->process_info.tcos == CALLED_EXPIRIED)
			{
				shmp->process_info.pre_warning = 0;
				shmp->process_info.playAnnouncement = 0;
			}
		}
		else
		{
			if(pps_mt_play_voice_flag() == 0)
			{
				if(shmp->context_info.callType != CT_MO_CALL)
				{
					//shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
					SendReleaseCall(portid);
					return (retval= S_RELEASE_ALL);
				}
			}
		}
		
    }
	if(shmp->process_info.serviceKey == 1)
	{
		shmp->process_info.pre_warning = 0;
		shmp->process_info.playAnnouncement = 0;
	}
	/* for vms service */
	if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL &&
		shmp->process_info.callConnected == 1)
	{
		shmp->process_info.pre_warning = 0;
		shmp->process_info.playAnnouncement = 0;
		shmp->process_info.promptAndCollectUserInfo = 0;
		if(shmp->caller_info.status == T_EXTERNAL)
		{
			return (retval = S_SEND_CONTINUE);
		}
	}
	/* added by Pierre, 2006-05-15 for tcap id */
	if(shmp->context_info.callType == CT_MT_CALL &&
		shmp->called_info.head<MSISDN_HEAD_NUM &&
	   getCurrentFee(shmp)== 0 &&
	   ppsParam.serviceControl.mt_release_for_no_charge)
	{
		SendContinue(portid);
		SendScfTcEND(portid);
		return (retval = S_RELEASE_ALL);
	}
	else if(shmp->context_info.callType == CT_MO_CALL &&
		shmp->caller_info.head<MSISDN_HEAD_NUM &&
		shmp->process_info.serviceType == SRV_NORMAL_MO_CALL &&
	    getCurrentFee(shmp) == 0 &&
	   ppsParam.serviceControl.mo_release_for_no_charge&&
	   shmp->process_info.tariff_flag)
	{
		SendContinue(portid);
		SendScfTcEND(portid);
		return (retval = S_RELEASE_ALL);
	}

	rst = isPoolChildReachCallLimit(shmp);
	if(rst)
	{
		switch(rst)
		{
			case 1:
				shmp->process_info.tcos= CALLER_REACH_CALL_LIMIT;
				shmp->process_info.voiceID = CHILD_REACH_CALL_LIMIT;
			break;
			case 2:
				shmp->process_info.tcos= CALLER_REACH_CHARGE_LIMIT;
				shmp->process_info.voiceID = CHILD_REACH_CHARGE_LIMIT;
			break;
		}
		shmp->process_info.pre_warning = 0;
		shmp->process_info.playAnnouncement = 1;
	}	
	retval = S_REQUEST_EVENTS;
	return retval;
}

static int
ApplyCharging(u_short portid)
{
	int retval;
	_state_data  *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("ApplyCharging");

	shmp += portid;
	retval = shmp->process_info.state;
	
	if(shmp->process_info.roamingFlag)
	{
		if(shmp->process_info.funnel ++ <
				ppsParam.serviceControl.delay_timer_for_roaming)
			return retval;
	}
	
	SendApplyCharging(portid);


	if(	shmp->process_info.serviceType != SRV_CRD &&
		shmp->process_info.serviceType != SRV_DIRECT_ACCESS &&
		shmp->process_info.serviceType != SRV_RESERVED_FUN &&
		shmp->process_info.serviceType != SRV_OTHER_VMS_MAITENANCE &&
		shmp->process_info.serviceType != SRV_VMS_DEPOSIT)
	{
		retval = S_SEND_CONTINUE;
	}
	else
	{
		shmp->process_info.promptAndCollectUserInfo = 1;
		retval = S_REQUEST_EVENTS;
	}
	shmp->process_info.funnel = 0;

	
	return retval;
}

int
ReleaseContinue(u_short portid)
{
	int retval;
	_state_data  *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("ReleaseContinue");

	shmp += portid;
	retval = shmp->process_info.state;
	
	if(shmp->process_info.roamingFlag)
	{
		if(shmp->process_info.funnel ++ <
				ppsParam.serviceControl.delay_timer_for_roaming)
			return retval;
	}
	shmp->process_info.funnel = 0;  
	shmp->process_info.down = 0;

	if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL &&
		shmp->process_info.callConnected == 1) /* added on 04-12-16, 
			for VoiceBox maintenance & Call forward to VMS need not to connect SRF */
	{
		if(!GetCRDDestination((char *)shmp->caller_info.number,
								shmp->process_info.tmpDigits,
								SRV_CRD-SRV_CRD)) 
		{
			return (retval = S_SEND_RELEASE_CALL);
		}	
		if(logMsgFlag & 0x01 || shmp->process_info.logMsisdn)
        	{
			DebugMsg(debugmib.display.asciiOut,"VMS conv: %s -> %s",
					shmp->caller_info.number, shmp->process_info.tmpDigits);
		}
		
		SendConnectForVMSService(portid);
		if(shmp->caller_info.status == T_EXTERNAL)
		{
			SendScfTcEND(portid);
			return (retval = S_RELEASE_ALL);
		}
	}
	else if(shmp->process_info.serviceType == SRV_CALLINGCARD_MANAGE)
	{/*calling card		*/
		if(logMsgFlag & 0x01 || shmp->process_info.logMsisdn)
        	{
			DebugMsg(debugmib.display.asciiOut,"Calling Card conv: %s -> %s",
					shmp->caller_info.number, shmp->process_info.tmpDigits);
		}	
		SendConnectForVMSService(portid);
		retval = S_WAITINGFOR_ANSWERED;
	}
	else if(shmp->process_info.routing_home_flag == 1)
	{
		if(logMsgFlag & 0x01 || shmp->process_info.logMsisdn)
        	{
			DebugMsg(debugmib.display.asciiOut,"[%04d] %s, routing home =%d",
				portid, __FUNCTION__, shmp->process_info.routing_home_flag);
		}	

		SendConnectForVMSService(portid);
	}	
	else
	{
		SendContinue(portid);
	}
	
	shmp->process_info.sub_state = 0;

	if(shmp->process_info.answerWanted)
	{
		retval = S_WAITINGFOR_ANSWERED;
	}
	else
	{	
		retval = S_WAITINGFOR_EVENTS;
	}
	return retval;
}

int
RequestBCSMEvent(u_short portid)
{
	int retval;
	_state_data *shmp;

	PutLogFunID("RequestBCSMEvent");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
   //SendApplyCharging(portid);
   //retval = ReleaseContinue(portid);

	if(shmp->process_info.playAnnouncement ||
		shmp->process_info.promptAndCollectUserInfo ||
		shmp->process_info.pre_warning)
	{
		if(	shmp->process_info.serviceType == SRV_CRD ||
			shmp->process_info.serviceType == SRV_DIRECT_ACCESS ||
			shmp->process_info.serviceType == SRV_RESERVED_FUN ||
			shmp->process_info.serviceType == SRV_OTHER_VMS_MAITENANCE ||
			shmp->process_info.serviceType == SRV_VMS_DEPOSIT)
		{
			if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
				SendPreWarningRequestBCSMEvent(portid);
		}
		else
				SendPreWarningRequestBCSMEvent(portid);			
		retval = S_ESTABLISH_TEMPORARY_CONNECTION;
	}
	else
	{
		/*
		if(shmp->caller_info.head>=MSISDN_HEAD_NUM &&
			ppsParam.serviceControl.vms_allways_go			
			)
		{
			SendPreWarningRequestBCSMEvent(portid);			
			retval = S_ESTABLISH_TEMPORARY_CONNECTION;
			return retval;	
		}
		*/
		SendRequestBCSMEvent(portid);
		if(shmp->context_info.acn_ver>=1) /* CAP V2 and above */
 			retval = S_APPLY_CHARGING;
		else
			retval = S_SEND_CONTINUE;
	}
	return retval;
}


int
WaitingforAnsweredProc(u_short portid)
{
	_state_data  	*shmp=(_state_data *)&smshm_ptr->state_data;
	DWORD        	instance = 0;
	int           	retval, release_flag = 0x00,tcend_flag=0;
	int           	dlgid,msglen,edpr, valid_time=0;
	CAP_Message   	capmsg;
	struct        	CapArg capArg;
	CHARGED_FEE		chargedFee;
	char			 error[32];

	PutLogFunID("WaitingforAnsweredProc");

	shmp += portid;

	dlgid  = shmp->context_info.dialogue_id;

	retval = shmp->process_info.state;
	if (shmp->process_info.funnel >= pps_get_answer_timer_out()) //WAITINGFOR_ANSWERED_DELAY )
	{
		shmp->process_info.tcos = NO_ANSWER;
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if(logMsgFlag & 0x01 || shmp->process_info.logMsisdn)
        	{
			debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,"P/DID: Wait for answer timeout!"
					,portid,dlgid);
		}

		SendReleaseCall(portid);

		if(shmp->process_info.ro_if.adaptor_enabled == 1)
		{
		
			shmp->process_info.sub_state = 0;							
			retval = S_RO_CALL_TERMIATED;
		}
		else
		{
			retval = S_RELEASE_ALL;
		}

		return retval;
	}
	
	shmp->process_info.funnel ++;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

	if(capmsg.msgOperaCode != CAP_OC_EventReportBCSM)
	{
	   if(capmsg.msgOperaCode != CAP_OC_ApplyChargingReport)
	   {
			shmp->process_info.tcos = NETWORK_OUT_OF_ORDER;
#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if(logMsgFlag & 0x04 || logMsgFlag & 0x01 ||  shmp->process_info.logMsisdn)
		   {
			  debug_messages ++;
			  DebugMsgDelimiter();
			  DebugMsg(debugmib.display.asciiOut,
			  "Warning: pid=%d did=%d  '%s' received (Waiting for ANSWER)",
			  portid,dlgid,GetCapError(error,capmsg.msgOperaCode));
			  ppsDebugCapMsg(&capmsg,0);
		   }
#endif

			SendReleaseCall(portid);

			if(shmp->process_info.ro_if.adaptor_enabled == 1)
			{
				shmp->process_info.sub_state = 0;							
				retval = S_RO_CALL_TERMIATED;
			}
			else
			{
//				SendReleaseCall(portid);
				retval = S_RELEASE_ALL;
			}

//			SendReleaseCall(portid);
//			retval = S_RELEASE_ALL;
			return retval;
	  }
	  else
	  {
	     AddPPSStatistics(MIBPPS_CHARGINGREPORT,shmp->process_info.dir);
		#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES){
			 if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			 {  
				debug_messages ++;
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,"[%04d] EventReportBCSM Received! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
			 }
			 if((logMsgFlag & 0x02 )|| shmp->process_info.logMsisdn )
			 {
				debug_messages ++;
				ppsDebugCapMsg(&capmsg,0);
			 }
			}
		 #endif
		 return retval;
	   }
    }
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	   debug_messages ++;
	    DebugMsgDelimiter();
		DebugMsg(debugmib.display.asciiOut,"portid=%d, dlgid=%d EventReportBCSM Received! (%ld.%ld)",
		portid,shmp->context_info.dialogue_id,tvnow.tv_sec,tvnow.tv_usec);
	}
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn )
	{
	   debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif
	msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
    
	capArg.version = shmp->context_info.acn_ver;
    
	if(decode_capmsg((char *)&capmsg.msgContent[5],
				   msglen,
				   capmsg.msgOperaCode,
				   CAP_CONFIRM,
				   &capArg)<0)
			return retval;
	edpr = capArg.msg_list.eventReportBCSMArg.eventTypeBCSM;
	switch(edpr)
	{
		case capp_routeSelectFailure:
			release_flag = 0x01;
			//tcend_flag = 0x01;
			shmp->process_info.tcos = NO_ROUTE;
		break;
		case capp_oCalledPartyBusy:
		case capp_tBusy:
			release_flag = 0x01;
			shmp->process_info.tcos = USER_BUSY;
		break;
		case capp_oNoAnswer:
		case capp_tNoAnswer:
			release_flag = 0x01;
			shmp->process_info.tcos = NO_ANSWER;
		break;
		case capp_oAbandon:
		case capp_tAbandon:	 
			release_flag = 0x01;
			//tcend_flag = 0x01;
			shmp->process_info.tcos = CALL_REJECTED;
		break;
		case capp_oAnswer:
		case capp_tAnswer:
		#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				DebugMsg(debugmib.display.asciiOut,"portid=%d EventReportBCSM (Answered)!",portid);
			}
		#endif

			shmp->cdr_info.answertime = tvnow.tv_sec;
			shmp->process_info.duration = 0;
			shmp->process_info.down = 0;
			shmp->process_info.funnel = 0;

			AddPPSStatistics(MIBPPS_ANSWERED,shmp->process_info.dir);
			retval = S_WAITINGFOR_EVENTS;  

			if(shmp->process_info.ro_if.adaptor_enabled)
			{
				shmp->process_info.ro_if.recv_cmd = 1;
				shmp->process_info.ro_if.result = 1;
				return retval;
			}
			
			if(shmp->process_info.serviceKey != 1)
			{
				shmp->caller_info.charge += shmp->caller_info.fee;
				shmp->called_info.charge += shmp->called_info.fee;
			 
				if(shmp->context_info.callType == CT_MT_CALL \
					&& (shmp->called_info.fee !=0 \
						|| shmp->process_info.bundle_flag))
				{
					UpdateBalance(shmp,&shmp->called_info, -(shmp->called_info.fee),&chargedFee);
					instance = shmp->called_info.head * UNIT_STORE_ACCOUNT 
								+ shmp->called_info.tail;
					if(shmp->process_info.cap_flag)
					{
							UpdateSubsCapInfo(
								&shmp->called_info,
								0,
								(shmp->called_info.fee),
								shmp->called_info.valid_time/CYCLE_STATE_INTERVAL,
								shmp);
					} 
					if(shmp->process_info.bundle_flag)
					{
						int valid_time = shmp->called_info.valid_time/CYCLE_STATE_INTERVAL;
						//DebugMsg(debugmib.display.asciiOut, "WaitingforAnsweredProc()->%s update bundle mt valid time[%d]",
						//				shmp->called_info.number, -valid_time);
						pps_update_account_bundle_mt_voice(shmp, -valid_time);
					}

					SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT);
				}
				else if(shmp->caller_info.status != T_EXTERNAL \
						&& (shmp->caller_info.fee != 0 \
							|| shmp->process_info.bundle_flag))
				{
					UpdateBalance(shmp,&shmp->caller_info, -(shmp->caller_info.fee),&chargedFee);
					instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
								+ shmp->caller_info.tail;
					if(shmp->process_info.cap_flag)
					{
							UpdateSubsCapInfo(
								&shmp->caller_info,
								0,
								(shmp->caller_info.fee),
								shmp->caller_info.valid_time/CYCLE_STATE_INTERVAL,
								shmp);
					} 
					if(shmp->process_info.bundle_flag)
					{
						valid_time = shmp->caller_info.valid_time/CYCLE_STATE_INTERVAL;
						pps_update_account_bundle_mo_voice(shmp, -valid_time);
					}
					
					SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT); 		 
				}

				if((shmp->process_info.rest_if.total_plan_value>0)
					&& (shmp->caller_info.free_flag == 0))
				{
					valid_time = shmp->caller_info.valid_time/CYCLE_STATE_INTERVAL;
					shmp->process_info.rest_if.used_plan_value += valid_time;
					//
					shmp->process_info.rest_if.plan_value_add_this_time = valid_time;
					pps_send_update_plan_value_req(portid);
				}
				if (shmp->caller_info.free_flag == 1)
				{
					shmp->caller_info.free_flag = 0;
				}
			}
		break;
		case capp_oDisconnect:
		case capp_tDisconnect:
			//if(capArg.msg_list.eventReportBCSMArg.legID == 0x01) //calling party
			//	tcend_flag = 0x01;
			release_flag = 0x01;
			shmp->process_info.tcos = edpr;
		break;
		default:
			release_flag = 0x01;
			shmp->process_info.tcos = NETWORK_OUT_OF_ORDER;
			#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if(logMsgFlag & 0x04 || logMsgFlag & 0x01 )
			{
				debug_messages ++;
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,
						"Warning: pid=%d did=%d Error Message %d,edpr:%d (Waiting for ANSWER)",
						dlgid,shmp->context_info.dialogue_id,capmsg.msgOperaCode,edpr);
				ppsDebugCapMsg(&capmsg,0);
			}
			#endif
		break;
	}/* switch */
		
	if(release_flag)
	{
		if(tcend_flag)
		{
			SendScfTcEND(portid);
			retval = S_RELEASE_ALL;
		}			
		else
		{
			SendReleaseCall(portid);

			if(shmp->process_info.ro_if.adaptor_enabled == 1)
			{
				shmp->process_info.sub_state = 0;							
				retval = S_RO_CALL_TERMIATED;
			}
			else
			{
				retval = S_RELEASE_ALL;
			}
		}
		return retval;
	}
    
	return retval;
}

void ChargeAccountByRealCallDuration(u_short portid)
{
	_account_info	*account_ptr;
	int				instance;
	_state_data		*shmp=(_state_data *)&smshm_ptr->state_data;
	CHARGED_FEE		chargedFee;
		
	PutLogFunID("ChargeAccountByRealCallDuration");

	shmp += portid;

	switch(shmp->context_info.callType)
	{
		case CT_MT_CALL:
			account_ptr = &shmp->called_info;
		break;
		default:
			account_ptr = &shmp->caller_info;
		break;
	}

	if(shmp->process_info.realCallDuration != 0)
	{
		shmp->process_info.realCallDuration /= 10; /* in 100ms intervals */
		account_ptr->charge = ChargeGprsAccountBalance(shmp,shmp->process_info.realCallDuration);

		shmp->cdr_info.releasetime = shmp->cdr_info.answertime + 
						shmp->process_info.realCallDuration;
		shmp->process_info.duration = 
			(shmp->process_info.realCallDuration * CYCLE_STATE_INTERVAL);
	}
	else
	{
		account_ptr->charge = ChargeGprsAccountBalance(shmp,shmp->process_info.duration/CYCLE_STATE_INTERVAL);

		shmp->cdr_info.releasetime = shmp->cdr_info.answertime + 
						shmp->process_info.duration/CYCLE_STATE_INTERVAL;
	}
	UpdateBalance(shmp,account_ptr,-(account_ptr->charge),&chargedFee);
	instance = account_ptr->head * UNIT_STORE_ACCOUNT 
				  + account_ptr->tail;	
	SendCDR(portid);	
	SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT);
}

int
WaitingForEventsReport(u_short portid)
{
	int         		retval, release_flag = 0x00,tcend_flag=0x00, valid_time=0;
	int         		dlgid,msglen, instance = 0,edpr,update_flag=0;
	CAP_Message 		capmsg;
	struct      		CapArg capArg;
	CHARGED_FEE			chargedFee;
	
	_state_data *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("WaitingForEventsReport");

	shmp += portid;
	retval = shmp->process_info.state;


	dlgid  = shmp->context_info.dialogue_id;

	if (shmp->process_info.funnel >= ACTIVITY_TEST_DELAY )
	{
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn )
		{  
			debug_messages ++;
			DebugMsgDelimiter();
			DebugMsg(debugmib.display.asciiOut,"portid=%d ActivityTest missed! (%ld.%ld)",
					portid,tvnow.tv_sec,tvnow.tv_usec);
		}
#endif
		shmp->process_info.tcos = ACTIVITY_MISSED;
		shmp->cdr_info.releasetime = tvnow.tv_sec;

		if(shmp->process_info.serviceKey == 1)
		{
			ChargeAccountByRealCallDuration(portid);
		}
		else
		{
		       if(shmp->process_info.favoriteCall == FRIEND_FAMILY_FREE_CALL){
		       	IncreaseFriendFamilyFreeCallDuration(shmp->caller_info.head, 
		       	    shmp->caller_info.tail, 
		       	    shmp->process_info.duration);
		       }
			SendCDR(portid);
		}

		SendReleaseCall(portid);

		if(shmp->process_info.ro_if.adaptor_enabled == 1)
		{
			shmp->process_info.sub_state = 0;							
			retval = S_RO_CALL_TERMIATED;
		}
		else
			retval = S_RELEASE_ALL;
		
		return (retval);
	}

	if(ReadScfMsg(&capmsg,dlgid))
	{
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
		   debug_messages ++;
		   ppsDebugCapMsg(&capmsg,0);
		}
#endif
		if(capmsg.msgOperaCode == CAP_OC_ActivityTest ) 
		{
			if(capmsg.msgContent[2] != 0x03)
			{
				shmp->process_info.funnel = 0;
				AddPPSStatistics(MIBPPS_ACTIVITYR,shmp->process_info.dir);
				#if DEBUG
					if(debug_messages<=MAX_DEBUG_MESSAGES)
					if((logMsgFlag & 0x04) ||
						(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
					{  
						debug_messages ++;
						DebugMsgDelimiter();
						DebugMsg(debugmib.display.asciiOut,
							"portid=%d ActivityTest Received! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
					}
				#endif
			}
		}
		else if(capmsg.msgOperaCode == 251) //notice 
		{
			shmp->process_info.funnel = 0;
			#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					debug_messages ++;
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"portid=%d Notice Received while waiting for ACT! (%ld.%ld)",
							portid,tvnow.tv_sec,tvnow.tv_usec);
				}
			#endif
		}
		else if(capmsg.msgOperaCode == CAP_OC_ApplyChargingReport 
						/* charging report */
			|| capmsg.msgOperaCode == CAP_OC_EventReportBCSM) 
				/* bcsm event report */
		{
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
						   msglen,
						   capmsg.msgOperaCode,
						   CAP_CONFIRM,
						   &capArg)<0)
			{
				#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
									"portid=%d Decode failed OC=%d",
					portid,capmsg.msgOperaCode);
				}
				#endif
				return retval;					
			}
			
			if(capmsg.msgOperaCode == CAP_OC_ApplyChargingReport)
			{
				#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					debug_messages ++;
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"portid=%d ApplyChargingReport Received! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
				}
				#endif
				 /* charging time control */
				if(capArg.msg_list.applyChargingReportArg.callActive)
				{
					if(	shmp->process_info.ro_if.adaptor_enabled == 1)
					{
						if(shmp->process_info.ro_if.granted_value>0)
							SendApplyCharging(portid);
					}
					else
							SendApplyCharging(portid);

				}
				if(shmp->process_info.serviceKey ==1)
				{
					shmp->process_info.realCallDuration += 
						capArg.msg_list.applyChargingReportArg.timeInformation.timeIfNoTariffSwitch;
				}

				AddPPSStatistics(MIBPPS_CHARGINGREPORT,shmp->process_info.dir);
			}

			if(capmsg.msgOperaCode == CAP_OC_EventReportBCSM)
			{
				#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					debug_messages ++;
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"portid=%d EventReportBCSM Received (disconnect)! (%ld.%ld)",
							portid,tvnow.tv_sec,tvnow.tv_usec);
				}
				#endif

				edpr = capArg.msg_list.eventReportBCSMArg.eventTypeBCSM;
				switch(edpr)
				{
					/*
				   case capp_routeSelectFailure:
						release_flag = 0x01;
						tcend_flag = 0x01;
						shmp->process_info.tcos = NO_ROUTE;
					break;		   
					case capp_oCalledPartyBusy:
					case capp_tBusy:
						release_flag = 0x01;
						shmp->process_info.tcos = USER_BUSY;
					break;
					case capp_oNoAnswer:
					case capp_tNoAnswer:
						release_flag = 0x01;
						shmp->process_info.tcos = NO_ANSWER;
					break;
					case capp_oAbandon:
					case capp_tAbandon:
						release_flag = 0x01;
						shmp->process_info.tcos = CALL_REJECTED;
					break;
				   */
					case capp_oDisconnect:
					case capp_tDisconnect:
					default:
					 //if(capArg.msg_list.eventReportBCSMArg.legID == 0x01)
					//	tcend_flag = 0x01;
						release_flag = 0x01;
						shmp->process_info.tcos = edpr;
						AddPPSStatistics(MIBPPS_DISCONNECT,shmp->process_info.dir);
						shmp->cdr_info.releasetime = tvnow.tv_sec;
					break;
				}/* switch */

				if(release_flag)
				{
					if(tcend_flag)
						SendScfTcEND(portid);
					else
						SendReleaseCall(portid);
					shmp->cdr_info.releasetime = tvnow.tv_sec;

					if(shmp->process_info.serviceKey == 1)
					{
						ChargeAccountByRealCallDuration(portid);
					}
					else
					{
					       if(shmp->process_info.favoriteCall == FRIEND_FAMILY_FREE_CALL)
     		       	                    IncreaseFriendFamilyFreeCallDuration(shmp->caller_info.head, 
                        		       	    shmp->caller_info.tail, 
		                             	    shmp->process_info.duration);
						SendCDR(portid);
					}
					
					if(shmp->process_info.ro_if.adaptor_enabled == 1)
					{
						shmp->process_info.sub_state = 0;					
						retval = S_RO_CALL_TERMIATED;
					}
					else
						retval = S_RELEASE_ALL;
					return retval;
				}
			}
		}
		else
		{
			shmp->process_info.tcos = INVALID_MESSAGE;
			shmp->cdr_info.releasetime = tvnow.tv_sec;
			if(shmp->process_info.serviceKey == 1)
			{
				ChargeAccountByRealCallDuration(portid);
			}
			else
			{
			        if(shmp->process_info.favoriteCall == FRIEND_FAMILY_FREE_CALL)
     		       	                    IncreaseFriendFamilyFreeCallDuration(shmp->caller_info.head, 
                        		       	    shmp->caller_info.tail, 
		                             	    shmp->process_info.duration);
				SendCDR(portid);
			}

			SendReleaseCall(portid);
			if(shmp->process_info.ro_if.adaptor_enabled == 1)
				retval = S_RO_CALL_TERMIATED;
			else
				retval = S_RELEASE_ALL;
			
			return retval;
		}
	}/* ReadScfMsg */


	if(OCS_with_external_CRM())//query tariff from CRM database
	{
		if(shmp->caller_info.valid_time == CYCLE_STATE_INTERVAL)
		{
			pps_send_query_tariff_req(portid);
		}
	}
	
	if(shmp->process_info.serviceKey != 1 && shmp->process_info.ro_if.adaptor_enabled == 0)
	{
	
		if (shmp->caller_info.valid_time <= 0      /*  Acquire next call period */
			|| shmp->called_info.valid_time <= 0) 
		{ 
			if(OCS_with_external_CRM())//query tariff from CRM database
				BillingProc_crm(shmp, FALSE);				
			else		
				BillingProc(shmp, FALSE);
	#if DEBUG1
			DebugMsg(debugmib.display.asciiOut,"Charge fee: caller=%f, called=%f", 
					 shmp->caller_info.fee,shmp->called_info.fee);
	#endif
			shmp->caller_info.charge += shmp->caller_info.fee;
			shmp->called_info.charge += shmp->called_info.fee;
			if((shmp->context_info.callType == CT_MT_CALL))
			{
				if((shmp->called_info.fee != 0 ))
				{
					UpdateBalance(shmp,&shmp->called_info, -(shmp->called_info.fee),&chargedFee);
					update_flag = 1;
				}
				if(shmp->process_info.cap_flag)
				{
					UpdateSubsCapInfo(
						&shmp->called_info,
						0,
						(shmp->called_info.fee),
						shmp->called_info.valid_time/CYCLE_STATE_INTERVAL,
						shmp);
					update_flag = 1;
				}
				if(shmp->process_info.bundle_flag)
				{
					int valid_time = shmp->called_info.valid_time/CYCLE_STATE_INTERVAL;
					//DebugMsg(debugmib.display.asciiOut, "WaitingForEventsReport()->%s update bundle mt valid time[%d]",
					//				shmp->called_info.number, -valid_time);
					pps_update_account_bundle_mt_voice(shmp, -valid_time);
					update_flag = 1;
				}


				if(update_flag)
				{
					instance = shmp->called_info.head * UNIT_STORE_ACCOUNT 
							   + shmp->called_info.tail;
					SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT);
				}
			}else if((shmp->caller_info.status != T_EXTERNAL) )
			{
				if((shmp->caller_info.fee != 0))
				{
					UpdateBalance(shmp,&shmp->caller_info, -(shmp->caller_info.fee),&chargedFee);
					update_flag = 1;
				}
				if(shmp->process_info.cap_flag)
				{
					UpdateSubsCapInfo(
						&shmp->caller_info,
						0,
						(shmp->caller_info.fee),
						shmp->caller_info.valid_time/CYCLE_STATE_INTERVAL,
						shmp);
					update_flag = 1;
				} 
				if(shmp->process_info.bundle_flag)
				{
					valid_time = shmp->caller_info.valid_time/CYCLE_STATE_INTERVAL;
					//DebugMsg(debugmib.display.asciiOut, "WaitingForEventsReport()->%s update bundle mo valid time[%d]",
					//				shmp->caller_info.number, -valid_time);
					pps_update_account_bundle_mo_voice(shmp, -valid_time);
					update_flag = 1;
				}

				if(update_flag)
				{
					instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
						   + shmp->caller_info.tail;
					SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT);
				}

				if(shmp->process_info.rest_if.total_plan_value>0 && shmp->process_info.rest_if.used_plan_value < shmp->process_info.rest_if.total_plan_value)
				{
					valid_time = shmp->caller_info.valid_time/CYCLE_STATE_INTERVAL;
					shmp->process_info.rest_if.used_plan_value += valid_time;
					shmp->process_info.rest_if.plan_value_add_this_time = valid_time;
					pps_send_update_plan_value_req(portid);
				}
				
			}
		}

		if (shmp->caller_info.valid_time <= 0
					|| shmp->called_info.valid_time <= 0) 
		{ 
			shmp->cdr_info.releasetime = tvnow.tv_sec;
			if(shmp->process_info.tcos != CALLER_REACH_CHARGE_LIMIT)
			{
				if(shmp->context_info.callType == CT_MT_CALL){
					shmp->process_info.tcos = CALLED_CREDIT_OUT;
					/*
					SendAccountInfoForLowCredit(shmp->called_info.number, 
						   (int)GetBalance(&shmp->called_info),
							GetExpiration(&shmp->called_info)); 
					*/
				}else{
					shmp->process_info.tcos = CALLER_CREDIT_OUT;
					/*
					SendAccountInfoForLowCredit(shmp->caller_info.number, 
						   (int)GetBalance(&shmp->caller_info),
							GetExpiration(&shmp->caller_info)); 
					*/
				}
			}

			 if(shmp->process_info.favoriteCall == FRIEND_FAMILY_FREE_CALL)
     		       	                    IncreaseFriendFamilyFreeCallDuration(shmp->caller_info.head, 
                        		       	    shmp->caller_info.tail, 
		                             	    shmp->process_info.duration);
			 
			SendCDR(portid);
			SendReleaseCall(portid); 

			return (retval = S_RELEASE_ALL);
		}

		shmp->caller_info.valid_time --;
		shmp->called_info.valid_time --;

	}

	if(shmp->process_info.ro_if.adaptor_enabled == 1)
	{
		shmp->caller_info.valid_time --;
		shmp->called_info.valid_time --;
	
		if(shmp->process_info.ro_if.is_final == 0 &&
			shmp->process_info.ro_if.no_more_ccr != 1)
		{
			if(shmp->caller_info.valid_time < 3* CYCLE_STATE_INTERVAL ||
				shmp->process_info.sub_state>0)
			{
				int ccr_result = 0;
				switch(shmp->process_info.sub_state)
				{
					case 0:
						shmp->process_info.ro_if.request_type = RT_UPDATE_REQUEST;
						pps_ro_adaptor_call_init(portid);
						shmp->process_info.sub_state = 1;
					break;
					case 1:
						ccr_result = pps_ro_call_wait_first_cca(portid);
						
						if(shmp->process_info.ro_if.recv_cmd == 1)
							shmp->process_info.sub_state = 0;
						if(ccr_result == -1)
						{
							shmp->process_info.ro_if.no_more_ccr = 1;
							shmp->process_info.sub_state = 0;							
							/*
							SendCDR(portid);
							SendReleaseCall(portid); 
							if(shmp->process_info.ro_if.adaptor_enabled == 1)
								retval = S_RO_CALL_TERMIATED;
							else
								retval = S_RELEASE_ALL;
							return retval;
							*/
						}						 
					break;
					case 2:
						shmp->process_info.sub_state = 0;						
					break;
				}
			}
		}

		if(shmp->caller_info.valid_time<=0)
		{
			SendCDR(portid);
			SendReleaseCall(portid); 
			shmp->process_info.sub_state = 0;									
			retval = S_RO_CALL_TERMIATED;

			if((logMsgFlag & 0x04) || 
				(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,
					"portid=%d quota used up, release call! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
			}

			/*
			if(shmp->process_info.ro_if.adaptor_enabled == 1)
				retval = S_RO_CALL_TERMIATED;
			else
				retval = S_RELEASE_ALL;
			*/
			return retval;
		}
		
	}
	
	shmp->process_info.down ++ ;
	if(shmp->process_info.down >=send_activitytest_timer) //SEND_ACTIVITYTEST_PERIODIC)
	{
		shmp->process_info.down = 0;
		SendActivityTest(portid);     
	}
	shmp->process_info.funnel ++;

	shmp->process_info.duration ++;
	if(shmp->process_info.duration>ppsParam.max_call_duration*50)
	{
	    if(shmp->process_info.send_warning_sms_flag == 0)
	    {
	        char warning_message[256];
	        
	        shmp->process_info.send_warning_sms_flag = 1;

	        sprintf(warning_message, "call duration exceed MAX call duration %d minutes, caller=%s, called=%s, port id=%d",
	        	ppsParam.max_call_duration, shmp->caller_info.number, shmp->called_info.number, portid);

	        sendPPSTestShortMessage(warning_message);
	    }
	}
	return retval;
}

void SetActivityTestTimer(char timer)
{
	send_activitytest_timer = timer * 20 ;
}
/* ------------------------------ */
static int SendSMSMNP_ATI(u_short portid)
{
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	shmp += portid;	
	
	shmp->process_info.mnp_status = 0;
	SendMNP_ATI(portid);
	shmp->process_info.funnel = 0;
	
	return S_SMS_WAIT_MNP_ATI_RES;

}				

static int WaitingForSMSMNP_ATI_Res(u_short portid)
{
	return WaitingForMNP_ATI_Res(portid);
}

static int
CheckSMSValidity(u_short portid)
{
	int retval ;
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("CheckSMSValidity");

	shmp += portid;
	retval = shmp->process_info.state;


	if(OCS_with_external_CRM())//query tariff from CRM database
	{
		if(shmp->process_info.rest_if.query_tariff_status < 2)
		{
			if(shmp->process_info.funnel ++ > SSHORT_DELAY_TIMER)
			{
				goto CHECK_SMS_TARIFF_NOT_SET;
			}
			else
				return (retval = S_SMS_CHECK_VALIDITY);				
		}
		else
		{
			if(shmp->process_info.rest_if.query_tariff_status == 3)
				goto CHECK_SMS_TARIFF_NOT_SET;				
		}
		
	}
	
	BillingSMSProc(shmp, 1);

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				DebugMsg(debugmib.display.asciiOut,
					"tariff id: %d, charged prefix: %s ", 
					shmp->caller_info.location,shmp->charge_info.number);
	}	
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
	{
		DebugMsg(debugmib.display.asciiOut,
			"cap SM flag: %d",shmp->process_info.cap_flag);
	}
			   
	if (IsEnableToCall(portid) ) 
	{
		retval = S_REQUEST_SMS_EVENTS;
	}
	else
	{
		if(shmp->process_info.serviceKey == 11)
		{
			if(shmp->caller_info.status == T_EXTERNAL)
			{
				retval = S_REQUEST_SMS_EVENTS;
				return retval;		
			}
		}
		
		SendReleaseSMS(portid);
		retval = S_RELEASE_ALL;
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x01) )
		{	   
			DebugMsgDelimiter();
			switch(shmp->process_info.tcos)
			{
				case CALLER_EXPIRIED:
					DebugMsg(debugmib.display.asciiOut,
					"\33[31mCaller is expired , Send SM failed!\33[0m");
				break;
				case CALLER_CREDIT_OUT:
					DebugMsg(debugmib.display.asciiOut,
					"\33[31mCaller is out of balance , Send SM failed!\33[0m");
				break;
				case CALLER_REACH_SMS_LIMIT:
					DebugMsg(debugmib.display.asciiOut,
					"\33[31mCaller is a child,reaching Max SMS limit today, Send SM failed!\33[0m");
				break;
				case CALLER_REACH_CHARGE_LIMIT:
					DebugMsg(debugmib.display.asciiOut,
					"\33[31mCaller is a child,reaching Max fee charge limit today, Send SM failed!\33[0m");
				break;
			}
		}
	#endif
	}

	return retval;	

CHECK_SMS_TARIFF_NOT_SET:
	shmp->process_info.tcos = TARIFF_NOT_SET;			
	SendReleaseSMS(portid);

	return (retval = S_RELEASE_ALL);
	
}

static int
RequestSMSEvents(u_short portid)
{
   int retval;

	PutLogFunID("RequestSMSEvents");

   SendRequestSMSEvents(portid);
   
   //SendContinueSMS(portid);

   //retval = S_WAITINGFOR_SMS_EVENTS;
   retval = S_RELEASE_SMS_CONTINUE;
   return retval;
}

int ReleaseContinueSMS(u_short portid)
{
   int retval;

//   SendRequestSMSEvents(portid);
   	PutLogFunID("ReleaseContinueSMS");

   SendContinueSMS(portid);

   retval = S_WAITINGFOR_SMS_EVENTS;
   return retval;

}

static int
WaitingForSMSEvents(u_short portid)
{
	int					retval,release_flag = 0x00;
	int					dlgid,msglen, instance = 0;  
	_state_data 		*shmp=(_state_data *)&smshm_ptr->state_data;
	CAP_Message			capmsg;
 	struct	CapArg		capArg;
	CHARGED_FEE			chargedFee;

	PutLogFunID("WaitingForSMSEvents");

	shmp += portid;
 	retval = shmp->process_info.state;

   
 	dlgid  = shmp->context_info.dialogue_id;

 	if (shmp->process_info.funnel >= ACTIVITY_TEST_DELAY )
 	{
  		shmp->process_info.tcos = ACTIVITY_MISSED;
		SendReleaseSMS(portid);
		return (retval = S_RELEASE_ALL);
	}

	if(ReadScfMsg(&capmsg,dlgid))
	{
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
  		if(logMsgFlag & 0x02)
		{
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
#endif
  		if(capmsg.msgOperaCode == CAP_OC_ActivityTest ) 
		{
			if(capmsg.msgContent[2] != 0x03)
			{
				shmp->process_info.funnel = 0;
				AddPPSStatistics(MIBPPS_ACTIVITYR,shmp->process_info.dir);
			#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
				   debug_messages ++;
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,"[%04d] ActivityTest Received! (%ld.%ld)",
					portid,tvnow.tv_sec,tvnow.tv_usec);
				}
			#endif
			}
		}
		else if(capmsg.msgOperaCode == CAP_OC_EventReportSMS)
 		{
#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
 			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,"[%04d] EventReportSMS Received! (%ld.%ld)",
					portid,tvnow.tv_sec,tvnow.tv_usec);
			}
#endif
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
 			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
				msglen,
				capmsg.msgOperaCode,
				CAP_CONFIRM,
				&capArg)<0)
			{
				retval = S_RELEASE_ALL;
				return retval;
			}		
			
			switch(capArg.msg_list.eventReportSMSArg.eventTypeSMS)
			{
				case capp_osmsFailure:
					release_flag = 0x01;
					shmp->process_info.tcos = NO_ROUTE;
					if(shmp->process_info.ro_if.adaptor_enabled )
					{
						retval = S_RO_SMS_REFUND;
						return retval;
					}
				break;
				case capp_osmsSubmitted:
					release_flag = 0x01;
					shmp->process_info.tcos = NORMAL_CLEARING;
			 		AddPPSStatistics(MIBPPS_REPORT_SMS,shmp->process_info.dir);
			 		shmp->cdr_info.answertime = tvnow.tv_sec;
			 		shmp->cdr_info.seizuretime = tvnow.tv_sec;
					shmp->cdr_info.releasetime = tvnow.tv_sec;

					if(shmp->process_info.ro_if.adaptor_enabled == 0)
					{
						if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
						{
							SendCDR(portid); 						
							SendReleaseSMS(portid);
							retval = S_RELEASE_ALL;
 							return retval;
						}
						
						UpdateBalance(shmp,&shmp->caller_info, -(shmp->caller_info.fee),&chargedFee);
						instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
	 						+ shmp->caller_info.tail;
						if(shmp->process_info.cap_flag)
						{
							UpdateSubsCapInfo(
								&shmp->caller_info,
								1,
								(shmp->caller_info.fee),
								0,
								shmp);
						} 
						if(shmp->process_info.bundle_flag)
						{
							pps_update_account_bundle_mo_sms(shmp, -1);
						}
						
						if(shmp->process_info.favoriteCall == FRIEND_FAMILY_FREE_SMS)
						{
						    IncreaseFriendFamilyFreeSMSCounter(shmp->caller_info.head, shmp->caller_info.tail);
						}

 						SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT);
						
	   					shmp->caller_info.charge = shmp->caller_info.fee;

						if(OCS_with_external_CRM())
						{
							if(shmp->process_info.rest_if.total_plan_value > 0)
							{
								if(shmp->process_info.rest_if.used_plan_value < 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 = 1;
									pps_send_update_plan_value_req(portid);
								}
							}	
						}
							
						if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
						{  
							debug_messages ++;
							DebugMsg(debugmib.display.asciiOut,"mo sms submitted %d, charge: %.2f", 
								shmp->process_info.cap_flag,shmp->caller_info.charge);
						}
					}
					
					SendCDR(portid); 

				break;
				default:
					retval = S_RELEASE_ALL;
				break;
			}/* switch */

			if(release_flag){
				
				SendReleaseSMS(portid);
				retval = S_RELEASE_ALL;
 				return retval;
			}

 		}
	}/* ReadScfMsg */

	/*
	shmp->caller_info.valid_time --;
	if (shmp->caller_info.valid_time <= 0) 
	{ 
        	shmp->cdr_info.releasetime = tvnow.tv_sec;
        	shmp->process_info.tcos = CALLER_CREDIT_OUT;
        	SendReleaseSMS(portid); 
        	SendCDR(portid); 
        	return (retval = S_RELEASE_ALL);
	}
	*/
	
	shmp->process_info.down ++ ;
	if(shmp->process_info.down >=SEND_ACTIVITYTEST_PERIODIC)
	{
		shmp->process_info.down = 0;
		SendActivityTest(portid);     
	}
	shmp->process_info.funnel ++;
	
	return retval;
}




int
ConferenceRequest(u_char oidLen, DWORD *oid,u_char *pdata,u_short dataLen)
{
   	int         			duration,instance,caller_status;
   	int	    		 		proc_id;
   	_state_data 			*shmp;
   	u_char      			calledbuf[32]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
	CHARGED_FEE				chargedFee;
	
   if(dataLen < 19) return 0;
   
	PutLogFunID("ConferenceRequest");

   proc_id = AssignProcID(0);
   if(proc_id>=MAX_FSM_PROCESS || proc_id<0) return 0;

   shmp = (_state_data *)&smshm_ptr->state_data;
   shmp += proc_id;
 
   duration = pdata[16] + pdata[17]*256;

   memcpy(shmp->cdr_info.caller,&pdata[8], 8);
   ppsBcdToAsciiR((char *)shmp->caller_info.number, &pdata[8], 16);
   StringCut((char *)shmp->caller_info.number, 'F');
   StringCut((char *)shmp->caller_info.number, 'E');
   memcpy(shmp->caller_info.IMSI, pdata, 8);
   memcpy(shmp->cdr_info.called,calledbuf,8);
   
   //CheckWetherLocalNumber(shmp->caller_info.number); 
            
   GetAccountPos(&shmp->caller_info);
   
   caller_status = GetAccountStatus(&shmp->caller_info);
   
   shmp->caller_info.charge = 0;
   shmp->caller_info.fee = 0;
   shmp->process_info.tcos = NORMAL_CLEARING;
   shmp->caller_info.status = caller_status;
   shmp->process_info.duration = duration*CYCLE_STATE_INTERVAL;
   shmp->cdr_info.seizuretime = tvnow.tv_sec;
   shmp->cdr_info.answertime = tvnow.tv_sec;
   shmp->cdr_info.releasetime = tvnow.tv_sec;
   shmp->context_info.callType = CT_CONFERENCE_CALL;
   SetCallType(shmp,CT_CONFERENCE_CALL);
   
   pdata[18] = 0x01;
 
   shmp->process_info.logMsisdn = 0x00;
			
   if(logMsgFlag & 0x08){
	 if(strstr((char *)shmp->caller_info.number, logMsisdn)){
	     shmp->process_info.logMsisdn = 0x01;
	 }
   }

#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
	    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
		   debug_messages ++;
			DebugMsgDelimiter();
			DebugMsg(debugmib.display.asciiOut,"Conference call: ");
			DebugMsg(debugmib.display.asciiOut,"Duration: %d seconds",duration);
			DebugMsg(debugmib.display.asciiOut,"Caller info : %s (%d %d) status:%d,balance: %.1f", 
                            shmp->caller_info.number,
                            shmp->caller_info.head,
                            shmp->caller_info.tail,
							caller_status,
                            GetBalance(&shmp->caller_info));
    }
#endif

   if(!ConferenceCallBillingProc(shmp,duration)){      
      pdata[18] = 0x00;
      ReleasePortStatus(proc_id);
      return dataLen;
   }

#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
	    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
		   debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,"Caller calltype: %d fee: %.0f", 
                        shmp->process_info.call_type,
                        shmp->caller_info.fee);
		}
#endif
  UpdateBalance(shmp,&shmp->caller_info, -(shmp->caller_info.fee),&chargedFee);
  instance = 
           shmp->caller_info.head * UNIT_STORE_ACCOUNT 
           + shmp->caller_info.tail;
  SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT); 
  SendCDR(proc_id);
  ReleasePortStatus(proc_id);           
  AddPPSStatistics(MIBPPS_CONFERENCE,0);
  return dataLen;
}

int thirdPartyChargeProc(snmp_pdu *pdu, snmp_addr *addr)
{
	int			charge=0,instance,caller_status,datalen;
	int			proc_id,operation_type,
				result,loop,vallen,/*msisdnlen,*/
				dataLen;
	u_short		ptagcode;
	char		caller[32],called[32];
	u_char		pdata1[128],pdata2[128],pflag;
	char		serviceID[32],servicePWD[32],cardPWD[24],cause[64]="";   
	char		tagbuf[32];
	_state_data	*shmp;
	CHARGED_FEE	chargedFee;
	ASN_BUF      *asnbuf, asnbuf1;
	ASN_BUF      *asnbuf2, asnbuf3;

	PutLogFunID("ThirdPartyChargeReqeust");


	memset(pdata1,0,128);
	memset(pdata2,0,128);


	dataLen = pdu->var[0].msglen;
	if(dataLen>128) dataLen = 128;

	memcpy(pdata1,pdu->var[0].msg,dataLen);

	asnbuf = &asnbuf1;

	AsnEncode(pdu->var[0].msg,128,asnbuf);
	asnbuf2 = &asnbuf3;

	AsnDecode(pdata1, 128, 10, NULL, asnbuf2);

	if(dataLen < 19){
		return dataLen;
	}

	proc_id = AssignProcID(0);
	if(proc_id>=MAX_FSM_PROCESS || proc_id<0) 
		return dataLen;

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

    AddPPSStatistics(MIBPPS_THIRD_PARTY,shmp->process_info.dir);
 //start
	for(loop=1;loop<7;loop++)
	{     
		sprintf(tagbuf,"-%d",loop);
        if((vallen=GetAnyTLV(tagbuf,128,pdata2,&pflag,&ptagcode,asnbuf2))<=0)
		{
		    break;
		}
		else
		{
			sprintf(tagbuf,"%d",ptagcode);
			pdata2[vallen]=0;
			switch(ptagcode)
			{
				case 0x01: //serviceID
					if(vallen>8) vallen = 8;
					memcpy(serviceID,pdata2,vallen);
					serviceID[vallen] = 0;
				break;
				case 0x02: //servicePWD
					if(vallen>12) vallen=12;
					memcpy(servicePWD,pdata2,vallen);
					servicePWD[vallen] = 0;
				break;
				case 0x03: //serviceType
					operation_type =  pdata2[0];
				break;
				case 0x04: //caller
					if(vallen>20) vallen = 20;
					memcpy(caller,pdata2,vallen);
					//msisdnlen = vallen;
					caller[vallen] = 0;
				break;
				case 0x05: //cardPWD
					if(vallen>16) vallen = 16;
					memcpy(cardPWD,pdata2,vallen);
					cardPWD[vallen] = 0;
				break;
				case 0x06:  //charge
					GetInteger(tagbuf,&charge ,pflag,asnbuf2);
		//			memcpy(&charge,pdata2,vallen); 
				break;
				default:
				break;
			}//switch
		}//else
	}//for
//end

	CheckSeriveIdentification(serviceID,servicePWD,addr->remote_ip,&result,cause);
	pdu->var_num = 1;
	pdu->var[0].vartype = 0x04;
	pdu->pdu_type = 2;

	if(result==0)
	{
		  /*
		sprintf(tagbuf,"0");
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"1");
		result = ERROR_SERVICE_KEY;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"2");
		datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
			*/
		sprintf((char *)pdu->var[0].msg, "%s", cause);
		datalen = strlen(cause);
		pdu->error_index = 1;
		pdu->error_status = 3; 
		pdu->var[0].msglen = datalen;
		snmp_send(pdu,addr);
		ReleasePortStatus(proc_id);
		return datalen;
   }
/*
	memcpy(shmp->cdr_info.caller,caller, msisdnlen);
	ppsBcdToAsciiR(shmp->caller_info.number, caller, msisdnlen*2);
	printf("number: %s\n",shmp->caller_info.number);
	StringCut(shmp->caller_info.number, 'F');
	StringCut(shmp->caller_info.number, 'E');
*/
	strcpy((char *)shmp->caller_info.number, caller);
	strcat(caller,"E");
	ppsAsciiToBcdR(shmp->cdr_info.caller,caller,16);
	strcpy(caller,serviceID);
	strcat(caller,"EE");
	ppsAsciiToBcdR(shmp->cdr_info.msisdn,caller,16);	
	memset(shmp->cdr_info.called,0xFF,8);
	memset(shmp->caller_info.IMSI,0xFF,8);


   //CheckWetherLocalNumber(shmp->caller_info.number);             
	GetAccountPos(&shmp->caller_info);   


	if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
	{
		   	/*
		sprintf(tagbuf,"0");
		result = 0;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"1");
		result = EMPTY_NUMBER;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"2");
		
		sprintf(cause,"No such account");
		datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
		*/
		sprintf(cause,"No such account");
		datalen = strlen(cause);
		strcpy((char *)pdu->var[0].msg, cause);
		pdu->error_index = 1;
		pdu->error_status = 3; 
		pdu->var[0].msglen = datalen;
		snmp_send(pdu,addr);
		ReleasePortStatus(proc_id);

		return datalen;
	}
	caller_status = GetAccountStatus(&shmp->caller_info);
	shmp->caller_info.cos_id = GetAccountCosID(&shmp->caller_info);
	shmp->caller_info.charge = 0;	
	shmp->process_info.tcos = 0x8090;
	shmp->caller_info.status = caller_status;
	shmp->process_info.duration = 0;
	shmp->cdr_info.seizuretime = tvnow.tv_sec;
	shmp->cdr_info.answertime = tvnow.tv_sec;
	shmp->cdr_info.releasetime = tvnow.tv_sec;
	shmp->context_info.callType = CT_THIRD_PARTY_CHARGE;
	shmp->process_info.call_type = CT_THIRD_PARTY_CHARGE;

	if(operation_type == 0){//recharge
		memset(shmp->cdr_info.called,0xFF,8);
		strcpy(called,cardPWD);
		strcat(called,"E");
		ppsAsciiToBcdR(shmp->cdr_info.called,called,(strlen(called)+1)/2*2);
		shmp->process_info.rechargeByOther = 2;
	
		switch(caller_status)
		{
			case T_FRESH:
			case T_NORMAL:
			case T_SUSPEND:
			case T_OPRTRIAL:
				if(UseExternalVC())
				{

					strcpy((char *)shmp->called_info.number, cardPWD);
					shmp->process_info.state = S_SMMP_RECHAGE_ACCOUNT;
					shmp->process_info.sub_state = 0;
			
					pdu->var_num = 1;
					pdu->var[0].vartype = 0x04;
					pdu->pdu_type = 2;
					pdu->var[0].msglen = dataLen;
					memcpy(pdu->var[0].msg,pdata1,dataLen);
					snmp_send(pdu,addr);

					return dataLen;
				}
	
				if(RechargeCardRequest(proc_id,cardPWD,&result) != 1){
					SendRechargeCDR(proc_id, CT_RECHARGE_FAIL, 0);
					/*
					sprintf(tagbuf,"-0");
					result = 0;
					datalen = AddInteger(tagbuf,result,0x80,asnbuf);
					sprintf(tagbuf,"-1");
					result = ERROR_ACCOUNT_STATUS;
					datalen = AddInteger(tagbuf,result,0x80,asnbuf);
					sprintf(tagbuf,"-2");
					sprintf(cause,"Error card");
					datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
					*/
					sprintf(cause,"Error card");
					datalen = strlen(cause);
					strcpy((char *)pdu->var[0].msg, cause);
					pdu->error_index = 1;
					pdu->error_status = 3; 
					pdu->var[0].msglen = datalen;
					snmp_send(pdu,addr);
					ReleasePortStatus(proc_id);
					return datalen;
				}
			    RechargeRequestProc(proc_id);
				ReleasePortStatus(proc_id);
			break;
			default:
				/*
				sprintf(tagbuf,"0");
				result = 0;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"1");
				result = ERROR_ACCOUNT_STATUS;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"2");
				sprintf(cause,"Unknow operation request");
				datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
				*/
				sprintf(cause,"Unknow operation request");
				datalen = strlen(cause);
				strcpy((char *)pdu->var[0].msg, cause);
				pdu->var[0].msglen = datalen;
				pdu->error_index = 1;
				pdu->error_status = 3; 
				snmp_send(pdu,addr);
			    ReleasePortStatus(proc_id);
				return datalen;
			break;
		}
	}
	else if(operation_type == 1)
	{//charge
		shmp->process_info.chargeOther = 2;
		if(caller_status != T_NORMAL ||
			GetExpiration(&shmp->caller_info)<tvnow.tv_sec)
		{
					/*
				sprintf(tagbuf,"0");
				result = 0;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"1");
				result = ERROR_ACCOUNT_STATUS;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"2");
				sprintf(cause,"Account status error or expired");
				datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
				*/
        		DebugMsg(debugmib.display.asciiOut,
								"Account %s status error",
								shmp->caller_info.number);				
				sprintf(cause,"Account status error or expired");
				datalen = strlen(cause);
				strcpy((char *)pdu->var[0].msg, cause);
				pdu->error_index = 1;
				pdu->error_status = 3; 
				pdu->var[0].msglen = datalen;
				snmp_send(pdu,addr);
			    ReleasePortStatus(proc_id);
				return datalen;
		}
		if((GetBalanceWithPromotionControl(shmp,&shmp->caller_info)+charge)<0)
		{
					/*
				sprintf(tagbuf,"0");
				result = 0;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"1");
				result = LOW_ACCOUNT_BALANCE;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"2");
				sprintf(cause,"Account balance is low");
				datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
					*/
				sprintf(cause,"Account balance is low");
				datalen = strlen(cause);
				strcpy((char *)pdu->var[0].msg, cause);
				pdu->error_index = 1;
				pdu->error_status = 3; 
				pdu->var[0].msglen = datalen;
				snmp_send(pdu,addr);

				ReleasePortStatus(proc_id);
				return datalen;
		}
		UpdateBalance(shmp,&shmp->caller_info,charge,&chargedFee);
		instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT +
					shmp->caller_info.tail;
		SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion, OMC_OCODE_EDIT);
		shmp->caller_info.charge = -charge;	

		SendCDR(proc_id);

		ReleasePortStatus(proc_id);
	}
	else if(operation_type == 2 || operation_type == 3) /* type3 = mt sms charge */
	{
		if(caller_status == T_FRESH)
		{
        	DebugMsg(debugmib.display.asciiOut,
							"Account %s status error",
							shmp->caller_info.number);				
			sprintf(cause,"Account status error or expired");
			datalen = strlen(cause);
			strcpy((char *)pdu->var[0].msg, cause);
			pdu->error_index = 1;
			pdu->error_status = 3; 
			pdu->var[0].msglen = datalen;
			snmp_send(pdu,addr);
			ReleasePortStatus(proc_id);
			return datalen;
		}
		shmp->process_info.chargeOther = 2;
		shmp->caller_info.charge = -charge;	
		if(operation_type == 3)
		{
		       shmp->caller_info.charge = ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id].serviceControl[0].mtSMSCharge;
		       charge = -shmp->caller_info.charge;
			shmp->context_info.callType = CT_MT_SM;
			shmp->process_info.call_type = CT_MT_SM;
			memcpy(&shmp->called_info, &shmp->caller_info, sizeof(_account_info));
		}
		
		UpdateBalance(shmp,&shmp->caller_info,charge,&chargedFee);
		instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT +
					shmp->caller_info.tail;
		SendAccountRealSync(instance, chargedFee.balance,chargedFee.promotion,OMC_OCODE_EDIT);
		

		SendCDR(proc_id);

		ReleasePortStatus(proc_id);
	}
	else
	{
		/*
		sprintf(tagbuf,"0");
		result = 0;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"1");
		result = ERROR_SERVICE_KEY;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"2");
		sprintf(cause,"Unknow operation request");
		datalen =add_tlv(tagbuf,strlen(cause),cause,0x80,asnbuf);
		*/
		sprintf(cause,"Unknow operation request");
		datalen = strlen(cause);
		strcpy((char *)pdu->var[0].msg, cause);
		pdu->error_index = 1;
		pdu->error_status = 3; 
		pdu->var[0].msglen = datalen;
		snmp_send(pdu,addr);
		ReleasePortStatus(proc_id);
		return datalen;
	}

   	/*
	sprintf(tagbuf,"0");
	result = 1;
	datalen = AddInteger(tagbuf,result,0x80,asnbuf);
	pdu->var_num = 1;
	pdu->var[0].oidlen = 11;
	memcpy(pdu->var[0].oid,PPS_OID_THIRDPARTY,11);
	pdu->var[0].vartype = 0x04;
	pdu->pdu_type = 2;
	pdu->var[0].msglen = datalen;
	snmp_send(pdu,addr);
	return datalen;
	*/

	pdu->var_num = 1;
	pdu->var[0].vartype = 0x04;
	pdu->pdu_type = 2;
	pdu->var[0].msglen = dataLen;
	memcpy(pdu->var[0].msg,pdata1,dataLen);
	snmp_send(pdu,addr);

	return dataLen;
}

int ThirdPartyChargeReqeust(u_char oidLen,u_long *oid,u_char *pdata,u_short dataLen)
{
   int			charge,instance,caller_status,datalen;
   int			proc_id,operation_type,result,loop,vallen;//,msisdnlen;
   u_short		ptagcode;
   char			caller[32];
   u_char		pdata1[128],pdata2[128],pflag;
   char			serviceID[32],servicePWD[32],cardPWD[32],cause[32]="";   
   char			tagbuf[32];
   _state_data	*shmp;
	CHARGED_FEE	chargedFee;
   ASN_BUF      *asnbuf, asnbuf1;
   ASN_BUF      *asnbuf2, asnbuf3;

	PutLogFunID("ThirdPartyChargeReqeust");
	debugmib.watch_dog[4] ++;
	return -1;

   memset(pdata1,0,128);
   memset(pdata2,0,128);
		
   memcpy(pdata1,pdata,dataLen);

   asnbuf = &asnbuf1;

   AsnEncode(pdata,128,asnbuf);
   asnbuf2 = &asnbuf3;

   AsnDecode(pdata1, 128, 10, NULL, asnbuf2);

   if(dataLen < 19){
//	 printf("error datalen: %d\n",dataLen);
	 return dataLen;
   }


   proc_id = AssignProcID(0);
   if(proc_id>=MAX_FSM_PROCESS || proc_id<0)
   {
	//	printf("can't get port id\n");
		return dataLen;
	}

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

    AddPPSStatistics(MIBPPS_THIRD_PARTY,shmp->process_info.dir);
 //start
	for(loop=0;loop<6;loop++)
	{     
		sprintf(tagbuf,"-%d",loop);
        if((vallen=GetAnyTLV(tagbuf,128,pdata2,&pflag,&ptagcode,asnbuf2))<=0)
		{
		    break;
		}
		else
		{
		  sprintf(tagbuf,"%d",ptagcode);
		  pdata2[vallen]=0;
		  switch(ptagcode)
		  {
			case 0x00: //serviceID
				memcpy(serviceID,pdata2,vallen%9);
				serviceID[vallen%9] = 0;
			break;
			case 0x01: //servicePWD
				memcpy(servicePWD,pdata2,vallen%13);
				servicePWD[vallen%13] = 0;
			break;
			case 0x02: //serviceType
				operation_type =  pdata2[0];
			break;
			case 0x03: //caller
				memcpy(caller,pdata2,vallen%20);
				//msisdnlen = vallen%20;
				caller[vallen%20] = 0;
			break;
			case 0x04: //cardPWD
				memcpy(cardPWD,pdata2,vallen%17);
			break;
			case 0x05:  //charge
//				GetInteger(tagbuf,&charge ,pflag,asnbuf2);
				memcpy(&charge,pdata2,vallen); 
			break;
			default:
			break;
		  }//switch
		}//else
	  }//for
//end
   CheckSeriveIdentification(serviceID,servicePWD,0,&result,cause);

   if(result==0)
   {
		sprintf(tagbuf,"0");
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"1");
		result = ERROR_SERVICE_KEY;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"2");
		datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);
		ReleasePortStatus(proc_id);
		return datalen;
   }
/*
   memcpy(shmp->cdr_info.caller,caller, msisdnlen);
   ppsBcdToAsciiR(shmp->caller_info.number, caller, msisdnlen*2);
   printf("number: %s\n",shmp->caller_info.number);
   StringCut(shmp->caller_info.number, 'F');
   StringCut(shmp->caller_info.number, 'E');
*/

	strcpy((char *)shmp->caller_info.number, caller);

	strcat(caller,"F");
	
	ppsAsciiToBcdR(shmp->cdr_info.caller,caller,16);
	memset(shmp->cdr_info.called,0xFF,8);
	memset(shmp->caller_info.IMSI,0xFF,8);
   //CheckWetherLocalNumber(shmp->caller_info.number);             
   GetAccountPos(&shmp->caller_info);   


   if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
   {
		sprintf(tagbuf,"0");
		result = 0;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"1");
		result = EMPTY_NUMBER;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"2");
		sprintf(cause,"No such account");
		datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);
		ReleasePortStatus(proc_id);

		return datalen;
   }
	caller_status = GetAccountStatus(&shmp->caller_info);
	shmp->caller_info.charge = 0;	
	shmp->process_info.tcos = NORMAL_CLEARING;
	shmp->caller_info.status = caller_status;
	shmp->process_info.duration = 0;
	shmp->cdr_info.seizuretime = tvnow.tv_sec;
	shmp->cdr_info.answertime = tvnow.tv_sec;
	shmp->cdr_info.releasetime = tvnow.tv_sec;
	shmp->context_info.callType = CT_THIRD_PARTY_CHARGE;
	shmp->process_info.call_type = CT_THIRD_PARTY_CHARGE;

	if(operation_type == 0){//recharge
		switch(caller_status)
		{
			case T_FRESH:
			case T_NORMAL:
 			case T_SUSPEND:
 			case T_OPRTRIAL:
				if(RechargeCardRequest(proc_id,cardPWD, &result) != 1){
					SendRechargeCDR(proc_id, CT_RECHARGE_FAIL, 0);
					sprintf(tagbuf,"-0");
					result = 0;
					datalen = AddInteger(tagbuf,result,0x80,asnbuf);
					sprintf(tagbuf,"-1");
					result = ERROR_ACCOUNT_STATUS;
					datalen = AddInteger(tagbuf,result,0x80,asnbuf);
					sprintf(tagbuf,"-2");
					sprintf(cause,"Error card");
					datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);					
					ReleasePortStatus(proc_id);
					return datalen;
				}
			    shmp->process_info.state = S_RECHARGE_OVER;
			break;
			default:
				sprintf(tagbuf,"0");
				result = 0;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"1");
				result = ERROR_ACCOUNT_STATUS;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"2");
				sprintf(cause,"Unknow operation request");
				datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);
			    ReleasePortStatus(proc_id);
				return datalen;
			break;
		}
   }
   else if(operation_type == 1)
   {//charge
		if(caller_status != T_NORMAL ||
			GetExpiration(&shmp->caller_info)<tvnow.tv_sec)
		{
				sprintf(tagbuf,"0");
				result = 0;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"1");
				result = ERROR_ACCOUNT_STATUS;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"2");
				sprintf(cause,"Account status error or expired");
				datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);
			    ReleasePortStatus(proc_id);
				return datalen;
		}
		if((GetBalanceWithPromotionControl(shmp,&shmp->caller_info)+charge)<0)
		{
				sprintf(tagbuf,"0");
				result = 0;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"1");
				result = LOW_ACCOUNT_BALANCE;
				datalen = AddInteger(tagbuf,result,0x80,asnbuf);
				sprintf(tagbuf,"2");
				sprintf(cause,"Account balance is low");
				datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);

				ReleasePortStatus(proc_id);
				return datalen;
		}
		UpdateBalance(shmp,&shmp->caller_info,charge,&chargedFee);
		instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT +
					shmp->caller_info.tail;
		SendAccountRealSync(instance,chargedFee.balance,chargedFee.promotion, OMC_OCODE_EDIT);
		shmp->caller_info.charge = charge;	

		SendCDR(proc_id);

		ReleasePortStatus(proc_id);
   }else{
		sprintf(tagbuf,"0");
		result = 0;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"1");
		result = ERROR_SERVICE_KEY;
		datalen = AddInteger(tagbuf,result,0x80,asnbuf);
		sprintf(tagbuf,"2");
		sprintf(cause,"Unknow operation request");
		datalen =add_tlv(tagbuf,strlen(cause), (u_char *)cause,0x80,asnbuf);
		ReleasePortStatus(proc_id);
		return datalen;
   }

	sprintf(tagbuf,"0");
	result = 1;
	datalen = AddInteger(tagbuf,result,0x80,asnbuf);
	ReleasePortStatus(proc_id);
	return datalen;
}


int	EstablishTemporaryConnection(u_short portid)
{
	int 	retval;
	_state_data *shmp;

	PutLogFunID("EstablishTemporaryConnection");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
/*
	if(!CheckSRFResource())
	{
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
		   debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,
						"Warning: SRF is not reachable!");
		}
#endif
		return (retval=S_SEND_RELEASE_CALL);
	}
*/
	SendEstablishTemporaryConnection(portid);
	shmp->process_info.srfRelease = 0;
	shmp->process_info.funnel = 0;
	shmp->process_info.down = 0;
	shmp->process_info.Tassist = 0;
	shmp->process_info.connFlag = 1;
	retval = S_DISCONNECT_FORWARD_CONNECTION;
	return retval;
}

int	SendPlayAnnouncementOrPCUI(u_short portid)
{
	int		retval,correlationID;
	_state_data *shmp,*shmpconn;

	PutLogFunID("SendPlayAnnouncementOrPCUI");

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

	if(subSystemID)
	{/* plan 1 correlation ID range: 4000-(4000+2047) 
		while plan 0 range: 0-2047*/
		if(correlationID <4000)
		{
			shmp->process_info.u_error = CAP_ERR_TASK_REFUSED;
			shmp->process_info.oc	= CAP_OC_AssistRequestInstructions;
			SendScfUError(portid); /* add later, 2004-02-17 */
			shmp->process_info.tcend = 1;
			//SendScfTcEND(portid);
			return (retval = S_RELEASE_ALL);
		}
		else
		{
			correlationID -= 4000;
		}
	}
	if(correlationID>=MAX_FSM_PROCESS) 
	{
		shmp->process_info.u_error = CAP_ERR_TASK_REFUSED;
		shmp->process_info.oc	= CAP_OC_AssistRequestInstructions;
		SendScfUError(portid); /* add later, 2004-02-17 */
		shmp->process_info.tcend = 1;
		//SendScfTcEND(portid);
		return (retval = S_RELEASE_ALL);
	}

	shmpconn = (_state_data *)&smshm_ptr->state_data;
	shmpconn += correlationID;
	shmp->process_info.promptAndCollectUserInfo =
		shmpconn->process_info.promptAndCollectUserInfo;


	if(shmpconn->process_info.connFlag != 1)
	{	
	/*
		if(logMsgFlag & 0x02 ||
			logMsgFlag & 0x04 ||
			logMsgFlag & 0x10 )
		{		
	      DebugMsg(debugmib.display.asciiOut,
		    "Warning: port=%d not correlated",correlationID);
		}
		*/
		shmp->process_info.u_error = CAP_ERR_TASK_REFUSED;
		shmp->process_info.oc	= CAP_OC_AssistRequestInstructions;
		SendScfUError(portid); /* add later, 2004-02-17 */
		shmp->process_info.tcend = 1;
		//SendScfTcEND(portid);
		return (retval = S_RELEASE_ALL);
	}
	memcpy(&shmp->caller_info,&shmpconn->caller_info,sizeof(_account_info));
	memcpy(&shmp->called_info,&shmpconn->called_info,sizeof(_account_info));
	memcpy(&shmp->cdr_info,&shmpconn->cdr_info,sizeof(_cdr_info));
	
	shmp->process_info.connFlag = 2;
	shmp->process_info.correlationID = correlationID;
	shmpconn->process_info.connFlag = 2;
	shmpconn->process_info.correlationID = portid;

    	shmp->process_info.voiceID		= shmpconn->process_info.voiceID;
	shmp->process_info.pre_warning	= shmpconn->process_info.pre_warning;
	shmp->process_info.tcos			= shmpconn->process_info.tcos;
	shmp->process_info.logMsisdn	= shmpconn->process_info.logMsisdn;
	shmp->process_info.serviceType	= shmpconn->process_info.serviceType;
	shmp->process_info.sub_state	= shmpconn->process_info.sub_state;
	shmp->context_info.callType		= shmpconn->context_info.callType;
	shmp->process_info.palim_auto_register = shmpconn->process_info.palim_auto_register;

	if(shmp->process_info.promptAndCollectUserInfo)
	{
		switch(shmp->process_info.serviceType)
		{
			case SRV_INQUIRY:
				shmp->process_info.sub_state = S_INQ_SEND_PROMPT;
				retval = S_INQUIRY_MANAGE;
			break;
			case SRV_SCRATCH_CARD_RECHARGE:
			case SRV_RECHARGE_2TYPES:
				/*
				shmp->process_info.sub_state = S_REC_CHECK_ACCOUNT_STATUS;
				retval = S_RECHARGE_MANAGE;
				*/
				clearTransferInfo(portid);
				retval = S_CHARGE_OR_TRANSFER;
			break;
			case SRV_CREDIT_CARD_RECHARGE:
				shmp->process_info.sub_state = S_CCR_PLAY_INFO;
				retval = S_CREDIT_CARD_RECHARGE;
			break;
			case SRV_THIRD_PARTY_RECHARGE:
				shmp->process_info.sub_state = S_REC_INPUT_ACCOUNT;
				retval = S_RECHARGE_MANAGE;
			break;
			case SRV_RECHARGE_ONE_INPUT:
				shmp->process_info.srfRelease = 2;
				if(UseExternalVC() )
				{
				       shmp->process_info.sub_state = S_REC_CHECK_CARD_VALIDITY;
					return (retval = S_RECHARGE_MANAGE);
				}
				if(OCS_with_external_CRM())
				{
				       shmp->process_info.sub_state = S_REC_CHECK_CARD_VALIDITY;
					return (retval = S_RECHARGE_MANAGE);
				}

				switch(shmp->process_info.sub_state)
				{
					case 0://error status
						shmp->process_info.voiceID = ERROR_ACCOUNT_STATUS;
						SendSrfPlayAnnouncement(portid);
					break;
					case 1://success
						SendRechargeInfoPromptToSrf(portid);
					break;
					case 2://error pwd
						shmp->process_info.voiceID = RECHARGE_FAILED;
						SendSrfPlayAnnouncement(portid);
					break;
				}
				retval = S_WAITING_SPECIAL_RESOURCE_REPORT;	
				break;				
			case SRV_CALL_HOTLINE:
				if(shmp->caller_info.head<MSISDN_HEAD_NUM)
				{
					shmp->process_info.voiceID = SERVICE_SELECT_PROMPT;
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					retval = S_WAITING_RR_PCUI;
				}
				else
				{
					shmp->process_info.sub_state = S_REC_INPUT_ACCOUNT;
					retval = S_RECHARGE_MANAGE;
				}
			break;
			case SRV_CRD:
			case SRV_DIRECT_ACCESS:
			case SRV_RESERVED_FUN:
				retval = S_CRD_SERVICE;
				if(shmp->context_info.callType == CT_MF_CALL)
				{
					shmp->process_info.chargeOther = 2;
					shmp->process_info.sub_state = S_CRD_CONNECT;	
				}
				else
					shmp->process_info.sub_state = S_CRD_CHECK_CALLER_INFO;
			break;
			case SRV_OTHER_VMS_MAITENANCE:
				retval = S_CRD_SERVICE;
				shmp->process_info.sub_state = S_CRD_INPUT_VOICEBOX;
			break;
			case SRV_VMS_DEPOSIT:
				retval = S_CRD_SERVICE;
				shmp->process_info.sub_state = S_CRD_SET_DEPOSIT;
			break;
			case SRV_OPR_MANAGE:
				retval = S_OPR_MANAGE;
			break;
			case SRV_CALLINGCARD_MANAGE:/*calling card		*/
				clearTransferInfo(portid);
				retval = S_CALLING_CARD;
			break;	
			case SRV_FEE_TRANSFER:
				clearTransferInfo(portid);
				retval = S_FEE_TRANSFER;
			break;
			case SRV_POOL_ACCOUNT:
				clearMasterSlaveInfo(portid);
				retval = S_POOL_ACCOUNT;
			break;
		}
	}
	else
	{
		shmp->process_info.srfRelease = 0x00;
		SendSrfPlayAnnouncement(portid);
		retval = S_WAITING_SPECIAL_RESOURCE_REPORT;
	}
	shmp->process_info.funnel = 0;
	
	return retval;
}

int WaitingForDisconnectForwardConnection(u_short portid)
{
	int				retval,dlgid,correlationID;
	CAP_Message		capmsg;
	_state_data		*shmp,*shmpconn;

	PutLogFunID("WaitingForDisconnectForwardConnection");

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

	/*
	*/
	retval = shmp->process_info.state;

	if(shmp->process_info.funnel++>ACTIVITY_TEST_DELAY)
	{
		shmp->process_info.tcos = TIMER_OUT;
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
	    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,
			"portid=%d ActivityTest missed (waiting DFC)!",portid);
		}
#endif
		SendReleaseCall(portid);
		return (retval = S_RELEASE_ALL);
	}

	if(shmp->process_info.connFlag == 1)
	if(shmp->process_info.Tassist++>ONE_MINUTE_STATE_TIME)
	{
		shmp->process_info.tcos = TIMER_OUT;
		SendReleaseCall(portid);
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
		   debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,
						"portid=%d AssistRequest missed (waiting DFC)!",portid);
		}
#endif
		return (retval = S_RELEASE_ALL);
	}

	shmp->process_info.down ++ ;
	if(shmp->process_info.down >=SEND_ACTIVITYTEST_PERIODIC)
	{
		shmp->process_info.down = 0;
		SendActivityTest(portid);     
	}

	if(shmp->process_info.disconnectForwardConnection == 1)
	{   //released by SRF


		SendDisconnectForwardConnection(portid);

//DebugMsg(debugmib.display.asciiOut,"connected:%d",shmp->process_info.callConnected);

		if(shmp->process_info.callConnected)
		{
			sendConnectForCRDService(portid);
			shmp->process_info.chargeOther = 0;
			if(shmp->process_info.callConnected == 1)
			{
				SendScfTcEND(portid);
				return (retval = S_RELEASE_ALL);
			}
		}
		if(shmp->process_info.serviceType == SRV_CRD ||
			shmp->process_info.serviceType == SRV_DIRECT_ACCESS ||
			shmp->process_info.serviceType == SRV_RESERVED_FUN ||
			shmp->process_info.serviceType == SRV_OTHER_VMS_MAITENANCE ||
			shmp->process_info.serviceType == SRV_VMS_DEPOSIT)
		{
			
			if(shmp->caller_info.head>=MSISDN_HEAD_NUM )
			{
				SendScfTcEND(portid);
				return (retval = S_RELEASE_ALL);
			}
			
			if((shmp->process_info.serviceType == SRV_CRD ||
				shmp->process_info.serviceType == SRV_DIRECT_ACCESS ||
				shmp->process_info.serviceType == SRV_RESERVED_FUN )
				&& shmp->caller_info.status != T_NORMAL)
			{
				SendScfTcEND(portid);
				return (retval = S_RELEASE_ALL);
			}
			shmp->process_info.promptAndCollectUserInfo = 0;
			shmp->process_info.funnel = 0;  
			shmp->process_info.down = 0;
			return (retval = S_WAITINGFOR_ANSWERED);
		}
		
		if(shmp->process_info.serviceType == SRV_CALLINGCARD_MANAGE)
		{/* calling card */
			if(shmp->process_info.callingCardState == sendMainMenu 
				&&shmp->process_info.callingCardFunction == MakeCall)
			{/*	calling card routing call		*/
				shmp->process_info.disconnectForwardConnection = 0;
				shmp->process_info.callingCardState = 0;
				shmp->process_info.callingCardFunction = 0;
				if(ocs_get_calling_card_method() == 0)
					return (retval = S_CHECK_CALL_VALIDITY);
				else
					return (retval = S_CC_CHECK_CALL_VALIDITY);
			}
			else
			{
				SendScfTcEND(portid);
				return (retval = S_RELEASE_ALL);	
			}
		}
		
		if(!shmp->process_info.pre_warning)
		{
				return (retval = S_SEND_RELEASE_CALL);
		}
		else
		{
			shmp->process_info.pre_warning = 0;
			shmp->process_info.playAnnouncement = 0;
			shmp->process_info.promptAndCollectUserInfo = 0;
			return (retval = S_REQUEST_EVENTS);
		}
	}

	dlgid = shmp->context_info.dialogue_id;
	if(ReadScfMsg(&capmsg,dlgid))
	{
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_EventReportBCSM:
				shmp->process_info.tcos = NORMAL_CLEARING;
				SendReleaseCall(portid);
			break;
			case CAP_OC_ActivityTest:
				if(capmsg.msgContent[2] != 0x03)
					shmp->process_info.funnel = 0;
				return retval;
			break;
			case CAP_O_UABORT:
			case CAP_O_PABORT:
			default:
				shmp->process_info.tcos = INVALID_MESSAGE;
				SendReleaseCall(portid);
			break;
		}

		if(shmp->process_info.connFlag == 2)
		{   // to release SRF
			correlationID = shmp->process_info.correlationID;
			shmpconn = (_state_data *)&smshm_ptr->state_data;
			shmpconn += correlationID;
			if(shmp->process_info.connFlag == 2)
				shmpconn->process_info.disconnectForwardConnection = 1;
		}
		shmp->process_info.connFlag = 0;
		retval = S_RELEASE_ALL;
	}
	return retval;

}

int SendSSFReleaseCall(u_short portid)
{
	PutLogFunID("SendSSFReleaseCall");

	SendReleaseCall(portid);
	return S_RELEASE_ALL;
}

int	WaitingForSpecialResourceReport(u_short portid)
{
	int					retval,dlgid;
	CAP_Message			capmsg;
	_state_data			*shmp;
	COSTable			*cosTableItem;
	
	PutLogFunID("WaitingForSpecialResourceReport");

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

	retval = shmp->process_info.state;

	if(shmp->process_info.funnel++>SPECIAL_RESOURCE_REPORT_TIMER)
	{
		shmp->process_info.tcos = TIMER_OUT;
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
	    DebugMsgDelimiter();
		DebugMsg(debugmib.display.asciiOut,"[%04d] Wait SpecailResourceReport timer out! (%ld.%ld)",
		portid,tvnow.tv_sec,tvnow.tv_usec);
	}
#endif

		return (retval = S_RELEASE_SRF);
	}

    if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = S_RELEASE_ALL);
	}

	dlgid = shmp->context_info.dialogue_id;
	if(ReadScfMsg(&capmsg,dlgid))
	{
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_SpecializedResourceReport:
			    AddPPSStatistics(MIBPPS_SPE_RUS_RPT,shmp->process_info.dir);
				switch(shmp->process_info.srfRelease)
				{
					case 1:
						shmp->process_info.voiceID = SERVICE_SELECT_PROMPT;
						shmp->process_info.maxPCUInfoLen = 1;
						SendPromptAndCollectUserInfo(portid);
						retval = S_WAITING_RR_PCUI;					
					break;
					case 2:
						return (retval = S_RELEASE_SRF);
					break;
					case 0:/* confused , should be re-wroten latter */
					default:
						if(!shmp->process_info.pre_warning)
						{

							if(shmp->context_info.callType != CT_MO_CALL)
							{
								return (retval = S_RELEASE_SRF);
							}/* above added for mt voice , 2005-11-30 */
							if(shmp->process_info.serviceType != SRV_INQUIRY)
							{
								if(shmp->caller_info.status != T_SUSPEND &&
									shmp->caller_info.status != T_BLACKLIST &&
									shmp->caller_info.status != T_RELEASED)
								{
									if(shmp->process_info.tcos == TARIFF_NOT_SET)
									{
										return (retval = S_RELEASE_SRF);
									}
									cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
									if(cosTableItem->serviceControl[0].creditVault && GetOverdraft(&shmp->caller_info)<=0)
									if(shmp->process_info.tcos == CALLER_CREDIT_OUT)
									{
										shmp->process_info.sub_state = S_INQ_PLAY_CREDIT_VAULT;
										return (retval = S_INQUIRY_MANAGE);
									}
									if(shmp->process_info.tcos == CALLER_REACH_CALL_LIMIT
										||shmp->process_info.tcos == CALLER_REACH_CHARGE_LIMIT)
									{/*	 child reach limits ,release call	*/
										return (retval = S_RELEASE_SRF);
									}

									if(shmp->process_info.tcos == SRVICE_NOT_SUBSCRIBERED || pps_get_adaptor_flag())
										return (retval = S_RELEASE_SRF);
									
									shmp->process_info.sub_state = S_INQ_TO_RECHARGE;													
									return (retval = S_INQUIRY_MANAGE);
								}
							}
							else
							{
								shmp->process_info.sub_state = S_INQ_TO_RECHARGE;													
								return (retval = S_INQUIRY_MANAGE);
							}
						}
						if(shmp->process_info.serviceType == SRV_CRD ||
							shmp->process_info.serviceType == SRV_DIRECT_ACCESS ||
							shmp->process_info.serviceType == SRV_RESERVED_FUN)
						{
							shmp->process_info.sub_state = S_CRD_CHECK_CALLER_INFO;
							retval = S_CRD_SERVICE;
						}
						else if(shmp->process_info.serviceType == SRV_OTHER_VMS_MAITENANCE)
						{
							shmp->process_info.sub_state = S_CRD_INPUT_VOICEBOX;
							retval = S_CRD_SERVICE;
						}
						else if(shmp->process_info.serviceType == SRV_VMS_DEPOSIT)
						{
							shmp->process_info.sub_state = S_CRD_SET_DEPOSIT;
							retval = S_CRD_SERVICE;
						}
						else
						{
							retval = S_RELEASE_SRF;
						}
					break;
				}
			break;
			case CAP_O_UABORT:
			case CAP_O_PABORT:
#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,
				"[%04d] Abort Received! (%ld.%ld)",
				portid,tvnow.tv_sec,tvnow.tv_usec);
		}
#endif
				//no end need, later 2004-02-17
				retval = S_RELEASE_SRF;
			break;
			default:
				shmp->process_info.tcos = INVALID_MESSAGE;
				retval = S_RELEASE_SRF;
			break;
		}
	}
	return retval;
}

int ReleaseSRF(u_short portid)
{
	int				retval,correlationID;
	_state_data		*shmp,*shmpconn;

	PutLogFunID("ReleaseSRF");

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


    if(shmp->process_info.connFlag == 2)
	{
		correlationID = shmp->process_info.correlationID;
		shmpconn = (_state_data *)&smshm_ptr->state_data;
		shmpconn += correlationID;
		if(shmpconn->process_info.connFlag == 2)
			shmpconn->process_info.disconnectForwardConnection = 1;
	}
	shmp->process_info.connFlag = 0;
	SendScfTcEND(portid);
	
	retval = S_RELEASE_ALL;
	return retval;

}

int GetRegisteredServiceKey(u_char serviceKey)
{
	int i;

	PutLogFunID("GetRegisteredServiceKey");

	for(i=0;i<MaxServiceKeyItem;i++)
		if(ppsParam.ppsTables.serviceKey[i].key == serviceKey)
			return i;
	return -1;
}

int WaitingForRRofPromptAndCollectUserInfo(u_short portid)
{
	int								retval,dlgid,msglen;//,len;
	int								serviceKey,regKey;
	CAP_Message						capmsg;
	CapArg							capArg;
	_state_data 					*shmp;
	CosFriendFamilyControl			*friendFamilyControl;
	
	PutLogFunID("WaitingForRRofPromptAndCollectUserInfo");

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

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{
		DebugMsg(debugmib.display.asciiOut,"[%04d] Wait RR PCUI timeout!(%ld.%ld)",
			portid,tvnow.tv_sec,tvnow.tv_usec);
		return (retval = S_RELEASE_SRF);
	}

    if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = S_RELEASE_ALL);
	}
	dlgid = shmp->context_info.dialogue_id;
	if(ReadScfMsg(&capmsg,dlgid))
	{
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
				AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
				shmp->process_info.funnel = 0;
				msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
				capArg.version = shmp->context_info.acn_ver;
				if(decode_capmsg((char *)&capmsg.msgContent[5],
								msglen,
								capmsg.msgOperaCode,
								CAP_CONFIRM,
								&capArg)<0)
				{
						return (retval = S_RELEASE_SRF);
				}
				//len = capArg.msg_list.promptAndCollectUserInformationArg.digitsResponse[0];
				serviceKey = capArg.msg_list.promptAndCollectUserInformationArg.digitsResponse[2] &0x0F;
				if((regKey=GetRegisteredServiceKey(serviceKey))<0)
				{
					if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
					{
						SendDisconnectForwardConnection(portid);
						shmp->process_info.tcos = NORMAL_CLEARING;
						return (retval = S_RELEASE_SRF);
					}
					shmp->process_info.srfRelease = 0;
					shmp->process_info.maxPCUInfoLen = 1;
					shmp->process_info.voiceID = SERVICE_SELECT_PROMPT;
					SendPromptAndCollectUserInfo(portid);
					shmp->process_info.funnel = 0;
					return (retval = S_WAITING_RR_PCUI);				
				}
				shmp->process_info.serviceInput = 0;
				switch(regKey)
				{
					case HELP:
						//SendDisconnectForwardConnection(portid);
						shmp->process_info.tcos = NORMAL_CLEARING;
						retval = S_RELEASE_SRF;
					break;
					case INQUIRY_SERVICE:
						shmp->process_info.sub_state = S_INQ_SEND_PROMPT;
						retval = S_INQUIRY_MANAGE;
					break;
					case SCRATCH_CARD_RECHARGE:
						shmp->process_info.sub_state = S_REC_CHECK_ACCOUNT_STATUS;
						retval = S_RECHARGE_MANAGE;
					break;
					case CREDIT_CARD_RECHARGE:
						shmp->process_info.sub_state = S_CCR_PLAY_INFO;
						retval = S_CREDIT_CARD_RECHARGE;
					break;
					case FAVORITE_NUMBER_SERVICE:
						friendFamilyControl = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id].friendFamilyControl[0];
						if(!(friendFamilyControl->friendFamilyFlag))
						{
							shmp->process_info.voiceID = SERIVCE_NOT_APPLIED;
							shmp->process_info.srfRelease = 1;
							SendSrfPlayAnnouncement(portid);
							return (retval = S_WAITING_SPECIAL_RESOURCE_REPORT);
						}
						if(GetAccountStatus(&shmp->caller_info) != T_NORMAL)
						{
							shmp->process_info.voiceID = ERROR_ACCOUNT_STATUS;
							shmp->process_info.srfRelease = 0;
							SendSrfPlayAnnouncement(portid);
							return (retval = S_WAITING_SPECIAL_RESOURCE_REPORT);
						}
						shmp->process_info.sub_state = S_FAV_PLAY_MENU;
						retval = S_FAVORITE_NUMBER_MANAGE;
					break;
					case LANGUAGE_MANAGEMENT:
					case PIN_MANAGEMENT:
						if(GetAccountStatus(&shmp->caller_info) != T_NORMAL)
						{
							shmp->process_info.voiceID = ERROR_ACCOUNT_STATUS;
							shmp->process_info.srfRelease = 0;
							SendSrfPlayAnnouncement(portid);
							retval = S_WAITING_SPECIAL_RESOURCE_REPORT;
						}
						if(regKey == LANGUAGE_MANAGEMENT)
						{
							shmp->process_info.sub_state = S_LANGUAGE_MANAGE_MENU;
							retval = S_LANGUAGE_MANAGEMENT;
						}
						else if(regKey == PIN_MANAGEMENT)
						{
							shmp->process_info.sub_state = S_PIN_INPUT_OLD_PIN;
							retval = S_PIN_MANAGEMENT;
						}
					break;
				}
			break;
			case CAP_O_UABORT:
			case CAP_O_PABORT:
			default:
				retval = S_RELEASE_SRF;
			break;
		}
	}
	return retval;
}

int InquiryManageProc(u_short portid)
{
	int				retval,dlgid,msglen;
	int				key,caller_status,instance;
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation	*pPCUI;
	COSTable			*cosTableItem;
	_state_data *shmp;
	int tmpval;
	
	PutLogFunID("InquiryManageProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = inq_mng_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{
		return (retval = inq_mng_exit);
	}
	if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = inq_mng_exit);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_INQ_SEND_PROMPT:
			
		if(pps_get_adaptor_flag())
		{
			shmp->process_info.sub_state = S_INQ_REST_GET;
			shmp->process_info.sub_state_2 = 0;
			shmp->process_info.rest_if.rest_oc = 0;
			shmp->process_info.rest_if.rest_src = 2;
			strcpy((char *)shmp->origin_info.number, (char *)shmp->called_info.number);
			return retval;
		}
			
		caller_status = GetAccountStatus(&shmp->caller_info);
		if(caller_status == T_NORMAL|| caller_status == T_OPRTRIAL) 
		{
			cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
			if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenInquiry)
			{
				SendAccountInfoBySMPP(
						&shmp->caller_info,
						shmp->called_info.number);  
			}
							
			SendAccountInfoPromptToSrf(portid,FALSE,TRUE);
			shmp->process_info.funnel = 0;
			shmp->process_info.srfRelease = 0x01;
			shmp->process_info.sub_state = S_INQ_SRR;
		}
		else 
		{
			if(caller_status == T_FRESH && shmp->caller_info.head<MSISDN_HEAD_NUM)
			{
				cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
				if(cosTableItem->accountValidity[0].activiationByInquiryIs)
				{
					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);
					if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenInquiry)
					{
						SendAccountInfoBySMPP(
								&shmp->caller_info,
								shmp->called_info.number);  
					}
							
					SendAccountInfoPromptToSrf(portid,FALSE,TRUE);
					shmp->process_info.funnel = 0;
					shmp->process_info.srfRelease = 0x01;
					shmp->process_info.sub_state = S_INQ_SRR;
					return retval;
				}
			}
//			else
			{
				shmp->process_info.voiceID = ERROR_ACCOUNT_STATUS;
				shmp->process_info.srfRelease = 0;
				SendSrfPlayAnnouncement(portid);
				shmp->process_info.sub_state = S_INQ_SRR0;
			}
		}
		break;
		case S_INQ_SRR0:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			return retval;
		
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
	#endif
		retval = inq_mng_exit;
		break;
		case S_INQ_SRR:				
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			return retval;
		
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
	#endif

		if(capmsg.msgOperaCode !=CAP_OC_SpecializedResourceReport)
		{
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				DebugMsg(debugmib.display.asciiOut,"< Error message received >");
			}
			return (retval=inq_mng_exit);
		}
		AddPPSStatistics(MIBPPS_SPE_RUS_RPT,shmp->process_info.dir);
		shmp->process_info.sub_state = S_INQ_TO_RECHARGE;
		break;
		case S_INQ_PLAY_CREDIT_VAULT:
        if (0)// PCUI and wait for input
        {
    		shmp->process_info.voiceID = PRESS_2_TO_USE_CREDIT_VAULT;
    		shmp->process_info.maxPCUInfoLen = 1;
    		shmp->process_info.endOfReplyDigit[0] = 0;
    		shmp->process_info.endOfReplyDigit[1] = ' ';
    		SendPromptCollectedRechargedUserInfo(portid);
    		shmp->process_info.funnel = 0;
    		shmp->process_info.sub_state = S_INQ_WAIT_CREDIT_VAULT;
        }
        if (1)// change to PAI and release
        {
    		shmp->process_info.voiceID = OPERATION_SUCESSFULLY_DONE;
    		shmp->process_info.srfRelease = 0;
    		SendSrfPlayAnnouncement(portid);
    		shmp->process_info.funnel = 0;
    		shmp->process_info.sub_state = S_INQ_WAIT_CREDIT_VAULT;
        }
		break;
		case S_INQ_WAIT_CREDIT_VAULT:
		dlgid = shmp->context_info.dialogue_id;

		if(!ReadScfMsg(&capmsg,dlgid))
		{
			return retval;
		}
        else
        {
            retval = inq_mng_exit;
			return retval;
        }

		#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif
		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
					msglen,
					capmsg.msgOperaCode,
					CAP_CONFIRM,
					&capArg)<0)
			{
				return (retval = inq_mng_exit);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			if(pPCUI->digitsResponse[0]<2) 
				return (retval = inq_mng_exit);

			key = pPCUI->digitsResponse[2] &0x0F;

			if(key == 1)
			{
				shmp->process_info.serviceInput = 0;
				retval = inq_mng_to_recharge;
			}
			else if(key == 2)
			{
				cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
				UpdateAccountOverdraft(shmp->caller_info.head,
										shmp->caller_info.tail,
										cosTableItem->serviceControl[0].creditVaultAmount);
				instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT
							+ shmp->caller_info.tail;
				SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
				shmp->process_info.sub_state = S_INQ_PLAY_OPERATION_DONE;
				if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenApplyOverdraft)
				{
					char notificationSMS[256],buf[32];

					fillMoneyToContent((float)(cosTableItem->serviceControl[0].creditVaultAmount),buf);

					sprintf(notificationSMS,
						"%s%s",
						getSmsSentenceNative(0,SMS_OVERDRAFT_NOTIFICATION),
						buf
						);
					smppSendMOSM((char *)shmp->caller_info.number,
						(char *)ppsParam.ppsTables.serviceNumber[ScratchCardRechargeNumberPosition].number,
						(u_char *)notificationSMS,
						strlen(notificationSMS),
						0);
				}
			}
			else
			{
				retval = inq_mng_exit;
			}
			break;
			default:
				retval = inq_mng_exit;
			break;
		}
		break;
		case S_INQ_PLAY_OPERATION_DONE:
		shmp->process_info.voiceID = OPERATION_SUCESSFULLY_DONE;
		shmp->process_info.srfRelease = 0;
		SendSrfPlayAnnouncement(portid);
		shmp->process_info.sub_state = S_INQ_SRR_OPERATION_DONE;
		break;
		case S_INQ_SRR_OPERATION_DONE:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			return retval;
		
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
	#endif
		retval = inq_mng_exit;
		break;
		case S_INQ_TO_RECHARGE:		
		shmp->process_info.voiceID = INQUIRY_RECHARGE_KEY;
		shmp->process_info.maxPCUInfoLen = 1;
		shmp->process_info.endOfReplyDigit[0] = 0;
		shmp->process_info.endOfReplyDigit[1] = ' ';
		SendPromptCollectedRechargedUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_INQ_TO_RECHARGE_CONFIRM;
		break;
		case S_INQ_TO_RECHARGE_CONFIRM:
		dlgid = shmp->context_info.dialogue_id;

		if(!ReadScfMsg(&capmsg,dlgid))
		{
			return retval;
		}

		#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) 
						|| shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif
		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
					msglen,
					capmsg.msgOperaCode,
					CAP_CONFIRM,
					&capArg)<0)
			{
				return (retval = inq_mng_exit);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			if(pPCUI->digitsResponse[0]<2)
				return (retval = inq_mng_exit);

			key = pPCUI->digitsResponse[2] &0x0F;
			if(key == 1)
			{
				shmp->process_info.serviceInput = 0;
				retval = inq_mng_to_recharge;
			}
			else
			{
				retval = inq_mng_exit;
			}
			break;
			default:
				retval = inq_mng_exit;
			break;
		}
		break;
		case S_INQ_REST_GET:

			tmpval = pps_rest_query_process(portid);
			if( tmpval == 0)
				return retval;
			
			if(tmpval == 1)
			{
				//SendRestAccountInfoPromptToSrf(portid);
				SendAccountInfoPromptToSrf(portid, FALSE, FALSE);
				shmp->process_info.funnel = 0;
				shmp->process_info.srfRelease = 0x01;
				shmp->process_info.sub_state = S_INQ_SRR;
			}
			else
			{
				shmp->process_info.voiceID = ERROR_ACCOUNT_STATUS;
				shmp->process_info.srfRelease = 0;
				SendSrfPlayAnnouncement(portid);
				shmp->process_info.sub_state = S_INQ_SRR0;
			}
			
		break;
	}//sub_state
	return retval;
}


int creditCardRechargeProc(u_short portid)
{
	int				retval,dlgid;	
	u_short			connPort;
	_state_data *shmp,*shmpConn;

	CAP_Message		capmsg;


	PutLogFunID("creditCardRechargeProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = ccr_mng_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{
		return (retval = ccr_mng_exit);
	}

	if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = ccr_mng_exit);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_CCR_PLAY_INFO:
		
		SendAccountInfoPromptToSrf(portid,TRUE,FALSE);
		shmp->process_info.sub_state = S_CCR_SSR;
		break;
		case S_CCR_SSR:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			return retval;
		
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
	#endif

		if(capmsg.msgOperaCode !=CAP_OC_SpecializedResourceReport)
		{
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if((logMsgFlag & 0x04) 
					|| (logMsgFlag & 0x02) 
					|| shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				DebugMsg(debugmib.display.asciiOut,"< Error message received >");
			}
			return (retval=inq_mng_exit);
		}
		AddPPSStatistics(MIBPPS_SPE_RUS_RPT,shmp->process_info.dir);
		shmp->process_info.sub_state = S_CCR_CONNECT_TO_CREDIT_CENTER;
		break;
		case S_CCR_CONNECT_TO_IVR_SCRATCH_CARD:
		connPort = shmp->process_info.correlationID;
		shmpConn = (_state_data *)&smshm_ptr->state_data;
		shmpConn += connPort;
		shmpConn->process_info.callConnected = 1;
		strcpy(shmpConn->process_info.tmpDigits,
					(char *)ppsParam.ppsTables.serviceNumber[ScratchCardRechargeNumberPosition].number);
		retval = ccr_mng_connect_to_credit_center;
		break;
		case S_CCR_CONNECT_TO_CREDIT_CENTER:
		connPort = shmp->process_info.correlationID;
		shmpConn = (_state_data *)&smshm_ptr->state_data;
		shmpConn += connPort;
		shmpConn->process_info.callConnected = 1;
		strcpy(shmpConn->process_info.tmpDigits,
					(char *)ppsParam.ppsTables.serviceNumber[CreditCardRechargeNumberPosition].number);
//		sendConnectForCRDService(connPort);
		
		retval = ccr_mng_connect_to_credit_center;
		break;
	}

	return retval;
}

int WaitingForRechargeTypeResponse(u_short portid)
{
	int				retval=0,dlgid,msglen,len,key;
	CAP_Message		capmsg;
	CapArg			capArg;
    CapPromptAndCollectUserInformation	*pPCUI;
	
	_state_data *shmp;

	PutLogFunID("WaitingForRechargeTypeResponse");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) 
					|| shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = 4);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
				return (retval = 4);

			key = pPCUI->digitsResponse[2]&0x0F;

			if(key == 1)
			{
				retval = 1;
			}
			else if(key == 2)
			{
				retval = 2;				
			}
			else
			{
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
					return (retval=4);
				}
				retval = 3;
			}
		break;
		case CAP_O_UABORT:
		case CAP_O_PABORT:
		default:
			retval = 4;
		break;
	}
	return retval;
}


int WaitingForRechargeAccountResponse(u_short portid)
{
	int				retval=0,dlgid,msglen,len;
	CAP_Message		capmsg;
	CapArg			capArg;
    CapPromptAndCollectUserInformation	*pPCUI;
	
	_state_data *shmp;

	PutLogFunID("WaitingForRechargeAccountResponse");

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

	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) 
					|| shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = 3);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len>11) len = 11;
			if(len<=2) //
			{
				//if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
				{
					if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
					{
						return (retval = 3);
					}
					return (retval = 2);
				}
			}

			if(pPCUI->digitsResponse[1] & 0x20)
			{
				pPCUI->digitsResponse[len] |=0xF0;
			}
			memset(shmp->cdr_info.msisdn,0xFF,10);
			memcpy(shmp->cdr_info.msisdn,
				   &pPCUI->digitsResponse[2],
					len-1);			
			ppsBcdToAsciiR((char *)shmp->recharge_info.number,
					&pPCUI->digitsResponse[2],
					2*(len-1));
			StringCut((char *)shmp->recharge_info.number,'F');
			CutUnknownPrefix((char *)shmp->recharge_info.number);
			GetAccountPos(&shmp->recharge_info);

			shmp->recharge_info.status = GetAccountStatus(&shmp->recharge_info);
			GetAccountCosID(&shmp->recharge_info);
			if(shmp->recharge_info.head>=MSISDN_HEAD_NUM)
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = 3);
				}
				return (retval = 2);
			}

			if(shmp->recharge_info.status != T_FRESH &&
				shmp->recharge_info.status != T_NORMAL &&
				shmp->recharge_info.status != T_SUSPEND	)
			{
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
					return (retval = 3);
				}
				return (retval = 2);						
			}
			retval = 1;
		break;
		case CAP_O_UABORT:
		case CAP_O_PABORT:
		default:
			retval = 3;
		break;
	}
	return retval;
}

int WaitingForRechargePIN(u_short portid)
{
	int				retval=0,dlgid,msglen,len;
	CAP_Message		capmsg;
	CapArg			capArg;
    CapPromptAndCollectUserInformation	*pPCUI;
	
	_state_data *shmp;

	PutLogFunID("WaitingForRechargePIN");

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

	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
					return (retval = 3);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<=2 || len>12)
			{
					return (retval = 3);
			}
			if(pPCUI->digitsResponse[1] & 0x20)
			{
				pPCUI->digitsResponse[len] |=0xF0;
			}
			ppsBcdToAsciiR(shmp->process_info.tmpDigits,
					&pPCUI->digitsResponse[2],
					2*(len-1));
			//StringCut(shmp->process_info.tmpDigits,'F');

			len = strlen(shmp->process_info.tmpDigits);
//			DebugMsg(debugmib.display.asciiOut,"input pwd: %s,len: %d,%s",
//							shmp->process_info.tmpDigits,len,shmp->recharge_info.number);
			if(len != MAX_PIN_LEN)
				return (retval = 2);
			if(CheckPINValidity(&shmp->recharge_info,shmp->process_info.tmpDigits)==0)
			{
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
					return (retval = 3);
				}
				return (retval = 2);
			}
			retval = 1;
		break;
	}
	return retval;
}

int WaitingForRechargeAccountConfirmResponse(u_short portid)
{
	int				retval=0,dlgid,msglen,len,key;
	CAP_Message		capmsg;
	CapArg			capArg;
    	CapPromptAndCollectUserInformation	*pPCUI;
	
	_state_data *shmp;

	PutLogFunID("WaitingForRechargeAccountConfirmResponse");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = 3);				
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
			{
				return (retval = 3);				
			}
			key = pPCUI->digitsResponse[2]&0x0F;
			if(key == 2)
			{
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
					return (retval=3);
				}
				retval = 2;				
			}else if(key == 1)
			{
				shmp->process_info.chargeOther = 1;
				retval = 1;
			}
			else
			{
				shmp->process_info.serviceInput ++;
				retval = 3;				
			}
		break;
		case CAP_O_UABORT:
		case CAP_O_PABORT:
		default:
			retval = 3;
		break;
	}
	return retval;
}

int WaitingForRechargeCardPasswordResponse(u_short portid)
{
	int		retval=0,len,dlgid,
			msglen,result;
	char		card_hrn[32];
	CAP_Message	capmsg;
	CapArg		capArg;
	CapPromptAndCollectUserInformation *pCUI;
	_state_data *shmp;

	PutLogFunID("WaitingForRechargeCardPasswordResponse");

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

	dlgid = shmp->context_info.dialogue_id;
	if(!ReadScfMsg(&capmsg,dlgid))
	{
			return retval;
	}
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				 	return (retval = 3);
			}
			pCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pCUI->digitsResponse[0];
			if(len<2 || len>11) 
			{
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
				 	return (retval = 3);
				}
				return (retval = 2);
			}
			len --;
			if(pCUI->digitsResponse[1] & 0x80)
				pCUI->digitsResponse[len] |= 0xF0;
	
			memset(shmp->cdr_info.called,0xFF,10);
			memcpy(shmp->cdr_info.called,&pCUI->digitsResponse[2],len);

			ppsBcdToAsciiR(card_hrn,&pCUI->digitsResponse[2],len*2);
			if(CheckWetherValidRechargeCard(portid,card_hrn, &result)==0)
			{				
				if(result==5)
				{
					return (retval = 4);
				}			
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
				 	return (retval = 3);
				}
				return (retval = 2);
			}
			else
			{						
				shmp->process_info.serviceInput = 0;
				retval = 1;
			}
		break;
		default:
			retval = 3;
		break;
	}/* swithc */
	return retval;
}

int WaitingForRechargeCardPasswordResponseRcm(u_short portid)
{
    int    retval=0,len,dlgid,
            msglen;
    char card_hrn[32];
    CAP_Message	capmsg;
    CapArg		capArg;
    CapPromptAndCollectUserInformation *pCUI;
    _state_data *shmp;

    PutLogFunID("WaitingForRechargeCardPasswordResponse");

    shmp = (_state_data *)&smshm_ptr->state_data;
    if(portid>=MAX_FSM_PROCESS)
        return -1;
    
    shmp += portid;
    
    
    dlgid = shmp->context_info.dialogue_id;
    if(!ReadScfMsg(&capmsg,dlgid))
    {
        return retval;
    }
  #if DEBUG
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
    {  
        ppsDebugCapMsg(&capmsg,0);
    }
    #endif
            
    if(capmsg.msgOperaCode != CAP_OC_PromptAndCollectUserInformation)
            return 3;

    AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
    shmp->process_info.funnel = 0;
    msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
    capArg.version = shmp->context_info.acn_ver;
    if(decode_capmsg((char *)&capmsg.msgContent[5],
                msglen%140,
                capmsg.msgOperaCode,
                CAP_CONFIRM,
                &capArg)<0)
    {
        return (retval = 3);
    }
    pCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
    len = pCUI->digitsResponse[0];
    if(len<2 || len>11) 
    {
        return (retval = 2);
    }

    len --;

    if(pCUI->digitsResponse[1] & 0x80)
    pCUI->digitsResponse[len] |= 0xF0;
	
    memset(shmp->cdr_info.called,0xFF,10);
    memcpy(shmp->cdr_info.called,&pCUI->digitsResponse[2],len);
    ppsBcdToAsciiR(card_hrn,&pCUI->digitsResponse[2],len*2);

    strcpy((char *)shmp->called_info.number, card_hrn);                

    return (retval = 1);
    
}

int RechargeManageProc(u_short portid)
{
	int					retval,retval1,dlgid;
	int					caller_status,result=0;
	CAP_Message			capmsg;	
	_state_data 		       *shmp;
	COSTable			*cosTableItem;
	int					tmpval;
	
	PutLogFunID("RechargeManageProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = rec_mng_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{
		return (retval = rec_mng_exit);
	}
    	if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = rec_mng_exit);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_REC_CHECK_ACCOUNT_STATUS:
		if(pps_get_adaptor_flag())
		{
			shmp->process_info.sub_state = S_REC_INPUT_PWD;
			return retval;		
		}
		
		caller_status = GetAccountStatus(&shmp->caller_info);
		if(shmp->caller_info.head>=MSISDN_HEAD_NUM)
		{
			shmp->process_info.sub_state = S_REC_INPUT_ACCOUNT;
		}
		else
		{
			if( caller_status != T_NORMAL &&
				caller_status != T_FRESH &&
				caller_status != T_SUSPEND &&
				caller_status != T_OPRTRIAL	)
			{
				shmp->process_info.voiceID = ERROR_ACCOUNT_STATUS;
				shmp->process_info.srfRelease = 1;
				SendSrfPlayAnnouncement(portid);
				shmp->process_info.tcos = NORMAL_CLEARING;
				shmp->process_info.sub_state  = S_REC_WAIT_SRR;
				return retval;
			}

			shmp->process_info.sub_state = S_REC_PLAY_BALANCE;
		}
		break;
		case S_REC_INPUT_ACCOUNT:
		shmp->process_info.chargeFrom = 1; /* charge from SRF */
		shmp->process_info.funnel = 0;
		shmp->process_info.voiceID = INPUT_RECHARGE_ACCOUNT;
		shmp->process_info.endOfReplyDigit[0] = 1;
		shmp->process_info.endOfReplyDigit[1] = 12;
		shmp->process_info.maxPCUInfoLen = 20;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.sub_state = S_REC_WAIT_ACCOUNT;
		break;
		case S_REC_WAIT_ACCOUNT:
		retval1 = WaitingForRechargeAccountResponse(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 2:
			shmp->process_info.srfRelease = 0;
			shmp->process_info.voiceID = ERROR_RECHARGE_ACCOUNT;
			shmp->process_info.maxPCUInfoLen = 20;
			shmp->process_info.endOfReplyDigit[0] = 1;
			shmp->process_info.endOfReplyDigit[1] = 12;
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.funnel = 0;
			break;
			case 1:
			shmp->process_info.serviceInput = 0;
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_REC_INPUT_PIN;
			break;
			case 3:
				retval = rec_mng_exit;
			break;
		}
		break;
		case S_REC_INPUT_PIN:
		shmp->process_info.srfRelease = 0;
		shmp->process_info.endOfReplyDigit[0] = 1;
		shmp->process_info.endOfReplyDigit[1] = 12;
		shmp->process_info.voiceID = INPUT_OLD_PIN;
		shmp->process_info.maxPCUInfoLen = MAX_PIN_LEN;
		SendPromptCollectedRechargedUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.serviceInput = 0;
		shmp->process_info.sub_state = S_REC_WAIT_PIN;
		break;
		case S_REC_WAIT_PIN:
		retval1 = WaitingForRechargePIN(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 1:
			shmp->process_info.rechargeByOther = 1;
			shmp->process_info.funnel = 0;							
			shmp->process_info.sub_state = S_REC_INPUT_PWD;
			break;
			case 2:
			shmp->process_info.srfRelease = 0;
			shmp->process_info.voiceID = ERROR_PIN;
			shmp->process_info.maxPCUInfoLen = MAX_PIN_LEN;
			shmp->process_info.endOfReplyDigit[0] = 1;
			shmp->process_info.endOfReplyDigit[1] = 12;
			SendPromptCollectedRechargedUserInfo(portid);
			shmp->process_info.funnel = 0;				
			break;
			case 3:
			retval = rec_mng_exit;
			break;
		}
		break;
		case S_REC_ACCOUNT_READ:
		shmp->process_info.srfRelease = 0;
		shmp->process_info.voiceID = TO_BE_RECHARGED_NUMBER;
		shmp->process_info.maxPCUInfoLen = 1;
		shmp->process_info.endOfReplyDigit[0] = 1;
		shmp->process_info.endOfReplyDigit[1] = 12;
		SendPromptCollectedRechargedUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.serviceInput = 0;
		shmp->process_info.sub_state = S_REC_ACCOUNT_CONFRIM;
		break;
		case S_REC_ACCOUNT_CONFRIM:
		retval1 = WaitingForRechargeAccountConfirmResponse(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 1:
			shmp->process_info.sub_state = S_REC_INPUT_PWD;
			break;
			case 2:
			shmp->process_info.sub_state = S_REC_INPUT_ACCOUNT;
			break;
			case 3:
			retval = rec_mng_exit;
			break;
		}
		break;
		case S_REC_PLAY_BALANCE:
		shmp->process_info.funnel = 0;
		SendAccountInfoPromptToSrf(portid,TRUE,FALSE);
		shmp->process_info.sub_state = S_REC_WAIT_SRR0;
		break;
		case S_REC_WAIT_SRR0:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			return retval;
		
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
	#endif

		if(capmsg.msgOperaCode !=CAP_OC_SpecializedResourceReport)
		{
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				DebugMsg(debugmib.display.asciiOut,"< Error message received >");
			}
		}
		AddPPSStatistics(MIBPPS_SPE_RUS_RPT,shmp->process_info.dir);
		if(shmp->process_info.serviceType == SRV_RECHARGE_2TYPES)
			shmp->process_info.sub_state = S_REC_INPUT_RECHARGE_TYPE;
		else
			shmp->process_info.sub_state = S_REC_INPUT_PWD;			
		break;
		case S_REC_INQ_CHECK_MENU:
		if(pps_get_adaptor_flag())
		{
			shmp->process_info.sub_state = S_REC_INPUT_PWD;
			return retval;		
		}
		
		cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
		if(cosTableItem->serviceControl[0].rechargeViaCreditCard == 0)
			shmp->process_info.sub_state = S_REC_INPUT_RECHARGE_TYPE;
		else
			shmp->process_info.sub_state = S_REC_INPUT_PWD;
		break;
		case S_REC_INPUT_RECHARGE_TYPE:
		shmp->process_info.funnel = 0;
		shmp->process_info.voiceID = RECHARGE_TYPE_SELECTION;
		shmp->process_info.maxPCUInfoLen = 1;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.sub_state = S_REC_WAIT_TYPE;			
		break;		
		case S_REC_WAIT_TYPE:
		retval1 = WaitingForRechargeTypeResponse(portid);
		switch(retval1)
		{
			case 0: /* keep state */
			break;
			case 1: /* scratch card recharge */
			shmp->process_info.serviceInput = 0;
			shmp->process_info.sub_state = S_REC_INPUT_PWD;
			break;
			case 2: /* credit card recharge */
			retval = rec_mng_turn_to_credit_recharge;
			break;
			case 3:
			shmp->process_info.sub_state = S_REC_INPUT_RECHARGE_TYPE;
			break;
			case 4: /* 3 times input error , hang up */
			retval = rec_mng_exit;
			break;
		}
		break;
		case S_REC_INPUT_PWD:
		/* return to IVR here */
		if(ppsParam.ppsTables.ivrSource[0].recharge)
		{
			return (retval = rec_mng_turn_to_ivr_scratch_card);
		}
		shmp->process_info.chargeFrom = 1; /* charge from SRF */
		shmp->process_info.funnel = 0;
		shmp->process_info.serviceInput = 0;
		shmp->process_info.voiceID = INPUT_PRECARD_PWD;
		shmp->process_info.endOfReplyDigit[0] = 1;
		shmp->process_info.endOfReplyDigit[1] = 12;
		shmp->process_info.maxPCUInfoLen = 20;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.sub_state = S_REC_CHECK_PWD;
		break;
		case S_REC_CHECK_PWD:
		retval1 = WaitingForRechargeCardPasswordResponseRcm(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 1:
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_REC_CHECK_CARD_VALIDITY;
			break;
			case 2:	/* error pwd, input again */
			default:
			shmp->process_info.sub_state = S_REC_INPUT_PWD_AGAIN;
			break;	     
		}
		break;
	       case S_REC_CHECK_CARD_VALIDITY:
			if(UseExternalVC())
                     {
                         shmp->process_info.sub_state_2 = 0;
                         shmp->process_info.sub_state = S_REC_CHECK_CARD_WITH_RCM;
                        return retval;
                     }
			if(OCS_with_external_CRM())
			{
                         shmp->process_info.sub_state_2 = 0;
                         shmp->process_info.sub_state = S_REC_CHECK_CARD_WITH_CRM;
                        return retval;
			}
			
			if(pps_get_adaptor_flag())
			{
				shmp->process_info.sub_state_2 = 0;
				shmp->process_info.sub_state = S_REC_CHECK_CARD_WITH_REST;
				strcpy((char *)shmp->origin_info.number, (char *)shmp->called_info.number);
						 
				return retval;
			}

			if(CheckWetherValidRechargeCard(portid, (char *)shmp->called_info.number, &result)==0)
			{
			    if(result == 5) /* too much money in account */
			        return ( retval = rec_mng_exit );
			    else
			    {
			    	shmp->process_info.sub_state = S_REC_INPUT_PWD_AGAIN;
			    	return retval;
			    }
			}
			else
			{						
				shmp->process_info.serviceInput = 0;
			}			
			RechargeRequestProc(portid);
			shmp->process_info.srfRelease = 0;
			shmp->process_info.maxPCUInfoLen = 1;
			SendRechargeInfoPromptToSrf(portid);
			shmp->process_info.sub_state = S_REC_WAIT_SRR;
			break;			  	
	       break;
		case S_REC_INPUT_PWD_AGAIN:
			if(shmp->process_info.serviceInput ++ >SERVICE_INPUT_NUM)
			{
			    return ( retval = rec_mng_exit );
			}
   		       shmp->process_info.srfRelease = 0;
			shmp->process_info.voiceID = RECHARGE_FAILED;
			shmp->process_info.maxPCUInfoLen = 20;
			shmp->process_info.endOfReplyDigit[0] = 1;
			shmp->process_info.endOfReplyDigit[1] = 12;
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_REC_CHECK_PWD;
		break;
		case S_REC_CHECK_CARD_WITH_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.funnel > SSHORT_DELAY_TIMER)
            	            {            	               
            	                if(shmp->process_info.serviceInput ++>3)
            	                {
            	                    return rec_mng_exit;
            	                }
            	                shmp->process_info.sub_state_2 = 0;
            	                return retval;
            	            }
            	  	     if(!shmp->process_info.update_card_ack)
            	  	    {
            	  	        return retval;
            	  	    }
            	  	    if(shmp->process_info.update_card_result != OC_RESULT_OK)
            	  	    {
            	  	        RechargeFailedUpdateAccountData(portid);
				 shmp->process_info.sub_state = S_REC_INPUT_PWD_AGAIN;
            	  	        return retval;
            	  	    }
            	  	    RechargeRequestProc(portid);
			    shmp->process_info.srfRelease = 0;
			    shmp->process_info.maxPCUInfoLen = 1;
			   	SendRechargeInfoPromptToSrf(portid);
			    shmp->process_info.sub_state = S_REC_WAIT_SRR;
            	       break;
			default:
				return rec_mng_exit;
            	       break;
                 }
            break;			
		case S_REC_CHECK_CARD_WITH_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.funnel > SSHORT_DELAY_TIMER)
            	            {            	               
            	                if(shmp->process_info.serviceInput ++>3)
            	                {
            	                    return rec_mng_exit;
            	                }
            	                shmp->process_info.sub_state_2 = 0;
            	                return retval;
            	            }
            	  	     if(!shmp->process_info.rest_if.recv_cmd)
            	  	    {
            	  	        return retval;
            	  	    }
   			    if(shmp->process_info.rest_if.result)
			    {
         	  	        RechargeFailedUpdateAccountData(portid);
				 shmp->process_info.sub_state = S_REC_INPUT_PWD_AGAIN;
            	  	        return retval;
               	     }
            	  	    RechargeSucceedwithCRM(portid);
						
			    shmp->process_info.srfRelease = 0;
			    shmp->process_info.maxPCUInfoLen = 1;
			   SendRechargeInfoPromptToSrf(portid);
			    shmp->process_info.sub_state = S_REC_WAIT_SRR;
            	       break;
			default:
				return rec_mng_exit;
            	       break;
                 }
            break;
            case S_REC_WAIT_SRR:

		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			return retval;
		
	#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
	#endif

		if(capmsg.msgOperaCode !=CAP_OC_SpecializedResourceReport)
		{
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				DebugMsg(debugmib.display.asciiOut,"< Error message received >");
			}
		}
		AddPPSStatistics(MIBPPS_SPE_RUS_RPT,shmp->process_info.dir);

		retval = rec_mng_exit;		
		break;
		case S_REC_CHECK_CARD_WITH_REST:
			tmpval = pps_rest_topup_process(portid);
			if(tmpval == 0)
				return retval;
			if(tmpval == 1)
			{
				retval = rec_mng_exit;		
			}
			else
			{
				shmp->process_info.srfRelease = 1;
				shmp->process_info.voiceID = RECHARGE_FAILED;
				SendSrfPlayAnnouncement(portid);
				shmp->process_info.tcos = NORMAL_CLEARING;
				shmp->process_info.sub_state  = S_REC_WAIT_SRR;
				return retval;
			}
			
		break;
		case S_REC_CHECK_CARD_WITH_REST_GET:
			tmpval = pps_rest_query_process(portid);
			if(tmpval == 0)
				return retval;

			shmp->process_info.srfRelease = 0;
			shmp->process_info.maxPCUInfoLen = 1;
			SendRestRechargeInfoPromptToSrf(portid);			
			shmp->process_info.sub_state = S_REC_WAIT_SRR;
			
		break;
	}
	return retval;
}

/* ------------------- end of recharge functions ----------------*/

/* ------------------ favorite number management functions ------*/

int WaitingForFavoriteNumberFunctionResponse(u_short portid)
{

	int				retval=0,len,dlgid,
					counter,msglen,serviceKey;
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;
	_state_data		*shmp;

	PutLogFunID("WaitingForFavoriteNumberFunctionResponse");

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

	dlgid = shmp->context_info.dialogue_id;
	if(!ReadScfMsg(&capmsg,dlgid)) return retval;
	
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = 4);
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
				return (retval = 4);
			serviceKey = pPCUI->digitsResponse[2]&0x0F;
			
			counter = GetAccountFavoriteNumberCounter(&shmp->caller_info);
			switch(serviceKey)
			{
				case 1: /* add */
				if(counter == MAX_FAVORITE_NUMBERS)
				{
					if(shmp->process_info.serviceInput ++ >=SERVICE_INPUT_NUM)
					{
						return 6;		
					}						
					shmp->process_info.srfRelease = 0;
					shmp->process_info.voiceID = FULL_FAVORITE_NUMBER; /* + main menu */
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					shmp->process_info.funnel = 0;
					return (retval = 4);
				}
				retval = 1;
				break;
				case 2: /* edit */
				if(counter==0)
				{
					if(shmp->process_info.serviceInput ++ >=SERVICE_INPUT_NUM)
					{
						return 6;		
					}						
					shmp->process_info.srfRelease = 1;
					shmp->process_info.voiceID = NO_FAVORITE_NUMBER;  /* + main menu */
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					return (retval = 4);
				}					
				retval = 2;
				break;
				case 3: /* inquiry */
				if(counter<=0)
				{
					if(shmp->process_info.serviceInput ++ >=SERVICE_INPUT_NUM)
					{
						return 6;		
					}
					shmp->process_info.srfRelease = 1;
					shmp->process_info.voiceID = NO_FAVORITE_NUMBER; /*+ main menu */
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					return (retval = 4);
				}					
				retval = 3;
				break;					
				case 0: // exit to main menu 
				retval = 5;
				break;
				default:
				retval = 6;
				break;
			}
		break;
		default:
			retval = 6;
		break;
	}/* swithc */

	return retval;

}

int WaitingForFavoriteNumberAddResponse(u_short portid)
{
	int				retval=0,len,dlgid,
					msglen, errflag = 0;
	char			       msisdn[32];
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;
	_state_data		*shmp;

	PutLogFunID("WaitingForFavoriteNumberAddResponse");

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


	dlgid = shmp->context_info.dialogue_id;
	if(!ReadScfMsg(&capmsg,dlgid)) return retval;
	
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
					return (retval = 2);
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0]-1;
			if(len<0) len=0;
			if(len >=MAX_MSISDN_BLEN+1 || len<2)
			{
			    errflag = 1;
			}
			else
			{
			    if(pPCUI->digitsResponse[1] & 0x20)
				 pPCUI->digitsResponse[len+1] |= 0xF0;
			    ppsBcdToAsciiR(msisdn,&pPCUI->digitsResponse[2],(len)*2);
			    StringCut(msisdn,'F');

			    strcpy(shmp->process_info.tmpDigits,msisdn);
			
			    CutUnknownPrefix(msisdn);
			    if(CheckWetherFavoriteNumber(&shmp->caller_info, msisdn)==FAVORITE_NUMBER)
			        errflag = 2;
			}
			if(errflag>0)
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = 0);
				}
				shmp->process_info.srfRelease = 0;
				if(errflag == 1)
				     shmp->process_info.voiceID = ERROR_FAVUMBER_INPUT_AND_INPUT_AGAIN;
				else
				    shmp->process_info.voiceID = FAVUMBER_EXIST_INPUT_AGAIN;
				shmp->process_info.maxPCUInfoLen = 20;
				shmp->process_info.endOfReplyDigit[0] = 1;
				shmp->process_info.endOfReplyDigit[1] = 12;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				return (retval = 0);				
			
			}
			retval = 1;				
		break;
		default:
			retval = 2;
		break;
	}/* swithc */
	return retval;
}

int WaitingForFavoriteNumberAddConfirmResponse(u_short portid)
{
	int				retval=0,dlgid,msglen,instance,
					key;
	CAP_Message		capmsg;
	CapArg			capArg;
    CapPromptAndCollectUserInformation	*pPCUI;
	CosFriendFamilyControl	 	*serviceControlItem;
	
	_state_data *shmp;

	PutLogFunID("WaitingForFavoriteNumberAddConfirmResponse");

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

	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
					return (retval=4);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			key = pPCUI->digitsResponse[2]&0x0F;


			if(key == 2)//cancel
			{
				if(shmp->process_info.serviceInput++>SERVICE_INPUT_NUM)
				{
					return (retval=4);
				}
				retval = 2;
			}
			else if(key == 1)//confirm
			{

				shmp->process_info.srfRelease = 0;
				shmp->process_info.voiceID = ADD_FAVORITE_NUMBER_SUC; /* + fav. main menu */
				shmp->process_info.maxPCUInfoLen = 1; 
				shmp->process_info.endOfReplyDigit[0] = 1;
				shmp->process_info.endOfReplyDigit[1] = 12;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.serviceInput = 0;

				if(!shmp->process_info.editFavNumber)
				{
					StoreAccountFavoriteNumber(&shmp->caller_info,
							shmp->process_info.tmpDigits,
							0);	
					
				}
				else
				{
					StoreAccountFavoriteNumber(&shmp->caller_info,
							shmp->process_info.tmpDigits,
							shmp->process_info.choice_sn);	

					shmp->process_info.editFavNumber = 0;
					serviceControlItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id].friendFamilyControl[0];
					if(serviceControlItem->friendFamilyChangeChargeFlag)
					{
						if(IncreaseFavoriteNumberChangeCounter(shmp->caller_info.head,
																shmp->caller_info.tail)>
							serviceControlItem->friendFamilyFreeChangeTimes)
						{
							BillingFavoriteNumberChange(shmp);
							SendPPSGeneralCDR(shmp->caller_info.head,
								shmp->caller_info.tail,
								shmp->caller_info.charge,
								CT_FF_NUMBER_EDIT);
						}
					}
				}
				instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT +
							shmp->caller_info.tail;
				SendAccountRealSync(instance,-(shmp->caller_info.charge),0.0,OMC_OCODE_EDIT);

				retval = 1;

			}else //quit to main menu
			{
				retval = 3;				
			}
		break;
		case CAP_O_UABORT:
		case CAP_O_PABORT:
		default:
			retval = 4;
		break;
	}
	return retval;

}

int WaitingForEditFavoriteNumberSNResponse(u_short portid)
{
	int				retval=0,len,dlgid,
					msglen,sn,counter;
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;
	_state_data		*shmp;

	PutLogFunID("WaitingForEditFavoriteNumberSNResponse");

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

	dlgid = shmp->context_info.dialogue_id;
	if(ReadScfMsg(&capmsg,dlgid))
	{
		#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
				AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
				shmp->process_info.funnel = 0;
				msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
				capArg.version = shmp->context_info.acn_ver;
				if(decode_capmsg((char *)&capmsg.msgContent[5],
								msglen,
								capmsg.msgOperaCode,
								CAP_CONFIRM,
								&capArg)<0)
				{
					return (retval = 3);
				}
				pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
				len = pPCUI->digitsResponse[0];
				if(len<2 || len>12)
					return (retval = 3);
				len --;
				sn = pPCUI->digitsResponse[2]&0x0F;
				counter = GetAccountFavoriteNumberCounter(&shmp->caller_info);

				if(sn<1 || sn>counter )
				{
					if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
					{
						return (retval = 3);
					}
					shmp->process_info.srfRelease = 0;
					shmp->process_info.voiceID = NO_SUCH_SN_FAVORITE_NUMBER; /* input again */
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					shmp->process_info.funnel = 0;
					return (retval = 2);				
				}
				shmp->process_info.choice_sn = sn;
				shmp->process_info.editFavNumber = 1;
				retval = 1;				
			break;
			default:
				retval = 3;
			break;
		}/* swithc */
	}/* if */
	return retval;
}

int WaitingForInquiryFavoriteNumberSNResponse(u_short portid)
{
	int				retval=0,len,dlgid,
					msglen,sn,counter;
	char			msisdn[32];
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;
	_state_data		*shmp;

	PutLogFunID("WaitingForInquiryFavoriteNumberSNResponse");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid)) return retval;
	
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	    debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = 2);
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
				return (retval = 2);

			sn = pPCUI->digitsResponse[2]&0x0F;

			counter = GetAccountFavoriteNumber(&shmp->caller_info,msisdn,sn);
			if(!counter )
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = 3);
				}
				shmp->process_info.srfRelease = 0;
				shmp->process_info.voiceID = NO_SUCH_SN_FAVORITE_NUMBER; /* + input serial no */
				shmp->process_info.maxPCUInfoLen = 1;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				return (retval = 2);				
			}


			if(IsEnableToAddEditFavoriteNumber(shmp,0))
		    		shmp->process_info.voiceID = SN_X_FAVORITE_NUMBER_IS; /* + main menu */
			else if(IsEnableToAddEditFavoriteNumber(shmp,1))
		    		shmp->process_info.voiceID = FAVORITE_READ_NUMBER_DIDT_QUERY; /* + main menu */
	       	else
	           		shmp->process_info.voiceID = FAVORITE_READ_NUMBER_QUERY; /* + main menu */
			
			shmp->process_info.maxPCUInfoLen = 1;
			
			len = msisdn[MAX_MSISDN_BLEN-1];
			BcdToAscii(shmp->process_info.tmpDigits, (BYTE *)msisdn, (len+1)/2*2);
			shmp->process_info.tmpDigits[len]=0;

			SendFavPromptAndCollectUserInfo(portid);
			
			shmp->process_info.serviceInput = 0;
			retval = 1;
		break;
		default:
			retval = 3;
		break;
	}/* swithc */

	return retval;
}

int FavoriteNumberManageProc(u_short portid)
{
	int				retval,retval1;
	
	_state_data *shmp;

	PutLogFunID("FavoriteNumberManageProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = fav_mng_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{
		SendScfTcEND(portid);
		return (retval = fav_mng_exit);
	}
    if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = fav_mng_exit);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_FAV_PLAY_MENU:
		shmp->process_info.funnel = 0;
		if(IsEnableToAddEditFavoriteNumber(shmp,0))
		{
		   if(IsEnableToAddEditFavoriteNumber(shmp,1))
		        shmp->process_info.voiceID = FAVORITE_NUMBER_FUNC;
		   else
		   	shmp->process_info.voiceID = FAVORITE_NUMBER_FUNC_QUERY; /* play  query voice */	
		}
		else if(IsEnableToAddEditFavoriteNumber(shmp,1))
		    shmp->process_info.voiceID = FAVORITE_NUMBER_FUNC_EDIT_QUERY; /* play edit & query voice */
	       else
	           shmp->process_info.voiceID = FAVORITE_NUMBER_FUNC_QUERY; /* play  query voice */	
		shmp->process_info.maxPCUInfoLen = 1;
		shmp->process_info.serviceInput = 0;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.sub_state = S_FAV_SET_TYPE;
		break;
		case S_FAV_SET_TYPE:
		retval1 = WaitingForFavoriteNumberFunctionResponse(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 1: /* add */
			if(!IsEnableToAddEditFavoriteNumber(shmp,0))
			{
			    shmp->process_info.voiceID = FULL_FAVORITE_NUMBER;
			    shmp->process_info.sub_state = S_FAV_PLAY_MENU;
			}
			else
			{
			    shmp->process_info.voiceID = INPUT_NEW_FAVORITE_NUMBER;
			    shmp->process_info.sub_state = S_FAV_INPUT_NEW_NUMBER;
			}
			break;
			case 2: /* edit */
			if(!IsEnableToAddEditFavoriteNumber(shmp,1))
			    shmp->process_info.sub_state = S_FAV_PLAY_MENU;
			else
			    shmp->process_info.sub_state = S_FAV_INPUT_EDIT_NO;
			break;
			case 3: /* iquiry */
			shmp->process_info.sub_state = S_FAV_INQUIRY;
			break;
			case 4:
			shmp->process_info.sub_state = S_FAV_SET_TYPE;
			break;
			case 5: /* to main menu */
			retval = fav_mng_exit_to_main_menu;
			break;
			case 6: /* exit */
			retval = fav_mng_exit;
			break;
		}
		break;
		case S_FAV_INPUT_NEW_NUMBER:
		if(shmp->process_info.serviceInput++>3)
		{
		    return (retval = fav_mng_exit);
		}
		
		shmp->process_info.srfRelease = 0;
		//shmp->process_info.voiceID = INPUT_NEW_FAVORITE_NUMBER;
		shmp->process_info.maxPCUInfoLen = 20;
		shmp->process_info.endOfReplyDigit[0] = 1;
		shmp->process_info.endOfReplyDigit[1] = 12;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_FAV_WAIT_NEW_NUMBER;
		break;
		case S_FAV_WAIT_NEW_NUMBER:
		retval1 = WaitingForFavoriteNumberAddResponse(portid);
		switch(retval1)
		{
			case 0: /* keep */
			break;
			case 1: /* success */
			if(!IsFavoriteNumberTypeOk(shmp))
			{			    
			    shmp->process_info.voiceID = ERROR_FAVUMBER_INPUT_AND_INPUT_AGAIN;
		           shmp->process_info.sub_state = S_FAV_INPUT_NEW_NUMBER;
			}
			else
			    shmp->process_info.sub_state = S_FAV_SET_CONFIRM;
			break;
			case 2:
			retval = fav_mng_exit;
			break;
		}
		break;
		case S_FAV_SET_CONFIRM:
		shmp->process_info.srfRelease = 0;//2
		shmp->process_info.voiceID = TO_BE_ADDED_NUMBER_IS;
		shmp->process_info.maxPCUInfoLen = 1;
		shmp->process_info.serviceInput = 0;
		SendFavPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_FAV_WAIT_CONFIRM;
		break;
		case S_FAV_WAIT_CONFIRM:
		retval1 = WaitingForFavoriteNumberAddConfirmResponse(portid);
		switch(retval1)
		{
			case 1: /* confirm */
			shmp->process_info.sub_state = S_FAV_SET_TYPE;
			break;
			case 2: /* cancel */
			shmp->process_info.voiceID = INPUT_NEW_FAVORITE_NUMBER;
			shmp->process_info.sub_state = S_FAV_INPUT_NEW_NUMBER;
			break;
			case 3: /* to fav. main menu */
			shmp->process_info.sub_state = S_FAV_PLAY_MENU;
			break;
			case 4: /* exit */
			retval = fav_mng_exit;
			break;
		}
		break;
		case S_FAV_INPUT_EDIT_NO:
		shmp->process_info.srfRelease = 0;
		shmp->process_info.voiceID = INPUT_EDIT_FAVORITE_NUMBER_SN;
		shmp->process_info.maxPCUInfoLen = 1;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.serviceInput = 0;
		shmp->process_info.sub_state = S_FAV_WAIT_EDIT_NO;
		break;
		case S_FAV_WAIT_EDIT_NO:
		retval1 = WaitingForEditFavoriteNumberSNResponse(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 1: /* ok */
			shmp->process_info.voiceID = INPUT_NEW_FAVORITE_NUMBER;
			shmp->process_info.sub_state = S_FAV_INPUT_NEW_NUMBER;
			break;
			case 2: /* no such serial no. input again */
			break;
			case 3:
			retval = fav_mng_exit;
			break;
		}
		break;
		case S_FAV_INQUIRY:
		shmp->process_info.srfRelease = 1;
		shmp->process_info.voiceID = INPUT_INQUIRY_FAVORITE_NUMBER_SN;
		shmp->process_info.maxPCUInfoLen = 1;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state =  S_FAV_INQUIRY_READ;
		break;
		case S_FAV_INQUIRY_READ:
		retval1 = WaitingForInquiryFavoriteNumberSNResponse(portid);
		switch(retval1)
		{
			case 0:
			break;
			case 1:
			shmp->process_info.sub_state = S_FAV_SET_TYPE;
			break;
			case 2:
			shmp->process_info.sub_state = S_FAV_INQUIRY_READ;
			break;
			case 3:
			retval = fav_mng_exit;
			break;
		}
		break;
	}
	return retval;
}

/* ------------- language set functions --------------------*/
int LanguageManagementProc(u_short portid)
{
	int				retval,len,dlgid,
					msglen,sn,instance;
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;

	_state_data		*shmp;

	PutLogFunID("LanguageManagementProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = language_mng_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
		return (retval = language_mng_exit);
	if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = language_mng_exit);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_LANGUAGE_MANAGE_MENU:
		shmp->process_info.maxPCUInfoLen = 1;
		shmp->process_info.voiceID = LANGUAGE_MANAGEMENT_MENU;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_LANGUAGE_SET;
		break;
		case S_LANGUAGE_SET:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;
			
		#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = language_mng_exit);  //timeout ,exit 
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12) 
				return (retval = language_mng_exit);  //timeout ,exit 
			sn = pPCUI->digitsResponse[2] & 0x0F;
			shmp->process_info.choice_sn = sn;
			if( sn > MAX_LANGUAGE_TYPES) //max language types = 5
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = language_mng_exit);
				}
				shmp->process_info.maxPCUInfoLen = 1;
				shmp->process_info.voiceID = INVALID_LANGUAGE_SELECTION_KEY;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_LANGUAGE_SET;						
			}
			if(sn == 0)
			{
				return (retval = language_mng_exit_to_main_menu);
			}
			shmp->process_info.maxPCUInfoLen = 1;
			shmp->process_info.voiceID = YOUR_DEFAULT_LANGUAGE_SET_IS;
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_LANGUAGE_SET_CONFIRM;
			break;
			default:
			return (retval = language_mng_exit);
			break;
		}				
		break;
		case S_LANGUAGE_SET_CONFIRM:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;
			
		#if DEBUG
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = language_mng_exit);  //timeout ,exit 
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
				return (retval = language_mng_exit);  //timeout ,exit 
			sn = pPCUI->digitsResponse[2] & 0x0F;
			if(sn == 1) //confirm 
			{
				shmp->process_info.serviceInput = 0;
				UpdateAccountDefaultLanguageType(&shmp->caller_info,
						shmp->process_info.choice_sn-1);
				instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT +
							shmp->caller_info.tail;
				SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
						
				retval = language_mng_exit_to_main_menu;
			}
			else if(sn == 2) //re-input
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
					 return (retval = language_mng_exit);   
				shmp->process_info.maxPCUInfoLen = 1;
				shmp->process_info.voiceID = LANGUAGE_MANAGEMENT_MENU;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_LANGUAGE_SET;
			}
			else
			{
				retval = language_mng_exit_to_main_menu;
			}
			break;
			default:
			return (retval = language_mng_exit);
			break;
		}				
		break;
	}

	return retval;
}
/* ------------- end of language set functions --------------------*/


/* ------------- PIN set functions --------------------*/
int PINManagementProc(u_short portid,u_char callingCardFlag)
{/* calling card*/
	int				retval,len,dlgid,
					msglen,instance;
	char			pin[MAX_PIN_LEN+1];
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;

	_state_data		*shmp;

	PutLogFunID("PINManagementProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = pin_mng_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
		return (retval = pin_mng_exit);
	if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = pin_mng_exit);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_PIN_INPUT_OLD_PIN:
		shmp->process_info.maxPCUInfoLen = MAX_PIN_LEN;
		shmp->process_info.voiceID = INPUT_OLD_PIN;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_PIN_CHECK_OLD_PIN;
		break;
		case S_PIN_CHECK_OLD_PIN:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;			
		#if DEBUG
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = pin_mng_exit);  //timeout ,exit 			
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
				return (retval = pin_mng_exit);  //timeout ,exit 			
			len --;
			if(pPCUI->digitsResponse[1] & 0x20)
			{
				pPCUI->digitsResponse[len+1] |= 0xF0;
				len =len * 2-1;
			}
			else
				len *=2;
			if( len != MAX_PIN_LEN) //max language types = 5
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = pin_mng_exit);
				}
				shmp->process_info.maxPCUInfoLen = 6;
				shmp->process_info.voiceID = ERROR_PIN_LENGTH;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_PIN_CHECK_OLD_PIN;		
				return retval;
			}
			ppsBcdToAsciiR(shmp->process_info.tmpDigits,
							&pPCUI->digitsResponse[2],
							len);
			shmp->process_info.tmpDigits[MAX_PIN_LEN] = 0;
			if(!CheckPINValidity(&shmp->caller_info,shmp->process_info.tmpDigits))
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = pin_mng_exit);
				}
				shmp->process_info.maxPCUInfoLen = 6;
				shmp->process_info.voiceID = ERROR_PIN;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_PIN_CHECK_OLD_PIN;						
				return retval;
			}
			shmp->process_info.serviceInput = 0;
			shmp->process_info.sub_state = S_PIN_MANAGE_MENU;						
			break;
		}
		break;
		case S_PIN_MANAGE_MENU:
		shmp->process_info.maxPCUInfoLen = 6;
		shmp->process_info.voiceID = INPUT_NEW_PIN;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_PIN_NEW_SET;
		break;
		case S_PIN_NEW_SET:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;			
		#if DEBUG
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = pin_mng_exit);  //timeout ,exit 			
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12) 
				return (retval = pin_mng_exit);  //timeout ,exit 			
			len --;
			if(pPCUI->digitsResponse[1] & 0x20)
			{
				pPCUI->digitsResponse[len+1] |= 0xF0;
				len =len * 2-1;
			}
			else
				len *=2;
			if( len != MAX_PIN_LEN) //max language types = 5
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = pin_mng_exit);
				}
				shmp->process_info.maxPCUInfoLen = 6;
				shmp->process_info.voiceID = ERROR_PIN_LENGTH;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_PIN_NEW_SET;		
				return retval;
			}
			ppsBcdToAsciiR(shmp->process_info.tmpDigits,
							&pPCUI->digitsResponse[2],
							len);
			shmp->process_info.tmpDigits[MAX_PIN_LEN] = 0;

			DebugMsg(debugmib.display.asciiOut,"%s",shmp->process_info.tmpDigits);
			
			shmp->process_info.serviceInput = 0;
			shmp->process_info.maxPCUInfoLen = 6;
			shmp->process_info.voiceID = INPUT_NEW_PIN_AGAIN;
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_PIN_SET_AGAIN;						
			break;
			default:
			return (retval = pin_mng_exit);
			break;
		}				
		break;
		case S_PIN_SET_AGAIN:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;
			
		#if DEBUG
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif

		switch(capmsg.msgOperaCode)
		{
			case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = pin_mng_exit);  //timeout ,exit 			
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<2 || len>12)
				return (retval = pin_mng_exit);  //timeout ,exit 			
			len --;
			if(pPCUI->digitsResponse[1] & 0x20)
			{
				pPCUI->digitsResponse[len+1] |= 0xF0;
				len =len * 2-1;
			}
			else
				len *=2;
			if( len != MAX_PIN_LEN) //max language types = 5
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = pin_mng_exit);
				}
				shmp->process_info.maxPCUInfoLen = 6;
				shmp->process_info.voiceID = ERROR_PIN_LENGTH;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_PIN_SET_AGAIN;
				return retval;
			}
					
			ppsBcdToAsciiR(pin,
							&pPCUI->digitsResponse[2],
							len);
			pin[MAX_PIN_LEN] = 0;
			DebugMsg(debugmib.display.asciiOut,"%s-%s",pin,shmp->process_info.tmpDigits);
			if(strcmp(pin,shmp->process_info.tmpDigits))
			{
				if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
				{
					return (retval = pin_mng_exit);
				}
				shmp->process_info.maxPCUInfoLen = 6;
				shmp->process_info.voiceID = TWO_PINS_NOT_MATCH;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.funnel = 0;
				shmp->process_info.sub_state = S_PIN_SET_AGAIN;		
				return retval;
			}
			shmp->process_info.tmpDigits[MAX_PIN_LEN] = 0;
			shmp->process_info.serviceInput = 0;
			instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT +
						shmp->caller_info.tail;
			UpdateAccountPIN(&shmp->caller_info,pin);
			SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
			shmp->process_info.sub_state = S_PIN_SET_OK;
			break;
			default:
				return (retval = pin_mng_exit);
			break;
		}		
		break;
		case S_PIN_SET_OK:
		if(!callingCardFlag)
			shmp->process_info.voiceID = PIN_SET_OK;
		else
			shmp->process_info.voiceID = CallingCardPasswordSetSuccess;
		shmp->process_info.voiceID = PIN_SET_OK;
		shmp->process_info.srfRelease = 0;														
		SendSrfPlayAnnouncement(portid);
		shmp->process_info.sub_state = S_PIN_SET_OK_1;
		shmp->process_info.funnel = 0;
		break;
		case S_PIN_SET_OK_1:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;
			
		#if DEBUG
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif
		retval = pin_mng_exit_to_main_menu;
		break;
	}

	return retval;
}
/* ------------- end of PIN set functions --------------------*/

int pps_routing_home_proc(u_short portid)
{
	int	retval=0;
	_state_data	*shmp;
	MapComSrv_struct	com_data;
	MapOprSrv_struct	opr_srv;
   	struct MapPRN_Res	*prn_res;
	
	u_char data_flow[256];

	PutLogFunID("pps_routing_home_proc");

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

	if(shmp->process_info.funnel++>(SSHORT_DELAY_TIMER))
	{
		pps_send_map_close(portid);
		shmp->process_info.routing_home_flag = 0;
		return -1;
	}

	switch(shmp->process_info.sub_state)
	{
		case 0:
			pps_send_map_open(portid);
			pps_send_routing_home_prn(portid);
			shmp->process_info.sub_state = 1;
			shmp->process_info.funnel = 0;
		break;
		case 1:
			if(map_get_oprdata(data_flow,shmp->context_info.map_did))
			{
				u_char	msglen;
				msglen = data_flow[0] * 256 + data_flow[1];
				if((data_flow[9] != ProvRoamNum) || msglen<14)
				{
					if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
					{
						DebugMsg(debugmib.display.asciiOut,
								"\n\33[31m portid: %d ,did: %d, wait PRN_Res but %d received\33[0m",
								portid,shmp->context_info.map_did,data_flow[9]);
					}		
					return -1;
				}
				if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\nportid: %d ,did: %d, Get Map opr,type:<%d>, PRN response \33[0m",
							portid,shmp->context_info.map_did,	data_flow[9]);			
					pps_debug_map_msg(data_flow,0);
				}
		
				opr_srv.version = 2;	
				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 PRN_Res failed \33[0m",
							portid,shmp->context_info.map_did);
					}		
					return -1;
				}
		
				prn_res = &opr_srv.msg_list.prn_res;
				ppsBcdToAsciiR(shmp->process_info.tmpDigits, &prn_res->roam_num[2], (prn_res->roam_num[0]-1)*2);
				if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\nportid: %d ,did: %d, routing home number: %s \33[0m",
							portid,shmp->context_info.map_did,	shmp->process_info.tmpDigits);			
					pps_debug_map_msg(data_flow,0);
				}

				retval = 1;				
			}
			else
			{
				if(map_get_comdata_struct(&com_data,shmp->context_info.map_did))
				{		
		
					if(com_data.message_type == MAP_OPEN)
					{
						if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
						{
							DebugMsg(debugmib.display.asciiOut,
								"\nportid: %d ,did: %d, Get Map Open Res. @ %ld.%ld",
								portid,shmp->context_info.map_did,
								tvnow.tv_sec,tvnow.tv_usec);
							map_com_stof(&com_data,data_flow,0);
							pps_debug_map_msg(data_flow,0);
						}			
					}
					else 
					{
						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);
						}			
						retval = 1;
					}				
				}				
			}			
		break;
	}
	return retval;
}


/* -------------------call distribution functions------------------*/
int CheckCRDService(u_short portid)
{
	int				retval;
	int				msglen,len;
	char			msisdn[32];
	u_short			dlgid,correlationID;
	CAP_Message		capmsg;
	CapArg			capArg;
	CapPromptAndCollectUserInformation *pPCUI;
	_state_data		*shmp,*shmpconn;

	PutLogFunID("CheckCRDService");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	retval = crd_keep_state;

	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
		return (retval = crd_release_call);

	if(shmp->process_info.disconnectForwardConnection == 1)
	{
		SendScfTcEND(portid);
		return (retval = crd_release_call);
	}

	switch(shmp->process_info.sub_state)
	{
		case S_CRD_CHECK_CALLER_INFO:
		if(shmp->context_info.callType == CT_MF_CALL)
		{
			shmp->process_info.chargeOther = 2;
			shmp->process_info.sub_state = S_CRD_CONNECT;
			return retval; 
		}
		/*
		if(CheckWetherHPLMNUser(shmp->caller_info.number))
		{
			shmp->process_info.sub_state = S_CRD_CONNECT;
		}
		*/
		/* added by Pierre, 2005-11-28, 
		 * for Local other network, CCNDC is the same */
		if(GetCRDDestination((char *)shmp->caller_info.number,
								msisdn,
								shmp->process_info.serviceType-SRV_CRD)) 
		{
			shmp->process_info.sub_state = S_CRD_CONNECT;
		}
		else 
		{/*
			shmp->process_info.funnel = 0;
			shmp->process_info.voiceID = SERIVCE_NOT_APPLIED;
			SendSrfPlayAnnouncement(portid);
			shmp->process_info.sub_state = S_CRD_SRR;
		 */
			shmp->process_info.sub_state = S_CRD_INPUT_VOICEBOX;
			shmp->process_info.serviceType = SRV_OTHER_VMS_MAITENANCE;
		}
		break;
		case S_CRD_INPUT_VOICEBOX:
		case S_CRD_SET_DEPOSIT:
		if(shmp->context_info.callType == CT_MF_CALL)
		{
			shmp->process_info.funnel = 0;
			shmp->process_info.voiceID = SERIVCE_NOT_APPLIED;
			SendSrfPlayAnnouncement(portid);
			shmp->process_info.sub_state = S_CRD_SRR;
			return retval;
		}
		shmp->process_info.maxPCUInfoLen = 16;
		shmp->process_info.endOfReplyDigit[0] = 1;
		shmp->process_info.endOfReplyDigit[1] = 12;
		shmp->process_info.voiceID = INPUT_VOICEBOX;
		SendPromptAndCollectUserInfo(portid);
		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_CRD_SET_DESTINATION;
		break;
		case S_CRD_SET_DESTINATION:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;
		#if DEBUG		
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif
		if(capmsg.msgOperaCode == CAP_OC_PromptAndCollectUserInformation)
		{
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = crd_release_call);  //timeout ,exit 
			}
			pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len<3 || len>12) 
				return (retval = crd_release_call);  //timeout ,exit 
			len --;
			memcpy(shmp->process_info.tmpNumber,
						&pPCUI->digitsResponse[2],
						len);
			if(pPCUI->digitsResponse[1] & 0x20)
			{
				shmp->process_info.tmpNumber[len-1] |= 0xF0;
				len =len * 2-1;
			}
			else
				len *=2;
			shmp->process_info.tmpNumber[MAX_MSISDN_BLEN-1] = len;
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_CRD_CONNECT;
		}
		shmp->process_info.chargeOther = 1;
		break;
		case S_CRD_CONNECT:
		if(shmp->process_info.chargeOther == 1)
		{
			len = shmp->process_info.tmpNumber[MAX_MSISDN_BLEN-1];
			ppsBcdToAsciiR(msisdn,shmp->process_info.tmpNumber,(len+1)/2*2);
			StringCut(msisdn,'F');
		}
		else
		{
			strcpy(msisdn, (char *)shmp->caller_info.number);
		}
//		DebugMsg(debugmib.display.asciiOut,"voice box: %s",msisdn);
		CutUnknownPrefix(msisdn);
//	DebugMsg(debugmib.display.asciiOut,"voice box: %s,type:%d",
//		msisdn,shmp->process_info.chargeOther);
		//following 2 lines added 09-27
		len = strlen(msisdn);
		if(len>18) len = 18;
		shmp->process_info.tmpNumber[MAX_MSISDN_BLEN-1] = len;
		ppsAsciiToBcdR(shmp->process_info.tmpNumber,msisdn,(len+1)/2*2);

		if(!GetCRDDestination(msisdn,
								shmp->process_info.tmpDigits,
								shmp->process_info.serviceType-SRV_CRD)) 
								/* don't want crd.c to include ppsm.h, serivceType changed to 0-2 */
								/* not VMS box number */
		{
			shmp->process_info.voiceID = NO_SUCH_VOICEBOX;
			shmp->process_info.srfRelease = 0;
			SendSrfPlayAnnouncement(portid);
			shmp->process_info.sub_state = S_CRD_SRR;
			return (retval); /* special resource report ,2004-08-30*/
		}
//		DebugMsg(debugmib.display.asciiOut,"VMS address: %s",shmp->process_info.tmpDigits);

		correlationID = shmp->process_info.correlationID;
		shmpconn = (_state_data *)&smshm_ptr->state_data;
		shmpconn += correlationID;
		shmpconn->process_info.chargeOther = shmp->process_info.chargeOther;
		memcpy(shmpconn->process_info.tmpNumber,
				shmp->process_info.tmpNumber,12);
		shmpconn->process_info.callConnected = 2;
		strcpy(shmpconn->process_info.tmpDigits,
					shmp->process_info.tmpDigits);

		retval = crd_release_call;
		break;
		case S_CRD_SRR:
		dlgid = shmp->context_info.dialogue_id;
		if(!ReadScfMsg(&capmsg,dlgid))
			break;
		#if DEBUG		
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			ppsDebugCapMsg(&capmsg,0);
		}
		#endif
		retval = crd_release_call; /* special resource report ,2004-08-30*/
		break;
	}

	return retval;
}

/* -------------------Gy/Ro interfaces -------------*/

#define PRINT_CALL_INFO() do { \
	\
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn) \
	{ \
		DebugMsg(debugmib.display.asciiOut,"Call info: PID = [%04d]", pid); \
		DebugMsg(debugmib.display.asciiOut,"Caller info : %s (%d %d) status:%d,cosid:%d,balance: %.04f", \
                 shmp->caller_info.number,	\
                 shmp->caller_info.head,		\
                 shmp->caller_info.tail,		\
  		   shmp->caller_info.status,		\
		   shmp->caller_info.cos_id,		\
                 GetBalance(&shmp->caller_info));	\
			\
		if(shmp->process_info.state != S_GY_PS_INIT) \
		{	\
			DebugMsg(debugmib.display.asciiOut,"Called info : %s (%d %d) status: %d,cosid:%d, balance: %.04f", 	\
	                 shmp->called_info.number,		\
	                 shmp->called_info.head,			\
	                 shmp->called_info.tail,			\
			   shmp->called_info.status,			\
			  shmp->called_info.cos_id,			\
	                 GetBalance(&shmp->called_info));	\
		} \
		\
		DebugMsg(debugmib.display.asciiOut,	\
                "Tariff :(%s) %s CT:%d DI:%d FreeTime:%d unit_time:%d Miniunit:%d Adj:%.04f ,CapFlag%d, Discount: %d",	\
				 shmp->charge_info.number,			\
				 shmp->process_info.tariff.bill_id,			\
				 shmp->process_info.tariff.call_type,		\
			     shmp->process_info.tariff.discountID,		\
                 shmp->process_info.tariff.free_time,			\
                 shmp->process_info.tariff.unit_time,				\
                 shmp->process_info.tariff.mini_unit,                	\
                 shmp->process_info.tariff.adjustment,			\
                 shmp->process_info.tariff.cap_flag,				\
                 GetDiscount(tvnow.tv_sec,shmp->process_info.tariff.discountID));		\
		DebugMsg(debugmib.display.asciiOut,				\
				 "tierInfo:L-%d,A-(units:%d,bf:%.04f,lf:%.04f),B-(units:%d,bf:%.04f,lf:%.04f),C-(units:%d,bf:%.04f,lf:%.04f)",	\
				shmp->process_info.tariff.tierRating.tierNumber,			\
				shmp->process_info.tariff.tierRating.rating[0].units,			\
				shmp->process_info.tariff.tierRating.rating[0].base_fee,		\
				shmp->process_info.tariff.tierRating.rating[0].long_distance_fee,	\
				shmp->process_info.tariff.tierRating.rating[1].units,				\
				shmp->process_info.tariff.tierRating.rating[1].base_fee,			\
				shmp->process_info.tariff.tierRating.rating[1].long_distance_fee,	\
				shmp->process_info.tariff.tierRating.rating[2].units,				\
				shmp->process_info.tariff.tierRating.rating[2].base_fee,			\
				shmp->process_info.tariff.tierRating.rating[2].long_distance_fee);		\
	}\
}while(0)

extern void SendGprsCDR(_account_info *caller_info,_state_data 	*shmp);
int	pps_print_gy_msg(_gy_msg  *gy_ptr)
{
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
	{
		DebugMsgDelimiter();
		DebugMsg(debugmib.display.asciiOut,
				"Time: %ld.%03d, Ro CCR is received", tvnow.tv_sec,tvnow.tv_usec/1000);
		DebugMsg(debugmib.display.asciiOut,
				"    msg type := %d, req type := %d, serice type := %d ",
					gy_ptr->msg_type, gy_ptr->request_type, gy_ptr->service_type);
		DebugMsg(debugmib.display.asciiOut,
				"    caller := %s, called := %s, ", 
				gy_ptr->msg_body.ccr.caller, gy_ptr->msg_body.ccr.called);
		DebugMsg(debugmib.display.asciiOut,
				"    fd port := %d, app port := %d ", 
				gy_ptr->fd_port, gy_ptr->app_port);		
		
	}			

	return 1;
}



int  	pps_get_number_from_sip_number(char *sip_number, char *number)
{
	int i;
	int idd_flag=0;
	int len = strlen(sip_number);

       if(len>MAX_ASCII_NUMBER_LEN) len = MAX_ASCII_NUMBER_LEN;
	//memset(number, 0x00, MAX_ASCII_NUMBER_LEN);
	
	for(i=0; i<len; i++)
	{
		if(sip_number[i] == '+')
			idd_flag = 1;
		if(isdigit(sip_number[i]))
			break;
	}
	memcpy(number, &sip_number[i], MAX_ASCII_NUMBER_LEN -1);
	for(i=0; i<MAX_ASCII_NUMBER_LEN; i++)
	{
		if(!isdigit(number[i]))
		{
			number[i] = '\0';
			break;
		}
	}
	
	return idd_flag;
}

int	pps_get_gy_number(_account_info *ptr, char *sip_number)
{
	char	number[MAX_ASCII_NUMBER_LEN+1] = {0};
	int idd_flag = 0;
	
	idd_flag = pps_get_number_from_sip_number(sip_number, number);
	strcpy((char *)ptr->number, number);
	
	GetAccountPos(ptr);// get user data position by msisdn: [head]/[tail]
	ptr->cos_id = GetAccountCosID( ptr);// user cos in user data
	ptr->status = GetAccountStatus(ptr);// user status in user data
	ptr->idd_flag = idd_flag;

	ptr->expired_flag = isAccountExpired(ptr);// expiration day in user data
	
	return 1;
}


/* ------------------Start of   Ro Adaptor interfaces -------------*/
int mapping_diameter_error_to_camel(int fd_result)
{
	int	tcos=NORMAL_RELEASE;

	switch(fd_result)
	{
		case 4010: //DIAMETER_END_USER_SERVICE_DENIED
			tcos = CALLER_STATUS_ERROR;
		break;
		case 4011: //DIAMETER_CREDIT_CONTROL_NOT_APPLICABLE
			tcos = BOTH_USER_NOT_PREPAID;
		break;
		case 4012: //DIAMETER_CREDIT_LIMIT_REACHED
			tcos = CALLER_CREDIT_OUT;
		break;
		case 5030: //DIAMETER_USER_UNKNOWN
			tcos = BOTH_USER_NOT_PREPAID;
		break;
		case 5031: //DIAMETER_RATING_FAILED
			tcos = TARIFF_NOT_SET;
		break;
		default:
			tcos = TARIFF_NOT_SET;			
		break;
	}

	return tcos;
}

int start_pps_ocs_procedure(int flag, int nums)
{
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    
	int	 port;
	long	 long msisdn=86755900123;
	int     i;
	
	for(i=0;i<nums; i++)
	{
		port = AssignProcID(0);
		if(port <0)
			continue;
		
		shmp += port;

		sprintf((char *)shmp->caller_info.number, "%lld", msisdn+i*1000);
		sprintf((char *)shmp->called_info.number, "%lld", msisdn+1+i*1000);

		if(flag == 0)
			shmp->process_info.state = S_RO_ADAPTOR_CALL_INIT;
		else	
			shmp->process_info.state = S_RO_ADAPTOR_SMS_INIT;
	}
	
	return 1;
}

extern int ocs_get_cellid_present_flag();
int	pps_ro_adaptor_call_init(u16 port)
{
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    
	_gy_msg		gy_msg;
	_gy_ccr 		*ccr_ptr;
	int			used_duration = 0;
	int			vcs_enable = pps_get_adaptor_vcs_flag();

	if( port >= MAX_FSM_PROCESS )
	{
		return 0;
	}
	
	shmp += port;

	shmp->process_info.ro_if.adaptor_enabled = 1;

	memset(&gy_msg, 0x00, sizeof(_gy_msg));
	
	ccr_ptr = &gy_msg.msg_body.ccr;

	gy_msg.app_port = port;
	gy_msg.fd_port = shmp->process_info.ro_if.fd_port;
	gy_msg.msg_type = 	GY_MSG_CCR;
	gy_msg.service_type = 	ST_CS_VOICE;
	gy_msg.request_type = shmp->process_info.ro_if.request_type;

	if(shmp->process_info.duration>0)
		used_duration = (shmp->process_info.duration - shmp->process_info.ro_if.last_updated_duration);
	else
		used_duration = 0;
	if(used_duration<0)
		used_duration = 0;
	
	shmp->process_info.ro_if.granted_value = 0;
	shmp->process_info.ro_if.last_updated_duration = shmp->process_info.duration;
	ccr_ptr->used_unit = used_duration / CYCLE_STATE_INTERVAL;

	if(shmp->process_info.serviceType == SRV_NORMAL_MT_CALL)
		ccr_ptr->role_of_node = 1;
	else if(shmp->process_info.serviceType == SRV_NORMAL_MF_CALL && vcs_enable)
		ccr_ptr->role_of_node = 2;
	else
		ccr_ptr->role_of_node = 0;

	if(pps_get_ocs_proxy_nai_flag() == 0)
		strcpy(ccr_ptr->caller, (char *)shmp->caller_info.number);
	else
	{
		if(shmp->caller_info.nai == 0x91)
			sprintf(ccr_ptr->caller,  "+%s", shmp->caller_info.number);			
		else
			strcpy(ccr_ptr->caller, (char *)shmp->caller_info.number);		
	}
	
	
	if(shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)
	{
		if(pps_get_ocs_proxy_nai_flag() == 0)
			strcpy(ccr_ptr->origin_caller, (char *)shmp->origin_info.number);		
		else
		{
			if(shmp->origin_info.nai == 0x91)
				sprintf(ccr_ptr->origin_caller,  "+%s", shmp->origin_info.number);			
			else
				strcpy(ccr_ptr->origin_caller, (char *)shmp->origin_info.number);		
		}
	}

	memset(ccr_ptr->imsi, 0x00, 15);
       {
		if(vcs_enable)
		{
			char tmp_buf[32];
      			if(pps_get_ocs_proxy_nai_flag() == 0)
				strcpy(ccr_ptr->called, (char *)shmp->called_info.number);			
			else
			{
				if(shmp->called_info.nai == 0x91)
					sprintf(ccr_ptr->called,  "+%s", shmp->called_info.number);			
				else
					strcpy(ccr_ptr->called, (char *)shmp->called_info.number);			
			}
			if(shmp->process_info.serviceType == SRV_NORMAL_MT_CALL)
				ppsBcdToAsciiR(tmp_buf, shmp->called_info.IMSI, 16);
			else
				ppsBcdToAsciiR(tmp_buf, shmp->caller_info.IMSI, 16);
			tmp_buf[15] = '\0';
			strcpy(ccr_ptr->imsi, tmp_buf);
		}
		else
		{
			if (ccr_ptr->role_of_node == 1)// MT call
			{
				strcpy(ccr_ptr->called, (char *)shmp->called_info.number);
			}
			else
			{
				strcpy(ccr_ptr->called, (char *)shmp->charge_info.number);
			}
		}
       }
	   
	if(vcs_enable)
	{
		ccr_ptr->service_key = shmp->process_info.serviceKey;
		strcpy(ccr_ptr->msc_addr, shmp->cdr_info.msc_addr);
		strcpy(ccr_ptr->vlr_number, shmp->cdr_info.locationNumber);
	}

	if(ocs_get_cellid_present_flag())
	{
		ccr_ptr->cellid_presented = 1;
		BcdToAscii(ccr_ptr->cellid, shmp->cdr_info.cgi, 14);
		
	}
	else
		ccr_ptr->cellid_presented = 0;
	
	if(gx_send_ccr_from_client(&gy_msg))
		shmp->process_info.ro_if.fd_port = gy_msg.fd_port;

	shmp->process_info.ro_if.recv_cmd = 0;
	shmp->process_info.wait_timer = 0;	

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{

		DebugMsg(debugmib.display.asciiOut,
			"    [%04d] TS: %ld.%03d, caller=%s, called=%s\r\n Send CCR, serivce type=%d, request type=%d\r\n", port,
			tvnow.tv_sec, tvnow.tv_usec/1000,
			shmp->caller_info.number, shmp->called_info.number,
			ST_CS_VOICE, gy_msg.request_type);
		
		if(vcs_enable)
			DebugMsg(debugmib.display.asciiOut,
				"    [%04d] TS: %ld.%03d,  vcs enable flag=%d, msc_addr=%s, vlr_num=%s\r\n", port,
				tvnow.tv_sec, tvnow.tv_usec/1000,
				vcs_enable,
				shmp->cdr_info.msc_addr, ccr_ptr->vlr_number);

	}
	
	return 1;
}

int  pps_ro_call_wait_first_cca(u16 port)
{
	//disconnect/cancel received to cancel Ro
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    

	if( port >= MAX_FSM_PROCESS )
	{
		return 0;
	}

	shmp += port;

	if(shmp->process_info.wait_timer ++ > 5*CYCLE_STATE_INTERVAL)
	{
		shmp->process_info.tcend = 1;
		//ReleaseAll(port);
		gx_release_port_for_timerout(shmp->process_info.ro_if.fd_port);

		return -1;
	}

	if(shmp->process_info.ro_if.recv_cmd == 0)
		return 0;
	
	if(shmp->process_info.ro_if.granted_value <= 0 || shmp->process_info.ro_if.result != 2001)
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{

			DebugMsg(debugmib.display.asciiOut,
				"    [%04d] TS: %ld.%03d,  caller=%s, called=%s\r\nCCR is not authenticated, result=%d\r\n", port,
				tvnow.tv_sec, tvnow.tv_usec/1000, 
				shmp->caller_info.number, shmp->called_info.number,
				shmp->process_info.ro_if.result);

		}
		
		shmp->process_info.tcos = mapping_diameter_error_to_camel(shmp->process_info.ro_if.result);	
		if(shmp->process_info.duration <= 0) //playannoucment here...
		{
			shmp->process_info.ro_if.adaptor_enabled = 0;
			shmp->process_info.tcend = 1;
			//ReleaseAll(port);
			return -1;
		}
		return -1;
	}

	
	//shmp->caller_info.valid_time += shmp->process_info.ro_if.granted_value * CYCLE_STATE_INTERVAL;
	//shmp->called_info.valid_time += shmp->process_info.ro_if.granted_value * CYCLE_STATE_INTERVAL;

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{

		DebugMsg(debugmib.display.asciiOut,
			"    [%04d] TS: %ld.%03d,  caller=%s, called=%s \r\n call valididty, caller valid_time=%d, called valid_time=%d\r\n", port,
			tvnow.tv_sec, tvnow.tv_usec/1000,
			shmp->caller_info.number, shmp->called_info.number,
			shmp->caller_info.valid_time, shmp->called_info.valid_time);

	}
	
	return 1;
	
}

int pps_ro_call_termiate(u16 port)
{
	int retval = 0;
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    

	if( port >= MAX_FSM_PROCESS )
	{
		return 0;
	}
	
	shmp += port;

	switch(shmp->process_info.sub_state)
	{
		case 0:
		default:
			shmp->process_info.ro_if.request_type = RT_TERMINATE_REQUEST;
			shmp->process_info.duration += 1; //add 100ms to make sure qutation is correct in second
			pps_ro_adaptor_call_init(port);
			shmp->process_info.sub_state = 1;
		break;
		case 1:
			if(pps_ro_call_wait_first_cca(port) != 0)
				retval = 1;
		break;
	}

	return retval;
}


int	pps_ro_adaptor_sms_init(u16 port)
{
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    
	_gy_msg		gy_msg;
	_gy_ccr 		*ccr_ptr;
	int			vcs_enable = pps_get_adaptor_vcs_flag();

	if( port >= MAX_FSM_PROCESS )
	{
		return 0;
	}

	shmp += port;

	shmp->process_info.ro_if.adaptor_enabled = 1;

	memset(&gy_msg, 0x00, sizeof(_gy_msg));
	
	ccr_ptr = &gy_msg.msg_body.ccr;

	gy_msg.app_port = port;
	gy_msg.msg_type = 	GY_MSG_CCR;
	gy_msg.service_type = 	ST_CS_SMS;
	gy_msg.request_type = RT_EVENT_REQUEST;
	ccr_ptr->request_action = shmp->process_info.ro_if.request_action;
	
	strcpy(ccr_ptr->caller, (char *)shmp->caller_info.number);
	if(vcs_enable)
	{
		char tmp_buf[32];

		sprintf(ccr_ptr->caller,  "+%s", shmp->caller_info.number);

		if(pps_get_ocs_proxy_nai_flag() == 0)
			strcpy(ccr_ptr->called, (char *)shmp->called_info.number);			
		else
		{
			if(shmp->called_info.nai == 0x91)
				sprintf(ccr_ptr->called,  "+%s", shmp->called_info.number);			
			else
				strcpy(ccr_ptr->called, (char *)shmp->called_info.number);			
		}
		
		//strcpy(ccr_ptr->called,  shmp->called_info.number);
		strcpy(ccr_ptr->vlr_number, shmp->cdr_info.locationNumber);
		strcpy(ccr_ptr->msc_addr, shmp->cdr_info.smsc_addr);
		ccr_ptr->service_key = shmp->process_info.serviceKey;

		ppsBcdToAsciiR(tmp_buf, shmp->caller_info.IMSI, 16);
		tmp_buf[15] = '\0';
		strcpy(ccr_ptr->imsi, tmp_buf);
		
	}
	else
	{
		strcpy(ccr_ptr->called, (char *)shmp->charge_info.number);
	}
	strcpy(ccr_ptr->smsc,  shmp->cdr_info.smsc_addr); //pps_get_smsc_addr());

	ccr_ptr->role_of_node = 0;	

	if(ocs_get_cellid_present_flag())
	{
		ccr_ptr->cellid_presented = 1;
		BcdToAscii(ccr_ptr->cellid, shmp->cdr_info.cgi, 14);
		
	}
	else
		ccr_ptr->cellid_presented = 0;

	if(gx_send_ccr_from_client(&gy_msg))
		shmp->process_info.ro_if.fd_port = gy_msg.fd_port;

	shmp->process_info.ro_if.recv_cmd = 0;
	shmp->process_info.wait_timer = 0;	

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		char debug_buf[1024];

		sprintf(debug_buf, "\r\n [%04d] %s : request_action = %d, TS: %ld.%03ld\r\n",
			port, __FUNCTION__, ccr_ptr->request_action,
			tvnow.tv_sec, tvnow.tv_usec/1000);
		
		DebugMsg(debugmib.display.asciiOut, debug_buf);			
	}
	
	return 1;
}

int  pps_ro_sms_wait_first_cca(u16 port)
{
	//disconnect/cancel received to cancel Ro
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    


	if( port >= MAX_FSM_PROCESS )
	{
		return 0;
	}

	shmp += port;

	if(shmp->process_info.wait_timer ++ > 5*CYCLE_STATE_INTERVAL)
	{
		shmp->process_info.tcend = 1;
		//ReleaseAll(port);
		gx_release_port_for_timerout(shmp->process_info.ro_if.fd_port);
		return -1;
	}

	if(shmp->process_info.ro_if.recv_cmd == 0)
		return 0;

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		char debug_buf[1024];

		sprintf(debug_buf, "\r\n [%04d] %s : result = %d, TS: %ld.%03ld\r\n",
			port, __FUNCTION__, shmp->process_info.ro_if.result,
			tvnow.tv_sec, tvnow.tv_usec/1000);
		
		DebugMsg(debugmib.display.asciiOut, debug_buf);			
	}

	if(shmp->process_info.ro_if.result != 2001)
	{
		{
			shmp->process_info.tcend = 1;
			//ReleaseAll(port);
			return -1;
		}
	}
	
	return 1;	
}

int pps_ro_sms_refund(u16 port)
{
	int retval = 0;
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    
	char debug_buf[1024];

	if( port >= MAX_FSM_PROCESS )
	{
		return 0;
	}

	//PutLogFunID("pps_ro_sms_refund");

	shmp += port;

	switch(shmp->process_info.sub_state)
	{
		case 0:
			shmp->process_info.ro_if.request_action = RA_REFUND_ACCOUNT;
			pps_ro_adaptor_sms_init(port);
			shmp->process_info.sub_state = 1;

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{

				sprintf(debug_buf, "\r\n [%04d] %s : send CCR, TS: %ld.%03ld\r\n",
					port, __FUNCTION__, 
					tvnow.tv_sec, tvnow.tv_usec/1000);
				
				DebugMsg(debugmib.display.asciiOut, debug_buf);			
			}

		break;
		case 1:
			if(pps_ro_call_wait_first_cca(port) == 0)
			break;			
			retval = 1;
		break;
	}

	return retval;
}


/* ------------------End of   Ro Adaptor interfaces -------------*/

int	pps_ro_voice_process_with_ext_crm(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	char			buf[128];
	int			len, instance;
	int			return_duration=0;
	float			charge=0, pre_charge=0;
	u_char		cos_id = 0;
	_account_info   *pChargedUsrInfo = NULL;

	if( pid >= MAX_FSM_PROCESS )
	{
		return 0;
	}
	
	//PutLogFunID("pps_ro_voice_process_with_ext_crm");

	shmp += pid;
	switch(shmp->process_info.state)
	{
		case S_RO_VOC_INIT:
			if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
				shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)
			{
				strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);
				pChargedUsrInfo = &shmp->caller_info;

				if(shmp->called_info.idd_flag)
				{
					AddInterPrefix((char *)shmp->charge_info.number);
				}

				//cos_id = shmp->caller_info.cos_id;
			}
			else// SRV_NORMAL_MT_CALL
			{
				strcpy((char *)shmp->charge_info.number, (char *)shmp->caller_info.number);
				pChargedUsrInfo = &shmp->called_info;

				if(shmp->caller_info.idd_flag)
				{
					AddInterPrefix((char *)shmp->charge_info.number);
				}

				//cos_id = shmp->called_info.cos_id;
			}
			
			sprintf(buf, "%sE", shmp->caller_info.number);
			len = (strlen(buf)+1)/2 * 2;
			ppsAsciiToBcdR(shmp->cdr_info.caller, buf, len);// transfer to BCD for CDR
			sprintf(buf, "%sE", shmp->called_info.number);
			len = (strlen(buf)+1)/2 * 2;
			ppsAsciiToBcdR(shmp->cdr_info.called, buf, len);// transfer to BCD for CDR

			shmp->cdr_info.seizuretime = tvnow.tv_sec;

			SetCallType(shmp,shmp->process_info.tariff.call_type);

			PRINT_CALL_INFO();

			shmp->process_info.funnel = 60 * CYCLE_STATE_INTERVAL;// init to a enouth long timer
			shmp->process_info.state = S_RO_VOC_CONNECTED;

			// query tariff
			//pps_send_query_tariff_req(pid);
			//shmp->process_info.funnel = SSHORT_DELAY_TIMER*2;
			//shmp->process_info.state = S_RO_VOC_GET_TARIFF_FROM_CRM;
		case S_RO_VOC_CONNECTED:
			if(shmp->process_info.funnel -- <= 0)
			{
				shmp->process_info.state = S_RO_VOC_RELEASE;

				gx_release_port_for_timerout(shmp->process_info.fd_port);
				
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d, caller=%s, called=%s \r\n wait for CCR timer out, release the call!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
				}
				return 0;
			}
			if ((shmp->process_info.oc == RT_INITIAL_REQUEST) || (shmp->process_info.oc == RT_UPDATE_REQUEST))
			{
				pps_send_query_tariff_req(pid);
				shmp->process_info.oc = 0;
				shmp->process_info.funnel = SSHORT_DELAY_TIMER*2;
				shmp->process_info.state = S_RO_VOC_GET_TARIFF_FROM_CRM;
				return 0;
			}
			else if(shmp->process_info.oc == RT_TERMINATE_REQUEST)
			{
				//gx_release_port_for_timerout(shmp->process_info.fd_port);
				shmp->process_info.oc = 0;
				shmp->process_info.state = S_RO_VOC_RELEASE;

				// send ccr-T
				_gy_msg *gy_ptr = &shmp->process_info.ro_if.gy_ccr_info;
				gy_ptr->msg_body.cca.result = 2001;
				gy_ptr->msg_body.cca.grant_value = 0;
				gy_ptr->msg_body.cca.is_final = 1;
				gy_ptr->app_port = pid;
				gy_ptr->msg_type = GY_MSG_CCA;
				gx_handle_cca_from_server(gy_ptr);// response CCA
				//
			}
			else
			{
				return 0;
			}
		case S_RO_VOC_RELEASE:
		{
			u32 refund_bundle = 0;
			return_duration = shmp->process_info.charged_duration - 
								shmp->process_info.duration;
			if(return_duration>0)
			{
				charge = pps_refund_ro_voice_with_crm(shmp, return_duration, &refund_bundle);
				if (return_duration == shmp->process_info.charged_duration)
				{
					charge = shmp->charge_info.charge;// not used at all, so refund all charged balance
				}

				if (charge >= 0.0001f)// update balance
				{
					pre_charge = shmp->charge_info.charge;
					shmp->charge_info.charge = pre_charge - charge;

					UpdateAccountBalance(shmp->caller_info.head, shmp->caller_info.tail, charge);
				
					instance = shmp->called_info.head*UNIT_STORE_ACCOUNT + shmp->called_info.tail;
					SendAccountRealSync(instance, charge, 0, OMC_OCODE_EDIT);
				}
				if ((refund_bundle > 0) && (shmp->process_info.rest_if.used_plan_value>=refund_bundle))// update bundle usage
				{
					shmp->process_info.rest_if.used_plan_value -= refund_bundle;
					shmp->process_info.rest_if.plan_value_add_this_time = (0x8000000000000000) | refund_bundle;
					pps_send_update_plan_value_req(pid);
				}
			}

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"[%04d]  , caller=%s, called=%s \r\n call duration[%d], charged duration[%d], refund bundle[%d], pre-charge = %.2f, return charge = %.2f", pid, 
						shmp->caller_info.number, shmp->called_info.number,
						shmp->process_info.duration, shmp->process_info.charged_duration, refund_bundle, pre_charge, charge);
			}
			
			shmp->cdr_info.releasetime = tvnow.tv_sec;
			shmp->cdr_info.answertime = tvnow.tv_sec - shmp->process_info.duration;
			if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
				shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)
			{
				shmp->caller_info.charge = shmp->charge_info.charge;
			}
			else
			{
				shmp->called_info.charge = shmp->charge_info.charge;
			}
			shmp->process_info.duration = shmp->process_info.duration *CYCLE_STATE_INTERVAL;

			SendCDR(pid);
			
			ReleaseAll(pid);
			return 1;
		}
		break;
		case S_RO_VOC_GET_TARIFF_FROM_CRM:
			if(shmp->process_info.funnel -- <= 0)
			{
				shmp->process_info.state = S_RO_VOC_RELEASE;
				
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d, caller=%s, called=%s \r\n get tariff timer out, release the call!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
				}
				shmp->process_info.state = S_RO_VOC_RELEASE;
				return 0;
			}
			
			if(shmp->process_info.rest_if.query_tariff_status<2)
				return 0;

			if (shmp->process_info.rest_if.query_tariff_status == 3 || shmp->process_info.rest_if.unit<=0)
			{
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d, caller=%s, called=%s \r\n no tariff or bundle, release the call!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
				}
				
				shmp->process_info.state = S_RO_VOC_RELEASE;
				break;//return 0;
			}

			shmp->process_info.funnel = 120 * CYCLE_STATE_INTERVAL;// init to a enough long timer
			shmp->process_info.state = S_RO_VOC_CONNECTED;
		break;
	}

	unsigned int granted_quota, new_assigned_quota = 0;
	_gy_msg *gy_ptr = &shmp->process_info.ro_if.gy_ccr_info;
	gy_ptr->msg_body.cca.result = 2001;

	if((gy_ptr->request_type == RT_TERMINATE_REQUEST) || (shmp->process_info.state == S_RO_VOC_RELEASE))
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"    [%04d] caller=%s Call Terminated!", pid, shmp->caller_info.number);
			
			DebugMsg(debugmib.display.asciiOut,
				"    call duration = %d", shmp->process_info.duration);
		}
		
		gy_ptr->msg_body.cca.grant_value = 0;//shmp->process_info.duration;
		gy_ptr->msg_body.cca.is_final = 1;

		//shmp->process_info.oc = RT_TERMINATE_REQUEST;
		granted_quota = 0;
	}
	else
	{
		int	account_unnormal_status_flag = 0;
		u32 unused_quota;

		// get acount status, normal or not; ===============================
		if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
			shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
		{
			//balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);
			if(shmp->caller_info.status != T_NORMAL)
				account_unnormal_status_flag = 1;
			if(shmp->caller_info.expired_flag)
				account_unnormal_status_flag = 1;
		}
		else
		{
			//balance = GetAccountBalance(shmp->called_info.head, shmp->called_info.tail);
			if(shmp->called_info.status != T_NORMAL)
				account_unnormal_status_flag = 1;
			if(shmp->called_info.expired_flag)
				account_unnormal_status_flag = 1;
		}
		//=======================================================

		// calculate granted quota and new assigned quota=========================
		unused_quota = shmp->process_info.charged_duration - shmp->process_info.duration;
		int max_duration = pps_get_max_call_duration_in_second();
		if(account_unnormal_status_flag)
		{
			max_duration = 0;
			granted_quota = 0;
		}
		else
		{
			if (unused_quota >= max_duration)// unused quota is enough for next grant
			{
				granted_quota = max_duration;
			}
			else
			{
				new_assigned_quota = max_duration - unused_quota;
			}
		}
		//===================================================
		
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
					"	 [%04d] TS: %ld.%03d, max quota[%d], unused[%d], need assign quota[%d]\r\n", pid, tvnow.tv_sec, tvnow.tv_usec/1000,
				max_duration, unused_quota, new_assigned_quota);
		}
		
		// Try to assigned new quota to meet max_dration, and charge and sync
		if (new_assigned_quota > 0)
		{
			u32 new_assigned_bundle = 0;
			charge = pps_billing_ro_voice_with_crm(shmp, &new_assigned_quota, &new_assigned_bundle);
			if (charge >= 0.0001f)// update balance
			{
				shmp->charge_info.charge += charge;
				UpdateAccountBalance(shmp->caller_info.head, shmp->caller_info.tail, -charge);

				instance = shmp->called_info.head*UNIT_STORE_ACCOUNT + shmp->called_info.tail;
				SendAccountRealSync(instance, -charge, 0, OMC_OCODE_EDIT);
			}
			if (new_assigned_bundle > 0)// update bundle usage
			{
				shmp->process_info.rest_if.used_plan_value += new_assigned_bundle;
				shmp->process_info.rest_if.plan_value_add_this_time = new_assigned_bundle;
				pps_send_update_plan_value_req(pid);
			}

			if ((new_assigned_quota + unused_quota) >= max_duration)
			{
				granted_quota = max_duration;
			}
			else
			{
				granted_quota = new_assigned_quota + unused_quota;
			}
			
			shmp->process_info.charged_duration += new_assigned_quota;
		}
		//

		// Set is_final flag by granted_quota
		if(granted_quota > 0)
		{

			gy_ptr->msg_body.cca.is_final = 0;
		}	
		else
		{
			gy_ptr->msg_body.cca.is_final = 1;
		}
		gy_ptr->msg_body.cca.grant_value = granted_quota;
		//
	}

	if(gy_ptr->request_type == RT_INITIAL_REQUEST)
		shmp->process_info.funnel = (granted_quota + 35)*CYCLE_STATE_INTERVAL;
	else
		shmp->process_info.funnel = (granted_quota + 90)*CYCLE_STATE_INTERVAL;

	if(gy_ptr->msg_body.cca.is_final == 1)
	{
		if (gy_ptr->request_type != RT_TERMINATE_REQUEST)
		{
			gy_ptr->msg_body.cca.result = 4012;
		}
		shmp->process_info.state = S_RO_VOC_RELEASE;
	}

	gy_ptr->app_port = pid;
	
	gy_ptr->msg_type = GY_MSG_CCA;
	
	gx_handle_cca_from_server(gy_ptr);// response CCA

	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			float balance = 0;
			if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
				shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
			{
				balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);
			}
			else
			{
				balance = GetAccountBalance(shmp->called_info.head, shmp->called_info.tail);
			}
		
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] TS: %ld.%03d,  caller=%s, called=%s, Send CCA\r\n", pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] Granted duration[%d], new allocated duration[%d], charge duration[%d], charged = %.2f, total charged = %.2f, balance = %.2f", pid, 
					granted_quota, new_assigned_quota, shmp->process_info.charged_duration, charge, shmp->charge_info.charge, balance);
		}
	}
	return 1;
}

int	pps_ro_voice_process(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	char			buf[128];
	int			len, instance;
	int			return_duration=0;
	float			charge=0, pre_charge=0;
	u_char		cos_id = 0;
	_account_info   *pChargedUsrInfo = NULL;

	if(OCS_with_external_CRM())
	{
		return pps_ro_voice_process_with_ext_crm(pid);
	}
	
	if( pid >= MAX_FSM_PROCESS )
	{
		return 0;
	}
	
	//PutLogFunID("pps_ro_voice_process");

	shmp += pid;

	switch(shmp->process_info.state)
	{
		case S_RO_VOC_INIT:
			if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
				shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
			{
				strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);
				pChargedUsrInfo = &shmp->caller_info;

				if(shmp->called_info.idd_flag)
				{
					AddInterPrefix((char *)shmp->charge_info.number);
				}

				cos_id = shmp->caller_info.cos_id;
			}
			else// SRV_NORMAL_MT_CALL
			{
				strcpy((char *)shmp->charge_info.number, (char *)shmp->caller_info.number);
				pChargedUsrInfo = &shmp->called_info;

				if(shmp->caller_info.idd_flag)
				{
					AddInterPrefix((char *)shmp->charge_info.number);
				}

				cos_id = shmp->called_info.cos_id;
			}
			
			sprintf(buf, "%sE", shmp->caller_info.number);
			len = (strlen(buf)+1)/2 * 2;
			ppsAsciiToBcdR(shmp->cdr_info.caller, buf,  len);// transfer to BCD for CDR
			sprintf(buf, "%sE", shmp->called_info.number);
			len = (strlen(buf)+1)/2 * 2;
			ppsAsciiToBcdR(shmp->cdr_info.called, buf,  len);// transfer to BCD for CDR

			{
				//CosServiceControl	 	*serviceControlItem;
				COSTable				*cosTableItem;
				
				//serviceControlItem = &ppsParam.ppsTables.cosTable[cos_id].serviceControl[0];
				cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
				
				pChargedUsrInfo->location = GetAccountZoneID(pChargedUsrInfo->head, pChargedUsrInfo->tail);// tariff ID is location?

				if(cosTableItem->tariff[0].chargeBy)// 0, by cos; 1, by location
				{
					pChargedUsrInfo->location = 
							findTariffIDByAPNName(shmp->process_info.ro_if.apn);// get tariff ID(location) by apn(Origin-Host)
				
					pps_print_event(shmp->process_info.logMsisdn,"%s charged by APN", shmp->process_info.ro_if.apn);
					if(pChargedUsrInfo->location<0)// Can't charge by location, so charge by cos.
					{
						pps_print_error(shmp->process_info.logMsisdn,"%s isn't matched by cgi,so charged by cos", shmp->process_info.ro_if.apn);
						pChargedUsrInfo->location = GetAccountZoneID(pChargedUsrInfo->head, pChargedUsrInfo->tail);	
					}
					else
					{
						//CheckWetherRoamingUser(shmp);
						
					}
				}
				
				if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
					shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)
				{
					shmp->process_info.tariff_flag = GetMOTariffData(shmp, 
						&shmp->process_info.tariff, 
						(char *)shmp->charge_info.number, 
						pChargedUsrInfo->location);
				}
				else
				{
					shmp->process_info.tariff_flag = GetMTTariffData(shmp, 
						pChargedUsrInfo->location, 
						&shmp->process_info.tariff, 
						pChargedUsrInfo, 
						&shmp->charge_info);
				}
			}			
			
			shmp->cdr_info.seizuretime = tvnow.tv_sec;

			SetCallType(shmp,shmp->process_info.tariff.call_type);	

			PRINT_CALL_INFO();

			shmp->process_info.funnel = 60 * CYCLE_STATE_INTERVAL;// init to a enouth long timer
			shmp->process_info.state = S_RO_VOC_CONNECTED;
		break;
		case S_RO_VOC_CONNECTED:
			if(shmp->process_info.funnel -- <= 0)
			{
				shmp->process_info.state = S_RO_VOC_RELEASE;

				gx_release_port_for_timerout(shmp->process_info.fd_port);
				
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d, caller=%s, called=%s \r\n wait for CCR timer out, release the call!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
				}		
			}
			if(shmp->process_info.oc == RT_TERMINATE_REQUEST)
			{
				//gx_release_port_for_timerout(shmp->process_info.fd_port);
				
				shmp->process_info.state = S_RO_VOC_RELEASE;
			}
		break;
		case S_RO_VOC_RELEASE:
		{
			u32 refund_bundle = 0;
			return_duration = shmp->process_info.charged_duration - 
								shmp->process_info.duration;
			if(return_duration>0)
			{
				charge = pps_refund_ro_voice(shmp, return_duration, &refund_bundle);
				if (return_duration == shmp->process_info.charged_duration)
				{
					charge = shmp->charge_info.charge;// not used at all, so refund all charged balance
				}

				if ((charge >= 0.0001f) || (refund_bundle > 0))
				{
					pre_charge = shmp->charge_info.charge;
					shmp->charge_info.charge = pre_charge - charge;

					if (shmp->process_info.serviceType == SRV_NORMAL_MO_CALL 
						||shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)
					{
						UpdateAccountBalance(shmp->caller_info.head, shmp->caller_info.tail, charge);
						if (refund_bundle > 0)
							pps_update_account_bundle_mo_voice(shmp, refund_bundle);
						instance = shmp->caller_info.head*UNIT_STORE_ACCOUNT + shmp->caller_info.tail;
					}
					else
					{
						UpdateAccountBalance(shmp->called_info.head, shmp->called_info.tail, charge);
						if (refund_bundle > 0)
							pps_update_account_bundle_mt_voice(shmp, refund_bundle);
						instance = shmp->called_info.head*UNIT_STORE_ACCOUNT + shmp->called_info.tail;
					}
				
					SendAccountRealSync(instance, charge, 0, OMC_OCODE_EDIT);
				}
			}

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"[%04d]  , caller=%s, called=%s \r\n call duration[%d], charged duration[%d], refund bundle[%d], pre-charge = %.2f, return charge = %.2f", pid, 
						shmp->caller_info.number, shmp->called_info.number,
						shmp->process_info.duration, shmp->process_info.charged_duration, refund_bundle, pre_charge, charge);
			}
			
			shmp->cdr_info.releasetime = tvnow.tv_sec;
			shmp->cdr_info.answertime = tvnow.tv_sec - shmp->process_info.duration;
			if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
				shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
			{
				shmp->caller_info.charge     = shmp->charge_info.charge;
			}
			else
			{
				shmp->called_info.charge     = shmp->charge_info.charge;
			}
			shmp->process_info.duration =   shmp->process_info.duration *CYCLE_STATE_INTERVAL;

			SendCDR(pid);
			
			ReleaseAll(pid);
		}
		break;
	}

	return 1;
}

int ocs_gy_data_charge_process_with_ext_crm(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	char			buf[128], retval_reason[256];
	int			len, instance;
	long			return_data=0;
	int			retval;
	_gprs_process		*gprs_ptr = NULL;

	_gy_msg  *gy_ptr = NULL;

	if(pid >= MAX_FSM_PROCESS)
		return 0;
	
	//PutLogFunID("ocs_gy_data_charge_process_with_ext_crm");

	shmp += pid;
	gprs_ptr = &shmp->process_info.ppsService.gprs_process;

	gy_ptr = &shmp->process_info.ro_if.gy_ccr_info;
	
	if(shmp->process_info.state > S_GY_PS_INIT)
	{
		shmp->process_info.funnel --;
		if(shmp->process_info.funnel  <= 0)
		{
			shmp->process_info.state = S_GY_PS_RELEASE;
			shmp->process_info.funnel = SSHORT_DELAY_TIMER;
			gx_release_port_for_timerout(shmp->process_info.fd_port);

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
				"[%04d] TS: %ld.%03d , caller=%s, called=%s \r\n wait for tariff timeout, release the call!", 
					pid, tvnow.tv_sec, tvnow.tv_usec/1000,
					shmp->caller_info.number, shmp->called_info.number);
			}
		}
	}

	switch(shmp->process_info.state)
	{
		case S_GY_PS_INIT:
			sprintf(buf, "%sE", shmp->caller_info.number);
			len = (strlen(buf)+1)/2 * 2;
			ppsAsciiToBcdR(shmp->cdr_info.caller, buf,  len);// transfer "12345678" to 0x21436587, and save in cdr caller num

			shmp->cdr_info.seizuretime = tvnow.tv_sec;
			shmp->cdr_info.answertime = tvnow.tv_sec;// Init access time and answer time

	
			PRINT_CALL_INFO();
			
			if((shmp->caller_info.status == T_FRESH) && (shmp->caller_info.head<MSISDN_HEAD_NUM))
			{
				COSTable	*cosTableItem;

				cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
				if(cosTableItem->accountValidity[0].activiationByInquiryIs)
				{
					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
										);
					shmp->caller_info.expired_flag = isAccountExpired(&shmp->caller_info);
					shmp->caller_info.status = T_NORMAL;

					instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
										+ shmp->caller_info.tail;
					SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
					if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenInquiry)
					{
						SendAccountInfoBySMPP(
								&shmp->caller_info,
								shmp->called_info.number);  
					}
				}
			}
		//	shmp->process_info.state = S_GY_PS_GET_TARIFF_FROM_CRM;			
		//break;
		//case S_GY_PS_GET_TARIFF_FROM_CRM:
#ifndef OCS_USE_REDIS_DB
			pps_send_query_tariff_req(pid);
#endif
			shmp->process_info.funnel = SSHORT_DELAY_TIMER;
			shmp->process_info.state = S_GY_PS_GET_TARIFF_FROM_CRM_RES;
			return 0;
		break;
		case S_GY_PS_GET_TARIFF_FROM_CRM_RES:
#ifndef OCS_USE_REDIS_DB
			if(shmp->process_info.funnel <= 3)
			{
				gy_ptr->msg_body.cca.is_final = 0;
			
				gy_ptr->msg_body.cca.grant_value = shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime = 2048;			
				shmp->process_info.ro_if.result = 2001;

				gy_ptr->msg_body.cca.time_threshold = 120;

				//pps_send_query_tariff_req(pid);
				
			}
			else
			{	
				if(shmp->process_info.rest_if.query_tariff_status<2)
					return 0;
#endif
				if(1)
				{
					retval = allocate_ps_data_volume_quota(shmp, retval_reason);
					switch(retval)
					{
						case 1: //NORMAL
							shmp->process_info.ro_if.result = 2001;
						break;
						case 0: //No more Bundle
							shmp->process_info.ro_if.result = 4010;
						break;
						case -1: //BLACKLISTED
							shmp->process_info.ro_if.result = 5030;	
							//shmp->process_info.state = S_GY_PS_RELEASE;
						break;
						case -2: //NORMAL but EXPIRED
							shmp->process_info.ro_if.result = 4012;							
						break;
						case -3: //Max Qutoa
							shmp->process_info.ro_if.result = 4012;														
						break;
						case -4: //No Tariff
							shmp->process_info.ro_if.result = 4012;														
						break;
						case -5: //low balance
							shmp->process_info.ro_if.result = 4012;								
						break;
					}
				}
#ifndef OCS_USE_REDIS_DB
			}
#endif
			shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;// init to a enough long timer
			shmp->process_info.state = S_GY_PS_CONNECTED;
			
		break;
		case S_GY_PS_CONNECTED:
			if(shmp->process_info.oc == RT_TERMINATE_REQUEST)
			{
				shmp->process_info.state = S_GY_PS_RELEASE;
				shmp->process_info.oc = 0;
			}
			else if(shmp->process_info.oc == RT_UPDATE_REQUEST)
			{
				resetAccessTimeout(shmp);// every time receiving CCR Update, reset idle timer
				shmp->process_info.oc = 0;
			}

			if(isAccessTimeout(shmp))// check idle timer, release session if timeout
			{// before releasing diameter, sending Abort-Session-Request to peer?
				gx_release_port_for_timerout(shmp->process_info.fd_port);
				
				shmp->process_info.state = S_GY_PS_RELEASE;

			}
			
			shmp->process_info.duration ++;
			if(0)
			{
				if((shmp->process_info.duration % (CYCLE_STATE_INTERVAL * 3600)) == 0)//to send GRPS cdr every 60 minutes
				{
					shmp->cdr_info.releasetime = tvnow.tv_sec;
					shmp->charge_info.charge = shmp->caller_info.charge;
					
					if(shmp->charge_info.charge != 0 ||
						shmp->process_info.ppsService.gprs_process.vqConsumed.integer != 0)
					{
						SendGprsCDR(&shmp->caller_info, shmp);
						
						shmp->process_info.ppsService.gprs_process.vqConsumed.integer = 0;// reset consumed
						shmp->caller_info.charge = 0;

						shmp->cdr_info.seizuretime = tvnow.tv_sec;
						shmp->cdr_info.answertime = tvnow.tv_sec;		
						
					}
				}

				if((shmp->process_info.duration % (CYCLE_STATE_INTERVAL*5)) == 0)//every 5 seconds to get data tariff
				{
					//pps_send_query_tariff_req(pid);
				}
			}
						
			return 0;
		break;
		case S_GY_PS_WAIT_TERM:
			if(shmp->process_info.funnel <= 0)
			{
				shmp->process_info.state = S_GY_PS_RELEASE;

				gx_release_port_for_timerout(shmp->process_info.fd_port);

				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d , caller=%s\r\nS_GY_PS_WAIT_TERM, release the PS session!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number);
				}
			}
			return 0;
		break;
		case S_GY_PS_RELEASE:

			{
			//	return_data = shmp->process_info.ppsService.gprs_process.vqAllocated.integer - 
				return_data = shmp->process_info.ppsService.gprs_process.vqConsumed.integer -
								shmp->process_info.ppsService.gprs_process.dqConsumed;
			//	if((return_data > 0) && (return_data <= (pps_get_quota_per_request() * 2)))
				if((return_data > 0))
				{
					if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
					{
						DebugMsg(debugmib.display.asciiOut,
							"[%04d]  caller=%s \r\nPS charged volume = %lld, consumed volume = %ld, return volume=%ld, total charge = %.2f", 
								pid, 
								shmp->caller_info.number,
								shmp->process_info.ppsService.gprs_process.vqConsumed.integer, 
								shmp->process_info.ppsService.gprs_process.dqConsumed, 
								return_data,
								shmp->caller_info.charge);
					}

					shmp->process_info.ppsService.gprs_process.dqRefund = return_data;
					pps_refund_data_volume(shmp);

				}
			}
			
			//shmp->process_info.ppsService.gprs_process.vqConsumed.integer = 
			//					shmp->process_info.ppsService.gprs_process.dqConsumed;			

			
			shmp->cdr_info.releasetime = tvnow.tv_sec;
			shmp->charge_info.charge = shmp->caller_info.charge;
			
			//if(shmp->charge_info.charge != 0 ||
			//	shmp->process_info.ppsService.gprs_process.vqConsumed.integer != 0)// Used quota != 0
			if(shmp->process_info.ppsService.gprs_process.dqConsumed != 0)// Used quota != 0
					SendGprsCDR(&shmp->caller_info, shmp);
			
			ReleaseAll(pid);
			return 1;
		break;
	}

	gy_ptr = &shmp->process_info.ro_if.gy_ccr_info;
	
	gy_ptr->msg_body.cca.result = shmp->process_info.ro_if.result;
	shmp->process_info.oc = gy_ptr->request_type;

	if(gy_ptr->request_type == RT_TERMINATE_REQUEST)
	{

		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"    [%04d] PS Session Terminated, state=%d!", pid, shmp->process_info.state);
			
			DebugMsg(debugmib.display.asciiOut,
				"    data consumed = %ld", shmp->process_info.ppsService.gprs_process.dqConsumed);
		}
		
		gy_ptr->msg_body.cca.grant_value = 0;
		gy_ptr->msg_body.cca.is_final = 1;

		if (gprs_ptr->userType == PPS_PREPAID_USER)
		{
			shmp->process_info.state = S_GY_PS_RELEASE;
		}
		
		retval = 0;
	}
	else
	{
		gy_ptr->msg_body.cca.is_final = 0;
	
		gy_ptr->msg_body.cca.grant_value = 
			shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime;

		if(gy_ptr->msg_body.cca.grant_value == 0)
		{
			//if( gy_ptr->request_type == RT_UPDATE_REQUEST)
			{
				if(shmp->process_info.ro_if.result == 5030 ||
					shmp->process_info.ro_if.result == 4010 )
				{
					//gy_ptr->msg_body.cca.result = 4012;
					//gy_ptr->msg_body.cca.is_final = 1; //final outside the criteria of UPDATE??
					shmp->process_info.state = S_GY_PS_WAIT_TERM;
					shmp->process_info.funnel = 2*CYCLE_STATE_INTERVAL;
				}
				else
				{
					gy_ptr->msg_body.cca.time_threshold = 60;
					//shmp->process_info.funnel = (60 + 2)*CYCLE_STATE_INTERVAL;	
					shmp->process_info.funnel = (900 + 10)*CYCLE_STATE_INTERVAL;	
				}
			}	
		}
		else
		{	
			//if(shmp->process_info.bundle_flag == 1)
			//	shmp->process_info.rest_if.used_plan_value += gy_ptr->msg_body.cca.grant_value;

			gy_ptr->msg_body.cca.volume_threshold = gy_ptr->msg_body.cca.grant_value /5;
			
			if(ocs_get_threshold_supported())
			{
				int inactive_timer;
				
				inactive_timer = pps_get_gprs_inactive_timer(shmp);

				if(pps_get_control_state())
					inactive_timer = inactive_timer / 2;
				/*
				if (gy_ptr->msg_body.cca.grant_value >= pps_get_quota_per_request())
				{
					gy_ptr->msg_body.cca.volume_threshold = gy_ptr->msg_body.cca.grant_value /5;
				}
				else
				{
					gy_ptr->msg_body.cca.volume_threshold = 0;
				}
				*/
				if(inactive_timer > 10)
					gy_ptr->msg_body.cca.time_threshold = (inactive_timer * 8 / 10); 
			}
			shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;
		}
	}
	

	gy_ptr->app_port = pid;
	
	gy_ptr->msg_type = GY_MSG_CCA;
	
	gx_handle_cca_from_server(gy_ptr);// response CCA

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		float balance = 0;

		balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);

		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] TS: %ld.%03d,  caller=%s, result=%d, Send CCA\r\n", 
					pid, 
					tvnow.tv_sec, tvnow.tv_usec/1000, 
					shmp->caller_info.number,
					gy_ptr->msg_body.cca.result);
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] Granted volume = %ld, charge volume = %ld, consumed volume = %ld, total charged = %.2f, balance = %.2f", pid, 
					gy_ptr->msg_body.cca.grant_value, 
					shmp->process_info.ppsService.gprs_process.vqConsumed.integer, 
					shmp->process_info.ppsService.gprs_process.dqConsumed ,
					shmp->caller_info.charge, balance);
		}
	}
	
	return 1;
}

int	pps_gy_data_charge_process(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	char			buf[128], retval_reason[256];
	int			len, instance;
	long			return_data=0;
	int			retval;

	if(pid >= MAX_FSM_PROCESS)
		return 0;
	
	//PutLogFunID("pps_gy_data_charge_process");

	if(OCS_with_external_CRM())
		return ocs_gy_data_charge_process_with_ext_crm(pid);
		
	shmp += pid;


	switch(shmp->process_info.state)
	{
		case S_GY_PS_INIT:
			sprintf(buf, "%sE", shmp->caller_info.number);
			len = (strlen(buf)+1)/2 * 2;
			ppsAsciiToBcdR(shmp->cdr_info.caller, buf,  len);// transfer "12345678" to 0x21436587, and save in cdr caller num

			shmp->cdr_info.seizuretime = tvnow.tv_sec;
			shmp->cdr_info.answertime = tvnow.tv_sec;// Init access time and answer time

	
			PRINT_CALL_INFO();
			
			if((shmp->caller_info.status == T_FRESH) && (shmp->caller_info.head<MSISDN_HEAD_NUM))
			{
				COSTable	*cosTableItem;

				cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
				if(cosTableItem->accountValidity[0].activiationByInquiryIs)
				{
					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
										);
					shmp->caller_info.expired_flag = isAccountExpired(&shmp->caller_info);
					shmp->caller_info.status = T_NORMAL;

					instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
										+ shmp->caller_info.tail;
					SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
					if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenInquiry)
					{
						SendAccountInfoBySMPP(
								&shmp->caller_info,
								shmp->called_info.number);  
					}
				}
			}
			
			if(1)
			{
				retval = allocate_ps_data_volume_quota(shmp, retval_reason);
				switch(retval)
				{
					case 1: //NORMAL
						shmp->process_info.ro_if.result = 2001;
					break;
					case 0: //No more Bundle
						shmp->process_info.ro_if.result = 4010;
					break;
					case -1: //BLACKLISTED
						shmp->process_info.ro_if.result = 5030;	
						//shmp->process_info.state = S_GY_PS_RELEASE;
					break;
					case -2: //NORMAL but EXPIRED
						shmp->process_info.ro_if.result = 4012;							
					break;
					case -3: //Max Qutoa
						shmp->process_info.ro_if.result = 4012;														
					break;
					case -4: //No Tariff
						shmp->process_info.ro_if.result = 4012;														
					break;
					case -5: //low balance
						shmp->process_info.ro_if.result = 4012;								
					break;
				}
			}
			
			shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;// init to a enough long timer
			shmp->process_info.state = S_GY_PS_CONNECTED;
			/*
			if(allocate_ps_data_volume_quota(shmp, retval_reason)< 1)
			{
				shmp->process_info.state = S_GY_PS_RELEASE;
			}
			else
			{
				shmp->process_info.state = S_GY_PS_CONNECTED;
			}
			*/
		break;
		case S_GY_PS_CONNECTED:
			if(shmp->process_info.funnel -- <= 0)
			{
				shmp->process_info.state = S_GY_PS_RELEASE;

				gx_release_port_for_timerout(shmp->process_info.fd_port);

				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d , caller=%s, called=%s \r\n wait for CCR timer out, release the call!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
				}
			}
			if(shmp->process_info.oc == RT_TERMINATE_REQUEST)
			{
				shmp->process_info.state = S_GY_PS_RELEASE;
				shmp->process_info.oc = 0;
			}
			else if(shmp->process_info.oc == RT_UPDATE_REQUEST)
			{
				resetAccessTimeout(shmp);// every time receiving CCR Update, reset idle timer
				shmp->process_info.oc = 0;
			}

			if(isAccessTimeout(shmp))// check idle timer, release session if timeout
			{// before releasing diameter, sending Abort-Session-Request to peer?
				gx_release_port_for_timerout(shmp->process_info.fd_port);
				
				shmp->process_info.state = S_GY_PS_RELEASE;

			}
			
			shmp->process_info.duration ++;
			if(0)
			{
				if((shmp->process_info.duration % (CYCLE_STATE_INTERVAL * 3600)) == 0)//to send GRPS cdr every 60 minutes
				{
					shmp->cdr_info.releasetime = tvnow.tv_sec;
					shmp->charge_info.charge = shmp->caller_info.charge;
					
					if(shmp->charge_info.charge != 0 ||
						shmp->process_info.ppsService.gprs_process.vqConsumed.integer != 0)
					{
						SendGprsCDR(&shmp->caller_info, shmp);
						
						shmp->process_info.ppsService.gprs_process.vqConsumed.integer = 0;// reset consumed
						shmp->caller_info.charge = 0;

						shmp->cdr_info.seizuretime = tvnow.tv_sec;
						shmp->cdr_info.answertime = tvnow.tv_sec;		
						
					}
				}
			}
			
		break;
		case S_GY_PS_WAIT_TERM:
			if(shmp->process_info.funnel -- <= 0)
			{
				shmp->process_info.state = S_GY_PS_RELEASE;

				gx_release_port_for_timerout(shmp->process_info.fd_port);

				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
					"[%04d] TS: %ld.%03d , caller=%s\r\nWait for CCR timer out, release the PS session!", 
						pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number);
				}
			}

		break;
		case S_GY_PS_RELEASE:
			{
			//	return_data = shmp->process_info.ppsService.gprs_process.vqAllocated.integer - 
				return_data = shmp->process_info.ppsService.gprs_process.vqConsumed.integer -
								shmp->process_info.ppsService.gprs_process.dqConsumed;
			//	if((return_data > 0) && (return_data <= (pps_get_quota_per_request() * 2)))
				if((return_data > 0))
				{
					if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
					{
						DebugMsg(debugmib.display.asciiOut,
							"[%04d]  caller=%s \r\nPS charged volume = %lld, consumed volume = %ld, return volume=%ld, total charge = %.2f", 
								pid, 
								shmp->caller_info.number,
								shmp->process_info.ppsService.gprs_process.vqConsumed.integer, 
								shmp->process_info.ppsService.gprs_process.dqConsumed, 
								return_data,
								shmp->caller_info.charge);
					}			

					shmp->process_info.ppsService.gprs_process.dqRefund = return_data;
					pps_refund_data_volume(shmp);

				}
			}
			
			//shmp->process_info.ppsService.gprs_process.vqConsumed.integer = 
			//					shmp->process_info.ppsService.gprs_process.dqConsumed;			

			shmp->cdr_info.releasetime = tvnow.tv_sec;
			shmp->charge_info.charge = shmp->caller_info.charge;
			
			if(shmp->charge_info.charge != 0 ||
				shmp->process_info.ppsService.gprs_process.vqConsumed.integer != 0)// Used quota != 0
				SendGprsCDR(&shmp->caller_info, shmp);
			
			ReleaseAll(pid);
		break;
	}

	return 1;
}


static int	pps_gy_data_postpaid_reqest(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	char			buf[128];
	int			len;

	if(pid >= MAX_FSM_PROCESS)
		return 0;
	
	//PutLogFunID("pps_gy_data_postpaid_reqest");

	shmp += pid;

	switch(shmp->process_info.oc)
	{
	case RT_INITIAL_REQUEST:
		sprintf(buf, "%sE", shmp->caller_info.number);
		len = (strlen(buf)+1)/2 * 2;
		ppsAsciiToBcdR(shmp->cdr_info.caller, buf,  len);// transfer "12345678" to 0x21436587, and save in cdr caller num

		shmp->cdr_info.seizuretime = tvnow.tv_sec;
		shmp->cdr_info.answertime = tvnow.tv_sec;// Init access time and answer time
		shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime = pps_get_quota_per_request();
		//shmp->process_info.ppsService.gprs_process.vqAllocated.integer = shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime;
		shmp->process_info.ro_if.result = 2001;

		shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;// init to a enough long timer
		shmp->process_info.oc = 0;
		shmp->process_info.state = S_GY_PS_POSTPAID;
		break;
	case RT_UPDATE_REQUEST:
		shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime = pps_get_quota_per_request();
		/*if (shmp->process_info.ppsService.gprs_process.vqAllocated.integer 
			>= (shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime + shmp->process_info.ppsService.gprs_process.dqConsumed))
		{
			;
		}
		else
		{
			shmp->process_info.ppsService.gprs_process.vqAllocated.integer += shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime;
		}*/
		shmp->process_info.ro_if.result = 2001;
		shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;
		shmp->process_info.oc = 0;
		break;
	case RT_TERMINATE_REQUEST:
		shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime = 0;
		shmp->process_info.funnel = 10*CYCLE_STATE_INTERVAL;
		shmp->process_info.ro_if.result = 2001;
		break;
	default:
		break;
	}

	return 1;
}


static int	pps_gy_data_postpaid_process(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	int			rel_flag = 0;

	if(pid >= MAX_FSM_PROCESS)
		return 0;
	
	//PutLogFunID("pps_gy_data_postpaid_process");

	shmp += pid;

	shmp->process_info.duration ++;
	if(shmp->process_info.funnel -- <= 0)
	{
		gx_release_port_for_timerout(shmp->process_info.fd_port);
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
			"[%04d] TS: %ld.%03d , caller=%s \r\n wait for CCR timer out, release the call!", 
				pid, tvnow.tv_sec, tvnow.tv_usec/1000,
				shmp->caller_info.number);
		}
		
		rel_flag = 1;
	}
	
	if(shmp->process_info.oc == RT_TERMINATE_REQUEST)
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
			"[%04d] TS: %ld.%03d , caller=%s \r\n recv terminate request, release the call!", 
				pid, tvnow.tv_sec, tvnow.tv_usec/1000,
				shmp->caller_info.number);
		}
		
		shmp->process_info.oc = 0;
		rel_flag = 1;
	}

	if (rel_flag)
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"PS consumed volume = %ld", 
					shmp->process_info.ppsService.gprs_process.dqConsumed);
		}
		
		shmp->cdr_info.releasetime = tvnow.tv_sec;
		
		ReleaseAll(pid);
	}

	return 1;
}


static int	pps_ro_event_sms_process(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	int			instance;
	CHARGED_FEE	 chargedFee;
	u32 bundle_used_num;

	if( pid >= MAX_FSM_PROCESS )
	{
		return 0;
	}
	
	//PutLogFunID("pps_ro_event_sms_process");

	shmp += pid;
	switch(shmp->process_info.state)
	{
		case S_RO_EVENT_SMS_INIT:
			shmp->process_info.funnel = (100)*CYCLE_STATE_INTERVAL;// init to a enough long timer
			shmp->process_info.state = S_RO_EVENT_SMS_PROCESS;
		break;
		case S_RO_EVENT_SMS_PROCESS:
			bundle_used_num = shmp->process_info.count;
			switch(shmp->process_info.ro_if.request_action)
			{
			case RA_DIRECT_DEBITING:
				UpdateBalance(shmp, &shmp->caller_info, -(shmp->caller_info.fee), &chargedFee);// reduce
				
				if(shmp->process_info.cap_flag)
				{
					UpdateSubsCapInfo(&shmp->caller_info, 1, (shmp->caller_info.fee), 0, shmp);// reduce
				} 

				if(shmp->process_info.bundle_flag)
				{
					pps_update_account_bundle_mo_sms(shmp, -bundle_used_num);// reduce
				}

				if(shmp->process_info.favoriteCall == FRIEND_FAMILY_FREE_SMS)
				{
				    IncreaseFriendFamilyFreeSMSCounter(shmp->caller_info.head, shmp->caller_info.tail);
				}

				// Sync
				instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT + shmp->caller_info.tail;
				SendAccountRealSync(instance, chargedFee.balance, chargedFee.promotion, OMC_OCODE_EDIT);// reduce

				// Send CDR
				shmp->caller_info.charge = shmp->caller_info.fee;// reduce
				SendSmsDirectDebitAndRefundCDR(shmp, bundle_used_num, 0);
				
				ReleaseAll(pid);
				break;
			case RA_REFUND_ACCOUNT:
				if(shmp->process_info.bundle_flag)// has bundle, so only has to update bundle.
				{
					pps_update_account_bundle_mo_sms(shmp, bundle_used_num);// increase
					shmp->caller_info.fee = 0.0;
				}
				else
				{
					UpdateBalance(shmp, &shmp->caller_info, (shmp->caller_info.fee), &chargedFee);// increase
				
					if(shmp->process_info.cap_flag)
					{
			 			UpdateSubsCapInfo(&shmp->caller_info, 1, -(shmp->caller_info.fee), 0, shmp);// increase
					} 
				}

				instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT + shmp->caller_info.tail;
				SendAccountRealSync(instance, chargedFee.balance, chargedFee.promotion, OMC_OCODE_EDIT);// increase

				shmp->caller_info.charge = -shmp->caller_info.fee;// increase
				SendSmsDirectDebitAndRefundCDR(shmp, bundle_used_num, 1);
				
				ReleaseAll(pid);
				break;
			default:
				break;
			}
		break;
	}

	return 1;
}


static int pps_recv_ro_sms_request(_gy_msg  *gy_ptr)
{
	int rst;
	//_prepaid_data    *pPrepaidData = &ramshm_ptr->prepaid_data;
	_state_data   state_data, *shmp = (_state_data *) &smshm_ptr->state_data;
	COSTable				*cosTableItem;
	//CosServiceControl	 	*serviceControlItem;
	//CHARGED_FEE			chargedFee;
	int pid;

	//PutLogFunID("pps_recv_ro_sms_request");

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  CCR for Event Request of CS_SMS", tvnow.tv_sec, tvnow.tv_usec/1000);
		DebugMsg(debugmib.display.asciiOut,
			"    fd_port=%04d, requested action[%d], sent sms num[%d]\r\n", gy_ptr->fd_port, \
			gy_ptr->msg_body.ccr.request_action, gy_ptr->msg_body.ccr.sent_msg_num);
	}

	// check request action
	if (((gy_ptr->msg_body.ccr.request_action != RA_DIRECT_DEBITING) \
		&& (gy_ptr->msg_body.ccr.request_action != RA_REFUND_ACCOUNT))\
		|| (gy_ptr->msg_body.ccr.sent_msg_num <= 0))
	{
		gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
		goto out;
	}

	shmp = &state_data;
	memset(shmp, 0, sizeof(_state_data));
	shmp->context_info.callType = CT_MO_SM;
	SetCallType(shmp, CT_MO_SM);
	pps_get_gy_number(&shmp->caller_info, gy_ptr->msg_body.ccr.caller);// Get user data position and data by msisdn
	pps_get_gy_number(&shmp->called_info, gy_ptr->msg_body.ccr.called);// Get user data position and data by msisdn
	shmp->caller_info.cug_id = GetAccountCUG(&shmp->caller_info);
	shmp->process_info.serviceType = GetServiceType(shmp);
	strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);

	CHECK_MSISDN_LOG_LEVEL();

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"    fd_port=%04d, caller[%s], called[%s]", gy_ptr->fd_port, \
			shmp->caller_info.number, shmp->called_info.number);
	}

	// check if user not exist
	if((shmp->caller_info.head>=MSISDN_HEAD_NUM) || (shmp->caller_info.tail>=MSISDN_HEAD_NUM))
	{
		gy_ptr->msg_body.cca.result = 5030;// ER_DIAMETER_USER_UNKNOWN;
		goto out;
	}

	// check user status
	switch (shmp->caller_info.status)
	{
	case T_NORMAL:
		break;
	case T_FRESH:
	case T_SUSPEND:
		if(shmp->process_info.serviceType == SRV_SCRATCH_CARD_RECHARGE ||
			shmp->process_info.serviceType == SRV_INQUIRY)
		{
			break;
		}
	default:
		shmp->process_info.tcos = UNALLOCATED_NUMBER;
		gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
		goto out;
	}

	// check expiration
	if (shmp->caller_info.expired_flag) 
	{
		shmp->process_info.tcos= CALLER_EXPIRIED;
		gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
		goto out;
	} 

	// Check favoriteCall
	cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
	//serviceControlItem = &cosTableItem->serviceControl[0];
	if(cosTableItem->friendFamilyControl[0].friendFamilyFlag)
	{
		shmp->process_info.favoriteCall = CheckWetherFavoriteNumber(&shmp->caller_info,shmp->called_info.number);
	}
	
	shmp->process_info.tcos = NORMAL_CLEARING;
	shmp->caller_info.location = GetAccountZoneID(shmp->caller_info.head, shmp->caller_info.tail);// tariff ID

	int bundle_used_num = 0;

	switch(gy_ptr->msg_body.ccr.request_action)
	{
	case RA_DIRECT_DEBITING:
		// is enabled to call===========================================
		bundle_used_num = BillingSMSProc(shmp, gy_ptr->msg_body.ccr.sent_msg_num);
		shmp->process_info.count = bundle_used_num;
		rst = isPoolChildReachSMSLimit(shmp);
		if(rst)
		{
			switch(rst)
			{
			case 1:
				shmp->process_info.tcos= CALLER_REACH_SMS_LIMIT;
				break;
			case 2:
				shmp->process_info.tcos= CALLER_REACH_CHARGE_LIMIT;
				break;
			}
			gy_ptr->msg_body.cca.result = 4010;// END_USER_SERVICE_DENIED;
			goto out;
		}
		
		if (shmp->caller_info.valid_time <= 0 ) 
		{
			shmp->process_info.tcos= CALLER_CREDIT_OUT;
			gy_ptr->msg_body.cca.result = 4012;// CREDIT_LIMIT_REACHED;
			goto out;
		}
		//=======================================================

		/* main processor */

		gy_ptr->msg_body.cca.result = 2001;// ER_DIAMETER_SUCCESS;
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			DebugMsg(debugmib.display.asciiOut, "Ro SMS %d, dibeting: %.2f, sms num: %d, bundle sms: %d", 
				shmp->process_info.cap_flag, shmp->caller_info.charge, gy_ptr->msg_body.ccr.sent_msg_num, bundle_used_num);
		}
		break;
	case RA_REFUND_ACCOUNT:
		if (shmp->process_info.bundle_flag)// has bundle, so only has to update bundle.
		{
			bundle_used_num = gy_ptr->msg_body.ccr.sent_msg_num;
		}
		else
		{
			bundle_used_num = 0;
		}
		shmp->process_info.count = bundle_used_num;

		/* main processor */

		gy_ptr->msg_body.cca.result = 2001;// ER_DIAMETER_SUCCESS;
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  
			debug_messages ++;
			DebugMsg(debugmib.display.asciiOut, "Ro SMS %d, refund: %.2f, sms num: %d, bundle sms: %d", 
				shmp->process_info.cap_flag, shmp->caller_info.charge, gy_ptr->msg_body.ccr.sent_msg_num, bundle_used_num);
		}
		break;
	default:
		break;
	}

	// assign handle port to process================================
	pid = AssignProcID(1);
	if( pid >= MAX_FSM_PROCESS || pid<0)
	{
		gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
		goto out;
	}
	
	_state_data *tmp_shmp = (_state_data *) &smshm_ptr->state_data;
	tmp_shmp += pid;
	memcpy(tmp_shmp, shmp, sizeof(_state_data));
	tmp_shmp->process_info.portid = pid;
	tmp_shmp->context_info.mtype  = CAP_O_OPEN;// set to this value for Ro and Gy request
	tmp_shmp->process_info.state = S_RO_EVENT_SMS_INIT;// fsm state
	tmp_shmp->process_info.ro_if.gy_ro_enable = 1;// set to 1 for Ro and Gy
	tmp_shmp->process_info.ro_if.request_action = gy_ptr->msg_body.ccr.request_action;
	tmp_shmp->process_info.count = gy_ptr->msg_body.ccr.sent_msg_num;
	tmp_shmp->process_info.fd_port = gy_ptr->fd_port;

	pps_ro_event_sms_process(pid);
	//=====================================================

out:
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"    fd_port=%04d, send CCA for Ro SMS Event Request, Result-Code[%d]!", gy_ptr->fd_port, gy_ptr->msg_body.cca.result);
	}

	gy_ptr->msg_body.cca.is_final = 1;
	gy_ptr->app_port = INVALID_GY_PORT;
	gy_ptr->msg_type = GY_MSG_CCA;
	
	gx_handle_cca_from_server(gy_ptr);// response CCA

	return 1;
}


static int	pps_ro_event_common_process(u_short pid)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	int			instance;
	_prepaid_info	*user_ptr = NULL;
	float charge, promo_charge, refund;
	u_char promotion_used_flag = 0;

	if( pid >= MAX_FSM_PROCESS )
	{
		return 0;
	}
	
	//PutLogFunID("pps_ro_event_sms_process");

	shmp += pid;
	switch(shmp->process_info.state)
	{
		case S_RO_EVENT_COMMON_INIT:
			shmp->process_info.funnel = (100)*CYCLE_STATE_INTERVAL;// init to a enough long timer
			shmp->process_info.state = S_RO_EVENT_COMMON_PROCESS;
		break;
		case S_RO_EVENT_COMMON_PROCESS:
			switch(shmp->process_info.ro_if.request_action)
			{
			case RA_DIRECT_DEBITING:
				charge = shmp->caller_info.charge;
				instance = shmp->caller_info.head*UNIT_STORE_ACCOUNT + shmp->caller_info.tail;
				user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[shmp->caller_info.head][shmp->caller_info.tail];
				if(user_ptr->promo_balance >= charge)
				{
					UpdateAccountPromotionBalance(shmp->caller_info.head, shmp->caller_info.tail, -charge);
					SendAccountRealSync(instance, 0, -charge, OMC_OCODE_EDIT);

					// send cdr
					SendDirectDebitAndRefundCDR(&shmp->caller_info, -charge);
				}
				else
				{
					promo_charge = user_ptr->promo_balance;
					charge = charge - promo_charge;
					UpdateAccountPromotionBalance(shmp->caller_info.head, shmp->caller_info.tail, -promo_charge);	
					UpdateAccountBalance(shmp->caller_info.head, shmp->caller_info.tail, -charge);
				
					SendAccountRealSync(instance, -charge, -promo_charge, OMC_OCODE_EDIT);

					// send cdr
					SendDirectDebitAndRefundCDR(&shmp->caller_info, -(charge+promo_charge));
				}
				
				ReleaseAll(pid);
				break;
			case RA_REFUND_ACCOUNT:
				instance = shmp->caller_info.head*UNIT_STORE_ACCOUNT + shmp->caller_info.tail;
				user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[shmp->caller_info.head][shmp->caller_info.tail];
				refund = shmp->caller_info.charge;

				if(isPromotionCanBeUsedForRoDebit(&shmp->caller_info))
				{
					if(IsPromotionExpired(&shmp->caller_info) == 0)
					{
						promotion_used_flag = 1;
					}
				}

				if(promotion_used_flag && user_ptr->promo_balance>0)
				{
					UpdateAccountPromotionBalance(shmp->caller_info.head, shmp->caller_info.tail, refund);
					SendAccountRealSync(instance, 0, refund, OMC_OCODE_EDIT);
				}
				else
				{
					UpdateAccountBalance(shmp->caller_info.head, shmp->caller_info.tail, refund);
					SendAccountRealSync(instance, refund, 0, OMC_OCODE_EDIT);
				}

				// send cdr
				SendDirectDebitAndRefundCDR(&shmp->caller_info, refund);
				
				ReleaseAll(pid);
				break;
			default:
				break;
			}
		break;
	}

	return 1;
}


static int pps_recv_event_request(_gy_msg  *gy_ptr)
{
	int flag_log_msisdn = 0;
	_account_info user_info;
	double user_balance = 0.0;
	_prepaid_data    *shmp = &ramshm_ptr->prepaid_data;
	_prepaid_info	*user_ptr = NULL;
	//u_char		promotion_used_flag = 0;

	//PutLogFunID("pps_recv_event_request");

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  CCR for Event Request", tvnow.tv_sec, tvnow.tv_usec/1000);
		DebugMsg(debugmib.display.asciiOut,
			"    fd_port=%04d, requested action[%d]\r\n", gy_ptr->fd_port, gy_ptr->msg_body.ccr.request_action);
	}

	// Check user num
	pps_get_gy_number(&user_info, gy_ptr->msg_body.ccr.caller);// Get user data position and data by msisdn
	if ((user_info.head < MSISDN_HEAD_NUM) && (user_info.tail < UNIT_STORE_ACCOUNT))
	{
		COSTable				*cosTableItem = NULL;
		CosServiceControl	 	*serviceControlItem = NULL;

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

		// Check Event Charging flag
		cosTableItem = &ppsParam.ppsTables.cosTable[user_info.cos_id];
		serviceControlItem = &cosTableItem->serviceControl[0];
		if(!serviceControlItem->event_charging_flag)
		{
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"    Event Charging is disabled!\r\n");
			}
			gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
			goto out;
		}
	}
	else
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		{
			DebugMsg(debugmib.display.asciiOut,
				"    user num[%s] not exist!", user_info.number);
		}
		
		gy_ptr->msg_body.cca.result = 5030;// ER_DIAMETER_USER_UNKNOWN;
		if (gy_ptr->msg_body.ccr.request_action == RA_CHECK_BALANCE)
		{
			gy_ptr->msg_body.cca.check_balance_result = CBR_NO_CREDIT;
		}
		
		goto out;
	}

	user_ptr = &shmp->prepaid_info[user_info.head][user_info.tail];
	user_balance = user_ptr->balance;

	if(isPromotionCanBeUsedForRoDebit(&user_info))
	{
		if(IsPromotionExpired(&user_info) == 0)
		{
			user_balance = user_ptr->balance + user_ptr->promo_balance;
			//promotion_used_flag = 1;
		}
	}

	switch(gy_ptr->msg_body.ccr.request_action)// Common DCCA event
	{
	case RA_DIRECT_DEBITING:
		{
			float	charge;
				
			charge = gy_ptr->msg_body.ccr.req_service_unit;
			if ((user_info.status == T_NORMAL) \
				&& !user_info.expired_flag \
				&& (user_balance >= charge))
			{
				// assign handle port to process================================
				int pid = AssignProcID(1);
				if( pid >= MAX_FSM_PROCESS || pid<0)
				{
					gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
					goto out;
				}
				
				_state_data *tmp_shmp = (_state_data *) &smshm_ptr->state_data;
				tmp_shmp += pid;
				tmp_shmp->process_info.portid = pid;
				tmp_shmp->context_info.mtype  = CAP_O_OPEN;// set to this value for Ro and Gy request
				tmp_shmp->process_info.state = S_RO_EVENT_COMMON_INIT;// fsm state
				tmp_shmp->process_info.ro_if.gy_ro_enable = 1;// set to 1 for Ro and Gy
				tmp_shmp->process_info.ro_if.request_action = gy_ptr->msg_body.ccr.request_action;
				tmp_shmp->process_info.fd_port = gy_ptr->fd_port;

				memcpy(&tmp_shmp->caller_info, &user_info, sizeof(user_info));
				tmp_shmp->caller_info.charge = charge;

				pps_ro_event_common_process(pid);
				//=====================================================

				/* main processor */

				gy_ptr->msg_body.cca.result = 2001;// ER_DIAMETER_SUCCESS;
			}
			else
			{
				if (user_balance < charge)
				{
					gy_ptr->msg_body.cca.result = 4547;// for low balance
				}
				else
				{
					gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
				}
			}

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"    Direct Debiting, req_unit[%.2f], result-code[%d], pre balance[%.2f]\r\n", gy_ptr->msg_body.ccr.req_service_unit, \
									gy_ptr->msg_body.cca.result, user_balance);
			}
		}
		break;
	case RA_REFUND_ACCOUNT:
		{
			float	refund;

			refund = gy_ptr->msg_body.ccr.req_service_unit;
			if ((user_info.status == T_NORMAL) \
				&& !user_info.expired_flag)
			{
				// assign handle port to process================================
				int pid = AssignProcID(1);
				if( pid >= MAX_FSM_PROCESS || pid<0)
				{
					gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
					goto out;
				}
				
				_state_data *tmp_shmp = (_state_data *) &smshm_ptr->state_data;
				tmp_shmp += pid;
				tmp_shmp->process_info.portid = pid;
				tmp_shmp->context_info.mtype  = CAP_O_OPEN;// set to this value for Ro and Gy request
				tmp_shmp->process_info.state = S_RO_EVENT_COMMON_INIT;// fsm state
				tmp_shmp->process_info.ro_if.gy_ro_enable = 1;// set to 1 for Ro and Gy
				tmp_shmp->process_info.ro_if.request_action = gy_ptr->msg_body.ccr.request_action;
				tmp_shmp->process_info.fd_port = gy_ptr->fd_port;

				memcpy(&tmp_shmp->caller_info, &user_info, sizeof(user_info));
				tmp_shmp->caller_info.charge = refund;

				pps_ro_event_common_process(pid);
				//=====================================================

				/* main processor */

				gy_ptr->msg_body.cca.result = 2001;// ER_DIAMETER_SUCCESS;
			}
			else
			{
				gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
			}

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"    Refund Account, req_unit[%.2f], result-code[%d], old balance[%.2f]\r\n", gy_ptr->msg_body.ccr.req_service_unit, \
									gy_ptr->msg_body.cca.result, shmp->prepaid_info[user_info.head][user_info.tail].balance);
			}
		}
		break;
	case RA_CHECK_BALANCE:
		{
			//user_balance = shmp->prepaid_info[user_info.head][user_info.tail].balance;

			if ((user_info.status == T_NORMAL) \
				&& !user_info.expired_flag \
				&& (user_balance >= gy_ptr->msg_body.ccr.req_service_unit))
			{
				gy_ptr->msg_body.cca.check_balance_result = CBR_ENOUGH_CREDIT;
			}
			else
			{
				gy_ptr->msg_body.cca.check_balance_result = CBR_NO_CREDIT;
			}
			
			gy_ptr->msg_body.cca.result = 2001;// ER_DIAMETER_SUCCESS;

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"    Check Balance, req balance[%.2f], result[%s], user balance[%.2f]\r\n", gy_ptr->msg_body.ccr.req_service_unit, \
						(gy_ptr->msg_body.cca.check_balance_result == CBR_ENOUGH_CREDIT) ? "ENOUGH_CREDIT": "NO_CREDIT", user_balance);
			}
		}
		break;
	default :
		{
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
			{
				DebugMsg(debugmib.display.asciiOut,
					"    requested action[%d] not support!", gy_ptr->msg_body.ccr.request_action);
			}
			
			gy_ptr->msg_body.cca.result = 5012;// ER_DIAMETER_UNABLE_TO_COMPLY;// rejected for unspecified reasons.
		}
		break;
	}

out:
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"    fd_port=%04d, send CCA for Event Request, Result-Code[%d]!", gy_ptr->fd_port, gy_ptr->msg_body.cca.result);
	}

	gy_ptr->msg_body.cca.is_final = 1;
	gy_ptr->app_port = INVALID_GY_PORT;
	gy_ptr->msg_type = GY_MSG_CCA;
	
	gx_handle_cca_from_server(gy_ptr);// response CCA

	return 1;
}




static int pps_recv_gy_data_request(_gy_msg  *gy_ptr)
{
	int pid;
	int retval;
	int inactive_timer;
	char retval_reason[256];
	long postpaid_consumed_volume = 0;// do not charge a whole quota, after 2K is consumed
	
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;
	_gprs_process		*gprs_ptr = NULL;

	//PutLogFunID("pps_recv_gy_data_request");

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  CCR for PS\r\n", tvnow.tv_sec, tvnow.tv_usec/1000);
		DebugMsg(debugmib.display.asciiOut,
			"    fd_port=%04d, app_port=%04d, request_type=%d, rg[%d], si[%d], rr[%d]\r\n", gy_ptr->fd_port, \
			gy_ptr->app_port, gy_ptr->request_type, gy_ptr->rating_group, gy_ptr->service_identifier, gy_ptr->msg_body.ccr.reporting_reason);
	}
	
	if(gy_ptr->request_type == RT_INITIAL_REQUEST)// process Init request
	{
		pid = AssignProcID(1);// assign handle port
		if( pid >= MAX_FSM_PROCESS || pid<0)
		{
			return 0;
		}
		
		shmp += pid;
		shmp->process_info.portid = pid;
		shmp->process_info.call_type = CT_GPRS;
		shmp->context_info.callType = CT_GPRS;
		shmp->context_info.mtype  = CAP_O_OPEN;// set to this value for Ro and Gy request
		shmp->process_info.state = S_GY_PS_INIT;// fsm state
		shmp->process_info.oc = gy_ptr->request_type;
		shmp->process_info.ro_if.gy_ro_enable = 1;// set to 1 for Ro and Gy
		shmp->process_info.ro_if.request_type = RT_INITIAL_REQUEST;
		//shmp->process_info.ro_if.service_identifier = gy_ptr->service_identifier;
		shmp->process_info.fd_port = gy_ptr->fd_port;

		gprs_ptr = &shmp->process_info.ppsService.gprs_process;
		gprs_ptr->gsnIP   = gy_ptr->msg_body.ccr.ggsn_ip;
		gprs_ptr->sgsnIP = gy_ptr->msg_body.ccr.sgsn_ip;
		gprs_ptr->destIP  = gy_ptr->msg_body.ccr.ggsn_ip;
		shmp->process_info.ppsService.gprs_process.update_quote_counter = 1;
		{
			int tmp_len;
			char *dot_offset = NULL;
			
			if( (dot_offset = strstr(gy_ptr->msg_body.ccr.apn, "." )) != NULL)// Origin-Host in CCR, Charged by Location
			{
				tmp_len = dot_offset - gy_ptr->msg_body.ccr.apn; 
				memcpy(shmp->process_info.ro_if.apn, gy_ptr->msg_body.ccr.apn, tmp_len);
				shmp->process_info.ro_if.apn[tmp_len] = '\0';
			}

			//DebugMsg(debugmib.display.asciiOut,
			//	"    APN = %s", shmp->process_info.ro_if.apn);
			
		}

		pps_get_gy_number(&shmp->caller_info, gy_ptr->msg_body.ccr.caller);// Get user data position and data by msisdn

		CHECK_MSISDN_LOG_LEVEL();

		if (pps_get_gy_postpaid_flag() \
			&& ((shmp->caller_info.head > MSISDN_HEAD_NUM) || (shmp->caller_info.tail > UNIT_STORE_ACCOUNT)))
		{
			// process for postpaid user
			gprs_ptr->userType = PPS_POSTPAID_USER;
			pps_gy_data_postpaid_reqest(pid);
		}
		else
		{
			gprs_ptr->userType = PPS_PREPAID_USER;
			if(OCS_with_external_CRM())
			{
				//shmp->process_info.ro_if.gy_ccr_ptr = (void *)gy_ptr;
				memcpy(&shmp->process_info.ro_if.gy_ccr_info, gy_ptr, sizeof(_gy_msg));
				shmp->process_info.funnel = SSHORT_DELAY_TIMER *CYCLE_STATE_INTERVAL;
				return ocs_gy_data_charge_process_with_ext_crm(pid);
			}
			else
			{
				pps_gy_data_charge_process(pid);
			}
		}
	}
	else// handle Update and Terminate
	{
		pid = gy_ptr->app_port;
	
		if(pid >= MAX_FSM_PROCESS || pid<0)
		{
			DebugMsg(debugmib.display.asciiOut, "[%04d] Invalid PID for CCR!", pid);
			return 0;		
		}

		shmp += pid;
		gprs_ptr = &shmp->process_info.ppsService.gprs_process;
		shmp->process_info.ro_if.request_type = gy_ptr->request_type;
		//shmp->process_info.oc = gy_ptr->request_type;

		if(ocs_get_gy_report_data_metohd() == 0)// 0, Report individual Quota: Used-Service-Unit
			shmp->process_info.ppsService.gprs_process.dqConsumed = 
					shmp->process_info.ppsService.gprs_process.dqConsumed + gy_ptr->msg_body.ccr.used_unit;
		else// 1, Report total Quota: Used-Service-Unit
			shmp->process_info.ppsService.gprs_process.dqConsumed = gy_ptr->msg_body.ccr.used_unit;

		if (gprs_ptr->userType == PPS_POSTPAID_USER)/* process for postpaid user */
		{
			shmp->process_info.oc = gy_ptr->request_type;
			pps_gy_data_postpaid_reqest(pid);
		}
		else
		{
			if(shmp->process_info.state == S_GY_PS_CONNECTED)
			{
				long not_consumed_volume = 0;
				long max_quota_bytes = pps_get_quota_per_request();

				if(shmp->process_info.ro_if.post_charge == 1)
				{
					if(shmp->process_info.ppsService.gprs_process.dqConsumed <= 10) //should be ZERO
					{
						shmp->process_info.ro_if.result = 2001;
						goto send_cca_with_last_quota;
					}
					else
					{
						shmp->process_info.ppsService.gprs_process.vqAllocated.integer =
								shmp->process_info.ppsService.gprs_process.dqConsumed;
						not_consumed_volume = 0;
						pps_charge_postpaid_data(shmp, shmp->process_info.ppsService.gprs_process.dqConsumed, &postpaid_consumed_volume);
						shmp->process_info.ppsService.gprs_process.vqAllocated.integer =
								shmp->process_info.ppsService.gprs_process.dqConsumed;
						shmp->process_info.ro_if.post_charge = 0;
					}
				}

				if (shmp->process_info.ppsService.gprs_process.vqConsumed.integer > shmp->process_info.ppsService.gprs_process.dqConsumed)
				{
					not_consumed_volume = shmp->process_info.ppsService.gprs_process.vqConsumed.integer - 
											shmp->process_info.ppsService.gprs_process.dqConsumed;
				}
				
				if(gy_ptr->request_type != RT_TERMINATE_REQUEST)
				{

					if(1)
					{

						if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
						{
							DebugMsg(debugmib.display.asciiOut,
								"    [%04d] Session duration=%d, consumed data=%lld, update_timer=%d", 
								pid, 
								shmp->process_info.duration, shmp->process_info.ppsService.gprs_process.dqConsumed,
								shmp->process_info.ppsService.gprs_process.update_quote_counter);
						}
					
						if(shmp->process_info.duration > (CYCLE_STATE_INTERVAL * 3600 * shmp->process_info.ppsService.gprs_process.update_quote_counter))
						{								
							if(shmp->charge_info.charge != 0 ||
								//shmp->process_info.ppsService.gprs_process.dqConsumed != 0)
								shmp->process_info.ppsService.gprs_process.dqConsumed >= 1048576)//only more than 1M , CDR will be generated

							{
								shmp->cdr_info.releasetime = tvnow.tv_sec;
								shmp->charge_info.charge = shmp->caller_info.charge;

								SendGprsCDR(&shmp->caller_info, shmp);
									
								//shmp->process_info.ppsService.gprs_process.vqConsumed.integer = 0;// reset consumed
								shmp->process_info.ppsService.gprs_process.vqConsumed.integer -= shmp->process_info.ppsService.gprs_process.dqConsumed;

								shmp->process_info.ppsService.gprs_process.dqConsumed = 0;
								shmp->caller_info.charge = 0;

								shmp->cdr_info.seizuretime = tvnow.tv_sec;
								shmp->cdr_info.answertime = tvnow.tv_sec;		

							}
							shmp->process_info.ppsService.gprs_process.update_quote_counter ++;
						}
					}
				
					if(not_consumed_volume >= max_quota_bytes*8/10)
					{
						shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime = not_consumed_volume;
						if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
						{
							DebugMsg(debugmib.display.asciiOut,
								"    [%04d] Not consumed volume=%ld, no new quato is charged!", pid, not_consumed_volume);

						}
					}
					else
					{
						if (gy_ptr->msg_body.ccr.reporting_reason == RR_QUOTA_EXHAUSTED)
						{
							if (shmp->process_info.bundle_flag && (not_consumed_volume < 1024))
							{
								// set quota all used up
								shmp->process_info.ppsService.gprs_process.dqConsumed += not_consumed_volume;
							}
						}

						//
						if(OCS_with_external_CRM())
						{
#ifdef OCS_USE_REDIS_DB
							memcpy(&shmp->process_info.ro_if.gy_ccr_info, gy_ptr, sizeof(_gy_msg));
							shmp->process_info.state = S_GY_PS_GET_TARIFF_FROM_CRM_RES;
							return 0;
#endif
							//shmp->process_info.ro_if.gy_ccr_ptr = (void *)gy_ptr;
				
							//shmp->process_info.state = S_GY_PS_GET_TARIFF_FROM_CRM;			
							//shmp->process_info.funnel = SSHORT_DELAY_TIMER *CYCLE_STATE_INTERVAL;
							//update used plan value here...
							//return ocs_gy_data_charge_process_with_ext_crm(pid);
						}
						//
						
						retval = allocate_ps_data_volume_quota(shmp, retval_reason);
						switch(retval)
						{
							case 1: //NORMAL
								shmp->process_info.ro_if.result = 2001;
							break;
							case 0: //No more Bundle
								shmp->process_info.ro_if.result = 4010;
							break;
							case -1: //BLACKLISTED
								shmp->process_info.ro_if.result = 5030;
							break;
							case -2: //NORMAL but EXPIRED
								shmp->process_info.ro_if.result = 4012;
							break;
							case -3: //Max Qutoa
								shmp->process_info.ro_if.result = 4012;
							break;
							case -4: //No Tariff
								shmp->process_info.ro_if.result = 4012;
							break;
							case -5: //low balance
								shmp->process_info.ro_if.result = 4012;
							break;
						}
					}
				}
			}
			else
			{
				shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime = 0;
			}
				
		}
	}

send_cca_with_last_quota:
	gy_ptr->msg_body.cca.result = shmp->process_info.ro_if.result;
	shmp->process_info.oc = gy_ptr->request_type;

	if(gy_ptr->request_type == RT_TERMINATE_REQUEST)
	{

		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"    [%04d] PS Session Terminated, state=%d!", pid, shmp->process_info.state);
			
			DebugMsg(debugmib.display.asciiOut,
				"    data consumed = %ld", shmp->process_info.ppsService.gprs_process.dqConsumed);
		}
		
		gy_ptr->msg_body.cca.grant_value = 0;
		gy_ptr->msg_body.cca.is_final = 1;

		if (gprs_ptr->userType == PPS_PREPAID_USER)
		{
			shmp->process_info.state = S_GY_PS_RELEASE;
		}

		retval = 0;
		
	}
	else
	{
		gy_ptr->msg_body.cca.grant_value = 
			shmp->process_info.ppsService.gprs_process.vqAllocatedThisTime;
		if ((gy_ptr->request_type == RT_UPDATE_REQUEST) && (postpaid_consumed_volume > 0) && (gy_ptr->msg_body.cca.grant_value > postpaid_consumed_volume))
		{
			gy_ptr->msg_body.cca.grant_value -= postpaid_consumed_volume;
			if (shmp->process_info.ppsService.gprs_process.vqAllocated.integer > postpaid_consumed_volume)
			{
				shmp->process_info.ppsService.gprs_process.vqAllocated.integer -= postpaid_consumed_volume;
				shmp->process_info.ppsService.gprs_process.vqConsumed.integer -= postpaid_consumed_volume;
			}
		}


		if(gy_ptr->msg_body.cca.grant_value == 0)
		{
			//if( gy_ptr->request_type == RT_UPDATE_REQUEST)
			{
				if(shmp->process_info.ro_if.result == 5030 ||
					shmp->process_info.ro_if.result == 4010 )
				{
					//gy_ptr->msg_body.cca.result = 4012;
					//gy_ptr->msg_body.cca.is_final = 1; //final outside the criteria of UPDATE??
					shmp->process_info.state = S_GY_PS_WAIT_TERM;
					shmp->process_info.funnel = 2*CYCLE_STATE_INTERVAL;
				}
				else
				{
					gy_ptr->msg_body.cca.time_threshold = 60;
					//shmp->process_info.funnel = (60 + 2)*CYCLE_STATE_INTERVAL;	
					shmp->process_info.funnel = (900 + 10)*CYCLE_STATE_INTERVAL;	
				}
			}	
		}
		else
		{	
			if(ocs_get_threshold_supported())
			{
				inactive_timer = pps_get_gprs_inactive_timer(shmp);

				if(pps_get_control_state())
					inactive_timer = inactive_timer / 2;

				if (gy_ptr->msg_body.cca.grant_value >= pps_get_quota_per_request())
				{
					gy_ptr->msg_body.cca.volume_threshold = gy_ptr->msg_body.cca.grant_value /5;
				}
				else
				{
					gy_ptr->msg_body.cca.volume_threshold = 0;
				}
				
				if(inactive_timer > 10)
					gy_ptr->msg_body.cca.time_threshold = (inactive_timer * 8 / 10); 
			}
			shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;
		}
	}
	
	/*
	if(gy_ptr->msg_body.cca.is_final == 1)
	{
		shmp->process_info.state = S_GY_PS_RELEASE	;
	}
	*/
	
	//shmp->process_info.funnel = (3600 + 5)*CYCLE_STATE_INTERVAL;

	gy_ptr->app_port = pid;
	
	gy_ptr->msg_type = GY_MSG_CCA;
	
	gx_handle_cca_from_server(gy_ptr);// response CCA

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		float balance = 0;

		balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);

		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] TS: %ld.%03d,  caller=%s, result=%d, Send CCA\r\n", 
					pid, 
					tvnow.tv_sec, tvnow.tv_usec/1000, 
					shmp->caller_info.number,
					gy_ptr->msg_body.cca.result);
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] Granted volume = %ld, charge volume = %ld, consumed volume = %ld, total charged = %.2f, balance = %.2f", pid, 
					gy_ptr->msg_body.cca.grant_value, 
					shmp->process_info.ppsService.gprs_process.vqConsumed.integer, 
					shmp->process_info.ppsService.gprs_process.dqConsumed ,
					shmp->caller_info.charge, balance);
		}
	}

	return 1;
}
static int	pps_recv_cca(_gy_msg  *gy_ptr)
{
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;

	if(gy_ptr->app_port>=MAX_FSM_PROCESS)
		return 0;
	
	shmp += gy_ptr->app_port;

	
	shmp->process_info.ro_if.recv_cmd = 1;
	shmp->process_info.ro_if.fd_port = gy_ptr->fd_port;
	shmp->process_info.ro_if.result = gy_ptr->msg_body.cca.result;
	shmp->process_info.ro_if.granted_value = gy_ptr->msg_body.cca.grant_value;
	shmp->process_info.ro_if.is_final = gy_ptr->msg_body.cca.is_final;

	if(shmp->process_info.ro_if.granted_value>0)
	{
		shmp->caller_info.valid_time += shmp->process_info.ro_if.granted_value * CYCLE_STATE_INTERVAL;
		shmp->called_info.valid_time += shmp->process_info.ro_if.granted_value * CYCLE_STATE_INTERVAL;
	}
	
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{

		DebugMsg(debugmib.display.asciiOut,
			"    [%04d] TS: %ld.%03d,  caller=%s \r\nRecv CCA, gy_port=%d, app_port=%d\r\n", gy_ptr->app_port,
			tvnow.tv_sec, tvnow.tv_usec/1000,
			shmp->caller_info.number,
			gy_ptr->fd_port, gy_ptr->app_port);

		DebugMsg(debugmib.display.asciiOut,
			"    result=%d, granted_value=%d, is_final=%d\r\n", 		
			shmp->process_info.ro_if.result,
			shmp->process_info.ro_if.granted_value,
			shmp->process_info.ro_if.is_final);

	}
	
	return 1;
}

static int	pps_recv_ro_voice_request(_gy_msg  *gy_ptr)
{
	int pid;
	unsigned int instance, granted_quota, new_assigned_quota = 0;
	float charge=0;
	int    max_duration = 0;
	//int    delay_timer = 0;
	float balance = 0;
	
	_state_data   *shmp = (_state_data *) &smshm_ptr->state_data;

	//PutLogFunID("pps_recv_ro_voice_request");

	pps_print_gy_msg(gy_ptr);
	
	if(gy_ptr->request_type == RT_INITIAL_REQUEST)
	{
		pid = AssignProcID(0);
		if( pid >= MAX_FSM_PROCESS || pid<0)
		{
			return 0;
		}
		shmp += pid;
		shmp->context_info.mtype  = CAP_O_OPEN;
		shmp->process_info.state = S_RO_VOC_INIT;
		shmp->process_info.fd_port = gy_ptr->fd_port;
		shmp->process_info.ro_if.gy_ro_enable = 1;
		//shmp->process_info.ro_if.service_identifier = gy_ptr->service_identifier;
		shmp->cdr_info.seizuretime = tvnow.tv_sec;

		switch(gy_ptr->msg_body.ccr.role_of_node )// avp Role-of-Node: 0/1/2, ORIGINATING_ROLE/T/F
		{
			case 0:
				shmp->process_info.serviceType = SRV_NORMAL_MO_CALL;
				shmp->context_info.callType = CT_MO_CALL;
			break;
			case 1:
				shmp->process_info.serviceType = SRV_NORMAL_MT_CALL;
				shmp->context_info.callType = CT_MT_CALL;
			break;
			case 2:
				shmp->process_info.serviceType = SRV_NORMAL_MF_CALL;
				shmp->context_info.callType = CT_MF_CALL;
			break;
		}
					
		pps_get_gy_number(&shmp->caller_info, gy_ptr->msg_body.ccr.caller);
		pps_get_gy_number(&shmp->called_info, gy_ptr->msg_body.ccr.called);

		CHECK_MSISDN_LOG_LEVEL();
		{
			int tmp_len;
			char *dot_offset = NULL;
			
			if( (dot_offset = strstr(gy_ptr->msg_body.ccr.apn, "." )) != NULL)// get pod name from Origin-Host, charged by location
			{
				tmp_len = dot_offset - gy_ptr->msg_body.ccr.apn; 
				memcpy(shmp->process_info.ro_if.apn, gy_ptr->msg_body.ccr.apn, tmp_len);
				shmp->process_info.ro_if.apn[tmp_len] = '\0';
			}

			//DebugMsg(debugmib.display.asciiOut,
			//	"    APN = %s", shmp->process_info.ro_if.apn);
			
		}
		/*
		DebugMsg(debugmib.display.asciiOut,
				"    caller = %s", shmp->caller_info.number);
		
		DebugMsg(debugmib.display.asciiOut,
				"    called = %s", shmp->called_info.number);
		*/
		shmp->process_info.duration = 0;
		if(OCS_with_external_CRM())
		{
			memcpy(&shmp->process_info.ro_if.gy_ccr_info, gy_ptr, sizeof(_gy_msg));
			shmp->process_info.oc = RT_INITIAL_REQUEST;
			shmp->process_info.funnel = SSHORT_DELAY_TIMER *CYCLE_STATE_INTERVAL;
			return pps_ro_voice_process_with_ext_crm(pid);
		} else {
			pps_ro_voice_process(pid);
		}
		//delay_timer = pps_get_gy_delay_timer(0);// Init Request delay time? Not used!
	}
	else
	{
		pid = gy_ptr->app_port;
		if( pid >= MAX_FSM_PROCESS || pid<0)
		{
			return 0;
		}
		
		shmp += pid;
		//delay_timer = pps_get_gy_delay_timer(1);// Update Request's delay time? Not used!

		shmp->process_info.duration += gy_ptr->msg_body.ccr.used_unit;

	}

	if(OCS_with_external_CRM())
	{
		if(gy_ptr->request_type == RT_TERMINATE_REQUEST)
		{
			shmp->process_info.ro_if.gy_ccr_info.request_type = RT_TERMINATE_REQUEST;
			shmp->process_info.oc = RT_TERMINATE_REQUEST;
		}
		else
		{
			shmp->process_info.ro_if.gy_ccr_info.request_type = RT_UPDATE_REQUEST;
			shmp->process_info.oc = RT_UPDATE_REQUEST;
		}
		return 1;
	}
	
	gy_ptr->msg_body.cca.result = 2001;

	if(gy_ptr->request_type == RT_TERMINATE_REQUEST)
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"    [%04d] caller=%s Call Terminated!", pid, shmp->caller_info.number);
			
			DebugMsg(debugmib.display.asciiOut,
				"    call duration = %d", shmp->process_info.duration);
		}
		
		gy_ptr->msg_body.cca.grant_value = shmp->process_info.duration;
		gy_ptr->msg_body.cca.is_final = 1;

		shmp->process_info.oc = RT_TERMINATE_REQUEST;
		granted_quota = 0;
		//delay_timer = 0;// Terminate Request's delay time? Not used!
	}
	else
	{
		int	account_unnormal_status_flag = 0;
		u32 unused_quota;
		
		shmp = &smshm_ptr->state_data[pid];

		// get acount status, normal or not; ===============================
		if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
			shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
		{
			//balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);
			if(shmp->caller_info.status != T_NORMAL)
				account_unnormal_status_flag = 1;
			if(shmp->caller_info.expired_flag)
				account_unnormal_status_flag = 1;
		}
		else
		{
			//balance = GetAccountBalance(shmp->called_info.head, shmp->called_info.tail);
			if(shmp->called_info.status != T_NORMAL)
				account_unnormal_status_flag = 1;
			if(shmp->called_info.expired_flag)
				account_unnormal_status_flag = 1;
		}
		//=======================================================

		// calculate granted quota and new assigned quota=========================
		unused_quota = shmp->process_info.charged_duration - shmp->process_info.duration;
		max_duration = pps_get_max_call_duration_in_second();
		if(account_unnormal_status_flag)
		{
			max_duration = 0;
			granted_quota = 0;
		}
		else
		{
			if (unused_quota >= max_duration)// unused quota is enough for next grant
			{
				granted_quota = max_duration;
			}
			else
			{
				new_assigned_quota = max_duration - unused_quota;
			}
		}
		//===================================================
		
		// Try to assigned new quota to meet max_dration, and charge and sync
		if (new_assigned_quota > 0)
		{
			u32 new_assigned_bundle = 0;
			charge = pps_billing_ro_voice(shmp, &new_assigned_quota, &new_assigned_bundle);
			if((charge >= 0.0001f) || (new_assigned_bundle > 0))
			{
				shmp->charge_info.charge += charge;

				if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
					shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
				{
					UpdateAccountBalance(shmp->caller_info.head, shmp->caller_info.tail, -charge);
					pps_update_account_bundle_mo_voice(shmp, -new_assigned_bundle);
				
					instance = shmp->caller_info.head*UNIT_STORE_ACCOUNT + shmp->caller_info.tail;
				}
				else
				{
					UpdateAccountBalance(shmp->called_info.head, shmp->called_info.tail, -charge);
					pps_update_account_bundle_mt_voice(shmp, -new_assigned_bundle);
				
					instance = shmp->called_info.head*UNIT_STORE_ACCOUNT + shmp->called_info.tail;
				}
				
				SendAccountRealSync(instance, -charge, 0, OMC_OCODE_EDIT);
			}

			if ((new_assigned_quota + unused_quota) >= max_duration)
			{
				granted_quota = max_duration;
			}
			else
			{
				granted_quota = new_assigned_quota + unused_quota;
			}
			
			shmp->process_info.charged_duration += new_assigned_quota;
		}
		//

		// Set is_final flag by granted_quota
		if(granted_quota > 0)
		{

			gy_ptr->msg_body.cca.is_final = 0;
		}	
		else
		{
			gy_ptr->msg_body.cca.is_final = 1;
		}
		gy_ptr->msg_body.cca.grant_value = granted_quota;
		//
	}

	//sleep(delay_timer);
	if(gy_ptr->request_type == RT_INITIAL_REQUEST)
		shmp->process_info.funnel = (granted_quota + 35)*CYCLE_STATE_INTERVAL;
	else
		shmp->process_info.funnel = (granted_quota + 5)*CYCLE_STATE_INTERVAL;

	if(gy_ptr->msg_body.cca.is_final == 1)
	{
		gy_ptr->msg_body.cca.result = 4012;	
		shmp->process_info.state = S_RO_VOC_RELEASE;
	}

	gy_ptr->app_port = pid;
	
	gy_ptr->msg_type = GY_MSG_CCA;
	
	gx_handle_cca_from_server(gy_ptr);// response CCA

	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{  

			if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL ||
				shmp->process_info.serviceType == SRV_NORMAL_MF_CALL)	
			{
				balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);
			}
			else
			{
				balance = GetAccountBalance(shmp->called_info.head, shmp->called_info.tail);
			}
		
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] TS: %ld.%03d,  caller=%s, called=%s, Send CCA\r\n", pid, tvnow.tv_sec, tvnow.tv_usec/1000,
						shmp->caller_info.number, shmp->called_info.number);
			DebugMsg(debugmib.display.asciiOut,
					"    [%04d] Granted duration[%d], new allocated duration[%d], charge duration[%d], charged = %.2f, total charged = %.2f, balance = %.2f", pid, 
					granted_quota, new_assigned_quota, shmp->process_info.charged_duration, charge, shmp->charge_info.charge, balance);
		}
	}
	return 1;
}


static int	pps_recv_ro_gy_process(_gy_msg  *gy_ptr)
{
	//PutLogFunID("pps_recv_ro_gy_process");

	if(gy_ptr == NULL)
		return 0;

	// process cca
	if(gy_ptr->msg_type == GY_MSG_CCA)
		return pps_recv_cca(gy_ptr);

	memset(&gy_ptr->msg_body.cca, 0x00, sizeof(_gy_cca));

	// process event request
	if (gy_ptr->request_type == RT_EVENT_REQUEST)
	{
		if (gy_ptr->service_type == ST_CS_SMS)
		{
			return pps_recv_ro_sms_request(gy_ptr);// Ro SMS
		}
		else
		{
			return pps_recv_event_request(gy_ptr);// Common DCCA Event
		}
	}
	//
		
	if(gy_ptr->service_type == ST_PS_DATA)
	{
		return pps_recv_gy_data_request(gy_ptr);
	}
	else
	{
		return pps_recv_ro_voice_request(gy_ptr);
	}
}


int pps_ro_gy_cb(_gy_msg  *gy_ptr)
{
	//pthread_mutex_lock( &pps_mtx );
	pps_recv_ro_gy_process(gy_ptr);
	//pthread_mutex_unlock( &pps_mtx );

	return 1;
}


/* ------------------End of  Gy/Ro interfaces -------------*/

/**---------------end of call distribution--------------------**/
/**------------------------------------------------------**/
extern int SmppRechargeProc(u_short portid);
extern int pps_crm_query_tariff_test_proc(u_short portid);
void CallProc()
{
	int    portid,retval;
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;    

	for(portid=0; portid<MAX_FSM_PROCESS; portid++) 
	{
		if (smshm_ptr->port_info[portid].status == 0x00)
		{
			continue;
		}
		
		shmp = (_state_data *) smshm_ptr->state_data;    
		shmp += (portid);

		switch(shmp->process_info.state) 
		{
			case S_IDLE:
				if (shmp->context_info.new_flag == NO )
				{
					// smshm_ptr->port_info[portid].status =0;
					break;
				}
				shmp->context_info.new_flag = NO;
				switch(shmp->context_info.mtype)
				{
					case CAP_O_OPEN:
						shmp->process_info.state = S_WAITING_INITIALDP;
					break;
					case 0x80:
						shmp->process_info.sub_state = S_MAP_SEND_OPENRSP;
						shmp->process_info.state = S_MAP_STATE;
					break;
					case GPRS_O_OPEN:
						shmp->process_info.ppsService.gprs_process.state = pps_gprs_idle;
						shmp->process_info.state = S_GPRS_STATE;
					break;
					case VAS_O_OPEN:
						shmp->process_info.ppsService.gprs_process.state = VAS_STATE_IDLE;
					  	shmp->process_info.state = S_VAS_STATE;
					break;
					default:
						ReleaseAll(portid);
						shmp->process_info.state = S_IDLE;
					break;
				}					
			break;            
			case S_GPRS_STATE:
				retval = pps_gprs_process(portid);
				switch(retval)
				{
					case SERVICE_KEEP_STATE:
					break;					
					case SERVICE_RETURN_TO_PARENT:
					case SERVICE_EXIT_PPS:
					default:
						shmp->process_info.state = S_RELEASE_ALL;
					break;
				}		
			break;
			case S_VAS_STATE:
				retval = vasProcess(portid);
				switch(retval)
				{
					case SERVICE_KEEP_STATE:
					break;					
					case SERVICE_RETURN_TO_PARENT:
					case SERVICE_EXIT_PPS:
					default:
						shmp->process_info.state = S_RELEASE_ALL;
					break;
				}		
			break;									
			case S_MAP_STATE:
				retval = ppsMapState(portid);
				if(retval != 0)
				{
					shmp->process_info.state = S_RELEASE_ALL;
				} 
			break;         
			case S_WAITING_INITIALDP:
				shmp->process_info.state = WaitingForInitialDP(portid);
			break;
			case S_SEND_MNP_ATI:				
				shmp->process_info.state = SendCallMNP_ATI(portid);
			break;		    
			case S_WAIT_MNP_ATI_RES:
				retval = WaitingForMNP_ATI_Res(portid);
				switch(retval)
				{
					case 0:
					break;
					case 1: /* get ati response */
					case -1: /* ati res timeout */
						shmp->process_info.state =  S_CHECK_CALL_VALIDITY;
					break;
					default:
						shmp->process_info.state = S_RELEASE_ALL;
					break;
				}       
			break;								
			case S_CHECK_CALL_VALIDITY:
				shmp->process_info.state =	CheckCallValidity(portid);
			break;
			case S_REQUEST_EVENTS:
				shmp->process_info.state = RequestBCSMEvent(portid);
				shmp->process_info.funnel = 0;
			break;			
			case S_APPLY_CHARGING:
				shmp->process_info.state = ApplyCharging(portid);
				/* idle state to make interval between open confirm and the 2nd continue operation  longer */
			break;	
			case S_APPLY_CHARGING_REAL:
				shmp->process_info.state = ApplyCharging(portid);
			break;
			case S_SEND_CONTINUE:
				shmp->process_info.state = ReleaseContinue(portid);
			break;
			case S_WAITINGFOR_EVENTS:
				shmp->process_info.fsm_timer = 0;
				if(shmp->process_info.ccc_flag == 0)
					shmp->process_info.state = WaitingForEventsReport(portid);
				else
					shmp->process_info.state = WaitingForEventsReport_ccc(portid);
					
			break;
			case S_WAITINGFOR_ANSWERED:
				if(shmp->process_info.ccc_flag == 0)
					shmp->process_info.state = WaitingforAnsweredProc(portid);
				else
					shmp->process_info.state = WaitingforAnsweredProc_ccc(portid);					
			break;
			case S_RECHARGE_OVER:
				debugmib.watch_dog[3] ++;
				shmp->process_info.state =  S_IDLE;
			break;
			case S_SEND_SMS_MNP_ATI:
				shmp->process_info.state = SendSMSMNP_ATI(portid);
			break;
			case S_SMS_WAIT_MNP_ATI_RES:
				retval = WaitingForSMSMNP_ATI_Res(portid);
				switch(retval)
				{
					case 0:
					break;
					case 1: /* get ati response */
					case -1: /* ati res timeout */
						shmp->process_info.state = 
								S_SMS_CHECK_VALIDITY;
					break;
					default:
						shmp->process_info.state = 
								S_RELEASE_ALL;
					break;
				}
			break;
			case S_SMS_CHECK_VALIDITY:
				shmp->process_info.state = 
				        CheckSMSValidity(portid);
			break;
			case S_REQUEST_SMS_EVENTS:
			    shmp->process_info.state = 
				        RequestSMSEvents(portid);
			break;
			case S_RELEASE_SMS_CONTINUE:
				shmp->process_info.state =
						ReleaseContinueSMS(portid);
			break;
			case S_WAITINGFOR_SMS_EVENTS:
			    shmp->process_info.state =
				        WaitingForSMSEvents(portid);
			break;
			case S_ESTABLISH_TEMPORARY_CONNECTION:
				shmp->process_info.state =
						EstablishTemporaryConnection(portid);
			break;
			case S_DISCONNECT_FORWARD_CONNECTION:
				shmp->process_info.state =
						WaitingForDisconnectForwardConnection(portid);						
			break;
			case S_SEND_RELEASE_CALL:
				shmp->process_info.state =
						SendSSFReleaseCall(portid);
			break;
			case S_SEND_PLAY_ANNOUNCEMENT:
				shmp->process_info.state =
						SendPlayAnnouncementOrPCUI(portid);
			break;
			case S_WAITING_SPECIAL_RESOURCE_REPORT:
				shmp->process_info.state =
						WaitingForSpecialResourceReport(portid);
			break;
			case S_WAITING_RR_PCUI:
				shmp->process_info.state =
						WaitingForRRofPromptAndCollectUserInfo(portid);
			break;
			case S_INQUIRY_MANAGE:			
			retval = InquiryManageProc(portid);
			switch(retval)
			{
				case inq_mng_keep_state:
				break;
				case inq_mng_to_recharge:

				shmp->process_info.sub_state = S_REC_INQ_CHECK_MENU;
				shmp->process_info.state = S_RECHARGE_MANAGE;				
				break;
				case inq_mng_exit:
				shmp->process_info.state = S_RELEASE_SRF;
				break;
			}
			break;
			case S_RECHARGE_MANAGE:
			retval = RechargeManageProc(portid);
			switch(retval)
			{
				case rec_mng_keep_state:
				break;
				case rec_mng_turn_to_ivr_scratch_card:
				shmp->process_info.sub_state = S_CCR_CONNECT_TO_IVR_SCRATCH_CARD;
				shmp->process_info.state = S_CREDIT_CARD_RECHARGE;
				break;
				case rec_mng_turn_to_credit_recharge:
				shmp->process_info.sub_state = S_CCR_CONNECT_TO_CREDIT_CENTER;
				shmp->process_info.state = S_CREDIT_CARD_RECHARGE;
				break;
				case rec_mng_exit:
				default:
				shmp->process_info.state = S_RELEASE_SRF;
				break;
			}
			break;
			case S_CREDIT_CARD_RECHARGE:
			retval = creditCardRechargeProc(portid);
			switch(retval)
			{
				case ccr_mng_keep_state:
				break;
				case ccr_mng_connect_to_credit_center:
				default:
				shmp->process_info.state = S_RELEASE_SRF;
				break;
			}
			break;
			case S_FAVORITE_NUMBER_MANAGE:
			retval = FavoriteNumberManageProc(portid);
			switch(retval)
			{
				case fav_mng_keep_state:
				break;
				case fav_mng_exit:
				shmp->process_info.state = S_RELEASE_SRF;
				break;
				case fav_mng_exit_to_main_menu:
				shmp->process_info.voiceID = SERVICE_SELECT_PROMPT;
				shmp->process_info.maxPCUInfoLen = 1;
				SendPromptAndCollectUserInfo(portid);
				shmp->process_info.state = S_WAITING_RR_PCUI;
				break;
			}
			break;
			case S_LANGUAGE_MANAGEMENT:
				retval = LanguageManagementProc(portid);
				switch(retval)
				{
					case language_mng_keep_state:
					break;
					case language_mng_exit:
					shmp->process_info.state = S_RELEASE_SRF;
					break;
					case language_mng_exit_to_main_menu:
					shmp->process_info.voiceID = SERVICE_SELECT_PROMPT;
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					shmp->process_info.state = S_WAITING_RR_PCUI;
					break;
					default:
					shmp->process_info.state = S_RELEASE_SRF;
					break;
				}
			break;
			case S_PIN_MANAGEMENT:
				retval = PINManagementProc(portid,0);
				switch(retval)
				{
					case pin_mng_keep_state:
					break;
					case pin_mng_exit_to_main_menu:
					shmp->process_info.voiceID = SERVICE_SELECT_PROMPT;
					shmp->process_info.maxPCUInfoLen = 1;
					SendPromptAndCollectUserInfo(portid);
					shmp->process_info.state = S_WAITING_RR_PCUI;
					break;
					case pin_mng_exit:
					default:
					shmp->process_info.state = S_RELEASE_SRF;
					break;
				}
			break;
			case S_CALLING_CARD:/*calling card		*/
				retval = callingCardProc(portid);
				switch(retval)
				{
					case pin_mng_keep_state:
					break;					
					case pin_mng_exit:
					default:
					ReleaseSRF(portid);					
					ReleaseAll(portid);
					shmp->process_info.state = S_IDLE;
					break;
				}				
			break;
			case S_CC_CHECK_CALL_VALIDITY:
				shmp->process_info.state =	CheckCallValidity_ccc(portid);
			break;			
			case S_CHARGE_OR_TRANSFER:				
				retval = chargeOrTransfer(portid);
				switch(retval)
				{
					case SERVICE_KEEP_STATE:
					break;					
					case SERVICE_RETURN_TO_PARENT:	
						retval = getInputtedChoice(shmp);					
						switch(retval)
						{
							case CONFIRM_OK:
								shmp->process_info.sub_state = S_REC_CHECK_ACCOUNT_STATUS;
								shmp->process_info.state = S_RECHARGE_MANAGE;
							break;
							case CONFIRM_ENTER_AGAIN:
							default:
								shmp->process_info.state = S_FEE_TRANSFER;
								clearTransferInfo(portid);
							break;													
						}				
					break;
					case SERVICE_EXIT_PPS:
					default:
						ReleaseSRF(portid);					
						ReleaseAll(portid);
						shmp->process_info.state = S_IDLE;
					break;
				}		
			break;
			case S_FEE_TRANSFER:
				retval = transferAccountIVRProc(portid);
				switch(retval)
				{
					case SERVICE_KEEP_STATE:
					break;					
					case SERVICE_RETURN_TO_PARENT:
					case SERVICE_EXIT_PPS:
					default:
						shmp->process_info.state = S_RELEASE_SRF;
					break;
				}		
			break;
			case S_POOL_ACCOUNT:
				retval = masterSlaveIVRProc(portid);
				switch(retval)
				{
					case SERVICE_KEEP_STATE:
					break;					
					case SERVICE_RETURN_TO_PARENT:
					case SERVICE_EXIT_PPS:
					default:
						shmp->process_info.state = S_RELEASE_SRF;
					break;
				}						
			break;
			case S_RELEASE_SRF:
				shmp->process_info.state =
						ReleaseSRF(portid);
			break;
			case S_CRD_SERVICE:
				retval = CheckCRDService(portid);
				switch(retval)
				{
					case crd_keep_state:
					break;
					case crd_release_call:
					shmp->process_info.state =
						S_RELEASE_SRF;
					break;
					case crd_wait_answer:
					default:
					shmp->process_info.state = 
						S_RELEASE_SRF;
					break;
				}					
				
			break;

			case S_SMMP_RECHAGE_ACCOUNT:
				if(SmppRechargeProc(portid) != 0)
				{
					ReleaseAll(portid);
					shmp->process_info.state = S_IDLE;
				}
			break;
		 
			case S_RO_EVENT_SMS_INIT:
			break;// do nothing
			case S_RO_EVENT_SMS_PROCESS:
				pps_ro_event_sms_process(portid);
		 	break;
			case S_RO_EVENT_COMMON_INIT:
			break;// do nothing
			case S_RO_EVENT_COMMON_PROCESS:
				pps_ro_event_common_process(portid);
		 	break;

			case S_RO_VOC_INIT:
			break;// do nothing
			case S_RO_VOC_CONNECTED:
			case S_RO_VOC_RELEASE:
			case S_RO_VOC_GET_TARIFF_FROM_CRM:
				pps_ro_voice_process(portid);
			break;
			case S_GY_PS_INIT:
			break;// do nothing
			case S_GY_PS_CONNECTED:
			case S_GY_PS_WAIT_TERM:
			case S_GY_PS_RELEASE:
			//case S_GY_PS_GET_TARIFF_FROM_CRM:
			case S_GY_PS_GET_TARIFF_FROM_CRM_RES:
				pps_gy_data_charge_process(portid);
			break;
			case S_GY_PS_POSTPAID:
				pps_gy_data_postpaid_process(portid);
			break;
			
			case S_RO_ADAPTOR_CALL_INIT:
				shmp->process_info.ro_if.request_type = RT_INITIAL_REQUEST;
				if(pps_ro_adaptor_call_init(portid)==1)
					shmp->process_info.state = S_RO_CALL_WAIT_FIRST_CCA;
			break;
			case S_RO_CALL_WAIT_FIRST_CCA:
				retval = pps_ro_call_wait_first_cca(portid); 
				if( retval == 1)
				{
					if(shmp->process_info.routing_home_flag == 1)
						shmp->process_info.state = S_ROUTING_HOME_PRN;
					else
						shmp->process_info.state = S_REQUEST_EVENTS;
				}
				else if(retval == -1)
				{
					shmp->process_info.pre_warning = 0;
					if(shmp->process_info.serviceType == SRV_NORMAL_MO_CALL)
					{
						shmp->process_info.playAnnouncement = 1;
						shmp->process_info.state = S_REQUEST_EVENTS;
					}
					else
						shmp->process_info.state = S_SEND_RELEASE_CALL;
				}
			break;
			case S_RO_CALL_TERMIATED:
				if(pps_ro_call_termiate(portid) == 1)
					shmp->process_info.state = S_RELEASE_ALL;
			break;
			case S_RO_ADAPTOR_SMS_INIT:
				shmp->process_info.ro_if.request_type = RT_INITIAL_REQUEST;
				shmp->process_info.ro_if.request_action = RA_DIRECT_DEBITING;
				if(pps_ro_adaptor_sms_init(portid)==1)
					shmp->process_info.state = S_RO_SMS_WAIT_RESULT;
			break;
			case S_RO_SMS_WAIT_RESULT:
				retval = pps_ro_sms_wait_first_cca(portid);

				if( retval == 1)
				{
					shmp->process_info.state = S_REQUEST_SMS_EVENTS;			
				}
				else if (retval == -1)
				{
					SendReleaseSMS(portid);
					shmp->process_info.state = S_RELEASE_ALL;

				}
			break;
			case S_RO_SMS_REFUND:
				if(pps_ro_sms_refund(portid) == 1)
					shmp->process_info.state = S_RELEASE_ALL;
			break;
			case S_ROUTING_HOME_PRN:
				retval = pps_routing_home_proc(portid);	
				if(retval == 1)
				{
				  	shmp->process_info.state = S_REQUEST_EVENTS;
				}		  
				else if(retval < 0)
				{
				       shmp->process_info.tcend = 1;
				  	shmp->process_info.state = S_RELEASE_ALL;
				}		  	
			break;
			case S_SMPP_MAIN:
				retval = pps_smpp_state(portid);
				if(retval !=0 )
				{
					ReleaseAll(portid);
				}
			break;
			case S_CRM_QUERY_TARIFF_TEST:
				retval = pps_crm_query_tariff_test_proc(portid);
				if(retval != 0)
				{
					ReleaseAll(portid);					
				}
			break;
			case S_RELEASE_ALL:
				ReleaseAll(portid);
				shmp->process_info.state = S_IDLE;
			break;
			
			default:
				ReleaseAll(portid);
				shmp->process_info.state = S_IDLE;
			break;
		} /* switch() */

		if(shmp->process_info.state != S_IDLE)
			shmp->process_info.fsm_timer++;
			
		if(shmp->process_info.state != S_IDLE &&
				shmp->process_info.state != S_WAITINGFOR_EVENTS &&
				shmp->process_info.state != S_GPRS_STATE 
				&& shmp->process_info.state != S_GY_PS_CONNECTED
				&& shmp->process_info.state != S_RELEASE_ALL
				&& shmp->process_info.state != S_GY_PS_POSTPAID
				&& shmp->process_info.state != S_RO_VOC_GET_TARIFF_FROM_CRM
				&& shmp->process_info.state != S_RO_VOC_CONNECTED
				&& shmp->process_info.state != S_RO_VOC_RELEASE
				)
		{
			if(shmp->process_info.fsm_timer>PPS_FSM_TIMEROUT)
			{
				DebugMsg(debugmib.display.asciiOut,"Release port: %d in state: %d",
									portid,shmp->process_info.state);

				SendCDR(portid);

				ReleaseAll(portid);
				shmp->process_info.state = S_IDLE;					
			}
		}
	} /* for() */
}


void ListAllPortStatus(int flag)
{
	FILE *fpStatus=NULL;
	
    int        portid;
    _state_data   *shmp = (_state_data *) smshm_ptr->state_data;    

	if(flag)
	{
    		for(portid=0; portid<MAX_FSM_PROCESS; portid++) 
		{
        		shmp = (_state_data *) smshm_ptr->state_data;    
        		shmp += (portid);
			//if(shmp->process_info.state == S_IDLE &&
			//	smshm_ptr->port_info[portid].status == 1)
			{
				ReleaseAll(portid);
				shmp->process_info.state = S_IDLE;
			}
		}
		return;
	}

	fpStatus = fopen("../log/pps_state.txt","w");
	if(fpStatus == NULL)
			return;
	
    for(portid=0; portid<MAX_FSM_PROCESS; portid++) 
	{
        shmp = (_state_data *) smshm_ptr->state_data;    
        shmp += (portid);
		fprintf(fpStatus,"[%04d].status = %d.%d, %s->%s, duration=%d(s)\n",
						portid, smshm_ptr->port_info[portid].status,
						shmp->process_info.state, shmp->caller_info.number,shmp->called_info.number,
						shmp->process_info.fsm_timer/CYCLE_STATE_INTERVAL);
						
	}
	fclose(fpStatus);
}

int	ClearAllPortForStop()
{
	u_short              portid;
    	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	PutLogFunID("ClearAllPortForStop");

    	for(portid=0; portid<MAX_FSM_PROCESS; portid++) 
	{
	        shmp = (_state_data *) smshm_ptr->state_data;    
	        shmp += portid;
	        switch(shmp->process_info.state)
		{
			case S_WAITINGFOR_EVENTS:
				shmp->process_info.tcos = NETWORK_OUT_OF_ORDER;
				shmp->cdr_info.releasetime = tvnow.tv_sec;
				SendCDR(portid);
			    	SendReleaseCall(portid);
			break;

			case S_RO_EVENT_SMS_PROCESS:
				pps_ro_event_sms_process(portid);
		 	break;
			case S_RO_EVENT_COMMON_PROCESS:
				pps_ro_event_common_process(portid);
		 	break;

			case S_RO_VOC_INIT:
			case S_RO_VOC_CONNECTED:
			case S_RO_VOC_RELEASE:
				shmp->process_info.state = S_RO_VOC_RELEASE;
				pps_ro_voice_process(portid);
			break;
			case S_GY_PS_INIT:
			case S_GY_PS_CONNECTED:
			case S_GY_PS_WAIT_TERM:
			case S_GY_PS_RELEASE:
				shmp->process_info.state = S_GY_PS_RELEASE;				
				pps_gy_data_charge_process(portid);
			break;			
			case S_GY_PS_POSTPAID:
				shmp->process_info.oc = RT_TERMINATE_REQUEST;
				pps_gy_data_postpaid_process(portid);
			break;
			case S_RECHARGE_OVER:
				debugmib.watch_dog[5] ++;
				//RechargeRequestProc(portid);
			break;
			default:
			break;
		}
	}
	return 1;
}

#ifdef CONVERT_16DIGIT_CARD
void Convert16DigitCard()
{
	int		i,j,len,tail,snRead,snExist;
	int		foundFlag,consistentCounter=0;
	char	fileName[]="./conf/card_info_rebuild.txt";
	char	record[512],buf[128];
	char	card_no[32],card_pwd[32];
	FILE	*fp;
    _card_data     *card_data=&ramshm_ptr->card_data;

	fp = fopen(fileName,"r");
	if(fp == NULL) 
	{
		//printf("File %s not found, abort converting!\n",fileName);
		return;
	}

	stopReceivePeriodicSyncFlag = 1;
	while(fgets(record,512,fp) != (char *)0) 
	{
		memcpy(card_no,record,16);
		card_no[16] = 0;
		memcpy(card_pwd,&record[17],16);
		card_pwd[16] = 0;
		snRead = atoi(&card_no[8]);
		tail = atoi(&card_no[14]);
		foundFlag = 0;

		for(i=0;i<MAX_CARD_SEGMENT-MAX_CLIMAX_CARD_SEGMENT;i++)
		{
			len = card_data->prepaid_card[i][tail].card_no[MAX_CARD_LENGTH];
			if(len !=16 )
			{
				continue;
			}
			BcdToAscii(buf,card_data->prepaid_card[i][tail].card_no,len);
			snExist = atoi(&buf[8]);
			if(snRead == snExist)
			{
				foundFlag = 1;
				consistentCounter ++;
				AsciiToBcd(card_data->prepaid_card[i][tail].card_pwd,card_pwd,16);
			}
		}
		if(!foundFlag)
		{
			for(i=MAX_CARD_SEGMENT-MAX_CLIMAX_CARD_SEGMENT;i<MAX_CARD_SEGMENT;i++)
				for(j=0;j<MAX_CARD_NUM_PSEG;j++)
			{
				len = card_data->prepaid_card[i][j].card_no[MAX_CARD_LENGTH];
				if(len !=16 )
				{
					continue;
				}
				BcdToAscii(buf,card_data->prepaid_card[i][j].card_no,len);
				snExist = atoi(&buf[8]);
				if(snRead == snExist)
				{
					foundFlag = 1;
					consistentCounter ++;
					AsciiToBcd(card_data->prepaid_card[i][j].card_pwd,card_pwd,16);
				}
			}
		}//!
	}
	//printf("total %d converted\n",consistentCounter);
	//stopReceivePeriodicSyncFlag = 0;
	fclose(fp);
	remove(fileName);
}
#endif

extern int ocs_init_hash_table();
extern int ocs_read_crm_base_prefix_file();
int CreatePPSDataIndexForAll()
{
	int	i;
	_card_data	*card_data=&ramshm_ptr->card_data;
	struct timeval	tmstart,tmend;

	gettimeofday(&tmstart,NULL);

	PutLogFunID("PrivateRamInit");
#ifdef OCS_WITH_CRM
	ocs_init_hash_table();
#endif

	CreatePPSSubsIndexTable();
	
	debugmib.measurement.cardnumber = 0;
	debugmib.measurement.cardheadnumber = 0;

	for(i=0;i<MAX_VALUE_TYPE;i++)
	{
		card_data->face_value[i]=0;
	}

	CreateQuenceList();

	gettimeofday(&tmend,NULL);
	printf("create index take: %ld usec\n",
		(tmend.tv_sec-tmstart.tv_sec)*1000000 +
		tmend.tv_usec-tmstart.tv_usec);
	return 1;
}

static int
PrivateRamInit()
{

	CreatePPSDataIndexForAll();   
    
	load_tariff_main();

	return SUCCESS;
}


int realSyncTcpSend(DWORD db_type, DWORD instance, DWORD ocode, BYTE *payload, WORD len)
{
	if ((!ppsParam.serviceControl.tcp_sync_flag) || (realSyncTcpSap < 0) || (realSyncTcpPid < 0))
	{
		return -1;
	}
	
        if (tcp_send(realSyncTcpSap, 0, realSyncTcpPid, payload, len, db_type, instance, ocode) < 0)
        {
            return -1;
        }

	return 0;
}

static int realSyncTcpInit(u_long localip, u_long peerip)
{
	tcp_sap_t realTcpSap;
	tcp_session_t sess;

	// bind
	strcpy(realTcpSap.name, "PpsRealSync");
	realTcpSap.recv_cb = tcpRealSyncProc;
	realSyncTcpSap = tcp_bind(&realTcpSap);
	if (realSyncTcpSap < 0)
	{
		return -1;
	}

	// allocate port, 1: client; 0: server;
	sess.bServer = subSystemID ? FALSE : TRUE;
	sess.src_ip = localip;
	sess.src_port = PPS_REALSYNC_PORT;
	sess.dst_ip = peerip;
	sess.dst_port = PPS_REALSYNC_PORT;
	realSyncTcpPid = tcp_port_alloc_port(realSyncTcpSap, 0, &sess);
	if (realSyncTcpPid < 0)
	{
		return -1;
	}

	return 0;
}


int SystemInit()
{
	blf_shmp = (_tariff_private *) ShmInit(blf_shmid, prog_name, 
            TARIFF_SHM_KEY, PRIVATE_TARIFF_SIZE, 
            TARIFF_SHM_PERM|IPC_CREAT);

	memset(blf_shmp, EMPTY, PRIVATE_TARIFF_SIZE);

	ramshm_ptr = (_ram_data *) ShmInit(ramshm_id, prog_name, 
            RAMDATA_SHM_KEY, 84*1024*1024,
            RAMDATA_SHM_PERM|IPC_CREAT);
	memset(ramshm_ptr,0,84*1024*1024);
    
	GetVersionID(VERSION,version_id);
	GetVersionID(VERSION,peer_version_id);

	reportInit();
   
	ppsInitCSTA();
        
	LoadPPSParam();
    	pps_smppInit(); 
	debugmib.display.proc_used = 0;
	debugmib.display.ro_used = 0;
	debugmib.display.gy_used = 0;
	initSNMP();
	
	init_radius_gsn();
	realSyncTcpInit(LOCAL_IP, peer_server_ip);
	icap_reg_ssn(SSN_SCF);  //CAP
	imap_reg_ssn(0x99);  //gsmSCF
	return SUCCESS;
}
 
 int pps_read_sysparam(int *sysID, u_long *localIP, u_long *peerIP)
{
	FILE	*fp;
	int		ii;
	char	*ch_ptr,*buf_ptr;
	char	*temp_ptr;
	char	hostname[64];
	char	temp_info[64],info_str[1024];
	struct	hostent		*pcn;
	struct	in_addr		temp_addr;

	char    sysconf[]="./conf/wxc2_sys.conf";

	if ((gethostname(hostname,-1)) == -1)
	{
		printf("Can not get hostname\n");
		return 0;
	}
	pcn = gethostbyname(hostname);
	if (pcn == NULL)
	{
		printf("Get host ip address fail. Please check your ethernet configure\n");
		return 0;
	}
	fp = fopen(sysconf,"r");			/* read system configure */
	if (fp == NULL)
	{
		printf("can not open file %s!!\n",sysconf);
		return 0;
	}
	ch_ptr = strchr(hostname,'.');
	if (ch_ptr != NULL)
		ch_ptr[0] = '\0';	/* delete the suffix of host name */
	while (!feof(fp))
	{
		info_str[0] = '\n';
		fgets(info_str,250,fp);
		if (info_str[0] == '#' || info_str[0] == '\n')
			continue;
		buf_ptr = info_str;
		for (ii = 0;ii < 2;ii ++)
		{
			ch_ptr = strsep(&(buf_ptr),"=;");
			if (ch_ptr == NULL)
			{
				printf("This field lacks infomation:%s\n",buf_ptr);
				return 0;
			}
			if (ii == 0)
			{
				if (strlen(ch_ptr) != strlen(hostname))
				{
					printf("Please check host name in file:%s\t%s\n",ch_ptr,hostname);
					return 0;
				}
				temp_ptr = strchr(hostname,'-');
				if (memcmp(ch_ptr,hostname,strlen(hostname)-strlen(temp_ptr)) != 0)
				{
					printf("The host name is unexpect!\n");
					return 0;
				}
				strcpy(temp_info,ch_ptr);
			}
			else
			{
				if (memcmp(hostname,temp_info,strlen(temp_info)) == 0)	/* owner ip address */
				{
					if (strcmp(inet_ntoa(*(struct in_addr *)(*pcn->h_addr_list)),ch_ptr) != 0)
					{
						printf("Error ip address\n");
						return 0;
					}
					*sysID = temp_info[strlen(temp_info)-1] - '0';

					if (*sysID > 1)
					{
						printf("Error system id\n");
						return 0;
					}
					*localIP = ((struct in_addr *)(*pcn->h_addr_list))->s_addr;
				}
				else
				{
					if (!inet_aton(ch_ptr,&temp_addr))
					{
						printf("Can not get peer ip address\n");
						return 0;
					}
					*peerIP = temp_addr.s_addr;
				}
			}
		}
	}
	fclose(fp);
	return 1;
}


int InitRamData(int no_sync_flag)
{
	static int initState = _INIT_CHECK_VERSION;
	static int trytimes = 0;
	int    retval=0;

	PutLogFunID("InitRamData");

	switch(initState)
	{
		case _INIT_CHECK_VERSION:  /* check version, waiting 10s	    */
			//initState = _INIT_READ_FROM_LOCAL_HD;
			
			if(no_sync_flag)
			{
				initState = _INIT_READ_FROM_LOCAL_HD;
				trytimes=0;
				break;
			}
			if(pps_peer_hb_flag)
			{
				if(memcmp(version_id,peer_version_id,2))/* the first 2 version should be the same */
				{
					debugmib.display.sysState = _SYS_STATE_SUSPEND;
					initState = _INIT_CHECK_VERSION;
					trytimes = 0;
					alarm_code[0] = 0; /* pps */
					alarm_code[1] = 1; /* version not the same */
					return 1;
				}				
				/*
				else if(peer_version_id[2]<4)
				{
					initState = _INIT_READ_FROM_LOCAL_HD;
					trytimes=0;				
					break;
				}
				*/
				pps_peer_hb_flag = 0;
				initState = _INIT_CHECK_SYNC;
				trytimes=0;
			}
			else if(trytimes++>2000)
			{
				initState = _INIT_READ_FROM_LOCAL_HD;
				trytimes=0;
			}
			//initState = _INIT_CHECK_SYNC;
			//trytimes=0;
		break;
		case _INIT_CHECK_SYNC:
			/*
			if(ReadPeroidicSyncData())
			{	  
				debugmib.display.dataSrc=_SRC_PEER_SRV;
				initState = _INIT_READ_FROM_PEER;
			}
			else if(trytimes++>MAX_RAM_INIT_RETRY*10)
			{
				trytimes = 0;
				initState = _INIT_READ_FROM_LOCAL_HD;
			}
			*/
			debugmib.display.dataSrc=_SRC_PEER_SRV;
			initState = _INIT_READ_FROM_PEER;
		break;
		case _INIT_READ_FROM_PEER:  /* read from peer server */
			retval = ReadDataFromPeerSever();
			if(retval == 1)
			{
				data_source = _SRC_PEER_SRV;
				initState = _INIT_OVER;				
			}
			else if(retval == -1)
			{
				initState = _INIT_READ_FROM_LOCAL_HD;
			}
			retval = 0;
		break;
		case _INIT_READ_FROM_LOCAL_HD: /* read from local backup file */
			retval = LoadDataFromBackfile();
			if(retval<0)
			{
			//error = no local backup file 
				initState = _INIT_READ_FROM_OMC_HD;
			}
			else
			{ /* retval =0 not supported backup data */
				data_source = _SRC_LOCAL_HD;
				debugmib.display.dataSrc =_SRC_LOCAL_HD;
				debugmib.display.initProgress = 100;
				masterFlag = 1;
				initState = _INIT_OVER;
	  			debugmib.display.masterIP = LOCAL_IP;
			}
			retval = 0;
		break;
		case _INIT_READ_FROM_OMC_HD: /* read from omc backup file */
		//	   retval = ReadDataFromOMCServer();
			retval = -1;
			if(retval==1)
			{
				initState = _INIT_OVER;
				debugmib.display.dataSrc=_SRC_OMC_HD;
			}
			else if(retval==-1)
			{
				debugmib.display.dataSrc = _SRC_NO_SRC;
				initState = _INIT_UNNORMAL;
			}
			retval = 0;
		break;
		case _INIT_OVER:
			initState = _INIT_CHECK_VERSION;
			retval = 1;
			ramInitFlag = 1;
#ifdef OCS_WITH_CRM
			ocs_read_crm_base_prefix_file();
#endif
			
			//debugmib.display.sysState = _SYS_STATE_NORMAL;
		break;
		case _INIT_UNNORMAL:
			initState = _INIT_CHECK_VERSION;
			retval = 1;
			alarm_code[0] = 0x00;
			alarm_code[1] = 0x02; /* no data source */
			//debugmib.display.sysState = _SYS_STATE_SUSPEND;
			//debugmib.display.sysState = _SYS_STATE_NORMAL;
		break;
		default:
			initState = _INIT_CHECK_VERSION;
			retval = 0;
		break;
	}
	return retval;
}

void ppsRecordLog()
{
	int			i;
    FILE		*fpLog=NULL;

	fpLog = fopen("../log/pps_exit.log","w");
	if(fpLog !=NULL)
	{
		fprintf(fpLog,"Last function :	%s(%d)\n",
				smshm_ptr->func_log.func_name[(smshm_ptr->func_log.funcID+MAX_LOG_FUNC-1)%MAX_LOG_FUNC],
				(smshm_ptr->func_log.funcID+MAX_LOG_FUNC-1)%MAX_LOG_FUNC);
		for(i=0;i<MAX_LOG_FUNC;i++)
		fprintf(fpLog,"-> %s \n",smshm_ptr->func_log.func_name[i]);
		fclose(fpLog);
	}
}

int
pps_init(int max_user, int sysID,u_long localip,u_long peerip,char *sn,int no_sync_flag)
{
	static int	firstInit=0;
	int		retval=0,i;
	char		buf[128];
	FILE		*fpLog=NULL;

	if(!firstInit)
	{
		smshm_ptr = (_state_machine *) ShmInit(smshm_id, prog_name, 
				SMMP_SHM_KEY, PPS_FSM_RAMSIZE, 
				SMMP_SHM_PERM|IPC_CREAT);

		fpLog = fopen("../log/pps_trace.log","w");
		if(fpLog !=NULL)
		{
			fprintf(fpLog,"Last function :	%s(%d)\n",
					smshm_ptr->func_log.func_name[(smshm_ptr->func_log.funcID+MAX_LOG_FUNC-1)%MAX_LOG_FUNC],
					(smshm_ptr->func_log.funcID+MAX_LOG_FUNC-1)%MAX_LOG_FUNC);
			for(i=0;i<MAX_LOG_FUNC;i++)
				fprintf(fpLog,"-> %s \n",smshm_ptr->func_log.func_name[i]);
			fclose(fpLog);
		}
		memset(smshm_ptr, EMPTY, PPS_FSM_RAMSIZE);

		systemCapability = 10000;	
		if(max_user<=MSISDN_HEAD_NUM*UNIT_STORE_ACCOUNT && max_user>=1000)
		{
			systemCapability = max_user;
			msisdn_head_num = ceil((float )systemCapability/UNIT_STORE_ACCOUNT);
		}
		peer_server_ip = peerip;
		subSystemID = sysID;
		strcpy(serialNumber,sn);
		LOCAL_IP = GetLocalIP();
		SystemInit();

		sprintf(buf,"%08d",systemCapability);
		AsciiToBcd(debugmib.measurement.sys_capability,buf,8);
      		printf("sizoef(user) = %lu, sizeof(card) = %lu, sizeof(tariff) = %lu, total = %lu\r\n",
				sizeof(_prepaid_data), sizeof(_card_data), sizeof(_tariff_data), sizeof(_ram_data));
      		printf("sizoef(_state_machine) = %lu\r\n", sizeof(_state_machine));

#ifdef OCS_USE_REDIS_DB
			RedisInit((u32)localip, (u32)peerip);
#endif
					
		totalPeriodSyncPackets = 
	  		(sizeof(_tariff_data) + sizeof(_card_data)) / RAMDATA_PACK_SIZE;
		//printf("total: %d\n",totalPeriodSyncPackets);
	  
		debugmib.display.sysState = _SYS_STATE_INIT;
	}
	retval = InitRamData(no_sync_flag);
	ReadSyncMessageForInit();
	
	firstInit ++;
	if(firstInit %10 ==0)
		BeatTrans();
	if(retval)
	{	  
		PrivateRamInit();
		pps_exit(0);
		pps_real_update_file_init();
		debugmib.display.sysState = _SYS_STATE_NORMAL;
	}
	return retval;
}

static void 
PrepaidProc()
{
   	static int PPS_flag = 0x00;
	static int initLocalBackup = 0;
//	static int initRemoteBackup = 0;
	static int periodicBackup = 0;
	static int periodicCounter =0;
	
	int		   tmpLicense=0;
	
	if(PPS_flag) return ;
	PPS_flag = 0x01;
    	debug_messages=0;
	
    	gettimeofday(&tvnow,NULL);
    	getnowtime(time_now);

    	BeatTrans();
	cstaInstanceCheck();
	ppsCheckParameterAutoSaveFlag();
	
	TariffPlanProc();

	CheckLoadFile();
	ppsDebugRt();
	chargeID = masterFlag;
  
	if(GetMSISDNOfSSN(SSN_SCF,&ppsParam.ppsNumber[1])){
		ppsParam.ppsNumber[0] = 0x91;
	}
	if(GetMSISDNOfSSN(20,&ppsParam.smscNumber[1])){
		ppsParam.smscNumber[0] = 0x91;
	}
	if(GetMSISDNOfSSN(19,&ppsParam.esmeNumber[1])){
		ppsParam.esmeNumber[0] = 0x91;
	}
    
	if(debugmib.display.sysState==_SYS_STATE_NORMAL)
	{
		PeriodicChargeProc();	   
		smppMonitor();
		reportCreatedDaily();

         	SyncMessageProc();  //receive sync message

		srfActivityMonitor();		
		if(PERIODIC_ACTIONS>1) /* 1K/1S */
		{
			if(periodicCounter++==(PERIODIC_ACTIONS-1))
			{
				PeriodicSyncRamData();
				periodicCounter = 0;
			}
		}
		else
		{
			PeriodicSyncRamData();
		}

		if(initLocalBackup ==0){
			if(data_source !=_SRC_LOCAL_HD)
			{
				pps_exit(0);
				initLocalBackup = 0x01;
			}
		}
	   
		/*
		if(initRemoteBackup ==0)
		{
			if(data_source !=_SRC_OMC_HD && masterFlag ==1)
			{
				if(ppsBackupRamDataToOMCServer()){
					initRemoteBackup = 0x01;
				}
			}
			else
			{
				initRemoteBackup = 0x01;
			}
		}
		*/
		   
		if(subSystemID == 0)
		{
			if(time_now[3]==4 && time_now[4]==0 && 
				time_now[5]<5 && periodicBackup==0)
			{
				periodicBackup = 1;
			}
		}
		else
		{
			if(time_now[3]==4 && time_now[4]==10 && 
				time_now[5]<5 && periodicBackup==0)
			{
				periodicBackup = 1;
			}
		}	   
		if(periodicBackup==1){
			if(ppsBackupRamDataToFile()){
				if(masterFlag)
					periodicBackup = 0x02;
				else
					periodicBackup = 0x00;
			}	     
		}
		if((periodicBackup==2)){
			//if(ppsBackupRamDataToOMCServer())
			//{
			periodicBackup = 0x00;
			//}
		}	
		saveCommand();
		
		capMessageProc(); 	
		   
		CallProc();

		pps_rest_recv_proxy();		
	}
	else{
		alarm_code[0] = 0;
		alarm_code[1] = 2;
	}

	    
	tmpLicense = wxc2_get_license(LIC_PPS_USERS);
	//if(tmpLicense>ppsParam.serviceControl.licenseduser)
		ppsParam.serviceControl.licenseduser = tmpLicense;

	PPS_flag = 0x00;

}

void
pps_proc()
{
//  if(!stoprunning_flag)
	  PrepaidProc();	  
}

void 	SaveTariffPlan()
{
	FILE *fp;
  
	fp=fopen(PPS_TARIFF_DATA_TEMP,"w");
	if(fp !=NULL)
	{
		fwrite((void *)&ramshm_ptr->tariff_data,sizeof(_tariff_data),1,fp);
		fclose(fp);
		rename(PPS_TARIFF_DATA_TEMP,PPS_TARIFF_DATA_NAME);
	}
}

void	SaveRechargeCard()
{
	FILE *fp;
	void *ptr=(void *)ramshm_ptr;

	fp=fopen(PPS_RECAHRGE_CARD_BACKUP_TEMP,"w");
	if(fp !=NULL)
	{
		ptr = &ramshm_ptr->card_data;
		fwrite(ptr,sizeof(_card_data),1,fp);
		fclose(fp);
		rename(PPS_RECAHRGE_CARD_BACKUP_TEMP,PPS_RECHARGE_CARD_BACKUP_NAME);				
	}
}

int    SetIndexMessAlamFlag(int flag)
{	
	
	switch(flag)
	{
		case 0:
			debugmib.measurement.search_table_result[0] ++;			
		break;
		case 1:
			debugmib.measurement.index_alarm = 1;	
			alarm_code[0] = 0x00;
			alarm_code[1] = 0x02;	
			ppsSendHeartBeating();					
		break;
		case 2:
			debugmib.measurement.search_table_result[1] ++;
		default:	
		break;
	}	
	return 1;
}

void	SaveSubsData()
{
	FILE *fp;
	void *ptr=(void *)ramshm_ptr;
    
    printf("save data at %d.%d.%d\n",
    	time_now[3],time_now[4],time_now[5]);
    	
	fp=fopen(PPS_USER_BACKUP_TEMP,"w");
    	if(fp !=NULL)
	{
		ptr = &ramshm_ptr->prepaid_data;
	    	fwrite(ptr,sizeof(_prepaid_data),1,fp);
		fclose(fp);
		rename(PPS_USER_BACKUP_TEMP,PPS_USER_BACKUP_NAME);
		if(debugmib.measurement.index_alarm)
		{
			debugmib.measurement.index_alarm = 0;
			CreatePPSSubsIndexTable();
		}
		else if(debugmib.measurement.search_table_result[0]>0)
		{
			int	succeed_rate = 0;
			succeed_rate = debugmib.measurement.search_table_result[1] * 100 /
					debugmib.measurement.search_table_result[0];
					
			if(succeed_rate<80)
			{
				CreatePPSSubsIndexTable();
			}
		}
	}
}

int	SaveSubsDataPeriodic()
{
	FILE *fp;
	void *ptr=(void *)ramshm_ptr;
    
	fp=fopen(PPS_USER_BACKUP_TEMP,"w");
    if(fp !=NULL)
	{
		ptr = &ramshm_ptr->prepaid_data;
	    fwrite(ptr,sizeof(_prepaid_data),1,fp);
		fclose(fp);
		rename(PPS_USER_BACKUP_TEMP,PPS_USER_BACKUP_NAME);
		if(debugmib.measurement.index_alarm)
		{
			debugmib.measurement.index_alarm = 0;
			CreatePPSSubsIndexTable();
		}
		else if(debugmib.measurement.search_table_result[0]>0)
		{
			int	succeed_rate = 0;
			succeed_rate = debugmib.measurement.search_table_result[1] * 100 /
					debugmib.measurement.search_table_result[0];
					
			if(succeed_rate<80)
			{
				CreatePPSSubsIndexTable();
			}
		}
	}
	return 1;
}

int pps_exit(int flag)
{

	if(debugmib.display.sysState != _SYS_STATE_NORMAL)
	{
		return 0;
	}

	if(flag)
	{
		stoprunning_flag = 1;
		SaveDailyReport();
		ClearAllPortForStop();
		//SaveParam();
	}
	pps_real_update_file_close();
	SaveTariffPlan();
	SaveRechargeCard();
	SaveSubsData();
	return 1;
}

void ReloadPPSSubscriberFromHD()
{
	FILE	*fp=NULL;
	struct stat fileinfo;
	   
	fp=fopen(PPS_USER_BACKUP_NAME,"r");
    if(fp !=NULL)
    {
		stat(PPS_USER_BACKUP_NAME,&fileinfo);
		if(fileinfo.st_size == sizeof(_prepaid_data))
		{ //check length
			fread(&ramshm_ptr->prepaid_data,sizeof(_prepaid_data),1,fp);
		}
		fclose(fp);	
		CreatePPSSubsIndexTable();		
	}
}
