/* 
**
** Message send control entity.
**
*/
#include <pthread.h>
#include    <stddef.h>
#include    "../include/includes.h"
#include    "../include/message.h"
#include    "../include/ppsm.h"
#include    "../include/cdrme.h"
#include    "../include/ramdata.h"
#include    "../include/mfunc.h"
#include    "../include/config.h"
#include    "../include/param.h"
#include    "../include/precard.h"
#include	 "../include/mfunc.h"

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

#include    "../../../../plat/scf/src/include/scfmsg.h"
/*------------------------------------------------*/

extern _state_machine     *smshm_ptr;
extern _ram_data          *ramshm_ptr;
extern char               prog_name[12];
extern char				  alarm_code[2];
extern u_char			  version_id[3];
extern int				  subSystemID;
extern _pps_cdr_buffer    pps_cdr_buffer;

extern	PPSParamStruct	ppsParam;

extern int				  cdr_head_ptr , cdr_tail_ptr ;
extern u_long			  primary_data_server,
				          second_data_server;	
extern struct             timeval tvnow;

extern DWORD              PPS_OID_PREFIX[]; 
extern int				  logMsgFlag;
extern int		          systemCapability;
extern u_char			  sumOfParameter;
extern u_long			  peer_server_ip;
extern u_long			  LOCAL_IP;

extern u_short				debug_messages;
extern char			serialNumber[8];
extern char			masterFlag;
/*------------------------------------------------*/

int	GetSrfAddress(char *msisdn);

/*------------------------------------------------*/
extern int smppSendAccountInfo(char *caller, char *called,
			long balance, char *expire_date,
			long promotion,char *promotionExpireDate,
			int calltype0,
			char *call_date, 
			char *msisdn,
			u_char	flag);
extern int  StuffCapMessage();
extern int ppsDebugCapMsg();
extern int GetMaxCallDuration();
extern int GetAccountLastCallInfo(_account_info *ptr, _last_call_info *pInfo);
extern int UpdateAccountLastCDR();
extern int FindPPSTableIndex();
extern int UpdateAccountExpiration();
extern int ListAllPortStatus();
extern int sccp_GetSSNType ( BYTE ssn );
extern int CheckPromotionLatchFlag();
extern int cdr_submit(unsigned char ssn, unsigned short length, char *data);
extern const char * AsciiTimeYMDHMS(char *ptr, time_t time);
extern int ReplaceStr(char *sSrc, char *sMatchStr, char *sReplaceStr);
/*------------------------------------------------*/
void PutWarningMessage(u_short portid)
{
    _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;
   char		   causebuf[128];
   int			cause;

   PutLogFunID("PutWarningMessage");
   shmp += portid;   
   cause = shmp->process_info.tcos;
   switch(cause){
     case CALLER_CREDIT_OUT:
	   sprintf(causebuf,"Warning: Caller is out of balance");
	 break;
	 case ACTIVITY_MISSED:
	   sprintf(causebuf,"Warning: Activity message missed");
	 break;
	 case CALLED_CREDIT_OUT:
	   sprintf(causebuf,"Warning: Called is out of balance");
	 break;
	 case CALLER_STATUS_ERROR:
	   sprintf(causebuf,"Warning: Caller status is error");
	 break;
	 case CALLED_STATUS_ERROR:
	   sprintf(causebuf,"Warning: Called status is error");
	 break;
	 case CALLER_EXPIRIED:
	   sprintf(causebuf,"Warning: Caller is expiry");	   
     break;
     case CALLED_EXPIRIED:
       sprintf(causebuf,"Warning: Called is expiry");
	 break;
	 case TARIFF_NOT_SET:
	   sprintf(causebuf,"Warning: Tariff not set for destination %s",
	      shmp->charge_info.number);
	 break;
	 case capp_oDisconnect:
	   sprintf(causebuf,"Caller disconnect");
	 break;
	 case capp_tDisconnect:
	   sprintf(causebuf,"Called disconnect");
	 break;
	 case USER_BUSY:
	   sprintf(causebuf,"Called busy");
	 break;
	 case NO_ANSWER:
	   sprintf(causebuf,"No answer");
	 break;
	 case CALL_REJECTED:
	   sprintf(causebuf,"Call rejected");
	 break;
	 case NO_ROUTE:
	   sprintf(causebuf,"No route ");
	 break;
	 case UNALLOCATED_NUMBER:
	   sprintf(causebuf,"Caller is unallocated");
	 break;
	 case DESTINATION_OUT_OF_ORDER:
	   sprintf(causebuf,"Called is unallocated");
	 break;
	 case INVALID_MESSAGE:
		sprintf(causebuf,"Invalid message Received");
	 break;
	 case NETWORK_OUT_OF_ORDER:
	    sprintf(causebuf,"Unexpected message receive");
	 break;
	 case TIMER_OUT:
		sprintf(causebuf,"Waiting message time out");
	 break;
	 case SERVICE_NOT_AVAILABLE:
		sprintf(causebuf,"Called party is not OK!");
	 break;
	 default:
	   sprintf(causebuf,"Normal release: %d",cause);
	 break;
   }
	if(shmp->process_info.pre_warning)
	{
		if(shmp->process_info.voiceID == PRE_WARNING_LOW_BALANCE)
		{
			sprintf(causebuf," Pre-warning for low balance ");
		}
		else
		{
			sprintf(causebuf," Pre-warning for near expiry ");
		}
	}
    DebugMsg(debugmib.display.asciiOut,"\33[31m< %s > \33[0m",causebuf);
}

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

   PutLogFunID("ConvertTcosToCause");
   shmp += portid;   
   cause = shmp->process_info.tcos;

   switch(cause)
   {
	 case ACTIVITY_MISSED:
	 case NETWORK_OUT_OF_ORDER:
	 case TIMER_OUT:
		shmp->process_info.tcos = NETWORK_OUT_OF_ORDER;
	 break;
	 case CALLED_CREDIT_OUT:
	 case CALLED_STATUS_ERROR:
   	 case CALLED_EXPIRIED:
		shmp->process_info.tcos = CALL_REJECTED; //INCOMING_CALLS_BARRED;
	 break;
	 case CALLER_EXPIRIED:
	 	if(shmp->process_info.duration>1)
	 		shmp->process_info.tcos = NORMAL_CLEARING;
	 	else
	 		shmp->process_info.tcos = CALL_REJECTED;
	 break;
	 case CALLER_STATUS_ERROR:
        case CALLER_CREDIT_OUT: //ODB
	 case CALL_REJECTED: //UDB
		shmp->process_info.tcos = CALL_REJECTED;
	 break;
	 case TARIFF_NOT_SET:
	 case SERVICE_NOT_AVAILABLE:
	 	shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
	 break;
	 case capp_oDisconnect:
	 case capp_tDisconnect:
		shmp->process_info.tcos = NORMAL_CLEARING;
	 break;
	 case USER_BUSY:
	 	shmp->process_info.tcos = USER_BUSY;
	 break;
	 case NO_ANSWER:
	 	shmp->process_info.tcos = NO_ANSWER;
	 break;	 	
	 case NO_ROUTE:
	 	shmp->process_info.tcos = NO_ROUTE;
	 break;
	 case UNALLOCATED_NUMBER:
	 case DESTINATION_OUT_OF_ORDER:
	 	shmp->process_info.tcos = UNALLOCATED_NUMBER;
	 break;
	 case INVALID_MESSAGE:
	 	shmp->process_info.tcos = INVALID_MESSAGE;
	 break;
	 default:
		shmp->process_info.tcos = NORMAL_CLEARING;
	 break;
   }
}

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

   u_short     dlgid,invokeid=0;//,errflag=1;
   
   CAP_Message cap_message;
   CapArg      capArg;

   PutLogFunID("SendReleaseCall");

   shmp += portid;   
   AddPPSStatistics(MIBPPS_RELEASECALL,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
	
//   shmp->process_info.tcos = NORMAL_CLEARING;
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02)
	|| shmp->process_info.logMsisdn)
	{  
		DebugMsgDelimiter();
		PutWarningMessage(portid);
   }
#endif

   capArg.ocode = CAP_OC_ReleaseCall;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id   = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   capArg.msg_list.releaseCallArg.cause[0] = 0x02; //length

   ConvertTcosToCause(portid);

   capArg.msg_list.releaseCallArg.cause[1] = shmp->process_info.tcos>>8;
   capArg.msg_list.releaseCallArg.cause[2] = shmp->process_info.tcos;
   StuffCapMessage(capArg,&cap_message);
   WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

void SendPreWarningRequestBCSMEvent(u_short portid)
{
   int          invokeid=0,dlgid;
   CAP_Message  capmsg;
   CapArg       capArg;
   struct       CapRequestReportBCSMEvent *pStr;
  _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendPreWarningRequestBCSMEvent");

   shmp += portid;   
   shmp->process_info.answerWanted = 0x01;

   AddPPSStatistics(MIBPPS_REQUESTBCSM,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
 
   capArg.ocode = CAP_OC_RequestReportBCSMEvent;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   pStr = &capArg.msg_list.requestReportBCSMEventArg;
 
   pStr->bcsmEvents_num = 2;
   pStr->bcsmEvents[0].eventTypeBCSM = capp_oDisconnect;
   pStr->bcsmEvents[0].monitorMode   = capp_notifyAndContinue;
   pStr->bcsmEvents[0].optional_flag = 0x01;
   pStr->bcsmEvents[0].legID_ch = 0x00;
   pStr->bcsmEvents[0].legID.sendingSideID = 0x01;

   pStr->bcsmEvents[1].eventTypeBCSM = capp_oAbandon;
   pStr->bcsmEvents[1].monitorMode   = capp_notifyAndContinue;
   pStr->bcsmEvents[1].optional_flag = 0x01;
   pStr->bcsmEvents[1].legID_ch = 0x00;
   pStr->bcsmEvents[1].legID.sendingSideID = 0x01;

   switch(shmp->context_info.callType){
     	 case CT_MO_CALL:
	 case CT_MF_CALL:
	 break;
	 case CT_MT_CALL:
	    pStr->bcsmEvents[0].eventTypeBCSM = capp_tDisconnect;;
	    pStr->bcsmEvents[1].eventTypeBCSM = capp_tAbandon;
	 break;
	 default:
	 break;
   }

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

}

void SendRequestBCSMEvent_MO_Call(u_short portid)
{
   int          invokeid=0,dlgid, event_counter=0;
   CAP_Message  capmsg;
   CapArg       capArg;
   struct       CapRequestReportBCSMEvent *pStr;
  _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendRequestBCSMEvent_MO_Call");

   shmp += portid;   
   shmp->process_info.answerWanted = 0x01;

   AddPPSStatistics(MIBPPS_REQUESTBCSM,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
 
   capArg.ocode = CAP_OC_RequestReportBCSMEvent;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   pStr = &capArg.msg_list.requestReportBCSMEventArg;
   /*if shmp->context_info.callType == CT_MO_CALL,
   or all oEvents should be tEvents
   */
   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oDisconnect;
   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
   pStr->bcsmEvents[event_counter].optional_flag = 0x01;
   pStr->bcsmEvents[event_counter].legID_ch = 0x00;
   pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x01;
   event_counter ++;
   
   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oDisconnect;
   pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
   pStr->bcsmEvents[event_counter].optional_flag = 0x01;
   pStr->bcsmEvents[event_counter].legID_ch = 0x00;
   pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x02;
   event_counter ++;

   if(shmp->context_info.acn_ver>0)
   {
	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_routeSelectFailure;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x00;
	   event_counter++;
   
	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oCalledPartyBusy;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x00;
	   event_counter ++;

	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oAbandon;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x01;
	   pStr->bcsmEvents[event_counter].legID_ch = 0x00;
	   pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x01;
	   event_counter ++;

	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oNoAnswer;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x02;
	   pStr->bcsmEvents[event_counter].dPSpecificCriteria.applicationTimer = 40; 
	   event_counter ++;
   }
   
   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oAnswer;
   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
   pStr->bcsmEvents[event_counter].optional_flag = 0x00;
   event_counter ++;

   pStr->bcsmEvents_num = event_counter;
  
   StuffCapMessage(capArg, &capmsg);   
   
   WriteScfMsg(capmsg);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&capmsg,1);
		debug_messages ++;
	}
#endif
}

void
SendRequestBCSMEvent_MF_Call(u_short portid)
{
   int          invokeid=0,dlgid, event_counter=0;
   CAP_Message  capmsg;
   CapArg       capArg;
   struct       CapRequestReportBCSMEvent *pStr;
  _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendRequestBCSMEvent_MF_Call");

   shmp += portid;   
   shmp->process_info.answerWanted = 0x01;

   AddPPSStatistics(MIBPPS_REQUESTBCSM,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);
 
   capArg.ocode = CAP_OC_RequestReportBCSMEvent;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   pStr = &capArg.msg_list.requestReportBCSMEventArg;

	pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oDisconnect;
	pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
	pStr->bcsmEvents[event_counter].optional_flag = 0x01;
	pStr->bcsmEvents[event_counter].legID_ch = 0x00;
	pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x01;
       event_counter ++;

	if(1)
	{
		pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oDisconnect;
		pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
		pStr->bcsmEvents[event_counter].optional_flag = 0x01;
		pStr->bcsmEvents[event_counter].legID_ch = 0x00;
		pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x02;
		event_counter ++;
	}

	if(1)
	{
		if(shmp->context_info.acn_ver>0)
	   	{

			pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_routeSelectFailure;
			pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
			pStr->bcsmEvents[event_counter].optional_flag = 0x00;
			event_counter ++;

			pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oCalledPartyBusy;
			pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
			pStr->bcsmEvents[event_counter].optional_flag = 0x00;
			event_counter ++;

			pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oAbandon;
			pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
			pStr->bcsmEvents[event_counter].optional_flag = 0x01;
			pStr->bcsmEvents[event_counter].legID_ch = 0x00;
			pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x01;
			event_counter ++;

			pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oNoAnswer;
			pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
			pStr->bcsmEvents[event_counter].optional_flag = 0x02;
			pStr->bcsmEvents[event_counter].dPSpecificCriteria.applicationTimer = 30; 
			event_counter ++;
		}
	}
	pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_oAnswer;
	pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
	pStr->bcsmEvents[event_counter].optional_flag = 0x00;
	event_counter ++;

	pStr->bcsmEvents_num = event_counter;

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

void
SendRequestBCSMEvent_MT_Call(u_short portid)
{
   int          invokeid=0,dlgid, event_counter=0;
   CAP_Message  capmsg;
   CapArg       capArg;
   struct       CapRequestReportBCSMEvent *pStr;
  _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;

   PutLogFunID("SendRequestBCSMEvent_MT_Call");

   shmp += portid;   
   shmp->process_info.answerWanted = 0x01;

   AddPPSStatistics(MIBPPS_REQUESTBCSM,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);
 
   capArg.ocode = CAP_OC_RequestReportBCSMEvent;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   pStr = &capArg.msg_list.requestReportBCSMEventArg;

   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_tDisconnect;
   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
   pStr->bcsmEvents[event_counter].optional_flag = 0x01;
   pStr->bcsmEvents[event_counter].legID_ch = 0x00;
   pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x01;
   event_counter ++;

   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_tDisconnect;
   pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
   pStr->bcsmEvents[event_counter].optional_flag = 0x01;
   pStr->bcsmEvents[event_counter].legID_ch = 0x00;
   pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x02;
   event_counter ++;

   if(shmp->context_info.acn_ver>0)
   {

	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_tBusy;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x00;
	   event_counter++;
	 
	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_tAbandon;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x01;
	   pStr->bcsmEvents[event_counter].legID_ch = 0x00;
	   pStr->bcsmEvents[event_counter].legID.sendingSideID = 0x01;
	   event_counter ++;

	   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_tNoAnswer;
	   pStr->bcsmEvents[event_counter].monitorMode   = capp_interrupted;
	   pStr->bcsmEvents[event_counter].optional_flag = 0x02;
	   pStr->bcsmEvents[event_counter].dPSpecificCriteria.applicationTimer = 40; 
	   event_counter ++;
	/* Tnoanswer; */
   }
   
   pStr->bcsmEvents[event_counter].eventTypeBCSM = capp_tAnswer;
   pStr->bcsmEvents[event_counter].monitorMode   = capp_notifyAndContinue; 
   pStr->bcsmEvents[event_counter].optional_flag = 0x00;
   event_counter ++;

   pStr->bcsmEvents_num = event_counter;

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

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

//	PutLogFunID("SendRequestBCSMEvent");

   shmp += portid;   
    
   switch(shmp->context_info.callType){
     case CT_MO_CALL:
    case CT_MO_CC_CALL:
	   SendRequestBCSMEvent_MO_Call(portid);
     break;
	 case CT_MF_CALL:
	   SendRequestBCSMEvent_MF_Call(portid);
	 break;
	 case CT_MT_CALL:
	   SendRequestBCSMEvent_MT_Call(portid);
	 break;
	 default:
	 break;
   }
}


void
SendApplyCharging(u_short portid)
{
	int dlgid,  invokeid=0;
	CAP_Message cap_message;
	CapArg      capArg;
	CapApplyCharging  *pApplyCharging;

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

	PutLogFunID("SendApplyCharging");

	shmp += portid;   
	AddPPSStatistics(MIBPPS_APPLYCHARGING,shmp->process_info.dir);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_ApplyCharging;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
	capArg.version = shmp->context_info.acn_ver;
	pApplyCharging = &capArg.msg_list.applyChargingArg;
	pApplyCharging->partyToCharge = 0x01; //sendingSideID

	if(shmp->process_info.ro_if.adaptor_enabled == 0	)
	{
		int left_voice_bundle = 0;
		if (shmp->process_info.bundle_flag)
		{
			switch(shmp->context_info.callType)
			{
			case CT_MT_CALL:
				left_voice_bundle = pps_get_account_bundle_mt_voice(shmp);// MT left voice bundle
				break;
			case CT_MO_CALL:
			case CT_MF_CALL:
				left_voice_bundle = pps_get_account_bundle_mo_voice(shmp);// MO left voice bundle
			default:
				break;
			}
		}
		
		GetMaxCallDuration(shmp);
		
		shmp->process_info.maxCallDuration += left_voice_bundle;
	}
	else
		shmp->process_info.maxCallDuration = shmp->process_info.ro_if.granted_value;
	
	pApplyCharging->ACBCC.optional_flag = 0x00;

	if(shmp->process_info.maxCallDuration>=MAX_CALL_DURATION) // 16min.s 
	{
		pApplyCharging->ACBCC.maxCallPeriodDuration = 9000; 
	}
	else	
	{
		pApplyCharging->ACBCC.maxCallPeriodDuration = shmp->process_info.maxCallDuration * 10;

		if(shmp->process_info.ro_if.adaptor_enabled == 0	)
		{
			pApplyCharging->ACBCC.optional_flag = 0x01;
			//pApplyCharging->ACBCC.releaseIfdurationExceeded.tone = 0xff;
			 if(shmp->process_info.maxCallDuration<60 && shmp->process_info.duration<1200) 
	                        pApplyCharging->ACBCC.releaseIfdurationExceeded.tone = 0x00;
	                else
	                        pApplyCharging->ACBCC.releaseIfdurationExceeded.tone = 0xff;
			
			if(shmp->process_info.maxCallDuration<60 && shmp->process_info.duration<1200)
				pApplyCharging->ACBCC.releaseIfdurationExceeded.tone = 0x00;
			else
				pApplyCharging->ACBCC.releaseIfdurationExceeded.tone = 0xff;
		}
	}

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);

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

}

