2012-12-17 20:14:30 -05:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
# include <limits.h>
# include "CCProvider.h"
# include "cpr_types.h"
# include "cpr_stdlib.h"
# include "cpr_stdio.h"
# include "cpr_string.h"
# include "cpr_rand.h"
# include "cpr_timers.h"
# include "cpr_errno.h"
# include "phone.h"
# include "lsm.h"
# include "fsm.h"
# include "sm.h"
# include "ccapi.h"
# include "ccsip_cc.h"
# include "phone_debug.h"
# include "fim.h"
# include "config.h"
# include "sdp.h"
# include "ccsip_sdp.h" // Temporary include
# include "rtp_defs.h"
# include "debug.h"
# include "gsm_sdp.h"
# include "vcm.h"
# include "uiapi.h"
# include "gsm.h"
# include "phntask.h"
# include "prot_configmgr.h"
# include "sip_interface_regmgr.h"
# include "dialplanint.h"
# include "subapi.h"
# include "text_strings.h"
# include "platform_api.h"
# include "peer_connection_types.h"
2012-12-17 21:28:13 -05:00
//#include "prlog.h"
2012-12-17 20:14:30 -05:00
# include "sessionHash.h"
extern void update_kpmlconfig ( int kpmlVal ) ;
extern boolean g_disable_mass_reg_debug_print ;
void escalateDeescalate ( ) ;
# define FSMDEF_NO_NUMBER (NULL)
# define DIGIT_POUND ('#')
# define FSMDEF_MAX_DCBS (LSM_MAX_CALLS)
# define FSMDEF_CC_CALLER_ID ((cc_state_data_t *)(&(dcb->caller_id)))
# define RINGBACK_DELAY 90
// Minimum and maximum hold reversion timer in seconds
# define MIN_HOLD_REVERSION_INTERVAL_TIMER 10
# define MAX_HOLD_REVERSION_INTERVAL_TIMER 1200
fsmdef_dcb_t * fsmdef_dcbs ;
static const char * fsmdef_state_names [ ] = {
" IDLE " ,
" COLLECTING_INFO " ,
" CALL_SENT " ,
" OUTGOING_PROCEEDING " ,
" KPML_COLLECTING_INFO " ,
" OUTGOING_ALERTING " ,
" INCOMING_ALERTING " ,
" CONNECTING " ,
" JOINING " ,
" CONNECTED " ,
" CONNECTED MEDIA PEND " ,
" RELEASING " ,
" HOLD_PENDING " ,
" HOLDING " ,
" RESUME_PENDING " ,
" PRESERVED "
} ;
static sm_rcs_t fsmdef_ev_createoffer ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_createanswer ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_setlocaldesc ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_setremotedesc ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_setpeerconnection ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_localdesc ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_remotedesc ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_addstream ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_removestream ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_addcandidate ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_default ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_default_feature_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_idle_setup ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_idle_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_idle_offhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_idle_dialstring ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_onhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_collectinginfo_release ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_collectinginfo_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_offhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_digit_begin ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_dialstring ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_proceeding ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_callsent_release ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_callsent_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_out_alerting ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_inalerting_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_inalerting_offhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_handle_inalerting_offhook_answer ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connected ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connected_line ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connected_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connecting_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connected_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connected_media_pend_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_connected_media_pend_feature_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_release ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_release_complete ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_releasing_release ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_releasing_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_releasing_onhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_hold_pending_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_hold_pending_feature_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_holding_release ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_holding_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_holding_feature_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_holding_onhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_holding_offhook ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_session_audit ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_resume_pending_feature ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_resume_pending_feature_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_preserved_feature ( sm_event_t * event ) ;
static void fsmdef_ev_join ( cc_feature_data_t * data ) ;
static sm_rcs_t fsmdef_cfwd_clear_ccm ( fsm_fcb_t * fcb ) ;
static sm_rcs_t fsmdef_process_dialstring_for_callfwd ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_process_cfwd_softkey_event ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_cfwd_clear_ccm ( fsm_fcb_t * fcb ) ;
static sm_rcs_t fsmdef_ev_joining_connected_ack ( sm_event_t * event ) ;
static sm_rcs_t fsmdef_ev_joining_offhook ( sm_event_t * event ) ;
static void fsmdef_b2bjoin_invoke ( fsmdef_dcb_t * dcb ,
cc_feature_data_t * join_data ) ;
static void fsmdef_select_invoke ( fsmdef_dcb_t * dcb ,
cc_feature_data_t * select_data ) ;
static void fsmdef_handle_join_pending ( fsmdef_dcb_t * dcb ) ;
static void fsmdef_append_dialstring_to_feature_uri ( fsmdef_dcb_t * dcb ,
const char * dialstring ) ;
static boolean fsmdef_is_feature_uri_configured ( cc_features_t ftr_id ) ;
static void fsmdef_set_call_info_cc_call_state ( fsmdef_dcb_t * dcb ,
cc_states_t state ,
cc_causes_t cause ) ;
static boolean fsmdef_extract_join_target ( sm_event_t * event ) ;
static void fsmdef_ev_notify_feature ( cc_feature_t * msg , fsmdef_dcb_t * dcb ) ;
static void fsmdef_notify_hook_event ( fsm_fcb_t * fcb , cc_msgs_t msg ,
char * global_call_id ,
callid_t prim_call_id ,
cc_hold_resume_reason_e consult_reason ,
monitor_mode_t monitor_mode ,
cfwdall_mode_t cfwdall_mode ) ;
static void fsmdef_update_callinfo_security_status ( fsmdef_dcb_t * dcb ,
cc_feature_data_call_info_t * call_info ) ;
static void fsmdef_update_calltype ( fsm_fcb_t * fcb , cc_feature_t * msg ) ;
/*
* TODO < emannion > Update events for correct JSEP transitions
* Instead of providing events for all states
*/
static sm_function_t fsmdef_function_table [ FSMDEF_S_MAX ] [ CC_MSG_MAX ] =
{
/* FSMDEF_S_IDLE ------------------------------------------------------------ */
{
/* CC_MSG_SETUP */ fsmdef_ev_idle_setup , // New incoming
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_default ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_release_complete ,
/* CC_MSG_FEATURE */ fsmdef_ev_idle_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_idle_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_default ,
/* CC_MSG_LINE */ fsmdef_ev_idle_offhook ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_idle_dialstring , // new outgoing
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_COLLECT_INFO ---------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_collectinginfo_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_collectinginfo_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_default ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_digit_begin ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_dialstring ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_CALL_SENT ------------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_proceeding ,
/* CC_MSG_ALERTING */ fsmdef_ev_out_alerting ,
/* CC_MSG_CONNECTED */ fsmdef_ev_connected ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_callsent_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_callsent_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_OUTGOING_PROCEEDING --------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_out_alerting ,
/* CC_MSG_CONNECTED */ fsmdef_ev_connected ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_callsent_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_callsent_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_KPML_COLLECT_INFO ----------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_out_alerting ,
/* CC_MSG_CONNECTED */ fsmdef_ev_connected ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_callsent_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_collectinginfo_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_default ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_digit_begin ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_OUTGOING_ALERTING ----------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_out_alerting ,
/* CC_MSG_CONNECTED */ fsmdef_ev_connected ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_callsent_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_callsent_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_INCOMING_ALERTING ----------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_inalerting_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_inalerting_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_inalerting_offhook ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_CONNECTING ------------------------------------------------------ */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_connected_ack ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_connecting_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_connected_line ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_JOINING --------------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_joining_connected_ack ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_connecting_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_joining_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_connected_line ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_CONNECTED ------------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_connected_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_connected_line ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_CONNECTED_MEDIA_PEND ------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_connected_media_pend_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_connected_media_pend_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_connected_line ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_RELEASING ------------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_releasing_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_release_complete ,
/* CC_MSG_FEATURE */ fsmdef_ev_releasing_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_default ,
/* CC_MSG_ONHOOK */ fsmdef_ev_releasing_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_connected_line ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_HOLD_PENDING ---------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_holding_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_hold_pending_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_hold_pending_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_default ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_HOLDING --------------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_holding_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_holding_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_holding_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_holding_offhook ,
/* CC_MSG_ONHOOK */ fsmdef_ev_holding_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_RESUME_PENDING -------------------------------------------------- */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_resume_pending_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_resume_pending_feature_ack ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_default ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
} ,
/* FSMDEF_S_PRESERVED ------------------------------------------------------ */
{
/* CC_MSG_SETUP */ fsmdef_ev_default ,
/* CC_MSG_SETUP_ACK */ fsmdef_ev_default ,
/* CC_MSG_PROCEEDING */ fsmdef_ev_default ,
/* CC_MSG_ALERTING */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED */ fsmdef_ev_default ,
/* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default ,
/* CC_MSG_RELEASE */ fsmdef_ev_release ,
/* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default ,
/* CC_MSG_FEATURE */ fsmdef_ev_preserved_feature ,
/* CC_MSG_FEATURE_ACK */ fsmdef_ev_default ,
/* CC_MSG_OFFHOOK */ fsmdef_ev_default ,
/* CC_MSG_ONHOOK */ fsmdef_ev_onhook ,
/* CC_MSG_LINE */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default ,
/* CC_MSG_DIGIT_END */ fsmdef_ev_default ,
/* CC_MSG_DIALSTRING */ fsmdef_ev_default ,
/* CC_MSG_MWI */ fsmdef_ev_default ,
/* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit ,
/* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer ,
/* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer ,
/* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc ,
/* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc ,
/* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc ,
/* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc ,
/* CC_MSG_SETPEERCONNECTION */ fsmdef_ev_setpeerconnection ,
/* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream ,
/* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream ,
/* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
}
} ;
static sm_table_t fsmdef_sm_table ;
sm_table_t * pfsmdef_sm_table = & fsmdef_sm_table ;
/*--------------------------------------------------------------------------
* Global data
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
uint16_t g_numofselected_calls = 0 ;
boolean g_b2bjoin_pending = FALSE ;
callid_t g_b2bjoin_callid = CC_NO_CALL_ID ;
static sdp_direction_e s_default_video_dir = SDP_DIRECTION_SENDRECV ;
static sdp_direction_e s_session_video_dir = SDP_MAX_QOS_DIRECTIONS ;
void set_default_video_pref ( int pref ) {
s_default_video_dir = pref ;
}
void set_next_sess_video_pref ( int pref ) {
s_session_video_dir = pref ;
}
const char *
fsmdef_state_name ( int state )
{
if ( ( state < = FSMDEF_S_MIN ) | | ( state > = FSMDEF_S_MAX ) ) {
return ( get_debug_string ( GSM_UNDEFINED ) ) ;
}
return ( fsmdef_state_names [ state ] ) ;
}
/*
* fsmdef_get_dcb_by_call_id
*
* return the dcb referenced by the given call_id
*/
fsmdef_dcb_t *
fsmdef_get_dcb_by_call_id ( callid_t call_id )
{
static const char fname [ ] = " fsmdef_get_dcb_by_call_id " ;
fsmdef_dcb_t * dcb ;
fsmdef_dcb_t * dcb_found = NULL ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > call_id = = call_id ) {
dcb_found = dcb ;
break ;
}
}
if ( dcb_found ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_PTR ) ,
dcb - > call_id , dcb - > line , fname , dcb_found ) ;
}
return ( dcb_found ) ;
}
/*
* fsmdef_check_if_chaperone_call_exist
*
* return the dcb referenced by the given call_id
*/
boolean
fsmdef_check_if_chaperone_call_exist ( void )
{
static const char fname [ ] = " fsmdef_check_if_chaperone_call_exist " ;
fsmdef_dcb_t * dcb ;
boolean result = FALSE ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > policy = = CC_POLICY_CHAPERONE ) {
result = TRUE ;
break ;
}
}
if ( result ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_PTR ) ,
dcb - > call_id , dcb - > line , fname , dcb ) ;
}
return result ;
}
void fsmdef_get_rtp_stat ( fsmdef_dcb_t * dcb , cc_kfact_t * kfactor )
{
static const char fname [ ] = " fsmdef_get_rtp_stat " ;
int call_stats_flag ;
fsmdef_media_t * media ;
media = gsmsdp_find_audio_media ( dcb ) ;
if ( ! media ) {
GSM_ERR_MSG ( GSM_F_PREFIX " dcb media pointer invalid \n " , fname ) ;
return ;
}
memset ( kfactor , 0 , sizeof ( cc_kfact_t ) ) ;
config_get_value ( CFGID_CALL_STATS , & call_stats_flag , sizeof ( call_stats_flag ) ) ;
if ( call_stats_flag ) {
vcmGetRtpStats ( media - > cap_index , dcb - > group_id ,
media - > refid ,
lsm_get_ms_ui_call_handle ( dcb - > line , dcb - > call_id , CC_NO_CALL_ID ) , & ( kfactor - > rxstats [ 0 ] ) , & ( kfactor - > txstats [ 0 ] ) ) ;
}
}
/**
* The function sets or clears the local hold status to the given media or
* for all of the media .
*
* @ param [ in ] dcb - pointer to fsmdef_dcb_t .
* @ param [ in ] media - specify which media to use . The value of
* NULL indicates for all media .
* @ param [ in ] set - set local hold or clear local hold .
*
* @ return none
*
* @ pre ( dcb not_eq NULL )
*/
static void
fsmdef_update_media_hold_status ( fsmdef_dcb_t * dcb , fsmdef_media_t * media ,
boolean set )
{
fsmdef_media_t * start_media , * end_media ;
if ( media = = NULL ) {
/* NULL value of the given media indicates for all media */
start_media = GSMSDP_FIRST_MEDIA_ENTRY ( dcb ) ;
end_media = NULL ; /* NULL means till the end of the list */
} else {
/* given media, uses the provided media */
start_media = media ;
end_media = media ;
}
GSMSDP_FOR_MEDIA_LIST ( media , start_media , end_media , dcb ) {
if ( GSMSDP_MEDIA_ENABLED ( media ) ) {
if ( set ) {
FSM_SET_FLAGS ( media - > hold , FSM_HOLD_LCL ) ;
} else {
FSM_RESET_FLAGS ( media - > hold , FSM_HOLD_LCL ) ;
}
}
}
}
/**
* The function checks to see whether all media streams are
* in locally held or not .
*
* @ param [ in ] dcb - pointer to fsmdef_dcb_t .
*
* @ return TRUE - all media streams are in local hold .
* FALSE - not all media streams are in local hold .
*
* @ pre ( dcb not_eq NULL )
*/
static boolean
fsmdef_all_media_are_local_hold ( fsmdef_dcb_t * dcb )
{
fsmdef_media_t * media ;
/*
* Check the local hold status of each media to see if the
* media is already locally held or not .
*/
GSMSDP_FOR_ALL_MEDIA ( media , dcb ) {
if ( ! GSMSDP_MEDIA_ENABLED ( media ) ) {
continue ;
}
if ( ! FSM_CHK_FLAGS ( media - > hold , FSM_HOLD_LCL ) ) {
/* found one media that is not on hold */
return ( FALSE ) ;
}
}
/* all media streams are local held */
return ( TRUE ) ;
}
/**
* The function gets the numbmer of media in local hold .
*
* @ param [ in ] dcb - pointer to fsmdef_dcb_t .
*
* @ return uint16_t for the number of media in local hold .
*
* @ pre ( dcb not_eq NULL )
*/
static unsigned int
fsmdef_num_media_in_local_hold ( fsmdef_dcb_t * dcb )
{
fsmdef_media_t * media ;
unsigned int num_local_hold = 0 ;
/* Check the local hold status of the media(s) */
GSMSDP_FOR_ALL_MEDIA ( media , dcb ) {
if ( ! GSMSDP_MEDIA_ENABLED ( media ) ) {
continue ;
}
if ( FSM_CHK_FLAGS ( media - > hold , FSM_HOLD_LCL ) ) {
num_local_hold + + ;
}
}
return ( num_local_hold ) ;
}
/**
* The function is a convenient function to set each local hold in
* SDP for each media if it is marked as locally held .
*
* @ param [ in ] dcb - pointer to fsmdef_dcb_t .
*
* @ return None
*
* @ pre ( dcb not_eq NULL )
*/
static void
fsmdef_set_per_media_local_hold_sdp ( fsmdef_dcb_t * dcb )
{
fsmdef_media_t * media ;
GSMSDP_FOR_ALL_MEDIA ( media , dcb ) {
if ( ! GSMSDP_MEDIA_ENABLED ( media ) ) {
continue ;
}
if ( FSM_CHK_FLAGS ( media - > hold , FSM_HOLD_LCL ) ) {
/* set local hold to this media entry */
gsmsdp_set_local_hold_sdp ( dcb , media ) ;
}
}
}
void
fsmdef_init_dcb ( fsmdef_dcb_t * dcb , callid_t call_id ,
fsmdef_call_types_t call_type ,
string_t called_number , line_t line , fsm_fcb_t * fcb )
{
string_t calling_name ;
int blocking ;
char name [ MAX_LINE_NAME_SIZE ] ;
dcb - > call_id = call_id ;
dcb - > line = line ;
dcb - > spoof_ringout_requested = FALSE ;
dcb - > spoof_ringout_applied = FALSE ;
dcb - > log_disp = CC_CALL_LOG_DISP_UNKNWN ;
fsmutil_init_groupid ( dcb , call_id , call_type ) ;
/*
* Fill in as much of the caller_id data as possible .
* Different data is available based on the call_type .
*/
switch ( call_type ) {
case FSMDEF_CALL_TYPE_OUTGOING :
config_get_value ( CFGID_CALLERID_BLOCKING , & blocking , sizeof ( blocking ) ) ;
if ( line ! = 0 ) {
sip_config_get_display_name ( line , name , sizeof ( name ) ) ;
}
if ( blocking & 1 | | line = = 0 ) {
calling_name = SIP_HEADER_ANONYMOUS_STR ;
} else {
calling_name = name ;
}
dcb - > caller_id . calling_name = strlib_update ( dcb - > caller_id . calling_name ,
calling_name ) ;
dcb - > caller_id . calling_number =
strlib_update ( dcb - > caller_id . calling_number , name ) ;
/*
* called_xxx data will be set when the fsmdef receives the dialstring .
*/
dcb - > caller_id . called_name = strlib_empty ( ) ;
dcb - > caller_id . called_number = strlib_empty ( ) ;
dcb - > caller_id . orig_rpid_number = strlib_empty ( ) ;
dcb - > inbound = FALSE ;
break ;
case FSMDEF_CALL_TYPE_INCOMING :
case FSMDEF_CALL_TYPE_FORWARD :
/*
* calling_xxx data will be set when the fsmdef receives the setup .
*/
dcb - > caller_id . calling_name = strlib_empty ( ) ;
dcb - > caller_id . calling_number = strlib_empty ( ) ;
dcb - > caller_id . last_redirect_name = strlib_empty ( ) ;
dcb - > caller_id . last_redirect_number = strlib_empty ( ) ;
dcb - > caller_id . orig_called_name = strlib_empty ( ) ;
dcb - > caller_id . orig_called_number = strlib_empty ( ) ;
dcb - > caller_id . orig_rpid_number = strlib_empty ( ) ;
sip_config_get_display_name ( line , name , sizeof ( name ) ) ;
dcb - > caller_id . called_name =
strlib_update ( dcb - > caller_id . called_name , name ) ;
dcb - > caller_id . called_number =
strlib_update ( dcb - > caller_id . called_number , called_number ) ;
dcb - > inbound = TRUE ;
break ;
case FSMDEF_CALL_TYPE_NONE :
dcb - > caller_id . calling_name = strlib_empty ( ) ;
dcb - > caller_id . calling_number = strlib_empty ( ) ;
dcb - > caller_id . called_name = strlib_empty ( ) ;
dcb - > caller_id . called_number = strlib_empty ( ) ;
dcb - > caller_id . alt_calling_number = strlib_empty ( ) ;
dcb - > caller_id . last_redirect_name = strlib_empty ( ) ;
dcb - > caller_id . last_redirect_number = strlib_empty ( ) ;
dcb - > caller_id . orig_called_name = strlib_empty ( ) ;
dcb - > caller_id . orig_called_number = strlib_empty ( ) ;
dcb - > caller_id . orig_rpid_number = strlib_empty ( ) ;
dcb - > inbound = FALSE ;
break ;
default :
break ;
} /* switch (call_type) { */
dcb - > caller_id . display_calling_number = TRUE ;
dcb - > caller_id . display_called_number = TRUE ;
/* Initially, assume ui update is required for a new call. */
dcb - > ui_update_required = TRUE ;
dcb - > placed_call_update_required = TRUE ;
dcb - > is_conf_call = FALSE ; /*Initially, set to conf call false*/
dcb - > digit_cnt = 0 ;
dcb - > call_type = call_type ;
dcb - > orientation = CC_ORIENTATION_NONE ;
dcb - > caller_id . call_instance_id = 0 ;
dcb - > msgs_sent = FSMDEF_MSG_NONE ;
dcb - > msgs_rcvd = FSMDEF_MSG_NONE ;
dcb - > send_release = FALSE ;
dcb - > inband = FALSE ;
dcb - > inband_received = FALSE ;
dcb - > outofband = 0 ;
dcb - > remote_sdp_present = FALSE ;
dcb - > remote_sdp_in_ack = FALSE ;
dcb - > sdp = NULL ;
dcb - > src_sdp_version = 0 ;
dcb - > dial_mode = DIAL_MODE_NUMERIC ;
dcb - > hold_reason = CC_REASON_NONE ;
dcb - > pd_updated = FALSE ;
dcb - > alerting_tone = VCM_NO_TONE ;
dcb - > tone_direction = VCM_PLAY_TONE_TO_EAR ;
dcb - > alert_info = ALERTING_NONE ;
dcb - > dialplan_tone = FALSE ;
dcb - > active_tone = VCM_NO_TONE ;
dcb - > monrec_tone_action = FSMDEF_MRTONE_NO_ACTION ;
dcb - > monitor_tone_direction = VCM_PLAY_TONE_TO_EAR ;
dcb - > recorder_tone_direction = VCM_PLAY_TONE_TO_EAR ;
dcb - > play_tone_action = FSMDEF_PLAYTONE_NO_ACTION ;
dcb - > fcb = fcb ;
dcb - > early_error_release = FALSE ;
dcb - > active_feature = CC_FEATURE_NONE ;
/* Release transient timers if any have been allocated */
if ( dcb - > err_onhook_tmr ) {
( void ) cprDestroyTimer ( dcb - > err_onhook_tmr ) ;
dcb - > err_onhook_tmr = NULL ;
}
if ( dcb - > req_pending_tmr ) {
( void ) cprDestroyTimer ( dcb - > req_pending_tmr ) ;
dcb - > req_pending_tmr = NULL ;
}
FSM_SET_SECURITY_STATUS ( dcb , CC_SECURITY_UNKNOWN ) ;
FSM_SET_POLICY ( dcb , CC_POLICY_UNKNOWN ) ;
dcb - > session = PRIMARY ;
dcb - > dsp_out_of_resources = FALSE ;
if ( dcb - > selected ) {
g_numofselected_calls - - ;
}
dcb - > selected = FALSE ;
dcb - > select_pending = FALSE ;
dcb - > call_not_counted_in_mnc_bt = FALSE ;
if ( g_disable_mass_reg_debug_print = = FALSE ) {
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " call_not_counted_in_mnc_bt = FALSE \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , line , call_id , " fsmdef_init_dcb " ) ) ;
}
/* clear all bit flags */
dcb - > flags = 0 ;
dcb - > onhook_received = FALSE ;
dcb - > cur_video_avail = SDP_DIRECTION_INACTIVE ;
if ( s_session_video_dir ! = SDP_MAX_QOS_DIRECTIONS & &
call_type = = FSMDEF_CALL_TYPE_OUTGOING ) {
dcb - > video_pref = s_session_video_dir ;
s_session_video_dir = SDP_MAX_QOS_DIRECTIONS ;
} else {
dcb - > video_pref = s_default_video_dir ;
}
gsmsdp_init_media_list ( dcb ) ;
dcb - > join_call_id = CC_NO_CALL_ID ;
dcb - > callref = 0 ;
dcb - > ice_ufrag = NULL ;
dcb - > ice_pwd = NULL ;
dcb - > ice_default_candidate_addr [ 0 ] = ' \0 ' ;
dcb - > digest_alg [ 0 ] = ' \0 ' ;
dcb - > digest [ 0 ] = ' \0 ' ;
}
static void
fsmdef_free_dcb ( fsmdef_dcb_t * dcb )
{
if ( dcb = = NULL ) {
return ;
}
strlib_free ( dcb - > caller_id . calling_name ) ;
strlib_free ( dcb - > caller_id . calling_number ) ;
strlib_free ( dcb - > caller_id . alt_calling_number ) ;
strlib_free ( dcb - > caller_id . called_name ) ;
strlib_free ( dcb - > caller_id . called_number ) ;
strlib_free ( dcb - > caller_id . last_redirect_name ) ;
strlib_free ( dcb - > caller_id . last_redirect_number ) ;
strlib_free ( dcb - > caller_id . orig_called_name ) ;
strlib_free ( dcb - > caller_id . orig_called_number ) ;
strlib_free ( dcb - > caller_id . orig_rpid_number ) ;
/* Cancel any existing error onhook timer */
if ( dcb - > err_onhook_tmr ) {
( void ) cprCancelTimer ( dcb - > err_onhook_tmr ) ;
( void ) cprDestroyTimer ( dcb - > err_onhook_tmr ) ;
dcb - > err_onhook_tmr = NULL ;
}
/* Cancel any existing request pending timer */
if ( dcb - > req_pending_tmr ) {
( void ) cprCancelTimer ( dcb - > req_pending_tmr ) ;
( void ) cprDestroyTimer ( dcb - > req_pending_tmr ) ;
dcb - > req_pending_tmr = NULL ;
}
/* Cancel any existing ringback delay timer */
if ( dcb - > ringback_delay_tmr ) {
( void ) cprCancelTimer ( dcb - > ringback_delay_tmr ) ;
}
// Free the call instance id
if ( dcb - > caller_id . call_instance_id ! = 0 ) {
fsmutil_free_ci_id ( dcb - > caller_id . call_instance_id , dcb - > line ) ;
}
/* clean media list */
gsmsdp_clean_media_list ( dcb ) ;
gsmsdp_free ( dcb ) ;
fsmdef_init_dcb ( dcb , CC_NO_CALL_ID , FSMDEF_CALL_TYPE_NONE , NULL ,
LSM_NO_LINE , NULL ) ;
/*
* Cache random numbers for SRTP keys
*/
gsmsdp_cache_crypto_keys ( ) ;
}
void
fsmdef_free_cb ( fim_icb_t * icb , callid_t call_id )
{
fsm_fcb_t * fcb = NULL ;
fsmdef_dcb_t * dcb = NULL ;
if ( call_id ! = CC_NO_CALL_ID ) {
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb ! = NULL ) {
fcb = dcb - > fcb ;
fsmdef_init_dcb ( dcb , CC_NO_CALL_ID , FSMDEF_CALL_TYPE_NONE ,
NULL , LSM_NO_LINE , NULL ) ;
/* fsmdef_init_dcb(...,NULL) will always set the fcb ptr to NULL,
so if fsmdef_free_cb were called on that we ' d have fcb = = NULL here */
if ( fcb ! = NULL ) {
fsm_init_fcb ( fcb , CC_NO_CALL_ID , FSMDEF_NO_DCB , FSM_TYPE_NONE ) ;
}
} else {
fcb = fsm_get_fcb_by_call_id_and_type ( call_id , FSM_TYPE_DEF ) ;
if ( fcb ! = NULL ) {
fsm_init_fcb ( fcb , CC_NO_CALL_ID , FSMDEF_NO_DCB , FSM_TYPE_NONE ) ;
}
}
}
}
/*
* ROUTINE : fsmdef_get_new_dcb
*
* DESCRIPTION : return a new dcb initialized with the given data
*
* PARAMETERS :
* call_id : call_id
*
* RETURNS :
* dcb : the new dcb
*
* NOTES : None
*/
fsmdef_dcb_t *
fsmdef_get_new_dcb ( callid_t call_id )
{
static const char fname [ ] = " fsmdef_get_new_dcb " ;
fsmdef_dcb_t * dcb = NULL ;
/*
* Get a free dcb .
*/
if ( ( dcb = fsmdef_get_dcb_by_call_id ( CC_NO_CALL_ID ) ) = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , call_id , 0 , fname ,
" no dcbs available " ) ;
return ( NULL ) ;
}
dcb - > call_id = call_id ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_PTR ) ,
dcb - > call_id , dcb - > line , fname , dcb ) ;
return ( dcb ) ;
}
/**
*
* Returns dcb related to connected call .
*
* @ param none
*
* @ return dcb of connected call .
*
* @ pre none
*/
fsmdef_dcb_t *
fsmdef_get_connected_call ( void )
{
fsmdef_dcb_t * dcb ;
fsm_fcb_t * fcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > call_id ! = CC_NO_CALL_ID ) {
fcb = dcb - > fcb ;
if ( ( fcb ! = NULL ) & & ( fcb - > state = = FSMDEF_S_RESUME_PENDING | |
fcb - > state = = FSMDEF_S_CONNECTED | |
fcb - > state = = FSMDEF_S_CONNECTED_MEDIA_PEND ) ) {
return ( dcb ) ;
}
}
}
return ( NULL ) ;
}
/**
*
* Returns dcb related to alerting out call .
*
* @ param none
*
* @ return dcb of outgoing alerting call .
*
* @ pre none
*/
static fsmdef_dcb_t *
fsmdef_get_alertingout_call ( void )
{
fsmdef_dcb_t * dcb ;
fsm_fcb_t * fcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > call_id ! = CC_NO_CALL_ID ) {
fcb = dcb - > fcb ;
if ( ( fcb ! = NULL ) & & ( fcb - > state = = FSMDEF_S_OUTGOING_ALERTING ) ) {
return ( dcb ) ;
}
}
}
return ( NULL ) ;
}
/*
* fsmdef_get_active_call_cnt
*
* Return the count of active calls aside from the
* callid passed in .
*/
int
fsmdef_get_active_call_cnt ( callid_t callId )
{
fsmdef_dcb_t * dcb ;
int cnt = 0 ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( ( dcb - > call_id ! = CC_NO_CALL_ID ) & & ( dcb - > call_id ! = callId ) ) {
cnt + + ;
}
}
return ( cnt ) ;
}
/*
* return the dcbs and count of calls that are ringing and
* are in error state not including the given call_id
*
* @ param pointer to dcbs array
* @ param call_id that should be ignored from search
*
* @ return int number of ringing or error state calls
*
* @ pre none
*/
static int
fsmdef_get_ringing_n_error_call_dcbs ( fsmdef_dcb_t * * dcbs , callid_t ignore_call_id )
{
fsmdef_dcb_t * dcb ;
int cnt = 0 ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > spoof_ringout_applied | |
( ( dcb - > call_id ! = CC_NO_CALL_ID ) & &
( dcb - > call_id ! = ignore_call_id ) & &
( dcb - > fcb & & ( ( dcb - > fcb - > state < = FSMDEF_S_CONNECTING ) | |
( dcb - > fcb - > state = = FSMDEF_S_RELEASING ) ) ) ) ) {
dcbs [ cnt + + ] = dcb ;
}
}
return ( cnt ) ;
}
int
fsmdef_get_dcbs_in_held_state ( fsmdef_dcb_t * * dcbs , callid_t ignore_call_id )
{
fsmdef_dcb_t * dcb ;
int cnt = 0 ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( ( dcb - > call_id ! = CC_NO_CALL_ID ) & &
( dcb - > call_id ! = ignore_call_id ) & &
( dcb - > fcb & & ( dcb - > fcb - > state = = FSMDEF_S_HOLDING | |
dcb - > fcb - > state = = FSMDEF_S_HOLD_PENDING ) ) ) {
dcbs [ cnt + + ] = dcb ;
}
}
return ( cnt ) ;
}
void fsmdef_call_cc_state_dialing ( fsmdef_dcb_t * dcb , boolean suppress )
{
cc_state_data_dialing_t data ;
if ( dcb - > caller_id . called_number [ 0 ] = = ' \0 ' ) {
data . play_dt = TRUE ;
} else {
data . play_dt = FALSE ;
}
data . suppress_stutter = suppress ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_DIALING ,
( cc_state_data_t * ) ( & data ) ) ;
}
/*
* fsmdef_get_other_dcb_by_line
*
* return the dcb of the call that is active on a given line ,
* not including the given call_id
*/
fsmdef_dcb_t *
fsmdef_get_other_dcb_by_line ( callid_t call_id , line_t line )
{
fsmdef_dcb_t * dcb ;
fsmdef_dcb_t * dcb_found = NULL ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( ( dcb - > call_id ! = CC_NO_CALL_ID ) & &
( dcb - > line = = line ) & & ( dcb - > call_id ! = call_id ) ) {
dcb_found = dcb ;
}
}
return ( dcb_found ) ;
}
/*
* fsmdef_are_there_selected_calls_onotherline
*
* @ param line - line number
*
* loop thru the dcbs and check if there are selected calls
* on a line other than this one
*
* @ return TRUE , there are
* FALSE there are not
*/
boolean fsmdef_are_there_selected_calls_onotherline ( line_t line )
{
fsmdef_dcb_t * dcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > selected ) {
if ( dcb - > line ! = line ) {
return ( TRUE ) ;
}
}
}
return ( FALSE ) ;
}
/*
* fsmdef_are_join_calls_on_same_line
*
* @ param line - line number
*
* loop thru the dcbs and check if the line passed is the
* same as where the initial join started
*
* @ return TRUE , they are on the same line
* FALSE not on the same line
*/
boolean fsmdef_are_join_calls_on_same_line ( line_t line )
{
fsmdef_dcb_t * dcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > call_id = = g_b2bjoin_callid ) {
if ( dcb - > line ! = line ) {
return ( FALSE ) ;
} else {
return ( TRUE ) ;
}
}
}
return ( FALSE ) ;
}
/**
*
* Handles media capability update feature event from platform when
* media stream capability changes .
*
* @ param [ in ] msg - pointer to the cc_feature_t .
*
* @ return None .
*
* @ pre ( msg not_eq NULL )
*/
void
fsmdef_update_media_cap_feature_event ( cc_feature_t * msg )
{
static const char fname [ ] = " fsmdef_update_media_cap_feature_event " ;
fsmdef_dcb_t * dcb ;
fsm_fcb_t * fcb ;
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " \n " , DEB_L_C_F_PREFIX_ARGS ( FSM , msg - > line , msg - > call_id , fname ) ) ;
/*
* Find the connected call to send the media capability update
* event to . There can be more than one call chains in
* connected state for an example , a call that participates in
* local conference , barged , monitored . All calls that
* are active are sent the update event . Each call leg will handle
* the event .
*
*/
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > call_id ! = CC_NO_CALL_ID ) {
fcb = dcb - > fcb ;
if ( ( fcb ! = NULL ) & & ( fcb - > state = = FSMDEF_S_RESUME_PENDING | |
fcb - > state = = FSMDEF_S_CONNECTED ) ) {
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_UPD_MEDIA_CAP , NULL ) ;
}
}
}
}
/**
*
* Function to find and hold any connected call .
*
* @ param call_id call id of the call
* @ param wait flag to indicate if the caller has to wait ton invoke the event
* @ param src_id source id of the caller where to post hold or endcall event .
*
* @ return none
*
* @ pre ( wait = = FALSE )
*/
static void
fsmdef_find_and_hold_connected_call ( callid_t call_id , boolean * wait ,
cc_srcs_t src_id )
{
fsmdef_dcb_t * con_dcb ;
fsmcnf_ccb_t * ccb ;
fsmcnf_ccb_t * con_ccb ;
fsmxfr_xcb_t * xcb ;
cc_feature_data_t data ;
callid_t other_call_id ;
callid_t other_call_id2 ;
* wait = FALSE ;
/*
* Place the connected call , if there is one , on hold ,
* but there are some restrictions to ignore the hold request :
* 1. the connected call must be different than the one requesting the hold ,
* 2. the connected call is involved with this call in a conference and
* the conference is active .
* NOTE : for case 2 , why do we not send a hold for each of the calls
* involved in the conference ? Because , the fsmcnf will generate the
* second hold for the other leg of the conference when it receives
* this hold .
* 3. the connected call is in a conference with another call that is
* involved with a transfer . This is the case when two calls are in a
* conference and a bridge decides to transfer one leg of the bridge
* using REFER . I . E . , cnf between A - B and A - C . B initiates transfer to D .
* B holds A - B , sends REFER to A , A holds A - B , initiates A - D , D answers ,
* A hangs up A - B and connects conference . So , when A initiates A - D ,
* we do not want to hold the active bridge between A - C .
*/
con_dcb = fsmdef_get_connected_call ( ) ;
if ( ( con_dcb ! = NULL ) & & ( ( con_dcb - > call_id ! = call_id ) | |
( con_dcb - > spoof_ringout_applied = = FALSE ) ) ) {
ccb = fsmcnf_get_ccb_by_call_id ( call_id ) ;
con_ccb = fsmcnf_get_ccb_by_call_id ( con_dcb - > call_id ) ;
if ( ( ccb = = NULL ) | | ( con_ccb = = NULL ) | |
( ( ccb = = con_ccb ) & & ( ccb - > active ! = TRUE ) ) | | ( ccb ! = con_ccb ) ) {
other_call_id = fsmcnf_get_other_call_id ( con_ccb , con_dcb - > call_id ) ;
xcb = fsmxfr_get_xcb_by_call_id ( other_call_id ) ;
other_call_id2 = fsmxfr_get_other_call_id ( xcb , other_call_id ) ;
if ( call_id ! = other_call_id2 ) {
* wait = TRUE ;
data . hold . call_info . type = CC_FEAT_HOLD ;
data . hold . call_info . data . hold_resume_reason =
CC_REASON_INTERNAL ;
data . hold . msg_body . num_parts = 0 ;
data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
cc_int_feature ( src_id , CC_SRC_GSM , con_dcb - > call_id ,
con_dcb - > line , CC_FEATURE_HOLD , & data ) ;
}
}
}
}
/*
* Function post a event to end the call which are in ringing
* reorder or busy and connecting state . This would indicate call function to
* wait on the existing event .
*
* @ param call_id that should be ignored from search
* @ param pointer to boolean to indicate if the caller has to wait
*
* @ return none
*
* @ pre none
*/
static void
fsmdef_find_and_handle_ring_connecting_releasing_calls ( callid_t call_id , boolean * wait )
{
int i ;
int act_dcb_cnt ;
fsmdef_dcb_t * act_dcb ;
fsmdef_dcb_t * act_dcbs [ LSM_MAX_CALLS ] ;
cc_feature_data_t data ;
* wait = FALSE ;
data . endcall . cause = CC_CAUSE_NORMAL ;
data . endcall . dialstring [ 0 ] = ' \0 ' ;
act_dcb_cnt = fsmdef_get_ringing_n_error_call_dcbs ( act_dcbs , call_id ) ;
for ( i = 0 ; i < act_dcb_cnt ; i + + ) {
act_dcb = act_dcbs [ i ] ;
/*
* Clear all the outgoing ringing lines ( if there are any ) .
*/
if ( act_dcb - > call_type = = FSMDEF_CALL_TYPE_OUTGOING | |
act_dcb - > spoof_ringout_applied ) {
* wait = TRUE ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , act_dcb - > call_id ,
act_dcb - > line , CC_FEATURE_END_CALL , & data ) ;
}
else if ( act_dcb - > fcb - > state = = FSMDEF_S_CONNECTING ) {
/* If the call is in connecting state, then wait till SIP
* response to get the call in connected state .
* The call can be put on hold only when call is connected .
*/
* wait = TRUE ;
}
}
}
void
fsmdef_end_call ( fsmdef_dcb_t * dcb , cc_causes_t cause )
{
cc_feature_data_t data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
data . endcall . cause = cause ;
data . endcall . dialstring [ 0 ] = ' \0 ' ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id , dcb - > line ,
CC_FEATURE_END_CALL , & data ) ;
}
/*
* fsmdef_clear_preserved_calls
*
* Release any calls in the preserved state
*/
static void
fsmdef_clear_preserved_calls ( boolean * wait )
{
fsmdef_dcb_t * dcb ;
* wait = FALSE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( ( dcb - > call_id ! = CC_NO_CALL_ID ) & &
( dcb - > fcb - > state = = FSMDEF_S_PRESERVED ) ) {
* wait = TRUE ;
fsmdef_end_call ( dcb , CC_CAUSE_NORMAL ) ;
}
}
}
/**
*
* Checks to see if actions are required for existing calls before the new
* call can be activated .
*
* 1. Place the currently active connected call on hold .
* 2. Clear any ringing calls .
* 3. Release any call in the preserved state .
*
* @ param is_newcall To indicate if this is a new call
* @ param src_id source of the caller
* @ param call_id call - id
* @ param line line number
* @ param feature feature which is waiting on hodling call .
* @ param feature data
*
* @ return TRUE if actions require delay before the new call may begin
* FALSE if no actions are required an the new call may begin
*
* @ pre ( wait , wait2 , wait3 all FALSE )
*/
static boolean
fsmdef_wait_to_start_new_call ( boolean is_newcall , cc_srcs_t src_id , callid_t call_id ,
line_t line , cc_features_t feature ,
cc_feature_data_t * data )
{
boolean wait = FALSE ;
boolean wait2 = FALSE ;
boolean wait3 = FALSE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsmdef_find_and_hold_connected_call ( call_id , & wait , src_id ) ;
fsmdef_find_and_handle_ring_connecting_releasing_calls ( call_id , & wait2 ) ;
fsmdef_clear_preserved_calls ( & wait3 ) ;
/*
* Requeue the message because we need to wait for call actions to complete
*/
if ( ( wait ) | | ( wait2 ) | | ( wait3 ) ) {
cc_int_feature ( src_id , CC_SRC_GSM , call_id , line , feature , data ) ;
}
return ( wait | wait2 | wait3 ) ;
}
static cc_causes_t
fsmdef_get_cause ( boolean data_valid , cc_feature_data_t * data )
{
cc_causes_t cause ;
if ( data_valid ) {
cause = data - > endcall . cause ;
} else {
cause = CC_CAUSE_NORMAL ;
}
return ( cause ) ;
}
/**
* common function to release a call given cause code
* i . e onhooks the given call .
*
* @ param [ in ] fcb The pointer to the fsm_fcb_t structure of this
* call chain .
* @ param [ in ] cause release cause code .
*
* @ param [ in ] send_release When set to TRUE the function sends release
* and waits for release complete .
* When set to FALSE the function cleans up
* dcb and release fcb .
*
* @ pre ( fcb not_eq NULL )
*
* @ return sm_rcs_t indicates whether the execution of
* next statmachine to end ( SM_RC_END ) or clean up
* ( SM_RC_CLEANUP )
*
* @ Usage Note : The function uses send_release flag to
* as an indicator for sending release out or not .
* If release is sent , the function transitions fsmdef ' s
* state to FSMDEF_S_RELEASING and
* return the SM_RC_END to waite for release complete .
*
* Otherwise , it cleans up dcb and releases fcb and
* return SM_RC_CLEANUP to the caller .
*
* If the SM_RC_CLEANUP is returned , the caller should
* terminate any access or perform any operation
* afterward .
*/
sm_rcs_t
fsmdef_release ( fsm_fcb_t * fcb , cc_causes_t cause , boolean send_release )
{
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_state_data_t state_data ;
cc_kfact_t kfactor ;
fsmdef_media_t * media ;
char tmp_str [ STATUS_LINE_MAX_LEN ] ;
if ( ! dcb ) {
/* Already been released */
return SM_RC_CLEANUP ;
}
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " Entered. cause= %s \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , __FUNCTION__ ) , cc_cause_name ( cause ) ) ;
if ( g_dock_undock_event ! = MEDIA_INTERFACE_UPDATE_NOT_REQUIRED ) {
ui_update_media_interface_change ( dcb - > line , dcb - > call_id , MEDIA_INTERFACE_UPDATE_FAIL ) ;
}
memset ( & kfactor , 0 , sizeof ( cc_kfact_t ) ) ;
/* Cancel any existing autoanswer timer */
( void ) cprCancelTimer ( dcb - > autoAnswerTimer ) ;
/*
* Let Dialog Manager know that there is ONHOOK event
*/
fsmdef_notify_hook_event ( fcb , CC_MSG_ONHOOK , NULL , CC_NO_CALL_ID ,
CC_REASON_NONE , CC_MONITOR_NONE , CFWDALL_NONE ) ;
media = gsmsdp_find_audio_media ( dcb ) ;
if ( ( media ) & & ( media - > direction ! = SDP_DIRECTION_INACTIVE ) ) {
fsmdef_get_rtp_stat ( dcb , & kfactor ) ;
}
if ( cause = = CC_SIP_CAUSE_ANSWERED_ELSEWHERE ) {
ui_log_disposition ( dcb - > call_id , CC_CALL_LOG_DISP_IGNORE ) ;
}
if ( cause = = CC_CAUSE_RESP_TIMEOUT ) {
if ( ( platGetPhraseText ( STR_INDEX_RESP_TIMEOUT ,
( char * ) tmp_str ,
STATUS_LINE_MAX_LEN - 1 ) ) = = CPR_SUCCESS ) {
lsm_ui_display_status ( tmp_str , dcb - > line , dcb - > call_id ) ;
}
}
if ( send_release ) {
cc_int_release ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
cause , NULL , & kfactor ) ;
/*
* Wait around for the release_complete .
*/
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_RELEASING ) ;
/*
* Only move the UI if we changed the UI ' s state when the call was
* received .
*/
if ( ( dcb - > line ! = LSM_NO_LINE ) | | ( cause ! = CC_CAUSE_BUSY ) ) {
state_data . onhook . caller_id = dcb - > caller_id ;
state_data . onhook . local = FALSE ;
state_data . onhook . cause = CC_CAUSE_NORMAL ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ONHOOK ,
& state_data ) ;
}
return ( SM_RC_END ) ;
} else {
/*
* Only move the UI if we changed the UI ' s state when the call was
* initiated .
*/
if ( ( dcb - > line ! = LSM_NO_LINE ) | | ( cause ! = CC_CAUSE_BUSY ) ) {
state_data . onhook . caller_id = dcb - > caller_id ;
state_data . onhook . local = FALSE ;
state_data . onhook . cause = CC_CAUSE_NORMAL ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ONHOOK ,
& state_data ) ;
}
/*
* Only send a release complete to the remote end if they are waiting
* for it . This is the case when we have sent a proceeding or we
* have received a release .
*/
if ( FSM_CHK_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_PROCEEDING ) | |
FSM_CHK_FLAGS ( dcb - > msgs_rcvd , FSMDEF_MSG_RELEASE ) ) {
cc_int_release_complete ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , cause , & kfactor ) ;
}
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_IDLE ) ;
fsmdef_free_dcb ( dcb ) ;
fsm_release ( fcb , __LINE__ , cause ) ;
/*
* fsmdef has been released , indiate cleanup FSM chain .
*/
return ( SM_RC_CLEANUP ) ;
}
}
/*
* fsmdef_convert_esc_plus
*
* replaces an escaped " + " ( % 2 B ) with a real " + "
*/
static void
fsmdef_convert_esc_plus ( const char * src_number )
{
int i , len ;
char * number ;
len = strlen ( src_number ) - 2 ;
number = ( char * ) src_number ;
number [ 0 ] = ' + ' ;
for ( i = 1 ; i < len ; i + + ) {
number [ i ] = number [ i + 2 ] ;
}
number [ i ] = ' \0 ' ;
}
static boolean
fsmdef_compare_caller_id_string ( string_t dest , string_t src )
{
if ( ( dest = = NULL ) & & ( src = = NULL ) ) {
/*
* Strings are same .
*/
return ( FALSE ) ;
}
if ( ( dest = = NULL ) | | ( src = = NULL ) ) {
/*
* Strings differ .
*/
return ( TRUE ) ;
}
if ( strncmp ( dest , src , FSMDEF_MAX_CALLER_ID_LEN ) ! = 0 ) {
/*
* Strings differ .
*/
return ( TRUE ) ;
}
/*
* Strings are same .
*/
return ( FALSE ) ;
}
static boolean
fsmdef_compare_caller_id ( cc_caller_id_t * dest_caller_id ,
cc_caller_id_t * src_caller_id )
{
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > calling_name ,
src_caller_id - > calling_name ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > calling_number ,
src_caller_id - > calling_number ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > called_name ,
src_caller_id - > called_name ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > called_number ,
src_caller_id - > called_number ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > orig_called_name ,
src_caller_id - > orig_called_name ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > orig_called_number ,
src_caller_id - > orig_called_number ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > last_redirect_name ,
src_caller_id - > last_redirect_name ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > last_redirect_number ,
src_caller_id - > last_redirect_number ) ) {
return ( TRUE ) ;
}
if ( fsmdef_compare_caller_id_string ( dest_caller_id - > orig_rpid_number ,
src_caller_id - > orig_rpid_number ) ) {
return ( TRUE ) ;
}
if ( dest_caller_id - > display_calling_number ! = src_caller_id - > display_calling_number | |
dest_caller_id - > display_called_number ! = src_caller_id - > display_called_number | |
dest_caller_id - > call_type ! = src_caller_id - > call_type | |
dest_caller_id - > call_instance_id ! = src_caller_id - > call_instance_id ) {
return ( TRUE ) ;
}
return ( FALSE ) ;
}
static void
fsmdef_mv_caller_id ( fsmdef_dcb_t * dcb , cc_caller_id_t * caller_id )
{
/*
* Move the caller ID from the source to the storage in dcb if there
* is a change in what is already stored in the dcb .
*/
if ( fsmdef_compare_caller_id ( & dcb - > caller_id , caller_id ) ) {
cc_mv_caller_id ( & dcb - > caller_id , caller_id ) ;
dcb - > ui_update_required = TRUE ;
}
}
static void
fsmdef_update_callinfo ( fsm_fcb_t * fcb , cc_feature_t * msg )
{
static const char fname [ ] = " fsmdef_update_callinfo " ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_data_t * feat_data = & ( msg - > data ) ;
cc_action_data_t action_data ;
cc_caller_id_t * caller_id ;
if ( msg - > data_valid = = FALSE ) {
/* No data to use for update. Just ignore the event. */
return ;
}
if ( ( feat_data - > call_info . feature_flag & CC_UI_STATE ) & &
( feat_data - > call_info . ui_state = = CC_UI_STATE_RINGOUT ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , fname ,
" setting spoof_ringout_requested " ) ;
dcb - > spoof_ringout_requested = TRUE ;
} else {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_RQSTD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_requested = FALSE ;
}
caller_id = & feat_data - > call_info . caller_id ;
if ( feat_data - > call_info . feature_flag & CC_CALLER_ID ) {
fsmdef_mv_caller_id ( dcb , caller_id ) ;
}
/*
* If CCM provides a call instance id and it does not match
* the current call instance id , free the current call instance
* id and set the call instance id to the newly provided value .
*/
if ( feat_data - > call_info . feature_flag & CC_CALL_INSTANCE & &
feat_data - > call_info . caller_id . call_instance_id ! = dcb - > caller_id . call_instance_id ) {
if ( dcb - > caller_id . call_instance_id ! = 0 ) {
fsmutil_free_ci_id ( dcb - > caller_id . call_instance_id , dcb - > line ) ;
}
dcb - > caller_id . call_instance_id =
feat_data - > call_info . caller_id . call_instance_id ;
fsmutil_set_ci_id ( dcb - > caller_id . call_instance_id , dcb - > line ) ;
dcb - > ui_update_required = TRUE ;
}
/*
* Update security status
*/
fsmdef_update_callinfo_security_status ( dcb , & feat_data - > call_info ) ;
/*
* Update call policy
*/
if ( feat_data - > call_info . feature_flag & CC_POLICY ) {
if ( dcb - > policy ! = feat_data - > call_info . policy ) {
dcb - > policy = feat_data - > call_info . policy ;
dcb - > ui_update_required = TRUE ;
}
}
/*
* Save orientation so that UI call update can be done at
* any time that UI needs to be updated .
*/
if ( feat_data - > call_info . feature_flag & CC_ORIENTATION ) {
if ( dcb - > orientation ! = feat_data - > call_info . orientation ) {
dcb - > orientation = feat_data - > call_info . orientation ;
dcb - > ui_update_required = TRUE ;
}
}
/*
* This call info . event may be as part of media effecting
* signaling event ( such as INVITE , re - INVITE , 180 etc . )
* which will be followed by actual media effected event . It is
* indicated by SIP stack to improve media cutting through as soonest .
* If SIP indicates that UI can be delayed then do not update call
* information now . The UI will be updated as part of media
* manipulation event that will follow .
* ( Note : call info event is sent separately from the SIP signaling
* event currently and it is sent before SIP signaling event ) .
*/
if ( feat_data - > call_info . feature_flag & CC_DELAY_UI_UPDATE ) {
/* Delay UI update */
} else {
/*
* Only perform a UI update if something changed .
*/
if ( dcb - > ui_update_required = = TRUE
| | dcb - > spoof_ringout_requested = = TRUE ) {
action_data . update_ui . action = CC_UPDATE_CALLER_INFO ;
action_data . update_ui . data . caller_info = feat_data - > call_info ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_UPDATE_UI ,
& action_data ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , dcb - > call_id ,
dcb - > line , fname , " UI update " ) ;
} else {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , fname , " No UI update " ) ;
}
}
/* update callref */
if ( dcb - > callref = = 0 ) {
dcb - > callref = feat_data - > call_info . callref ;
ui_update_callref ( dcb - > line , dcb - > call_id , feat_data - > call_info . callref ) ;
}
/* update gcid */
if ( feat_data - > call_info . global_call_id [ 0 ] ! = ' \0 ' ) {
ui_update_gcid ( dcb - > line , dcb - > call_id , feat_data - > call_info . global_call_id ) ;
/*
* store the gcid lcb , this is used to prevent short ringing
* in scenarios where a call is routed to the calling phone .
*/
lsm_update_gcid ( dcb - > call_id , feat_data - > call_info . global_call_id ) ;
}
}
/**
* Function : fsmdef_set_feature_timer
*
* Description : This function is called to set ( start ) timer for a
* given timer . The context of the timer is set so that upon
* expiration the corresponding context ( dcb ) can be obtained .
*
* Parameters :
* dcb - pointer to the fsmdef_dcb_t . The caller must ensure
* dcb is not NULL .
* timer - pointer to cprTimer_t . The caller must ensure that
* timer is not NULL .
* duration - the time duration for the timer to be set .
*
* Returns :
* N / A .
*/
static void
fsmdef_set_feature_timer ( fsmdef_dcb_t * dcb , cprTimer_t * timer ,
uint32_t duration )
{
static const char fname [ ] = " fsmdef_set_feature_timer " ;
if ( cprCancelTimer ( * timer ) ! = CPR_SUCCESS ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CANCEL_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Feature " , cpr_errno ) ;
return ;
}
if ( cprStartTimer ( * timer , duration , ( void * ) ( long ) dcb - > call_id ) = = CPR_FAILURE ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_START_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Feature " , cpr_errno ) ;
}
}
static void
fsmdef_set_req_pending_timer ( fsmdef_dcb_t * dcb )
{
static const char fname [ ] = " fsmdef_set_req_pending_timer " ;
uint32_t msec ;
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_INVALID_DCB ) , fname ) ;
return ;
}
if ( ! dcb - > req_pending_tmr ) {
dcb - > req_pending_tmr = cprCreateTimer ( " Request Pending " ,
GSM_REQ_PENDING_TIMER ,
TIMER_EXPIRATION ,
gsm_msg_queue ) ;
if ( dcb - > req_pending_tmr = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CREATE_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Request Pending " ) ;
return ;
}
}
if ( dcb - > inbound ) {
// We did not initiate this call, so set timer between 0 and 2000ms
msec = abs ( cpr_rand ( ) ) % 2000 ;
} else {
// We initiated this call, so set the timer between 2100 and 4000ms
msec = abs ( cpr_rand ( ) ) % 1900 + 2100 ;
}
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " Starting req pending timer for %d ms. \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) , msec ) ;
fsmdef_set_feature_timer ( dcb , & dcb - > req_pending_tmr , msec ) ;
}
static void
fsmdef_set_ringback_delay_timer ( fsmdef_dcb_t * dcb )
{
static const char fname [ ] = " fsmdef_set_ringback_delay_timer " ;
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_INVALID_DCB ) , fname ) ;
return ;
}
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " Starting Ringback Delay timer "
" for %d ms. \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) , RINGBACK_DELAY ) ;
fsmdef_set_feature_timer ( dcb , & dcb - > ringback_delay_tmr , RINGBACK_DELAY ) ;
}
/*******************************************************************
* event functions
*/
static sm_rcs_t
fsmdef_ev_default ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SM_DEFAULT_EVENT ) ) ;
if ( fcb - > dcb ) {
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
}
return ( SM_RC_END ) ;
}
/*
* Default event handler for feature_ack event
*/
static sm_rcs_t
fsmdef_ev_default_feature_ack ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_default_feature_ack " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_ack_t * msg = ( cc_feature_ack_t * ) event - > msg ;
cc_features_t ftr_id = msg - > feature_id ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , " fsmdef_ev_default_feature_ack " ) ) ;
if ( ftr_id = = CC_FEATURE_SELECT ) {
/* Reeceived the response for select, so turn the flag off */
dcb - > select_pending = FALSE ;
if ( dcb - > selected ) {
dcb - > selected = FALSE ;
g_numofselected_calls - - ;
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " call is unselected and number of selected \
calls on the phone is % d \ n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , msg - > call_id , fname ) ,
g_numofselected_calls ) ;
} else {
dcb - > selected = TRUE ;
if ( ( g_b2bjoin_pending = = FALSE ) & &
( dcb - > active_feature = = CC_FEATURE_B2B_JOIN ) ) {
g_b2bjoin_pending = TRUE ;
g_b2bjoin_callid = dcb - > call_id ;
}
g_numofselected_calls + + ;
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " call is selected and number of selected \
calls on the phone is % d \ n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) ,
g_numofselected_calls ) ;
}
ui_call_selected ( dcb - > line , lsm_get_ui_id ( dcb - > call_id ) , ( dcb - > selected ) ? CC_DIALOG_LOCKED : CC_DIALOG_UNLOCKED ) ;
} else if ( dcb - > active_feature ! = ftr_id ) {
// check if we are getting feature_ack for the active feature
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " feature_ack rcvd for %s but %s is active \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) ,
cc_feature_name ( ftr_id ) , cc_feature_name ( dcb - > active_feature ) ) ;
}
// reset active feature
dcb - > active_feature = CC_FEATURE_NONE ;
return ( SM_RC_END ) ;
}
static void
fsmdef_sm_ignore_ftr ( fsm_fcb_t * fcb , int fname , cc_features_t ftr_id )
{
fsm_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
if ( fcb - > dcb ) {
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
}
}
static void
fsmdef_sm_ignore_src ( fsm_fcb_t * fcb , int fname , cc_srcs_t src_id )
{
fsm_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
if ( fcb - > dcb ) {
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
}
}
/*
* fsmdef_error_onhook_timeout
*
* Timer is started immediately after the call error . This function is called
* when there is a timeout event generated by the timer .
*
* @ param [ in ] data The gsm ID ( callid_t ) of the call onhook timeout
* has occured .
*
* @ return N / A
*/
void
fsmdef_error_onhook_timeout ( void * data )
{
static const char fname [ ] = " fsmdef_error_onhook_timeout " ;
fsmdef_dcb_t * dcb ;
callid_t call_id ;
call_id = ( callid_t ) ( long ) data ;
if ( call_id = = CC_NO_CALL_ID ) {
/* Invalid call id */
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG1 ) , 0 , 0 , fname , " invalid data " ) ;
return ;
}
/* Retrieve dcb from call id */
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG_INVALID_DCB ) , fname ) ;
return ;
}
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , fname , " timeout " ) ;
cc_int_onhook ( CC_SRC_GSM , CC_SRC_GSM , CC_NO_CALL_ID , CC_REASON_NONE ,
dcb - > call_id , dcb - > line , FALSE , FALSE ) ;
}
/**
* Function : fsmdef_feature_timer_timeout
*
* Description : This function is called when receives time out
* notification . The function then converts the timer event
* into the CCAPI event suitable for GSM ' s call state machine .
*
* Parameters :
* feature_id - corresponding feature ID of the timer event .
* data - the opaque data for the caller which is actually
* is the GSM ' s call id .
*
* Returns :
* NULL or
* pointer to the cc_feature_t .
*/
void *
fsmdef_feature_timer_timeout ( cc_features_t feature_id , void * data )
{
static const char fname [ ] = " fsmdef_feature_timer_timeout " ;
cc_feature_t * pmsg ;
callid_t call_id ;
fsmdef_dcb_t * dcb ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , 0 , 0 , fname , " timeout " ) ;
call_id = ( callid_t ) ( long ) data ;
if ( call_id = = CC_NO_CALL_ID ) {
/* Invalid call id */
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG1 ) , 0 , 0 , fname , " invalid data " ) ;
return NULL ;
}
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
/* The corresponding dcb for the call ID is not found */
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_INVALID_DCB ) , fname ) ;
return ( NULL ) ;
}
if ( dcb - > inband_received & & feature_id = = CC_FEATURE_RINGBACK_DELAY_TIMER_EXP ) {
/* Double check if inbound ringback indication is received*/
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , 0 , 0 , fname , " inband received! " ) ;
return ( NULL ) ;
}
pmsg = ( cc_feature_t * ) gsm_get_buffer ( sizeof ( * pmsg ) ) ;
if ( ! pmsg ) {
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG1 ) ,
call_id , dcb - > line , fname ,
" failed to allocate feature timer message " ) ;
return NULL ;
}
memset ( pmsg , 0 , sizeof ( * pmsg ) ) ;
pmsg - > msg_id = CC_MSG_FEATURE ;
pmsg - > src_id = CC_SRC_GSM ;
pmsg - > call_id = call_id ;
pmsg - > line = dcb - > line ;
pmsg - > feature_id = feature_id ;
pmsg - > data_valid = FALSE ;
return ( void * ) pmsg ;
}
/**
*
* Function handles idle setup request received from the network
*
* @ sm_eent_t event
*
* @ return SM_RC_END
*
* @ pre ( called_number and called_number not NULL )
* @ pre ( event - > data not_eq NULL )
* @ pre ( event - > msg not_eq NULL )
*/
static sm_rcs_t
fsmdef_ev_idle_setup ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_idle_setup " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_setup_t * msg = ( cc_setup_t * ) event - > msg ;
callid_t call_id = msg - > call_id ;
int temp ;
string_t called_number = msg - > caller_id . called_number ;
string_t calling_number = msg - > caller_id . calling_number ;
fsmdef_dcb_t * dcb ;
cc_causes_t cause ;
fsmxfr_xcb_t * xcb ;
fsm_fcb_t * other_fcb ;
callid_t other_call_id ;
boolean alerting = TRUE ;
boolean replaces = msg - > replaces ;
int other_active_calls ;
boolean transfer_target = FALSE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Make sure we have a valid called_number .
*/
if ( ( called_number = = NULL ) | | ( called_number [ 0 ] = = ' \0 ' ) ) {
return ( SM_RC_CLEANUP ) ;
}
/*
* Check the called / calling number for the E .164 escaped " + "
* and convert it to a real " + " if present .
*/
if ( cpr_strncasecmp ( called_number , " %2B " , 3 ) = = 0 ) {
fsmdef_convert_esc_plus ( called_number ) ;
}
if ( cpr_strncasecmp ( calling_number , " %2B " , 3 ) = = 0 ) {
fsmdef_convert_esc_plus ( calling_number ) ;
}
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " called_number= %s calling_number= %s \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , msg - > line , msg - > call_id , fname ) ,
msg - > caller_id . called_number , msg - > caller_id . calling_number ) ;
//idle = lsm_is_phone_idle();
xcb = fsmxfr_get_xcb_by_call_id ( call_id ) ;
if ( xcb & & replaces ) {
transfer_target = TRUE ;
}
/*
* Get a new incoming call context .
* if we the target of a transfer , request that the line
* availability be increased by one to account for the third
* instance of a line to become available to allow completion
* of transfer .
*/
cause = fsm_get_new_incoming_call_context ( call_id , fcb , called_number ,
transfer_target ) ;
dcb = fcb - > dcb ;
if ( ( msg - > call_info . type ! = CC_FEAT_MONITOR ) & &
( replaces ! = TRUE ) ) {
if ( lsm_is_line_available ( dcb - > line , TRUE ) = = FALSE ) {
/* increment it to compensate for decrementing while ending the call. */
lsm_increment_call_chn_cnt ( dcb - > line ) ;
fsmdef_end_call ( dcb , CC_CAUSE_BUSY ) ;
return ( SM_RC_END ) ;
}
lsm_increment_call_chn_cnt ( dcb - > line ) ;
}
else {
/*
* join calls ( barged , M & R ) are not counted by CUCM . so we should not count either
*/
dcb - > call_not_counted_in_mnc_bt = TRUE ;
dcb - > join_call_id = msg - > call_info . data . join . join_call_id ;
}
/*
* Set default orientation for the incoming setup as " from " to
* avoid updating UI when call info is received in " ACK " which
* shoule be " from " for typicall incoming call .
*/
dcb - > orientation = CC_ORIENTATION_FROM ;
switch ( cause ) {
case CC_CAUSE_OK :
break ;
case CC_CAUSE_NO_RESOURCE :
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( SM_RC_CLEANUP ) ;
default :
fsmdef_end_call ( dcb , cause ) ;
return ( SM_RC_END ) ;
}
/*
* Check for Anonymous call blocking . If low bit is set ,
* then do not allow call . Note that we must allow both upper and lowercase
* ANON strings , hence the use of strcasestr
*/
config_get_value ( CFGID_ANONYMOUS_CALL_BLOCK , & temp , sizeof ( temp ) ) ;
if ( temp & 1 ) {
/*
* We compare the calling name to the hardcoded Anonymous string we use in
* our SIP headers . This handles the case where calling name was pulled from
* the From header and was set to Anonymous . We also compare the calling name
* to the localized string index for Private which is what the calling name will
* be set to if an RPID header was received .
*/
char tmp_str [ STATUS_LINE_MAX_LEN ] ;
sstrncpy ( tmp_str , platform_get_phrase_index_str ( UI_PRIVATE ) , sizeof ( tmp_str ) ) ;
if ( strcasestr ( msg - > caller_id . calling_name , SIP_HEADER_ANONYMOUS_STR ) | |
strcasestr ( msg - > caller_id . calling_name , tmp_str ) ) {
fsmdef_end_call ( dcb , CC_CAUSE_ANONYMOUS ) ;
return ( SM_RC_END ) ;
}
}
/*
* Check if Call Waiting is disabled .
* If call - waiting is disabled and there is another call active
* then the GSM will return busy .
* unless this is a barge / monitor target call
*
*/
config_get_line_value ( CFGID_LINE_CALL_WAITING , & temp , sizeof ( temp ) ,
dcb - > line ) ;
other_active_calls = fsmdef_get_active_call_cnt ( call_id ) ;
if ( ( msg - > call_info . type ! = CC_FEAT_MONITOR ) ) {
if ( ( ! ( temp & 1 ) ) & & ( other_active_calls > 0 ) & &
( ! ( ( xcb ! = NULL ) & & ( xcb - > mode = = FSMXFR_MODE_TARGET ) ) ) ) {
fsmdef_end_call ( dcb , CC_CAUSE_BUSY ) ;
return ( SM_RC_END ) ;
}
}
/*
* If this is a call to replace another call ,
* check that we have a call to replace
*/
other_call_id = fsmxfr_get_other_call_id ( xcb , call_id ) ;
if ( replaces ) {
if ( ( xcb = = NULL ) | | ( other_call_id = = CC_NO_CALL_ID ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , " " ,
" No call to replace " ) ;
fsmdef_end_call ( dcb , CC_CAUSE_NO_REPLACE_CALL ) ;
return ( SM_RC_END ) ;
}
}
/*
* The called name and number will not be obtained from
* the setup . Remove it before getting from the setup message .
*/
if ( msg - > caller_id . called_name ! = NULL ) {
strlib_free ( msg - > caller_id . called_name ) ;
msg - > caller_id . called_name = NULL ;
}
if ( msg - > caller_id . called_number ! = NULL ) {
strlib_free ( msg - > caller_id . called_number ) ;
msg - > caller_id . called_number = NULL ;
}
/* Get the caller ID from the setup message */
fsmdef_mv_caller_id ( dcb , & msg - > caller_id ) ;
if ( msg - > caller_id . call_type = = CC_CALL_FORWARDED ) {
dcb - > call_type = FSMDEF_CALL_TYPE_FORWARD ;
}
/*
* If a call instance id is provided , use it in the dcb . We will
* check to see that the call instance id provided differs from
* what is currently stored in the dcb before assigning it .
*/
if ( msg - > call_info . type = = CC_FEAT_CALLINFO ) {
cc_feature_data_call_info_t * data ;
data = & msg - > call_info . data . call_info_feat_data ;
if ( data - > feature_flag & CC_CALL_INSTANCE ) {
if ( data - > caller_id . call_instance_id ! = 0 & &
data - > caller_id . call_instance_id ! =
dcb - > caller_id . call_instance_id ) {
if ( dcb - > caller_id . call_instance_id ! = 0 ) {
fsmutil_free_ci_id ( dcb - > caller_id . call_instance_id ,
dcb - > line ) ;
}
dcb - > caller_id . call_instance_id =
data - > caller_id . call_instance_id ;
fsmutil_set_ci_id ( dcb - > caller_id . call_instance_id , dcb - > line ) ;
}
}
if ( data - > feature_flag & CC_SECURITY ) {
FSM_SET_SECURITY_STATUS ( dcb , data - > security ) ;
}
if ( data - > feature_flag & CC_POLICY ) {
FSM_SET_POLICY ( dcb , data - > policy ) ;
}
}
dcb - > alert_info = msg - > alert_info ;
dcb - > alerting_ring = msg - > alerting_ring ;
dcb - > alerting_tone = msg - > alerting_tone ;
/*
* This is an incoming call , so we know we will need to send a
* RELEASE when we clear the call .
*/
dcb - > send_release = TRUE ;
cause = gsmsdp_negotiate_offer_sdp ( fcb , & msg - > msg_body , TRUE ) ;
if ( cause ! = CC_CAUSE_OK ) {
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
if ( transfer_target ) {
/*
* Send a proceeding event to the transfer call .
*
* The proceeding event will end the other call
* and answer the current call .
*
*/
cc_int_proceeding ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , & ( dcb - > caller_id ) ) ;
}
cc_int_setup_ack ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , NULL ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_SETUP_ACK ) ;
cc_int_proceeding ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_PROCEEDING ) ;
alerting = fsmdef_extract_join_target ( event ) ;
/*
* This might be the transfer call from the transferee to the target .
* In such a case we want this new call to match the state of the call
* that it is replacing .
*/
if ( xcb ! = NULL ) {
other_fcb = fsm_get_fcb_by_call_id_and_type ( other_call_id ,
FSM_TYPE_DEF ) ;
if ( other_fcb & & ( other_fcb - > old_state = = FSMDEF_S_CONNECTED | |
other_fcb - > old_state = = FSMDEF_S_CONNECTED_MEDIA_PEND | |
other_fcb - > old_state = = FSMDEF_S_RESUME_PENDING | |
other_fcb - > state = = FSMDEF_S_CONNECTED | |
other_fcb - > state = = FSMDEF_S_CONNECTED_MEDIA_PEND | |
other_fcb - > state = = FSMDEF_S_RESUME_PENDING ) ) {
alerting = FALSE ;
}
}
if ( alerting = = TRUE ) {
/*
* set the call priority in lcb . This is used by ringer logic .
*/
if ( ( msg - > call_info . type = = CC_FEAT_CALLINFO ) & &
( msg - > call_info . data . call_info_feat_data . priority = = CC_CALL_PRIORITY_URGENT ) ) {
lsm_set_lcb_call_priority ( call_id ) ;
}
if ( ( msg - > call_info . type = = CC_FEAT_CALLINFO ) & &
( msg - > call_info . data . call_info_feat_data . dusting = = TRUE ) ) {
lsm_set_lcb_dusting_call ( call_id ) ;
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ALERTING ,
FSMDEF_CC_CALLER_ID ) ;
/*
* Currently we do not send SDP in the 180 response .
*/
cc_int_alerting ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , NULL , FALSE ) ;
/* update callref */
if ( dcb - > callref = = 0 ) {
dcb - > callref = msg - > call_info . data . call_info_feat_data . callref ;
ui_update_callref ( dcb - > line , dcb - > call_id , msg - > call_info . data . call_info_feat_data . callref ) ;
}
/* update gcid */
ui_update_gcid ( dcb - > line , dcb - > call_id , msg - > call_info . data . call_info_feat_data . global_call_id ) ;
/*
* store the gcid lcb , this is used to prevent short ringing
* in scenarios where a call is routed to the calling phone .
*/
lsm_update_gcid ( dcb - > call_id , msg - > call_info . data . call_info_feat_data . global_call_id ) ;
}
ui_cc_capability ( dcb - > line , lsm_get_ui_id ( dcb - > call_id ) , msg - > recv_info_list ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_ALERTING ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_INCOMING_ALERTING ) ;
return ( SM_RC_END ) ;
}
sm_rcs_t
fsmdef_dialstring ( fsm_fcb_t * fcb , const char * dialstring ,
cc_redirect_t * redirect , boolean replace ,
cc_call_info_t * call_info )
{
static const char fname [ ] = " fsmdef_dialstring " ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_causes_t cause ;
cc_msgbody_info_t msg_body ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( dialstring ) {
if ( strlen ( dialstring ) > MAX_SIP_URL_LENGTH ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " Dial string too long \n " , DEB_F_PREFIX_ARGS ( FSM , fname ) ) ;
/* Force clean up call without sending release */
return ( fsmdef_release ( fcb , CC_CAUSE_INVALID_NUMBER , FALSE ) ) ;
}
}
/*
* If there is active feature which is waiting for digit collection
* then use service URI preceded with dialed number .
*/
switch ( dcb - > active_feature ) {
case CC_FEATURE_CFWD_ALL :
fsmdef_append_dialstring_to_feature_uri ( dcb , dialstring ) ;
break ;
default :
if ( dialstring ) {
dcb - > caller_id . called_number =
strlib_update ( dcb - > caller_id . called_number , dialstring ) ;
}
break ;
}
cause = gsmsdp_create_local_sdp ( dcb , FALSE , TRUE , TRUE , TRUE , TRUE ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
/* Force clean up call without sending release */
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
/* Build SDP for sending out */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
/* Force clean up call without sending release */
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
/*
* Since we are sending setup to UI we will also have to send
* release to it to for sip stack to clean up the call
*/
dcb - > send_release = TRUE ;
/*
* lsm_parse_displaystr will free present called number and return
* pointer to parsed called number
*/
dcb - > caller_id . called_number =
lsm_parse_displaystr ( dcb - > caller_id . called_number ) ;
/* set default orientation for outgoing call */
dcb - > orientation = CC_ORIENTATION_TO ;
dcb - > inbound = FALSE ;
/*
* Invoke cc_call_state with modified caller_id for features such as
* pickups
*/
fsmdef_set_call_info_cc_call_state ( dcb , CC_STATE_DIALING_COMPLETED , CC_CAUSE_MIN ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_SETUP ) ;
fsmdef_set_call_info_cc_call_state ( dcb , CC_STATE_CALL_SENT , CC_CAUSE_MIN ) ;
/*
* Send setup or INVITE out after finishing all UI activities and media
* preparation . This is done as the final step in order to minimize
* UI activities / media activities to run concurrently while processing
* the response from the network . On the platform that uses Java VM to
* support UI and media , the time to process the UI and media activities
* may take longer than the network response time to the INVITE ( such as
* voice mail case ) and JNI calls may be blocked while invoking the
* UI or media calls in the LSM .
*/
cc_int_setup ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , dcb - > alert_info , VCM_INSIDE_RING ,
VCM_INSIDE_DIAL_TONE , redirect , call_info , replace , NULL , & msg_body ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CALL_SENT ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_dialstring ( sm_event_t * event )
{
sm_rcs_t sm_rc ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
// handle dialstring event if from callfwdall
if ( fsmdef_process_dialstring_for_callfwd ( event ) = = SM_RC_END ) {
// release the call started to collect callfwd info
dcb - > send_release = FALSE ;
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ) ;
}
sm_rc = fsmdef_dialstring ( fcb , ( ( cc_dialstring_t * ) event - > msg ) - > dialstring ,
NULL , FALSE , NULL ) ;
return ( sm_rc ) ;
}
/**
* fsmdef_ev_createoffer
*
* Generates Offer SDP
*
*/
static sm_rcs_t
fsmdef_ev_createoffer ( sm_event_t * event ) {
2012-12-18 11:01:51 -05:00
// sm_rcs_t sm_rc;
2012-12-17 20:14:30 -05:00
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_causes_t cause = CC_CAUSE_NORMAL ;
cc_msgbody_info_t msg_body ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
line_t line = msg - > line ;
callid_t call_id = msg - > call_id ;
2012-12-18 11:01:51 -05:00
// cc_causes_t lsm_rc;
2012-12-17 20:14:30 -05:00
int sdpmode = 0 ;
char * ufrag = NULL ;
char * ice_pwd = NULL ;
short vcm_res ;
session_data_t * sess_data_p = NULL ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
/* Force clean up call without sending release */
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
if ( msg - > data . session . has_constraints ) {
sess_data_p = ( session_data_t * ) findhash ( msg - > data . session . sessionid ) ;
if ( sess_data_p ) {
gsmsdp_process_cap_constraints ( dcb , sess_data_p - > cc_constraints ) ;
if ( 0 > delhash ( msg - > data . session . sessionid ) ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " failed to delete hash sessid=0x%08x \n " ,
DEB_F_PREFIX_ARGS ( SIP_CC_PROV , __FUNCTION__ ) , msg - > data . session . sessionid ) ;
}
cpr_free ( sess_data_p ) ;
}
}
vcmGetIceParams ( dcb - > peerconnection , & ufrag , & ice_pwd ) ;
if ( ! ufrag | | ! ice_pwd ) {
ui_create_offer ( evCreateOfferError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
dcb - > ice_ufrag = ( char * ) cpr_malloc ( strlen ( ufrag ) + 1 ) ;
if ( ! dcb - > ice_ufrag )
return SM_RC_END ;
sstrncpy ( dcb - > ice_ufrag , ufrag , strlen ( ufrag ) + 1 ) ;
free ( ufrag ) ;
dcb - > ice_pwd = ( char * ) cpr_malloc ( strlen ( ice_pwd ) + 1 ) ;
if ( ! dcb - > ice_pwd )
return SM_RC_END ;
sstrncpy ( dcb - > ice_pwd , ice_pwd , strlen ( ice_pwd ) + 1 ) ;
free ( ice_pwd ) ;
vcm_res = vcmGetDtlsIdentity ( dcb - > peerconnection ,
dcb - > digest_alg , FSMDEF_MAX_DIGEST_ALG_LEN ,
dcb - > digest , FSMDEF_MAX_DIGEST_LEN ) ;
if ( vcm_res ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " vcmGetDtlsIdentity returned an error \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_END ;
}
cause = gsmsdp_create_local_sdp ( dcb , FALSE , TRUE , TRUE , TRUE , TRUE ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_create_offer ( evCreateOfferError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_create_offer ( evCreateOfferError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
/* Pass offer SDP back to UI */
ui_create_offer ( evCreateOffer , line , call_id , dcb - > caller_id . call_instance_id , msg_body . parts [ 0 ] . body ) ;
return ( SM_RC_END ) ;
}
/**
* fsmdef_ev_createanswer
*
* Generates Answer SDP
*
*/
static sm_rcs_t
fsmdef_ev_createanswer ( sm_event_t * event ) {
2012-12-18 11:01:51 -05:00
// sm_rcs_t sm_rc;
2012-12-17 20:14:30 -05:00
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_causes_t cause = CC_CAUSE_NORMAL ;
cc_msgbody_info_t msg_body ;
line_t line = msg - > line ;
callid_t call_id = msg - > call_id ;
2012-12-18 11:01:51 -05:00
// line_t free_line;
2012-12-17 20:14:30 -05:00
int sdpmode = 0 ;
2012-12-18 11:01:51 -05:00
// const char *called_number = "1234";
// cc_causes_t lsm_rc;
// cc_msgbody_t *part;
// uint32_t body_length;
2012-12-17 20:14:30 -05:00
char * ufrag = NULL ;
char * ice_pwd = NULL ;
short vcm_res ;
session_data_t * sess_data_p ;
boolean has_audio ;
boolean has_video ;
boolean has_data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
if ( msg - > data . session . has_constraints ) {
sess_data_p = ( session_data_t * ) findhash ( msg - > data . session . sessionid ) ;
if ( sess_data_p ) {
gsmsdp_process_cap_constraints ( dcb , sess_data_p - > cc_constraints ) ;
if ( 0 > delhash ( msg - > data . session . sessionid ) ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " failed to delete hash sessid=0x%08x \n " ,
DEB_F_PREFIX_ARGS ( SIP_CC_PROV , __FUNCTION__ ) , msg - > data . session . sessionid ) ;
}
cpr_free ( sess_data_p ) ;
}
}
vcmGetIceParams ( dcb - > peerconnection , & ufrag , & ice_pwd ) ;
if ( ! ufrag | | ! ice_pwd ) {
ui_create_offer ( evCreateAnswerError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
dcb - > ice_ufrag = ( char * ) cpr_malloc ( strlen ( ufrag ) + 1 ) ;
if ( ! dcb - > ice_ufrag )
return SM_RC_END ;
sstrncpy ( dcb - > ice_ufrag , ufrag , strlen ( ufrag ) + 1 ) ;
free ( ufrag ) ;
dcb - > ice_pwd = ( char * ) cpr_malloc ( strlen ( ice_pwd ) + 1 ) ;
if ( ! dcb - > ice_pwd )
return SM_RC_END ;
sstrncpy ( dcb - > ice_pwd , ice_pwd , strlen ( ice_pwd ) + 1 ) ;
free ( ice_pwd ) ;
vcm_res = vcmGetDtlsIdentity ( dcb - > peerconnection ,
dcb - > digest_alg , FSMDEF_MAX_DIGEST_ALG_LEN ,
dcb - > digest , FSMDEF_MAX_DIGEST_LEN ) ;
if ( vcm_res ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " vcmGetDtlsIdentity returned an error \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_END ;
}
/*
* Determine what media types are offered , used to create matching local SDP
* for negotiation .
*/
gsmsdp_get_offered_media_types ( fcb , dcb - > sdp , & has_audio , & has_video , & has_data ) ;
/*
* The sdp member of the dcb has local and remote sdp
* this next function fills in the local part
*/
cause = gsmsdp_create_local_sdp ( dcb , FALSE , has_audio , has_video , has_data , FALSE ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_create_answer ( evCreateAnswerError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
// Force clean up call without sending release
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
/* TODO(ekr@rtfm.com): The second true is because we are acting as if we are
processing an offer . The first , however , is for an initial offer and we may
want to set that conditionally . */
cause = gsmsdp_negotiate_media_lines ( fcb , dcb - > sdp , TRUE , TRUE , FALSE , TRUE ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_create_answer ( evCreateAnswerError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_create_answer ( evCreateAnswerError , line , call_id , dcb - > caller_id . call_instance_id , NULL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
/* Pass SDP back to UI */
ui_create_answer ( evCreateAnswer , line , call_id , dcb - > caller_id . call_instance_id , msg_body . parts [ 0 ] . body ) ;
return ( SM_RC_END ) ;
}
/**
* SetLocalDescription
*
*/
static sm_rcs_t
fsmdef_ev_setlocaldesc ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_causes_t cause = CC_CAUSE_NORMAL ;
cc_msgbody_info_t msg_body ;
int action = msg - > action ;
2012-12-18 11:01:51 -05:00
// string_t sdp = msg->sdp;
2012-12-17 20:14:30 -05:00
int sdpmode = 0 ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
2012-12-18 11:01:51 -05:00
// cc_causes_t lsm_rc;
2012-12-17 20:14:30 -05:00
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
ui_set_local_description ( evSetLocalDescError , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_SETLOCALDESCERROR ) ;
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
if ( JSEP_OFFER = = action ) {
cause = gsmsdp_encode_sdp ( dcb - > sdp , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
ui_set_local_description ( evSetLocalDescError , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_SETLOCALDESCERROR ) ;
return ( SM_RC_END ) ;
}
/* compare and fail if different:
* anant : Why ? The JS should be able to modify the SDP . Commenting out for now ( same for answer )
2012-12-18 11:01:51 -05:00
if ( strcmp ( msg_body . parts [ 0 ] . body , msg - > sdp ) ! = 0 ) {
2012-12-17 20:14:30 -05:00
ui_set_local_description ( evSetLocalDescError , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_SDPCHANGED ) ;
return ( SM_RC_END ) ;
}
*/
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CALL_SENT ) ;
} else if ( JSEP_ANSWER = = action ) {
/* compare SDP generated from CreateAnswer */
cause = gsmsdp_encode_sdp ( dcb - > sdp , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
ui_set_local_description ( evSetLocalDescError , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_SETLOCALDESCERROR ) ;
return ( SM_RC_END ) ;
}
/* compare and fail if different
2012-12-18 11:01:51 -05:00
if ( strcmp ( msg_body . parts [ 0 ] . body , msg - > sdp ) ! = 0 ) {
2012-12-17 20:14:30 -05:00
ui_set_local_description ( evSetLocalDescError , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_SDPCHANGED ) ;
return ( SM_RC_END ) ;
} */
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_CONNECTED ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ANSWERED ,
FSMDEF_CC_CALLER_ID ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTING ) ;
/*
* Now that we have negotiated the media , time to set up ICE .
* There also needs to be an ICE check in negotiate_media_lines .
*/
cause = gsmsdp_install_peer_ice_attributes ( fcb ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_set_local_description ( evSetLocalDescError , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_SDPCHANGED ) ;
return ( SM_RC_END ) ;
}
/* taken from fsmdef_ev_connected_ack start rx and tx */
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
/*
* If DSP is not able to start rx / tx channels , release the call
*/
if ( dcb - > dsp_out_of_resources = = TRUE ) {
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN , NULL ) ;
return ( SM_RC_END ) ;
}
/* we may want to use the functionality in the following method
* to handle media capability changes , needs discussion
* fsmdef_transition_to_connected ( fcb ) ;
*/
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTED ) ;
}
ui_set_local_description ( evSetLocalDesc , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_OK ) ;
return ( SM_RC_END ) ;
}
/**
* SetRemoteDescription
*
*/
static sm_rcs_t
fsmdef_ev_setremotedesc ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_causes_t cause = CC_CAUSE_NORMAL ;
int action = msg - > action ;
int sdpmode = 0 ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
2012-12-18 11:01:51 -05:00
// cc_causes_t lsm_rc;
2012-12-17 20:14:30 -05:00
cc_msgbody_t * part ;
uint32_t body_length ;
cc_msgbody_info_t msg_body ;
boolean has_audio ;
boolean has_video ;
boolean has_data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
ui_set_remote_description ( evSetRemoteDescError , line , call_id ,
dcb - > caller_id . call_instance_id , NULL , PC_SETREMOTEDESCERROR ) ;
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
cc_initialize_msg_body_parts_info ( & msg_body ) ;
msg_body . num_parts = 1 ;
msg_body . content_type = cc_content_type_SDP ;
part = & msg_body . parts [ 0 ] ;
body_length = strlen ( msg - > sdp ) ;
part - > body = msg - > sdp ;
part - > body_length = body_length ;
part - > content_type = cc_content_type_SDP ;
part - > content_disposition . required_handling = FALSE ;
part - > content_disposition . disposition = cc_disposition_session ;
part - > content_id = NULL ;
if ( JSEP_OFFER = = action ) {
cause = gsmsdp_process_offer_sdp ( fcb , & msg_body , TRUE ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_set_remote_description ( evSetRemoteDescError , line , call_id ,
dcb - > caller_id . call_instance_id , NULL , PC_SETREMOTEDESCERROR ) ;
return ( SM_RC_END ) ;
}
/*
* Determine what media types are offered , used to create matching local SDP
* for negotiation .
*/
gsmsdp_get_offered_media_types ( fcb , dcb - > sdp , & has_audio , & has_video , & has_data ) ;
/*
* The sdp member of the dcb has local and remote sdp
* this next function fills in the local part
*/
cause = gsmsdp_create_local_sdp ( dcb , TRUE , has_audio , has_video , has_data , FALSE ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_set_remote_description ( evSetRemoteDescError , line , call_id , dcb - > caller_id . call_instance_id ,
NULL , PC_SETREMOTEDESCERROR ) ;
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
// Force clean up call without sending release
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
cause = gsmsdp_negotiate_media_lines ( fcb , dcb - > sdp , TRUE , TRUE , TRUE , FALSE ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_set_remote_description ( evSetRemoteDescError , line , call_id , dcb - > caller_id . call_instance_id ,
NULL , PC_SETREMOTEDESCERROR ) ;
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
gsmsdp_clean_media_list ( dcb ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_INCOMING_ALERTING ) ;
} else if ( JSEP_ANSWER = = action ) {
cause = gsmsdp_negotiate_answer_sdp ( fcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_set_remote_description ( evSetRemoteDescError , line , call_id , dcb - > caller_id . call_instance_id ,
NULL , PC_SETREMOTEDESCERROR ) ;
return ( SM_RC_END ) ;
}
/*
* Now that we have negotiated the media , time to set up ICE .
* There also needs to be an ICE check in negotiate_media_lines .
*/
cause = gsmsdp_install_peer_ice_attributes ( fcb ) ;
if ( cause ! = CC_CAUSE_OK ) {
ui_set_remote_description ( evSetRemoteDescError , line , call_id , dcb - > caller_id . call_instance_id ,
NULL , PC_SETREMOTEDESCERROR ) ;
return ( SM_RC_END ) ;
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED , FSMDEF_CC_CALLER_ID ) ;
/* we may want to use the functionality in the following method
* to handle media capability changes , needs discussion
* fsmdef_transition_to_connected ( fcb ) ;
* fsmdef_transition_to_connected ( fcb ) ;
*/
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTED ) ;
}
ui_set_remote_description ( evSetRemoteDesc , line , call_id , dcb - > caller_id . call_instance_id , NULL , PC_OK ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_localdesc ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
2012-12-18 11:01:51 -05:00
// cc_causes_t cause = CC_CAUSE_NORMAL;
2012-12-17 20:14:30 -05:00
int sdpmode = 0 ;
2012-12-18 11:01:51 -05:00
// cc_causes_t lsm_rc;
// cc_msgbody_t *part;
// uint32_t body_length;
// cc_msgbody_info_t msg_body;
2012-12-17 20:14:30 -05:00
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_remotedesc ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
2012-12-18 11:01:51 -05:00
// cc_causes_t cause = CC_CAUSE_NORMAL;
2012-12-17 20:14:30 -05:00
int sdpmode = 0 ;
2012-12-18 11:01:51 -05:00
// cc_causes_t lsm_rc;
// cc_msgbody_t *part;
// uint32_t body_length;
// cc_msgbody_info_t msg_body;
2012-12-17 20:14:30 -05:00
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_setpeerconnection ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
2012-12-18 11:01:51 -05:00
// cc_causes_t cause = CC_CAUSE_NORMAL;
2012-12-17 20:14:30 -05:00
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
callid_t call_id = msg - > call_id ;
int sdpmode = 0 ;
line_t line = msg - > line ;
cc_causes_t lsm_rc ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( ! sdpmode ) {
return ( SM_RC_END ) ;
}
if ( ! msg )
return SM_RC_END ;
if ( ! msg - > data_valid )
return SM_RC_END ;
if ( dcb = = NULL ) {
dcb = fsmdef_get_new_dcb ( call_id ) ;
if ( dcb = = NULL ) {
return SM_RC_ERROR ;
}
lsm_rc = lsm_get_facility_by_line ( call_id , line , FALSE , dcb ) ;
if ( lsm_rc ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " lsm_get_facility_by_line failed. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_END ;
}
fsmdef_init_dcb ( dcb , call_id , FSMDEF_CALL_TYPE_NONE , NULL , line , fcb ) ;
fsm_set_fcb_dcbs ( dcb ) ;
}
PR_ASSERT ( strlen ( msg - > data . pc . pc_handle ) < PC_HANDLE_SIZE ) ;
sstrncpy ( dcb - > peerconnection , msg - > data . pc . pc_handle , sizeof ( dcb - > peerconnection ) ) ;
dcb - > peerconnection_set = TRUE ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_addstream ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
2012-12-18 11:01:51 -05:00
// cc_causes_t cause = CC_CAUSE_NORMAL;
2012-12-17 20:14:30 -05:00
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
2012-12-18 11:01:51 -05:00
int sdpmode = 0 ;
// cc_causes_t lsm_rc;
// cc_msgbody_t *part;
// uint32_t body_length;
// cc_msgbody_info_t msg_body;
2012-12-17 20:14:30 -05:00
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( sdpmode = = FALSE ) {
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
/*
* This is temporary code to allow configuration of the two
* default streams . When multiple streams > 2 are supported this
* will be re - implemented .
*/
if ( msg - > data . track . media_type = = VIDEO ) {
dcb - > media_cap_tbl - > cap [ CC_VIDEO_1 ] . enabled = TRUE ;
dcb - > media_cap_tbl - > cap [ CC_VIDEO_1 ] . support_direction = SDP_DIRECTION_SENDRECV ;
dcb - > media_cap_tbl - > cap [ CC_VIDEO_1 ] . pc_stream = msg - > data . track . stream_id ;
dcb - > media_cap_tbl - > cap [ CC_VIDEO_1 ] . pc_track = msg - > data . track . track_id ;
} else if ( msg - > data . track . media_type = = AUDIO ) {
dcb - > media_cap_tbl - > cap [ CC_AUDIO_1 ] . enabled = TRUE ;
dcb - > media_cap_tbl - > cap [ CC_AUDIO_1 ] . support_direction = SDP_DIRECTION_SENDRECV ;
dcb - > media_cap_tbl - > cap [ CC_AUDIO_1 ] . pc_stream = msg - > data . track . stream_id ;
dcb - > media_cap_tbl - > cap [ CC_AUDIO_1 ] . pc_track = msg - > data . track . track_id ;
} else {
return ( SM_RC_END ) ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_removestream ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
2012-12-18 11:01:51 -05:00
// cc_causes_t cause = CC_CAUSE_NORMAL;
2012-12-17 20:14:30 -05:00
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
int sdpmode = 0 ;
2012-12-18 11:01:51 -05:00
// cc_causes_t lsm_rc;
// cc_msgbody_t *part;
// uint32_t body_length;
// cc_msgbody_info_t msg_body;
2012-12-17 20:14:30 -05:00
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( sdpmode = = FALSE ) {
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
/*
* This is temporary code to allow configuration of the two
* default streams . When multiple streams > 2 are supported this
* will be re - implemented .
*/
if ( msg - > data . track . media_type = = AUDIO ) {
dcb - > media_cap_tbl - > cap [ CC_AUDIO_1 ] . enabled = TRUE ;
dcb - > media_cap_tbl - > cap [ CC_AUDIO_1 ] . support_direction = SDP_DIRECTION_RECVONLY ;
dcb - > video_pref = SDP_DIRECTION_SENDRECV ;
} else if ( msg - > data . track . media_type = = VIDEO ) {
dcb - > media_cap_tbl - > cap [ CC_VIDEO_1 ] . enabled = TRUE ;
dcb - > media_cap_tbl - > cap [ CC_VIDEO_1 ] . support_direction = SDP_DIRECTION_RECVONLY ;
} else {
return ( SM_RC_END ) ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_addcandidate ( sm_event_t * event ) {
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
2012-12-18 11:01:51 -05:00
// cc_causes_t cause = CC_CAUSE_NORMAL;
2012-12-17 20:14:30 -05:00
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
int sdpmode = 0 ;
short vcm_res ;
2012-12-18 11:01:51 -05:00
// uint16_t level;
2012-12-17 20:14:30 -05:00
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( sdpmode = = FALSE ) {
return ( SM_RC_END ) ;
}
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " dcb is NULL. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
return SM_RC_CLEANUP ;
}
/* Perform level lookup based on mid value */
/* comment until mid is properly updated
cause = gsmsdp_find_level_from_mid ( dcb , ( const char * ) msg - > data . candidate . mid , & level ) ;
*/
vcm_res = vcmSetIceCandidate ( dcb - > peerconnection , ( char * ) msg - > data . candidate . candidate , msg - > data . candidate . level ) ;
if ( vcm_res ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " failure setting ice candidate. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
}
return ( SM_RC_END ) ;
}
static void
fsmdef_check_active_feature ( fsmdef_dcb_t * dcb , cc_features_t ftr_id )
{
if ( ( dcb ) & & ( dcb - > active_feature ! = ftr_id ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_FTR_REQ_ACT ) ,
dcb - > call_id , dcb - > line ,
cc_feature_name ( ftr_id ) ,
cc_feature_name ( dcb - > active_feature ) ) ;
lsm_ui_display_notify ( INDEX_STR_KEY_NOT_ACTIVE , NO_FREE_LINES_TIMEOUT ) ;
}
}
static sm_rcs_t
fsmdef_ev_idle_feature ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_idle_feature " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_feature_data_t * data = & ( msg - > data ) ;
line_t line = msg - > line ;
cc_causes_t cause = CC_CAUSE_NORMAL ;
callid_t call_id = fcb - > call_id ;
boolean expline ;
sm_rcs_t sm_rc = SM_RC_END ;
fsmcnf_ccb_t * ccb ;
fsmxfr_xcb_t * xcb ;
char * global_call_id = NULL ;
fsm_sm_ftr ( ftr_id , src_id ) ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
switch ( src_id ) {
case CC_SRC_UI :
case CC_SRC_GSM :
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
if ( dcb ) {
dcb - > video_pref = data - > caps . support_direction ;
}
break ;
case CC_FEATURE_CFWD_ALL :
if ( fsmdef_is_feature_uri_configured ( ftr_id ) = = FALSE ) {
fsm_display_feature_unavailable ( ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
// handle cfwd event for ccm and non-ccm cases
// process feature event only if no other active feature
if ( ( dcb - > active_feature = = CC_FEATURE_NONE ) & &
( fsmdef_get_connected_call ( ) = = NULL ) ) {
dcb - > active_feature = ftr_id ;
( void ) fsmdef_process_cfwd_softkey_event ( event ) ;
} else {
fsmdef_check_active_feature ( dcb , ftr_id ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
}
break ;
case CC_FEATURE_NEW_CALL :
/* fetch the global_call_id from feature data */
global_call_id = data - > newcall . global_call_id ;
/*
* Set the expanded parameter . This parameter is used when
* requesting a free line . A transfer can request that the line
* availability be increased by one to account for the third
* instance of a line to become available for transfers .
*/
if ( data ! = NULL ) {
ccb = fsmcnf_get_ccb_by_call_id ( call_id ) ;
xcb = fsmxfr_get_xcb_by_call_id ( call_id ) ;
if ( ( ccb ! = NULL ) | | ( xcb ! = NULL ) ) {
expline = TRUE ;
} else {
expline = FALSE ;
}
} else {
expline = FALSE ;
}
/*
* Get a new outgoing call context if we have not already
* grabbed one .
*/
if ( fcb - > dcb = = NULL ) {
cause = fsm_get_new_outgoing_call_context ( call_id , line , fcb ,
expline ) ;
switch ( cause ) {
case CC_CAUSE_OK :
break ;
case CC_CAUSE_NO_RESOURCE :
GSM_ERR_MSG ( " %s No Resource! Return SM_RC_CLEANUP. " , fname ) ;
return ( SM_RC_CLEANUP ) ;
default :
/*
* No free lines .
*/
fsm_display_no_free_lines ( ) ;
/*
* Send an endcall message . This behaviour is different
* than an offhook or line event because the new_call
* feature may have been generated by a transfer ( as the
* consultation call ) and will need this end_call message
* so that it can cleanup the transfer . The offhook can
* only come from the UI so it can just be cleaned up here
* without regard for a transfer .
*/
fsmdef_end_call ( fcb - > dcb , cause ) ;
return ( SM_RC_END ) ;
}
dcb = fcb - > dcb ;
/*
* Let Dialog Manager know that there is OFFHOOK event
*/
fsmdef_notify_hook_event ( fcb , CC_MSG_OFFHOOK , global_call_id ,
data - > newcall . prim_call_id ,
data - > newcall . hold_resume_reason ,
CC_MONITOR_NONE , CFWDALL_NONE ) ;
}
/*
* The user is attempting to start a new call on a specific line :
* 1. need to place the connected call ( if there is one ) on hold ,
* 2. clear any outgoing ringing calls ,
* 3. initiate this call .
*/
if ( fsmdef_wait_to_start_new_call ( TRUE , CC_SRC_GSM , call_id , line ,
ftr_id , data ) ) {
return ( SM_RC_END ) ;
}
//lsm_set_active_call_id(call_id);
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_OFFHOOK ,
FSMDEF_CC_CALLER_ID ) ;
if ( data - > newcall . cause = = CC_CAUSE_CONF | |
data - > newcall . cause = = CC_CAUSE_XFER_LOCAL ) {
/* suppress stutter dial tone for conf and transfer features */
fsmdef_call_cc_state_dialing ( dcb , TRUE ) ;
} else {
fsmdef_call_cc_state_dialing ( dcb , FALSE ) ;
}
switch ( data - > newcall . cause ) {
case CC_CAUSE_XFER_REMOTE :
/*
* This newcall feature is really the consultation part of
* a local transfer that has been transferred by the
* consultation call , so proceed as though this is a
* dialstring call since we already have the called_number .
*/
if ( data - > newcall . redirect . redirects [ 0 ] . number [ 0 ] ! = ' \0 ' ) {
sm_rc = fsmdef_dialstring ( fcb , data - > newcall . dialstring ,
& ( data - > newcall . redirect ) , FALSE ,
NULL ) ;
} else if ( data - > newcall . redirect . redirects [ 0 ] . redirect_reason
= = CC_REDIRECT_REASON_DEFLECTION ) {
/*
* CC_REDIRECT_REASON_DEFLECTION shows that transferee is
* going to initiate a new call for replacing the call leg
* between transferor and target .
*/
memset ( data - > newcall . redirect . redirects [ 0 ] . number , 0 ,
sizeof ( CC_MAX_DIALSTRING_LEN ) ) ;
sm_rc = fsmdef_dialstring ( fcb , data - > newcall . dialstring ,
& ( data - > newcall . redirect ) , FALSE ,
NULL ) ;
} else {
sm_rc =
fsmdef_dialstring ( fcb , data - > newcall . dialstring , NULL ,
FALSE , NULL ) ;
}
return ( sm_rc ) ;
case CC_CAUSE_REDIRECT :
sm_rc = fsmdef_dialstring ( fcb , data - > newcall . dialstring ,
& ( data - > newcall . redirect ) , FALSE ,
NULL ) ;
return ( sm_rc ) ;
case CC_CAUSE_XFER_BY_REMOTE :
/* CC_REDIRECT_REASON_DEFLECTION shows that transferee is
* going to initiate a new call for replacing the call leg
* between transferor and target .
*/
memset ( data - > newcall . redirect . redirects [ 0 ] . number , 0 ,
sizeof ( CC_MAX_DIALSTRING_LEN ) ) ;
sm_rc = fsmdef_dialstring ( fcb , data - > newcall . dialstring ,
& ( data - > newcall . redirect ) , FALSE ,
NULL ) ;
return ( sm_rc ) ;
default :
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_COLLECT_INFO ) ;
return ( SM_RC_END ) ;
}
case CC_FEATURE_END_CALL :
cause = fsmdef_get_cause ( msg - > data_valid , data ) ;
/*
* There has to be a dcb to process this event .
*/
if ( fcb - > dcb = = NULL ) {
// commented out following line due to klocwork error
// call is dereferencing fcb->dcb when it is NULL (sorry, can't do that!)
// cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN, NULL);
return ( SM_RC_CLEANUP ) ;
}
if ( dcb - > call_type = = FSMDEF_CALL_TYPE_INCOMING | |
dcb - > call_type = = FSMDEF_CALL_TYPE_FORWARD ) {
dcb - > send_release = TRUE ;
}
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
} /* switch (src_id) { */
return ( sm_rc ) ;
}
sm_rcs_t
fsmdef_offhook ( fsm_fcb_t * fcb , cc_msgs_t msg_id , callid_t call_id ,
line_t line , const char * dial_string ,
sm_event_t * event , char * global_call_id ,
callid_t prim_call_id , cc_hold_resume_reason_e consult_reason ,
monitor_mode_t monitor_mode )
{
boolean wait = FALSE ;
boolean wait2 = FALSE ;
boolean wait3 = FALSE ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Get a new outgoing call context if we have not already
* grabbed one .
*/
if ( fcb - > dcb = = NULL ) {
cause = fsm_get_new_outgoing_call_context ( call_id , line , fcb , FALSE ) ;
switch ( cause ) {
case CC_CAUSE_OK :
break ;
default :
/*
* No free lines
*/
fsm_display_no_free_lines ( ) ;
if ( fsmdef_get_connected_call ( ) ! = NULL ) {
lsm_speaker_mode ( ON ) ;
} else {
lsm_speaker_mode ( OFF ) ;
}
return ( SM_RC_CLEANUP ) ;
}
/*
* Let Dialog Manager know that there is OFFHOOK event
*/
fsmdef_notify_hook_event ( fcb , CC_MSG_OFFHOOK , global_call_id ,
prim_call_id , consult_reason , monitor_mode , CFWDALL_NONE ) ;
}
/*
* The user is attempting to start a new call on a specific line :
* 1. need to place the connected call ( if there is one ) on hold ,
* 2. clear any outgoing ringing calls , or calls are in reorder / busy state
* 3. initiate this call .
*/
fsmdef_find_and_hold_connected_call ( call_id , & wait , CC_SRC_GSM ) ;
fsmdef_find_and_handle_ring_connecting_releasing_calls ( call_id , & wait2 ) ;
fsmdef_clear_preserved_calls ( & wait3 ) ;
/*
* Requeue the message if we need to wait for the connected line to
* hold
*/
if ( ( wait = = TRUE ) | | ( wait2 = = TRUE ) | | ( wait3 = = TRUE ) ) {
switch ( msg_id ) {
case CC_MSG_OFFHOOK :
cc_int_offhook ( CC_SRC_GSM , CC_SRC_GSM , prim_call_id , consult_reason ,
call_id , line , global_call_id , monitor_mode , CFWDALL_NONE ) ;
break ;
case CC_MSG_LINE :
cc_int_line ( CC_SRC_GSM , CC_SRC_GSM , call_id , line ) ;
break ;
case CC_MSG_DIALSTRING :
cc_int_dialstring ( CC_SRC_GSM , CC_SRC_GSM , call_id , line ,
dial_string , global_call_id , monitor_mode ) ;
break ;
case CC_MSG_FEATURE :
if ( dial_string ! = NULL ) {
cc_int_dialstring ( CC_SRC_GSM , CC_SRC_GSM , call_id , line ,
dial_string , global_call_id , monitor_mode ) ;
break ;
}
/*FALLTHROUGH*/
default :
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( SM_RC_CLEANUP ) ;
}
return ( SM_RC_END ) ;
}
//lsm_set_active_call_id(call_id);
return ( SM_RC_SUCCESS ) ;
}
static sm_rcs_t
fsmdef_ev_idle_offhook ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_offhook_t * msg = ( cc_offhook_t * ) event - > msg ;
fsmdef_dcb_t * dcb ;
sm_rcs_t sm_rc ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
sm_rc = fsmdef_offhook ( fcb , msg - > msg_id , msg - > call_id , msg - > line , NULL ,
event , msg - > global_call_id , msg - > prim_call_id ,
msg - > hold_resume_reason , msg - > monitor_mode ) ;
if ( sm_rc ! = SM_RC_SUCCESS ) {
return ( sm_rc ) ;
}
dcb = fcb - > dcb ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_OFFHOOK ,
FSMDEF_CC_CALLER_ID ) ;
fsmdef_call_cc_state_dialing ( dcb , FALSE ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_COLLECT_INFO ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_idle_dialstring ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_dialstring_t * msg = ( cc_dialstring_t * ) event - > msg ;
fsmdef_dcb_t * dcb ;
cc_action_data_t data ;
sm_rcs_t sm_rc ;
cc_call_info_t call_info ;
cc_call_info_t * call_info_p = NULL ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
sm_rc = fsmdef_offhook ( fcb , msg - > msg_id , msg - > call_id , msg - > line ,
msg - > dialstring , event , msg - > g_call_id ,
CC_NO_CALL_ID , CC_REASON_NONE , msg - > monitor_mode ) ;
if ( sm_rc ! = SM_RC_SUCCESS ) {
return ( sm_rc ) ;
}
dcb = fcb - > dcb ;
if ( msg - > dialstring ) {
lsm_set_lcb_dialed_str_flag ( dcb - > call_id ) ;
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_OFFHOOK ,
FSMDEF_CC_CALLER_ID ) ;
data . tone . tone = VCM_INSIDE_DIAL_TONE ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_STOP_TONE , & data ) ;
dcb - > send_release = TRUE ;
/* Set call_info with global call_id, sent in the Initcallreq,
* If this call is not because Initcallreq , then don ' t set call_info
* Also , if this is a monitor call , add the mode to the call_info
*/
if ( msg - > g_call_id ! = NULL ) {
call_info . type = CC_FEAT_INIT_CALL ;
call_info . data . initcall . monitor_mode = msg - > monitor_mode ;
sstrncpy ( call_info . data . initcall . gcid , msg - > g_call_id , CC_GCID_LEN ) ;
call_info_p = & call_info ;
}
if ( strncmp ( CISCO_BLFPICKUP_STRING , msg - > dialstring , strlen ( CISCO_BLFPICKUP_STRING ) ) = = 0 ) {
dcb - > log_disp = CC_CALL_LOG_DISP_RCVD ;
}
sm_rc = fsmdef_dialstring ( fcb , msg - > dialstring , NULL , FALSE , call_info_p ) ;
return ( sm_rc ) ;
}
static sm_rcs_t
fsmdef_ev_session_audit ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_session_audit " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_audit_sdp_req_t * audit_msg = ( cc_audit_sdp_req_t * ) event - > msg ;
cc_msgbody_info_t msg_body ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ! = CC_CAUSE_OK ) {
/*
* Failed to encode our local sdp . Send ack to SIP stack with
* no message body . SIP stack will include previously send
* SDP in response to session audit request .
*/
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
cc_int_audit_sdp_ack ( CC_SRC_GSM , CC_SRC_SIP , audit_msg - > call_id ,
audit_msg - > line , NULL ) ;
} else {
cc_int_audit_sdp_ack ( CC_SRC_GSM , CC_SRC_SIP , audit_msg - > call_id ,
audit_msg - > line , & msg_body ) ;
}
/*
* If we are currently performing a spoofed ringout and the current session audit
* does not indicate that we should continue to do so , go back to connected state .
* But only change to connected state if not locally held .
*/
if ( dcb - > spoof_ringout_applied & &
! dcb - > spoof_ringout_requested ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
if ( ( fcb - > state ! = FSMDEF_S_HOLDING ) & &
( fcb - > state ! = FSMDEF_S_HOLD_PENDING ) ) {
/*
* If is at least one media entry that is not in loally held
* then go to connected state .
*/
dcb - > spoof_ringout_applied = FALSE ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
}
}
return ( SM_RC_SUCCESS ) ;
}
static sm_rcs_t
fsmdef_ev_collectinginfo_release ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsmdef_set_call_info_cc_call_state ( dcb , CC_STATE_CALL_FAILED , CC_CAUSE_INVALID_NUMBER ) ;
// Start onhook timer
if ( dcb - > err_onhook_tmr ) {
( void ) cprDestroyTimer ( dcb - > err_onhook_tmr ) ;
}
dcb - > err_onhook_tmr = cprCreateTimer ( " Error Onhook " ,
GSM_ERROR_ONHOOK_TIMER ,
TIMER_EXPIRATION ,
gsm_msg_queue ) ;
if ( dcb - > err_onhook_tmr = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CREATE_FAILED ) ,
dcb - > call_id , dcb - > line , " " , " Error Onhook " ) ;
return ( SM_RC_CLEANUP ) ;
}
if ( cprStartTimer ( dcb - > err_onhook_tmr ,
FSMDEF_ERR_ONHOOK_TMR_SECS * 1000 ,
( void * ) ( long ) dcb - > call_id ) = = CPR_FAILURE ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_START_FAILED ) ,
dcb - > call_id , dcb - > line , " " ,
" Error Onhook " , cpr_errno ) ;
return ( SM_RC_CLEANUP ) ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_collectinginfo_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_action_data_t data ;
sm_rcs_t sm_rc = SM_RC_END ;
cc_causes_t cause ;
cc_feature_data_t * feature_data = & ( msg - > data ) ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( msg - > feature_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = feature_data - > caps . support_direction ;
break ;
case CC_FEATURE_END_CALL :
cause = fsmdef_get_cause ( msg - > data_valid , & ( msg - > data ) ) ;
if ( fcb - > state = = FSMDEF_S_KPML_COLLECT_INFO ) {
/* Clean up and send release */
return ( fsmdef_release ( fcb , cause , TRUE ) ) ;
}
else {
/* Clean up without sending release */
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
}
case CC_FEATURE_NUMBER :
case CC_FEATURE_URL :
dcb - > dial_mode = ( ( msg - > feature_id = = CC_FEATURE_NUMBER ) ?
( DIAL_MODE_NUMERIC ) : ( DIAL_MODE_URL ) ) ;
data . dial_mode . mode = dcb - > dial_mode ;
data . dial_mode . digit_cnt = dcb - > digit_cnt ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_DIAL_MODE ,
& data ) ;
break ;
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
/*
* lsm_set_lcb_prevent_ringing ( ) will check if there is a RINGIN call
* with the same GCID . If so , it will set a flag to prevent ringing .
*/
lsm_set_lcb_prevent_ringing ( dcb - > call_id ) ;
break ;
case CC_FEATURE_SELECT :
fsmdef_select_invoke ( dcb , feature_data ) ;
return ( SM_RC_END ) ;
case CC_FEATURE_CFWD_ALL :
if ( fsmdef_is_feature_uri_configured ( msg - > feature_id ) = = FALSE ) {
fsm_set_call_status_feature_unavailable ( dcb - > call_id , dcb - > line ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
// handle cfwd event for ccm and non-ccm cases
// process feature event only if no other active feature
if ( dcb - > active_feature = = CC_FEATURE_NONE ) {
dcb - > active_feature = ftr_id ;
( void ) fsmdef_process_cfwd_softkey_event ( event ) ;
} else {
fsmdef_check_active_feature ( dcb , ftr_id ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
}
break ;
default :
dcb - > active_feature = CC_FEATURE_NONE ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
return ( sm_rc ) ;
}
/*
* Function : fsmdef_ev_digit_begin
*
* Parameters : event
*
* Description : This function is called each time a digit is
* received from the platform code . Currently , the platform code
* parses the dialplan . This function simply turns the
* dialtone off every time a digit is received and
* displays the appropriate keyset . ( Eventually , this
* interface should be changed and GSM should have
* better knowledge of the dialplan . )
*
* Returns : SM_RC_END
*/
static sm_rcs_t
fsmdef_ev_digit_begin ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_digit_begin " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_digit_begin_t * msg = ( cc_digit_begin_t * ) event - > msg ;
char digit ;
cc_action_data_t data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
digit = lsm_digit2ch ( msg - > digit ) ;
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " Digit Received= %c: stopping dial tone.. \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , msg - > line , msg - > call_id , fname ) , digit ) ;
data . tone . tone = VCM_INSIDE_DIAL_TONE ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_STOP_TONE , & data ) ;
/*
* Increment digit_cnt so that the proper keyset will be
* displayed .
*/
if ( dcb - > digit_cnt < CC_MAX_DIALSTRING_LEN ) {
dcb - > digit_cnt + + ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_proceeding ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
fcb - > dcb - > send_release = TRUE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
# ifdef SAPP_SAPP_GSM
if ( ( event - > msg ! = NULL ) & &
( ( ( cc_proceeding_t * ) ( event - > msg ) ) - > caller_id . called_name ! = NULL ) ) {
dcb - > caller_id . called_name =
strlib_update ( dcb - > caller_id . called_name ,
( ( cc_proceeding_t * ) ( event - > msg ) ) - > caller_id .
called_name ) ;
}
# endif
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_FAR_END_PROCEEDING ,
FSMDEF_CC_CALLER_ID ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_OUTGOING_PROCEEDING ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_out_alerting ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_out_alerting " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_alerting_t * msg = ( cc_alerting_t * ) event - > msg ;
cc_causes_t cause = CC_CAUSE_ERROR ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
dcb - > send_release = TRUE ;
dcb - > inband = FALSE ;
if ( msg - > inband ) {
dcb - > inband = TRUE ;
cause = gsmsdp_negotiate_answer_sdp ( fcb , & msg - > msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/*
* Record fact that we have successfully negotiated media that may be
* used for inband ringback .
*/
dcb - > inband_received = TRUE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " inband_received, cancel timer. \n " , DEB_F_PREFIX_ARGS ( FSM , fname ) ) ;
/*
* If ringback delay timer has been started , cancel it now .
*/
if ( cprCancelTimer ( dcb - > ringback_delay_tmr ) ! = CPR_SUCCESS ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CANCEL_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Ringback Delay " ,
cpr_errno ) ;
}
} else {
/*
* Not inband alerting case . Set ringback delay timer so that local
* ringback will eventually be played . We delay the ringback for
* a short time to handle the case where the messages key was pressed .
* This is because VM server can respond very quickly with RTP , 183 ,
* and 200 and we do not want local ringback tone to interfere with
* the playing of the VM prompt .
*/
if ( ! cprIsTimerRunning ( dcb - > ringback_delay_tmr ) ) {
fsmdef_set_ringback_delay_timer ( dcb ) ;
}
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_FAR_END_ALERTING ,
FSMDEF_CC_CALLER_ID ) ;
/*
* If DSP is not able to start rx / tx channels , release the call
*/
if ( dcb - > dsp_out_of_resources = = TRUE ) {
( void ) fsmdef_release ( fcb , CC_CAUSE_NO_MEDIA , dcb - > send_release ) ;
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( SM_RC_END ) ;
}
// fsmdef_update_pd(dcb, FSMDEF_CALL_TYPE_OUTGOING);
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_OUTGOING_ALERTING ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_callsent_release ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_release_t * msg = ( cc_release_t * ) event - > msg ;
cc_causes_t cause = msg - > cause ;
cc_srcs_t src_id = msg - > src_id ;
sm_rcs_t sm_rc = SM_RC_END ;
char tmp_str [ STATUS_LINE_MAX_LEN ] ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/* if UI_STATE of BUSY in 183 Call-Info is causing the release,
do not modify dcb - > send_release */
if ( cause ! = CC_CAUSE_UI_STATE_BUSY ) {
dcb - > send_release = FALSE ;
} else {
// CSCti63677
if ( ( fcb - > state = = FSMDEF_S_OUTGOING_ALERTING ) & &
( dcb - > inband_received = = TRUE ) & &
( dcb - > placed_call_update_required ) ) {
lsm_update_placed_callinfo ( dcb ) ;
dcb - > placed_call_update_required = FALSE ;
}
}
FSM_SET_FLAGS ( dcb - > msgs_rcvd , FSMDEF_MSG_RELEASE ) ;
/* For 500 response from the CCM, disconnect the call and clear the UI.
* There are several cases in which CCM sends down 500 response code to
* clear the call and UI . Some of the cases are CFWDALL , early conference
* and CTI transfer of ringing call
*
* Non - auto pickups do receive 480 response , it is OK release the call .
*/
if ( ( cause = = CC_CAUSE_REMOTE_SERVER_ERROR ) | |
( ( ( strncmp ( dcb - > caller_id . called_number , CISCO_BLFPICKUP_STRING ,
( sizeof ( CISCO_BLFPICKUP_STRING ) - 1 ) ) = = 0 ) ) & &
( ( cause = = CC_TEMP_NOT_AVAILABLE ) | | ( cause = = CC_CAUSE_CONGESTION ) ) ) ) {
if ( cause = = CC_CAUSE_CONGESTION ) {
if ( platGetPhraseText ( STR_INDEX_NO_CALL_FOR_PICKUP , ( char * ) tmp_str , STATUS_LINE_MAX_LEN - 1 ) = = CPR_SUCCESS )
{
ui_set_notification ( CC_NO_LINE , CC_NO_CALL_ID , tmp_str , 2 , FALSE , DEF_NOTIFY_PRI ) ;
}
}
cause = CC_CAUSE_OK ;
}
switch ( cause ) {
case CC_CAUSE_ERROR :
case CC_CAUSE_NOT_FOUND :
case CC_CAUSE_BUSY :
case CC_CAUSE_CONGESTION :
case CC_CAUSE_INVALID_NUMBER :
case CC_CAUSE_PAYLOAD_MISMATCH :
case CC_CAUSE_REMOTE_SERVER_ERROR :
case CC_TEMP_NOT_AVAILABLE :
case CC_CAUSE_UI_STATE_BUSY :
case CC_CAUSE_NO_USER_ANS :
fsmdef_set_call_info_cc_call_state ( dcb , CC_STATE_CALL_FAILED , cause ) ;
if ( cause ! = CC_CAUSE_UI_STATE_BUSY ) {
cc_int_release_complete ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , cause , NULL ) ;
}
/* see if the SIP stack has aborted this call early for some reason
* If SIP brought this down , we are still offhook on the UI , so
* when we get the release_complete from the 200 for the BYE , we
* need to ignore it , so that reorder can be played AND when the user
* hangs up , then the UI will be driven to a clean state .
*/
if ( src_id = = CC_SRC_SIP ) {
dcb - > early_error_release = TRUE ;
}
if ( dcb - > err_onhook_tmr ) {
( void ) cprDestroyTimer ( dcb - > err_onhook_tmr ) ;
}
dcb - > err_onhook_tmr = cprCreateTimer ( " Error Onhook " ,
GSM_ERROR_ONHOOK_TIMER ,
TIMER_EXPIRATION ,
gsm_msg_queue ) ;
if ( dcb - > err_onhook_tmr = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CREATE_FAILED ) ,
dcb - > call_id , dcb - > line , " " , " Error Onhook " ) ;
return ( SM_RC_CLEANUP ) ;
}
if ( cprStartTimer ( dcb - > err_onhook_tmr ,
FSMDEF_ERR_ONHOOK_TMR_SECS * 1000 ,
( void * ) ( long ) dcb - > call_id ) = = CPR_FAILURE ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_START_FAILED ) ,
dcb - > call_id , dcb - > line , " " ,
" Error Onhook " , cpr_errno ) ;
return ( SM_RC_CLEANUP ) ;
}
break ;
default :
sm_rc = fsmdef_release ( fcb , cause , dcb - > send_release ) ;
if ( sm_rc = = SM_RC_CLEANUP ) {
/*
* FSM release indicates clean up , do not continue
* on since fcb and dcb have been freed or re - initialized .
*/
return ( sm_rc ) ;
}
} /* switch (cause) */
/*UI_STATE of BUSY in 183 is causing the release, so
* don ' t change state . This is needed to support
* callback feature . Since the callee is busy , we need
* update call UI status to " Busy " from " Ringout " to
* reflect this change .
*/
if ( cause ! = CC_CAUSE_UI_STATE_BUSY ) {
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_RELEASING ) ;
} else {
cc_action_data_t action_data ;
action_data . update_ui . action = CC_UPDATE_SET_CALL_STATUS ;
action_data . update_ui . data . set_call_status_parms . phrase_str_p = platform_get_phrase_index_str ( LINE_BUSY ) ;
action_data . update_ui . data . set_call_status_parms . timeout = 0 ;
action_data . update_ui . data . set_call_status_parms . call_id = dcb - > call_id ;
action_data . update_ui . data . set_call_status_parms . line = dcb - > line ;
/*Update UI status to "Busy".*/
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_UPDATE_UI ,
& action_data ) ;
}
return ( sm_rc ) ;
}
static sm_rcs_t
fsmdef_ev_callsent_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
cc_causes_t cause ;
cc_feature_data_redirect_t * data = & ( msg - > data . redirect ) ;
cc_action_data_t action_data ;
cc_feature_data_t * select_data = & ( msg - > data ) ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = select_data - > caps . support_direction ;
break ;
case CC_FEATURE_NOTIFY :
if ( src_id = = CC_SRC_SIP ) {
fsmdef_ev_notify_feature ( msg , dcb ) ;
} else {
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
}
break ;
case CC_FEATURE_END_CALL :
/**
* In case of earlier attandence , there might a waiting call .
*/
lsm_remove_lcb_prevent_ringing ( dcb - > call_id ) ;
/*
* Since user press the end call , no need to wait to play the busy tone .
* So , clear the early_error_release and clean the fcb / dcb .
*/
dcb - > early_error_release = FALSE ;
cause = fsmdef_get_cause ( msg - > data_valid , & ( msg - > data ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
case CC_FEATURE_REDIRECT :
/*
* The outgoing call has been redirected , so we need to :
* 1. ACK the redirect request ,
* 2. release the current call ,
* 3. start a new call to the redirect number .
*/
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_SIP , call_id , line ,
CC_FEATURE_REDIRECT , NULL , CC_CAUSE_REDIRECT ) ;
/*
* May need to update an xcb if this call is involved in a transfer .
*/
//xcb = fsmxfr_get_xcb_by_call_id(call_id);
// fsmxfr_update_xfr_context(xcb, call_id, redirect_call_id);
dcb - > caller_id . called_number =
strlib_update ( dcb - > caller_id . called_number , data - > redirect_number ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_DIALING_COMPLETED ,
FSMDEF_CC_CALLER_ID ) ;
break ;
case CC_FEATURE_CALLINFO :
fsmdef_update_calltype ( fcb , msg ) ;
fsmdef_update_callinfo ( fcb , msg ) ;
/*
* lsm_set_lcb_prevent_ringing ( ) will check if there is a RINGIN call
* with the same GCID . If so , it will set a flag to prevent ringing .
*/
lsm_set_lcb_prevent_ringing ( dcb - > call_id ) ;
break ;
case CC_FEATURE_UPDATE :
/* Simply reply with a 200OK to a received UPDATE */
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_SIP , call_id , line ,
CC_FEATURE_UPDATE , NULL , CC_CAUSE_OK ) ;
break ;
case CC_FEATURE_RINGBACK_DELAY_TIMER_EXP :
if ( ! dcb - > inband_received ) {
/*
* Ringback delay timer expired and we have not received
* a response from the far end indicating that they are
* playing inband ringback . Start local ringback tone now .
*/
action_data . tone . tone = VCM_ALERTING_TONE ;
( void ) cc_call_action ( call_id , line , CC_ACTION_PLAY_TONE ,
& action_data ) ;
}
break ;
case CC_FEATURE_SELECT :
fsmdef_select_invoke ( dcb , select_data ) ;
return ( SM_RC_END ) ;
case CC_FEATURE_SUBSCRIBE :
/* KPML subscription received so collect digits for KPML */
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_KPML_COLLECT_INFO ) ;
break ;
case CC_FEATURE_CFWD_ALL :
fsm_set_call_status_feature_unavailable ( call_id , line ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) { */
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_release_call ( fsm_fcb_t * fcb , cc_feature_t * msg )
{
cc_feature_data_t * data = & ( msg - > data ) ;
cc_state_data_t state_data ;
cc_causes_t cause ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
cause = fsmdef_get_cause ( msg - > data_valid , data ) ;
/*
* Do things a little different depending on the value of the
* release cause .
*/
switch ( cause ) {
case CC_CAUSE_XFER_LOCAL :
/*
* Send release and then wait for the release_complete .
*/
cc_int_release ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , data - > endcall . cause ,
data - > endcall . dialstring , NULL ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_RELEASING ) ;
state_data . onhook . caller_id = dcb - > caller_id ;
state_data . onhook . local = TRUE ;
state_data . onhook . cause = CC_CAUSE_NORMAL ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ONHOOK , & state_data ) ;
break ;
case CC_CAUSE_XFER_REMOTE :
/*
* No need to send release because the remote end initiated
* the transfer .
*/
dcb - > send_release = FALSE ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
case CC_CAUSE_XFER_CNF :
case CC_CAUSE_REPLACE :
/*
* We are the target of a transfer and this is the consultation
* call that is being replaced , so we just need to onhook this call
* but leave the signaling up until the stack notifies the FSM that
* the transfer is accepted - and then we will release the call .
* Same has to happen when bridge of conference ends the call . We are
* initiating transfer in this case so we want signaling to remain
* up while UI should be cleared up .
*/
state_data . onhook . caller_id = dcb - > caller_id ;
state_data . onhook . local = TRUE ;
state_data . onhook . cause = CC_CAUSE_NORMAL ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ONHOOK , & state_data ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLDING ) ;
break ;
default :
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_inalerting_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
cc_feature_data_t * data = & ( msg - > data ) ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case CC_SRC_UI :
case CC_SRC_GSM :
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
/* force an update to media cap */
dcb - > media_cap_tbl - > id - - ;
gsmsdp_update_local_sdp_media_capability ( dcb , FALSE , FALSE ) ;
break ;
case CC_FEATURE_END_CALL :
return ( fsmdef_release_call ( fcb , msg ) ) ;
case CC_FEATURE_ANSWER :
/*
* The user wants to answer this call , so . . .
* 1. need to place the connected call ( if there is one ) on hold ,
* 2. clear all the outgoing ringing lines ,
* 3. answer this call .
*/
if ( fsmdef_wait_to_start_new_call ( TRUE , CC_SRC_GSM , dcb - > call_id , dcb - > line ,
CC_FEATURE_ANSWER , NULL ) ) {
/*
* Inform the LSM that the answering of this call has
* been delayed while waiting for other calls to clear .
*/
( void ) cc_call_action ( dcb - > call_id , dcb - > line ,
CC_ACTION_ANSWER_PENDING , NULL ) ;
return ( SM_RC_END ) ;
}
return ( fsmdef_handle_inalerting_offhook_answer ( event ) ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) { */
break ;
case CC_SRC_SIP :
switch ( ftr_id ) {
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
case CC_FEATURE_UPDATE :
/* Simply reply with a 200 OK to a received UPDATE */
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_SIP , call_id , line ,
CC_FEATURE_UPDATE , NULL , CC_CAUSE_OK ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) { */
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (src_id) { */
return ( SM_RC_END ) ;
}
/*
* This function contains the common code for fsmdef_ev_inalerting_offhook ( )
* and the ANSWER event handling in the fsmdef_ev_inalerting_feature ( ) .
*/
static sm_rcs_t
fsmdef_handle_inalerting_offhook_answer ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_causes_t cause ;
cc_msgbody_info_t msg_body ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/* Build our response SDP to include in the connected */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/* For CCM, call_type indicate if the call is forwarded or not
* for forwarded call display will be shown as " Forward " , only
* during ringing state . Once the call is connected then the call
* is shown as normal incoming call " From " . so change call type now
* Do this only if Retain Forward Information is disabled or not configured .
* If configured / enabled then leave the call type as Forward .
*/
if ( dcb - > call_type = = FSMDEF_CALL_TYPE_FORWARD ) {
if ( ! fsmdef_check_retain_fwd_info_state ( ) ) {
dcb - > call_type = FSMDEF_CALL_TYPE_INCOMING ;
/*
* Force us to update the UI so that any possible callinfo received
* prior to the call is answered takes effect .
*/
dcb - > ui_update_required = TRUE ;
}
}
/* Cancel any existing autoanswer timer */
( void ) cprCancelTimer ( dcb - > autoAnswerTimer ) ;
cc_int_connected ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , NULL , & msg_body ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_CONNECTED ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_ANSWERED ,
FSMDEF_CC_CALLER_ID ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTING ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_inalerting_offhook ( sm_event_t * event )
{
return ( fsmdef_handle_inalerting_offhook_answer ( event ) ) ;
}
static sm_rcs_t
fsmdef_ev_connecting_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_causes_t cause ;
cc_feature_data_t * data = & ( msg - > data ) ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case CC_SRC_UI :
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
break ;
case CC_FEATURE_END_CALL :
cause = fsmdef_get_cause ( msg - > data_valid , & ( msg - > data ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
case CC_SRC_SIP :
switch ( ftr_id ) {
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
case CC_FEATURE_CALL_PRESERVATION :
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ) ;
case CC_FEATURE_NOTIFY :
fsmdef_ev_notify_feature ( msg , dcb ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
case CC_SRC_GSM :
switch ( ftr_id ) {
case CC_FEATURE_END_CALL :
cause = fsmdef_get_cause ( msg - > data_valid , & ( msg - > data ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
}
return ( SM_RC_END ) ;
}
/**
*
* Function to handle transition to FSMDEF_S_CONNECTED . It checks
* whether there is any media capability that needs to be updated
* or not . If there is not then it transition to FSMDEF_S_CONNECTED
* otherwise it transitions to the FSMDEF_S_CONNECTED_MEDIA_PEND state
* and sends out the media update request .
*
* @ param [ in ] fcb - The pointer to the fsm_fcb_t structure of this
* call .
*
* @ return SM_RC_END or SM_RC_CLEANUP
*
* @ pre ( fcb not_eq NULL )
*/
static sm_rcs_t
fsmdef_transition_to_connected ( fsm_fcb_t * fcb )
{
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_data_t feature_data ;
sm_rcs_t sm_rc = SM_RC_END ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( dcb - > req_pending_tmr ) {
/* cancel any request pending timer, just in case */
( void ) cprCancelTimer ( dcb - > req_pending_tmr ) ;
}
/*
* Update the media capability without effecting the existing media line .
*/
if ( ! gsmsdp_update_local_sdp_media_capability ( dcb , FALSE , FALSE ) ) {
/* not thing is changed, transition to connected state */
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTED ) ;
return ( sm_rc ) ;
}
feature_data . resume . call_info . type = CC_FEAT_NONE ;
feature_data . resume . call_info . data . hold_resume_reason = CC_REASON_NONE ;
feature_data . resume . msg_body . num_parts = 0 ;
feature_data . resume . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . resume . call_info . data . call_info_feat_data . protect = FALSE ;
/* Encode SDP */
cause = gsmsdp_encode_sdp_and_update_version ( dcb ,
& feature_data . resume . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
fsmdef_get_rtp_stat ( dcb , & ( feature_data . resume . kfactor ) ) ;
/* Send feature request to SIP */
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
CC_FEATURE_MEDIA , & feature_data ) ;
if ( g_dock_undock_event = = MEDIA_INTERFACE_UPDATE_STARTED ) {
g_dock_undock_event = MEDIA_INTERFACE_UPDATE_IN_PROCESS ;
ui_update_media_interface_change ( dcb - > line , dcb - > call_id , MEDIA_INTERFACE_UPDATE_BEGIN ) ;
} else if ( g_dock_undock_event = = MEDIA_INTERFACE_UPDATE_IN_PROCESS ) {
DEF_DEBUG ( DEB_F_PREFIX " MEDIA_INTERFACE_UPDATE is already in process. "
" Ignore another update event. \n " , DEB_F_PREFIX_ARGS ( FSM , " fsmdef_transition_to_connected " ) ) ;
}
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTED_MEDIA_PEND ) ;
return ( sm_rc ) ;
}
static sm_rcs_t
fsmdef_ev_connected ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_connected " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_connected_t * msg = ( cc_connected_t * ) event - > msg ;
cc_causes_t cause ;
sm_rcs_t sm_rc ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
dcb - > send_release = TRUE ;
cause = gsmsdp_negotiate_answer_sdp ( fcb , & msg - > msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
// Reset dcb->active_feature flag
dcb - > active_feature = CC_FEATURE_NONE ;
/* Reset spoof ring out in case t was set before going to connected state. */
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
/*
* Cancel ringback delay timer
*/
if ( cprCancelTimer ( dcb - > ringback_delay_tmr ) ! = CPR_SUCCESS ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CANCEL_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Ringback Delay " ,
cpr_errno ) ;
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
if ( dcb - > log_disp ! = CC_CALL_LOG_DISP_UNKNWN ) {
ui_log_disposition ( dcb - > call_id , dcb - > log_disp ) ;
}
ui_cc_capability ( dcb - > line , lsm_get_ui_id ( dcb - > call_id ) , msg - > recv_info_list ) ;
/*
* If DSP is not able to start rx / tx channels , release the call
*/
if ( dcb - > dsp_out_of_resources = = TRUE ) {
( void ) fsmdef_release ( fcb , CC_CAUSE_NO_MEDIA , dcb - > send_release ) ;
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( SM_RC_END ) ;
}
cc_int_connected_ack ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , NULL ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_CONNECTED_ACK ) ;
// fsmdef_update_pd(dcb, FSMDEF_CALL_TYPE_OUTGOING);
/*
* Handle media capability changes if there is before transition to
* connected state .
*/
sm_rc = fsmdef_transition_to_connected ( fcb ) ;
fsmutil_set_shown_calls_ci_element ( dcb - > caller_id . call_instance_id , dcb - > line ) ;
return ( sm_rc ) ;
}
static sm_rcs_t
fsmdef_ev_connected_ack ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_connected_ack_t * msg = ( cc_connected_ack_t * ) event - > msg ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Check the remote SDP . The far end may not have included the SDP in an
* earlier message , which means that the SDP must be in this message .
*/
if ( dcb - > remote_sdp_in_ack = = TRUE ) {
cause = gsmsdp_negotiate_answer_sdp ( fcb , & msg - > msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
/*
* If DSP is not able to start rx / tx channels , release the call
*/
if ( dcb - > dsp_out_of_resources = = TRUE ) {
( void ) fsmdef_release ( fcb , CC_CAUSE_NO_MEDIA , dcb - > send_release ) ;
cc_call_state ( fcb - > dcb - > call_id , fcb - > dcb - > line , CC_STATE_UNKNOWN ,
NULL ) ;
return ( SM_RC_END ) ;
}
// fsmdef_update_pd(dcb, FSMDEF_CALL_TYPE_INCOMING);
/*
* Handle media capability changes if there is before transition to
* connected state .
*/
return ( fsmdef_transition_to_connected ( fcb ) ) ;
}
/**
* The function handles local hold event but not sending any hold request
* out to the remote end . The local SDP is updated by the way .
*
* @ param [ in ] fcb - pointer to fsm_fcb_t
*
* @ return SM_RC_END or failrue .
*
* @ pre ( fcb not_eq NULL )
*/
static sm_rcs_t
fsm_hold_local_only ( fsm_fcb_t * fcb )
{
static const char fname [ ] = " fsm_hold_local_only " ;
cc_state_data_t state_data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Check local hold status , and allow request if the media is not
* locally held .
*/
if ( fsmdef_all_media_are_local_hold ( dcb ) ) {
/*
* a new hold request is not allowed . Ignore the request
* but we should still ack the request .
*/
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_HOLD , NULL , CC_CAUSE_NORMAL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , dcb - > call_id , dcb - > line ,
fname , " already hold " ) ;
return ( SM_RC_END ) ;
}
state_data . hold . caller_id = dcb - > caller_id ;
state_data . hold . local = TRUE ;
/*
* Update the SDP so that offer indicates hold . Reinitialize the local
* sdp media to include all available codecs . We do this because our local
* list has been shortened to the one negotiated codec .
*/
( void ) gsmsdp_update_local_sdp_media_capability ( dcb , TRUE , TRUE ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_HOLD , & state_data ) ;
/* set all the media to local hold */
fsmdef_update_media_hold_status ( dcb , NULL , TRUE ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLDING ) ;
sipsdp_src_dest_free ( CCSIP_DEST_SDP_BIT | CCSIP_SRC_SDP_BIT ,
& dcb - > sdp ) ;
return ( SM_RC_END ) ;
}
/**
* The function handles local hold event . The function also supports
* re - sending hold request out such as during a glare condition .
*
* @ param [ in ] fcb - pointer to fsm_fcb_t
* @ param [ in ] data_p - pointer to the cc_feature_data_t of the
* hold feature .
* @ param [ in ] resend - TRUE indicates to resend hold request .
*
* @ return SM_RC_END or failrue .
*
* @ pre ( fcb not_eq NULL )
* @ pre ( data_p not_eq NULL )
*/
static sm_rcs_t
fsm_hold_local ( fsm_fcb_t * fcb , cc_feature_data_t * data_p ,
boolean resend )
{
static const char fname [ ] = " fsm_hold_local " ;
cc_state_data_t state_data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Check local hold status , and allow request if the media is not
* locally held or the caller indicates that to resend the hold
* request ( such as in glare resolution ) .
*/
if ( ! resend & & fsmdef_all_media_are_local_hold ( dcb ) ) {
/*
* a new hold request is not allowed . Ignore the request
* but we should still ack the request .
*/
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_HOLD , NULL ,
CC_CAUSE_NORMAL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , dcb - > call_id , dcb - > line ,
fname , " already hold " ) ;
return ( SM_RC_END ) ;
}
state_data . hold . caller_id = dcb - > caller_id ;
state_data . hold . local = TRUE ;
state_data . hold . reason = data_p - > hold . call_info . data . hold_resume_reason ;
/* Store hold reason in case we need to resend the hold request due to
* request pending response .
*/
dcb - > hold_reason = data_p - > hold . call_info . data . hold_resume_reason ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
fsmdef_get_rtp_stat ( dcb , & ( data_p - > hold . kfactor ) ) ;
/* put the call on hold before building the SDP as DSP
* will then be able to give us a full set of codecs
* CUCM doesn ' t like to see a change in codecs on the fly
* ( i . e . without going to inactive state ) */
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_HOLD , & state_data ) ;
/*
* Update the SDP so that offer indicates hold . Reinitialize the local
* sdp to include all available codecs . We do this because our
* local list has been shortened to the one negotiated codec .
*/
( void ) gsmsdp_update_local_sdp_media_capability ( dcb , TRUE , TRUE ) ;
/*
* Do not expect any msg . body from local hold but free them
* just in case before build new SDP body to send out .
*/
cc_free_msg_body_parts ( & data_p - > hold . msg_body ) ;
/* Build SDP for sending out */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & data_p - > hold . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/* set all the media to local hold */
fsmdef_update_media_hold_status ( dcb , NULL , TRUE ) ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
CC_FEATURE_HOLD , data_p ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLDING ) ;
sipsdp_src_dest_free ( CCSIP_DEST_SDP_BIT | CCSIP_SRC_SDP_BIT ,
& dcb - > sdp ) ;
return ( SM_RC_END ) ;
}
/**
* Handles hold feature in connected media update pending state .
*
* @ param [ in ] fcb The pointer to the fsm_fcb_t structure of this
* call chain .
* @ param [ in ] data_p pointer to the cc_feature_data_t .
*
* @ return sm_rsc_t indicates whether the execution of
* next statmachine to end or to clean up .
*/
static sm_rcs_t
fsm_connected_media_pend_local_hold ( fsm_fcb_t * fcb , cc_feature_data_t * data_p )
{
static const char fname [ ] = " fsm_hold_local_connected_media_pend " ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Check local hold status , and allow request if the media is not
* locally held .
*/
if ( fsmdef_all_media_are_local_hold ( dcb ) ) {
/*
* a new hold request is not allowed . Ignore the request
* but we should still ack the request .
*/
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_HOLD , NULL ,
CC_CAUSE_NORMAL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , dcb - > call_id , dcb - > line ,
fname , " already hold " ) ;
return ( SM_RC_END ) ;
}
if ( dcb - > req_pending_tmr & &
cprIsTimerRunning ( dcb - > req_pending_tmr ) ) {
/*
* Request timer is running , that means we are waiting
* to re - send media update again due to previously glare .
* Since the previous offer has not been accepted , we can
* simply just send hold instead when glare resolution timer
* expires .
*/
/* store the reason to resend when glare timer expires */
dcb - > hold_reason = data_p - > hold . call_info . data . hold_resume_reason ;
/*
* reset feature hold pending flag in case that there are
* multiple hold feature received while waiting for
* glare resolution to resolve .
*/
FSM_RESET_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLD_PENDING ) ;
return ( SM_RC_END ) ;
}
/*
* We have sent media capability update out but have not received
* any response yet . The glare condition may occur but we can only
* assume that the media update was sent out at this point .
* We can not send out any more request until the result is
* known . We can not do any thing now but simply remember
* to re - send media with the hold feature pending when
* the result is known .
*/
FSM_SET_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ;
return ( SM_RC_END ) ;
}
/**
* common function to handles media feature from remote end .
*
* @ param [ in ] fcb The pointer to the fsm_fcb_t structure of this
* call chain .
* @ param [ in ] msg The pointer to cc_feature_t .
*
* @ return sm_rsc_t indicates whether the execution of
* next statmachine to end or to clean up .
*/
static sm_rcs_t
fsmdef_remote_media ( fsm_fcb_t * fcb , cc_feature_t * msg )
{
static const char fname [ ] = " fsmdef_remote_media " ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_data_t * data = & ( msg - > data ) ;
cc_feature_data_t feature_data ;
cc_causes_t cause ;
boolean send_ack = TRUE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
memset ( & feature_data , 0 , sizeof ( cc_feature_data_t ) ) ;
/*
* Determine what type of RESUME / MEDIA this is :
* 1. third - party control is just trying to change the media -
* midcall - invite with no SDP , so we need to wait for the SDP
* in the SIP ACK before we can truly resume the media .
* 2. remote end wants to resume a held call or just a media
* changes .
*
* We can distinguish between the two because case 1 will not
* have any data and case 2 will have data .
*/
if ( msg - > data_valid = = FALSE ) {
/*
* Case 1.
*
* negotiate offer without SDP will reset all local media entries
* to have all codecs included . This is to re - advertise the
* capabilities again .
*/
( void ) gsmsdp_negotiate_offer_sdp ( fcb , NULL , FALSE ) ;
/*
* Update the media direction based on whether each media
* stream is locally held or not before sending out the
* offer SDP .
*/
fsmdef_set_per_media_local_hold_sdp ( dcb ) ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_STOP_MEDIA ,
NULL ) ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_START_RCV ,
NULL ) ;
} else {
/*
* SIP may send MEDIA feature when answer SDP is received in
* ACK . The secnario is found when remote resumes and the
* resume INVITE is a delayed media INVITE . We sent an offer in
* the 200 OK and gets the answer back in the ACK . In this
* case , SIP will send MEDIA feature to GSM . We need to check
* whether we are waiting for an answer in ACK or not and
* use the corresponding offer / answer SDP negotiation function .
*/
if ( dcb - > remote_sdp_in_ack ) {
cause = gsmsdp_negotiate_answer_sdp ( fcb ,
& data - > resume . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
/*
* There is some thing wrong the answer SDP for some
* reason , can not go on .
*/
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/*
* This is the answer to our previous offer , no need to
* to ack to SIP this one .
*/
send_ack = FALSE ;
} else {
/* This is a new offer */
/*
* get k factor to be included in the feature ack . Getting
* the k factor needs to be done before maniputate media
* stream by the LSM .
*/
fsmdef_media_t * media = gsmsdp_find_audio_media ( dcb ) ;
if ( ( media ) & & ( media - > direction ! = SDP_DIRECTION_INACTIVE ) ) {
fsmdef_get_rtp_stat ( dcb , & ( feature_data . resume . kfactor ) ) ;
}
cause = gsmsdp_negotiate_offer_sdp ( fcb ,
& data - > resume . msg_body , FALSE ) ;
if ( cause ! = CC_CAUSE_OK ) {
/*
* Received a sdp that cannot be accepted .
* It should just reject the new sdp offer rather than
* tearing down the call .
*/
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , msg - > feature_id , NULL , cause ) ;
return ( SM_RC_END ) ;
}
/*
* Update the media based on local hold .
*/
fsmdef_set_per_media_local_hold_sdp ( dcb ) ;
}
/*
* If spoof ringout is not being requested and we are currently
* playing spoof ringout , transition the LSM from the far end alerting
* to the connected state .
*/
if ( ( ! dcb - > spoof_ringout_requested ) & & ( dcb - > spoof_ringout_applied ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
} else {
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_MEDIA ,
NULL ) ;
}
}
if ( send_ack ) {
/* Build SDP from our current SDP */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & feature_data . resume . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , msg - > feature_id , & feature_data ,
CC_CAUSE_NORMAL ) ;
}
return ( SM_RC_END ) ;
}
/**
*
* Function to handles connected state feature events . Function handles
* feature events generated by GSM , UI and SIP stack .
*
* @ param sm_event_t event
*
* @ return SM_RC_END or SM_RC_CLEANUP
*
* @ pre ( fcb - > dcb not_eq NULL )
* @ pre ( event - > data not_eq NULL )
* @ pre ( event - > msg not_eq NULL )
*/
static sm_rcs_t
fsmdef_ev_connected_feature ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_connected_feature " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_feature_data_t * data = & ( msg - > data ) ;
sm_rcs_t sm_rc ;
cc_feature_data_t feature_data ;
cc_action_data_t action_data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case CC_SRC_UI :
case CC_SRC_GSM :
switch ( msg - > feature_id ) {
case CC_FEATURE_HOLD :
/* If the line number is 0xFF, then this request
* came from GSM during a Transfer . We want to
* put the call on local hold only . We do not want
* to send a cc_feature to the SIP stack because
* that will cause an Invite Hold to go via SIP .
* We don ' t want to put the other end on hold , just
* ourselves .
*/
if ( msg - > line = = 0xFF ) {
sm_rc = fsm_hold_local_only ( fcb ) ;
} else {
if ( msg - > data_valid ) {
sm_rc = fsm_hold_local ( fcb , data , FALSE ) ;
} else {
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
CC_REASON_NONE ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
sm_rc = fsm_hold_local ( fcb , & feature_data , FALSE ) ;
}
}
fsmdef_handle_join_pending ( dcb ) ;
return ( sm_rc ) ;
case CC_FEATURE_END_CALL :
sm_rc = fsmdef_release_call ( fcb , msg ) ;
fsmdef_handle_join_pending ( dcb ) ;
return ( sm_rc ) ;
case CC_FEATURE_JOIN :
/*
* Send offhook to the new call that triggers the
* completion of the setup of the join in call
*/
fsmdef_ev_join ( data ) ;
break ;
case CC_FEATURE_SELECT :
if ( msg - > data_valid = = FALSE ) {
fsmdef_select_invoke ( dcb , NULL ) ;
} else {
fsmdef_select_invoke ( dcb , data ) ;
}
return ( SM_RC_END ) ;
case CC_FEATURE_B2B_JOIN :
if ( msg - > data_valid = = FALSE ) {
fsmdef_b2bjoin_invoke ( dcb , NULL ) ;
} else {
fsmdef_b2bjoin_invoke ( dcb , data ) ;
}
return ( SM_RC_END ) ;
case CC_FEATURE_DIRTRXFR :
case CC_FEATURE_UNDEFINED :
fsm_display_feature_unavailable ( ) ;
fsmdef_handle_join_pending ( dcb ) ;
return ( SM_RC_END ) ;
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
// Force an re-INVITE by mismatching the id
dcb - > media_cap_tbl - > id - - ;
/* FALL THRU */
case CC_FEATURE_UPD_MEDIA_CAP :
/*
* Media capability update request , check to see if
* there is any change in media capability and transition
* the pending state or stay in the connected state .
*/
sm_rc = fsmdef_transition_to_connected ( fcb ) ;
return ( sm_rc ) ;
case CC_FEATURE_REQ_PEND_TIMER_EXP :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
default :
fsmdef_handle_join_pending ( dcb ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (msg->feature_id) */
break ;
case CC_SRC_SIP :
switch ( msg - > feature_id ) {
case CC_FEATURE_MEDIA :
/*
* remote send media update which can be resume or
* or just media changes .
*/
sm_rc = fsmdef_remote_media ( fcb , msg ) ;
return ( sm_rc ) ;
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
case CC_FEATURE_CALL_PRESERVATION :
action_data . update_ui . action = CC_UPDATE_CALL_PRESERVATION ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_UPDATE_UI ,
& action_data ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_PRESERVED ) ;
break ;
case CC_FEATURE_NOTIFY :
fsmdef_ev_notify_feature ( msg , dcb ) ;
break ;
case CC_FEATURE_UPDATE :
/*
* We only get an UPDATE feature event if we receive a medialess UPDATE .
* This type of event only conveys UI updates that are processed with
* a call info event . We do perform one check to see if we are currently
* spoofing ringout . If we are and the spoof ringout requested flag
* has been cleared , we tell the LSM to go connected .
*/
if ( ( ! dcb - > spoof_ringout_requested ) & & ( dcb - > spoof_ringout_applied ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
}
/*
* For chaperone call , we will update call state here , to update
* the related key ' s status .
*/
if ( dcb - > policy = = CC_POLICY_CHAPERONE ) {
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
}
break ;
case CC_FEATURE_FAST_PIC_UPD :
vcmMediaControl ( CREATE_CALL_HANDLE ( dcb - > line , dcb - > call_id ) , VCM_MEDIA_CONTROL_PICTURE_FAST_UPDATE ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (msg->feature_id) */
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
} /* switch (src_id) */
return ( SM_RC_END ) ;
}
/**
*
* Function to handles connected state media update pending feature .
*
* @ param sm_event_t event
*
* @ return SM_RC_END or SM_RC_CLEANUP
*
* @ pre ( fcb - > dcb not_eq NULL )
* @ pre ( event - > data not_eq NULL )
* @ pre ( event - > msg not_eq NULL )
*/
static sm_rcs_t
fsmdef_ev_connected_media_pend_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_feature_data_t * data = & ( msg - > data ) ;
sm_rcs_t sm_rc = SM_RC_END ;
cc_feature_data_t feature_data ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case CC_SRC_UI :
case CC_SRC_GSM :
switch ( msg - > feature_id ) {
case CC_FEATURE_HOLD :
/* If the line number is 0xFF, then this request
* came from GSM during a Transfer . We want to
* put the call on local hold only . We do not want
* to send a cc_feature to the SIP stack because
* that will cause an Invite Hold to go via SIP .
* We don ' t want to put the other end on hold , just
* ourselves .
*/
if ( msg - > line = = 0xFF ) {
sm_rc = fsm_hold_local_only ( fcb ) ;
} else {
if ( msg - > data_valid ) {
sm_rc = fsm_connected_media_pend_local_hold ( fcb , data ) ;
} else {
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
CC_REASON_NONE ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
sm_rc = fsm_connected_media_pend_local_hold ( fcb ,
& feature_data ) ;
}
}
fsmdef_handle_join_pending ( dcb ) ;
return ( sm_rc ) ;
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
/* FALL THRU */
case CC_FEATURE_UPD_MEDIA_CAP :
/* We are already in the media update state */
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
return ( SM_RC_END ) ;
case CC_FEATURE_REQ_PEND_TIMER_EXP :
/*
* Glare resolution timer expires .
*/
if ( FSM_CHK_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ) {
/* There is a hold feature pending, send out hold instead */
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
dcb - > hold_reason ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
FSM_RESET_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ;
return ( fsm_hold_local ( fcb , & feature_data , FALSE ) ) ;
}
/*
* Check the possible media capbility changes .
*/
( void ) gsmsdp_update_local_sdp_media_capability ( dcb , FALSE , FALSE ) ;
feature_data . resume . call_info . type = CC_FEAT_NONE ;
feature_data . resume . call_info . data . hold_resume_reason =
CC_REASON_NONE ;
feature_data . resume . msg_body . num_parts = 0 ;
feature_data . resume . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . resume . call_info . data . call_info_feat_data . protect = FALSE ;
/* Encode SDP */
cause = gsmsdp_encode_sdp_and_update_version ( dcb ,
& feature_data . resume . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/* Send feature request to SIP */
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
CC_FEATURE_MEDIA , & feature_data ) ;
return ( SM_RC_END ) ;
default :
/*
* The rest of the feature handles the same way as the
* connected feature handling .
*/
break ;
} /* switch (msg->feature_id) */
break ;
default :
/*
* The rest of the feature handles the same way as the
* connected feature handling .
*/
break ;
}
/*
* Unhandled features are handled by the normal connected feature
*/
return ( fsmdef_ev_connected_feature ( event ) ) ;
}
/**
*
* Function to handles connected media update pending state feature ack
* events .
*
* @ param sm_event_t event
*
* @ return SM_RC_END or SM_RC_CLEANUP
*
* @ pre ( fcb - > dcb not_eq NULL )
* @ pre ( event - > data not_eq NULL )
* @ pre ( event - > msg not_eq NULL )
*/
static sm_rcs_t
fsmdef_ev_connected_media_pend_feature_ack ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_connected_media_pend_feature_ack " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_ack_t * msg = ( cc_feature_ack_t * ) event - > msg ;
cc_features_t ftr_id = msg - > feature_id ;
cc_srcs_t src_id = msg - > src_id ;
cc_feature_data_t feature_data ;
sm_rcs_t sm_rc = SM_RC_END ;
cc_msgbody_info_t * msg_body ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case CC_SRC_SIP :
switch ( ftr_id ) {
case CC_FEATURE_MEDIA :
/* Media update feature ack from SIP */
if ( msg - > cause = = CC_CAUSE_REQUEST_PENDING ) {
/*
* The glare condition occurs from the previously sent
* media update . Starts a request pending timer so that
* we retry .
*/
fsmdef_set_req_pending_timer ( dcb ) ;
if ( FSM_CHK_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ) {
/*
* Feature hold is pending , abort the media capability
* update and retry with hold instead .
*/
FSM_RESET_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLD_PENDING ) ;
}
return ( SM_RC_END ) ;
}
/* Check for error code reported */
if ( ( msg - > cause ! = CC_CAUSE_NORMAL ) & &
( msg - > cause ! = CC_CAUSE_OK ) ) {
/* Unable to send media request */
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG2 ) ,
dcb - > call_id , dcb - > line , fname ,
" Media request failed, cause= " , msg - > cause ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
msg_body = & msg - > data . resume . msg_body ;
cause = gsmsdp_negotiate_answer_sdp ( fcb , msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/*
* Check to see if we have a feature request pending
*/
if ( FSM_CHK_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ) {
/* There is a hold feature pending, send out hold instead */
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
dcb - > hold_reason ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
FSM_RESET_FLAGS ( dcb - > flags , FSMDEF_F_HOLD_REQ_PENDING ) ;
sm_rc = fsm_hold_local ( fcb , & feature_data , FALSE ) ;
} else {
/*
* If spoof ringout is not being requested and we are
* currently playing spoof ringout , transition the LSM from
* the far end alerting to the connected state .
*/
if ( ( ! dcb - > spoof_ringout_requested ) & &
( dcb - > spoof_ringout_applied ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
} else {
( void ) cc_call_action ( dcb - > call_id , dcb - > line ,
CC_ACTION_MEDIA , NULL ) ;
}
/*
* Check any media capability changes that might occurs
* while we were in the middle of the previous transaction .
*/
sm_rc = fsmdef_transition_to_connected ( fcb ) ;
if ( g_dock_undock_event ! = MEDIA_INTERFACE_UPDATE_NOT_REQUIRED ) {
if ( is_gsmsdp_media_ip_updated_to_latest ( dcb ) = = TRUE ) {
ui_update_media_interface_change ( dcb - > line , dcb - > call_id , MEDIA_INTERFACE_UPDATE_SUCCESSFUL ) ;
} else {
DEF_DEBUG ( " We must have received another MEDIA_INTERFACE_UPDATE events "
" while current MEDIA_INTERFACE_UPDATE event is in procoess. Sending re-invite again " ) ;
escalateDeescalate ( ) ;
}
}
}
return ( sm_rc ) ;
default :
break ;
}
break ;
default :
break ;
}
/* call default feature ack handler to take common/default actions*/
( void ) fsmdef_ev_default_feature_ack ( event ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_offhook ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_action_data_t data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* User has gone offhook while using the speaker .
*/
data . speaker . on = FALSE ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_SPEAKER , & data ) ;
//lsm_set_active_call_id(dcb->call_id);
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_connected_line ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
/*
* Handle media capability changes if there is before transition to
* connected state .
*/
return ( fsmdef_transition_to_connected ( fcb ) ) ;
}
static sm_rcs_t
fsmdef_ev_onhook ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
sm_rcs_t sm_rc ;
cc_action_data_t data ;
int sdpmode = 0 ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/* currently this flag is only set by conference case. It signals
* that onhook has been received , do not process it anymore .
*/
if ( dcb - > onhook_received ) {
dcb - > onhook_received = FALSE ;
return SM_RC_END ;
}
config_get_value ( CFGID_SDPMODE , & sdpmode , sizeof ( sdpmode ) ) ;
if ( sdpmode ) {
if ( dcb - > ice_ufrag )
cpr_free ( dcb - > ice_ufrag ) ;
if ( dcb - > ice_pwd )
cpr_free ( dcb - > ice_pwd ) ;
}
/*
* If the user presses the ENDCALL softkey for an
* incoming call set the release cause to Busy .
*/
if ( fcb - > state = = FSMDEF_S_INCOMING_ALERTING ) {
sm_rc = fsmdef_release ( fcb , CC_CAUSE_BUSY , dcb - > send_release ) ;
} else {
dcb - > early_error_release = FALSE ;
sm_rc = fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ;
}
if ( sm_rc = = SM_RC_CLEANUP ) {
/* This dcb has been cleaned up, do nothing more */
return ( sm_rc ) ;
} else if ( fcb - > state = = FSMDEF_S_HOLDING | |
fcb - > state = = FSMDEF_S_HOLD_PENDING ) {
data . ringer . on = TRUE ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_RINGER , & data ) ;
sm_rc = SM_RC_END ;
} else {
sm_rc = SM_RC_END ;
}
return ( sm_rc ) ;
}
static sm_rcs_t
fsmdef_ev_release ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_release_t * msg = ( cc_release_t * ) event - > msg ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
dcb - > send_release = FALSE ;
FSM_SET_FLAGS ( dcb - > msgs_rcvd , FSMDEF_MSG_RELEASE ) ;
if ( msg - > cause = = CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE ) {
fsmdef_set_call_info_cc_call_state ( dcb , CC_STATE_CALL_FAILED , CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE ) ;
/* what to return for return code */
return ( SM_RC_SUCCESS ) ;
} else {
return ( fsmdef_release ( fcb , msg - > cause , dcb - > send_release ) ) ;
}
}
static sm_rcs_t
fsmdef_ev_releasing_release ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_release_t * msg = ( cc_release_t * ) event - > msg ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/* see if the SIP stack has aborted this call early for some reason
* If SIP brought this down , we are still offhook on the UI . We
* need to ignore it , so that reorder can be played AND when the user
* hangs up , then the UI will be driven to a clean state .
*/
if ( fcb - > dcb - > early_error_release = = FALSE ) {
cc_int_release_complete ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
msg - > cause , NULL ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_IDLE ) ;
fsmdef_free_dcb ( dcb ) ;
FSM_SET_FLAGS ( dcb - > msgs_rcvd , FSMDEF_MSG_RELEASE ) ;
fsm_release ( fcb , __LINE__ , msg - > cause ) ;
return ( SM_RC_CLEANUP ) ;
} else {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SM_DEFAULT_EVENT ) ) ;
return ( SM_RC_END ) ;
}
}
static sm_rcs_t
fsmdef_ev_releasing_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_causes_t cause ;
sm_rcs_t sm_rc = SM_RC_END ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( ftr_id ) {
case CC_FEATURE_END_CALL :
cause = fsmdef_get_cause ( msg - > data_valid , & ( msg - > data ) ) ;
/* Clean up call chain, no release sent */
return ( fsmdef_release ( fcb , cause , FALSE ) ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
return ( sm_rc ) ;
}
static sm_rcs_t
fsmdef_ev_releasing_onhook ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/* Clean up call chain, no release sent */
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , FALSE ) ) ;
}
static sm_rcs_t
fsmdef_ev_release_complete ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( fcb - > dcb = = NULL ) {
return ( SM_RC_CLEANUP ) ;
}
/* see if the SIP stack has aborted this call early for some reason
* If SIP brought this down , we are still offhook on the UI . We
* need to ignore it , so that reorder can be played AND when the user
* hangs up , then the UI will be driven to a clean state .
*/
if ( fcb - > dcb - > early_error_release = = FALSE ) {
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_IDLE ) ;
fsmdef_free_dcb ( fcb - > dcb ) ;
fsm_release ( fcb , __LINE__ ,
( ( cc_release_complete_t * ) ( event - > msg ) ) - > cause ) ;
return ( SM_RC_CLEANUP ) ;
} else {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SM_DEFAULT_EVENT ) ) ;
return ( SM_RC_END ) ;
}
}
static sm_rcs_t
fsmdef_ev_hold_pending_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
fsmcnf_ccb_t * ccb = NULL ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
cc_feature_data_t * data = & ( msg - > data ) ;
cc_feature_data_t feature_data ;
sm_rcs_t sm_rc ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case ( CC_SRC_UI ) :
case ( CC_SRC_GSM ) :
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
break ;
case CC_FEATURE_RESUME :
/*
* We will not be able to resume this call since we are in the
* hold pending state but we can place any other active call
* on hold . Find the connected call ( if there is one ) and place
* it on hold but not call if it is involved in a conference .
*/
if ( msg - > data . resume . cause ! = CC_CAUSE_CONF ) {
if ( fsmdef_wait_to_start_new_call ( TRUE , src_id , call_id , line ,
CC_FEATURE_RESUME , NULL ) ) {
ccb = fsmcnf_get_ccb_by_call_id ( call_id ) ;
if ( ccb ! = NULL ) {
ccb - > cnf_ftr_ack = FALSE ;
}
}
}
return ( SM_RC_END ) ;
case CC_FEATURE_REQ_PEND_TIMER_EXP :
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
dcb - > hold_reason ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
sm_rc = fsm_hold_local ( fcb , & feature_data , TRUE ) ;
return sm_rc ;
case CC_FEATURE_END_CALL :
sm_rc = fsmdef_release_call ( fcb , msg ) ;
return ( sm_rc ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) */
break ;
case ( CC_SRC_SIP ) :
switch ( ftr_id ) {
case CC_FEATURE_MEDIA :
return ( fsmdef_remote_media ( fcb , msg ) ) ;
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
case CC_FEATURE_CALL_PRESERVATION :
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ) ;
case CC_FEATURE_NOTIFY :
fsmdef_ev_notify_feature ( msg , dcb ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) */
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
} /* switch (src_id) */
return ( SM_RC_END ) ;
}
/**
* feature ack event handler in hold pending state .
*
* @ param [ in ] event Pointer to sm_event_t structure for feature ack event .
*
* @ return Value of type sm_rcs_t to state machine
*
* @ pre ( event not_eqs NULL ) and
* ( event - > data not_eqs NULL ) and
* ( ( fsm_fcb_t * ) ( event - > data ) - > dcb not_eqs NULL )
*/
static sm_rcs_t
fsmdef_ev_hold_pending_feature_ack ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_ack_t * msg = ( cc_feature_ack_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_causes_t cause ;
cc_msgbody_info_t * msg_body ;
cc_feature_data_t feature_data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case ( CC_SRC_SIP ) :
switch ( ftr_id ) {
case CC_FEATURE_RESUME :
/*
* This is feature ack for resume . We received resume
* feature ack because the hold request was received while
* we are waiting to resume i . e . was in the
* resume pending state and resume request has been sent out .
*
* If the resume ack indicates glare , then ignore sending the
* resume and transition to holding ( we were in hold and
* unable to send RESUME ) . Otherwise send hold out right away
* if there is no other error .
*/
fsm_sm_ftr ( ftr_id , src_id ) ;
if ( msg - > cause = = CC_CAUSE_REQUEST_PENDING ) {
/*
* The glare condition occurs from the previously sent
* resume transition to holding .
*/
( void ) fsm_hold_local_only ( fcb ) ;
break ;
}
/* call default feature ack handler to take common/default actions*/
( void ) fsmdef_ev_default_feature_ack ( event ) ;
if ( ( msg - > cause ! = CC_CAUSE_NORMAL ) & &
( msg - > cause ! = CC_CAUSE_OK ) ) {
cc_call_state ( dcb - > call_id , dcb - > line ,
CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
if ( msg - > data_valid ! = TRUE ) {
cc_call_state ( dcb - > call_id , dcb - > line ,
CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
msg_body = & msg - > data . resume . msg_body ;
cause = gsmsdp_negotiate_answer_sdp ( fcb , msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/*
* HOLD can be sent now .
*/
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
dcb - > hold_reason ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
fsm_hold_local ( fcb , & feature_data , FALSE ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_holding_release ( sm_event_t * event )
{
cc_release_t * msg = ( cc_release_t * ) event - > msg ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( msg - > cause ! = CC_CAUSE_XFER_LOCAL ) {
fcb - > dcb - > send_release = FALSE ;
}
FSM_SET_FLAGS ( dcb - > msgs_rcvd , FSMDEF_MSG_RELEASE ) ;
return ( fsmdef_release ( fcb , msg - > cause , fcb - > dcb - > send_release ) ) ;
}
static sm_rcs_t
fsmdef_ev_holding_onhook ( sm_event_t * event )
{
cc_onhook_t * msg = ( cc_onhook_t * ) event - > msg ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( ! ( msg - > softkey ) ) {
/* Meaning Hangup, ignore, a held call can't be hung up */
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SM_DEFAULT_EVENT ) ) ;
return ( SM_RC_END ) ;
}
/*
* Meaning EndCall softkey is sent , take down
* the call , this happens during failover .
*/
FSM_SET_FLAGS ( dcb - > msgs_rcvd , FSMDEF_MSG_RELEASE ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ) ;
}
/**
*
* fsmdef_reversion_timeout - Triggers LSM for doing Reversion alerts .
*
* @ param fsmdef_dcb_t dcb for this call
*
* @ return none
*
* @ pre ( dcb not_eq NULL )
*/
void fsmdef_reversion_timeout ( callid_t call_id )
{
int ret = CPR_SUCCESS ;
fsmdef_dcb_t * dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( ( dcb = = NULL ) | | ( dcb - > fcb = = NULL ) ) {
return ;
}
// check that we are in HOLDING state before proceeding
if ( ( dcb - > fcb - > state ! = FSMDEF_S_HOLDING ) & &
( dcb - > fcb - > state ! = FSMDEF_S_HOLD_PENDING ) ) {
return ;
}
if ( dcb - > reversionInterval > 0 ) {
ret = cprStartTimer ( dcb - > revertTimer , dcb - > reversionInterval * 1000 , ( void * ) ( long ) call_id ) ;
}
if ( ret = = CPR_FAILURE ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_START_FAILED ) ,
dcb - > call_id , dcb - > line , " " , " Reversion " , cpr_errno ) ;
return ;
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_HOLD_REVERT , NULL ) ;
}
/**
*
* fsmdef_resume - Performs Resume Operation .
*
* @ param sm_event_t event
*
* @ return sm_rcs_t SM_RC_END - indicating the event has been consumed
*
* @ pre ( event not_eq NULL )
*/
static void
fsmdef_resume ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_resume " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
fsmcnf_ccb_t * ccb = NULL ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_feature_data_t * data = & ( msg - > data ) ;
cc_srcs_t src_id = msg - > src_id ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
cc_feature_data_t feature_data ;
cc_causes_t cause ;
boolean req_pending_tmr_running = FALSE ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* Ignore the request if local hold is not active .
*/
if ( fsmdef_num_media_in_local_hold ( dcb ) = = 0 ) {
/*
* No media in local held , should not happen here .
*/
cc_int_feature_ack ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_RESUME , NULL ,
CC_CAUSE_NORMAL ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , call_id , dcb - > line ,
fname , " resume media not in hold state \n " ) ;
return ;
}
( void ) cprCancelTimer ( dcb - > revertTimer ) ;
dcb - > reversionInterval = - 1 ;
/*
* Make sure the connected call ( if there is one ) goes on hold ,
* but do not hold the connected call if it is involved in a
* conference .
*/
if ( msg - > data . resume . cause ! = CC_CAUSE_CONF ) {
if ( fsmdef_wait_to_start_new_call ( TRUE , src_id , call_id , line ,
CC_FEATURE_RESUME , ( msg - > data_valid ?
data : NULL ) ) ) {
ccb = fsmcnf_get_ccb_by_call_id ( call_id ) ;
if ( ccb ! = NULL ) {
ccb - > cnf_ftr_ack = FALSE ;
}
return ;
}
}
/* Clear all media holding status */
fsmdef_update_media_hold_status ( dcb , NULL , FALSE ) ;
if ( dcb - > req_pending_tmr & & cprIsTimerRunning ( dcb - > req_pending_tmr ) ) {
req_pending_tmr_running = TRUE ;
}
if ( ! req_pending_tmr_running ) {
/*
* Reinitialize the local sdp to include all available codecs .
* We do this because it is possible that our local list
* may have been shortened to the one negotiated codec . This is
* the case when we receive an incoming call , we negotiate a
* single codec , copy it into the local sdp and send it back
* in the connected msg .
*/
( void ) gsmsdp_update_local_sdp_media_capability ( dcb , TRUE , FALSE ) ;
if ( msg - > data_valid ) {
feature_data . resume . call_info = data - > resume . call_info ;
} else {
feature_data . resume . call_info . type = CC_FEAT_RESUME ;
feature_data . resume . call_info . data . hold_resume_reason =
CC_REASON_NONE ;
feature_data . resume . msg_body . num_parts = 0 ;
feature_data . resume . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . resume . call_info . data . call_info_feat_data . protect = FALSE ;
}
/* Encode SDP */
cause = gsmsdp_encode_sdp_and_update_version ( dcb ,
& feature_data . resume . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
( void ) fsmdef_release ( fcb , cause , dcb - > send_release ) ;
return ;
}
}
/*
* If spoof ringout is currently requested , transition to the
* far end alerting state instead of the connected state .
*/
if ( dcb - > spoof_ringout_requested ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , fname ,
" setting spoof_ringout_applied " ) ;
dcb - > spoof_ringout_applied = TRUE ;
cc_call_state ( dcb - > call_id , dcb - > line ,
CC_STATE_FAR_END_ALERTING , FSMDEF_CC_CALLER_ID ) ;
} else {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
/* Start receiving but not transmit, before sending resume */
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_START_RCV ,
NULL ) ;
}
if ( ! req_pending_tmr_running ) {
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
CC_FEATURE_RESUME , & feature_data ) ;
}
/*
* We lock the UI until we learn the result of the resume request
*/
fim_lock_ui ( call_id ) ;
/* Wait for feature ack */
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_RESUME_PENDING ) ;
return ;
}
/**
*
* fsmdef_ev_holding_offhook - Handles offhook in for holding state .
*
* @ param sm_event_t event
*
* @ return sm_rcs_t SM_RC_END - indicating the event has been consumed
*
* @ pre ( event not_eq NULL )
*/
static sm_rcs_t
fsmdef_ev_holding_offhook ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( cprIsTimerRunning ( dcb - > revertTimer ) ) {
// Off hook resume calls only if HR is active else ignore this event
fsmdef_resume ( event ) ;
}
return SM_RC_END ;
}
static sm_rcs_t
fsmdef_ev_holding_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_feature_data_t * data = & ( msg - > data ) ;
cc_feature_data_t feature_data ;
sm_rcs_t sm_rc ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case ( CC_SRC_UI ) :
case ( CC_SRC_GSM ) :
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
break ;
case CC_FEATURE_HOLD :
if ( msg - > data_valid ) {
sm_rc = fsm_hold_local ( fcb , data , FALSE ) ;
} else {
feature_data . hold . call_info . type = CC_FEAT_HOLD ;
feature_data . hold . call_info . data . hold_resume_reason =
CC_REASON_NONE ;
feature_data . hold . msg_body . num_parts = 0 ;
feature_data . hold . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . hold . call_info . data . call_info_feat_data . protect = FALSE ;
sm_rc = fsm_hold_local ( fcb , & feature_data , FALSE ) ;
}
fsmdef_handle_join_pending ( dcb ) ;
return ( sm_rc ) ;
case CC_FEATURE_HOLD_REVERSION :
// Stop the timer for alert interval
( void ) cprCancelTimer ( dcb - > revertTimer ) ;
dcb - > reversionInterval = - 1 ;
// Do not revert if alertInterval is negative
if ( data - > hold_reversion . alertInterval < 0 )
return SM_RC_END ;
// interval timer of 0 implies continue to revert
// Clamp the interval to be in MIN/MAX_HOLD_REVERSION_INTERVAL_TIMER
if ( data - > hold_reversion . alertInterval > 0 & &
data - > hold_reversion . alertInterval < MIN_HOLD_REVERSION_INTERVAL_TIMER )
data - > hold_reversion . alertInterval = MIN_HOLD_REVERSION_INTERVAL_TIMER ;
if ( data - > hold_reversion . alertInterval > MAX_HOLD_REVERSION_INTERVAL_TIMER )
data - > hold_reversion . alertInterval = MAX_HOLD_REVERSION_INTERVAL_TIMER ;
dcb - > reversionInterval = data - > hold_reversion . alertInterval ;
fsmdef_reversion_timeout ( fcb - > dcb - > call_id ) ;
fsmdef_handle_join_pending ( dcb ) ;
return SM_RC_END ;
case CC_FEATURE_RESUME :
fsmdef_resume ( event ) ;
break ;
case CC_FEATURE_END_CALL :
sm_rc = fsmdef_release_call ( fcb , msg ) ;
( void ) cprCancelTimer ( dcb - > revertTimer ) ;
dcb - > reversionInterval = - 1 ;
fsmdef_handle_join_pending ( dcb ) ;
return ( sm_rc ) ;
case CC_FEATURE_SELECT :
if ( msg - > data_valid = = FALSE ) {
fsmdef_select_invoke ( dcb , NULL ) ;
} else {
fsmdef_select_invoke ( dcb , data ) ;
}
return ( SM_RC_END ) ;
case CC_FEATURE_B2B_JOIN :
if ( msg - > data_valid = = FALSE ) {
fsmdef_b2bjoin_invoke ( dcb , NULL ) ;
} else {
fsmdef_b2bjoin_invoke ( dcb , data ) ;
}
return ( SM_RC_END ) ;
case CC_FEATURE_DIRTRXFR :
case CC_FEATURE_UNDEFINED :
fsm_display_feature_unavailable ( ) ;
fsmdef_handle_join_pending ( dcb ) ;
return ( SM_RC_END ) ;
case CC_FEATURE_REQ_PEND_TIMER_EXP :
/* Ignore the request pending timer when in holding state */
default :
fsmdef_handle_join_pending ( dcb ) ;
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) */
break ;
case ( CC_SRC_SIP ) :
switch ( ftr_id ) {
case CC_FEATURE_MEDIA :
return ( fsmdef_remote_media ( fcb , msg ) ) ;
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
case CC_FEATURE_CALL_PRESERVATION :
( void ) cprCancelTimer ( dcb - > revertTimer ) ;
dcb - > reversionInterval = - 1 ;
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ) ;
case CC_FEATURE_NOTIFY :
fsmdef_ev_notify_feature ( msg , dcb ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) */
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
} /* switch (src_id) */
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_holding_feature_ack ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_holding_feature_ack " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_ack_t * msg = ( cc_feature_ack_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_causes_t cause = msg - > cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
switch ( src_id ) {
case ( CC_SRC_SIP ) :
switch ( ftr_id ) {
case CC_FEATURE_HOLD :
if ( cause = = CC_CAUSE_REQUEST_PENDING ) {
/*
* If this is feature ack for hold and request is pending ,
* set a request pending timer so that we retry the hold
* feature request .
*/
fsmdef_set_req_pending_timer ( dcb ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLD_PENDING ) ;
return ( SM_RC_END ) ;
}
/* Check for error code reported */
if ( ( cause ! = CC_CAUSE_NORMAL ) & &
( cause ! = CC_CAUSE_OK ) ) {
/* Unable to send hold request */
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG2 ) ,
dcb - > call_id , dcb - > line , fname ,
" HOLD request failed, cause= " , cause ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
// update video_avail as we are not negotiating the answer below
dcb - > cur_video_avail = SDP_DIRECTION_INACTIVE ;
lsm_update_video_avail ( dcb - > line , dcb - > call_id , dcb - > cur_video_avail ) ;
break ;
default :
fsm_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
default :
fsm_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
/* call default feature ack handler to take common/default actions */
( void ) fsmdef_ev_default_feature_ack ( event ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_resume_pending_feature ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_resume_pending_feature " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
callid_t call_id = msg - > call_id ;
cc_feature_data_t * data = & ( msg - > data ) ;
cc_feature_data_t feature_data ;
sm_rcs_t sm_rc ;
cc_causes_t cause ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case ( CC_SRC_UI ) :
switch ( ftr_id ) {
case CC_FEATURE_UPD_SESSION_MEDIA_CAP :
dcb - > video_pref = data - > caps . support_direction ;
break ;
case CC_FEATURE_END_CALL :
fim_unlock_ui ( call_id ) ;
sm_rc = fsmdef_release_call ( fcb , msg ) ;
return ( sm_rc ) ;
case CC_FEATURE_HOLD :
/*
* The UI should be locked but the hold event from UI here
* can be the result of other call chain wants to put this
* other call that may be in conected state or in resume
* pending state on hold . One example , the user want to
* resume a call that is on hold , that call chain will look
* for any other call in connected state or call in resume
* pending ( about to be connected ) and puts this call on hold .
*
* There are 2 choices here . If we are in this state and has
* not sent a resume out to the network , then simply
* transition to holding state . If resume has already
* been sent and we are here waiting for resume pending ack ,
* then we can not send out hold immediately . In the later
* case , go to hold pending state and wait for resume
* feature ack to send hold out .
*
* In either case , UI can be unlocked since we are now
* about to hold again .
*/
fim_unlock_ui ( dcb - > call_id ) ;
if ( dcb - > req_pending_tmr & &
cprIsTimerRunning ( dcb - > req_pending_tmr ) ) {
/*
* Request timer is running , that means we are waiting
* to send resume or we already have sent one out
* but it resulted in glare condition and that we are waiting
* to resent it again . In this , just go back to hold state .
*/
( void ) cprCancelTimer ( dcb - > req_pending_tmr ) ;
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , fname ,
" Received Hold while waiting to send resume \n " ) ;
/* Go back to holding without sending any thing out */
( void ) fsm_hold_local_only ( fcb ) ;
} else {
/*
* We have sent resume to the network and wait for
* for the feature ack . The glare condition can
* occur but we can only assume that resume was sent out
* at this point . We can not send out any more request
* until the result is known .
*/
if ( msg - > data_valid ) {
dcb - > hold_reason =
data - > hold . call_info . data . hold_resume_reason ;
} else {
dcb - > hold_reason = CC_REASON_NONE ;
}
// since we are going to hold stop the media now
// else the next new call or resume will result in 2 sets of media ports open
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_STOP_MEDIA ,
NULL ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_HOLD_PENDING ) ;
}
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
case ( CC_SRC_GSM ) :
switch ( ftr_id ) {
case CC_FEATURE_HOLD :
sm_rc = fsm_hold_local_only ( fcb ) ;
fim_unlock_ui ( call_id ) ;
return ( sm_rc ) ;
case CC_FEATURE_END_CALL :
fim_unlock_ui ( call_id ) ;
sm_rc = fsmdef_release_call ( fcb , msg ) ;
return ( sm_rc ) ;
case CC_FEATURE_REQ_PEND_TIMER_EXP :
/*
* Reinitialize the local sdp to include all available codecs .
* We do this because it is possible that our local list
* may have been shortened to the one negotiated codec . This is
* the case when we receive an incoming call , we negotiate a
* single codec , copy it into the local sdp and send it back
* in the connected msg .
*/
( void ) gsmsdp_update_local_sdp_media_capability ( dcb , TRUE , FALSE ) ;
feature_data . resume . call_info . type = CC_FEAT_RESUME ;
feature_data . resume . call_info . data . hold_resume_reason =
CC_REASON_NONE ;
feature_data . resume . msg_body . num_parts = 0 ;
feature_data . resume . call_info . data . call_info_feat_data . swap = FALSE ;
feature_data . resume . call_info . data . call_info_feat_data . protect = FALSE ;
/* Encode SDP */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & feature_data . resume . msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/*
* We lock the UI until we learn the result of the resume request .
*/
fim_lock_ui ( call_id ) ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
CC_FEATURE_RESUME , & feature_data ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) */
break ;
case ( CC_SRC_SIP ) :
switch ( ftr_id ) {
case CC_FEATURE_MEDIA :
return ( fsmdef_remote_media ( fcb , msg ) ) ;
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
case CC_FEATURE_CALL_PRESERVATION :
fim_unlock_ui ( call_id ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_NORMAL , dcb - > send_release ) ) ;
case CC_FEATURE_NOTIFY :
fsmdef_ev_notify_feature ( msg , dcb ) ;
break ;
case CC_FEATURE_UPDATE :
/*
* We only get an UPDATE feature event if we receive a medialess UPDATE .
* This type of event only conveys UI updates that are processed with
* a call info event . We do perform one check to see if we are currently
* spoofing ringout . If we are and the spoof ringout requested flag
* has been cleared , we tell the LSM to go connected which halts the
* spoofed ringout .
*/
if ( ( ! dcb - > spoof_ringout_requested ) & & ( dcb - > spoof_ringout_applied ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_CLR_SPOOF_APPLD ) ,
dcb - > call_id , dcb - > line , fname ) ;
dcb - > spoof_ringout_applied = FALSE ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
}
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (ftr_id) */
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
} /* switch (src_id) */
return ( SM_RC_END ) ;
}
/**
* feature ack event handler in resume pending state .
*
* @ param [ in ] event Pointer to sm_event_t structure for feature ack event .
*
* @ return Value of type sm_rcs_t to state machine
*
* @ pre ( event not_eqs NULL ) and
* ( event - > data not_eqs NULL ) and
* ( ( fsm_fcb_t * ) ( event - > data ) - > dcb not_eqs NULL )
*/
static sm_rcs_t
fsmdef_ev_resume_pending_feature_ack ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_ev_resume_pending_feature_ack " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_ack_t * msg = ( cc_feature_ack_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
cc_causes_t cause ;
cc_msgbody_info_t * msg_body ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case ( CC_SRC_SIP ) :
switch ( ftr_id ) {
case CC_FEATURE_HOLD :
/*
* This can occur because SIP stack has not sent HOLD out yet
* but the user has pressed resume since we already moved
* to HOLD state as soon as the user pressed HOLD . Ignore the
* HOLD feature ACK except if it indicates error . If we get
* REQUEST_PENDING , we ' ll just move to connected state .
*/
if ( msg - > cause = = CC_CAUSE_REQUEST_PENDING ) {
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CONNECTED ) ;
return ( SM_RC_END ) ;
}
if ( ( msg - > cause ! = CC_CAUSE_NORMAL ) & &
( msg - > cause ! = CC_CAUSE_OK ) ) {
cc_call_state ( dcb - > call_id , dcb - > line ,
CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
case CC_FEATURE_RESUME :
/*
* If this is feature ack for resume and request is pending ,
* set a request pending timer so that we retry the resume
* feature request . Otherwise , unlock the UI and continue
* processing .
*/
fsm_sm_ftr ( ftr_id , src_id ) ;
if ( msg - > cause = = CC_CAUSE_REQUEST_PENDING ) {
fsmdef_set_req_pending_timer ( dcb ) ;
return ( SM_RC_END ) ;
} else {
fim_unlock_ui ( dcb - > call_id ) ;
}
/* call default feature ack handler to take common/default actions*/
( void ) fsmdef_ev_default_feature_ack ( event ) ;
if ( ( msg - > cause = = CC_CAUSE_SERV_ERR_UNAVAIL ) & &
( dcb - > hold_reason = = CC_REASON_MONITOR_UPDATE ) ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) ,
dcb - > call_id , dcb - > line , fname ,
" msg->cause == CC_CAUSE_SERV_ERR_UNAVAIL, unable to monitor update \n " ) ;
return ( fsmdef_transition_to_connected ( fcb ) ) ;
}
if ( ( msg - > cause ! = CC_CAUSE_NORMAL ) & &
( msg - > cause ! = CC_CAUSE_OK ) ) {
cc_call_state ( dcb - > call_id , dcb - > line ,
CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
if ( msg - > data_valid ! = TRUE ) {
cc_call_state ( dcb - > call_id , dcb - > line ,
CC_STATE_UNKNOWN , NULL ) ;
return ( fsmdef_release ( fcb , CC_CAUSE_ERROR , dcb - > send_release ) ) ;
}
msg_body = & msg - > data . resume . msg_body ;
cause = gsmsdp_negotiate_answer_sdp ( fcb , msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
if ( ! dcb - > spoof_ringout_applied ) {
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
FSMDEF_CC_CALLER_ID ) ;
}
/*
* Handle media capability changes if there is before transition
* to connected state to catch any changes during resume
* transaction .
*/
return ( fsmdef_transition_to_connected ( fcb ) ) ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
}
/* call default feature ack handler to take common/default actions */
( void ) fsmdef_ev_default_feature_ack ( event ) ;
return ( SM_RC_END ) ;
}
static sm_rcs_t
fsmdef_ev_preserved_feature ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_srcs_t src_id = msg - > src_id ;
cc_features_t ftr_id = msg - > feature_id ;
sm_rcs_t sm_rc ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fsm_sm_ftr ( ftr_id , src_id ) ;
switch ( src_id ) {
case CC_SRC_UI :
case CC_SRC_GSM :
switch ( msg - > feature_id ) {
case CC_FEATURE_END_CALL :
sm_rc = fsmdef_release_call ( fcb , msg ) ;
return ( sm_rc ) ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
}
break ;
case CC_SRC_SIP :
switch ( msg - > feature_id ) {
case CC_FEATURE_HOLD :
case CC_FEATURE_RESUME :
sm_rc = fsmdef_release_call ( fcb , msg ) ;
return ( sm_rc ) ;
case CC_FEATURE_MEDIA :
sm_rc = fsmdef_remote_media ( fcb , msg ) ;
return ( sm_rc ) ;
case CC_FEATURE_CALLINFO :
fsmdef_update_callinfo ( fcb , msg ) ;
break ;
default :
fsmdef_sm_ignore_ftr ( fcb , __LINE__ , ftr_id ) ;
break ;
} /* switch (msg->feature_id) */
break ;
default :
fsmdef_sm_ignore_src ( fcb , __LINE__ , src_id ) ;
break ;
} /* switch (src_id) */
return ( SM_RC_END ) ;
}
cc_int32_t
fsmdef_show_cmd ( cc_int32_t argc , const char * argv [ ] )
{
fsmdef_dcb_t * dcb ;
fsm_fcb_t * fcb ;
int i = 0 ;
callid_t call_id ;
unsigned long strtoul_result ;
char * strtoul_end ;
2012-12-18 11:01:51 -05:00
PR_ASSERT ( i = = 0 ) ;
2012-12-17 20:14:30 -05:00
/*
* Check if need help .
*/
if ( ( argc = = 2 ) & & ( argv [ 1 ] [ 0 ] = = ' ? ' ) ) {
2012-12-18 11:01:51 -05:00
debugif_printf ( " %s " , " show fsmdef [all|rel] \n " ) ;
2012-12-17 20:14:30 -05:00
} else if ( ( argc = = 1 ) | | ( strcmp ( argv [ 1 ] , " all " ) = = 0 ) ) {
2012-12-18 11:01:51 -05:00
debugif_printf ( " %s " , " \n -------- FSMDEF dcbs -------- " ) ;
debugif_printf ( " %s " , " \n i call_id dcb line " ) ;
debugif_printf ( " %s " , " \n ----------------------------- \n " ) ;
2012-12-17 20:14:30 -05:00
/*
* Print info for all dcbs .
*/
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
debugif_printf ( " %-2d %-7d 0x%8p %-4d \n " ,
i + + , dcb - > call_id , dcb , dcb - > line ) ;
}
} else if ( strcmp ( argv [ 1 ] , " rel " ) = = 0 ) {
errno = 0 ;
strtoul_result = strtoul ( argv [ 2 ] , & strtoul_end , 10 ) ;
if ( errno | | argv [ 2 ] = = strtoul_end | | strtoul_result > USHRT_MAX ) {
debugif_printf ( " %s parse error of call_id %s " , __FUNCTION__ , argv [ 2 ] ) ;
return 0 ;
}
call_id = ( callid_t ) strtoul_result ;
debugif_printf ( " \n DEF %-4d/%d: releasing \n " , call_id , 0 ) ;
fcb = fsm_get_fcb_by_call_id_and_type ( call_id , FSM_TYPE_DEF ) ;
if ( fcb = = NULL ) {
return ( 0 ) ;
}
( void ) fsmdef_release ( fcb , CC_CAUSE_NORMAL , fcb - > dcb - > send_release ) ;
}
return ( 0 ) ;
}
/**
*
* This function is called to determine if the phone
* is in a state where autoAnswer is supported . Even
* if the feature is enabled on the line being called ,
* the phone may be in a state that does not allow it .
*
* @ param autoAnswerAlt to indicate what states auto answer enabled .
* @ param myCallId call_id
*
* @ return TRUE or FALSE
*
*/
static int
fsmdef_check_auto_answer_allowed ( int autoAnswerAlt , callid_t myCallId )
{
fsmdef_dcb_t * dcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > call_id ! = myCallId & & dcb - > fcb ! = NULL ) {
/*
* autoAnswer is disabled if there is an incoming or an
* outgoing call that has not reached the connected state
* regardless of the value of autoAnswerAlt .
*/
if ( ( dcb - > fcb - > state = = FSMDEF_S_COLLECT_INFO ) | |
( dcb - > fcb - > state = = FSMDEF_S_CALL_SENT ) | |
( dcb - > fcb - > state = = FSMDEF_S_OUTGOING_PROCEEDING ) | |
( dcb - > fcb - > state = = FSMDEF_S_KPML_COLLECT_INFO ) | |
( dcb - > fcb - > state = = FSMDEF_S_CONNECTING ) | |
( dcb - > fcb - > state = = FSMDEF_S_JOINING ) ) {
return ( FALSE ) ;
}
/*
* If autoAnswerAlt is 1 , then autoAnswer is also
* disabled if there is a connected call or a call
* on hold .
*/
if ( autoAnswerAlt = = 1 ) {
if ( ( dcb - > fcb - > state = = FSMDEF_S_CONNECTED ) | |
( dcb - > fcb - > state = = FSMDEF_S_PRESERVED ) | |
( dcb - > fcb - > state = = FSMDEF_S_RESUME_PENDING ) | |
( dcb - > fcb - > state = = FSMDEF_S_CONNECTED_MEDIA_PEND ) | |
( dcb - > fcb - > state = = FSMDEF_S_HOLDING ) | |
( dcb - > fcb - > state = = FSMDEF_S_OUTGOING_ALERTING ) | |
( dcb - > fcb - > state = = FSMDEF_S_INCOMING_ALERTING ) | |
( dcb - > fcb - > state = = FSMDEF_S_HOLD_PENDING ) ) {
return ( FALSE ) ;
}
} else if ( autoAnswerAlt = = 0 ) {
if ( ( dcb - > fcb - > state = = FSMDEF_S_CONNECTED ) | |
( dcb - > fcb - > state = = FSMDEF_S_PRESERVED ) | |
( dcb - > fcb - > state = = FSMDEF_S_CONNECTED_MEDIA_PEND ) | |
( dcb - > fcb - > state = = FSMDEF_S_OUTGOING_ALERTING ) ) {
return ( FALSE ) ;
}
}
}
}
return ( TRUE ) ;
}
/**
*
* This function is called when a call is received on a
* line that has auto answer enabled and the autoAnswer
* timer has expired .
*
* @ param data pointer to opaque data
*
* @ return none
*
* @ pre ( fcb and fcb - > dcb not_eq NULL )
* @ pre ( data should be fcb data )
*/
void
fsmdef_auto_answer_timeout ( void * data )
{
static const char fname [ ] = " fsmdef_auto_answer_timeout " ;
int autoAnswerAlternate = 0 ;
int autoAnswerOverride = 0 ;
int headSetActive = 0 ;
int speakerEnabled = 1 ;
callid_t call_id ;
char autoAnswerMode [ MAX_LINE_AUTO_ANS_MODE_SIZE ] ;
fsmdef_dcb_t * dcb ;
call_id = ( callid_t ) ( long ) data ;
if ( call_id = = CC_NO_CALL_ID ) {
/* Invalid call id */
GSM_ERR_MSG ( get_debug_string ( FSMDEF_DBG1 ) , 0 , 0 , fname , " invalid data " ) ;
return ;
}
/* Retrieve dcb from call id */
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
/*
* The only way this should happen is for the
* call to be released without cancelling the
* autoAnswer timer .
*/
FSM_DEBUG_SM ( DEB_F_PREFIX " AutoAnswer timer expired but no dcb was found. \n " , DEB_F_PREFIX_ARGS ( FSM , fname ) ) ;
return ;
}
/*
* The device - based config parameter autoAnswerIdleAlternate
* determines what state the phone must be in for autoAnswer
* feature to be enabled .
*/
config_get_value ( CFGID_AUTOANSWER_IDLE_ALTERNATE , & autoAnswerAlternate ,
sizeof ( autoAnswerAlternate ) ) ;
if ( fsmdef_check_auto_answer_allowed ( autoAnswerAlternate , dcb - > call_id ) ) {
/*
* Is headset active ? No need to check if headset has been disabled
* on the phone because the headset will never be active if it has .
*/
headSetActive = platGetAudioDeviceStatus ( VCM_AUDIO_DEVICE_HEADSET ) ;
/*
* If function call fails , just assume headset is not active
* and drive on
*/
if ( headSetActive = = - 1 ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " platGetAudioDeviceStatus() for headset failed. \n " , DEB_F_PREFIX_ARGS ( FSM , fname ) ) ;
headSetActive = 0 ;
}
/*
* Determine where the audio should be sent
*/
config_get_line_string ( CFGID_LINE_AUTOANSWER_MODE , autoAnswerMode ,
dcb - > line , sizeof ( autoAnswerMode ) ) ;
/*
* Check to see if the speaker has been disabled
*/
config_get_value ( CFGID_SPEAKER_ENABLED , & speakerEnabled ,
sizeof ( speakerEnabled ) ) ;
/*
* autoAnswer using speaker
*/
if ( strcasestr ( autoAnswerMode , " speaker " ) ) {
/*
* Speaker has not been disabled , normal processing .
*/
if ( speakerEnabled ) {
/*
* Enable audio path to speaker if headset is not being used .
*/
if ( ! headSetActive ) {
platSetSpeakerMode ( TRUE ) ;
}
/* Send offhook event to GSM */
cc_int_feature ( CC_SRC_UI , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_ANSWER , NULL ) ;
} else {
/*
* Speaker is disabled , but autoAnswer is enabled and says to
* use the speaker . Check the device - based override
* parameter to see what action to take . If override is
* set just return and let normal call processing happen .
* If not , terminate the call . The best SIP response we
* could come up in this situation is to send a 480
* Temporarily Unavailable .
*/
config_get_value ( CFGID_AUTOANSWER_OVERRIDE , & autoAnswerOverride ,
sizeof ( autoAnswerOverride ) ) ;
if ( ! autoAnswerOverride ) {
fsmdef_end_call ( dcb , CC_TEMP_NOT_AVAILABLE ) ;
}
}
} else if ( strcasestr ( autoAnswerMode , " headset " ) ) {
/*
* autoAnswer using headset . If headset is not enabled just let
* the phone ring normally .
*/
if ( headSetActive ) {
/* Send offhook event to GSM */
cc_int_feature ( CC_SRC_UI , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_ANSWER , NULL ) ;
}
} else {
/*
* Unknown autoAnswer mode
*/
FSM_DEBUG_SM ( DEB_F_PREFIX " Unknown autoAnswer Mode: %s AutoAnswer is disabled. \n " ,
DEB_F_PREFIX_ARGS ( FSM , fname ) , autoAnswerMode ) ;
}
}
}
/*
* fsmdef_b2bjoin_invoke
*
* Description :
* This function implements the b2bjoin feature invocation .
*
* Parameters :
* fsmdef_dcb_t * dcb - dcb associated with this call
*
* Returns : None
*/
static void
fsmdef_b2bjoin_invoke ( fsmdef_dcb_t * dcb , cc_feature_data_t * join_data )
{
cc_feature_data_t feature_data ;
int join_across_lines ;
cc_uint32_t major_ver ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
// Disable Join if the CUCM doesn't support it
platGetSISProtocolVer ( & major_ver , NULL , NULL , NULL ) ;
if ( major_ver < SIS_PROTOCOL_MAJOR_VERSION_UNISON ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG1 ) , dcb - > call_id , dcb - > line ,
" fsmdef_b2bjoin_invoke " , " Major sis is small than SIS_PROTOCOL_MAJOR_VERSION_UNISON, so, B2BJOIN is disabled " ) ;
fsm_display_feature_unavailable ( ) ;
fsmdef_sm_ignore_ftr ( dcb - > fcb , __LINE__ , CC_FEATURE_B2B_JOIN ) ;
return ;
}
config_get_value ( CFGID_JOIN_ACROSS_LINES ,
& join_across_lines , sizeof ( join_across_lines ) ) ;
/*
* Invoke B2BJoin feature towards SIP . It will send a REFER to CCM
*/
if ( join_data ) {
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , CC_FEATURE_B2B_JOIN , join_data ) ;
} else {
if ( ( g_b2bjoin_pending = = FALSE ) & & ( dcb - > fcb - > state = = FSMDEF_S_HOLDING )
& & ( ( fsmdef_get_connected_call ( ) ! = NULL ) | |
( fsmdef_get_alertingout_call ( ) ! = NULL ) ) ) {
/* Single Button Join case
* If Join is pressed on a held call while there is
* an active ( connected or alerting ) call , that completes the Join
*/
feature_data . b2bjoin . b2bjoin_callid = dcb - > call_id ;
feature_data . b2bjoin . b2bjoin_joincallid = dcb - > call_id ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , CC_FEATURE_B2B_JOIN , & feature_data ) ;
return ;
}
if ( ( g_numofselected_calls = = 0 ) | |
( ( g_b2bjoin_pending = = FALSE ) & & ( join_across_lines = = JOIN_ACROSS_LINES_DISABLED ) & &
( fsmdef_are_there_selected_calls_onotherline ( dcb - > line ) = = TRUE ) ) ) {
dcb - > active_feature = CC_FEATURE_B2B_JOIN ;
feature_data . select . select = TRUE ;
fsmdef_select_invoke ( dcb , & feature_data ) ;
fsm_display_use_line_or_join_to_complete ( ) ;
return ;
}
if ( g_b2bjoin_pending ) {
if ( join_across_lines = = JOIN_ACROSS_LINES_DISABLED ) {
if ( fsmdef_are_join_calls_on_same_line ( dcb - > line ) = = FALSE ) {
fsm_display_use_line_or_join_to_complete ( ) ;
g_b2bjoin_pending = FALSE ;
g_b2bjoin_callid = CC_NO_CALL_ID ;
return ;
}
}
if ( dcb - > call_id = = g_b2bjoin_callid ) {
/* If join is pending, pressing Join on the same call will cancel it */
g_b2bjoin_pending = FALSE ;
g_b2bjoin_callid = CC_NO_CALL_ID ;
/* Remove the check mark from it*/
cc_int_feature ( CC_SRC_UI , CC_SRC_GSM , dcb - > call_id ,
dcb - > line , CC_FEATURE_SELECT , NULL ) ;
return ;
}
feature_data . b2bjoin . b2bjoin_callid = dcb - > call_id ;
if ( g_b2bjoin_callid = = CC_NO_CALL_ID ) {
feature_data . b2bjoin . b2bjoin_joincallid = dcb - > call_id ;
}
else {
feature_data . b2bjoin . b2bjoin_joincallid = g_b2bjoin_callid ;
}
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , CC_FEATURE_B2B_JOIN , & feature_data ) ;
} else {
if ( ( g_numofselected_calls = = 1 ) & & ( dcb - > selected ) ) {
/*
* If this is only one selected call , pressing
* Join on it will start a new join operation
*/
g_b2bjoin_pending = TRUE ;
g_b2bjoin_callid = dcb - > call_id ;
fsm_display_use_line_or_join_to_complete ( ) ;
return ;
}
feature_data . b2bjoin . b2bjoin_callid = dcb - > call_id ;
feature_data . b2bjoin . b2bjoin_joincallid = dcb - > call_id ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , CC_FEATURE_B2B_JOIN , & feature_data ) ;
}
}
g_b2bjoin_pending = FALSE ;
g_b2bjoin_callid = CC_NO_CALL_ID ;
}
/*
* fsmdef_select_invoke
*
*
* Description :
* This function implements the join feature invocation .
*
* Parameters :
* fsmdef_dcb_t * dcb - dcb associated with this call
*
* Returns : None
*/
static void
fsmdef_select_invoke ( fsmdef_dcb_t * dcb , cc_feature_data_t * select_data )
{
cc_feature_data_t feature_data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( dcb - > select_pending ) {
/* We have sent a select but have not received a
* response yet , so diallow further selects till then
*/
return ;
}
if ( select_data ) {
feature_data . select . select = select_data - > select . select ;
} else {
if ( dcb - > selected = = TRUE ) {
feature_data . select . select = FALSE ;
} else {
feature_data . select . select = TRUE ;
}
}
if ( ( g_b2bjoin_pending ) & & ( dcb - > call_id = = g_b2bjoin_callid ) ) {
/* If join is pending, pressing Select on the same call cancels join*/
g_b2bjoin_pending = FALSE ;
g_b2bjoin_callid = CC_NO_CALL_ID ;
}
dcb - > select_pending = TRUE ; ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id ,
dcb - > line , CC_FEATURE_SELECT , & feature_data ) ;
}
/*
* handle_join_pending
*
*
* Description :
* This function checks if the join_pending flag
* needs to be cleared . due to the invocation of other features
*
* Parameters :
* fsmdef_dcb_t * dcb - dcb associated with this call
*
* Returns : None
*/
static void fsmdef_handle_join_pending ( fsmdef_dcb_t * dcb )
{
if ( ( g_b2bjoin_pending ) & & ( dcb - > call_id = = g_b2bjoin_callid ) ) {
/* If join is pending, invoking any other feature cancels join*/
g_b2bjoin_pending = FALSE ;
g_b2bjoin_callid = CC_NO_CALL_ID ;
}
}
/*
* fsmdef_process_dialstring_for_callfwd
*
* Description :
* This function processes the dialstring event for callfwd .
*
* Parameters :
* sm_event_t * event - data associated with this call / dialstring
*
* Returns : sm_rcs_t
*/
static sm_rcs_t
fsmdef_process_dialstring_for_callfwd ( sm_event_t * event )
{
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/*
* For ccm case just return success .
* It will continue the call by sending INVITE
*/
return ( SM_RC_SUCCESS ) ;
}
/*
* fsmdef_process_cfwd_softkey_event
*
* Description :
* This function processes the cfwd softkey press event for callfwd .
*
* Parameters :
* sm_event_t * event - data associated with this call / dialstring
*
* Returns : sm_rcs_t
*/
static sm_rcs_t
fsmdef_process_cfwd_softkey_event ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_t * msg = ( cc_feature_t * ) event - > msg ;
cc_features_t ftr_id = msg - > feature_id ;
cc_feature_data_t * ftr_data = & ( msg - > data ) ;
cc_action_data_t cc_data ;
int skMask [ MAX_SOFT_KEYS ] ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
// check if callfwd is active (i.e. set previously)
if ( lsm_check_cfwd_all_ccm ( dcb - > line ) ) {
// call fsmdef_dialstring() version of the function specific
// to cfwd feature
return ( fsmdef_cfwd_clear_ccm ( fcb ) ) ;
}
// code from here on is common to both modes/feature_id
if ( fcb - > state = = FSMDEF_S_IDLE ) {
/*
* The user is attempting to start a cfwdall call on a specific line :
* 1. need to place the connected call ( if there is one ) on hold ,
* 2. clear any outgoing ringing calls ,
* 3. initiate this call .
*/
if ( fsmdef_wait_to_start_new_call ( TRUE , CC_SRC_GSM , dcb - > call_id , dcb - > line , ftr_id , ftr_data ) )
{
dcb - > active_feature = CC_FEATURE_NONE ;
return ( SM_RC_END ) ;
}
// go offhook and then move to dialing state to collect digits
//only contains <cfwdall-set> in initial NOTIFY to CUCM
fsmdef_notify_hook_event ( fcb , CC_MSG_OFFHOOK ,
ftr_data - > newcall . global_call_id ,
ftr_data - > newcall . prim_call_id ,
ftr_data - > newcall . hold_resume_reason ,
CC_MONITOR_NONE ,
( ftr_id = = CC_FEATURE_CFWD_ALL ) ? CFWDALL_SET : CFWDALL_NONE ) ;
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_OFFHOOK ,
( ( cc_state_data_t * ) ( & ( dcb - > caller_id ) ) ) ) ;
fsmdef_call_cc_state_dialing ( dcb , FALSE ) ;
// stop the dial tone for parity with SCCP phone behavior
cc_data . tone . tone = VCM_INSIDE_DIAL_TONE ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_STOP_TONE ,
& cc_data ) ;
// give different (zip-zip) tone rather than dial tone. zip_zip
// is not a permanent tone so it will end on it's own without
// us telling media termination to stop playing the tone.
cc_data . tone . tone = VCM_ZIP_ZIP ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_PLAY_TONE ,
& cc_data ) ;
// move to collect digit info state
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_COLLECT_INFO ) ;
} else { // we must be in FSMDEF_S_COLLECT_INFO state
// stop the dial tone for parity with SCCP phone behavior
cc_data . tone . tone = VCM_INSIDE_DIAL_TONE ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_STOP_TONE ,
& cc_data ) ;
// give different (zip-zip) tone rather than dial tone. zip_zip
// is not a permanent tone so it will end on it's own without
// us telling media termination to stop playing the tone.
cc_data . tone . tone = VCM_ZIP_ZIP ;
( void ) cc_call_action ( dcb - > call_id , dcb - > line , CC_ACTION_PLAY_TONE ,
& cc_data ) ;
}
ui_control_feature ( dcb - > line , dcb - > call_id , skMask , 1 , FALSE ) ;
return ( SM_RC_END ) ;
}
/**
* This function is a reduced version of the fsmdef_dialstring ( ) function .
* It is customized for sending INVITE out to CCM to clear CFA state .
*
* @ param [ in ] fcb The pointer to the fsm_fcb_t structure of this
* call chain .
*
* @ pre ( fcb not_eq NULL )
*
* @ return sm_rsc_t indicates whether the execution of
* next statmachine .
*/
static sm_rcs_t
fsmdef_cfwd_clear_ccm ( fsm_fcb_t * fcb )
{
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_causes_t cause ;
cc_msgbody_info_t msg_body ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
// to clear CFA in CCM mode... only put service uri... no dialstring.
fsmdef_append_dialstring_to_feature_uri ( dcb , NULL ) ;
// From here on all we need to do is send INVITE out.
// Since, its not a real call there is no need to update UI etc.
// Response to this call will be 5xx so it will be released by the SIP stack.
cause = gsmsdp_create_local_sdp ( dcb , FALSE , TRUE , TRUE , TRUE , TRUE ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
/* Build SDP for sending out */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
return ( fsmdef_release ( fcb , cause , dcb - > send_release ) ) ;
}
cc_int_setup ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , dcb - > alert_info , VCM_INSIDE_RING ,
VCM_INSIDE_DIAL_TONE , NULL , NULL , FALSE , NULL , & msg_body ) ;
/*
* Since we are sending setup to UI we will also have to send
* release to it to for sip stack to clean up the call
*/
dcb - > send_release = TRUE ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_SETUP ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_CALL_SENT ) ;
return ( SM_RC_END ) ;
}
/*
* fsmdef_append_dialstring_to_feature_uri
*
* Description :
* This function appends dialstring to feature URI .
*
* Parameters :
* fsmdef_dcb_t * dcb , char * dialstring
*
* Return Value : none
*
* Note : TNP specific implementation .
*/
static void
fsmdef_append_dialstring_to_feature_uri ( fsmdef_dcb_t * dcb ,
const char * dialstring )
{
char service_uri [ MAX_URL_LENGTH ] ;
service_uri [ 0 ] = ' \0 ' ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( dcb = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_INVALID_DCB ) ,
__FUNCTION__ ) ;
return ;
}
switch ( dcb - > active_feature ) {
case CC_FEATURE_CFWD_ALL :
config_get_string ( CFGID_CALL_FORWARD_URI , service_uri ,
sizeof ( service_uri ) ) ;
break ;
default :
// do nothing
break ;
}
if ( service_uri [ 0 ] ! = NUL ) {
dcb - > caller_id . called_number =
strlib_update ( dcb - > caller_id . called_number , service_uri ) ;
if ( dialstring & & dialstring [ 0 ] ) {
dcb - > caller_id . called_number =
strlib_append ( dcb - > caller_id . called_number , " - " ) ;
dcb - > caller_id . called_number =
strlib_append ( dcb - > caller_id . called_number , dialstring ) ;
}
} else {
FSM_DEBUG_SM ( DEB_F_PREFIX " Configured Feature/Service URI Not Found For Feature[%d] \n " , DEB_F_PREFIX_ARGS ( FSM , " fsmdef_append_dialstring_to_feature_uri " ) , ( int ) dcb - > active_feature ) ;
if ( dialstring & & dialstring [ 0 ] ) {
dcb - > caller_id . called_number =
strlib_update ( dcb - > caller_id . called_number , dialstring ) ;
}
}
}
/*
* fsmdef_is_feature_uri_configured
*
* Description :
* This function checks is a feature URI is configured .
*
* Parameters :
* cc_features_t ftr_id
*
* Return Value : TRUE or FALSE
*
* Note : TNP specific implementation .
*/
static boolean
fsmdef_is_feature_uri_configured ( cc_features_t ftr_id )
{
char service_uri [ MAX_URL_LENGTH ] ;
service_uri [ 0 ] = ' \0 ' ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
switch ( ftr_id ) {
case CC_FEATURE_CFWD_ALL :
config_get_string ( CFGID_CALL_FORWARD_URI , service_uri ,
sizeof ( service_uri ) ) ;
break ;
default :
break ;
}
if ( service_uri [ 0 ] ! = NUL ) {
return TRUE ;
}
FSM_DEBUG_SM ( DEB_F_PREFIX " Configured Feature/Service URI Not Found For Feature[%d] \n " , DEB_F_PREFIX_ARGS ( FSM , " fsmdef_is_feature_uri_configured " ) , ( int ) ftr_id ) ;
return FALSE ;
}
/*
* fsmdef_check_if_ok_for_dial_call
*
* Description :
* This function checks if there is a call in collecting info state
* on a given line .
*
* Parameters :
* line_t line
*
* Returns : TRUE or FALSE
*/
boolean
fsmdef_check_if_ok_for_dial_call ( line_t line )
{
fsmdef_dcb_t * dcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( ( ( dcb - > line = = line ) & & ( dcb - > call_id ! = CC_NO_CALL_ID ) ) & &
( dcb - > fcb ! = NULL ) & &
( ( dcb - > fcb - > state = = FSMDEF_S_COLLECT_INFO ) | |
( dcb - > fcb - > state = = FSMDEF_S_CALL_SENT ) | |
( dcb - > fcb - > state = = FSMDEF_S_OUTGOING_PROCEEDING ) | |
( dcb - > fcb - > state = = FSMDEF_S_KPML_COLLECT_INFO ) ) ) {
return ( TRUE ) ;
}
}
return ( FALSE ) ;
}
/*
* fsmdef_check_if_ok_to_ans_call
*
* Description :
* Checks if given call is in ringing state .
*
* Parameters :
* line
* call_id
*
* Returns : TRUE or FALSE
*/
boolean
fsmdef_check_if_ok_to_ans_call ( line_t line , callid_t call_id )
{
fsmdef_dcb_t * dcb ;
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
return ( FALSE ) ;
}
if ( ( dcb - > line ! = line ) | | ( ( dcb - > fcb ! = NULL ) & & ( dcb - > fcb - > state ! = FSMDEF_S_INCOMING_ALERTING ) ) ) {
return ( FALSE ) ;
}
return ( TRUE ) ;
}
/*
* fsmdef_check_if_ok_to_hold_call
*
* Description :
* Checks if the requested call is in connected state .
*
* Parameters :
* line
* call_id
*
* Returns : TRUE - if there is a connected or resume pending call
* FALSE - if the call is not in above state
*/
boolean
fsmdef_check_if_ok_to_hold_call ( line_t line , callid_t call_id )
{
fsmdef_dcb_t * dcb ;
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
return ( FALSE ) ;
}
if ( ( dcb - > line ! = line ) | |
( ( dcb - > fcb ! = NULL ) & &
( ( dcb - > fcb - > state ! = FSMDEF_S_CONNECTED ) & &
( dcb - > fcb - > state ! = FSMDEF_S_CONNECTED_MEDIA_PEND ) & &
( dcb - > fcb - > state ! = FSMDEF_S_RESUME_PENDING ) ) ) ) {
return ( FALSE ) ;
}
return ( TRUE ) ;
}
/*
* fsmdef_check_if_ok_to_resume_call
*
* Description :
* Checks if the requested call is in held state .
*
* Parameters :
* line
* call_id
*
* Returns : TRUE or FALSE
*/
boolean
fsmdef_check_if_ok_to_resume_call ( line_t line , callid_t call_id )
{
fsmdef_dcb_t * dcb ;
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
return ( FALSE ) ;
}
if ( ( dcb - > line ! = line ) | | ( ( dcb - > fcb ! = NULL ) & & ( dcb - > fcb - > state ! = FSMDEF_S_HOLDING ) ) ) {
return ( FALSE ) ;
}
return ( TRUE ) ;
}
/*
* fsmdef_check_if_ok_to_run_feature
*
* Description :
* Checks if it is ok to run features on the call .
*
* Parameters :
* line
* call_id
*
* Returns : TRUE or FALSE
*/
boolean
fsmdef_check_if_ok_to_run_feature ( line_t line , callid_t call_id )
{
fsmdef_dcb_t * dcb ;
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
return ( FALSE ) ;
}
if ( ( dcb - > line ! = line ) | |
( ( dcb - > fcb ! = NULL ) & &
( dcb - > fcb - > state ! = FSMDEF_S_CONNECTED ) & &
( dcb - > fcb - > state ! = FSMDEF_S_CONNECTED_MEDIA_PEND ) ) ) {
return ( FALSE ) ;
}
return ( TRUE ) ;
}
/*
* fsmdef_check_if_ok_to_monitor_update_call
*
* Description :
* Checks if it is ok to update the monitoring call .
*
* Parameters :
* line
* call_id
*
* Returns : TRUE or FALSE
*/
boolean
fsmdef_check_if_ok_to_monitor_update_call ( line_t line , callid_t call_id )
{
fsmdef_dcb_t * dcb ;
dcb = fsmdef_get_dcb_by_call_id ( call_id ) ;
if ( dcb = = NULL ) {
return ( FALSE ) ;
}
if ( ( dcb - > line ! = line ) | |
( ( dcb - > fcb ! = NULL ) & &
( dcb - > fcb - > state ! = FSMDEF_S_CONNECTED ) ) ) {
return ( FALSE ) ;
}
return ( TRUE ) ;
}
/*
* fsmdef_set_call_info_cc_call_state
*
* Description :
* Sets the called number to readable localized values
* if it is service URI based feature and invokes cc_call_state ( )
*
* Parameters :
* dcb
* state
*
* Returns : none
*/
static void
fsmdef_set_call_info_cc_call_state ( fsmdef_dcb_t * dcb , cc_states_t state , cc_causes_t cause )
{
cc_state_data_t temp_data ;
char tmp_str [ CALL_BUBBLE_STR_MAX_LEN ] ;
int rc = CPR_FAILURE ;
tmp_str [ 0 ] = ' \0 ' ;
switch ( dcb - > active_feature ) {
case CC_FEATURE_CFWD_ALL :
rc = platGetPhraseText ( STR_INDEX_CALL_FORWARD ,
( char * ) tmp_str ,
CALL_BUBBLE_STR_MAX_LEN ) ;
break ;
default :
rc = CPR_FAILURE ;
break ;
}
switch ( state ) {
case CC_STATE_DIALING_COMPLETED :
temp_data . dialing_completed . caller_id = dcb - > caller_id ;
break ;
case CC_STATE_CALL_SENT :
temp_data . call_sent . caller_id = dcb - > caller_id ;
break ;
case CC_STATE_CALL_FAILED :
temp_data . call_failed . caller_id = dcb - > caller_id ;
temp_data . call_failed . cause = cause ;
break ;
default :
/* Set the call id for other states */
temp_data . offhook . caller_id = dcb - > caller_id ;
break ;
}
if ( ( rc = = CPR_SUCCESS ) & & strlen ( tmp_str ) > 0 ) {
temp_data . offhook . caller_id . called_number = tmp_str ;
}
cc_call_state ( dcb - > call_id , dcb - > line , state , & temp_data ) ;
}
/*
* fsmdef_get_dcb_by_call_instance_id
*
* Description :
* This function returns fsmdef DCB that has a match for a given call
* instance ID of a given line .
*
* Parameters :
* line - the dn line
* call_instance_id - for call instance ID .
*
* Returns : pointer to fsmdef_dcb_t if a matching dcb is found otherwise
* returns NULL
*/
fsmdef_dcb_t *
fsmdef_get_dcb_by_call_instance_id ( line_t line , uint16_t call_instance_id )
{
fsmdef_dcb_t * dcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( ( dcb - > caller_id . call_instance_id = = call_instance_id ) & &
( dcb - > line = = line ) ) {
return ( dcb ) ;
}
}
return ( NULL ) ;
}
/*
* fsmdef_ev_join
*
* Description :
* The fsmdef_ev_join function sends an offhook event
* to the barging call and sets its state to FSMDEF_S_JOINING .
*
* Parameters :
* data - pointer to the cc_feature_data_t
*
* Returns :
* none
*/
static void
fsmdef_ev_join ( cc_feature_data_t * data )
{
fsm_fcb_t * fcb = NULL ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
fcb = fsm_get_fcb_by_call_id_and_type ( data - > newcall . join . join_call_id ,
FSM_TYPE_DEF ) ;
if ( fcb ) {
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_int_offhook ( CC_SRC_GSM , CC_SRC_GSM , CC_NO_CALL_ID , CC_REASON_NONE ,
dcb - > call_id , dcb - > line , NULL , CC_MONITOR_NONE , CFWDALL_NONE ) ;
fsm_change_state ( fcb , __LINE__ , FSMDEF_S_JOINING ) ;
}
}
/*
* fsmdef_ev_joining_connected_ack
*
* Description :
* The fsmdef_ev_joining_connected_ack negotiates the sdp in the
* ack ( if there is one ) and sets the fsm / ccapi state to connected
*
* Parameters :
* event - pointer to the sm_event_t
*
* Returns :
* sm_rcs_t value
*/
static sm_rcs_t
fsmdef_ev_joining_connected_ack ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_connected_ack_t * msg = ( cc_connected_ack_t * ) event - > msg ;
cc_causes_t cause ;
fsmcnf_ccb_t * ccb ;
fsm_fcb_t * join_target_fcb ;
cc_feature_data_t data ;
cc_uint32_t major_sis_ver = SIS_PROTOCOL_MAJOR_VERSION_SEADRAGON ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
memset ( & data , 0 , sizeof ( data ) ) ;
/* Check the remote SDP. The far end may not have included the SDP in an
* earlier message , which means that the SDP must be in this message .
*/
if ( dcb - > remote_sdp_in_ack = = TRUE ) {
cause = gsmsdp_negotiate_answer_sdp ( fcb , & msg - > msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
data . endcall . cause = cause ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id , dcb - > line ,
CC_FEATURE_END_CALL , & data ) ;
return ( SM_RC_END ) ;
}
}
platGetSISProtocolVer ( & major_sis_ver , NULL , NULL , NULL ) ;
ccb = fsmcnf_get_ccb_by_call_id ( dcb - > call_id ) ;
if ( ccb ) {
join_target_fcb = fsm_get_fcb_by_call_id_and_type ( ccb - > cnf_call_id ,
FSM_TYPE_CNF ) ;
if ( ( gsmsdp_is_media_encrypted ( dcb ) = = FALSE ) & &
( gsmsdp_is_media_encrypted ( ( join_target_fcb ! = NULL ) ? join_target_fcb - > dcb : NULL ) = = TRUE ) & &
( major_sis_ver < SIS_PROTOCOL_MAJOR_VERSION_MUSTER ) ) {
/*
* Target Call was secure , a non - secure is trying to Barge / Monitor ,
* fail it
*/
data . endcall . cause = CC_CAUSE_SECURITY_FAILURE ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id , dcb - > line ,
CC_FEATURE_END_CALL , & data ) ;
return ( SM_RC_END ) ;
}
}
cc_call_state ( dcb - > call_id , dcb - > line , CC_STATE_CONNECTED ,
( cc_state_data_t * ) & ( dcb - > caller_id ) ) ;
/*
* If DSP is not able to start rx / tx channels , release the call
*/
if ( dcb - > dsp_out_of_resources = = TRUE ) {
data . endcall . cause = CC_CAUSE_NO_MEDIA ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id , dcb - > line ,
CC_FEATURE_END_CALL , & data ) ;
return ( SM_RC_END ) ;
}
if ( ccb ) {
/*
* Bridge the conference legs for the join call , even though
* it ' s done here , ccb should only be accessed from fsmcnf
*/
ccb - > active = TRUE ;
ccb - > bridged = TRUE ;
}
/*
* Handle media capability changes if there is before transition to
* connected state .
*/
return ( fsmdef_transition_to_connected ( fcb ) ) ;
}
/*
* fsmdef_ev_joining_offhook
*
* Description :
* The fsmdef_ev_joining_offhook creates the local sdp
* for the sip stack to send 200 Ok out
*
* Parameters :
* event - pointer to the sm_event_t
*
* Returns :
* sm_rcs_t value
*/
static sm_rcs_t
fsmdef_ev_joining_offhook ( sm_event_t * event )
{
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_causes_t cause ;
cc_msgbody_info_t msg_body ;
cc_feature_data_t data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
/* Build our response SDP to include in the connected */
cause = gsmsdp_encode_sdp_and_update_version ( dcb , & msg_body ) ;
if ( cause ! = CC_CAUSE_OK ) {
FSM_DEBUG_SM ( get_debug_string ( FSM_DBG_SDP_BUILD_ERR ) ) ;
memset ( & data , 0 , sizeof ( data ) ) ;
data . endcall . cause = cause ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , dcb - > call_id , dcb - > line ,
CC_FEATURE_END_CALL , & data ) ;
return ( SM_RC_END ) ;
}
cc_int_connected ( CC_SRC_GSM , CC_SRC_SIP , dcb - > call_id , dcb - > line ,
& ( dcb - > caller_id ) , NULL , & msg_body ) ;
FSM_SET_FLAGS ( dcb - > msgs_sent , FSMDEF_MSG_CONNECTED ) ;
return ( SM_RC_END ) ;
}
/*
* fsmdef_extract_join_target
*
* Description :
* The fsmdef_extract_join_target extract join target call id from
* the setup message and sends a JOIN event to that call
*
* Parameters :
* event - pointer to the sm_event_t
*
* Returns :
* TRUE or FALSE
*/
static boolean
fsmdef_extract_join_target ( sm_event_t * event )
{
static const char fname [ ] = " fsmdef_extract_join_target " ;
fsm_fcb_t * fcb = ( fsm_fcb_t * ) event - > data ;
cc_setup_t * msg = ( cc_setup_t * ) event - > msg ;
callid_t call_id = msg - > call_id ;
line_t line = msg - > line ;
fsmdef_dcb_t * dcb ;
fsmdef_dcb_t * join_dcb ;
cc_feature_data_t data ;
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
dcb = fcb - > dcb ;
if ( ( msg - > call_info . type = = CC_FEAT_MONITOR ) | |
( dcb - > session = = WHISPER_COACHING ) ) {
/* For now, null out the ui id */
lsm_set_ui_id ( dcb - > call_id , CC_NO_CALL_ID ) ;
join_dcb =
fsmdef_get_dcb_by_call_id ( msg - > call_info . data . join . join_call_id ) ;
if ( join_dcb ) {
dcb - > group_id = join_dcb - > group_id ;
memset ( & data , 0 , sizeof ( data ) ) ;
data . newcall . join . join_call_id = call_id ;
if ( dcb - > session = = WHISPER_COACHING ) {
data . newcall . cause = CC_CAUSE_MONITOR ;
} else if ( msg - > call_info . type = = CC_FEAT_MONITOR ) {
data . newcall . cause = CC_CAUSE_MONITOR ;
// set the session leg of this dcb to monitor
dcb - > session = MONITOR ;
}
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " dcb-session type is = %s \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) ,
dcb - > session = = WHISPER_COACHING ? " WHISPER_COACHING " :
dcb - > session = = MONITOR ? " MONITOR " : " PRIMARY " ) ;
cc_int_feature ( CC_SRC_GSM , CC_SRC_GSM , join_dcb - > call_id , line ,
CC_FEATURE_JOIN , & data ) ;
} else {
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " Unable to find join target dcb \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) ) ;
return ( TRUE ) ;
}
} else {
FSM_DEBUG_SM ( DEB_L_C_F_PREFIX " Unable to find join target call information \n " ,
DEB_L_C_F_PREFIX_ARGS ( FSM , dcb - > line , dcb - > call_id , fname ) ) ;
return ( TRUE ) ;
}
return ( FALSE ) ;
}
/*
* fsmdef_ev_notify_feature
*
* Description :
* Handles NOTIFY event in different states .
*
* Parameters :
* msg - message pointer
* dcb - pointer to the fsmdef_dcb_t
*
* Returns :
* none
*/
static void
fsmdef_ev_notify_feature ( cc_feature_t * msg , fsmdef_dcb_t * dcb )
{
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
}
/*
* fsmdef_notify_hook_event
*
* Description :
* Send offhook / onhook events to SIP ( DialogManager ) task .
*
* Parameters :
* dcb - pointer to the fsmdef_dcb_t
*
* Returns :
* none
*/
static void
fsmdef_notify_hook_event ( fsm_fcb_t * fcb , cc_msgs_t msg , char * global_call_id ,
callid_t prim_call_id ,
cc_hold_resume_reason_e consult_reason ,
monitor_mode_t monitor_mode ,
cfwdall_mode_t cfwdall_mode )
{
FSM_DEBUG_SM ( DEB_F_PREFIX " Entered. \n " , DEB_F_PREFIX_ARGS ( FSM , __FUNCTION__ ) ) ;
if ( msg = = CC_MSG_OFFHOOK ) {
cc_int_offhook ( CC_SRC_GSM , CC_SRC_SIP , prim_call_id , consult_reason ,
fcb - > dcb - > call_id , fcb - > dcb - > line ,
global_call_id , monitor_mode , cfwdall_mode ) ;
} else if ( msg = = CC_MSG_ONHOOK ) {
cc_int_onhook ( CC_SRC_GSM , CC_SRC_SIP , prim_call_id ,
consult_reason , fcb - > dcb - > call_id , fcb - > dcb - > line , FALSE , FALSE ) ;
}
return ;
}
/*
* fsmdef_update_callinfo_security_status
*
* Description :
* The fsmdef_update_callinfo_security_status function updates the call
* information that applies to TNP platform .
*
* Parameters :
* dcb - pointer to the fsmdef_dcb_t
* call_info - pointer to the cc_feature_data_call_info_t
*
* Returns :
* none
*/
static void
fsmdef_update_callinfo_security_status ( fsmdef_dcb_t * dcb ,
cc_feature_data_call_info_t * call_info )
{
/*
* Update security information
*/
if ( call_info - > feature_flag & CC_SECURITY ) {
if ( sip_regmgr_get_sec_level ( dcb - > line ) ! = AUTHENTICATED & &
sip_regmgr_get_sec_level ( dcb - > line ) ! = ENCRYPTED ) {
// Signaling security can't be trusted downgrade security level to NOT_AUTHENTICATED
call_info - > security = CC_SECURITY_NOT_AUTHENTICATED ;
}
if ( dcb - > security ! = call_info - > security ) {
FSM_SET_SECURITY_STATUS ( dcb , call_info - > security ) ;
if ( call_info - > security = = CC_SECURITY_ENCRYPTED )
ui_update_call_security ( dcb - > line , lsm_get_ui_id ( dcb - > call_id ) , CC_SECURITY_ENCRYPTED ) ;
else
ui_update_call_security ( dcb - > line , lsm_get_ui_id ( dcb - > call_id ) , CC_SECURITY_UNKNOWN ) ;
dcb - > ui_update_required = TRUE ;
}
}
}
/*
* fsmdef_check_retain_fwd_info_state
*
* Description : This function checks the " Retain Forward Information " config
* parameter ( only for TNP ) . It returns TRUE if forward info is
* to be retained ; FALSE otherwise . This config parameter is
* is used to change call bubble display from " Forward <DN> " to
* " From <DN> " when an incoming call is answered AND the config
* parameter value is set to TRUE . For non - TNP , this function
* will always return FALSE ( i . e . not to retain fwd info ) .
*
* Parameters : none
*
* Return Value : TRUE or FALSE
*/
boolean
fsmdef_check_retain_fwd_info_state ( void )
{
int retain_fwd_info_cfg = 0 ; /* default to Disabled (or 0) for no-op */
config_get_value ( CFGID_RETAIN_FORWARD_INFORMATION ,
& retain_fwd_info_cfg ,
sizeof ( retain_fwd_info_cfg ) ) ;
if ( ! retain_fwd_info_cfg ) {
return ( FALSE ) ; /* do NOT retain forward information */
} else {
return ( TRUE ) ; /* retain forward information */
}
}
void
fsmdef_init ( void )
{
static const char fname [ ] = " fsmdef_init " ;
fsmdef_dcb_t * dcb ;
/*
* Initialize the dcbs .
*/
fsmdef_dcbs = ( fsmdef_dcb_t * )
cpr_calloc ( FSMDEF_MAX_DCBS , sizeof ( fsmdef_dcb_t ) ) ;
if ( fsmdef_dcbs = = NULL ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " cpr_calloc returned NULL \n " ,
DEB_F_PREFIX_ARGS ( FSM , fname ) ) ;
return ;
}
/* Create free media structure list */
if ( ! gsmsdp_create_free_media_list ( ) ) {
FSM_DEBUG_SM ( DEB_F_PREFIX " Unable to create free media list \n " ,
DEB_F_PREFIX_ARGS ( FSM , fname ) ) ;
return ;
}
DEF_DEBUG ( DEB_F_PREFIX " Disabling mass registration print " , DEB_F_PREFIX_ARGS ( SIP_REG , fname ) ) ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
fsmdef_init_dcb ( dcb , CC_NO_CALL_ID , FSMDEF_CALL_TYPE_NONE ,
FSMDEF_NO_NUMBER , LSM_NO_LINE , NULL ) ;
/*
* Allocate ringback delay timer for each dcb
*/
dcb - > ringback_delay_tmr = cprCreateTimer ( " Ringback Delay " ,
GSM_RINGBACK_DELAY_TIMER ,
TIMER_EXPIRATION ,
gsm_msg_queue ) ;
if ( dcb - > ringback_delay_tmr = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CREATE_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Ringback Delay " ) ;
return ;
}
/*
* Allocate auto answer timer for each dcb
*/
dcb - > autoAnswerTimer = cprCreateTimer ( " Auto Answer " ,
GSM_AUTOANSWER_TIMER ,
TIMER_EXPIRATION ,
gsm_msg_queue ) ;
if ( dcb - > autoAnswerTimer = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CREATE_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Auto Answer " ) ;
( void ) cprDestroyTimer ( dcb - > ringback_delay_tmr ) ;
dcb - > ringback_delay_tmr = NULL ;
return ;
}
dcb - > revertTimer = cprCreateTimer ( " Call Reversion " ,
GSM_REVERSION_TIMER ,
TIMER_EXPIRATION ,
gsm_msg_queue ) ;
dcb - > reversionInterval = - 1 ;
if ( dcb - > revertTimer = = NULL ) {
FSM_DEBUG_SM ( get_debug_string ( FSMDEF_DBG_TMR_CREATE_FAILED ) ,
dcb - > call_id , dcb - > line , fname , " Hold Revertion " ) ;
( void ) cprDestroyTimer ( dcb - > ringback_delay_tmr ) ;
dcb - > ringback_delay_tmr = NULL ;
( void ) cprDestroyTimer ( dcb - > autoAnswerTimer ) ;
dcb - > autoAnswerTimer = NULL ;
return ;
}
if ( dcb = = fsmdef_dcbs ) {
g_disable_mass_reg_debug_print = TRUE ;
}
}
g_disable_mass_reg_debug_print = FALSE ;
/*
* Initialize the state / event table .
*/
fsmdef_sm_table . min_state = FSMDEF_S_MIN ;
fsmdef_sm_table . max_state = FSMDEF_S_MAX ;
fsmdef_sm_table . min_event = CC_MSG_MIN ;
fsmdef_sm_table . max_event = CC_MSG_MAX ;
fsmdef_sm_table . table = ( & ( fsmdef_function_table [ 0 ] [ 0 ] ) ) ;
}
void
fsmdef_shutdown ( void )
{
fsmdef_dcb_t * dcb ;
FSM_FOR_ALL_CBS ( dcb , fsmdef_dcbs , FSMDEF_MAX_DCBS ) {
if ( dcb - > req_pending_tmr ) {
( void ) cprDestroyTimer ( dcb - > req_pending_tmr ) ;
}
if ( dcb - > err_onhook_tmr ) {
( void ) cprDestroyTimer ( dcb - > err_onhook_tmr ) ;
}
if ( dcb - > ringback_delay_tmr ) {
( void ) cprDestroyTimer ( dcb - > ringback_delay_tmr ) ;
}
if ( dcb - > autoAnswerTimer ) {
( void ) cprDestroyTimer ( dcb - > autoAnswerTimer ) ;
}
if ( dcb - > revertTimer ) {
( void ) cprDestroyTimer ( dcb - > revertTimer ) ;
}
/* clean media list */
gsmsdp_clean_media_list ( dcb ) ;
}
/* destroy free media structure list */
gsmsdp_destroy_free_media_list ( ) ;
cpr_free ( fsmdef_dcbs ) ;
fsmdef_dcbs = NULL ;
}
static void
fsmdef_update_calltype ( fsm_fcb_t * fcb , cc_feature_t * msg ) {
fsmdef_dcb_t * dcb = fcb - > dcb ;
cc_feature_data_t * feat_data = & ( msg - > data ) ;
cc_caller_id_t * caller_id ;
if ( msg - > data_valid = = FALSE ) {
/* No data to use for update. Just ignore the event. */
return ;
}
if ( feat_data - > call_info . feature_flag & CC_CALLER_ID ) {
caller_id = & feat_data - > call_info . caller_id ;
if ( caller_id - > call_type = = CC_CALL_FORWARDED ) {
if ( fsmdef_check_retain_fwd_info_state ( ) ) {
dcb - > call_type = FSMDEF_CALL_TYPE_FORWARD ;
}
}
}
}