FreeCalypso > hg > fc-magnetite
view src/aci2/aci/cmh_smsr.c.orig @ 204:e2714de970a4
TCS2/TCS3 hybrid config links after adding cl.lib
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 14 Oct 2016 06:21:03 +0000 |
parents | 93999a60b835 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GSM-PS (6147) | Modul : CMH_SMSR +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : This module defines the functions which are responsible | for the responses of the protocol stack adapter for | the short message service. +----------------------------------------------------------------------------- */ #ifndef CMH_SMSR_C #define CMH_SMSR_C #endif #include "aci_all.h" /*==== INCLUDES ===================================================*/ #include "aci_cmh.h" #include "ati_cmd.h" #include "aci_cmd.h" #ifdef FAX_AND_DATA #include "aci_fd.h" #endif /* of #ifdef FAX_AND_DATA */ #ifdef UART #include "dti.h" #include "dti_conn_mng.h" #endif #include "aci.h" #include "aci_lst.h" #include "aci_mem.h" #include "psa.h" #include "psa_sms.h" #include "psa_mmi.h" #include "psa_cc.h" #include "cmh.h" #include "cmh_sms.h" #include "psa_sim.h" #include "cmh_sim.h" #include "psa_util.h" #include "Phb.h" #ifdef SIM_TOOLKIT #include "psa_sat.h" #include "cmh_sat.h" #endif /* of SIM_TOOLKIT */ #if (defined (MFW) AND !defined (FF_MMI_RIV)) OR defined (_CONC_TESTING_) OR defined (SMI) #include "conc_sms.h" #endif /* ##if (defined (MFW) AND !defined (FF_MMI_RIV)) OR defined (_CONC_TESTING_) OR defined (SMI)*/ #ifdef _CONC_TESTING_ #include "aci_mfw.h" #endif /*==== CONSTANTS ==================================================*/ /* TP-User-Data-Header-Indicator (TP-UDHI) */ #define UDHI_MASK 0x40 #define UDHI_PRESENT 0x40 #define UDHI_ABSENT 0x00 /*==== TYPES ======================================================*/ /*==== EXPORT =====================================================*/ /*==== VARIABLES ==================================================*/ EXTERN T_ACI_LIST *set_prm_list; /*==== FUNCTIONS ==================================================*/ LOCAL BOOL cmhSMS_cpySTtoSM(T_ACI_CMGL_SM *p_sm,T_MNSMS_READ_CNF * mnsms_read_cnf); /* help function for cmhSMS_SMRead to inform user in case of * CCD decoding error with SMS * for this case the T_ACI_SMS_STAT has been extended with a value * of SMS_STAT_Invalid = -2 (e.g to tell BMI to emit "INVALID MESSAGE") */ LOCAL void cmhSMS_invalidSMS_notification_to_user(T_MNSMS_READ_CNF * mnsms_read_cnf) { UBYTE idx = 0; T_ACI_AT_CMD cmdBuf = smsShrdPrm.smsEntStat.curCmd; T_ACI_CMD_SRC ownBuf = smsShrdPrm.smsEntStat.entOwn; TRACE_FUNCTION ("cmhSMS_SMRead_invalidSMS_notification_to_user()"); if (smsShrdPrm.pDecMsg->stat EQ SMS_STAT_Invalid) { switch( smsShrdPrm.smsEntStat.curCmd ) { case ( AT_CMD_CMGR ): { smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; if (smsShrdPrm.rplyCB.cmgr NEQ NULL) { smsShrdPrm.rplyCB.cmgr( smsShrdPrm.pDecMsg, NULL ); } R_AT ( RAT_OK, ownBuf) ( cmdBuf ); break; } case ( AT_CMD_CMGL ): { R_AT ( RAT_CMGL, smsShrdPrm.smsEntStat.entOwn ) ( smsShrdPrm.pDecMsg ); /* intermediate result */ if (mnsms_read_cnf->rec_next NEQ SMS_RECORD_NOT_EXIST) { psaSMS_ReadReq ( smsShrdPrm.mem1, mnsms_read_cnf->rec_next, smsShrdPrm.rdMode, cmglStat ); } break; } } } else { /* * SMS decoding failed, but the status has not been set to SMS_STAT_Invalid */ TRACE_FUNCTION ("cmhSMS_SMRead_invalidSMS_notification_to_MFW(): [ERR] status not SMS_STAT_Invalid !"); } } #ifdef SIM_TOOLKIT LOCAL void cmhSMS_SATResult (T_ACI_SAT_TERM_RESP *p_resp_data, USHORT cause) { if (GET_CAUSE_ORIGIN_ENTITY(cause) EQ SMSCP_ORIGINATING_ENTITY) { /* CP-CAUSE */ p_resp_data->add_content = GET_CAUSE_VALUE(cause) | 0x80; psaSAT_SendTrmResp( RSLT_NTW_UNAB_PROC, p_resp_data ); } else { /* RP-CAUSE or other */ if (GET_CAUSE_ORIGIN_ENTITY(cause) EQ SMSRP_ORIGINATING_ENTITY) p_resp_data->add_content = GET_CAUSE_VALUE(cause); else p_resp_data->add_content = ADD_NO_CAUSE; psaSAT_SendTrmResp( RSLT_SMS_ERR, p_resp_data); } } #endif /* #ifdef SIM_TOOLKIT */ /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_CBMIndication | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of the receiving of a cell broadcast message. */ GLOBAL SHORT cmhSMS_CBMIndication ( T_MMI_CBCH_IND * mmi_cbch_ind ) { USHORT sn; /* serial number */ USHORT mid; /* message identifier */ UBYTE dcs; /* data coding scheme */ UBYTE page; /* actual page number */ UBYTE pages; /* total number of pages */ T_ACI_CBM_DATA msg; /* cell broadcast message data */ UBYTE idx; TRACE_FUNCTION ("cmhSMS_CBMIndication ()"); /* *----------------------------------------------------------------- * process parameters for new message indication *----------------------------------------------------------------- */ sn = ( ( SHORT )mmi_cbch_ind->cbch_msg[0] << 8 ) + mmi_cbch_ind->cbch_msg[1]; mid = ( ( SHORT )mmi_cbch_ind->cbch_msg[2] << 8 ) + mmi_cbch_ind->cbch_msg[3]; dcs = mmi_cbch_ind->cbch_msg[4]; page = ( mmi_cbch_ind->cbch_msg[5] & 0xF0 ) >> 4; pages = ( mmi_cbch_ind->cbch_msg[5] & 0x0F ); /* *----------------------------------------------------------------- * process message data, expanding from 7 to 8 bit *----------------------------------------------------------------- */ cmhSMS_expdSmsCb ( dcs, &mmi_cbch_ind->cbch_msg[CBCH_HEAD_LEN], (UBYTE)(mmi_cbch_ind->cbch_len - CBCH_HEAD_LEN), msg.data, &msg.len ); /* *----------------------------------------------------------------- * new message indication *----------------------------------------------------------------- */ #ifdef FF_MMI_RIV { T_ACI_CMGF_MOD sms_input_mode = CMGF_MOD_NotPresent; qAT_PlusCMGF (CMD_SRC_LCL, &sms_input_mode); if (sms_input_mode EQ CMGF_MOD_Pdu) { rAT_PlusCBMPdu (mmi_cbch_ind); } else { R_AT( RAT_CBM, CMD_SRC_LCL ) ( sn, mid, dcs, page, pages, &msg ); } } #else R_AT( RAT_CBM, CMD_SRC_LCL ) ( sn, mid, dcs, page, pages, &msg ); #endif /* If the SMS shared params indicate no valid source interested in * the SMS indications, the indication is buffered */ /* Issue 25033 */ if( smsShrdPrm.smsSrcId EQ CMD_SRC_NONE ) { #ifdef DTI T_CNMI_IND ind; memcpy (&ind.cbm, mmi_cbch_ind, sizeof(T_MMI_CBCH_IND)); cmd_addCnmiNtry ( CNMI_CBM, &ind ); #endif } else { #ifdef FF_ATI /* tell any remote source */ for( idx = CMD_SRC_LCL+1; idx < CMD_SRC_MAX; idx++ ) { if (IS_SRC_USED (idx)) { R_AT( RAT_CBM, idx ) ( mmi_cbch_ind ); } } #endif } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSInitState | +-------------------------------------------------------------------+ PURPOSE : This function is used to handle the SMS_STATE_INITIALISING state. */ GLOBAL SHORT cmhSMS_SMSInitState ( T_MNSMS_MESSAGE_IND * mnsms_message_ind ) { #if defined SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ T_ACI_CMGL_SM sm; T_ACI_SMS_STOR mem; /* holds message storage */ UBYTE retCode = TRUE; UBYTE msg_type; #endif /* SMI OR defined MFW */ #ifdef _CONC_TESTING_ #ifndef NTRACE char trcBuf[80]; char *writeP; int count; USHORT offset; TRACE_EVENT_P1("initstate:rec_num: %d", mnsms_message_ind->rec_num); TRACE_EVENT_P1("initstate:status: %d", mnsms_message_ind->status); offset = mnsms_message_ind->sms_sdu.o_buf>>3; writeP = trcBuf; for (count=offset; count<offset+20; count++) { writeP += sprintf (writeP, " %02X", mnsms_message_ind->sms_sdu.buf[count]); } TRACE_EVENT("buf: "); *writeP = '\0'; TRACE_EVENT(trcBuf); writeP = trcBuf; for (; count<offset+40; count++) { writeP += sprintf (writeP, " %02X", mnsms_message_ind->sms_sdu.buf[count]); } *writeP = '\0'; TRACE_EVENT(trcBuf); #endif #endif TRACE_FUNCTION ("cmhSMS_SMSInitState()"); switch (mnsms_message_ind->mem_type) { case MEM_ME: if (mnsms_message_ind->rec_num NEQ SMS_RECORD_NOT_EXIST) { smsShrdPrm.aci_sms_parameter.meUsed++; } if (smsShrdPrm.aci_sms_parameter.meTotal EQ 0) { smsShrdPrm.aci_sms_parameter.meTotal = mnsms_message_ind->rec_max; } break; case MEM_SM: if (mnsms_message_ind->rec_num NEQ SMS_RECORD_NOT_EXIST) { smsShrdPrm.aci_sms_parameter.simUsed++; TRACE_EVENT_P1("simUsed: %d", smsShrdPrm.aci_sms_parameter.simUsed); } if (smsShrdPrm.aci_sms_parameter.simTotal EQ 0) { smsShrdPrm.aci_sms_parameter.simTotal = mnsms_message_ind->rec_max; TRACE_EVENT_P1("simTotal: %d", smsShrdPrm.aci_sms_parameter.simTotal); } break; default: TRACE_EVENT("wrong memtype"); } #if defined SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ cmhSMS_getMemCmh ( mnsms_message_ind->mem_type, &mem ); cmhSMS_SMSQueryType (&mnsms_message_ind->sms_sdu , &msg_type); memset(&sm,0,sizeof(T_ACI_CMGL_SM) ); if(msg_type NEQ TP_MTI_SMS_STATUS_REP) { retCode = cmhSMS_cpyMsgInd ( &sm, mnsms_message_ind); } if (retCode EQ FALSE) { TRACE_EVENT("cmhSMS_SMSInitState():[ERR] decoding of SMS"); if (sm.stat NEQ SMS_STAT_Invalid) { TRACE_EVENT("cmhSMS_SMSInitState():[ERR] SMS decoding failed, but status not SMS_STAT_Invalid"); } } #if defined FF_MMI_RIV /* in case of RIV MMI: check if SMBS is enabled for sending also PDU data */ if(smsShrdPrm.perccmgf_smbs_mode EQ PERC_SMBS_MOD_ENABLE) { rAT_PlusCMTPdu (mnsms_message_ind); } #endif /* FF_MMI_RIV */ R_AT( RAT_CMTI, CMD_SRC_LCL ) (mem, sm.msg_ref, &sm); #endif /* defined SMI OR defined MFW OR defined FF_MMI_RIV */ return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSDelCnf | +-------------------------------------------------------------------+ PURPOSE : This function is used to handle MNSMS_DELETE_CNF primitive. */ GLOBAL SHORT cmhSMS_SMSDelCnf ( T_MNSMS_DELETE_CNF * mnsms_delete_cnf ) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ T_ACI_CMD_SRC srcId; /* Hold the request Source ID */ #ifdef _CONC_TESTING_ T_CONC_INIT_RETURN ret; #endif TRACE_FUNCTION ("cmhSMS_SMSDelCnf()"); /*-------------------------------------------------------------------------* * In R99 one more flag is added in CMGD command which is used to delete * * multiple messages of the same status ( READ, UNSENT, SENT etc ). * * For this purpose the setting of global variables are done, once * * the it is confirmed that all the messages of the same status are * * deleted. * *-------------------------------------------------------------------------*/ cmdBuf = smsShrdPrm.smsEntStat.curCmd; ownBuf = smsShrdPrm.smsEntStat.entOwn; srcId = smsShrdPrm.smsEntStat.entOwn; #if defined SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ SET_OWNBUF_CONC; #endif /*#if defined SMI OR defined MFW*/ if(smsShrdPrm.status > CMGD_DEL_INDEX) { ownBuf = smsShrdPrm.smsEntStat.entOwn; } if (IS_CAUSE_INVALID(mnsms_delete_cnf->cause)) /* no error */ { /* Check if the mnsms_delete_req for deleting messages of particular status returned indicating no messages of requested status. Note that in this case also we return OK to the user */ if(mnsms_delete_cnf->rec_num NEQ 0) { switch (mnsms_delete_cnf->mem_type) { case MEM_ME: smsShrdPrm.aci_sms_parameter.meUsed--; break; case MEM_SM: smsShrdPrm.aci_sms_parameter.simUsed--; break; default: TRACE_EVENT("wrong memtype"); return AT_FAIL; } } /*-----------------------------------------------------------------------* * The below code is the new code added on 07/08/2003 due to the new * * flag for CMGD command as mentioned in R99. This flag handles the * * deletion of multiple messages. The deletion of concatination is * * handled with different way other than handling normal indexed * * messages. The deletion of normal concatination messages is done as * * in the exiting code. But deletion of concatination message is handled * * in the different way when delete flag is greater than ZERO. If the * * delete flag in CMGD command is greater than ZERO, then there is no * * concatination check is done. After receiving the response from SMS * * with the deleted messages number, then we will do the concatination * * check. If CONC_NEEDED flag is set, then we will clear the * * concatinated list from the ACI. If CONC_NOT_NEEDED is set then check * * for the next record values, if it is greater than ZERO then send one * * more request for SMS to delete that message and repeat the above * * process untill ACI recive's the next record values as ZERO. * *-----------------------------------------------------------------------*/ if( smsShrdPrm.status > CMGD_DEL_INDEX AND mnsms_delete_cnf->rec_num NEQ 0) { #ifdef _CONC_TESTING_ /*-----------------------------------------------------------------* * Check for the concatination * *-----------------------------------------------------------------*/ ret= concSMS_initDeleteFromMem (srcId, mnsms_delete_cnf->rec_num); if( ret EQ CONC_NEEDED ) { SET_CONC; concSMS_DeleteConcList(); } #endif if ( mnsms_delete_cnf->delete_rec_next NEQ 0 ) { cmhSMS_SendDelete_Req (mnsms_delete_cnf->delete_rec_next, smsShrdPrm.status); return 0; } } /*-----------------------------------------------------------------------* * Reset the command context * *-----------------------------------------------------------------------*/ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = CMD_SRC_NONE; smsShrdPrm.owner = OWN_NONE; /*-----------------------------------------------------------------------* * The below code is used to handle the existing way where there is no * * delete falg is set ( i.e. delete flag == 0 ) * *-----------------------------------------------------------------------*/ #if defined SMI OR defined MFW OR defined FF_MMI_RIV if (ownBuf EQ CMD_SRC_LCL) { if( smsShrdPrm.status EQ CMGD_DEL_INDEX ) { #ifdef _CONC_TESTING_ if (!ISSET_CONC) { #endif /* _CONC_TESTING_ */ TRACE_EVENT("you just erased a normal SMS !"); if(smsShrdPrm.rplyCB.cmgd NEQ NULL) { smsShrdPrm.rplyCB.cmgd( ); } R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #ifdef _CONC_TESTING_ } else { /*-----------------------------------------------------------------* * Looks just about the same BUT: ISSET_CONC could be unsent * * in RAT_CMGD, so let this after checking ISSET_CONC * *-----------------------------------------------------------------*/ if(smsShrdPrm.rplyCB.cmgd NEQ NULL) { smsShrdPrm.rplyCB.cmgd( ); } } #endif /* _CONC_TESTING_ */ } else { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); if(smsShrdPrm.rplyCB.cmgd NEQ NULL) { smsShrdPrm.rplyCB.cmgd( ); } #if defined FF_MMI_RIV R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #else /* GPF-MMI */ #ifdef _CONC_TESTING_ if (!ISSET_CONC) #endif /* _CONC_TESTING_ */ R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } #endif } else /* if (ownBuf EQ CMD_SRC_LCL) */ #endif /*defined MFW OR defined FF_MMI_RIV*/ { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } } else { /*-----------------------------------------------------------------------* * Reset the command context * *-----------------------------------------------------------------------*/ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = CMD_SRC_NONE; smsShrdPrm.owner = OWN_NONE; if (smsShrdPrm.errorCB NEQ NULL) { smsShrdPrm.errorCB ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_delete_cnf->cause), NULL ); } else { R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_delete_cnf->cause), NULL ); } } /* Reset status flag to CMGD_DEL_INDEX = 0 */ smsShrdPrm.status = CMGD_DEL_INDEX; return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSStoCnf | +-------------------------------------------------------------------+ PURPOSE : This function is used to handle MNSMS_STORE_CNF primitive. */ GLOBAL SHORT cmhSMS_SMSStoCnf ( T_MNSMS_STORE_CNF * mnsms_store_cnf ) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ TRACE_FUNCTION ("cmhSMS_SMSStoCnf()"); /* *----------------------------------------------------------------- * reset the command context *----------------------------------------------------------------- */ cmdBuf = smsShrdPrm.smsEntStat.curCmd; smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; ownBuf = smsShrdPrm.smsEntStat.entOwn; #ifdef _CONC_TESTING_ /* this is only for testing */ SET_OWNBUF_CONC; #endif smsShrdPrm.smsEntStat.entOwn = CMD_SRC_NONE; smsShrdPrm.owner = OWN_NONE; /* Check for current cmd is CMGMDU */ if ( cmdBuf EQ AT_CMD_P_CMGMDU ) { if (IS_CAUSE_INVALID(mnsms_store_cnf->cause)) { #if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (ownBuf EQ CMD_SRC_LCL) { if(smsShrdPrm.rplyCB.cmgmdu NEQ NULL) { smsShrdPrm.rplyCB.cmgmdu(); } } else #endif /*#if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ */ { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } } else { if ( ownBuf NEQ CMD_SRC_LCL ) R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_store_cnf->cause), NULL ); return -1; } } else if (IS_CAUSE_INVALID(mnsms_store_cnf->cause)) { switch (mnsms_store_cnf->mem_type) { case MEM_ME: smsShrdPrm.aci_sms_parameter.meUsed++; break; case MEM_SM: smsShrdPrm.aci_sms_parameter.simUsed++; break; default: TRACE_EVENT("incorrect memtype"); return AT_FAIL; } #ifdef FF_ATI /* "internal storage" handling -> storing from CNMI-buf to SIM/MS */ if( smsShrdPrm.uiInternalSmsStorage NEQ CMD_SRC_NONE ) { if(mnsms_store_cnf->cause NEQ SMS_NO_ERROR) { TRACE_EVENT("cmhSMS_SMSStoCnf() : error at internal SMS storaging"); cmd_clearCnmiBuf(); /* clear CNMI buffer */ smsShrdPrm.uiInternalSmsStorage = CMD_SRC_NONE; return -1; } /* storing was succesful -> clear the stored msg. in CNMI buf */ cmd_clearFirstCnmiMessage(); /* try with the next msg. in CNMI-buf */ if( cmd_storeNextCnmiBufMsgToSim() NEQ TRUE ) /* do nothing if no more Msg's in CNMI buffer */ { /* no more messagees could be sent */ smsShrdPrm.uiInternalSmsStorage = CMD_SRC_NONE; } return 0; /* returns immediately if internal storage is running */ } #endif /* FF_ATI */ #if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (ownBuf EQ CMD_SRC_LCL) { if(smsShrdPrm.rplyCB.cmgw NEQ NULL) { smsShrdPrm.rplyCB.cmgw( mnsms_store_cnf->rec_num, 1 ); } #if defined FF_MMI_RIV R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #else /* GPF-MMI */ if (!ISSET_CONC) { TRACE_EVENT("you just wrote a normal SMS !"); R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } #endif /*#if !defined FF_MMI_RIV*/ } else #endif /*#if defined MFW OR defined FF_MMI_RIV*/ { R_AT ( RAT_CMGW, ownBuf ) ( mnsms_store_cnf->rec_num ); R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); /* inform BMI */ cmh_logRslt ( ownBuf, RAT_OK, AT_CMD_CMGW, mnsms_store_cnf->rec_num, -1, -1 ); } } else { if( smsShrdPrm.uiInternalSmsStorage NEQ CMD_SRC_NONE ) { smsShrdPrm.uiInternalSmsStorage = CMD_SRC_NONE; return 0; } if (ownBuf EQ CMD_SRC_LCL) { if (smsShrdPrm.errorCB NEQ NULL) { smsShrdPrm.errorCB ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_store_cnf->cause), NULL ); } } else { R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_store_cnf->cause), NULL ); } } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSSbmCnf | +-------------------------------------------------------------------+ PURPOSE : This function is used to handle MNSMS_SUBMIT_CNF primitive. */ GLOBAL SHORT cmhSMS_SMSSbmCnf ( T_MNSMS_SUBMIT_CNF * mnsms_submit_cnf ) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ #ifdef SIM_TOOLKIT T_ACI_SAT_TERM_RESP resp_data; #endif #ifdef _CONC_TESTING_ #ifndef NTRACE char trcBuf[80]; char *writeP; int count; USHORT offset; TRACE_EVENT_P1("cause: %d", mnsms_submit_cnf->cause); offset = mnsms_submit_cnf->sms_sdu.o_buf>>3; writeP = trcBuf; for (count=offset; count<offset+20; count++) { writeP += sprintf (writeP, " %02X", mnsms_submit_cnf->sms_sdu.buf[count]); } TRACE_EVENT("buf: "); *writeP = '\0'; TRACE_EVENT(trcBuf); writeP = trcBuf; for (; count<offset+40; count++) { writeP += sprintf (writeP, " %02X", mnsms_submit_cnf->sms_sdu.buf[count]); } *writeP = '\0'; TRACE_EVENT(trcBuf); #endif #endif TRACE_FUNCTION ("cmhSMS_SMSSbmCnf()"); /* *----------------------------------------------------------------- * reset the command context *----------------------------------------------------------------- */ cmdBuf = smsShrdPrm.smsEntStat.curCmd; smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; ownBuf = smsShrdPrm.smsEntStat.entOwn; #ifdef _CONC_TESTING_ /* this is only for testing */ SET_OWNBUF_CONC; #endif smsShrdPrm.smsEntStat.entOwn = CMD_SRC_NONE; smsShrdPrm.owner = OWN_NONE; #ifdef SIM_TOOLKIT psaSAT_InitTrmResp( &resp_data ); #endif if (IS_CAUSE_INVALID(mnsms_submit_cnf->cause)) { smsShrdPrm.aci_sms_parameter.snd_msg_ref = mnsms_submit_cnf->tp_mr; switch (cmdBuf) { case( AT_CMD_CMSS ): #if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (ownBuf EQ CMD_SRC_LCL) { if(smsShrdPrm.rplyCB.cmss NEQ NULL) { smsShrdPrm.rplyCB.cmss( mnsms_submit_cnf->tp_mr, 1 ); } #if defined FF_MMI_RIV R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #else if (!ISSET_CONC) { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } #endif /* FF_MMI_RIV */ } else /* if (ownBuf EQ CMD_SRC_LCL) */ #endif /*#if defined MFW OR defined FF_MMI_RIV*/ { R_AT ( RAT_CMSS, ownBuf ) ( mnsms_submit_cnf ); R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); /* inform BMI */ cmh_logRslt ( ownBuf, RAT_OK, AT_CMD_CMSS, mnsms_submit_cnf->rec_num, -1, -1 ); } break; case( AT_CMD_CMGS ): #if defined (SIM_TOOLKIT) if (ownBuf EQ OWN_SAT) { psaSAT_SendTrmResp( RSLT_PERF_SUCCESS, &resp_data ); break; } #endif if (mnsms_submit_cnf->rec_num NEQ SMS_RECORD_NOT_EXIST) { switch (mnsms_submit_cnf->mem_type) { case MEM_ME: smsShrdPrm.aci_sms_parameter.meUsed++; break; case MEM_SM: smsShrdPrm.aci_sms_parameter.simUsed++; break; default: TRACE_EVENT("incorrect memtype"); return AT_FAIL; } } #if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (ownBuf EQ CMD_SRC_LCL) { if(smsShrdPrm.rplyCB.cmgs NEQ NULL) { smsShrdPrm.rplyCB.cmgs( mnsms_submit_cnf->tp_mr, 1 ); } #if defined FF_MMI_RIV R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #else if (!ISSET_CONC) { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } #endif /* FF_MMI_RIV */ } else /* if (ownBuf EQ CMD_SRC_LCL) */ #endif /*#if defined MFW OR defined FF_MMI_RIV*/ { R_AT ( RAT_CMGS, ownBuf ) ( mnsms_submit_cnf ); R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); /* inform BMI */ cmh_logRslt ( ownBuf, RAT_OK, AT_CMD_CMGS, mnsms_submit_cnf->rec_num, -1, -1 ); } } /* switch */ } else /* if (mnsms_submit_cnf->rslt_type EQ SMS_RT_NON) */ { #if defined (SIM_TOOLKIT) if (ownBuf EQ OWN_SAT) { cmhSMS_SATResult (&resp_data, mnsms_submit_cnf->cause); } #endif /* MSMSMS */ if (ownBuf EQ CMD_SRC_LCL) { if (smsShrdPrm.errorCB NEQ NULL) { smsShrdPrm.errorCB ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_submit_cnf->cause), NULL ); } } else { R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_submit_cnf->cause), NULL ); } } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSCmdCnf | +-------------------------------------------------------------------+ PURPOSE : This function is used to handle MNSMS_COMMAND_CNF primitive. */ GLOBAL SHORT cmhSMS_SMSCmdCnf ( T_MNSMS_COMMAND_CNF * mnsms_command_cnf ) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ #ifdef SIM_TOOLKIT T_ACI_SAT_TERM_RESP resp_data; psaSAT_InitTrmResp( &resp_data ); #endif TRACE_FUNCTION ("cmhSMS_SMSCmdCnf()"); /* *----------------------------------------------------------------- * reset the command context *----------------------------------------------------------------- */ cmdBuf = smsShrdPrm.smsEntStat.curCmd; smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; ownBuf = smsShrdPrm.smsEntStat.entOwn; smsShrdPrm.smsEntStat.entOwn = CMD_SRC_NONE; smsShrdPrm.owner = OWN_NONE; if (IS_CAUSE_INVALID(mnsms_command_cnf->cause)) { #ifdef _CONC_TESTING_ /* this is only for testing */ SET_OWNBUF_CONC; #endif #if defined (SIM_TOOLKIT) if (ownBuf EQ OWN_SAT) { psaSAT_SendTrmResp( RSLT_PERF_SUCCESS, &resp_data ); } #endif #if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (ownBuf EQ CMD_SRC_LCL) { if(smsShrdPrm.rplyCB.cmgc NEQ NULL) { smsShrdPrm.rplyCB.cmgc( mnsms_command_cnf->tp_mr ); } #if defined FF_MMI_RIV R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #else if (!ISSET_CONC) { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } #endif /*!defined FF_MMI_RIV*/ } else /* if (ownBuf EQ CMD_SRC_LCL) */ #endif /*defined MFW OR defined FF_MMI_RIV*/ { R_AT ( RAT_CMGC, ownBuf ) ( mnsms_command_cnf ); R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); /* inform BMI */ /* This does not make much sense, but nice to have it for future requests */ /* cmh_logRslt ( ownBuf, RAT_OK, AT_CMD_CMGC, -1, -1, -1 ); */ } } else { #if defined (SIM_TOOLKIT) if (ownBuf EQ OWN_SAT) { cmhSMS_SATResult (&resp_data, mnsms_command_cnf->cause); } #endif R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_command_cnf->cause), NULL ); } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSErrorInd | +-------------------------------------------------------------------+ PURPOSE : This function is used to handle MNSMS_ERROR_IND primitive. */ GLOBAL SHORT cmhSMS_SMSErrorInd ( T_MNSMS_ERROR_IND * mnsms_error_ind ) { T_ACI_MM_CIND_VAL_TYPE sIndValues; int i; TRACE_FUNCTION ("cmhSMS_SMSErrorInd()"); TRACE_EVENT_P1("MNSMS_ERROR_IND: 0x%4.4X", (int)mnsms_error_ind->cause); if( (mnsms_error_ind->cause != SMS_CAUSE_MEM_FULL) && (mnsms_error_ind->cause != SMS_CAUSE_MEM_AVAIL) ) { smsShrdPrm.cnma_ack_expected = FALSE; cmhSMS_resetMtDsCnmiParam(); } else { /* process the SMS memory full/avail indication */ sIndValues.sCindSmsFullParam = (mnsms_error_ind->cause EQ SMS_CAUSE_MEM_AVAIL) ? CIND_SMSFULL_INDICATOR_MEMAVAIL : CIND_SMSFULL_INDICATOR_MEMFULL; sIndValues.sCindSignalParam = CIND_SIGNAL_INDICATOR_INVALID; for( i = CMD_SRC_LCL; i < CMD_SRC_MAX; i++) { if( ((cmhPrm[i].mmCmdPrm.sIndicationParam.sMmCINDSettings.sCindSmsFullParam EQ CIND_SMSFULL_INDICATOR_MEMFULL) AND (cmhPrm[i].mmCmdPrm.sIndicationParam.sMmCMERSettings.sCmerIndParam EQ CMER_INDICATOR_2)) OR ((cmhPrm[i].mmCmdPrm.sIndicationParam.sMmCINDSettings.sCindSmsFullParam <= CIND_SMSFULL_INDICATOR_MEMAVAIL) AND (cmhPrm[i].mmCmdPrm.sIndicationParam.sMmCMERSettings.sCmerIndParam EQ CMER_INDICATOR_1)) ) { /* process the service of +CIEV */ TRACE_EVENT("send +CIEV (SMS-full/avail)"); R_AT (RAT_CIEV, i) ( sIndValues, cmhPrm[i].mmCmdPrm.sIndicationParam.sMmCMERSettings ); } } } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSDeliver | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of the receiving of a SMS-DELIVER. */ #ifndef NTRACE LOCAL void trace_SMSDeliver ( T_MNSMS_MESSAGE_IND * mnsms_message_ind ) { #ifdef _CONC_TESTING_ char trcBuf[80]; char *writeP; int count; USHORT offset; TRACE_FUNCTION ("trace_SMSDeliver"); TRACE_EVENT_P1("cmt:bitoffset:%d", mnsms_message_ind->sms_sdu.o_buf); TRACE_EVENT_P1("cmt:lenght:%d", mnsms_message_ind->sms_sdu.l_buf); offset = mnsms_message_ind->sms_sdu.o_buf>>3; writeP = trcBuf; for (count=offset; count<offset+20; count++) { writeP += sprintf (writeP, " %02X", mnsms_message_ind->sms_sdu.buf[count]); } TRACE_EVENT("buf: "); *writeP = '\0'; TRACE_EVENT(trcBuf); writeP = trcBuf; for (; count<offset+40; count++) { writeP += sprintf (writeP, " %02X", mnsms_message_ind->sms_sdu.buf[count]); } *writeP = '\0'; TRACE_EVENT(trcBuf); #endif } #endif #if defined SMI OR defined MFW OR defined FF_MMI_RIV LOCAL void rAT_SMS_Deliver(T_MNSMS_MESSAGE_IND * mnsms_message_ind, T_ACI_CMGL_SM *p_sm) { #ifdef FF_MMI_RIV T_ACI_CMGF_MOD sms_input_mode = CMGF_MOD_NotPresent; #endif /* FF_MMI_RIV */ TRACE_FUNCTION ("rAT_SMS_Deliver"); #ifdef FF_MMI_RIV if(smsShrdPrm.perccmgf_smbs_mode EQ PERC_SMBS_MOD_ENABLE) { /*send both formats*/ rAT_PlusCMTPdu (mnsms_message_ind); R_AT( RAT_CMT, CMD_SRC_LCL ) (p_sm); return; } /* else: no SMBS enabled, CMGF mode decides */ qAT_PlusCMGF (CMD_SRC_LCL, &sms_input_mode); if (sms_input_mode EQ CMGF_MOD_Pdu) { rAT_PlusCMTPdu (mnsms_message_ind); } else { R_AT( RAT_CMT, CMD_SRC_LCL ) (p_sm); } return; #endif /* FF_MMI_RIV */ /* if GPF MMI call usual callback */ R_AT( RAT_CMT, CMD_SRC_LCL ) (p_sm); } #endif /* SMI OR defined MFW OR defined FF_MMI_RIV */ GLOBAL SHORT cmhSMS_SMSDeliver ( T_MNSMS_MESSAGE_IND * mnsms_message_ind ) { UBYTE idx; #if defined SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ T_ACI_CMGL_SM *p_sm; #endif /* SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_*/ TRACE_FUNCTION ("cmhSMS_SMSDeliver"); #ifndef NTRACE trace_SMSDeliver ( mnsms_message_ind ); #endif if( smsShrdPrm.CNMImt EQ 0 ) { TRACE_EVENT("cmhSMS_SMSDeliver():[ERR] <mt>==0 -> SMS will not be routed "); return 0; } #if defined SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ ACI_MALLOC(smsShrdPrm.pDecMsg, sizeof(T_ACI_CMGL_SM) ); p_sm = smsShrdPrm.pDecMsg; if (cmhSMS_cpyMsgInd ( p_sm, mnsms_message_ind) EQ FALSE) { TRACE_EVENT("cmhSMS_SMSDeliver():[ERR] decoding of SMS"); if (p_sm->stat NEQ SMS_STAT_Invalid) { TRACE_EVENT("cmhSMS_SMSDeliver():[ERR] SMS decoding failed, but status not SMS_STAT_Invalid"); } } #endif /* SMI OR defined MFW OR defined FF_MMI_RIV */ if (smsShrdPrm.CSMSservice EQ CSMS_SERV_GsmPh2Plus) smsShrdPrm.cnma_ack_expected = TRUE; /* *----------------------------------------------------------------- * new message indication *----------------------------------------------------------------- */ /* inform LOCAL MMI of new message */ #if defined SMI OR defined MFW OR defined FF_MMI_RIV rAT_SMS_Deliver(mnsms_message_ind, p_sm); #endif /* SMI OR defined MFW OR defined FF_MMI_RIV */ /* If the SMS shared params indicate no valid source interested in * the SMS indications, the indication is buffered */ /* Issue 25033 */ if( smsShrdPrm.smsSrcId EQ CMD_SRC_NONE ) { T_CNMI_IND ind; TRACE_EVENT("cmhSMS_SMSDeliver(): No registered source for "); memcpy ( &ind.cmt, mnsms_message_ind, sizeof ( T_MNSMS_MESSAGE_IND) ); #ifdef DTI cmd_addCnmiNtry ( CNMI_CMT, &ind ); #endif if ( smsShrdPrm.cnma_ack_expected EQ TRUE ) { /* the acknowledge must be send automatically, because terminal is busy */ PALLOC (mnsms_ack_res, MNSMS_ACK_RES); TRACE_EVENT("rCI_PlusCMT(): send 'automatic' acknowledge (Phase2+ mode and buffer)"); mnsms_ack_res->resp = SMS_RP_ACK; mnsms_ack_res->sms_sdu.o_buf = 0; mnsms_ack_res->sms_sdu.l_buf = 0; PSENDX (SMS, mnsms_ack_res); smsShrdPrm.cnma_ack_expected = FALSE; } } else { /* tell any remote source */ for( idx = CMD_SRC_LCL+1; idx < CMD_SRC_MAX; idx++ ) { #if defined _SIMULATION_ AND defined _CONC_TESTING_ /* don't display "+CMT: ..." in simulation if conc testing */ if (!concShrdPrm.concTesting) #endif { R_AT( RAT_CMT, idx ) ( mnsms_message_ind ); } } } if (smsShrdPrm.pDecMsg) { ACI_MFREE(smsShrdPrm.pDecMsg); smsShrdPrm.pDecMsg = NULL; } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSMemory | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of an incoming SMS written to preferred message storage. */ GLOBAL SHORT cmhSMS_SMSMemory ( T_MNSMS_MESSAGE_IND * mnsms_message_ind) { USHORT idx; /* holds command source id */ T_ACI_SMS_STOR mem; /* holds message storage */ T_ACI_CMGL_SM sm; #ifdef _CONC_TESTING_ #ifndef NTRACE char trcBuf[80]; char *writeP; int count; USHORT offset; TRACE_EVENT_P1("cmti:rec_num: %d", mnsms_message_ind->rec_num); TRACE_EVENT_P1("cmti:status: %d", mnsms_message_ind->status); offset = mnsms_message_ind->sms_sdu.o_buf>>3; writeP = trcBuf; for (count=offset; count<offset+20; count++) { writeP += sprintf (writeP, " %02X", mnsms_message_ind->sms_sdu.buf[count]); } TRACE_EVENT("buf: "); *writeP = '\0'; TRACE_EVENT(trcBuf); writeP = trcBuf; for (; count<offset+40; count++) { writeP += sprintf (writeP, " %02X", mnsms_message_ind->sms_sdu.buf[count]); } *writeP = '\0'; TRACE_EVENT(trcBuf); #endif #endif TRACE_FUNCTION ("cmhSMS_SMSMemory ()"); cmhSMS_getMemCmh ( mnsms_message_ind->mem_type, &mem ); switch (mnsms_message_ind->mem_type) { case MEM_ME: smsShrdPrm.aci_sms_parameter.meUsed++; break; case MEM_SM: smsShrdPrm.aci_sms_parameter.simUsed++; break; default: TRACE_EVENT("wrong memtype"); return AT_FAIL; } #if defined SMI OR defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (cmhSMS_cpyMsgInd ( &sm, mnsms_message_ind ) EQ FALSE) { TRACE_EVENT("cmhSMS_SMSMemory ():[ERR] decoding of SMS"); if (sm.stat NEQ SMS_STAT_Invalid) { TRACE_EVENT("cmhSMS_SMSMemory():[ERR] SMS decoding failed, but status not SMS_STAT_Invalid"); } } #endif /* *----------------------------------------------------------------- * new message indication *----------------------------------------------------------------- */ #if defined FF_MMI_RIV /* in case of RIV MMI: check if SMBS is enabled for sending also PDU data */ if(smsShrdPrm.perccmgf_smbs_mode EQ PERC_SMBS_MOD_ENABLE) { rAT_PlusCMTPdu (mnsms_message_ind); } #endif /* FF_MMI_RIV */ R_AT( RAT_CMTI, CMD_SRC_LCL ) (mem, sm.msg_ref, &sm); /* If the SMS shared params indicate no valid source interested in * the SMS indications, the indication is buffered */ /* Issue 25033 */ if( smsShrdPrm.smsSrcId EQ CMD_SRC_NONE ) { T_CNMI_IND ind; ind.cmti.mem = mem; ind.cmti.index = mnsms_message_ind->rec_num; #ifdef DTI cmd_addCnmiNtry ( CNMI_CMTI, &ind ); #endif } else { for( idx = CMD_SRC_LCL+1; idx < CMD_SRC_MAX; idx++ ) { #if defined _SIMULATION_ AND defined _CONC_TESTING_ /* don't display "+CMT: ..." in simulation if conc testing */ if (!concShrdPrm.concTesting) #endif { /* don't need the decoded message for Command Interpreter */ R_AT( RAT_CMTI, idx ) ( mem, mnsms_message_ind->rec_num ); } } } return AT_CMPL; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSStatRpt | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of the receiving of a SMS-STATUS-REPORT. */ GLOBAL SHORT cmhSMS_SMSStatRpt ( T_MNSMS_STATUS_IND * mnsms_status_ind ) { USHORT idx; /* holds command source id */ T_ACI_CDS_SM* p_st; TRACE_FUNCTION ("cmhSMS_SMSStatRpt ()"); #if defined SMI OR defined MFW OR defined FF_MMI_RIV ACI_MALLOC(smsShrdPrm.pDecMsg, sizeof(T_ACI_CDS_SM) ); p_st = (T_ACI_CDS_SM*)smsShrdPrm.pDecMsg; cmhSMS_cpyStatInd ( p_st, mnsms_status_ind); #endif if (smsShrdPrm.CSMSservice EQ CSMS_SERV_GsmPh2Plus) smsShrdPrm.cnma_ack_expected = TRUE; /* *----------------------------------------------------------------- * new message indication *----------------------------------------------------------------- */ { T_ACI_CMGF_MOD sms_input_mode = CMGF_MOD_NotPresent; /* If the SMS shared params indicate no valid source interested in * the SMS indications, the indication is buffered */ /* Issue 25033 */ if( smsShrdPrm.smsSrcId EQ CMD_SRC_NONE ) { T_CNMI_IND ind; memcpy ( &ind.cds, mnsms_status_ind, sizeof ( T_MNSMS_STATUS_IND) ); #ifdef DTI cmd_addCnmiNtry ( CNMI_CDS, &ind ); #endif } for( idx = 0; idx < CMD_SRC_MAX; idx++ ) { if (idx EQ CMD_SRC_LCL) { #ifdef FF_MMI_RIV qAT_PlusCMGF (CMD_SRC_LCL, &sms_input_mode); if (sms_input_mode EQ CMGF_MOD_Pdu) { rAT_PlusCDSPdu (mnsms_status_ind); } else { R_AT( RAT_CDS, idx ) ( p_st ); } #else R_AT( RAT_CDS, idx ) ( p_st ); #endif } else { R_AT( RAT_CDS, idx ) ( mnsms_status_ind ); } } } if (smsShrdPrm.pDecMsg) { ACI_MFREE(smsShrdPrm.pDecMsg); smsShrdPrm.pDecMsg = NULL; } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_cpyLstData | +-------------------------------------------------------------------+ PURPOSE : This function is used to copy the data read from memory. It sends a notification using the callback mechanism of ACI if necessary. */ GLOBAL void cmhSMS_cpyLstData ( T_ACI_AT_CMD curCmd, T_ACI_CMD_SRC entOwn, T_MNSMS_READ_CNF * mnsms_read_cnf ) { SHORT nextIdx; /* index of next short message */ TRACE_FUNCTION ("cmhSMS_cpyLstData ()"); nextIdx = mnsms_read_cnf->rec_next; if ( entOwn EQ CMD_SRC_LCL) { #ifdef FF_MMI_RIV { T_ACI_CMGF_MOD sms_input_mode = CMGF_MOD_NotPresent; qAT_PlusCMGF (CMD_SRC_LCL, &sms_input_mode); if (sms_input_mode EQ CMGF_MOD_Pdu ) { if (curCmd EQ AT_CMD_CMGL) { rAT_PlusCMGLPdu (mnsms_read_cnf); } else if (curCmd EQ AT_CMD_P_CMGL) { rAT_PercentCMGLPdu (mnsms_read_cnf); } } else if (curCmd EQ AT_CMD_CMGL) { R_AT ( RAT_CMGL, entOwn ) ( smsShrdPrm.pDecMsg ); } else if (curCmd EQ AT_CMD_P_CMGL) { R_AT ( RAT_P_CMGL, entOwn ) ( smsShrdPrm.pDecMsg ); } } #else if (curCmd EQ AT_CMD_CMGL) { R_AT ( RAT_CMGL, entOwn ) ( smsShrdPrm.pDecMsg ); } else if (curCmd EQ AT_CMD_P_CMGL) { R_AT ( RAT_P_CMGL, entOwn ) ( smsShrdPrm.pDecMsg ); } #endif } else if (curCmd EQ AT_CMD_CMGL) { R_AT ( RAT_CMGL, entOwn ) ( mnsms_read_cnf ); /* inform BMI */ cmh_logRslt ( entOwn, RAT_OK, AT_CMD_CMGL, mnsms_read_cnf->rec_num, -1, -1 ); } else if (curCmd EQ AT_CMD_P_CMGL) { /* the message shall not be displayed for ReadMode as Status Change */ if (smsShrdPrm.rdMode NEQ SMS_READ_StatusChange) { R_AT ( RAT_P_CMGL, entOwn ) ( mnsms_read_cnf ); /* inform BMI */ cmh_logRslt ( entOwn, RAT_OK, AT_CMD_P_CMGL, mnsms_read_cnf->rec_num, -1, -1 ); } } if (nextIdx NEQ SMS_RECORD_NOT_EXIST) { /* *----------------------------------------------------------- * request the next list elements of given cmglStat state *----------------------------------------------------------- */ psaSMS_ReadReq ( smsShrdPrm.mem1, nextIdx, smsShrdPrm.rdMode, cmglStat ); } else { /* *----------------------------------------------------------- * no more messages are available *----------------------------------------------------------- */ /* reset the command context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; R_AT ( RAT_OK, entOwn ) ( curCmd ); } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMReadCMSS | +-------------------------------------------------------------------+ PURPOSE : This function processes the mnsms_read_cnf which was triggered by +CMSS. */ GLOBAL void cmhSMS_SMReadCMSS ( T_MNSMS_READ_CNF * mnsms_read_cnf) { T_SMS_SET_PRM * pSMSSetPrm; /* points to SMS parameter set */ UBYTE srcId; UBYTE fo; T_ACI_CMGL_SM *p_sm; T_tp_da da_addr; T_ACI_RETURN ret=AT_CMPL; UBYTE modify=SMS_MODIFY_NON; #ifdef _CONC_TESTING_ char trcBuf[80]; char *writeP; int count; #endif TRACE_FUNCTION ("cmhSMS_SMReadCMSS ()"); srcId = smsShrdPrm.smsEntStat.entOwn; pSMSSetPrm = smsShrdPrm.pSetPrm[srcId]; if (smsShrdPrm.pDecMsg EQ NULL) { ACI_MALLOC(smsShrdPrm.pDecMsg, sizeof(T_ACI_CMGL_SM) ); p_sm = smsShrdPrm.pDecMsg; /* decode message */ cmhSMS_cpyReadCnf ( p_sm, mnsms_read_cnf ); } else p_sm = smsShrdPrm.pDecMsg; memset (&da_addr, 0, sizeof(T_tp_da)); /* start: check FDN if enabled */ if (pb_get_fdn_mode () EQ FDN_ENABLE AND pb_get_fdn_classtype() EQ CLASS_VceDatFaxSms ) { TRACE_EVENT_P1("cmhSMS_SMReadCMSS: FDN check: %s", p_sm->adress ); if (pb_check_fdn (0, (const UBYTE*) p_sm->adress) EQ PHB_OK) { TRACE_EVENT("cmhSMS_SMReadCMSS: Found match in FDN!"); } else { TRACE_EVENT("cmhSMS_SMReadCMSS: No match in FDN found, SMS rejected!"); /* error notification */ R_AT( RAT_CMS, smsShrdPrm.smsEntStat.entOwn ) ( smsShrdPrm.smsEntStat.curCmd, CMS_ERR_OpNotAllowed, NULL ); /* release context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = CMD_SRC_NONE; return; } } /* end: check FDN if enabled */ /* * ACI-SPR-17004: set RFU bits of status to 0 if present since these * should be ignored in a GSM session (GSM 11.11 section 9.3) */ cmhSMS_removeStatusRFUBits( &mnsms_read_cnf->status ); ACI_MALLOC(smsShrdPrm.tpdu.tp_submit, sizeof(T_TP_SUBMIT)); /* SMS-SUBMIT received */ if ((mnsms_read_cnf->status EQ SMS_RECORD_STO_UNSENT) OR (mnsms_read_cnf->status EQ SMS_RECORD_STO_SENT) OR (mnsms_read_cnf->status EQ SMS_RECORD_STAT_UNRCVD) OR (mnsms_read_cnf->status EQ SMS_RECORD_STAT_UNSTRD) OR (mnsms_read_cnf->status EQ SMS_RECORD_STAT_STRD) ) { /* destination address from stored message */ if (p_sm->adress[0] NEQ '\0') { cmhSMS_getAdrBcd ( da_addr.num, &da_addr.c_num, MAX_SMS_ADDR_DIG, p_sm->adress); da_addr.ton = p_sm->toa.ton; da_addr.npi = p_sm->toa.npi; da_addr.digits = da_addr.c_num; } /* service center address from shared parameter */ if (pSMSSetPrm->sca.c_num NEQ 0) { memcpy (&smsShrdPrm.tpdu.sc_addr, &pSMSSetPrm->sca, sizeof(T_rp_addr)); modify |= SMS_MODIFY_SCA; } /* ACI-SPR-22528.The memory is allocated for smsShrdPrm.tpdu.tp_submit only when it is necessary*/ cmhSMS_fillTpSubmit (smsShrdPrm.tpdu.tp_submit, srcId, 0, /* fo */ 0, &da_addr, NULL, 0, NULL ); } else { /* SMS-DELIVER received */ T_ACI_SM_DATA packedData; UBYTE byte_offset=0; /* service center address from shared parameter */ if (pSMSSetPrm->sca.c_num NEQ 0) { memcpy (&smsShrdPrm.tpdu.sc_addr, &pSMSSetPrm->sca, sizeof(T_rp_addr)); } else { if (p_sm->sca[0] NEQ '\0') { cmhSMS_getAdrBcd( smsShrdPrm.tpdu.sc_addr.num, &smsShrdPrm.tpdu.sc_addr.c_num, MAX_SMS_ADDR_DIG, p_sm->sca); smsShrdPrm.tpdu.sc_addr.ton = p_sm->tosca.ton; smsShrdPrm.tpdu.sc_addr.npi = p_sm->tosca.npi; smsShrdPrm.tpdu.sc_addr.v_ton = TRUE; smsShrdPrm.tpdu.sc_addr.v_npi = TRUE; } } fo = (pSMSSetPrm->msgType & (~TP_MTI_MASK)) | TP_MTI_SMS_SUBMIT; if (p_sm->udh.len) byte_offset = p_sm->udh.len+1; /* ACI-SPR-22528.The memory is allocated for smsShrdPrm.tpdu.tp_submit only when it is necessary*/ cmhSMS_rdcSmsPp ( byte_offset, p_sm -> dcs, ( UBYTE * ) p_sm->data.data, ( UBYTE ) p_sm->data.len, packedData.data, &packedData.len); if (p_sm->adress[0] NEQ '\0') { cmhSMS_getAdrBcd ( da_addr.num, &da_addr.c_num, MAX_SMS_ADDR_DIG, p_sm->adress); da_addr.ton = p_sm->toa.ton; da_addr.npi = p_sm->toa.npi; da_addr.digits = da_addr.c_num; } cmhSMS_fillTpSubmit (smsShrdPrm.tpdu.tp_submit, srcId, fo, 0, &da_addr, &packedData, p_sm->data.len, &p_sm->udh ); modify = SMS_MODIFY_ALL; } { PALLOC (mnsms_submit_req, MNSMS_SUBMIT_REQ); mnsms_submit_req->rec_num = mnsms_read_cnf->rec_num; mnsms_submit_req->mem_type = smsShrdPrm.mem2; mnsms_submit_req->condx = SMS_CONDX_OVR_ANY; mnsms_submit_req->modify = modify; #ifdef SIM_TOOLKIT if (psaSIM_ChkSIMSrvSup( SRV_MOSMCtrlSIM )) { if (simShrdPrm.setPrm[srcId].sat_cc_mode EQ SATCC_CONTROL_BY_SIM_ACTIVE) { ret = cmhSAT_MoSmCntr( smsShrdPrm.tpdu.sc_addr, da_addr, srcId); } else { simShrdPrm.setPrm[srcId].sat_cc_mode = SATCC_CONTROL_BY_SIM_ACTIVE; } } if (ret NEQ AT_CMPL) { /* save primitive address for SIM_TOOLKIT response */ sat_mnsms_submit_req = mnsms_submit_req; return; } #endif /* code SMS-SUBMIT here */ cmhSMS_codeMsg (&mnsms_submit_req->sms_sdu, SMS_VT_SUBMIT, &smsShrdPrm.tpdu.sc_addr, SMS_SUBMIT, (UBYTE*)smsShrdPrm.tpdu.tp_submit); PSENDX (SMS, mnsms_submit_req); #ifdef _CONC_TESTING_ #ifndef NTRACE writeP = trcBuf; for (count=0; count<20; count++) { writeP += sprintf (writeP, " %02X", mnsms_submit_req->sms_sdu.buf[count]); } TRACE_EVENT("buf: "); *writeP = '\0'; TRACE_EVENT(trcBuf); writeP = trcBuf; for (; count<40; count++) { writeP += sprintf (writeP, " %02X", mnsms_submit_req->sms_sdu.buf[count]); } *writeP = '\0'; TRACE_EVENT(trcBuf); #endif #endif if (smsShrdPrm.tpdu.tp_submit NEQ NULL) { ACI_MFREE(smsShrdPrm.tpdu.tp_submit); smsShrdPrm.tpdu.tp_submit = NULL; } } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMRead | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of a successfull reading of a short message from preferred message storage. */ #ifndef NTRACE LOCAL void trace_read_sms( T_MNSMS_READ_CNF * mnsms_read_cnf) { char trcBuf[80]; char *writeP; int count; TRACE_FUNCTION ("trace_read_sms ()"); TRACE_EVENT_P1(" rec_num: %u", mnsms_read_cnf->rec_num); TRACE_EVENT_P1(" rec_next: %u", mnsms_read_cnf->rec_next); TRACE_EVENT_P1(" rec_max: %u", mnsms_read_cnf->rec_max); TRACE_EVENT_P1(" status %u", mnsms_read_cnf->status); TRACE_EVENT_P1(" cause 0x%04x", mnsms_read_cnf->cause); writeP = trcBuf; for (count=0; count<20; count++) { writeP += sprintf (writeP, " %02X", mnsms_read_cnf->sms_sdu.buf[count]); } TRACE_EVENT("buf: "); *writeP = '\0'; TRACE_EVENT(trcBuf); writeP = trcBuf; for (; count<40; count++) { writeP += sprintf (writeP, " %02X", mnsms_read_cnf->sms_sdu.buf[count]); } *writeP = '\0'; TRACE_EVENT(trcBuf); } #endif GLOBAL SHORT cmhSMS_SMRead ( T_MNSMS_READ_CNF * mnsms_read_cnf) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ T_ACI_CMGL_SM *p_sm; T_rp_addr rp_addr; UBYTE* message; T_TP_DELIVER *sms_deliver, decoded_mesg; BOOL retCode = FALSE; UBYTE msg_type; TRACE_FUNCTION ("cmhSMS_SMRead ()"); #ifndef NTRACE trace_read_sms(mnsms_read_cnf); #endif cmdBuf = smsShrdPrm.smsEntStat.curCmd; ownBuf = smsShrdPrm.smsEntStat.entOwn; /* (SIM) error occurred */ if (!IS_CAUSE_INVALID(mnsms_read_cnf->cause)) { if (mnsms_read_cnf->cause NEQ SMS_NO_ERROR) { /* reset the command context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; if( ownBuf NEQ CMD_SRC_LCL OR cmdBuf NEQ AT_CMD_P_CMGMDU ) { R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_read_cnf->cause), NULL ); } return 1; } } #ifdef _CONC_TESTING_ /* this is only for testing */ SET_OWNBUF_CONC; #endif /* *----------------------------------------------------------------- * ignore primitives with incorrect message status *----------------------------------------------------------------- */ TRACE_EVENT_P1("mnsms_read_cnf->status: %d", mnsms_read_cnf->status); if ( (mnsms_read_cnf->status EQ SMS_RECORD_FREE) OR (mnsms_read_cnf->status EQ SMS_RECORD_INVALID) ) { /* reset the command context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; TRACE_EVENT("incorrect message status"); return 1; } /* always decode for local source */ if (ownBuf EQ CMD_SRC_LCL) /* ACI-SPR-9528 */ { /* pass dummy p_sm to CB */ if (((cmdBuf EQ AT_CMD_CMGL OR cmdBuf EQ AT_CMD_CMGR) OR (cmdBuf EQ AT_CMD_P_CMGR OR cmdBuf EQ AT_CMD_P_CMGL)) AND smsShrdPrm.rdMode NEQ READ_STATUS_CHANGE) /* ACI-FIX-9510 */ { retCode = cmhSMS_SMSQueryType (&mnsms_read_cnf->sms_sdu, &msg_type); if (retCode EQ FALSE) { /* reset the command context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; TRACE_EVENT("Error decoding message type"); return 1; } ACI_MALLOC(smsShrdPrm.pDecMsg, sizeof(T_ACI_CMGL_SM) ); memset(smsShrdPrm.pDecMsg,0,sizeof(T_ACI_CMGL_SM) ); p_sm = smsShrdPrm.pDecMsg; if (msg_type EQ TP_MTI_SMS_STATUS_REP) { retCode=cmhSMS_cpySTtoSM(p_sm ,mnsms_read_cnf); } else { retCode = cmhSMS_cpyReadCnf ( p_sm, mnsms_read_cnf ); } if (retCode EQ FALSE) { TRACE_EVENT("cmhSMS_SMRead ():[ERR] decoding of SMS"); cmhSMS_invalidSMS_notification_to_user (mnsms_read_cnf); ACI_MFREE(smsShrdPrm.pDecMsg); /* reset the command context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; smsShrdPrm.pDecMsg = NULL; if (mnsms_read_cnf->rec_next EQ SMS_RECORD_NOT_EXIST) { smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; if( cmdBuf NEQ AT_CMD_P_CMGMDU ) { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } } return 1; } } } else p_sm = smsShrdPrm.pDecMsg; /* *----------------------------------------------------------------- * check for command context *----------------------------------------------------------------- */ switch( smsShrdPrm.smsEntStat.curCmd ) { case ( AT_CMD_CMGR ): case ( AT_CMD_P_CMGR ): { /* *------------------------------------------------------------- * process event for +CGMR *------------------------------------------------------------- */ /* reset the command context */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; /* The message need not be displayed for Status Change */ if (cmdBuf EQ AT_CMD_P_CMGR AND smsShrdPrm.rdMode EQ READ_STATUS_CHANGE) { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); /* inform BMI */ cmh_logRslt ( ownBuf, RAT_OK, AT_CMD_P_CMGR, mnsms_read_cnf->rec_num, -1, -1 ); break; } #if defined MFW OR defined FF_MMI_RIV OR defined _CONC_TESTING_ if (ownBuf EQ CMD_SRC_LCL) /* AND /* ACI-FIX-9510 */ /* smsShrdPrm.rdMode NEQ READ_STATUS_CHANGE) */ /* call rplyCB (with invalid p_sm) anyway to touch all segments while in READ_STATUS_CHANGE */ { #if defined FF_MMI_RIV T_ACI_CMGF_MOD sms_input_mode = CMGF_MOD_NotPresent; qAT_PlusCMGF (CMD_SRC_LCL, &sms_input_mode); if (sms_input_mode EQ CMGF_MOD_Pdu ) { if (cmdBuf EQ AT_CMD_CMGR ) { rAT_PlusCMGRPdu (mnsms_read_cnf); } else if (cmdBuf EQ AT_CMD_P_CMGR ) { rAT_PercentCMGRPdu (mnsms_read_cnf); } } else { if (smsShrdPrm.rplyCB.cmgr NEQ NULL) { smsShrdPrm.rplyCB.cmgr( p_sm, NULL ); } } R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); #else /* GPF-MMI */ if (smsShrdPrm.rplyCB.cmgr NEQ NULL) { smsShrdPrm.rplyCB.cmgr( p_sm, NULL ); } if (!ISSET_CONC) { R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); } #endif } else /* if (ownBuf EQ CMD_SRC_LCL) */ #endif /*#if defined MFW OR defined FF_MMI_RIV*/ { if (cmdBuf EQ AT_CMD_CMGR ) { R_AT ( RAT_CMGR, ownBuf ) ( mnsms_read_cnf, NULL ); } else if (cmdBuf EQ AT_CMD_P_CMGR ) { R_AT ( RAT_P_CMGR, ownBuf ) ( mnsms_read_cnf, NULL ); } R_AT ( RAT_OK, ownBuf ) ( cmdBuf ); /* inform BMI */ cmh_logRslt ( ownBuf, RAT_OK, AT_CMD_CMGR, mnsms_read_cnf->rec_num, -1, -1 ); } break; } case ( AT_CMD_P_CMGL ): case ( AT_CMD_CMGL ): { /* *------------------------------------------------------------- * process event for +CMGL *------------------------------------------------------------- */ cmhSMS_cpyLstData ( cmdBuf, ownBuf, mnsms_read_cnf ); break; } case ( AT_CMD_P_CMGMDU ): { /* *------------------------------------------------------------- * process event for %CMGMDU *------------------------------------------------------------- */ message = cmhSMS_decodeMsg(&mnsms_read_cnf->sms_sdu, &rp_addr, SMS_VT_DELIVER); sms_deliver = (T_TP_DELIVER*)message; sms_deliver->tp_rp = 0; memcpy(&decoded_mesg, sms_deliver, sizeof(T_TP_DELIVER)); { PALLOC (mnsms_store_req, MNSMS_STORE_REQ); mnsms_store_req -> mem_type = smsShrdPrm.mem1; mnsms_store_req -> condx = SMS_CONDX_OVR_ANY; mnsms_store_req -> rec_num = mnsms_read_cnf->rec_num; mnsms_store_req -> status = mnsms_read_cnf->status; cmhSMS_codeMsg ( &mnsms_store_req->sms_sdu, SMS_VT_DELIVER, &rp_addr, SMS_DELIVER, (UBYTE*) &decoded_mesg); PSENDX (SMS, mnsms_store_req); } break; } #if defined (SIM_TOOLKIT) case ( AT_CMD_CMSS ): { /* *------------------------------------------------------------- * process event for +CMSS (only for SAT) *------------------------------------------------------------- */ cmhSMS_SMReadCMSS (mnsms_read_cnf); break; } #endif default: { TRACE_EVENT("error in command context"); } } if (smsShrdPrm.pDecMsg) { ACI_MFREE(smsShrdPrm.pDecMsg); smsShrdPrm.pDecMsg = NULL; } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_Result | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of a successfull transaction concerning the short message service. */ GLOBAL SHORT cmhSMS_Result ( T_MNSMS_REPORT_IND * mnsms_report_ind ) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ TRACE_FUNCTION ("cmhSMS_Result ()"); if (mnsms_report_ind->v_cmms_mode) { smsShrdPrm.CMMSmode = mnsms_report_ind->cmms_mode; return 0; } cmdBuf = AT_CMD_NONE; ownBuf = CMD_SRC_LCL; smsShrdPrm.smsStat = mnsms_report_ind->state; if (mnsms_report_ind->state EQ SMS_STATE_READY) { /* reading of SMs from SIM is completed, * read SMSP, CBMIR, CMBI fields now */ if (cmhSMS_ReadParams (NO_VLD_OWN, AT_CMD_CFUN, 1) NEQ AT_EXCT) { cmhSMS_ready (); } R_AT ( RAT_SIG_SMS, ownBuf ) ( SMS_STATE_READY ); } else if (mnsms_report_ind->state EQ SMS_STATE_INITIALISING) { { /*ACI-FIX-18055 resetting total and used storage counters of SIM and ME storages which will be updated by cmhSMS_SMSInitState */ smsShrdPrm.aci_sms_parameter.simTotal = 0; smsShrdPrm.aci_sms_parameter.simUsed = 0; smsShrdPrm.aci_sms_parameter.meTotal = 0; smsShrdPrm.aci_sms_parameter.meUsed = 0; } /*ACI-FIX-18055 Changes end here */ R_AT ( RAT_SIG_SMS, ownBuf ) ( SMS_STATE_INITIALISING ); } else if (mnsms_report_ind->state > SMS_STATE_INITIALISING) { R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, CMS_ERR_UnknownErr, NULL ); } return 0; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_WrCnfCSAS | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of the usage of SIM and ME memory. */ GLOBAL void cmhSMS_WrCnfCSAS (SHORT aId) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ USHORT errCode; USHORT dataField = 0xFF; UBYTE dataLen = 0; UBYTE data[MAX_SIM_CMD]; TRACE_FUNCTION ("cmhSMS_WrCnfCSAS ()"); cmdBuf = smsShrdPrm.smsEntStat.curCmd; ownBuf = smsShrdPrm.smsEntStat.entOwn; /* *----------------------------------------------------------------- * check for next SIM access *----------------------------------------------------------------- */ switch (smsShrdPrm.prmRdSeq) { case SMS_READ_SIM_SMSP: /* EF(SMSP) written */ errCode = simShrdPrm.atb[aId].errCode; if (smsShrdPrm.cbmPrm.cbmSIMmaxIdRge > 0 AND cmhSMS_PutCbmirSIM (ownBuf, data, (int)smsShrdPrm.cbmPrm.cbmSIMmaxIdRge * 4)) /* write CBMIR */ { dataField = SIM_CBMIR; dataLen = smsShrdPrm.cbmPrm.cbmSIMmaxIdRge * 4; break; } else smsShrdPrm.prmRdSeq--; if (smsShrdPrm.cbmPrm.cbmSIMmaxId > 0 AND cmhSMS_PutCbmiSIM (ownBuf, data, (int)smsShrdPrm.cbmPrm.cbmSIMmaxId * 2)) /* write CBMI */ { dataField = SIM_CBMI; dataLen = smsShrdPrm.cbmPrm.cbmSIMmaxId * 2; } else /* nothing else to write */ { smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; } break; case SMS_READ_SIM_CBMIR: /* CBMIR written */ errCode = simShrdPrm.atb[aId].errCode; if (smsShrdPrm.cbmPrm.cbmSIMmaxId > 0 AND /* write CBMI */ cmhSMS_PutCbmiSIM (ownBuf, data, (int)smsShrdPrm.cbmPrm.cbmSIMmaxId * 2)) { dataField = SIM_CBMI; dataLen = smsShrdPrm.cbmPrm.cbmSIMmaxId * 2; } else /* nothing else to write */ smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; break; case SMS_READ_SIM_CBMI: /* CBMI written */ errCode = simShrdPrm.atb[aId].errCode; smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; /* nothing else to write */ break; default: /* nothing else to write */ smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; errCode = SIM_CAUSE_OTHER_ERROR; break; } if ( smsShrdPrm.prmRdSeq EQ SMS_READ_SIM_CMPL) { smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; if (errCode EQ SIM_NO_ERROR) { R_AT( RAT_OK, ownBuf ) ( cmdBuf ); } else { R_AT( RAT_CMS, ownBuf ) /* unsuccessful SIM write */ ( cmdBuf, cmhSMS_GetCmsFromSim ( errCode ), NULL ); } } else { if (cmhSIM_WriteTranspEF (CMD_SRC_NONE, cmdBuf, dataField, 0, dataLen, data, cmhSMS_WrCnfCSAS) EQ AT_FAIL) { smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; R_AT( RAT_CMS, ownBuf ) ( cmdBuf, CMS_ERR_UnknownErr, NULL ); } else smsShrdPrm.prmRdSeq--; } simShrdPrm.atb[aId].ntryUsdFlg = FALSE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_RdCnfCRES | +-------------------------------------------------------------------+ PURPOSE : This function is used to notify the command handler of the usage of SIM and ME memory. */ GLOBAL void cmhSMS_RdCnfCRES (SHORT aId) { T_ACI_AT_CMD cmdBuf; /* buffers current command */ T_ACI_CMD_SRC ownBuf; /* buffers current owner */ USHORT errCode; USHORT dataField = 0xFF; UBYTE dataLen = 0; UBYTE profile; TRACE_FUNCTION ("cmhSMS_RdCnfCRES ()"); cmdBuf = smsShrdPrm.smsEntStat.curCmd; ownBuf = smsShrdPrm.smsEntStat.entOwn; /* *----------------------------------------------------------------- * check for next SIM access *----------------------------------------------------------------- */ switch (smsShrdPrm.prmRdSeq) { case SMS_READ_SIM_SMSP: if ((errCode = simShrdPrm.atb[aId].errCode) EQ SIM_NO_ERROR) { /* successful EF(SMSP) read */ profile = simShrdPrm.atb[aId].recNr; if (!cmhSMS_GetPrmSIM (ownBuf, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen)) { errCode = SIM_CAUSE_OTHER_ERROR; } } if (smsShrdPrm.cbmPrm.cbmSIMmaxIdRge > 0) { dataField = SIM_CBMIR; dataLen = smsShrdPrm.cbmPrm.cbmSIMmaxIdRge * 4; break; } else smsShrdPrm.prmRdSeq--; if (smsShrdPrm.cbmPrm.cbmSIMmaxId > 0) { dataField = SIM_CBMI; dataLen = smsShrdPrm.cbmPrm.cbmSIMmaxId * 2; break; } else smsShrdPrm.prmRdSeq--; smsShrdPrm.cbmPrm.cbchOwner = ownBuf; psaMMI_Cbch(); smsShrdPrm.cbmPrm.cbchOwner = OWN_NONE; #ifdef SIM_TOOLKIT smsShrdPrm.prmRdSeq--; /* when SAT is on, then SMS_READ_CBMID is defined which is irrelevant for +CRES */ #endif /* of SIM_TOOLKIT */ break; case SMS_READ_SIM_CBMIR: if ((errCode = simShrdPrm.atb[aId].errCode) EQ SIM_NO_ERROR) { /* successful EF(CBMIR) read */ if (!cmhSMS_GetCbmirSIM (ownBuf, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen)) { errCode = SIM_CAUSE_OTHER_ERROR; } } if (smsShrdPrm.cbmPrm.cbmSIMmaxId > 0) { dataField = SIM_CBMI; dataLen = smsShrdPrm.cbmPrm.cbmSIMmaxId * 2; } else { smsShrdPrm.prmRdSeq--; smsShrdPrm.cbmPrm.cbchOwner = ownBuf; psaMMI_Cbch(); smsShrdPrm.cbmPrm.cbchOwner = OWN_NONE; #ifdef SIM_TOOLKIT smsShrdPrm.prmRdSeq--; /* when SAT is on, then SMS_READ_CBMID is defined which is irrelevant for +CRES */ #endif /* of SIM_TOOLKIT */ } break; case SMS_READ_SIM_CBMI: if ((errCode = simShrdPrm.atb[aId].errCode) EQ SIM_NO_ERROR) { /* successful EF(CBMI) read */ if (!cmhSMS_GetCbmiSIM (ownBuf, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen)) { errCode = SIM_CAUSE_OTHER_ERROR; } } smsShrdPrm.cbmPrm.cbchOwner = ownBuf; psaMMI_Cbch(); smsShrdPrm.cbmPrm.cbchOwner = OWN_NONE; #ifdef SIM_TOOLKIT smsShrdPrm.prmRdSeq--; /* when SAT is on, then SMS_READ_CBMID is defined which is irrelevant for +CRES */ #endif /* of SIM_TOOLKIT */ break; default: smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; errCode = SIM_CAUSE_OTHER_ERROR; break; } if (--smsShrdPrm.prmRdSeq <= SMS_READ_SIM_CMPL) { smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; if (errCode EQ SIM_NO_ERROR) { R_AT( RAT_OK, ownBuf ) ( cmdBuf ); } else { R_AT( RAT_CMS, ownBuf ) /* unsuccessful SIM read */ ( cmdBuf, cmhSMS_GetCmsFromSim ( errCode ), NULL ); } } else if (cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmdBuf, dataField, 0, dataLen, NULL, cmhSMS_RdCnfCRES) EQ AT_FAIL) { smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; #ifdef SIM_TOOLKIT if (ownBuf EQ OWN_SAT /*smsShrdPrm.fuRef >= 0*/) { psaSAT_FUConfirm ((int)simShrdPrm.fuRef, SIM_FU_ERROR); } else { #endif R_AT( RAT_CMS, ownBuf ) ( cmdBuf, CMS_ERR_UnknownErr, NULL ); #ifdef SIM_TOOLKIT } #endif } simShrdPrm.atb[aId].ntryUsdFlg = FALSE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_InitSMSP | +-------------------------------------------------------------------+ PURPOSE : This function is used to store the parameters of EF(SMSP). */ GLOBAL void cmhSMS_InitSMSP (SHORT aId) { T_ACI_CMD_SRC srcId; T_SMS_SET_PRM * elem ; /* points to SMS parameter set */ UBYTE idx; UBYTE profile; TRACE_FUNCTION ("cmhSMS_InitSMSP ()"); /* *----------------------------------------------------------------- * process SIM result *----------------------------------------------------------------- */ srcId = smsShrdPrm.owner; switch (smsShrdPrm.prmRdSeq) { case SMS_READ_SIM_SMSP: if (simShrdPrm.atb[aId].errCode EQ SIM_NO_ERROR) { /* successful EF(SMSP) read */ smsShrdPrm.aci_sms_parameter.smsParamMaxRec = simShrdPrm.atb[aId].recMax; smsShrdPrm.aci_sms_parameter.smsParamRecLen = simShrdPrm.atb[aId].dataLen; if (set_prm_list EQ NULL) { set_prm_list = new_list(); } profile = simShrdPrm.atb[aId].recNr; elem = find_element(set_prm_list, profile, cmhSMS_findPrflId); if (elem EQ NULL) { ACI_MALLOC(elem, sizeof(T_SMS_SET_PRM)); memset(elem, 0, sizeof(T_SMS_SET_PRM)); insert_list(set_prm_list, elem); elem->prflId = profile; elem->numOfRefs = OWN_MAX; for( idx = 0; idx < OWN_MAX; idx++ ) { smsShrdPrm.pSetPrm[idx] = (T_SMS_SET_PRM*) elem; } } else { smsShrdPrm.pSetPrm[0] = (T_SMS_SET_PRM*) elem; } cmhSMS_GetPrmSIM (0, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen); } else { smsShrdPrm.aci_sms_parameter.smsParamMaxRec = 0; smsShrdPrm.aci_sms_parameter.smsParamRecLen = 0; } if( !psaSIM_ChkSIMSrvSup( SRV_CBMIdRnge )) { smsShrdPrm.prmRdSeq--; goto CBMIR; } if (cmhSIM_ReadTranspEF (CMD_SRC_NONE, smsShrdPrm.smsEntStat.curCmd, SIM_CBMIR, 0, 255, NULL, cmhSMS_InitSMSP) NEQ AT_FAIL) smsShrdPrm.prmRdSeq--; else { goto CBMIR; } break; case SMS_READ_SIM_CBMIR: if (simShrdPrm.atb[aId].errCode EQ SIM_NO_ERROR) { smsShrdPrm.cbmPrm.cbmSIMmaxIdRge = simShrdPrm.atb[aId].dataLen / 4; cmhSMS_GetCbmirSIM (CMD_SRC_NONE, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen); } else smsShrdPrm.cbmPrm.cbmSIMmaxIdRge = 0; CBMIR: if( !psaSIM_ChkSIMSrvSup( SRV_CBM_Ident )) { smsShrdPrm.prmRdSeq--; goto CBMI; } if (cmhSIM_ReadTranspEF (CMD_SRC_NONE, smsShrdPrm.smsEntStat.curCmd, SIM_CBMI, 0, 255, NULL, cmhSMS_InitSMSP) NEQ AT_FAIL) smsShrdPrm.prmRdSeq--; else { #ifdef SIM_TOOLKIT goto CBMI; #else smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = simShrdPrm.owner = OWN_NONE; #endif /* of SIM_TOOLKIT */ } break; case SMS_READ_SIM_CBMI: if (simShrdPrm.atb[aId].errCode EQ SIM_NO_ERROR) { smsShrdPrm.cbmPrm.cbmSIMmaxId = simShrdPrm.atb[aId].dataLen / 2; cmhSMS_GetCbmiSIM (CMD_SRC_NONE, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen); } else smsShrdPrm.cbmPrm.cbmSIMmaxId = 0; #ifdef SIM_TOOLKIT CBMI: if( (!psaSIM_ChkSIMSrvSup( SRV_DtaDownlCB )) OR smsShrdPrm.owner NEQ OWN_SAT) { smsShrdPrm.prmRdSeq--; goto CBMID; } if (cmhSIM_ReadTranspEF (CMD_SRC_NONE, smsShrdPrm.smsEntStat.curCmd, SIM_CBMID, 0, 255, NULL, cmhSMS_InitSMSP) NEQ AT_FAIL) smsShrdPrm.prmRdSeq--; else { smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = simShrdPrm.owner = OWN_NONE; } break; case SMS_READ_SIM_CBMID: if (simShrdPrm.atb[aId].errCode EQ SIM_NO_ERROR) { smsShrdPrm.cbmPrm.cbmSIMmaxSATId = simShrdPrm.atb[aId].dataLen / 2; cmhSMS_GetCbDtaDwnlSIM (CMD_SRC_NONE, simShrdPrm.atb[aId].exchData, simShrdPrm.atb[aId].dataLen); { PALLOC (sat_cbch_req, MMI_SAT_CBCH_DWNLD_REQ); sat_cbch_req->count = (USHORT)smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds; memset (sat_cbch_req->msg_id, NOT_PRESENT_16BIT, sizeof (sat_cbch_req->msg_id)); memcpy (sat_cbch_req->msg_id, smsShrdPrm.cbmPrm.CBDtaDwnlIdent, (size_t)smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds * 2); PSENDX (PL, sat_cbch_req); } } else smsShrdPrm.cbmPrm.cbmSIMmaxSATId = 0; default: CBMID: #else /*lint -fallthrough*/ default: CBMI: #endif /*SIM_TOOLKIT */ smsShrdPrm.cbmPrm.cbchOwner = srcId; psaMMI_Cbch(); smsShrdPrm.cbmPrm.cbchOwner = OWN_NONE; { smsShrdPrm.prmRdSeq = SMS_READ_SIM_CMPL; smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = simShrdPrm.owner = OWN_NONE; } #ifdef SIM_TOOLKIT if (srcId EQ OWN_SAT /*smsShrdPrm.fuRef >= 0*/) { smsShrdPrm.accessEnabled = TRUE; psaSAT_FUConfirm (simShrdPrm.fuRef,(USHORT) ((simShrdPrm.atb[aId].errCode EQ SIM_NO_ERROR)? SIM_FU_SUCC_ADD: SIM_FU_ERROR)); } else #endif cmhSMS_ready (); break; } simShrdPrm.atb[aId].ntryUsdFlg = FALSE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSResumeCnf | +-------------------------------------------------------------------+ PURPOSE : This function processes the MNSMS_RESUME_CNF primitive. */ GLOBAL void cmhSMS_SMSResumeCnf (T_MNSMS_RESUME_CNF * mnsms_resume_cnf) { UBYTE cmdBuf; UBYTE ownBuf; TRACE_FUNCTION("cmhSMS_ResumeCnf()"); cmdBuf = smsShrdPrm.smsEntStat.curCmd; ownBuf = smsShrdPrm.smsEntStat.entOwn; /* check whether resume has been successfully processed */ if (mnsms_resume_cnf->cause EQ SMS_NO_ERROR) { R_AT( RAT_OK, ownBuf ) ( cmdBuf ); } else { /* command unsuccessful */ R_AT ( RAT_CMS, ownBuf ) ( cmdBuf, cmhSMS_GetCmsFromSms(mnsms_resume_cnf->cause), NULL ); } /* reset command */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSQueryCnf | +-------------------------------------------------------------------+ PURPOSE : This function processes the MNSMS_QUERY_CNF primitive. */ GLOBAL void cmhSMS_SMSQueryCnf (T_MNSMS_QUERY_CNF * mnsms_query_cnf) { UBYTE cmdBuf; UBYTE ownBuf; TRACE_FUNCTION("cmhSMS_SMSQueryCnf()"); cmdBuf = smsShrdPrm.smsEntStat.curCmd; ownBuf = smsShrdPrm.smsEntStat.entOwn; /* check type of query request and process it */ switch (mnsms_query_cnf->query_type) { case SMS_QUERY_DELIVER_STATUS: { if ( mnsms_query_cnf->v_deliver_status ) { R_AT ( RAT_CPRSM, ownBuf ) ( cmhSMS_convertDeliverStatusToACI(mnsms_query_cnf->deliver_status ) ); R_AT( RAT_OK, ownBuf ) ( cmdBuf ); } else /* paramter inalid - unspecified protocol error */ { TRACE_EVENT("cmhSMS_QueryCnf: ERROR: paramter invalid"); R_AT ( RAT_CMS, ownBuf )( cmdBuf, CMS_ERR_InValManInfo, NULL ); } break; } default: /* unsupported query type - ME failure */ { TRACE_EVENT("cmhSMS_QueryCnf: ERROR: unsupported query type"); R_AT ( RAT_CMS, ownBuf )( cmdBuf, CMS_ERR_MeFail, NULL ); } } /* end switch */ /* reset command */ smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE; smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_ReadCbDtaDwnl | +-------------------------------------------------------------------+ PURPOSE : This function processes the T_SIM_MMI_INSERT_IND primitive. */ GLOBAL void cmhSMS_ReadCbDtaDwnl (T_SIM_MMI_INSERT_IND *sim_mmi_insert_ind) { TRACE_FUNCTION("cmhSMS_ReadCbDtaDwnl()"); if (sim_mmi_insert_ind->cbmid_rec.c_rec NEQ 0) { smsShrdPrm.cbmPrm.cbmSIMmaxSATId = sim_mmi_insert_ind->cbmid_rec.c_rec / 2; cmhSMS_GetCbDtaDwnlSIM (CMD_SRC_NONE, (UBYTE *) sim_mmi_insert_ind->cbmid_rec.rec, sim_mmi_insert_ind->cbmid_rec.c_rec); { PALLOC (sat_cbch_req, MMI_SAT_CBCH_DWNLD_REQ); sat_cbch_req->count = (USHORT)smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds; memset (sat_cbch_req->msg_id, NOT_PRESENT_16BIT, sizeof (sat_cbch_req->msg_id)); memcpy (sat_cbch_req->msg_id, smsShrdPrm.cbmPrm.CBDtaDwnlIdent, (size_t)smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds * 2); PSENDX (PL, sat_cbch_req); } } else { TRACE_EVENT(" CBMID records zero"); smsShrdPrm.cbmPrm.cbmSIMmaxSATId = 0; } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSR | | STATE : code ROUTINE : cmhSMS_SMSQueryType | +-------------------------------------------------------------------+ PURPOSE : This function queries the message type of the T_MNSMS_MESSAGE_IND. */ GLOBAL BOOL cmhSMS_SMSQueryType (T_sms_sdu *sms_sdu, UBYTE *msg_type) { UBYTE ccdRet; TRACE_FUNCTION("cmhSMS_SMSQueryType()"); if (sms_sdu->l_buf EQ 0) { TRACE_EVENT("empty SDU: no decoding"); return FALSE; } CCD_START; { MCAST( sim_pdu, SIM_PDU ); /* sim_pdu points to _decodedMsg */ /* decoding outer layer */ ccdRet = ccd_decodeMsg ( CCDENT_SMS, BOTH /* doesn't work with DOWNLINK!!! */, (T_MSGBUF *) sms_sdu, (UBYTE *) _decodedMsg, /* target */ SMS_VT_SIM_PDU); if ((ccdRet NEQ ccdOK) OR (!sim_pdu->v_tpdu) OR (_decodedMsg[0] NEQ SMS_VT_SIM_PDU)) { TRACE_EVENT_P1("CCD Decoding Error: %d", ccdRet); CCD_END; return FALSE; } *msg_type = sim_pdu->tp_mti; } CCD_END; return TRUE; } LOCAL BOOL cmhSMS_cpySTtoSM(T_ACI_CMGL_SM *p_sm,T_MNSMS_READ_CNF * mnsms_read_cnf) { T_ACI_CDS_SM p_st; T_MNSMS_STATUS_IND mnsms_status_ind; BOOL retCode = FALSE; memcpy (&mnsms_status_ind.sms_sdu, &mnsms_read_cnf->sms_sdu, sizeof (T_sms_sdu)); retCode = cmhSMS_cpyStatInd ( &p_st, &mnsms_status_ind); memcpy(p_sm->adress, p_st.addr, MAX_SMS_ADDR_DIG - 1 ); cmhSMS_getStatCmh ( mnsms_read_cnf->status, &p_sm->stat ); p_sm->msg_ref = mnsms_read_cnf->rec_num ; p_sm->tp_status=p_st.tp_status ; p_sm->toa .ton = p_st.toa .ton ; p_sm->toa.npi = p_st.toa.npi; p_sm->fo = p_st.fo; p_sm->scts =p_st.vpabs_scts ; return (retCode); } /*==== EOF ========================================================*/