void
SendContinue(u_short portid)
{
   int dlgid, invokeid=0;
   CAP_Message cap_message;
   CapArg      capArg;
  _state_data  *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendContinue");

   shmp += portid;
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);
   AddPPSStatistics(MIBPPS_CONTINUE,shmp->process_info.dir);
   
   capArg.ocode = CAP_OC_Continue;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

   StuffCapMessage(capArg,&cap_message);
   WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif

}

void
SendActivityTest(u_short portid)
{
  _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;
   u_short       dlgid,invokeid=0;
   CAP_Message   cap_message;
   CapArg        capArg;

	PutLogFunID("SendActivityTest");

   shmp += portid;
   dlgid = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);
   AddPPSStatistics(MIBPPS_ACTIVITYS,shmp->process_info.dir);

   capArg.ocode = CAP_OC_ActivityTest;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   StuffCapMessage(capArg,&cap_message);
   WriteScfMsg(cap_message);

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}
/***********************************************************/
void SendConnectToResource(u_short portid)
{
   int			dlgid,invokeid=0,len;
   char			buf[128],msisdn[32];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapEstablishTemporaryConnection	*pTemporaryConnection;

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

	PutLogFunID("SendConnectToResource");

   shmp += portid;   
   AddPPSStatistics(MIBPPS_CONNECT_TO_RESOURCE,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid); //???
   
   capArg.ocode = CAP_OC_EstablishTemporaryConnection;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pTemporaryConnection = &capArg.msg_list.establishTemporaryConnectionArg;

	pTemporaryConnection->optional_flag = 0x03;

	GetSrfAddress(msisdn);
	len =  strlen(msisdn);
	pTemporaryConnection->assistingSSPIPRoutingAddress[0] = (len+1)/2 + 1; 
	if(len%2==1) //odd
	{
		pTemporaryConnection->assistingSSPIPRoutingAddress[1] = 0x20;
		len ++;
	}
	else //even
	{
		pTemporaryConnection->assistingSSPIPRoutingAddress[1] = 0x00;
	}

	ppsAsciiToBcdR(&pTemporaryConnection->assistingSSPIPRoutingAddress[2],
			msisdn,
			len);

	pTemporaryConnection->correlationID[0] = 3;
	pTemporaryConnection->correlationID[1] = 0x00;
	/* added 01-06 to identify plan 0/1 */
	if(subSystemID)
		sprintf(buf,"%04d",4000+portid);
	else
		sprintf(buf,"%04d",portid);
	
	ppsAsciiToBcdR(&pTemporaryConnection->correlationID[2],
					buf,
					4);

	ppsBcdToAsciiR(msisdn,&ppsParam.ppsNumber[1],20);
	StringCut(msisdn,'F');
	len = (strlen(msisdn)+1)/2;
	if(len>10) len = 10;
	pTemporaryConnection->scfID[0] = len + 1;
	if((ppsParam.ppsNumber[len] & 0xF0) == 0xF0) //odd
	{
		pTemporaryConnection->scfID[1] = 0x20;
	}
	else
	{
		pTemporaryConnection->scfID[1] = 0x00;
	}
	
	memcpy(&pTemporaryConnection->scfID[2],
			&ppsParam.ppsNumber[1],
			len);

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif

}

int sendConnectForCRDService(u_short portid)
{
   int			dlgid,len;
   char			msisdn[32];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapConnect	*pConnect;

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

	PutLogFunID("sendConnectForCRDService");

	shmp += portid;   
	AddPPSStatistics(MIBPPS_CONNECT_TO_RESOURCE,shmp->process_info.dir);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_Connect;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = 0;
   capArg.version = shmp->context_info.acn_ver;

	pConnect = &capArg.msg_list.connectArg;


	len =  strlen(shmp->process_info.tmpDigits);
	pConnect->destinationRoutingAddress[0] = (len+1)/2 + 2; 
	if(len%2==1) //odd
	{
		pConnect->destinationRoutingAddress[1] = 0x84;
		len ++;
		shmp->process_info.tmpDigits[len] = '0';
	}
	else //even
	{
		pConnect->destinationRoutingAddress[1] = 0x04;
	}
	len %= 60;
	pConnect->destinationRoutingAddress[2] = 0x10; 
	ppsAsciiToBcdR(&pConnect->destinationRoutingAddress[3],
					shmp->process_info.tmpDigits,
					len);
	pConnect->optional_flag = 0x02;

	if(shmp->process_info.callConnected == 1) //credit card recharge
	{
		len = strlen((char *)shmp->called_info.number);
		strcpy(msisdn, (char *)shmp->called_info.number);
	}
	else
	{
	//		DebugMsg(debugmib.display.asciiOut,"type:%d",
	//			shmp->process_info.chargeOther);

		if(shmp->process_info.chargeOther == 0)
		{
			len = 0;
			msisdn[0] = 0;
			pConnect->optional_flag = 0x00;
		}
		else if(shmp->process_info.chargeOther == 1)
		{
			len = shmp->process_info.tmpNumber[MAX_MSISDN_BLEN-1]%20;			
			ppsBcdToAsciiR(msisdn,shmp->process_info.tmpNumber,(len+1)/2*2);
			msisdn[len] = 0;
		}
		else //call forwarded
		{
			len = strlen((char *)shmp->caller_info.number);
			strcpy(msisdn, (char *)shmp->caller_info.number);
		}
	}

	pConnect->originalCalledPartyID[0] = (len+1)/2 + 2;
	if(len % 2 ==1)
	{
		pConnect->originalCalledPartyID[1] = 0x84;
		len ++;
	}
	else
	{
		pConnect->originalCalledPartyID[1] = 0x04;
	}
	if(len>16) len = 16;	
	pConnect->originalCalledPartyID[2] = 0x10;
	ppsAsciiToBcdR(&pConnect->originalCalledPartyID[3],
					msisdn,
					len);
/*
	len = strlen(shmp->caller_info.number);
	pConnect->redirectingPartyID[0] = (len+1)/2 + 2;
	if(len % 2 ==1)
	{
		pConnect->redirectingPartyID[1] = 0x84;
		len ++;
	}
	else
	{
		pConnect->redirectingPartyID[1] = 0x04;
	}
	pConnect->redirectingPartyID[2] = 0x00;
	ppsAsciiToBcdR(&pConnect->redirectingPartyID[3],
					shmp->caller_info.number,
					len);
*/
	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,"SendConnectForVMSService...");
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
	return 1;
}

int SendConnectForVMSService(u_short portid)
{
	int			dlgid,len;
	char		msisdn[32];
	CAP_Message	cap_message;
	CapArg		capArg;
	CapConnect	*pConnect;

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

	PutLogFunID("SendConnectForVMSService");

	shmp += portid;   
//	AddPPSStatistics(MIBPPS_CONNECT_TO_RESOURCE,shmp->process_info.dir);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_Connect;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = 0;
    	capArg.version = shmp->context_info.acn_ver;

	pConnect = &capArg.msg_list.connectArg;


	len =  strlen(shmp->process_info.tmpDigits)%MAX_ASCII_NUMBER_LEN;
	pConnect->destinationRoutingAddress[0] = (len+1)/2 + 2; 
	if(len%2==1) //odd
	{
		pConnect->destinationRoutingAddress[1] = 0x84;
		len ++;
		shmp->process_info.tmpDigits[len] = '0';
	}
	else //even
	{
		pConnect->destinationRoutingAddress[1] = 0x04;
	}

	pConnect->destinationRoutingAddress[2] = 0x10; 
	ppsAsciiToBcdR(&pConnect->destinationRoutingAddress[3],
					shmp->process_info.tmpDigits,
					len);
	pConnect->optional_flag = 0x02;

	if(shmp->context_info.callType == CT_MF_CALL)
	{
		len = strlen((char *)shmp->caller_info.number)%MAX_ASCII_NUMBER_LEN;
		strcpy(msisdn, (char *)shmp->caller_info.number);
	}
	else
	{
		len = 0;
		msisdn[0] = 0;
		pConnect->optional_flag = 0x00;
	}

	pConnect->originalCalledPartyID[0] = (len+1)/2 + 2;
	if(len % 2 ==1)
	{
		pConnect->originalCalledPartyID[1] = 0x84;
		len ++;
	}
	else
	{
		pConnect->originalCalledPartyID[1] = 0x04;
	}
	
	pConnect->originalCalledPartyID[2] = 0x10;
	ppsAsciiToBcdR(&pConnect->originalCalledPartyID[3],
					msisdn,
					len);

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,"\nSendConnectForVMSService");
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
	return 1;
}



void SendEstablishTemporaryConnection(u_short portid)
{
   int			dlgid,invokeid=0,len;
   char			buf[128],msisdn[128];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapEstablishTemporaryConnection	*pTemporaryConnection;

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

	PutLogFunID("SendEstablishTemporaryConnection");

   	shmp += portid;   
	AddPPSStatistics(MIBPPS_EST_TMP_CNT,shmp->process_info.dir);
	   
   	dlgid  = shmp->context_info.dialogue_id;
	//   invokeid = ApplyForInvokeID(dlgid); //???
	   
	capArg.ocode = CAP_OC_EstablishTemporaryConnection;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	pTemporaryConnection = &capArg.msg_list.establishTemporaryConnectionArg;

    if((ppsParam.serviceControl.cdrFlag & 0x10 )== 0)
	{
		pTemporaryConnection->optional_flag = 0x03;
		GetSrfAddress(msisdn);
		len =  strlen(msisdn);
		pTemporaryConnection->assistingSSPIPRoutingAddress[0] = (len+1)/2 + 3; 
		pTemporaryConnection->assistingSSPIPRoutingAddress[1] = 0x05; 
		//number qualifier
		if(len%2==1) //odd
		{
			pTemporaryConnection->assistingSSPIPRoutingAddress[2] = 0x84;
			len ++;
		}
		else //even
		{
			pTemporaryConnection->assistingSSPIPRoutingAddress[2] = 0x04;
		}
		pTemporaryConnection->assistingSSPIPRoutingAddress[3] = 0x13;

		ppsAsciiToBcdR(&pTemporaryConnection->assistingSSPIPRoutingAddress[4],
				msisdn,
				len);

		pTemporaryConnection->correlationID[0] = 3;
		pTemporaryConnection->correlationID[1] = 0x00;
		if(subSystemID)
			sprintf(buf,"%04d",4000+portid);
		else
			sprintf(buf,"%04d",portid);
		ppsAsciiToBcdR(&pTemporaryConnection->correlationID[2],
						buf,
						4);
		if(subSystemID == 0)
		{
			ppsBcdToAsciiR(msisdn,&ppsParam.ppsNumber[1],20);
			StringCut(msisdn,'F');
			len = (strlen(msisdn)+1)/2;
			if(len>18) len = 18;
		//	len = ppsParam.ppsNumber[0];
		}
		else //only for local SRF
		{
			pps_get_ucbc_number(msisdn);
			len = (strlen(msisdn)+1)/2;
			if(len>18) len = 18;
			strcat(msisdn,"FF");

		}
		
		pTemporaryConnection->scfID[0] = len + 1;

		if((ppsParam.ppsNumber[len] & 0xF0) == 0xF0) //odd
		{
			pTemporaryConnection->scfID[1] = 0x20;
		}
		else
		{
			pTemporaryConnection->scfID[1] = 0x00;
		}
		if(subSystemID == 0)
		{
			memcpy(&pTemporaryConnection->scfID[2],
				&ppsParam.ppsNumber[1],
				len);
		}
		else
		{
			ppsAsciiToBcdR(&pTemporaryConnection->scfID[2],msisdn, len*2);
		}
	}
	else
	{
		pTemporaryConnection->optional_flag = 0x00;
		GetSrfAddress(msisdn);

		if(subSystemID)
			sprintf(buf,"B%04dB",4000+portid);
		else
			sprintf(buf,"B%04dB",portid);
		
		strcat(msisdn,buf);
		
		ppsBcdToAsciiR(buf,&ppsParam.ppsNumber[1],20);
		StringCut(buf,'F');
		StringCut(buf,'E');
		len = strlen(buf);
		if(len>18) buf[18]=0;
		strcat(msisdn,buf);
		len =  strlen(msisdn);

		pTemporaryConnection->assistingSSPIPRoutingAddress[0] = (len+1)/2 + 3; 
		pTemporaryConnection->assistingSSPIPRoutingAddress[1] = 0x05; 
		//number qualifier
		if(len%2==1) //odd
		{
			pTemporaryConnection->assistingSSPIPRoutingAddress[2] = 0x84;
			len ++;
		}
		else //even
		{
			pTemporaryConnection->assistingSSPIPRoutingAddress[2] = 0x04;
		}
		pTemporaryConnection->assistingSSPIPRoutingAddress[3] = 0x13;

		ppsAsciiToBcdR(&pTemporaryConnection->assistingSSPIPRoutingAddress[4],
				msisdn,
				len);


	}

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

void SendSrfPlayAnnouncement(u_short portid)
{
   int			dlgid,invokeid=0;
   CAP_Message	cap_message;
   CapArg		capArg;
   CapPlayAnnouncement	*pPlayAnnouncement;
   int 			voiceID;
   
  _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendSrfPlayAnnouncement");

   shmp += portid;   
   
   AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid); //???
   
   capArg.ocode = CAP_OC_PlayAnnouncement;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;
	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x00;
	/* review need 2003-10-08,user prefered language type not taken account  */

	if(pps_get_adaptor_flag())
		voiceID = shmp->process_info.voiceID;
	else
		voiceID = GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536  + shmp->process_info.voiceID;

	pPlayAnnouncement->informationToSend.inbandInfo.messageID.elementaryMessageID = voiceID;
/*
	if(shmp->process_info.srfRelease)
	{
		pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 1;
		pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
		pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01; //1seconds
		pPlayAnnouncement->optional_flag = 0x03;
		pPlayAnnouncement->disconnectFromIPForbidden = 0; 
		//if disconnectFromIPForbidden=1 then DisconnectForwardConnect need, 
		else no DisconnectForwardConnect need
		//
		pPlayAnnouncement->requestAnnouncementComplete = 0;
	}else
	*/
	{
		pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 3;
		pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
		pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01; /* 1seconds */
		pPlayAnnouncement->optional_flag = 0x03;
		pPlayAnnouncement->disconnectFromIPForbidden = 1; 
		/* if disconnectFromIPForbidden=1 then DisconnectForwardConnect need, 
		lse no DisconnectForwardConnect need
		*/
		pPlayAnnouncement->requestAnnouncementComplete = 1;

	}

	StuffCapMessage(capArg,&cap_message);
	PutLogFunID("end of SendSrfPlayAnnouncement");

	WriteScfMsg(cap_message);
	PutLogFunID("end of 1 SendSrfPlayAnnouncement");

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

void SendDisconnectForwardConnection(u_short portid)
{
   int			dlgid,invokeid=0;
   CAP_Message	cap_message;
   CapArg		capArg;

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

	PutLogFunID("SendDisconnectForwardConnection");

   shmp += portid;   
   AddPPSStatistics(MIBPPS_DISCNT_FWD_CNT,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid); //???
   
   capArg.ocode = CAP_OC_DisconnectForwardConnection;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

void SendPromptAndCollectUserInfo(u_short portid)
{
   int			dlgid,invokeid=0;
   CAP_Message	cap_message;
   CapArg		capArg;
   CapPromptAndCollectUserInformation	*pPCUI;

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

   PutLogFunID("SendPromptAndCollectUserInfo");

   if(portid>=MAX_FSM_PROCESS)
   	return;
   
   shmp += portid;   
   AddPPSStatistics(MIBPPS_PCUI,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid); //???
   
   capArg.ocode = CAP_OC_PromptAndCollectUserInformation;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;

    pPCUI->collectedInfo.choice_id = 0x00;
	pPCUI->collectedInfo.collectedDigits.minimumNbOfDigits = 0;
	pPCUI->collectedInfo.collectedDigits.maximumNbOfDigits = 
		shmp->process_info.maxPCUInfoLen;
	pPCUI->collectedInfo.collectedDigits.optional_flag = 0x79;
	memcpy(pPCUI->collectedInfo.collectedDigits.endOfReplyDigit,
			shmp->process_info.endOfReplyDigit,3);
	pPCUI->collectedInfo.collectedDigits.firstDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.interDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.errorTreatment = repeatPrompt;
	//pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 1;

       if(shmp->process_info.voiceID == INPUT_MOBILE_IMEI 
            || shmp->process_info.voiceID == INPUT_MOBILE_IMEI_AGAIN)
        {
            pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 0;
        }
        else
        {
            pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 1;
        }

	pPCUI->optional_flag = 0x03;
	pPCUI->disconnectFromIPForbidden = 0x01;
	pPCUI->informationToSend.choice_id = 0x00;
	pPCUI->informationToSend.inbandInfo.messageID.choice_id = 0x00;
		/* review need 2003-10-08,user prefered language type not taken account 
		*/
	if(pps_get_adaptor_flag())
		pPCUI->informationToSend.inbandInfo.messageID.elementaryMessageID = shmp->process_info.voiceID;
	else
		pPCUI->informationToSend.inbandInfo.messageID.elementaryMessageID =
			GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 
				+ shmp->process_info.voiceID;

	pPCUI->informationToSend.inbandInfo.optional_flag = 0x07;
	pPCUI->informationToSend.inbandInfo.numberOfRepetitions = 0x03;
	pPCUI->informationToSend.inbandInfo.duration = 0x00;
	pPCUI->informationToSend.inbandInfo.interval = 0x08;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

int SendAccountInfoPromptToSrf(u_short portid,u_char isOnlyBalance,u_char isLastCallAttatched)
{
	int						balance,centbalance,promotion=0,hth_b,th_b,h_b,b_b;
	char					expire_date[20]="",promo_expire_date[20]="",buf[BUFSIZE]="";
	int						resolution=100,last_call_flag=0;
	int						len;
	_last_call_info			callInfo;
	_state_data 			*shmp;
	long					expiry_date = 0;
	int					voice_id = 0;	
	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	int						index=0;
	u8						minusFlag=0;
	
	PutLogFunID("SendAccountInfoPromptToSrf");

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

	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);

	if(pps_get_adaptor_flag())
	{
		balance = shmp->process_info.rest_if.balance;
		expiry_date = shmp->process_info.rest_if.mo_expiry_date;
		promotion = 0;
		voice_id = 0;
	}
	else
	{
		balance = GetBalanceWithOutPromotion(shmp->caller_info.head,shmp->caller_info.tail);
		promotion = GetPromotion(&shmp->caller_info);
		expiry_date = GetExpiration(&shmp->caller_info);
		AsciiTime(promo_expire_date,GetPromotionExpiration(&shmp->caller_info));

		voice_id = GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail);
	}
	
			
	if(balance < 0) 
	{
		minusFlag = 1;
		balance = abs(balance);
	}
	
	AsciiTime(expire_date, expiry_date);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	resolution = getSystemCurrencyResolution();
	
	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	index=0;

	/******************balance sign symbol ********************* */
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 5;
	pMID->variableMessage.variableParts.variablePart[index].signSymbol = minusFlag;	
	/****************** balance sign symbol ********************* */
	
	/****************** account balance********************* */
	index++;
	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 4;
	sprintf(buf,"%02d",hth_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[3],
			buf,2);	

	if(isOnlyBalance == TRUE)
	{
		pMID->variableMessage.variableParts.num = 2;
		pMID->variableMessage.elementaryMessageID = voice_id*65536 +
								ONLY_BALANCE_IS;		
	}
	else
	{
	    /* account expiry day */
		index++;
	 	pMID->variableMessage.variableParts.variablePart[index].choice_id = 3;
		ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[0],
				expire_date,4);
		ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[2],
				&expire_date[4],2);
		ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[3],
				&expire_date[6],2);	
		/****************** account balance********************* */

		/****************** promotion	********************* */		
		if(promotion > 0)
		{
			index++;
			centbalance = (promotion % resolution);
			promotion	= (promotion / resolution);
		    hth_b		= (promotion / 10000)%100;
		    th_b		= (promotion / 1000)%10;
			h_b			= (promotion / 100)%10;
			b_b			= (promotion % 100); 
			pMID->variableMessage.variableParts.variablePart[index].choice_id = 4;
			sprintf(buf,"%02d",hth_b);

			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[0],
					buf,2);
			sprintf(buf,"%d%d",th_b,h_b);

			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[1],
					buf,2);
			sprintf(buf,"%02d",b_b);

			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[2],
					buf,2);
			sprintf(buf,"%02d",centbalance);

			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[3],
					buf,2);	
					
		    /* account expiry day */
			index++;
		 	pMID->variableMessage.variableParts.variablePart[index].choice_id = 3;
			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[0],
					promo_expire_date,4);
			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[2],
					&promo_expire_date[4],2);
			ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[3],
					&promo_expire_date[6],2);	
			pMID->variableMessage.elementaryMessageID = voice_id*65536 +
								INQUIRY_WITH_PROMOTION;				
			pMID->variableMessage.variableParts.num = 5;
		}
		/****************** promotion********************* */
		else
		{
			pMID->variableMessage.elementaryMessageID = voice_id*65536 +
									ACCOUNT_BALANCE_IS;
		   
			if(isLastCallAttatched == TRUE && GetAccountLastCallInfo(&shmp->caller_info,&callInfo))
			{
				pMID->variableMessage.variableParts.num = 6;
				last_call_flag = 1;
			}
			else
			{
				pMID->variableMessage.variableParts.num = 3;
			}

			if(last_call_flag)
			{
				index++;
				if(callInfo.last_call_type == LST_MT_CALL)
				pMID->variableMessage.elementaryMessageID = voice_id*65536 +
									INQUIRY_MESSAGE_FROM;

				AsciiTime(expire_date,callInfo.last_call_date);
				pMID->variableMessage.variableParts.variablePart[index].choice_id = 3;
				ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[0],
					expire_date,4);
				ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[2],
					&expire_date[4],2);
				ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[3],
					&expire_date[6],2);	

				index++;
				pMID->variableMessage.variableParts.variablePart[index].choice_id = 2;			
				ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].time[0],
					&expire_date[8],2);
				ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].time[1],
					&expire_date[10],2);


				len = callInfo.last_call_number[MAX_MSISDN_BLEN-1];
				if(len>(MAX_MSISDN_BLEN-1)*2) 
					len = (MAX_MSISDN_BLEN - 1 )*2;

				index++;
				pMID->variableMessage.variableParts.variablePart[index].choice_id = 1;
			
				pMID->variableMessage.variableParts.variablePart[index].number[0] = (len+1)/2+1;
				if(len%2==0)
				{
					pMID->variableMessage.variableParts.variablePart[index].number[1] = 0x04;
					memcpy(&pMID->variableMessage.variableParts.variablePart[index].number[2],
							callInfo.last_call_number,
							(len+1)/2);

				}
				else
				{
					pMID->variableMessage.variableParts.variablePart[index].number[1] = 0x24;
					memcpy(&pMID->variableMessage.variableParts.variablePart[index].number[2],
							callInfo.last_call_number,
							(len+1)/2);
					pMID->variableMessage.variableParts.variablePart[index].number[2+(len+1)/2] &=0x0F;
				}

			}	
		}
	}
	
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x03;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


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

int SendRestAccountInfoPromptToSrf(u_short portid)
{
	int						balance,centbalance,/*promotion=0,*/hth_b,th_b,h_b,b_b;
	char						expire_date[20]="",buf[BUFSIZE]="";
	int						resolution=100;
	long						expiry_date;
	_state_data 				*shmp;

	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	int						index=0;
	u8						minusFlag=0;
	
	PutLogFunID("SendRestAccountInfoPromptToSrf");

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

	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);

	balance = shmp->process_info.rest_if.balance;
	expiry_date = shmp->process_info.rest_if.mo_expiry_date;
		
	if(balance < 0) 
	{
		minusFlag = 1;
		balance = abs(balance);
	}
	
	AsciiTime(expire_date,expiry_date);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    	capArg.version = shmp->context_info.acn_ver;

	resolution = getSystemCurrencyResolution();
	
	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	index=0;

	/******************balance sign symbol ********************* */
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 5;
	pMID->variableMessage.variableParts.variablePart[index].signSymbol = minusFlag;	
	/****************** balance sign symbol ********************* */
	
	/****************** account balance********************* */
	index++;
	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    	hth_b		= (balance / 10000)%100;
    	th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 4;
	sprintf(buf,"%02d",hth_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[3],
			buf,2);	

	{
	    /* account expiry day */
		index++;
	 	pMID->variableMessage.variableParts.variablePart[index].choice_id = 3;
		ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[0],
				expire_date,4);
		ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[2],
				&expire_date[4],2);
		ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[3],
				&expire_date[6],2);	
		/****************** account balance********************* */

		pMID->variableMessage.elementaryMessageID = ACCOUNT_BALANCE_IS;
		   
		pMID->variableMessage.variableParts.num = index+1;
	}
	
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


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

void SendAccountBalanceBySrf(u_short portid)
{
	int			balance,centbalance,hth_b,th_b,h_b,b_b;
	char		buf[BUFSIZE]="";
	int			resolution=1000;
	_state_data *shmp;

	int			dlgid,invokeid=0;
	CAP_Message	cap_message;
	CapArg		capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	
	
	PutLogFunID("SendAccountBalanceBySrf");

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

	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);

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

	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	resolution = getSystemCurrencyResolution();
	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 
	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	/* account balance */
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	pMID->variableMessage.elementaryMessageID = 
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 +
							ONLY_BALANCE_IS;
   
	pMID->variableMessage.variableParts.num = 1;

	pMID->variableMessage.variableParts.variablePart[0].choice_id = 4;
	sprintf(buf,"%02d",hth_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[0].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[0].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[0].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[0].price[3],
			buf,2);	
			
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


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

int	SendRechargeInfoPromptToSrf(u_short portid)
{
	int						balance,centbalance,hth_b,th_b,h_b,b_b;
	char					expire_date[20]="",buf[BUFSIZE]="";
	int						resolution = 100;
	_state_data 			*shmp;

   int						dlgid,invokeid=0;
   CAP_Message				cap_message;
   CapArg					capArg;
   CapPlayAnnouncement		*pPlayAnnouncement;
   CapMessageID				*pMID;
	u_char					minusFlag=0,index=0;
	
	_account_info			tmpInfo;

	PutLogFunID("SendRechargeInfoPromptToSrf");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
   AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
   
   capArg.ocode = CAP_OC_PlayAnnouncement;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

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

	balance = GetAccountBalance(shmp->caller_info.head,
									shmp->caller_info.tail);
	if(balance < 0) 
	{
		minusFlag = 1;
		balance = abs(balance);
	}	
	
	AsciiTime(expire_date,GetExpiration(&shmp->caller_info));

	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	//recharge face value
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;
	pMID->variableMessage.elementaryMessageID =
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 +
			RECHARGE_SUCCESS;
	
	pMID->variableMessage.variableParts.num = 3;
	/******************balance sign symbol ********************* */
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 5;
	pMID->variableMessage.variableParts.variablePart[index].signSymbol = minusFlag;	
	/****************** balance sign symbol ********************* */

	index++;
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 4;
	sprintf(buf,"%02d",hth_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[3],
			buf,2);	

    /* account balance */
	/*
   	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 

	pMID->variableMessage.variableParts.variablePart[1].choice_id = 4;
	sprintf(buf,"%02d",hth_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[1].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[1].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[1].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[1].price[3],
			buf,2);	
		*/
    /* account expiry day */
	index++;
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 3;
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[0],
			expire_date,4);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[2],
			&expire_date[4],2);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[3],
			&expire_date[6],2);	

	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);
	if(shmp->process_info.rechargeByOther)
	{
		memcpy(&shmp->caller_info,&tmpInfo,sizeof(_account_info));
	}

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

int	SendRestRechargeInfoPromptToSrf(u_short portid)
{
	int						balance,centbalance,hth_b,th_b,h_b,b_b;
	char						expire_date[20]="",buf[BUFSIZE]="";
	int						resolution = 100;
	_state_data 			*shmp;

   int						dlgid,invokeid=0;
   CAP_Message				cap_message;
   CapArg					capArg;
   CapPlayAnnouncement		*pPlayAnnouncement;
   CapMessageID				*pMID;
	u_char					minusFlag=0,index=0;
	
	_account_info			tmpInfo;

	PutLogFunID("SendRestRechargeInfoPromptToSrf");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
   AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
   
   capArg.ocode = CAP_OC_PlayAnnouncement;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

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

	balance = shmp->process_info.rest_if.balance;
	if(balance < 0) 
	{
		minusFlag = 1;
		balance = abs(balance);
	}	
	
	AsciiTime(expire_date,shmp->process_info.rest_if.mo_expiry_date );

	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	//recharge face value
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;
	pMID->variableMessage.elementaryMessageID = RECHARGE_SUCCESS;
	
	pMID->variableMessage.variableParts.num = 3;
	/******************balance sign symbol ********************* */
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 5;
	pMID->variableMessage.variableParts.variablePart[index].signSymbol = minusFlag;	
	/****************** balance sign symbol ********************* */

	index++;
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 4;
	sprintf(buf,"%02d",hth_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].price[3],
			buf,2);	

    /* account expiry day */
	index++;
	pMID->variableMessage.variableParts.variablePart[index].choice_id = 3;
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[0],
			expire_date,4);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[2],
			&expire_date[4],2);
	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[index].date[3],
			&expire_date[6],2);	

	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);

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

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


void	SendPromptCollectedRechargedUserInfo(u_short portid)
{
   int			dlgid,invokeid=0,len;
   char			buf[BUFSIZE];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapPromptAndCollectUserInformation	*pPCUI;
   CapMessageID							*pMID;

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

	PutLogFunID("SendPromptCollectedRechargedUserInfo");

   shmp += portid;   
   AddPPSStatistics(MIBPPS_PCUI,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
   
   capArg.ocode = CAP_OC_PromptAndCollectUserInformation;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;

    pPCUI->collectedInfo.choice_id = 0x00;
	pPCUI->collectedInfo.collectedDigits.minimumNbOfDigits = 1;
	pPCUI->collectedInfo.collectedDigits.maximumNbOfDigits = 
		shmp->process_info.maxPCUInfoLen;
	pPCUI->collectedInfo.collectedDigits.optional_flag = 0x79;
	memcpy(pPCUI->collectedInfo.collectedDigits.endOfReplyDigit,
			shmp->process_info.endOfReplyDigit,3);
	pPCUI->collectedInfo.collectedDigits.firstDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.interDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.errorTreatment = repeatPrompt;
	pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 1;

	pPCUI->optional_flag = 0x03;
	pPCUI->disconnectFromIPForbidden = 0x01;
	pPCUI->informationToSend.choice_id = 0x00;
	pPCUI->informationToSend.inbandInfo.messageID.choice_id = 0x03;

	pMID = &pPCUI->informationToSend.inbandInfo.messageID;
	if(pps_get_adaptor_flag())
		pMID->variableMessage.elementaryMessageID = shmp->process_info.voiceID;
	else
		pMID->variableMessage.elementaryMessageID =
			GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 +
			+shmp->process_info.voiceID;
	pMID->variableMessage.variableParts.num = 1;
	pMID->variableMessage.variableParts.variablePart[0].choice_id = 1;
	
	ppsBcdToAsciiR(buf,shmp->cdr_info.msisdn,16);
	StringCut(buf,'F');
	len = strlen(buf);
	if(len>20) len = 20;

	pMID->variableMessage.variableParts.variablePart[0].number[0] = (len+1)/2+1;
	if(len%2==0)
	{
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x04;
		memcpy(&pMID->variableMessage.variableParts.variablePart[0].number[2],
				shmp->cdr_info.msisdn,
				(len+1)/2);

	}
	else
	{
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x24;
		memcpy(&pMID->variableMessage.variableParts.variablePart[0].number[2],
				shmp->cdr_info.msisdn,
				(len+1)/2);
		pMID->variableMessage.variableParts.variablePart[0].number[2+(len+1)/2] &=0x0F;
	}

	pPCUI->informationToSend.inbandInfo.optional_flag = 0x07;
	pPCUI->informationToSend.inbandInfo.numberOfRepetitions = 0x02;
	pPCUI->informationToSend.inbandInfo.duration = 0x00;
	pPCUI->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);

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

}

void SendFavPromptAndCollectUserInfo(u_short portid)
{
   int			dlgid,invokeid=0,len;
   u_char		u_msisdn[32];
   char			buf[BUFSIZE];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapPromptAndCollectUserInformation	*pPCUI;
   CapMessageID							*pMID;

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

	PutLogFunID("SendFavPromptAndCollectUserInfo");

	shmp += portid;   
	AddPPSStatistics(MIBPPS_PCUI,shmp->process_info.dir);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PromptAndCollectUserInformation;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;

    pPCUI->collectedInfo.choice_id = 0x00;
	pPCUI->collectedInfo.collectedDigits.minimumNbOfDigits = 1;
	pPCUI->collectedInfo.collectedDigits.maximumNbOfDigits = 
		shmp->process_info.maxPCUInfoLen;
	pPCUI->collectedInfo.collectedDigits.optional_flag = 0x79;
	memcpy(pPCUI->collectedInfo.collectedDigits.endOfReplyDigit,
			shmp->process_info.endOfReplyDigit,3);
	pPCUI->collectedInfo.collectedDigits.firstDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.interDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.errorTreatment = repeatPrompt;
	pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 1;

	pPCUI->optional_flag = 0x03;
	pPCUI->disconnectFromIPForbidden = 0x01;
	pPCUI->informationToSend.choice_id = 0x00;
	pPCUI->informationToSend.inbandInfo.messageID.choice_id = 0x03;

	pMID = &pPCUI->informationToSend.inbandInfo.messageID;
	pMID->variableMessage.elementaryMessageID =
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 +
			+shmp->process_info.voiceID;
	pMID->variableMessage.variableParts.num = 1;


	pMID->variableMessage.variableParts.variablePart[0].choice_id = 1;
	strcpy(buf,shmp->process_info.tmpDigits);
	len = strlen(buf);
	if(len>18) len = 18;
	ppsAsciiToBcdR(u_msisdn,buf,((len+1)/2)*2);
	pMID->variableMessage.variableParts.variablePart[0].number[0] = (len+1)/2+1;
	if(len%2==0)
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x04;
	else
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x24;
	memcpy(&pMID->variableMessage.variableParts.variablePart[0].number[2],
			u_msisdn,
			(len+1)/2);

	/*
	else
	{
		pMID->variableMessage.variableParts.variablePart[0].choice_id = 0;
		pMID->variableMessage.variableParts.variablePart[0].integer = counter;
	}
	*/
	pPCUI->informationToSend.inbandInfo.optional_flag = 0x07;
	pPCUI->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPCUI->informationToSend.inbandInfo.duration = 0x00;
	pPCUI->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


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

int SendScfUAbort(u_short portid)
{
	int           /*dlgid,*/msglen;
	CAP_Message  capmsg, *pcap_message;
	_state_data   *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendUAbort");

   shmp += portid;   
   //dlgid  = shmp->context_info.dialogue_id;

   pcap_message = &capmsg;
   memset(pcap_message,0,sizeof(CAP_Message));
   pcap_message->msgServiceCode  = CAP_MSG_TYPE;
   pcap_message->dialogue_id[0]  = shmp->context_info.dialogue_id>>8;
   pcap_message->dialogue_id[1]  = shmp->context_info.dialogue_id;
   pcap_message->dialogue_id[2]  = 0x00;
   pcap_message->port_id[0]      = portid>>8;
   pcap_message->port_id[1]      = portid;
   pcap_message->port_id[2]      = 0x00;
   pcap_message->msgOperaCode    = CAP_O_UABORT;
   pcap_message->msgOperaType	 = 0x01; //REQUEST;
   pcap_message->msgContent[0]   = shmp->process_info.u_error; 
   pcap_message->msgContent[1]   = 0x00;
   pcap_message->msgContent[2]   = 0x00;
   msglen  = 12;

   pcap_message->msgLength[0] = msglen>>8;
   pcap_message->msgLength[1] = msglen;
   
   WriteScfMsg(capmsg);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&capmsg,1);
		debug_messages ++;
	}
#endif
   return 1;
}

int SendScfUError(u_short portid)
{
	int           /*dlgid,*/msglen;
	CAP_Message  capmsg, *pcap_message;
	_state_data   *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendUError");

   shmp += portid;   
   //dlgid  = shmp->context_info.dialogue_id;

   pcap_message = &capmsg;
   memset(pcap_message,0,sizeof(CAP_Message));
   pcap_message->msgServiceCode  = CAP_MSG_TYPE;
   pcap_message->dialogue_id[0]  = shmp->context_info.dialogue_id>>8;
   pcap_message->dialogue_id[1]  = shmp->context_info.dialogue_id;
   pcap_message->dialogue_id[2]  = 0x00;
   pcap_message->port_id[0]      = portid>>8;
   pcap_message->port_id[1]      = portid;
   pcap_message->port_id[2]      = 0x00;
   pcap_message->msgOperaCode    = shmp->process_info.oc;
   pcap_message->msgOperaType	 = 0x03; //RESPONSE;
   pcap_message->msgContent[0]   = 0; //invokeid
   pcap_message->msgContent[1]   = 0x01; //optional tag
   pcap_message->msgContent[2]   = 0x02; //u_error tag
   pcap_message->msgContent[3]	 = 0x01;
   pcap_message->msgContent[4]	 = shmp->process_info.u_error;
   pcap_message->msgContent[5]	 = 0x10;
   pcap_message->msgContent[6]	 = 0x00;
   pcap_message->msgContent[7]	 = 0x00;
   msglen  = 17;

   pcap_message->msgLength[0] = msglen>>8;
   pcap_message->msgLength[1] = msglen;
   
   WriteScfMsg(capmsg);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&capmsg,1);
		debug_messages ++;
	}
#endif
   return 1;
}

int SendScfTcEND(u_short portid)
{
  int           /*dlgid,*/msglen;
   CAP_Message  capmsg, *pcap_message;
  _state_data   *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendScfTcEND");

   shmp += portid;   
   shmp->process_info.answerWanted = 0x01;

   
   //dlgid  = shmp->context_info.dialogue_id;

   pcap_message = &capmsg;
   memset(pcap_message,0,sizeof(CAP_Message));
   pcap_message->msgServiceCode  = CAP_MSG_TYPE;
   pcap_message->dialogue_id[0]  = shmp->context_info.dialogue_id>>8;
   pcap_message->dialogue_id[1]  = shmp->context_info.dialogue_id;
   pcap_message->dialogue_id[2]  = 0x00;
   pcap_message->port_id[0]      = portid>>8;
   pcap_message->port_id[1]      = portid;
   pcap_message->port_id[2]      = 0x00;
   pcap_message->msgOperaCode    = CAP_O_END;
   pcap_message->msgOperaType	 = 0x01; //REQUEST;
   pcap_message->msgContent[0]   = 0x01; //release method
   pcap_message->msgContent[1]   = 0x00; //optional tag
   pcap_message->msgContent[2]   = 0x00; //end tag

   msglen  = 12;

   pcap_message->msgLength[0] = msglen>>8;
   pcap_message->msgLength[1] = msglen;
   
   WriteScfMsg(capmsg);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&capmsg,1);
		debug_messages ++;
	}
#endif
   return 1;
}

/***********************************************************/
void
SendRequestSMSEvents(u_short portid)
{
  int          invokeid=0,dlgid;
   CAP_Message  capmsg;
   CapArg       capArg;
   struct       CapRequestReportSMSEvent *pStr;
  _state_data   *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendRequestSMSEvents");

   shmp += portid;   
   shmp->process_info.answerWanted = 0x01;

   AddPPSStatistics(MIBPPS_REQUEST_SMS,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);
 
   capArg.ocode = CAP_OC_RequestReportSMSEvent;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;
   pStr = &capArg.msg_list.requestReportSMSEventArg;
   pStr->sMSEvents_num = 2;
   pStr->sMSEvents[0].eventTypeSMS  = capp_osmsFailure;
   pStr->sMSEvents[0].monitorMode   = capp_interrupted;

   pStr->sMSEvents[1].eventTypeSMS  = capp_osmsSubmitted;
   pStr->sMSEvents[1].monitorMode   = capp_interrupted;
   
   StuffCapMessage(capArg, &capmsg);   
   
   WriteScfMsg(capmsg);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&capmsg,1);
		debug_messages ++;
	}
#endif
}

void
SendContinueSMS(u_short portid)
{
   int dlgid, invokeid=0;
   CAP_Message cap_message;
   CapArg      capArg;
  _state_data  *shmp=(_state_data *) &smshm_ptr->state_data;

	PutLogFunID("SendContinueSMS");

   AddPPSStatistics(MIBPPS_CONTINUE_SMS,shmp->process_info.dir);

   shmp += portid;
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);
   
   capArg.ocode = CAP_OC_ContinueSMS;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

   StuffCapMessage(capArg,&cap_message);
   WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

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

   int         dlgid,invokeid=0;
   CAP_Message cap_message;
   CapArg      capArg;
   u_char      cause=111;

	PutLogFunID("SendReleaseSMS");

   shmp += portid;   
   AddPPSStatistics(MIBPPS_RELEASE_SMS,shmp->process_info.dir);
   
   dlgid  = shmp->context_info.dialogue_id;
//   invokeid = ApplyForInvokeID(dlgid);

   capArg.ocode = CAP_OC_ReleaseSMS;
   capArg.message_flag = REQUEST;
   capArg.port_id = portid;
   capArg.dialogue_id = dlgid;
   capArg.invoke_id   = invokeid;
   capArg.msg_list.releaseSMSArg.cause = cause; 
   capArg.version = shmp->context_info.acn_ver;

   StuffCapMessage(capArg,&cap_message);
   WriteScfMsg(cap_message);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

/***************************************************/
void	stuff_sccp_address(SCCP_ADDR *pAddr,char *msisdn, u_char ssn,u_char translate_type)
{
	int	len;
	u_char tt=0;
	char gtt[32];

	pAddr->ip = 0;
	pAddr->DPC = 0;
	pAddr->RI = 0;
	pAddr->NetID = 4;
	pAddr->SSN = ssn;
	pAddr->GTI = 4;
	
	tt = sccp_GetSSNType(ssn);
	
	pAddr->NAI = 4;
	if(tt == 0)
	{
		pAddr->TT = translate_type;
		pAddr->NP = 1;
	}
	else
	{
		pAddr->TT = 14;
		pAddr->NP = 0;
		pAddr->GTI= 2;
	}
	
	len	= strlen(msisdn);
	if(len>20) len= 20;
	pAddr->len = len;
	if(len %2==1)
	{
		 strcpy(gtt,msisdn);
		 strcat(gtt,"F");	
		 len ++;
		ppsAsciiToBcdR(pAddr->GTAI,gtt,len);
	}else
		ppsAsciiToBcdR(pAddr->GTAI,msisdn,len);
}

void	srfActivityMonitor()
{
	static	u_char	srf_state[MaxSrfNumberItem]={0,0};
	static	u_long	srf_dlgid[MaxSrfNumberItem]={0,0};
	static	u_long	srf_timer[MaxSrfNumberItem]={0,0};
	CAP_Message		capmsg;
	SCCP_ADDR		sccpAddr;
	char			msisdn[32]="";
	int				i,sendEnd = 0, test_timer=10;

	for(i=0;i<MaxSrfNumberItem;i++)
	{
		switch(srf_state[i])
		{
			case 0:
				if((ppsParam.ppsTables.srfNumber[i].number[0]==0))
				{
					 ppsParam.ppsTables.srfNumber[i].reachable = 0;
					 break;
				}
				srf_dlgid[i] = cap_get_dialogueid(147);
				if(srf_dlgid[i] == 0) break;
				srf_state[i] = 1;
			break;
			case 1:				
				memset(&capmsg,0,sizeof(CAP_Message));
				capmsg.msgLength[0] = 0;
				capmsg.msgLength[1] = 68;
				capmsg.msgServiceCode  = CAP_MSG_TYPE;
				capmsg.dialogue_id[0]  = srf_dlgid[i]>>8;
				capmsg.dialogue_id[1]  = srf_dlgid[i];
				capmsg.dialogue_id[2]  = 0x00;
				capmsg.port_id[0]      = 0x00;
				capmsg.port_id[1]      = 0x00;
				capmsg.port_id[2]      = 0x00;
				capmsg.msgOperaCode    = CAP_O_OPEN;
				capmsg.msgOperaType	   = 0x01; //REQUEST;
				capmsg.msgContent[0]   = 0x32; //ACN
				capmsg.msgContent[1]   = 0x02; //ACN Version = 2
				
				stuff_sccp_address(&sccpAddr,
							(char *)ppsParam.ppsTables.srfNumber[i].number,
							8,0);
				memcpy(&capmsg.msgContent[2],
						&sccpAddr,
						sizeof(SCCP_ADDR));

				ppsBcdToAsciiR(msisdn,&ppsParam.ppsNumber[1],20);
				StringCut(msisdn,'F');				
				stuff_sccp_address(&sccpAddr,msisdn,147,0);
				memcpy(&capmsg.msgContent[2+sizeof(SCCP_ADDR)],
						&sccpAddr,
						sizeof(SCCP_ADDR));
				
				cap_send_comdata((u8 *)&capmsg);

				capmsg.msgLength[0] = 0;
				capmsg.msgLength[1] = 14;
				capmsg.msgServiceCode  = CAP_MSG_TYPE;
				capmsg.dialogue_id[0]  = srf_dlgid[i]>>8;
				capmsg.dialogue_id[1]  = srf_dlgid[i];
				capmsg.dialogue_id[2]  = 0x00;
				capmsg.port_id[0]      = 0x00;
				capmsg.port_id[1]      = 0x00;
				capmsg.port_id[2]      = 0x00;
				capmsg.msgOperaCode    = CAP_OC_ActivityTest;
				capmsg.msgOperaType	   = 0x01; //REQUEST;
				capmsg.msgContent[0]   = cap_get_invokeid(srf_dlgid[i]); 
				capmsg.msgContent[1]   = 0x01;
				capmsg.msgContent[2]   = 0x10;
				capmsg.msgContent[3]   = 0x00;
				capmsg.msgContent[4]   = 0x00;
			
				cap_send_oprdata((u8 *)&capmsg);
				srf_timer[i] = 0;
				srf_state[i] = 2;
#if DEBUG1
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if(logMsgFlag & 0x02)
	{
		ppsDebugCapMsg(&capmsg,1);
		debug_messages ++;
	}
#endif

			break;
			case 2:
				sendEnd = 0;
				if(srf_timer[i] ++> 5*CYCLE_STATE_INTERVAL)
				{
					ppsParam.ppsTables.srfNumber[i].reachable = 0;
					srf_state[i] = 3;
					sendEnd = 1;
				}
				if(cap_get_comdata((u8 *)&capmsg,srf_dlgid[i]))
				{
					if(capmsg.msgOperaCode == CAP_O_END)
					{
						ppsParam.ppsTables.srfNumber[i].reachable = 1;
						srf_state[i] = 3;
						//sendEnd = 1;
					}
				}
				else if(cap_get_oprdata((u8 *)&capmsg,srf_dlgid[i]))
				{
					if(capmsg.msgOperaCode == CAP_OC_ActivityTest)
						ppsParam.ppsTables.srfNumber[i].reachable = 1;
					srf_state[i] = 3;
					sendEnd = 1;
				}

				if(sendEnd)
				{
					capmsg.msgLength[0] = 0;
					capmsg.msgLength[1] = 12;
					capmsg.msgServiceCode  = CAP_MSG_TYPE;
					capmsg.dialogue_id[0]  = srf_dlgid[i]>>8;
					capmsg.dialogue_id[1]  = srf_dlgid[i];
					capmsg.dialogue_id[2]  = 0x00;
					capmsg.port_id[0]      = 0x00;
					capmsg.port_id[1]      = 0x00;
					capmsg.port_id[2]      = 0x00;
					capmsg.msgOperaCode    = CAP_O_END;
					capmsg.msgOperaType	   = 0x01; //REQUEST;
					capmsg.msgContent[0]   = BASIC_END; 
					capmsg.msgContent[1]   = 0x00;
					capmsg.msgContent[2]   = 0x00;				
					cap_send_comdata((u8 *)&capmsg);
				}
			break;
			case 3:
				if(ppsParam.ppsTables.srfNumber[i].reachable)
					test_timer = 30*ONE_MINUTE_STATE_TIME;
				else
					test_timer = 1*ONE_MINUTE_STATE_TIME;
				if(srf_timer[i] ++> test_timer)
					srf_state[i] = 0;
			break;
			default:
			break;
		}//switch
	}//for
}

int CheckSRFResource()
{
	int		srfNum=0;

	if(ppsParam.ppsTables.srfNumber[0].reachable)
		srfNum ++;
	if(ppsParam.ppsTables.srfNumber[1].reachable)
		srfNum ++;
	return srfNum;

}

int GetSrfAddress(char *msisdn)
{
	static	u_char	referenceNo=0;
	int		srfNum=0;

	if(ppsParam.ppsTables.srfNumber[0].reachable)
		srfNum ++;
	if(ppsParam.ppsTables.srfNumber[1].reachable)
		srfNum ++;
	
	if(srfNum == 0)
	{
		strcpy(msisdn, (char *)ppsParam.ppsTables.srfNumber[0].number);
		return 0;
	}
	if(srfNum == 1)
	{
		if(ppsParam.ppsTables.srfNumber[0].reachable)
			strcpy(msisdn, (char *)ppsParam.ppsTables.srfNumber[0].number);
		else if(ppsParam.ppsTables.srfNumber[1].reachable)
			strcpy(msisdn, (char *)ppsParam.ppsTables.srfNumber[1].number);
	}
	else
	{
	
		if(ppsParam.ppsTables.srfNumber[0].reachable && referenceNo%2==0)
		{
			strcpy(msisdn, (char *)ppsParam.ppsTables.srfNumber[0].number);
		}
		else if(ppsParam.ppsTables.srfNumber[1].reachable && referenceNo%2==1)
		{
			strcpy(msisdn, (char *)ppsParam.ppsTables.srfNumber[1].number);
		}
		referenceNo ++;
	}
	return 1;
}
/***************************************************/

int encodePPS_MO_CDR(_tocdr_report *pcdr,u_char *pdata)
{
   int           len = 0, recordType=0;
   ASN_BUF       *asnbuf, asnbuf1;	
   u_char	buf[BUFSIZE]={""},charge[8],balance[8],duration[8];
   
	PutLogFunID("encodePPS_MO_CDR");

   asnbuf = &asnbuf1;
   asn_encode(pdata,asnbuf);

   recordType = pcdr->mtype;
   len = add_int("2-1",pcdr->squence,0x00,asnbuf);            
   len = add_tlv("0-2.0",1, (u_char *)&recordType,0x80,asnbuf);  /* record type */
  
   len = add_tlv("0-2.3",9,pcdr->msisdn,0x80,asnbuf); /* served MSISDN */
   
   len = add_tlv("0-2.9",10,ppsParam.ppsNumber,0x80,asnbuf); /* Recording Entity */

   CharToTimeStamp(buf, (char *)pcdr->seizuretime);
   len = add_tlv("0-2.22",8,buf,0x80,asnbuf);     /* seizure timestamp */
   CharToTimeStamp(buf, (char *)pcdr->answertime);
   len = add_tlv("0-2.23",8,buf,0x80,asnbuf);     /* answer timestamp*/
   CharToTimeStamp(buf, (char *)pcdr->releasetime);   
   len = add_tlv("0-2.24",8,buf,0x80,asnbuf);     /* release timestamp*/
   duration[0] = pcdr->duration[3];
   duration[1] = pcdr->duration[2];
   duration[2] = pcdr->duration[1];
   duration[3] = pcdr->duration[0];
   len = add_tlv("0-2.25",4,duration,0x80,asnbuf);/*call duration*/
   len = add_tlv("0-2.30",1,pcdr->tcos,0x80,asnbuf);      /* cause for term*/

   switch(pcdr->type[0])
   {
   	case	CT_GPRS:
   	case	CT_GPRS_REFUND:
		len = add_tlv("0-2.4",9,pcdr->caller,0x80,asnbuf); /* calling number */
	   	len = add_tlv("0-2.35",strlen((char *)pcdr->gprsSgsnIP),pcdr->gprsSgsnIP,0x80,asnbuf);      /* sgsn ip*/
	   	len = add_tlv("0-2.36",strlen((char *)pcdr->gprsGgsnIP),pcdr->gprsGgsnIP,0x80,asnbuf);      /* gsn ip*/
	   	len = add_tlv("0-2.37",strlen((char *)pcdr->gprsDestIP),pcdr->gprsDestIP,0x80,asnbuf);      /* dest ip*/
	   	len = add_tlv("0-2.38",4,pcdr->gprsVolume,0x80,asnbuf);      /* volume*/
	break;
	case	CT_VAS_SMS:
    case	CT_VAS_MMS_SEND:   
		len = add_tlv("0-2.39",strlen((char *)pcdr->peerAddress),pcdr->peerAddress,0x80,asnbuf);      /* peer address*/		
	break;
	default:
		len = add_tlv("0-2.1",8,pcdr->imsi,0x80,asnbuf);   /* served IMSI */
		len = add_tlv("0-2.4",9,pcdr->caller,0x80,asnbuf); /* calling number */
		len = add_tlv("0-2.5",12,pcdr->called,0x80,asnbuf); /* called number	 */	
		if(OCS_with_external_CRM())
		{
			if (strlen(pcdr->peerAddress) > 0)
			{
			len = add_tlv("0-2.39",strlen((char *)pcdr->peerAddress),pcdr->peerAddress,0x80,asnbuf);/* area name */
			}
		}
	break;
   }
   
   len = add_tlv("0-2.128",1,pcdr->type,0x80,asnbuf);          /* call type */
   charge[0] = pcdr->charge[3];
   charge[1] = pcdr->charge[2];
   charge[2] = pcdr->charge[1];
   charge[3] = pcdr->charge[0];
   len = add_tlv("0-2.129",4,charge,0x80,asnbuf);          /* charge  */
   balance[0] = pcdr->balance[3];
   balance[1] = pcdr->balance[2];
   balance[2] = pcdr->balance[1];
   balance[3] = pcdr->balance[0];
   len = add_tlv("0-2.130",4,balance,0x80,asnbuf);          /* balance */
   if(OCS_with_external_CRM())
   {
   	   char plan_id[4];
	   plan_id[0] = pcdr->plan_id[3];
	   plan_id[1] = pcdr->plan_id[2];
	   plan_id[2] = pcdr->plan_id[1];
	   plan_id[3] = pcdr->plan_id[0];
	   len = add_tlv("0-2.131",4,(u_char *)plan_id,0x80,asnbuf);          /* balance */   	
   }
   else
   {
   	len = add_int("0-2.131",pcdr->cos_id,0x80,asnbuf);
   }
   return len;
}


int encodePPS_MT_CDR(_tocdr_report *pcdr,u_char *pdata)
{
   int           len = 0, recordType=0;
   ASN_BUF       *asnbuf, asnbuf1;

   u_char	buf[BUFSIZE]={""},charge[8],balance[8],duration[8];

	PutLogFunID("encdoePPS_MT_CDR");

   asnbuf = &asnbuf1;
   asn_encode(pdata,asnbuf);

   recordType = pcdr->mtype;
   len = add_int("2-1",pcdr->squence,0x00,asnbuf);            
   len = add_tlv("1-2.0",1, (u_char *)&recordType,0x80,asnbuf);  /* record type */
   
   len = add_tlv("1-2.6",10,ppsParam.ppsNumber,0x80,asnbuf); /* Recording Entity */

   CharToTimeStamp(buf, (char *)pcdr->seizuretime);
   len = add_tlv("1-2.19",8,buf,0x80,asnbuf);     /* seizure timestamp */
   CharToTimeStamp(buf, (char *)pcdr->answertime);
   len = add_tlv("1-2.20",8,buf,0x80,asnbuf);     /* answer timestamp*/
   CharToTimeStamp(buf, (char *)pcdr->releasetime);   
   len = add_tlv("1-2.21",8,buf,0x80,asnbuf);     /* release timestamp*/
   duration[0] = pcdr->duration[3];
   duration[1] = pcdr->duration[2];
   duration[2] = pcdr->duration[1];
   duration[3] = pcdr->duration[0];
   len = add_tlv("1-2.22",4,duration,0x80,asnbuf);/*call duration*/
   len = add_tlv("1-2.27",1,pcdr->tcos,0x80,asnbuf);      /* cause for term*/
   len = add_tlv("1-2.128",1,pcdr->type,0x80,asnbuf);          /* call type */
   charge[0] = pcdr->charge[3];
   charge[1] = pcdr->charge[2];
   charge[2] = pcdr->charge[1];
   charge[3] = pcdr->charge[0];
   len = add_tlv("1-2.129",4,charge,0x80,asnbuf);          /* charge  */
   balance[0] = pcdr->balance[3];
   balance[1] = pcdr->balance[2];
   balance[2] = pcdr->balance[1];
   balance[3] = pcdr->balance[0];
   len = add_tlv("1-2.130",4,balance,0x80,asnbuf);          /* balance */
    if(OCS_with_external_CRM())
   {
   	   char plan_id[4];
	   plan_id[0] = pcdr->plan_id[3];
	   plan_id[1] = pcdr->plan_id[2];
	   plan_id[2] = pcdr->plan_id[1];
	   plan_id[3] = pcdr->plan_id[0];
	   len = add_tlv("0-2.131",4,(u_char *)plan_id,0x80,asnbuf);          /* balance */   	
   }
   else
   	   len = add_int("0-2.131",pcdr->cos_id,0x80,asnbuf);

   switch(pcdr->type[0])
   {   
    case	CT_VAS_MMS_RETRIEVE:
    case	CT_VAS_MMS_EMAIL:
		len = add_tlv("1-2.39",strlen((char *)pcdr->peerAddress),pcdr->peerAddress,0x80,asnbuf);      /* peer address*/		
		len = add_tlv("1-2.3",9,pcdr->msisdn,0x80,asnbuf); /* served number	 */
	break;	
	default:
		len = add_tlv("1-2.1",8,pcdr->imsi,0x80,asnbuf);   /* served IMSI */
   		len = add_tlv("1-2.3",9,pcdr->called,0x80,asnbuf); /* called number	 */
   		len = add_tlv("1-2.4",9,pcdr->caller,0x80,asnbuf); /* calling number */
   		len = add_tlv("1-2.5",9,pcdr->called,0x80,asnbuf); /* connected number */
		if(OCS_with_external_CRM())
		{
			if (strlen(pcdr->peerAddress) > 0)
			{
			len = add_tlv("0-2.39",strlen((char *)pcdr->peerAddress),pcdr->peerAddress,0x80,asnbuf);/* area name */
			}
		}
	break;
   }
   return len;
}

static pthread_mutex_t store_cdr_mutx = PTHREAD_MUTEX_INITIALIZER;

int StoreCDR(_tocdr_report *pcdr)
{
	int	pWriteSub ,pReadSub;
	int	tmpLen=0;

	pthread_mutex_lock(&store_cdr_mutx);

	PutLogFunID("StoreCDR");

    	if((ppsParam.serviceControl.cdrFlag & 0x0f)== 0) return 0;

    	pWriteSub	= pps_cdr_buffer.pWriteSub;
	pReadSub	= pps_cdr_buffer.pReadSub;

	pcdr->squence = cdr_head_ptr++;
	cdr_head_ptr &= 0x7fffffff;
	
	pps_cdr_buffer.flag[pWriteSub] = 0x01;
	//memcpy(&pps_cdr_buffer.cdr_record[pWriteSub],pcdr,sizeof(_tocdr_report));
    	
	switch(pcdr->mtype)
	{
		case MO_CDR_TYPE:
		default:
			tmpLen = encodePPS_MO_CDR(pcdr,&pps_cdr_buffer.cdrMsg[pWriteSub][1]);
		break;
		case MT_CDR_TYPE:
			tmpLen = encodePPS_MT_CDR(pcdr,&pps_cdr_buffer.cdrMsg[pWriteSub][1]);
		break;
	}

	cdr_submit(SSN_SCF, tmpLen, (char *)&pps_cdr_buffer.cdrMsg[pWriteSub][1]);
	
	pps_cdr_buffer.cdrMsg[pWriteSub][0] = tmpLen%254;
	
	pWriteSub ++;

    	if(pReadSub == pWriteSub)
	{
	  alarm_code[0] = 0x01;  /* cdr */
	  alarm_code[1] = 0x01;  /* overflow */
	  ppsSendHeartBeating();
	  AddPPSStatistics(MIBPPS_CDROVERFLOW,0);
	}
	
	if(pWriteSub>=MAX_CDR_LEN) pWriteSub = 0;
	pps_cdr_buffer.pWriteSub = pWriteSub;
	AddPPSStatistics(MIBPPS_CDRNUMBER,0);

	pthread_mutex_unlock(&store_cdr_mutx);	

    return 1;
}

extern int pps_crm_get_sms_notification_for_event_flag();
extern void pps_send_last_call_info(_account_info *user_ptr, int call_type, int charge, int duration);
void SendCDR(int proc_id)
{
     _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;
    _tocdr_report  *pcdr,cdrreport;
    char buf[BUFSIZE]={""};
    int    len=0;
    int    duration=0, balance,charge;

    PutLogFunID("SendCDR");

    shmp += proc_id;

    UpdateAccountLastCDR(shmp);    

    pcdr = &cdrreport;
	
    duration = ceil( (double) shmp->process_info.duration /
                    CYCLE_STATE_INTERVAL);

    AsciiTime(buf, shmp->cdr_info.seizuretime);
    AsciiToBcd(pcdr->seizuretime,buf,14);
    AsciiTime(buf, shmp->cdr_info.answertime);
    AsciiToBcd(pcdr->answertime,buf,14);

    if(shmp->cdr_info.releasetime==0)
        shmp->cdr_info.releasetime = shmp->cdr_info.answertime + duration;

    AsciiTime(buf, shmp->cdr_info.releasetime);
    AsciiToBcd(pcdr->releasetime,buf,14);
	
    memcpy(pcdr->duration,&duration,4);
    if(shmp->caller_info.charge<0)
        charge = (int) shmp->caller_info.charge;
    else
        charge = (int)(shmp->caller_info.charge+0.5);// ceil ==> int
	
    switch(shmp->process_info.call_type) 
    {
        case CT_SERVICE:
        case CT_LOCAL_CALL_OUT:
        case CT_TRUNK_CALL_OUT:
        case CT_NDD_CALL_OUT:
        case CT_IDD_CALL_OUT:
        case CT_MO_SM:
        case CT_MF_CALL:
        case CT_CONFERENCE_CALL:
        case CT_THIRD_PARTY_CHARGE:
	 case CT_BUNDLE_PLAN_CHARGE:
            if(shmp->caller_info.charge > 0)
            {				
                if(shmp->process_info.call_type == CT_MO_SM)
                    increPoolChildSMS(&shmp->caller_info);
                else
                {
                    increPoolChildCalls(&shmp->caller_info);
                }
            }
            pcdr->mtype = MO_CDR_TYPE;

            pcdr->type[0] = shmp->process_info.call_type;
            pcdr->type[1] = 0;

            memcpy(pcdr->charge, &charge,4); //
            balance =  ceil (GetBalance(&shmp->caller_info)) ;

            memcpy(pcdr->balance,&balance,4);
            memcpy(pcdr->imsi,shmp->caller_info.IMSI,8);

            pcdr->msisdn[0] = 0x91;
            if(shmp->process_info.chargeOther)
                memcpy(&pcdr->msisdn[1],shmp->cdr_info.msisdn,8);
            else
                memcpy(&pcdr->msisdn[1],shmp->cdr_info.caller,8);
            pcdr->caller[0] = 0x91;
            memcpy(&pcdr->caller[1],shmp->cdr_info.caller,8);
            pcdr->called[0] = 0x91;
            memcpy(&pcdr->called[1],shmp->cdr_info.called,10);

            pcdr->tcos[0] = 0; // shmp->process_info.tcos>>8;
            pcdr->tcos[1] = 0;//shmp->process_info.tcos;
            if (shmp->process_info.call_type == CT_BUNDLE_PLAN_CHARGE)
            {
                pcdr->tcos[0] = shmp->process_info.tcos & 0xFF;
            }

            pcdr->cos_id = GetAccountCosID(&shmp->caller_info);

	      memcpy(pcdr->plan_id, &shmp->process_info.rest_if.plan_id, 4);

			if(OCS_with_external_CRM())
			{
				if ((shmp->process_info.call_type != CT_BUNDLE_PLAN_CHARGE)
					&& (shmp->process_info.call_type != CT_SERVICE))
				{
					strncpy(pcdr->peerAddress, shmp->process_info.ppsService.areaName, 31);
				}
			}
            CDRStatistics(pcdr,shmp->caller_info.charge, 0);  
            StoreCDR(pcdr);	
			
            CheckPromotionLatchFlag(&shmp->caller_info);
            pps_real_update_user_file(shmp->caller_info.head, shmp->caller_info.tail);
            
#if DEBUG
        if( logMsgFlag & 0x04 || shmp->process_info.logMsisdn)
        {
            DebugMsg(debugmib.display.asciiOut,"[%05d] Send MO CDR, type = %d", proc_id, shmp->process_info.call_type);
        }
#endif
        break;
        case CT_LOCAL_CALL_IN:
        case CT_TRUNK_CALL_IN:
	 case  CT_IDD_CALL_IN:
        case CT_MT_SM:
            pcdr->mtype = MT_CDR_TYPE;
            pcdr->type[0] = shmp->process_info.call_type;
            pcdr->type[1] = 0;

            charge = (int)(shmp->called_info.charge+0.5);// ceil ==> int
            memcpy(pcdr->charge, &charge,4); /* called_info.charge */
            balance =  ceil(GetBalance(&shmp->called_info) );   /* called_info */
            memcpy(pcdr->balance,&balance,4);
            memcpy(pcdr->imsi,shmp->called_info.IMSI,8);

            pcdr->msisdn[0] = 0x91;   
            /* maybe fault, if realnumber=81xxxx ?? */
            memcpy(&pcdr->msisdn[1],shmp->cdr_info.caller,8);
            pcdr->caller[0] = 0x91;
            memcpy(&pcdr->caller[1],shmp->cdr_info.caller,8);
            pcdr->called[0] = 0x91;
            len = strlen((char *)shmp->called_info.number)%20;
            ppsAsciiToBcdR(&pcdr->called[1], (char *)shmp->called_info.number, (len+1)/2*2);
            if(len %2)
            {
                pcdr->called[(len+1)/2] |= 0xF0;
            }
            if(len<21)
            {
				pcdr->called[(len+1)/2+1] = 0xFF;
            }

            pcdr->tcos[0] = 0;
            pcdr->cos_id = GetAccountCosID(&shmp->called_info);
	      memcpy(pcdr->plan_id, &shmp->process_info.rest_if.plan_id, 4);
		  
			if(OCS_with_external_CRM())
			{
				strncpy(pcdr->peerAddress, shmp->process_info.ppsService.areaName, 31);
			}
            CDRStatistics(pcdr,shmp->called_info.charge, 0);  
            StoreCDR(pcdr);	  
            CheckPromotionLatchFlag(&shmp->called_info);
            pps_real_update_user_file(shmp->called_info.head, shmp->called_info.tail);
#if DEBUG
    if(debug_messages<=MAX_DEBUG_MESSAGES)	
    if( logMsgFlag & 0x04 || shmp->process_info.logMsisdn){
            DebugMsg(debugmib.display.asciiOut,"[%05d] Send MT CDR, type = %d", proc_id, shmp->process_info.call_type);
            debug_messages ++;
    }
#endif
        break;
	  case CT_MO_CC_CALL:

	     pcdr->mtype = MO_CDR_TYPE;

            pcdr->type[0] = shmp->process_info.call_type;
            pcdr->type[1] = 0;

            memcpy(pcdr->charge, &charge,4); //
            balance =  (int) (ocs_get_calling_card_left_balance(shmp->card_info.cardhead, shmp->card_info.cardtail)+0.5) ;

            memcpy(pcdr->balance,&balance,4);
            memcpy(pcdr->imsi,shmp->caller_info.IMSI,8);

            pcdr->msisdn[0] = 0x91;
            memcpy(&pcdr->msisdn[1],shmp->cdr_info.caller,8);
            pcdr->caller[0] = 0x91;
            memcpy(&pcdr->caller[1],shmp->cdr_info.caller,8);
            pcdr->called[0] = 0x91;
            memcpy(&pcdr->called[1],shmp->cdr_info.called,10);

            pcdr->tcos[0] = 0; // shmp->process_info.tcos>>8;
            pcdr->tcos[1] = 0;//shmp->process_info.tcos;
  
            pcdr->cos_id = ocs_get_calling_card_cos_id();

            CDRStatistics(pcdr,shmp->caller_info.charge, 0);  
            StoreCDR(pcdr);	
			            
#if DEBUG
        if( logMsgFlag & 0x04 || shmp->process_info.logMsisdn)
        {
            DebugMsg(debugmib.display.asciiOut,"[%05d] Send MO CC CDR, type = %d", proc_id, shmp->process_info.call_type);
        }
#endif	  	
	  break;
    }

	if(OCS_with_external_CRM())
	{
		if(charge>0 && pps_crm_get_sms_notification_for_event_flag())
		{
			pps_send_last_call_info(&shmp->caller_info, shmp->process_info.call_type, charge, duration);
		}
	}
}


void SendAccountRealSync(DWORD instance, double balance, double promotion, int ocode)
{
    _prepaid_data    *ptr = &ramshm_ptr->prepaid_data;
    int    head=0, tail=0;
    
    snmp_pdu    snmpbuf;
    snmp_addr    snmpaddr;
    var_list    *varlist;

    PutLogFunID("SendAccountRealSync");

    if(instance>=UNIT_STORE_ACCOUNT*MSISDN_HEAD_NUM) 
        return ;
    if(ocode>=MAX_OMC_OCODE || ocode<OMC_OCODE_READ) 
    	return;
    
    snmpbuf.pdu_type = 0x07; /* trap */
    snmpbuf.var_num	 = 0x01;

    snmpaddr.remote_ip = peer_server_ip;
    //snmpaddr.local_ip  = GetLocalIP();
    snmpaddr.remote_port = PPS_REALSYNC_PORT;
    snmpaddr.local_port  = PPS_REALSYNC_PORT;
    snmpaddr.broadcast   = 0x00;

    varlist = snmpbuf.var;
    varlist->oidlen   = 16 + 1;
    varlist->vartype  = 0x04;

    memcpy(&varlist->oid,PPS_OID_PREFIX,11*4);
    varlist->oid[11] = 0x02; /* configuration */
    varlist->oid[12] = 0x02; /* database */
    varlist->oid[13] = 0x02; /* account_db */
    varlist->oid[14] = 0x01; /* user_info */

    head = (int) (instance / UNIT_STORE_ACCOUNT);
    tail = instance % UNIT_STORE_ACCOUNT;
    if(ptr->prepaid_info[head][tail].msisdn[9] < MIN_MSISDN_ALEN || 
    		ptr->prepaid_info[head][tail].msisdn[9]>MAX_MSISDN_ALEN) 
    {
        debugmib.watch_dog[48]++;
        return ; /* length error */
    }
    
    varlist->oid[15] = instance;
    varlist->oid[16] = ocode; /* update */
    varlist->msglen  = sizeof(_prepaid_info)+sizeof(double)*2;
    memcpy(varlist->msg,  (u_char *) &ptr->prepaid_info[head][tail], sizeof(_prepaid_info));
    memcpy(&varlist->msg[sizeof(_prepaid_info)],&balance,sizeof(double));
    memcpy(&varlist->msg[sizeof(_prepaid_info)+sizeof(double)],&promotion,sizeof(double));
		
    if(peer_server_ip != 0x100007f)
    {
        if (realSyncTcpSend(PPS_USER_DATA_DB_OID, instance, ocode, varlist->msg, varlist->msglen) < 0)
        {
            snmp_send(&snmpbuf,&snmpaddr);
        }
    }

    if(ocode == 4) 
    {
        snmpaddr.remote_ip = LOCAL_IP;
        snmp_send(&snmpbuf,&snmpaddr);
    }

#if DEBUG
    if(debug_messages<=MAX_DEBUG_MESSAGES)	
    {
        //char    buf[BUFSIZE]={""}, bufwork[BUFSIZE];
        //int    loop;

        debug_messages ++;
        if(logMsgFlag == 0x40)
        {
            DebugMsgDelimiter();
            DebugMsg(debugmib.display.asciiOut,"SendAccountRealSync (%08X,%d), instance:%d",
                peer_server_ip,PPS_REALSYNC_PORT,instance);
        }
    }
#endif
}

void SendAccountRealSync_2(_account_info   *accountInfo,double balance,double promotion ,int ocode)
{
	DWORD instance;
	
	instance = accountInfo->head * UNIT_STORE_ACCOUNT + accountInfo->tail;
	SendAccountRealSync(instance,balance,promotion,ocode);
}

static _pps_heartbeat hb_default =
{
	0x00, //system id
	0x00, //subsystem id
	{0x00,0x00,0x00,0x00}, //timestamp
	{0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, //led
	0x00,{0x00,0x00}, //alarm
	0x00, //length, h
	0x1c, //length, l
	0x00,0x00, // component id
	0x00,0x18, //component len
	{0x00,0x00,0x00}, //version
	0x00,    //state
	{0x00,0x00,0x00,0x00}, //check sum
	{0x00,0x00,0x00,0x00}, //licensed user
	{0x00,0x00,0x00,0x01}, //real user
	{0x00,0x00,0x00,0x00}, //serial number
	{0x00,0x00,0x00,0x01}, //system capability
};

int
ppsSendHeartBeating()
{
	u_long           nowSeconds;
    	_pps_heartbeat   ppsHeartBeat;

    	snmp_pdu         snmpbuf;
	snmp_addr		 snmpaddr;
    	var_list		 *varlist;
//	struct timeval	tm;
//	gettimeofday(&tm,NULL);
//	DebugMsg(debugmib.display.asciiOut,"Now send PPS hb: %ld",tm.tv_sec);
	PutLogFunID("ppsSendHeartBeating");

    	snmpbuf.pdu_type = 0x07; //trap 
	snmpbuf.var_num	 = 0x01;

	snmpaddr.remote_ip = peer_server_ip;
//	snmpaddr.local_ip  = GetLocalIP();
    	snmpaddr.remote_port = HEART_BEATING_PORT;
	snmpaddr.local_port  = HEART_BEATING_PORT;
	snmpaddr.broadcast   = 0x00;

    	varlist = snmpbuf.var;
    	varlist->oidlen   = 12;
	varlist->vartype  = 0x04;

	memcpy(&varlist->oid,PPS_OID_PREFIX,11*4);
	varlist->oid[11] = 0x01; /* configuration */
    	varlist->msglen  = sizeof(_pps_heartbeat);
	memcpy(&ppsHeartBeat,&hb_default,sizeof(_pps_heartbeat));    
	nowSeconds = tvnow.tv_sec;

	memcpy(ppsHeartBeat.timeStamp ,&nowSeconds,4);
    	ppsHeartBeat.systemID = subSystemID; 
	ppsHeartBeat.subSystemID = 0x00; 
	/* allways be 0x00 for function server subSystemID; */
    	memcpy(ppsHeartBeat.alarm,alarm_code,2);
	if(alarm_code[0] !=0 || alarm_code[1] !=0){
	  ppsHeartBeat.ledStatus[0]=0x29;
	}

	//ppsHeartBeat.reserved0 = debugmib.display.initProgress;
	ppsHeartBeat.reserved0 = 0;
	memcpy(ppsHeartBeat.version,version_id,3);
	ppsHeartBeat.status = debugmib.display.sysState;
    	memcpy(&ppsHeartBeat.sumOfParameter,&sumOfParameter,1);
	ppsHeartBeat.systemCapability[0] = systemCapability>>24;
	ppsHeartBeat.systemCapability[1] = systemCapability>>16;
    ppsHeartBeat.systemCapability[2] = systemCapability>>8;
	ppsHeartBeat.systemCapability[3] = systemCapability;
	ppsHeartBeat.licensedUser[0]=  ppsParam.serviceControl.licenseduser>>24;
	ppsHeartBeat.licensedUser[1]=  ppsParam.serviceControl.licenseduser>>16;
	ppsHeartBeat.licensedUser[2]=  ppsParam.serviceControl.licenseduser>>8;
	ppsHeartBeat.licensedUser[3]=  ppsParam.serviceControl.licenseduser;
    ppsHeartBeat.realUserNumber[0] = debugmib.measurement.usernumber>>24;
    ppsHeartBeat.realUserNumber[1] = debugmib.measurement.usernumber>>16;
    ppsHeartBeat.realUserNumber[2] = debugmib.measurement.usernumber>>8;
    ppsHeartBeat.realUserNumber[3] = debugmib.measurement.usernumber;
	AsciiToBcd(ppsHeartBeat.serialNumber,serialNumber,8);
    memcpy(varlist->msg, (u_char *)&ppsHeartBeat, 
		sizeof(_pps_heartbeat));
	if(peer_server_ip != 0x100007f)
            snmp_send(&snmpbuf,&snmpaddr);

	//primary_data_server = inet_addr("172.18.128.1");
  //  if(primary_data_server)
    {
		snmpaddr.remote_ip = primary_data_server;
		if(snmp_send(&snmpbuf,&snmpaddr)==0)
		{
			DebugMsg(debugmib.display.asciiOut,
				"PPS send hb to OMC0 fialed!");
		}
	}
	//second_data_server = inet_addr("172.18.129.1");
	if(second_data_server)
      {
		snmpaddr.remote_ip = second_data_server;
		if(snmp_send(&snmpbuf,&snmpaddr)==0)
		{
			DebugMsg(debugmib.display.asciiOut,
				"PPS send hb to OMC1 fialed!");
		}
    }
	alarm_code[0]=0;alarm_code[1] = 0;
    return 1;
}

void
SendPeriodicChargeCDR( int head, int tail, int charge, int rent_type)
{
    _tocdr_report  pcdr;
    char           buf[BUFSIZE];
    int			   balance;

	PutLogFunID("SendPeriodicChargeCDR");

    memset(&pcdr,0, sizeof(_tocdr_report));
    pcdr.mtype   = MO_CDR_TYPE;
    pcdr.type[0] = rent_type;
    AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
    pcdr.duration[0] = 0;
	memcpy(pcdr.charge,&charge, 4);

    balance = (int) GetAccountBalance(head, tail);
	memcpy(pcdr.balance, &balance, 4);

    GetAccountMsisdn(head,tail,&pcdr.msisdn[1]);
	ByteRev(pcdr.msisdn,9,0);
	pcdr.msisdn[0]=0x91;
	memcpy(pcdr.caller,pcdr.msisdn,9);
    buf[0] = 0;
	sprintf(buf,"FFFFFFFFFFFFFFFFFF");
	AsciiToBcd(pcdr.called,buf,18);
    AsciiToBcd(pcdr.imsi,buf,16);
	
	pcdr.tcos[0] = NORMAL_CLEARING%256;
	pcdr.tcos[1] = NORMAL_CLEARING>>8;

	CDRStatistics(&pcdr,charge, 0);
	StoreCDR(&pcdr);
	pps_real_update_user_file(head, tail);
	
#if DEBUG
	if(debug_messages++<=MAX_DEBUG_MESSAGES)	
   if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	DebugMsg(debugmib.display.asciiOut,"SendPeriodicChargeCDR:%d",charge);
#endif
}

void
SendRechargeCDR(int proc_id, int type, int charge)
{
    _state_data    *shmp=(_state_data *) &smshm_ptr->state_data;
    _tocdr_report  pcdr;

	char            buf[BUFSIZE]={""};
    int             balance;


	PutLogFunID("SendRechargeCDR");

    shmp += proc_id;
    memset(&pcdr, 0x00, sizeof(_tocdr_report));

    pcdr.mtype   = MO_CDR_TYPE;
	pcdr.type[0] = type;
	pcdr.type[1] = type>>8;
    AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
    pcdr.duration[0] = 0;
	pcdr.charge[0] = charge;
	pcdr.charge[1] = charge>>8;
	pcdr.charge[2] = charge>>16;
	pcdr.charge[3] = charge>>24;

    balance = GetAccountBalance(shmp->caller_info.head, 
                                shmp->caller_info.tail);
    pcdr.balance[0] = balance;
	pcdr.balance[1] = balance>>8;
	pcdr.balance[2] = balance>>16;
	pcdr.balance[3] = balance>>24;

	pcdr.msisdn[0] = 0x91;
	memset(pcdr.imsi,0xFF,8);
	if(shmp->process_info.rechargeByOther)
	{
		memcpy(&pcdr.msisdn[1],shmp->cdr_info.msisdn,8);	
		//memset(pcdr.imsi,0xFF,8);
	}
	else
	{
		memcpy(&pcdr.msisdn[1],shmp->cdr_info.caller,8);
	    //memcpy(pcdr.imsi,shmp->caller_info.IMSI,8);
	}
	pcdr.caller[0] = 0x91;
	memcpy(&pcdr.caller[1],shmp->cdr_info.caller,8);
	pcdr.called[0] = 0x91;
	memcpy(&pcdr.called[1],shmp->cdr_info.called,10);
	if(shmp->cdr_info.caller[1] == 0 )
	{
		debugmib.watch_dog[0] ++;
		debugmib.watch_dog[1] = proc_id;
		debugmib.watch_dog[2] = proc_id>>2;
		return;
	}
	//if(shmp->cdr_info.called[1] == 0) return;
    //pcdr.tcos[0] = NORMAL_CLEARING%256;
    pcdr.tcos[0] = shmp->process_info.rechargeByOther;

	StoreCDR(&pcdr);

	CDRStatistics(&pcdr,charge, 0);
	if(UseExternalVC() && type == CT_RECHARGE_SUCCESS)
	{
            CountUsedCardForDailyReport(charge);
	}
	pps_real_update_user_file(shmp->caller_info.head, shmp->caller_info.tail);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
  if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
  {
    DebugMsg(debugmib.display.asciiOut,"SendRechargeCDR");
	   debug_messages ++;
  }
#endif
}

void SendSelfcareRechargeCDR(_account_info *user_info, char *pwd, int type, int charge)
{
	_tocdr_report  pcdr;
	char            buf[64]={""};
	u_char   bcd_buf[12] = {0};
	int             balance;

	PutLogFunID("SendSelfcareRechargeCDR");

	memset(&pcdr, 0x00, sizeof(_tocdr_report));

	pcdr.mtype   = SC_CDR_TYPE;
	pcdr.type[0] = type;
	pcdr.type[1] = type>>8;

	AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
	memcpy(pcdr.answertime, pcdr.seizuretime, 9);
	memcpy(pcdr.releasetime, pcdr.seizuretime, 9);

	pcdr.duration[0] = 0;
	pcdr.charge[0] = charge;
	pcdr.charge[1] = charge>>8;
	pcdr.charge[2] = charge>>16;
	pcdr.charge[3] = charge>>24;

	balance = (int)(GetAccountBalance(user_info->head, user_info->tail) + 0.5);
	pcdr.balance[0] = balance;
	pcdr.balance[1] = balance>>8;
	pcdr.balance[2] = balance>>16;
	pcdr.balance[3] = balance>>24;

	memset(pcdr.imsi, 0xFF, 8);

	sprintf(buf, "%sE", user_info->number);
	int len = (strlen(buf)+1)/2 * 2;
	ppsAsciiToBcdR(bcd_buf, buf,  len);
	pcdr.msisdn[0] = 0x91;
	memcpy(&pcdr.msisdn[1], bcd_buf, 8);

	memcpy(pcdr.caller, pcdr.msisdn, 9);

	if (CT_ASSISTED_UP == type)
	{
		sprintf(buf,"FFFFFFFFFFFFFFFFFF");
		AsciiToBcd(pcdr.called, buf, 18);
	}
	else
	{
		// called num, recharge card num
		sprintf(buf, "%sE", pwd);
		len = (strlen(buf)+1)/2 * 2;
		if (len > 18)
		{
			len = 18;
		}
		ppsAsciiToBcdR(bcd_buf, buf,  len);
		pcdr.called[0] = 0x91;
		memcpy(&pcdr.called[1], bcd_buf, 8);
	}

	StoreCDR(&pcdr);

	CDRStatistics(&pcdr,charge, 0);
	if(UseExternalVC() && type == CT_RECHARGE_SUCCESS)
	{
		CountUsedCardForDailyReport(charge);
	}
	pps_real_update_user_file(user_info->head, user_info->tail);
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,"SendSelfcareRechargeCDR");
		debug_messages ++;
	}
#endif
}

void SendSelfcareBundleSubCDR(_account_info *user_info, int charge, u32 data_volume, u32 voice_sec)
{
	_tocdr_report  pcdr;
	char		buf[32]={""};
	u_char	bcd_buf[12] = {0};
	int		balance;

	PutLogFunID("SendSelfcareBundleSubCDR");

	memset(&pcdr, 0x00, sizeof(_tocdr_report));

	pcdr.mtype   = SC_CDR_TYPE;
	pcdr.type[0] = CT_BUNDLE_PLAN_CHARGE;
	pcdr.type[1] = CT_BUNDLE_PLAN_CHARGE>>8;

	AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
	memcpy(pcdr.answertime, pcdr.seizuretime, 9);
	memcpy(pcdr.releasetime, pcdr.seizuretime, 9);

	if (voice_sec > 0)
	{
		pcdr.tcos[0] = 0x01;// bundle plan
		/*
		pcdr.duration[0] = voice_sec;
		pcdr.duration[1] = voice_sec>>8;
		pcdr.duration[2] = voice_sec>>16;
		pcdr.duration[3] = voice_sec>>24;*/
	}

	if (data_volume > 0)
	{
		pcdr.gprsVolume[0] = data_volume;
		pcdr.gprsVolume[1] = data_volume>>8;
		pcdr.gprsVolume[2] = data_volume>>16;
		pcdr.gprsVolume[3] = data_volume>>24;
	}

	pcdr.charge[0] = charge;
	pcdr.charge[1] = charge>>8;
	pcdr.charge[2] = charge>>16;
	pcdr.charge[3] = charge>>24;

	balance = (int)(GetAccountBalance(user_info->head, user_info->tail) + 0.5);
	pcdr.balance[0] = balance;
	pcdr.balance[1] = balance>>8;
	pcdr.balance[2] = balance>>16;
	pcdr.balance[3] = balance>>24;

	memset(pcdr.imsi, 0xFF, 8);

	sprintf(buf, "%sE", user_info->number);
	int len = (strlen(buf)+1)/2 * 2;
	ppsAsciiToBcdR(bcd_buf, buf,  len);
	pcdr.msisdn[0] = 0x91;
	memcpy(&pcdr.msisdn[1], bcd_buf, 8);
	memcpy(pcdr.caller, pcdr.msisdn, 9);

	sprintf(buf,"FFFFFFFFFFFFFFFFFF");
	AsciiToBcd(pcdr.called, buf, 18);

	StoreCDR(&pcdr);

	CDRStatistics(&pcdr, charge, 0);
	pps_real_update_user_file(user_info->head, user_info->tail);
#if DEBUG
	if(debug_messages <= MAX_DEBUG_MESSAGES)
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut, "SendSelfcareBundleSubCDR");
		debug_messages ++;
	}
#endif
}

void SendSelfcareTransferCDR(_account_info *caller_info,_account_info *called_info, float charge)
{
	_tocdr_report  	pcdr;
	char           	buf[32] = {""}; 
	int			fee, balance, len;
	int			head, tail;
	u_char   bcd_buf[12] = {0};

	PutLogFunID("SendSelfcareTransferCDR");

	head = caller_info->head;
	tail = caller_info->tail;

	memset(&pcdr, 0, sizeof(_tocdr_report));
	pcdr.mtype = SC_CDR_TYPE;
	if (charge > 0.0)
	{
		pcdr.type[0] = CT_TRANFER_IN;
		pcdr.type[1] = CT_TRANFER_IN>>8;
	}
	else
	{
		pcdr.type[0] = CT_TRANFER_OUT;
		pcdr.type[1] = CT_TRANFER_OUT>>8;
	}

	AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
	memcpy(pcdr.answertime, pcdr.seizuretime, 9);
	memcpy(pcdr.releasetime, pcdr.seizuretime, 9);

	pcdr.duration[0] = 0;
	fee = (int)charge;
	fee = abs(fee);
	memcpy(pcdr.charge, &fee, 4);
	balance = (int)(GetAccountBalance(head, tail) + 0.5);
	memcpy(pcdr.balance, &balance, 4);

	sprintf(buf, "%sE", caller_info->number);
	len = (strlen(buf)+1)/2 * 2;
	ppsAsciiToBcdR(bcd_buf, buf,  len);
	pcdr.msisdn[0] = 0x91;
	memcpy(&pcdr.msisdn[1], bcd_buf, 8);

	memcpy(pcdr.caller, pcdr.msisdn, 9);

	sprintf(buf, "%sE", called_info->number);
	len = (strlen(buf)+1)/2 * 2;
	ppsAsciiToBcdR(bcd_buf, buf,  len);
	pcdr.called[0] = 0x91;
	memcpy(&pcdr.called[1], bcd_buf, 8);

	memset(pcdr.imsi, 0xFF, 8);

	pcdr.tcos[0] = NORMAL_CLEARING%256;

	CDRStatistics(&pcdr, charge, 0);
	StoreCDR(&pcdr);
	pps_real_update_user_file(head, tail);

#if DEBUG
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		DebugMsg(debugmib.display.asciiOut, "SendSelfcareTransferCDR");
#endif
}

void SendDirectDebitAndRefundCDR(_account_info *caller_info, float charge)
{
	_tocdr_report  	pcdr;
	char           	buf[BUFSIZE] = {""}; 
	int			fee, balance;//, len;
	int			head, tail;

	PutLogFunID("SendDirectDebitAndRefundCDR");

	head = caller_info->head;
	tail = caller_info->tail;

	memset(&pcdr, 0, sizeof(_tocdr_report));
	if (charge > 0)
	{
		pcdr.type[0] = CT_REFUND_ACCOUNT;
		pcdr.type[1] = CT_REFUND_ACCOUNT>>8;
	}
	else if (charge < 0)
	{
		pcdr.type[0] = CT_DIRECT_DEBITING;
		pcdr.type[1] = CT_DIRECT_DEBITING>>8;
	}
	else
	{
		return ;
	}

	AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
	AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
	AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
	pcdr.duration[0] = 0;
	fee =  (int)charge;
	fee = abs(fee);
	memcpy(pcdr.charge, &fee, 4);
	balance = (int) GetAccountBalance(head, tail);
	memcpy(pcdr.balance, &balance, 4);

	GetAccountMsisdn(head, tail, &pcdr.msisdn[1]);
	ByteRev(pcdr.msisdn, 9, 0);

	pcdr.msisdn[0] = 0x91;
	memcpy(pcdr.caller, pcdr.msisdn, 9);
	buf[0] = 0;

	pcdr.called[0] = 0x91;	
	/*len = 0;*//* strlen(called_info->number)%20;
	ppsAsciiToBcdR(&pcdr.called[1], called_info->number, (len+1)/2*2);
	if(len %2)
	{
		pcdr.called[(len+1)/2] |= 0xF0;
	}
	if(len<21)
	{*/
		//pcdr.called[(len+1)/2+1] = 0xFF;
		pcdr.called[1] = 0xFF;
	//}
			
	sprintf(buf, "FFFFFFFFFFFFFFFFFF");
	AsciiToBcd(pcdr.imsi, buf, 16);

	pcdr.tcos[0] = NORMAL_CLEARING%256;

	CDRStatistics(&pcdr, (int)charge, 0);
	StoreCDR(&pcdr);

	pps_real_update_user_file(head, tail);

#if DEBUG
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		DebugMsg(debugmib.display.asciiOut, "SendDirectDebitAndRefundCDR");
#endif
}

void SendSmsDirectDebitAndRefundCDR(_state_data *shmp, int sent_num, int bIsRefund)
{
	_tocdr_report  	pcdr;
	char           	buf[BUFSIZE] = {""}; 
	int			fee, balance, len;
	int			head, tail;
	_account_info *caller_info = &shmp->caller_info;
	float			charge = caller_info->charge;

	PutLogFunID("SendSmsDirectDebitAndRefundCDR");

	head = caller_info->head;
	tail = caller_info->tail;

	memset(&pcdr, 0, sizeof(_tocdr_report));
	if (bIsRefund)
	{
		pcdr.type[0] = CT_REFUND_ACCOUNT;
		pcdr.type[1] = CT_REFUND_ACCOUNT>>8;
	}
	else
	{
		pcdr.type[0] = CT_MO_SM;
		pcdr.type[1] = CT_MO_SM>>8;
	}

	increPoolChildSMS(&shmp->caller_info);
	AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
	AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
	AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
	pcdr.duration[0] = 0;
	fee =  (int)charge;
	fee = abs(fee);
	memcpy(pcdr.charge, &fee, 4);
	balance = (int) GetAccountBalance(head, tail);
	memcpy(pcdr.balance, &balance, 4);

	GetAccountMsisdn(head, tail, &pcdr.msisdn[1]);
	ByteRev(pcdr.msisdn, 9, 0);

	pcdr.msisdn[0] = 0x91;
	memcpy(pcdr.caller, pcdr.msisdn, 9);
	buf[0] = 0;

	len = strlen((char *)shmp->called_info.number);
	AsciiToRbcd(&pcdr.called[1], (char *)shmp->called_info.number, len);
	if (len & 0x01)
	{
		pcdr.called[1 + len/2] |= 0xF0;
	}
	else
	{
		pcdr.called[1 + len/2] = 0xFF;
	}
	pcdr.called[0] = 0x91;

	sprintf(buf, "FFFFFFFFFFFFFFFFFF");
	AsciiToBcd(pcdr.imsi, buf, 16);

	pcdr.cos_id = GetAccountCosID(&shmp->caller_info);

	pcdr.tcos[0] = NORMAL_CLEARING%256;

	CDRStatistics(&pcdr, (int)charge, 0);
	StoreCDR(&pcdr);
	
	CheckPromotionLatchFlag(&shmp->caller_info);
	pps_real_update_user_file(shmp->caller_info.head, shmp->caller_info.tail);
            
#if DEBUG
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		DebugMsg(debugmib.display.asciiOut, "SendDirectDebitAndRefundCDR");
#endif
}

void
SendOperatorRechargeCDR(int head, int tail, int charge)
{
    _tocdr_report  pcdr;
    char           buf[BUFSIZE]={""}; 
	int			   balance;

	PutLogFunID("SendOperatorRechargeCDR");

    memset(&pcdr, 0, sizeof(_tocdr_report));
    if (charge >= 0)
	{
        pcdr.type[0] = CT_ASSISTED_UP;
		pcdr.type[1] = CT_ASSISTED_UP>>8;
	}
    else
	{
        pcdr.type[0] = CT_ASSISTED_DOWN;
		pcdr.type[1] = CT_ASSISTED_DOWN>>8;
	}

    AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
    pcdr.duration[0] = 0;
	charge = abs(charge);
    memcpy(pcdr.charge,&charge,4);
    balance = (int) GetAccountBalance(head, tail);
    memcpy(pcdr.balance,&balance,4);

    GetAccountMsisdn(head,tail,&pcdr.msisdn[1]);
	ByteRev(pcdr.msisdn,9,0);

	pcdr.msisdn[0]=0x91;
	memcpy(pcdr.caller,pcdr.msisdn,9);
    buf[0] = 0;
	sprintf(buf,"FFFFFFFFFFFFFFFFFF");
	AsciiToBcd(pcdr.called,buf,18);
    AsciiToBcd(pcdr.imsi,buf,16);

    pcdr.tcos[0] = NORMAL_CLEARING%256;

	CDRStatistics(&pcdr,charge, 0);
	StoreCDR(&pcdr);

    pps_real_update_user_file(head, tail);

#if DEBUG
	if(debug_messages++<=MAX_DEBUG_MESSAGES)	
   if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
    DebugMsg(debugmib.display.asciiOut, "SendOperatorRechargeCDR");
#endif
}


void SendManualRechargeCDR(_recharge_card_info *shmp)
{
    _tocdr_report  pcdr;

	char            buf[BUFSIZE]={""},
					msisdn[32]="";
    int             balance,head,tail,instance,len;
    int				charge;

	PutLogFunID("SendManualRechargeCDR");

    memset(&pcdr, 0, sizeof(_tocdr_report));

	strcpy(msisdn,shmp->msisdn_used);
    len = strlen(msisdn);
	if(len>MAX_MSISDN_ALEN || len<MIN_MSISDN_ALEN) {
        DebugMsg(debugmib.display.asciiOut,
		"SendManualRechargeCDR to %s failed: length(%d) of msisdn is error",
		shmp->msisdn_used,len);

	   return;
    }
	instance = FindPPSTableIndex(atoll(msisdn));
	if(instance<0)
	{
        DebugMsg(debugmib.display.asciiOut,
		"SendManualRechargeCDR to %s failed: not exist",
			shmp->msisdn_used);
		return;
	}
	head = instance / UNIT_STORE_ACCOUNT;
	tail = instance % UNIT_STORE_ACCOUNT;

    pcdr.mtype   = MO_CDR_TYPE;
	pcdr.type[0] = CT_RECHARGE_SUCCESS;
	pcdr.type[1] = CT_RECHARGE_SUCCESS>>8;
    AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
    pcdr.duration[0] = 0;

	charge = (int)shmp->face_value;
	pcdr.charge[0] = charge;
	pcdr.charge[1] = charge>>8;
	pcdr.charge[2] = charge>>16;
	pcdr.charge[3] = charge>>24;
    UpdateAccountBalance(head, tail,charge);
    UpdateAccountStatus(head, tail,T_NORMAL);
    UpdateAccountExpiration(head,tail,shmp->face_value,shmp->valid_time);
   
    balance = GetAccountBalance(head, tail);
    pcdr.balance[0] = balance;
	pcdr.balance[1] = balance>>8;
	pcdr.balance[2] = balance>>16;
	pcdr.balance[3] = balance>>24;
	len = strlen(msisdn);
    if(len%2==1)
	{
		msisdn[len]='F';
		len ++;
	}

	memset(pcdr.imsi,0xFF,8);
	pcdr.msisdn[0] = 0x91;
	ppsAsciiToBcdR(&pcdr.msisdn[1],msisdn,len);
	pcdr.msisdn[1+len/2]=0xFF;
	memcpy(pcdr.caller,pcdr.msisdn,2+len/2);

    len = shmp->card_no[MAX_CARD_LENGTH];
    BcdToAscii(buf,shmp->card_no,len*2);

	pcdr.called[0] = 0x91;
	ppsAsciiToBcdR(&pcdr.called[1],buf,len);
    pcdr.called[1+len/2] = 0xFF;

    pcdr.tcos[0] = NORMAL_CLEARING%256;

	StoreCDR(&pcdr);

	CDRStatistics(&pcdr,charge, 0);

    pps_real_update_user_file(head, tail);

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
  if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
  {
    DebugMsg(debugmib.display.asciiOut,"SendManualRechargeCDR to %s",shmp->msisdn_used);
	   debug_messages ++;
  }
#endif

}


void
SendPPSGeneralCDR(int head, int tail, int charge, char cdr_type)
{
    _tocdr_report  pcdr;
    char           buf[BUFSIZE]={""}; 
    int			   balance;

    PutLogFunID("SendPPSGeneralCDR");

    memset(&pcdr, 0, sizeof(_tocdr_report));
 
     pcdr.type[0] = cdr_type;
    pcdr.type[1] = cdr_type>>8;
	
    AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
    pcdr.duration[0] = 0;
	charge = abs(charge);
    memcpy(pcdr.charge,&charge,4);
    balance = (int) GetAccountBalance(head, tail);
    memcpy(pcdr.balance,&balance,4);

    GetAccountMsisdn(head,tail,&pcdr.msisdn[1]);
	ByteRev(pcdr.msisdn,9,0);

	pcdr.msisdn[0]=0x91;
	memcpy(pcdr.caller,pcdr.msisdn,9);
    buf[0] = 0;
	sprintf(buf,"FFFFFFFFFFFFFFFFFF");
	AsciiToBcd(pcdr.called,buf,18);
    AsciiToBcd(pcdr.imsi,buf,16);

    pcdr.tcos[0] = NORMAL_CLEARING%256;

	CDRStatistics(&pcdr,charge, 0);
	StoreCDR(&pcdr);

    pps_real_update_user_file(head, tail);

#if DEBUG
	if(debug_messages++<=MAX_DEBUG_MESSAGES)	
   if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
    DebugMsg(debugmib.display.asciiOut, "SendPPSGeneralCDR");
#endif
}

void SendAccountInfoForLowCredit(char *caller,
										long balance,long expired_date,
										long promo,long promo_expired_date)
{
    char expire_date[64];
    char promo_expire_date[64];
    char serviceNumber[BUFSIZE]="";
	
	PutLogFunID("SendAccountInfoForLowCredit");

	strcpy(serviceNumber, (char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number);

	AsciiTime(expire_date,expired_date);
	AsciiTime(promo_expire_date, promo_expired_date);
    smppSendAccountInfo(caller,
						serviceNumber,
						balance,
						expire_date,
						promo,
						promo_expire_date,
						0,"","",0);
    AddPPSStatistics(MIBPPS_ACCOUNTINFO,0);    
}

void SendAccountInfoBySMPP(_account_info *ptr,char *called)
{
	long balance,promotion, expired_date,promo_expired_date;
	_last_call_info	callInfo;
	int		len;
	char msisdn[32];

	char expire_date[64],promotion_expire_date[64]={0};
	char expire_date1[64];

	PutLogFunID("SendAccountInfoBySMPP");

	balance = (int)GetBalanceWithOutPromotion(ptr->head,ptr->tail);
	promotion = (int)GetPromotion(ptr);
	expired_date = GetExpiration(ptr);
	promo_expired_date = GetPromotionExpiration(ptr);
	AsciiTime(expire_date,expired_date);
  	AsciiTime(promotion_expire_date,promo_expired_date);
   
	if(GetAccountLastCallInfo(ptr,&callInfo))
	{
		
		AsciiTime(expire_date1,callInfo.last_call_date);
		len = callInfo.last_call_number[MAX_MSISDN_BLEN-1];
		ppsBcdToAsciiR(msisdn,callInfo.last_call_number,18);
		msisdn[len]  = 0;
				
	    	smppSendAccountInfo((char *)ptr->number,
						called,
						balance,
						expire_date,
						promotion,
						promotion_expire_date,
						callInfo.last_call_type+1,
						expire_date1,
						msisdn,
						ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail].language_type);
	}
	else
	    smppSendAccountInfo((char *)ptr->number,
						called,
						balance,
						expire_date,
						promotion,
						promotion_expire_date,
						0,
						"",
						"",
						ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail].language_type);
    AddPPSStatistics(MIBPPS_ACCOUNTINFO,0);
}

void pps_send_last_call_info(_account_info *user_ptr, int call_type, int charge, int duration)
{
	char sms_content[256];
//	char to_be_replace_str[16][32]={"[Charge]","[Charged Units]","[ACCOUNT BALANCE]","[EXPIRY DATE]"};
	char to_be_replace_str[16][32]={"$C","$D","$B","$E"};
	char charge_str[32],duration_str[32],balance_str[32],expire_str[32];
	int    balance;
	long expired_day;
	
	//SendAccountInfoBySMPP(ptr, ppsParam.ppsTables.serviceNumber[HotLineNumberPosition].number);

	if(call_type == CT_MO_SM )
		strcpy(sms_content, (char *)getSmsSentenceNative(0,SMS_LAST_SMS_INFO));
	else
		strcpy(sms_content, (char *)getSmsSentenceNative(0,SMS_LAST_CALL_INFO));

	balance = GetAccountBalance(user_ptr->head, user_ptr->tail);
	expired_day = GetExpiration(user_ptr);
	AsciiTimeYMDHMS(expire_str,expired_day);
	
	sprintf(charge_str, "%.2f", charge/100.00);
	sprintf(duration_str, "%d", duration);
	sprintf(balance_str, "%.2f", balance/100.00);

	ReplaceStr(sms_content, to_be_replace_str[0], charge_str);
	ReplaceStr(sms_content, to_be_replace_str[1], duration_str);
	ReplaceStr(sms_content, to_be_replace_str[2], balance_str);
	ReplaceStr(sms_content, to_be_replace_str[3], expire_str);

	smppSendMOSM((char *)user_ptr->number, 
		(char *)ppsParam.ppsTables.serviceNumber[HotLineNumberPosition].number, 
		(u_char *)sms_content, strlen(sms_content), 0);
	
}

void SendAccountInfoBySMPPtoThirdParty(_account_info *ptr,char *called, char *third_party_number)
{
	long balance,promotion, expired_date,promo_expired_date;
	//_last_call_info	callInfo;
	//int		len;
	//char msisdn[32];
	char caller[32];
	
	char expire_date[64],promotion_expire_date[64]={0};
	//char expire_date1[64];

	PutLogFunID("SendAccountInfoBySMPP");

	balance = (int)GetBalanceWithOutPromotion(ptr->head,ptr->tail);
	promotion = (int)GetPromotion(ptr);
	expired_date = GetExpiration(ptr);
	promo_expired_date = GetPromotionExpiration(ptr);
	AsciiTime(expire_date,expired_date);
  	AsciiTime(promotion_expire_date,promo_expired_date);

   	if(third_party_number != NULL)
		strcpy(caller, third_party_number);
	else
		strcpy(caller, (char *)ptr->number);
	/*
	if(GetAccountLastCallInfo(ptr,&callInfo))
	{
		AsciiTime(expire_date1,callInfo.last_call_date);
		len = callInfo.last_call_number[MAX_MSISDN_BLEN-1];
		ppsBcdToAsciiR(msisdn,callInfo.last_call_number,18);
		msisdn[len]  = 0;
		smppSendAccountInfo(caller,
						called,
						balance,
						expire_date,
						promotion,
						promotion_expire_date,
						callInfo.last_call_type+1,
						expire_date1,
						msisdn,
						(0x40 | ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail].language_type));
	}
	else
	*/
		smppSendAccountInfo(caller,
						called,
						balance,
						expire_date,
						promotion,
						promotion_expire_date,
						0,
						"",
						(char *)ptr->number,
						(0x40 | ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail].language_type));
    AddPPSStatistics(MIBPPS_ACCOUNTINFO,0);    

}

 char notificationSMS[256]="";
 
char *sendPPSNotificationMessage(int head, int tail, int sms_id)
{
    char buf[32], configuredSMS[256];
    char caller_number[32], called_number[32];
    int    i,counter;
    float currency_rate = 100.0;
    char *buf_ptr[8],tmp_buf[8][32];
    int cos_id, plan_id, tariff_id, rent_id;
    unsigned char bValue=0x01;
    _prepaid_info   *shmp=NULL;

    if(!GetAccountMsisdnStr(head, tail, (u_char *)caller_number)) 
        return 0;
    strcpy(called_number, (char *)ppsParam.ppsTables.ussdServiceNumber[USSD_OC_FRIEND_FAMILY_QUERY].number);
    
    sprintf(configuredSMS,"%s ", getSmsSentenceNative(0,sms_id));

    for(i=0;i<8;i++)
        buf_ptr[i] = tmp_buf[i];

    switch(ppsParam.ppsTables.promptResolution[0].currencyResolution)
    {
        case 0:
        	currency_rate = 1.0;
        break;
        case 1:
        	currency_rate = 10.0;
        break;
        case 2:
        default:
        	currency_rate = 100.0;
        break;
    }
    
    switch(sms_id)
    {
        case SMS_RENT_CHARGE:
        	strcpy(called_number, (char *)ppsParam.ppsTables.serviceNumber[HotLineNumberPosition].number);
        	if(1)
        	{

        	    shmp = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
        	    cos_id = shmp->cos_id;
        	    tariff_id = ppsParam.ppsTables.cosTable[cos_id].tariff[0].moTariffID;
        	    rent_id = shmp->rent_type;
        	    
        	    for(i=0;i<MAX_RENT_TARIFF;i++)
        	    {
        	        if(rent_id & (bValue<<i))
        	        {
        	            sprintf(tmp_buf[0], "%s", ramshm_ptr->tariff_data.rent_tariff[tariff_id][i].description);
        	            sprintf(tmp_buf[1], "%.2f", ramshm_ptr->tariff_data.rent_tariff[tariff_id][i].rent_amount/currency_rate);
                    	     sprintf(notificationSMS, "%s",ppsParseSentence(configuredSMS, 2, buf_ptr));
                    	     smppSendMOSM(caller_number,
                                            called_number, 
                                    	  (u_char *)notificationSMS,
                                         	 strlen(notificationSMS), 0);     
        	        }
        	    }
        	}

        break;
	 case SMS_FRIEND_FAMILY_REG:
	 	if(1)
	 	{
	
        	    shmp = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
        	    cos_id = shmp->cos_id;
        	    plan_id = shmp->favorite_plan_id - 1;
        	    tariff_id = ppsParam.ppsTables.cosTable[cos_id].tariff[0].moTariffID;
        	    rent_id = ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0].friendFamilyPlan[plan_id].rentID - 1;
        	    
        	    sprintf(tmp_buf[0], "%.2f", ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0].friendFamilyPlan[plan_id].rentCharge/currency_rate);        	    
        	    sprintf(tmp_buf[1], "%.2f", ramshm_ptr->tariff_data.rent_tariff[tariff_id][rent_id].rent_amount/currency_rate);
        	    if( ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0].friendFamilyPlan[plan_id].freeCallDuration>0)
            	        sprintf(tmp_buf[2], "%d", ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0].friendFamilyPlan[plan_id].freeCallDuration);        	    
        	    else
        	    	sprintf(tmp_buf[2], "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NO_LIMIT));
        	    if(ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0].friendFamilyPlan[plan_id].freeSMS>0)
            	        sprintf(tmp_buf[3], "%d", ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0].friendFamilyPlan[plan_id].freeSMS);            	    
        	    else
        	    	 sprintf(tmp_buf[3], "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NO_LIMIT));           	    
	 	}
	 	sprintf(notificationSMS, "%s",ppsParseSentence(configuredSMS, 4, buf_ptr));
	 break;
	 case SMS_FRIEND_FAMILY_REG_FAILED:
	 	strcpy(notificationSMS, configuredSMS);
	 break;
	 case SMS_FRIEND_FAMILY_SERVICE_SUSPEND:
	 	strcpy(notificationSMS, configuredSMS);	 	
	 break;
	 case SMS_FRIEND_FAMILY_PLAN_EXHAUST:
	 	strcpy(notificationSMS, configuredSMS);	 	
	 break;
	 case SMS_FRIEND_FAMILY_QUERY:
	     shmp = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
	     sprintf(tmp_buf[0], "%d", shmp->favorite_numbers);
            counter = 1;
            for(i=0;i<MAX_FAVORITE_NUMBERS;i++)
            {
                if(shmp->favorite_number[i][MAX_MSISDN_BLEN-1]>3)
                {   
                    sprintf(tmp_buf[counter], "#%d: ", i);
                    MsisdnToAscii(buf, shmp->favorite_number[i]);
                    strcat(tmp_buf[counter++], buf);
                }
            }
            sprintf(notificationSMS,"%s", ppsParseSentence((char *)getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NOT_PLAN), counter, buf_ptr));
	 break;
	 case SMS_FRIEND_FAMILY_SERIVCE_REACTIVATE:
	 	strcpy(notificationSMS, configuredSMS);	 	
	 break;
	 case SMS_FRIEND_FAMILY_REMOVE:
	 	strcpy(notificationSMS, configuredSMS);
	 break;
    }

    if(sms_id != SMS_RENT_CHARGE)
        smppSendMOSM(caller_number,
            called_number, 
	     (u_char *)notificationSMS,
	     strlen(notificationSMS),	0);     
    
    return notificationSMS;
}

int pps_get_subid()
{
    return subSystemID;
}

/*----------------------- supplementary functions -------------------*/
extern pthread_mutex_t pps_mtx;
int AssignProcID(int gy_flag)
{
	static u_short roIdlePort = 0;// Ro handle port [0, 2K)
	static u_short gyIdlePort = MAX_RO_FSM_PROCESS;// Gy Handle port [2K, 10K)
	_state_data    *shmp = NULL;
	int i, retPort = -1;

	PutLogFunID("AssignProcID");

	pthread_mutex_lock( &pps_mtx );// mutex lock=================
	if (gy_flag)
	{
		for (i=0; i<MAX_GY_FSM_PROCESS; i++)
		{
			gyIdlePort ++;
			if (gyIdlePort >= MAX_FSM_PROCESS)
			{
				gyIdlePort = MAX_RO_FSM_PROCESS;// the first handle port of Gy
			}
			
			if(smshm_ptr->port_info[gyIdlePort].status == 0x00)
			{
				smshm_ptr->port_info[gyIdlePort].status = 0x01;
				debugmib.display.proc_used ++;
				debugmib.display.gy_used ++;

				shmp =(_state_data *)&smshm_ptr->state_data;
				shmp += gyIdlePort;
				
				memset(shmp,0,sizeof(_state_data));

				retPort = gyIdlePort;
				break;
			}
		}
	}
	else
	{
		for (i=0; i<MAX_RO_FSM_PROCESS; i++)
		{
			roIdlePort ++;
			if (roIdlePort >= MAX_RO_FSM_PROCESS)
			{
				roIdlePort = 0;
			}
			
			if(smshm_ptr->port_info[roIdlePort].status == 0x00)
			{
				smshm_ptr->port_info[roIdlePort].status = 0x01;
				debugmib.display.proc_used ++;
				debugmib.display.ro_used ++;

				shmp =(_state_data *)&smshm_ptr->state_data;
				shmp += roIdlePort;
				
				memset(shmp,0,sizeof(_state_data));

				retPort = roIdlePort;
				break;
			}
		}
	}

	pthread_mutex_unlock( &pps_mtx );// mutex unlock=================

	if (retPort >= 0)
	{
		return retPort;
	}

	ListAllPortStatus(1);
	return -1;
}

int ReleasePortStatus(u_short invoke_id)
{
	pthread_mutex_lock( &pps_mtx );// mutex lock=================
	if(invoke_id<MAX_FSM_PROCESS )
	{
		if(smshm_ptr->port_info[invoke_id].status == 0x01)
		{
			smshm_ptr->port_info[invoke_id].status = 0x00;
			debugmib.display.proc_used --;

			if (invoke_id < MAX_RO_FSM_PROCESS)
			{
				debugmib.display.ro_used--;
			}
			else
			{
				debugmib.display.gy_used--;
			}
		}
		else
		{
			smshm_ptr->port_info[invoke_id].status = 0x00;			
			debugmib.display.proc_begin[0]++;
		}
	}
	if(debugmib.display.proc_used>=MAX_FSM_PROCESS)
			debugmib.display.proc_used = 0;
	pthread_mutex_unlock( &pps_mtx );// mutex unlock=================

	return 1;
}

int ByteToAscii(char *ascii, BYTE *byte, int len)
{
	int i;
	for(i=0;i<len;i++)
	{
	  sprintf(&ascii[2*i],"%02X",byte[i]);
	}
	return 0;
}

int PutLogFunID(char  *func_name)
{
	if (!ppsParam.serviceControl.log_func_flag)// do not log func for thread safe
	{
		return -1;
	}

	int ptr;
	
	ptr = smshm_ptr->func_log.funcID % MAX_LOG_FUNC;

	snprintf(smshm_ptr->func_log.func_name[ptr], 63, "%02d : %s", ptr, func_name);
	smshm_ptr->func_log.funcID = (ptr+1)%(MAX_LOG_FUNC);
	return 1;
}


int log_warning(char *warning, u_short portid)
{
	_state_data	*shmp=(_state_data *)&smshm_ptr->state_data;
	int			dlgid;

	shmp += portid;
	dlgid  = shmp->context_info.dialogue_id;
	
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x01))
	{
		DebugMsgDelimiter();
		DebugMsg(debugmib.display.asciiOut,
			"Warning: p[%04d].d[%04d] <%s>@<%ld.%06ld>",
			portid,dlgid,warning,tvnow.tv_sec,tvnow.tv_usec);
	}

	return 1;
}

int	log_recv_message(void *ptr, u_char *msg_name,u_short portid,u_char first_message)
{
	_state_data	*shmp=(_state_data *)&smshm_ptr->state_data;
	int			dlgid;
	
	shmp += portid;
	dlgid  = shmp->context_info.dialogue_id;
	
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		DebugMsgDelimiter();
		if(first_message)
			DebugMsg(debugmib.display.asciiOut,
				"p[%04d].d[%04d] --> cap message <%s>@<%ld.%06ld>",
				portid,shmp->context_info.dialogue_id,msg_name,tvnow.tv_sec,tvnow.tv_usec);
		else
			DebugMsg(debugmib.display.asciiOut,
				"p[%04d].d[%04d] --> cap message <%s>@<%ld.%06ld>",
				portid,dlgid,msg_name,tvnow.tv_sec,tvnow.tv_usec);
		ppsDebugCapMsg((CAP_Message *)ptr,0);
	}

	return 1;
}

int	log_send_message(void *ptr, u_char *msg_name,u_short portid,u_char first_message)
{
	_state_data	*shmp=(_state_data *)&smshm_ptr->state_data;
	int			dlgid;

	shmp += portid;
	dlgid  = shmp->context_info.dialogue_id;
	
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{
		DebugMsgDelimiter();
		if(first_message)
			DebugMsg(debugmib.display.asciiOut,
				"p[%04d].d[%04d] <-- cap message <%s>@<%ld.%06ld>",
				portid,shmp->context_info.dialogue_id,msg_name,tvnow.tv_sec,tvnow.tv_usec);
		else
			DebugMsg(debugmib.display.asciiOut,
				"p[%04d].d[%04d] <-- cap message <%s>@<%ld.%06ld>",
				portid,dlgid,msg_name,tvnow.tv_sec,tvnow.tv_usec);
		ppsDebugCapMsg((CAP_Message *)ptr,0);
	}

	return 1;
}
