diff --git a/conf/autoload_configs/callcenter.conf.xml b/conf/autoload_configs/callcenter.conf.xml index 156ed374ca..e764d17f15 100644 --- a/conf/autoload_configs/callcenter.conf.xml +++ b/conf/autoload_configs/callcenter.conf.xml @@ -10,6 +10,8 @@ + + diff --git a/conf/dialplan/default.xml b/conf/dialplan/default.xml index 9862eed711..8abb8d8348 100644 --- a/conf/dialplan/default.xml +++ b/conf/dialplan/default.xml @@ -715,15 +715,6 @@ --> - - - + + + + + + diff --git a/conf/dialplan/default/99999_enum.xml b/conf/dialplan/default/99999_enum.xml deleted file mode 100644 index 6fd2151859..0000000000 --- a/conf/dialplan/default/99999_enum.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/conf/directory/default/skinny-example.xml b/conf/directory/default/skinny-example.xml index 2f19710136..357eb72f12 100644 --- a/conf/directory/default/skinny-example.xml +++ b/conf/directory/default/skinny-example.xml @@ -3,6 +3,7 @@ diff --git a/conf/skinny_profiles/internal.xml b/conf/skinny_profiles/internal.xml index e48557b234..5feac1ffbf 100644 --- a/conf/skinny_profiles/internal.xml +++ b/conf/skinny_profiles/internal.xml @@ -13,6 +13,17 @@ + + + + + + + + + + + diff --git a/docs/ChangeLog b/docs/ChangeLog index 0bc629ef60..a2ed493f37 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -15,6 +15,7 @@ freeswitch (1.0.7) build: Fix build with --with-curl (r:e704f021/FSBUILD-285) build: VS 2010 - Change to V4 framework, add SWIG v2.0 files to fix release build exceptions(temp fix till we upgrade all SWIG files) (r:812f4309) build: Windows VS2010 build - remove strange characters (r:ba1546e0/FSBUILD-297) + build: Make bootstrap.sh Bourne shell compatible (r:8dbd62ff/FSBUILD-301) config: move limit.conf to db.conf config: Update VM phrase macros to voice option then action on main, config menus config: Remove 99xx extension numbers to avoid dp conflicts (r:0c9bb174/DP-17) @@ -30,7 +31,7 @@ freeswitch (1.0.7) core: always export 'export_vars' core: add sanity check to launch threads that catch hangup and are not in a thread to make sure they clean up core: Tweak bridge_early_media to support passthrough codecs - core: cleanup C reserved identifer violation (JANITOR-3) + core: cleanup C reserved identifier violation (JANITOR-3) core: add sound_prefix support in uuid_displace (FSCORE-550) core: add 'critical' param on modules.conf to abort on mod load failure from Moc core: add 'direction' chan var @@ -71,6 +72,12 @@ freeswitch (1.0.7) core: Improve RTP timing on playback of files (r:d6d7773c/FSCORE-639) core: Allows bind_meta_app to use chars other than * (r:fd254766/FSCORE-630) core: Fixed core lib won't build for win32 (r:9327c994/FSCORE-646) + core: add last_bridge_to var to keep uuid of last bridged channel and fix race in show calls on hangup of bypass_media channels (r:77e2dccf) + core: Phrase "speak-text" application returns on first key press in phrase file on Windows (r:6d74d7ab/MODAPP-448) + core: pass originate flags into session_request so we can selectivly skip throttling (r:46c6650a) + core: Implemented 'Block Fork' and removed possibility for "-nc -nf" potential issue. (r:f26a6972/FSCORE-652) + core: Add console callback for listing loaded/available modules for load/unload/reload commands (r:d68a1218/FSCORE-662) + core: strip trailing and leading whitespace in api execute args and commands (r:ca481842) lang: Improve French phrase files (FSCONFIG-23) libdingaling: fix race on shutdown causing crash (FSMOD-47) libesl: Fix potential race condition (ESL-36) @@ -88,8 +95,10 @@ freeswitch (1.0.7) libfreetdm: implemented freetdm config nodes and ss7 initial configuration libopenzap: Add CLI tracing libs: Merged OpenZAP and FreeTDM into the FreeSWITCH tree. + libs: Add support for TLS on Windows using openssl (r:1abe3b93/MODSOFIA-92) libsofiasip: Fix random crashes (r:c15ee980/SFSIP-219) libsofiasip: Fix T.38 bug in sofia_glue (r:2843f1ad/MODSOFIA-94) + libsofiasip: VS2010 sofia posix problem (r:46dd24c2/SFSIP-220) libspandsp: Fixed a typo in spandsp's msvc/inttypes.h Updated sig_tone processing in spandsp to the latest, to allow moy to proceed with his signaling work. libspandsp: removed a saturate16 from spandsp that was causing problems fixed a typo in the MSVC inttypes.h file for spandsp libspandsp: Changes to the signaling tone detector to detect concurrent 2400Hz + 2600Hz tones. This passes voice immunity and other key tests, but it bounces a bit when transitions like 2400 -> 2400+2600 -> 2600 occur. Transitions between tone off and tone on are clean. (r:bc13e944) @@ -101,6 +110,13 @@ freeswitch (1.0.7) mod_callcenter: Try to fix the ring-all, also add cli auto complete done in previous commit (r:1666783c) mod_callcenter: Add missing odbc db support (Not tested, please someone test this) (r:42436e27) mod_callcenter: More ODBC changes. It is not a global settings value. Cannot be changed in runtime. (r:6980305f) + mod_callcenter: Added value busy_delay_time and reject_delay_time so we can wait if those 2 occur (Un registred phone are considered as busy). Add a ready_time epoch time when we can contact an again again, fix ring-all (good this time I hope). (r:8082aa98) + mod_callcenter: Add tiers rules before jumping to a different level. Also added support for dial-in agent. (r:86c9bed7) + mod_callcenter: Default the level to 0 since the new tier system will wait x second at level 1... just level 0 that will ring agent right away (if set to do so) (r:6558276a) + mod_callcenter: You can now allow caller that have hangup before agent answer to call back and resume their previous position. (r:ab2529d4) + mod_callcenter: correct multiple little things following the recent tiers and join back features (r:9b33bd1c) + mod_callcenter: Add more channel variable and event and fix a mem leak (r:2d3d8c8d) + od_callcenter: Make more sence to bridge the caller to the agent. Before, in the xml_cdr you saw it it like the agent initiated the call to the member (r:0be95658) mod_cidlookup: null xml is bad (r:095815f8) mod_cid_lookup: honor skipcitystate when using whitepages (r:a66654de/FSMOD-53) mod_commands: make break uuid_break and add cascade flag @@ -118,7 +134,11 @@ freeswitch (1.0.7) mod_conference: add conference_member_id variable to all sessions with the member id used by their conference participation (For drk__) (r:49c9bfdb) mod_conference: fix relate nohear (r:f029ce07/MODAPP-428) mod_conference: Fix floor change events not always firing (r:8f1767d3/MODAPP-424) + mod_curl: use method=post when post requested (r:c6a4ddd0/FSMOD-69) mod_dialplan_xml: Add in the INFO log the caller id number when processing a request (Currenly only show the caller name) (r:e1df5e13) + mod_dingaling: make mod_dingaling compat with google's new free phonecalls thing (r:ba0a2a32) + mod_dingaling: make dingaling work with google voice inbound too (r:4ee68141) + mod_dingaling: Fix crash when testing the new gv-dingaling with around 24 concurrent calls (r:73e1ec5e/FSCORE-667) mod_db: fix stack corruption (MODAPP-407) mod_dptools: add eavesdrop_enable_dtmf chan var (r:596c0012) mod_dptools: Make park app not send 183 session progress (r:76932995/FSCORE-567) @@ -126,7 +146,9 @@ freeswitch (1.0.7) mod_erlang_event: Make XML fetch reply ACKs distinguishable, update freeswitch.erl (r:9d44ed04) mod_erlang_event: Add 3 new commands; session_event, session_noevents, session_nixevent (r:698fa045) mod_erlang_event: generate long node names the same as erlang does (r:9ad509c2) + mod_erlang_event: Improve some logging to include UUIDs (r:c0d51b83) mod_event_socket: fix up other users of switch_event_xmlize() to use SWITCH_EVENT_NONE (r:d6eb7562) + mod_event_socket: Fix small mem leaks (r:e4f90584/MODEVENT-68) mod_fifo: allow multiple dtmf to exit fifo, set fifo_caller_exit_key to specify which (MODAPP-420) mod_fifo: cancel outbound call if customer hangs up (r:cadb4d94) mod_fifo: add taking_calls param to fifo member add and config file (r:821488bf) @@ -159,6 +181,8 @@ freeswitch (1.0.7) mod_freetdm: fix fxs dialtone - should be stopped on first digit (r:f822180f) mod_freetdm: add bearer capability and layer1 pass-thru for boost (r:07b81760) mod_freetdm: OPENZAP-107 - Patched by Jeff Lenk (r:aa075136/OPENZAP-107) + mod_freetdm: allocate channels in their own memory page when debugging (r:fcd8df0a) + mod_freetdm: lock the channel when placing call (r:705dd237) mod_gsmopen: copy from branch mod_hash: free all hashtables on shutdown (r:e76d7d92) mod_hash: remove unneeded initializer (r:10d468a6) @@ -179,6 +203,7 @@ freeswitch (1.0.7) mod_h323: add missing conf prameter (r:0b353d7a) mod_h323: Add mod_h323 to windows (r:015bcaf6/MODENDP-301) mod_h323: move PTrace level set to FSH323EndPoint::Initialise. partially apply patch from from Peter Olsson, Remove UnLock() when TryLock() failed and DEBUG_RTP_PACKETS directiv e. (r:7b5803f7) + mod_h323: set network_addr of caller profile to signaling ip address. (requested by Steven Ayre) (r:072bf5ad) mod_java: fix eventConsumer issue and add flush() method (r:7fd3aff6) mod_java: Allow user defined java methods to be called at startup and shutdown of JVM (r:1339e218/MODLANG-117) mod_json_cdr: Fix segfault in mod_json_cdr.c (r:f347698a/MODEVENT-66) @@ -210,7 +235,9 @@ freeswitch (1.0.7) mod_sangoma_codec: rename load/noload to register/noregister mod_sangoma_codec: silence suppression (r:73d9d56f) mod_say_es: fix grammar when saying dates and time (r:6bed19b2/MODAPP-429) + mod_say_ru: Fix saying time with +1 hour of current time (r:68d74c31/MODAPP-444) mod_say_zh: Number reading should now be OK for the whole range of integers for Cantonese and Mandarin + mod_silk: Fix mod_silk compliance and performance issues (r:2ddbc457/MODCODEC-20) mod_skinny: Add the missing api files mod_skinny: add example dialplan and directory config (r:1bfcc17e) mod_skinny: rewrite of the skinny state machine (r:8cc89ab0) @@ -225,8 +252,16 @@ freeswitch (1.0.7) mod_skinny: ib_calls stats (r:165140e0) mod_skinny: blind transfer MODSKINNY-10 (r:53f75e9c/MODSKINNY-10) mod_skinny: ring tone on dialing side (r:0a04ecb8) + mod_skinny: stop media on early media hangup (ring-out) (r:ce352bcc) + mod_skinny: add windows x64 build support for mod_skinny (r:3e205683) + mod_skinny: avoid "-ERR no reply" when using API commands from CLI (r:690ae1b3) + mod_skinny: allow configuration of softkeys via xml (r:f5a6831f) + mod_skinny: allow skinny-default-soft-key-set-set per device (r:07c3c94d) + mod_skinny: Rename skinny-default-soft-key-set-set to skinny-soft-key-set-set (r:ba3a6ad6) mod_skypopen: making XEvents to works when EARLYMEDIA, and correctly manage threads death mod_skypopen: now answer a call only when directed to do it (before was trying to answer any incoming call). Lot of changes to a messy part, so maybe some problem will come out... (r:45c6c4d3) + mod_skypopen: ignore early media sent by channels to be bridged before our channel is answered (r:ef14b78a) + mod_sndfile: Add support for .alaw and .ulaw to mod_sndfile (r:facf09b8/MODFORM-41) mod_sofia: Send SIP MESSAGE to unregistered users by prefixing sip: to user@domain mod_sofia: fix callee being updated with callee information mod_sofia: set appearance-index in update statement for SLA @@ -258,6 +293,16 @@ freeswitch (1.0.7) mod_sofia: Fix segfault (r:72be253d/MODSOFIA-83) mod_sofia: Add openssl build support to windows - no external build support needed (step 1 - not hooked up yet) vs2008 pro+ only (r:b0de3585/MODSOFIA-92) mod_sofia: REFER: to-tag and from-tag should be set other way around when other (bridged) channel is incoming. (r:92d324d3/MODSOFIA-91) + mod_sofia: fix 302 to hangup in the two cases where switch_ivr_transfer is used and not in the case when it should carry on and follow the redirect (r:00b51403) + mod_sofia: Remove OPENSSL_USE_APPLINK - not needed (r:437c7805/MODSOFIA-92) + mod_sofia: Send Instant Messages To All Endpoints Registered to Targeted Extension (r:96b790fa/BOUNTY-20) + mod_sofia: increase sps during recovery (r:f1aead31) + mod_sofia: Forward unsolicited MWI nofity (r:5481d9a9/MODSOFIA-86) + mod_sofia: Add a quick fix for basic Polycom presence support. A more sane solution need to be implemented (r:a55b9d07) + mod_sofia: Unify gateway printing between 'sofia xmlstatus gateway' and 'sofia xmlstatus gateway ' (r:37c22467) + mod_sofia: Fix memleak and mwi event not generated on first register (r:04b9b3e2) + mod_sofia: when getting presence with no payload consider it an extension to the expires time in the dialog (r:70331e88) + mod_sofia: don't put blank 'version' attr in dialog-info packets (r:749dc864) mod_spandsp: initial checkin of mod_fax/mod_voipcodecs merge into mod_spandsp (r:fa9a59a8) mod_spandsp: rework of new mod_spandsp to have functions broken up into different c files (r:65400642) mod_spandsp: improve duplicate digit detection and add 'min_dup_digit_spacing_ms' channel variable for use with the dtmf detector (r:eab4f246/FSMOD-45) @@ -276,6 +321,7 @@ freeswitch (1.0.7) mod_voicemail: add 'vm-enabled' param (default true) mod_voicemail: fix vm msg being deleted when pressing key to forward to email (MODAPP-403) mod_voicemail: make voicemails use the uuid of the channel who recorded it when applicable (r:98a5a30a) + mod_voicemail: user unable to play or delete voicemail via web API (r:b5205c0b/MODAPP-447) mod_xml_cdr: add force_process_cdr var to process b leg cdr on a case by case basis when b leg cdr is disabled (XML-17) mod_xml_cdr: add leg param to query string (XML-24) mod_xml_cdr: fix locked sessions (XML-26) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 56eebd7dd5..fb85b3515c 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3896,7 +3896,7 @@ SWITCH_STANDARD_API(ft_function) ftdm_channel_t *fchan = NULL; ftdm_span_t *span = NULL; if (argc < 2) { - stream->write_function(stream, "-ERR Usage: oz notrace []\n"); + stream->write_function(stream, "-ERR Usage: ftdm notrace []\n"); goto end; } ftdm_span_find_by_name(argv[1], &span); diff --git a/libs/freetdm/msvc/freetdm.2008.vcproj b/libs/freetdm/msvc/freetdm.2008.vcproj index 851017e9a8..c72891e525 100644 --- a/libs/freetdm/msvc/freetdm.2008.vcproj +++ b/libs/freetdm/msvc/freetdm.2008.vcproj @@ -338,6 +338,10 @@ RelativePath="..\src\include\private\ftdm_buffer.h" > + + @@ -416,6 +420,10 @@ RelativePath="..\src\ftdm_buffer.c" > + + diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index fc32a0ff0f..b275403c85 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1805,6 +1805,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, status = FTDM_SUCCESS; } ftdm_set_flag(check, FTDM_CHANNEL_INUSE); + ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND); *ftdmchan = check; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index 9ffd7097a3..e962eceb28 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -189,7 +189,8 @@ ftdm_state_map_t sangoma_isdn_state_map = { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_DIALING, FTDM_END}, - {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DOWN, FTDM_END} + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, + FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { ZSD_OUTBOUND, @@ -558,6 +559,9 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) /* We are hangup local call because there was a glare, we are waiting for a RELEASE on this call, before we can process the saved call */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for RELEASE on hungup glared call\n"); + } else if (sngisdn_test_flag(sngisdn_info, FLAG_SEND_DISC)) { + /* Remote side sent a PROGRESS message, but cause indicates disconnect or T310 expired*/ + sngisdn_snd_disconnect(ftdmchan); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call upon local request!\n"); @@ -568,16 +572,15 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALING) { + sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); + sngisdn_snd_release(ftdmchan, 0); + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { sng_isdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); } - - sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); - sngisdn_snd_release(ftdmchan, 0); } else { sngisdn_snd_disconnect(ftdmchan); } - } /* now go to the HANGUP complete state */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 3f63fbc1d4..5f26828529 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -68,6 +68,7 @@ typedef enum { FLAG_GLARE = (1 << 6), FLAG_DELAYED_REL = (1 << 7), FLAG_SENT_PROCEED = (1 << 8), + FLAG_SEND_DISC = (1 << 9), } sngisdn_flag_t; @@ -127,6 +128,13 @@ typedef enum { SNGISDN_EVENT_RST_IND, } ftdm_sngisdn_event_id_t; +/* Only timers that can be cancelled are listed here */ +#define SNGISDN_NUM_TIMERS 1 +/* Increase NUM_TIMERS as number of ftdm_sngisdn_timer_t increases */ +typedef enum { + SNGISDN_TIMER_FACILITY = 0, +} ftdm_sngisdn_timer_t; + typedef struct sngisdn_glare_data { int16_t suId; uint32_t suInstId; @@ -148,6 +156,7 @@ typedef struct sngisdn_chan_data { uint8_t globalFlg; sngisdn_glare_data_t glare; + ftdm_timer_t *timers[SNGISDN_NUM_TIMERS]; } sngisdn_chan_data_t; /* Span specific data */ @@ -165,6 +174,7 @@ typedef struct sngisdn_span_data { uint8_t overlap_dial; uint8_t setup_arb; uint8_t facility; + int8_t facility_timeout; ftdm_sched_t *sched; ftdm_queue_t *event_queue; } sngisdn_span_data_t; @@ -223,8 +233,8 @@ typedef struct sngisdn_cc { ftdm_trunk_type_t trunktype; uint32_t last_suInstId; ftdm_mutex_t *mutex; - sngisdn_chan_data_t *active_spInstIds[MAX_INSTID]; - sngisdn_chan_data_t *active_suInstIds[MAX_INSTID]; + sngisdn_chan_data_t *active_spInstIds[MAX_INSTID+1]; + sngisdn_chan_data_t *active_suInstIds[MAX_INSTID+1]; }sngisdn_cc_t; /* Global sngisdn data */ @@ -349,6 +359,7 @@ void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t void sngisdn_delayed_release(void* p_sngisdn_info); void sngisdn_delayed_connect(void* p_sngisdn_info); void sngisdn_delayed_disconnect(void* p_sngisdn_info); +void sngisdn_facility_timeout(void* p_sngisdn_info); /* Stack management functions */ ftdm_status_t sng_isdn_stack_cfg(ftdm_span_t *span); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index ec44142303..96eaf051a2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -249,6 +249,11 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ ftdm_span_set_bearer_capability(val, &span->default_caller_data.bearer_capability); } else if (!strcasecmp(var, "outbound-bearer_layer1")) { ftdm_span_set_bearer_layer1(val, &span->default_caller_data.bearer_layer1); + } else if (!strcasecmp(var, "facility-timeout")) { + signal_data->facility_timeout = atoi(val); + if (signal_data->facility_timeout < 0) { + signal_data->facility_timeout = 0; + } } else { ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index c3d97e5c5c..ff9a53b294 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -78,14 +78,13 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) } sngisdn_info->suInstId = get_unique_suInstId(suId); - sngisdn_info->spInstId = spInstId; + sngisdn_info->spInstId = spInstId; /* If this is a glared call that was previously saved, we moved all the info to the current call, so clear the glared saved data */ - if (sngisdn_info->glare.spInstId == spInstId) { clear_call_glare_data(sngisdn_info); - } + } ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; @@ -105,7 +104,8 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; - } + } + /* Fill in call information */ cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb); cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb); @@ -142,6 +142,10 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) if (ret_val == 1) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID); + /* Launch timer in case we never get a FACILITY msg */ + if (signal_data->facility_timeout) { + ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout, sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); + } break; } else if (ret_val == 0) { strcpy(ftdmchan->caller_data.cid_name, retrieved_str); @@ -289,6 +293,8 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt; ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); @@ -302,19 +308,49 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) suId, suInstId, spInstId, ces); switch(evntType) { + case MI_PROGRESS: + if (signal_data->switchtype == SNGISDN_SWITCH_NI2 && + cnStEvnt->causeDgn[0].eh.pres && cnStEvnt->causeDgn[0].causeVal.pres) { + + switch(cnStEvnt->causeDgn[0].causeVal.val) { + case 17: /* User Busy */ + case 18: /* No User responding */ + case 19: /* User alerting, no answer */ + case 21: /* Call rejected, the called party does not with to accept this call */ + case 27: /* Destination out of order */ + case 31: /* Normal, unspecified */ + case 34: /* Circuit/Channel congestion */ + case 41: /* Temporary failure */ + case 42: /* Switching equipment is experiencing a period of high traffic */ + case 47: /* Resource unavailable */ + case 58: /* Bearer Capability not available */ + case 63: /* Service or option not available */ + case 65: /* Bearer Cap not implemented, not supported */ + case 79: /* Service or option not implemented, unspecified */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Cause requires disconnect (cause:%d)\n", cnStEvnt->causeDgn[0].causeVal.val); + ftdmchan->caller_data.hangup_cause = cnStEvnt->causeDgn[0].causeVal.val; + + sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + goto sngisdn_process_cnst_ind_end; + } + } + /* fall-through */ case MI_ALERTING: case MI_CALLPROC: - case MI_PROGRESS: + switch(ftdmchan->state) { - case FTDM_CHANNEL_STATE_DIALING: - if (evntType == MI_PROGRESS) { + case FTDM_CHANNEL_STATE_DIALING: + if (evntType == MI_PROGRESS || + (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); } break; case FTDM_CHANNEL_STATE_PROGRESS: - if (evntType == MI_PROGRESS) { + if (evntType == MI_PROGRESS || + (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } break; @@ -371,6 +407,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) break; } +sngisdn_process_cnst_ind_end: ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } @@ -638,12 +675,14 @@ void sngisdn_process_flc_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; FacEvnt *facEvnt = &sngisdn_event->event.facEvnt; @@ -659,10 +698,16 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) if (sng_isdn_retrieve_facility_caller_name(facility_str, facEvnt->facElmt.facStr.len, retrieved_str) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to retrieve Caller Name from Facility IE\n"); } + /* Cancel facility timeout */ + ftdm_sched_cancel_timer(signal_data->sched, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); break; + case FTDM_CHANNEL_STATE_RING: + /* We received the caller ID Name in FACILITY, but its too late, facility-timeout already occurred */ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "FACILITY received, but we already proceeded with call\n"); + break; default: /* We do not support other FACILITY types for now, so do nothing */ break; @@ -794,6 +839,14 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; case 3: switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_PROGRESS: + /* T310 timer has expired */ + ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T310 Timer expired, hanging up call\n"); + sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + + break; case FTDM_CHANNEL_STATE_UP: /* Remote side is still waiting for our CONNECT message */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 29cfb2330e..f921b1be8c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -45,8 +45,8 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); uint8_t bchan_no = 0; - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n"); @@ -96,7 +96,7 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); memcpy(&sngisdn_event->event.conEvnt, conEvnt, sizeof(*conEvnt)); - + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -104,8 +104,8 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, int16_t dChan, uint8_t ces) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Cfm on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Cfm on unconfigured dchan\n"); @@ -118,6 +118,7 @@ void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, Cn if (!sngisdn_info->spInstId) { ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); + sngisdn_info->spInstId = spInstId; g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); @@ -146,8 +147,8 @@ void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, Cn void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, int16_t dChan, uint8_t ces) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Cnst Ind on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Cnst Ind on unconfigured dchan\n"); @@ -160,6 +161,7 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C if (!sngisdn_info->spInstId) { ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); + sngisdn_info->spInstId = spInstId; g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); @@ -188,15 +190,15 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C memcpy(&sngisdn_event->event.cnStEvnt, cnStEvnt, sizeof(*cnStEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(spInstId != 0, "Received DISCONNECT with invalid id"); @@ -207,13 +209,6 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D ftdm_assert(0, "Inconsistent call states\n"); return; } - - if (!sngisdn_info->spInstId) { - ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); - sngisdn_info->spInstId = spInstId; - g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info; - ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); - } ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); @@ -229,7 +224,7 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D memcpy(&sngisdn_event->event.discEvnt, discEvnt, sizeof(*discEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -237,8 +232,8 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -251,7 +246,7 @@ void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Re ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received RELEASE/RELEASE COMPLETE (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_REL_IND; @@ -270,7 +265,7 @@ void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, In { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -283,7 +278,7 @@ void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, In ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received DATA IND suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_DAT_IND; @@ -302,7 +297,7 @@ void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, S { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -315,7 +310,7 @@ void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, S ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SSHL IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SSHL_IND; @@ -335,7 +330,7 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -348,7 +343,7 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SSHL CFM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SSHL_CFM; @@ -360,14 +355,14 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S memcpy(&sngisdn_event->event.ssHlEvnt, ssHlEvnt, sizeof(*ssHlEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -380,7 +375,7 @@ void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, R ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received RMRT IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RMRT_IND; @@ -392,7 +387,7 @@ void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, R memcpy(&sngisdn_event->event.rmRtEvnt, rmRtEvnt, sizeof(*rmRtEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -400,7 +395,7 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -413,7 +408,7 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received RESUME/RETRIEVE CFM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RMRT_CFM; @@ -425,7 +420,7 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R memcpy(&sngisdn_event->event.rmRtEvnt, rmRtEvnt, sizeof(*rmRtEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -433,7 +428,7 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -446,7 +441,7 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received FLOW CONTROL IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_FLC_IND; @@ -457,7 +452,7 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St memcpy(&sngisdn_event->event.staEvnt, staEvnt, sizeof(*staEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -466,7 +461,7 @@ void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Fa { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -478,7 +473,7 @@ void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Fa ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received FACILITY IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_FAC_IND; @@ -499,7 +494,7 @@ void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, St { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -512,7 +507,7 @@ void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, St ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received STATUS CONFIRM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_STA_CFM; @@ -532,7 +527,7 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received SERVICE IND (dChan:%d ces:%u)\n", dChan, ces); @@ -540,7 +535,7 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SRV_IND; @@ -550,7 +545,7 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces sngisdn_event->signal_data = signal_data; memcpy(&sngisdn_event->event.srvEvnt, srvEvnt, sizeof(*srvEvnt)); - ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -560,8 +555,8 @@ void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; - sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_span_data_t *signal_data = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received SERVICE CFM (dChan:%d ces:%u)\n", dChan, ces); @@ -569,7 +564,7 @@ void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SRV_CFM; @@ -588,8 +583,8 @@ void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; - sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_span_data_t *signal_data = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received RESTART IND (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); @@ -597,7 +592,7 @@ void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RST_IND; @@ -618,7 +613,7 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); @@ -626,7 +621,7 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RST_CFM; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 29e7994c87..5e37e0c684 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -73,8 +73,10 @@ void __inline__ clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info) sngisdn_info->glare.suInstId, sngisdn_info->glare.spInstId, sngisdn_info->suInstId, sngisdn_info->spInstId); - ftdm_mutex_lock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex); - g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_spInstIds[sngisdn_info->glare.spInstId]=NULL; + ftdm_mutex_lock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex); + if (sngisdn_info->glare.spInstId != sngisdn_info->spInstId) { + g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_spInstIds[sngisdn_info->glare.spInstId]=NULL; + } g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_suInstIds[sngisdn_info->glare.suInstId]=NULL; ftdm_mutex_unlock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex); @@ -427,6 +429,24 @@ void sngisdn_delayed_disconnect(void* p_sngisdn_info) return; } +void sngisdn_facility_timeout(void* p_sngisdn_info) +{ + sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info; + ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + + ftdm_mutex_lock(ftdmchan->mutex); + if (ftdmchan->state == FTDM_CHANNEL_STATE_GET_CALLERID) { + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Facility timeout reached proceeding with call (suId:%d suInstId:%u spInstId:%u)\n", + signal_data->cc_id, sngisdn_info->spInstId, sngisdn_info->suInstId); + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + + ftdm_mutex_unlock(ftdmchan->mutex); + return; +} + ftdm_status_t sngisdn_check_free_ids(void) { unsigned i; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index c8c8bc3dd1..44764295d4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -444,8 +444,8 @@ int ftmod_ss7_mtp3_gen_config(void) cfg.t.cfg.s.snGen.tmr.t21.enb = TRUE; /* t21 - waiting to restart traffic routed through adjacent SP */ cfg.t.cfg.s.snGen.tmr.t21.val = 650; # if (SS7_ANS92 || SS7_ANS88 || SS7_ANS96 || defined(TDS_ROLL_UPGRADE_SUPPORT)) - cfg.t.cfg.s.snGen.t26.enb = TRUE; /* t26 - waiting to repeat traffic restart waiting message for ANSI */ - cfg.t.cfg.s.snGen.t26.val = 600; + cfg.t.cfg.s.snGen.tmr.t26.enb = TRUE; /* t26 - waiting to repeat traffic restart waiting message for ANSI */ + cfg.t.cfg.s.snGen.tmr.t26.val = 600; # endif #endif @@ -744,10 +744,6 @@ int ftmod_ss7_mtp3_dlsap_config(int id) cfg.t.cfg.s.snDLSAP.msgPrior = 0; /* management message priority */ cfg.t.cfg.s.snDLSAP.lnkType = k->mtp3.linkType; /* link type ANSI, ITU, BICI or CHINA */ cfg.t.cfg.s.snDLSAP.upSwtch = k->mtp3.switchType; /* user part switch type */ -# if (SS7_ANS92 || SS7_ANS88 || SS7_ANS96 || SS7_CHINA) - cfg.t.cfg.s.snDLSAP.l2Type = LSN_MTP2_56KBPS; /* layer 2 type - 56kbps MTP2 link, 1.536Mbps MTP2 link or QSAAL link */ - cfg.t.cfg.s.snDLSAP.isCLink = FALSE; /* identifies if the link is a C type link.Required to check if sls has to be rotated.*/ -# endif cfg.t.cfg.s.snDLSAP.maxSLTtry = MAX_SLTM_RETRIES; /* maximun times to retry SLTM */ cfg.t.cfg.s.snDLSAP.p0QLen = 32; /* size of the priority 0 Q */ cfg.t.cfg.s.snDLSAP.p1QLen = 32; /* size of the priority 1 Q */ @@ -775,17 +771,46 @@ int ftmod_ss7_mtp3_dlsap_config(int id) cfg.t.cfg.s.snDLSAP.selector = 0; /* lower layer selector */ cfg.t.cfg.s.snDLSAP.mem.region = S_REG; /* memory region id */ cfg.t.cfg.s.snDLSAP.mem.pool = S_POOL; /* memory pool id */ -#if( SS7_ANS92 || SS7_ANS88 || SS7_ANS96 || SS7_CHINA ) - cfg.t.cfg.s.snDLSAP.dpcLen = DPC24; /* dpc length 24 bits */ -#else - cfg.t.cfg.s.snDLSAP.dpcLen = DPC14; /* dpc length 14 bits */ -#endif cfg.t.cfg.s.snDLSAP.spId = k->mtp3.mtp2Id ;/* service provider id */ -#if (SS7_ITU88 || SS7_CHINA || SS7_TTC || SS7_NTT || SS7_BICI ) - cfg.t.cfg.s.snDLSAP.flushContFlag = FALSE; /* flush continue handling */ -#else - cfg.t.cfg.s.snDLSAP.flushContFlag = TRUE; /* flush continue handling */ -#endif + + switch (k->mtp3.linkType) { + /**************************************************************************/ + case (LSN_SW_ANS): + case (LSN_SW_ANS96): + case (LSN_SW_CHINA): + cfg.t.cfg.s.snDLSAP.dpcLen = DPC24; /* dpc length 24 bits */ + cfg.t.cfg.s.snDLSAP.l2Type = LSN_MTP2_56KBPS; /* layer 2 type - 56kbps MTP2 link, 1.536Mbps MTP2 link or QSAAL link */ + cfg.t.cfg.s.snDLSAP.isCLink = FALSE; /* identifies if the link is a C type link.Required to check if sls has to be rotated.*/ + break; + /**************************************************************************/ + case (LSN_SW_ITU): + cfg.t.cfg.s.snDLSAP.dpcLen = DPC14; /* dpc length 14 bits */ + break; + /**************************************************************************/ + default: + cfg.t.cfg.s.snDLSAP.dpcLen = DPC14; /* dpc length 14 bits */ + break; + /**************************************************************************/ + } /* switch (k->mtp3.linkType) */ + + switch (k->mtp3.linkType) { + /**************************************************************************/ + case (LSN_SW_ANS): + case (LSN_SW_ANS96): + cfg.t.cfg.s.snDLSAP.flushContFlag = TRUE; /* flush continue handling */ + break; + /**************************************************************************/ + case (LSN_SW_ITU): + case (LSN_SW_CHINA): + cfg.t.cfg.s.snDLSAP.flushContFlag = FALSE; /* flush continue handling */ + break; + /**************************************************************************/ + default: + cfg.t.cfg.s.snDLSAP.flushContFlag = FALSE; /* flush continue handling */ + break; + /**************************************************************************/ + } /* switch (k->mtp3.linkType) */ + cfg.t.cfg.s.snDLSAP.tmr.t1.enb = TRUE; /* t1 - delay to avoid missequencing on changeover */ cfg.t.cfg.s.snDLSAP.tmr.t1.val = k->mtp3.t1; cfg.t.cfg.s.snDLSAP.tmr.t2.enb = TRUE; /* t2 - waiting for changeover ack */ @@ -1209,12 +1234,12 @@ int ftmod_ss7_isup_ckt_config(int id) cfg.t.cfg.s.siCir.typeCntrl = k->typeCntrl; /* type of control */ cfg.t.cfg.s.siCir.contReq = FALSE; /* continuity check required */ #if (SI_218_COMP || SS7_ANS88 || SS7_ANS92 || SS7_ANS95 || SS7_BELL) - cfg.t.cfg.s.siCir.firstCic =; /* First cic in the circuit group */ - cfg.t.cfg.s.siCir.numCir =; /* Number of circuits in the circuit group */ + cfg.t.cfg.s.siCir.firstCic = 1; /* First cic in the circuit group */ + cfg.t.cfg.s.siCir.numCir = 24; /* Number of circuits in the circuit group */ cfg.t.cfg.s.siCir.nonSS7Con = TRUE; /* connecting to non SS7 network */ - cfg.t.cfg.s.siCir.outTrkGrpN =; /* outgoing trunk group number (For EXM) */ - cfg.t.cfg.s.siCir.cvrTrkClli =; /* Trunk Group number (For CVR validation) */ - cfg.t.cfg.s.siCir.clli =; /* common language location identifier */ + cfg.t.cfg.s.siCir.outTrkGrpN.length = 0; /* outgoing trunk group number (For EXM) */ + cfg.t.cfg.s.siCir.cvrTrkClli.length = 0; /* Trunk Group number (For CVR validation) */ + cfg.t.cfg.s.siCir.clli.length = 0; /* common language location identifier */ #endif cfg.t.cfg.s.siCir.cirTmr.t3.enb = TRUE; /* t3 timer - overload received */ cfg.t.cfg.s.siCir.cirTmr.t3.val = k->t3; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index f0cfa0237a..0c3dcffec0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -71,6 +71,8 @@ ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_status_t handle_local_blk(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_local_ubl(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -898,12 +900,12 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case SIT_STA_CGBREQ: /* CGB request */ SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGB\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGUREQ: /* CGU request */ SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGU\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + handle_cgu_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGQRYREQ: /* circuit group query request */ @@ -913,7 +915,7 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case SIT_STA_CGBRSP: /* mntc. oriented CGB response */ SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx mntc CGB\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGURSP: /* mntc. oriented CGU response */ @@ -1012,8 +1014,8 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ break; /**************************************************************************/ case SIT_STA_CGBINFOIND: /* circuit grp blking ind , no resp req */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGB no resp req\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + /*SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGB no resp req\n");*/ +/* handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);*/ break; /**************************************************************************/ case SIT_STA_LMCQMINFOREQ: /* when LM requests ckt grp query */ @@ -1989,6 +1991,265 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit return FTDM_SUCCESS; } +/******************************************************************************/ +ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = NULL; + ftdm_channel_t *ftdmchan = NULL; + int range; + uint8_t status[255]; + int blockType = 0; + int byte = 0; + int bit = 0; + int x; + + memset(&status[0], '\0', sizeof(status)); + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* grab the span info */ + sngss7_span = ftdmchan->span->mod_data; + + /* figure out what type of block needs to be applied */ + if ((siStaEvnt->cgsmti.eh.pres == PRSNT_NODEF) && (siStaEvnt->cgsmti.typeInd.pres == PRSNT_NODEF)) { + blockType = siStaEvnt->cgsmti.typeInd.val; + } else { + SS7_ERROR("Received CGB with no circuit group supervision value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the range value */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.range.pres == PRSNT_NODEF)) { + range = siStaEvnt->rangStat.range.val; + } else { + SS7_ERROR("Received CGB with no range value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the status field */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.status.pres == PRSNT_NODEF)) { + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + status[x] = siStaEvnt->rangStat.status.val[x]; + } + } else { + SS7_ERROR("Received CGB with no status value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* save the circuit, range and status */ + sngss7_span->rx_cgb.circuit = circuit; + sngss7_span->rx_cgb.range = range; + sngss7_span->rx_cgb.type = blockType; + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + sngss7_span->rx_cgb.status[x] = status[x]; + } + + /* loop over the cics starting from circuit until range+1 */ + for (x = circuit; x < (circuit + range + 1); x++) { + /* grab the circuit in question */ + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + break; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_ASSERT; + }; + +#if 1 + SS7_ERROR("KONRAD -> circuit=%d, byte=%d, bit=%d, status[byte]=%d, math=%d\n", + x, + byte, + bit, + status[byte], + (status[byte] & (1 << bit))); +#endif + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_set_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_set_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + + } /* for (x = circuit; x < (circuit + range + 1); x++) */ + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + ft_to_sngss7_cgba(ftdmchan); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = NULL; + ftdm_channel_t *ftdmchan = NULL; + int range; + uint8_t status[255]; + int blockType = 0; + int byte = 0; + int bit = 0; + int x; + + memset(&status[0], '\0', sizeof(status)); + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* grab the span info */ + sngss7_span = ftdmchan->span->mod_data; + + /* figure out what type of block needs to be applied */ + if ((siStaEvnt->cgsmti.eh.pres == PRSNT_NODEF) && (siStaEvnt->cgsmti.typeInd.pres == PRSNT_NODEF)) { + blockType = siStaEvnt->cgsmti.typeInd.val; + } else { + SS7_ERROR("Received CGB with no circuit group supervision value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the range value */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.range.pres == PRSNT_NODEF)) { + range = siStaEvnt->rangStat.range.val; + } else { + SS7_ERROR("Received CGB with no range value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the status field */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.status.pres == PRSNT_NODEF)) { + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + status[x] = siStaEvnt->rangStat.status.val[x]; + } + } else { + SS7_ERROR("Received CGB with no status value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* save the circuit, range and status */ + sngss7_span->rx_cgu.circuit = circuit; + sngss7_span->rx_cgu.range = range; + sngss7_span->rx_cgu.type = blockType; + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + sngss7_span->rx_cgu.status[x] = status[x]; + } + + /* loop over the cics starting from circuit until range+1 */ + for (x = circuit; x < (circuit + range + 1); x++) { + /* grab the circuit in question */ + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + break; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_ASSERT; + }; + + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } /* */ + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + + } /* for (x = circuit; x < (circuit + range + 1); x++) */ + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + ft_to_sngss7_cgua(ftdmchan); + + return FTDM_SUCCESS; +} /******************************************************************************/ /* For Emacs: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 66efe1ab12..9986b29b2c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -272,10 +272,8 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) ftdm_interrupt_t *ftdm_sangoma_ss7_int[2]; ftdm_span_t *ftdmspan = (ftdm_span_t *) obj; ftdm_channel_t *ftdmchan = NULL; - sngss7_chan_data_t *sngss7_info = NULL; sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; - int i; ftdm_log (FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u started.\n", ftdmspan->span_id); @@ -344,73 +342,11 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /**********************************************************************/ } /* switch ((ftdm_interrupt_wait(ftdm_sangoma_ss7_int, 100))) */ - /* extract the span data structure */ - sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; - /* check if there is a GRS being processed on the span */ if (sngss7_span->rx_grs.range > 0) { - ftdm_log(FTDM_LOG_DEBUG, "Found Rx GRS on span %d...checking circuits\n", ftdmspan->span_id); - /*SS7_DEBUG("Found Rx GRS on span %d...checking circuits\n", ftdmspan->span_id);*/ - - /* check all the circuits in the range to see if they are done resetting */ - for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { - - /* extract the channel in question */ - if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); - SS7_ASSERT; - } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - - /* check if there is a state change pending on the channel */ - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - /* check the state to the GRP_RESET_RX_DN flag */ - if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) { - /* this channel is still resetting...do nothing */ - goto GRS_UNLOCK_ALL; - } /* if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) */ - } else { - /* state change pending */ - goto GRS_UNLOCK_ALL; - } - } /* for ( i = circuit; i < (circuit + range + 1); i++) */ - - SS7_DEBUG("All circuits out of reset for GRS: circuit=%d, range=%d\n", - sngss7_span->rx_grs.circuit, - sngss7_span->rx_grs.range); - - /* check all the circuits in the range to see if they are done resetting */ - for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { - - /* extract the channel in question */ - if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n",i); - SS7_ASSERT; - } - - /* throw the GRP reset flag complete flag */ - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT); - - /* move the channel to the down state */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - - } /* for ( i = circuit; i < (circuit + range + 1); i++) */ - -GRS_UNLOCK_ALL: - for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { - /* extract the channel in question */ - if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); - SS7_ASSERT; - } - - /* unlock the channel */ - ftdm_mutex_unlock(ftdmchan->mutex); - } - - } /* if (ftdmspan->grs.range > 0) */ + /* check if the rx_grs has cleared */ + check_if_rx_grs_processed(ftdmspan); + } /* if (sngss7_span->rx_grs.range > 0) */ } /* master while loop */ /* clear the IN_THREAD flag so that we know the thread is done */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 050f59e00e..c9dbfb3ac8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -139,7 +139,6 @@ typedef struct sng_mtp_link { uint32_t t23; uint32_t t24; uint32_t t25; - uint32_t t26; uint32_t t27; uint32_t t28; uint32_t t29; @@ -188,6 +187,7 @@ typedef struct sng_route { uint32_t t19; uint32_t t21; uint32_t t25; + uint32_t t26; } sng_route_t; typedef struct sng_isup_intf { @@ -329,6 +329,8 @@ typedef struct sngss7_glare_data { typedef struct sngss7_group_data { uint32_t circuit; uint32_t range; + uint8_t status[255]; + uint8_t type; }sngss7_group_data_t; typedef struct sngss7_chan_data { @@ -348,6 +350,10 @@ typedef struct sngss7_span_data { ftdm_sched_t *sched; sngss7_group_data_t rx_grs; sngss7_group_data_t tx_grs; + sngss7_group_data_t rx_cgb; + sngss7_group_data_t tx_cgb; + sngss7_group_data_t rx_cgu; + sngss7_group_data_t tx_cgu; ftdm_queue_t *event_queue; }sngss7_span_data_t; @@ -376,8 +382,8 @@ typedef struct sngss7_event_data typedef enum { - FLAG_RESET_RX = (1 << 0), - FLAG_RESET_TX = (1 << 1), + FLAG_RESET_RX = (1 << 0), + FLAG_RESET_TX = (1 << 1), FLAG_RESET_SENT = (1 << 2), FLAG_RESET_TX_RSP = (1 << 3), FLAG_GRP_RESET_RX = (1 << 4), @@ -387,27 +393,25 @@ typedef enum { FLAG_GRP_RESET_TX = (1 << 8), FLAG_GRP_RESET_SENT = (1 << 9), FLAG_GRP_RESET_TX_RSP = (1 << 10), - FLAG_REMOTE_REL = (1 << 11), - FLAG_LOCAL_REL = (1 << 12), - FLAG_GLARE = (1 << 13), - FLAG_INFID_RESUME = (1 << 14), - FLAG_INFID_PAUSED = (1 << 15), + FLAG_REMOTE_REL = (1 << 11), + FLAG_LOCAL_REL = (1 << 12), + FLAG_GLARE = (1 << 13), + FLAG_INFID_RESUME = (1 << 14), + FLAG_INFID_PAUSED = (1 << 15), FLAG_CKT_UCIC_BLOCK = (1 << 16), FLAG_CKT_UCIC_UNBLK = (1 << 17), FLAG_CKT_LC_BLOCK_RX = (1 << 18), FLAG_CKT_LC_UNBLK_RX = (1 << 19), FLAG_CKT_MN_BLOCK_RX = (1 << 20), - FLAG_CKT_MN_BLOCK_TX = (1 << 21), - FLAG_CKT_MN_UNBLK_RX = (1 << 22), + FLAG_CKT_MN_UNBLK_RX = (1 << 21), + FLAG_CKT_MN_BLOCK_TX = (1 << 22), FLAG_CKT_MN_UNBLK_TX = (1 << 23), FLAG_GRP_HW_BLOCK_RX = (1 << 24), FLAG_GRP_HW_BLOCK_TX = (1 << 25), FLAG_GRP_MN_BLOCK_RX = (1 << 26), FLAG_GRP_MN_BLOCK_TX = (1 << 27), - FLAG_GRP_HW_UNBLK_RX = (1 << 28), - FLAG_GRP_HW_UNBLK_TX = (1 << 29), - FLAG_GRP_MN_UNBLK_RX = (1 << 30), - FLAG_GRP_MN_UNBLK_TX = (1 << 31) + FLAG_GRP_HW_UNBLK_TX = (1 << 28), + FLAG_GRP_MN_UNBLK_TX = (1 << 29) } flag_t; /******************************************************************************/ @@ -465,6 +469,8 @@ void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan); void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan); void ft_to_sngss7_gra(ftdm_channel_t *ftdmchan); void ft_to_sngss7_grs(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan); void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); @@ -524,6 +530,8 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa void handle_isup_t35(void *userdata); ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data); + +ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan); /******************************************************************************/ /* MACROS *********************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 4fac251c17..079f5e3e22 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -42,24 +42,27 @@ /******************************************************************************/ /* PROTOTYPES *****************************************************************/ -void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rlc (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_iam(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_acm(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_anm(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rel(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rlc(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rsc (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rsca (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rsc(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rsca(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_blo (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_bla (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_ubl (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_uba (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_blo(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_bla(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_ubl(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_uba(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_lpa (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_lpa(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_gra (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_gra(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_grs(ftdm_channel_t * ftdmchan); + +void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -113,6 +116,56 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) iam.txMedReq.eh.pres = PRSNT_NODEF; iam.txMedReq.trMedReq.pres = PRSNT_NODEF; iam.txMedReq.trMedReq.val = ftdmchan->caller_data.bearer_capability; + + if ((g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].switchType == LSI_SW_ANS88) || + (g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].switchType == LSI_SW_ANS92) || + (g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].switchType == LSI_SW_ANS95)) { + + iam.usrServInfoA.eh.pres = PRSNT_NODEF; + + iam.usrServInfoA.infoTranCap.pres = PRSNT_NODEF; + switch (ftdmchan->caller_data.bearer_capability) { + /**********************************************************************/ + case (FTDM_BEARER_CAP_SPEECH): + iam.usrServInfoA.infoTranCap.val = 0x0; /* speech as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + case (FTDM_BEARER_CAP_64K_UNRESTRICTED): + iam.usrServInfoA.infoTranCap.val = 0x8; /* unrestricted digital as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + case (FTDM_BEARER_CAP_3_1KHZ_AUDIO): + iam.usrServInfoA.infoTranCap.val = 0x10; /* 3.1kHz audio as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + default: + SS7_ERROR_CHAN(ftdmchan, "Unknown Bearer capability falling back to speech%s\n", " "); + iam.usrServInfoA.infoTranCap.val = 0x0; /* speech as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + } /* switch (ftdmchan->caller_data.bearer_capability) */ + + iam.usrServInfoA.cdeStand.pres = PRSNT_NODEF; + iam.usrServInfoA.cdeStand.val = 0x0; /* ITU-T standardized coding */ + iam.usrServInfoA.tranMode.pres = PRSNT_NODEF; + iam.usrServInfoA.tranMode.val = 0x0; /* circuit mode */ + iam.usrServInfoA.infoTranRate0.pres = PRSNT_NODEF; + iam.usrServInfoA.infoTranRate0.val = 0x10; /* 64kbps origination to destination */ + iam.usrServInfoA.infoTranRate1.pres = PRSNT_NODEF; + iam.usrServInfoA.infoTranRate1.val = 0x10; /* 64kbps destination to origination */ + iam.usrServInfoA.chanStruct.pres = PRSNT_NODEF; + iam.usrServInfoA.chanStruct.val = 0x1; /* 8kHz integrity */ + iam.usrServInfoA.config.pres = PRSNT_NODEF; + iam.usrServInfoA.config.val = 0x0; /* point to point configuration */ + iam.usrServInfoA.establish.pres = PRSNT_NODEF; + iam.usrServInfoA.establish.val = 0x0; /* on demand */ + iam.usrServInfoA.symmetry.pres = PRSNT_NODEF; + iam.usrServInfoA.symmetry.val = 0x0; /* bi-directional symmetric */ + iam.usrServInfoA.usrInfLyr1Prot.pres = PRSNT_NODEF; + iam.usrServInfoA.usrInfLyr1Prot.val = 0x2; /* G.711 ulaw */ + iam.usrServInfoA.rateMultiplier.pres = PRSNT_NODEF; + iam.usrServInfoA.rateMultiplier.val = 0x1; /* 1x rate multipler */ + } /* if ANSI */ /* copy down the called number information */ copy_cdPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cdPtyNum); @@ -126,7 +179,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) sngss7_info->circuit->id, &iam, 0); - + SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx IAM\n"); SS7_FUNC_TRACE_EXIT (__FUNCTION__); @@ -463,7 +516,7 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan) SiStaEvnt grs; - memset (&grs, 0x0, sizeof (grs)); + memset (&grs, 0x0, sizeof(grs)); grs.rangStat.eh.pres = PRSNT_NODEF; grs.rangStat.range.pres = PRSNT_NODEF; @@ -485,6 +538,101 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan) return; } +/******************************************************************************/ +void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan) +{ + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_span_data_t *sngss7_span = ftdmchan->span->mod_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + int x = 0; + + SiStaEvnt cgba; + + memset (&cgba, 0x0, sizeof(cgba)); + + /* fill in the circuit group supervisory message */ + cgba.cgsmti.eh.pres = PRSNT_NODEF; + cgba.cgsmti.typeInd.pres = PRSNT_NODEF; + cgba.cgsmti.typeInd.val = sngss7_span->rx_cgb.type; + + cgba.rangStat.eh.pres = PRSNT_NODEF; + /* fill in the range */ + cgba.rangStat.range.pres = PRSNT_NODEF; + cgba.rangStat.range.val = sngss7_span->rx_cgb.range; + /* fill in the status */ + cgba.rangStat.status.pres = PRSNT_NODEF; + cgba.rangStat.status.len = ((sngss7_span->rx_cgb.range + 1) >> 3) + (((sngss7_span->rx_cgb.range + 1) & 0x07) ? 1 : 0); + for(x = 0; x < cgba.rangStat.status.len; x++){ + cgba.rangStat.status.val[x] = sngss7_span->rx_cgb.status[x]; + } + + sng_cc_sta_request (1, + 0, + 0, + sngss7_span->rx_cgb.circuit, + 0, + SIT_STA_CGBRSP, + &cgba); + + SS7_INFO_CHAN(ftdmchan, "Tx CGBA (%d:%d)\n", + sngss7_info->circuit->cic, + (sngss7_info->circuit->cic + sngss7_span->rx_cgb.range)); + + /* clean out the saved data */ + memset(&sngss7_span->rx_cgb, 0x0, sizeof(sngss7_group_data_t)); + + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan) +{ + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_span_data_t *sngss7_span = ftdmchan->span->mod_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + int x = 0; + + SiStaEvnt cgua; + + memset (&cgua, 0x0, sizeof(cgua)); + + /* fill in the circuit group supervisory message */ + cgua.cgsmti.eh.pres = PRSNT_NODEF; + cgua.cgsmti.typeInd.pres = PRSNT_NODEF; + cgua.cgsmti.typeInd.val = sngss7_span->rx_cgu.type; + + cgua.rangStat.eh.pres = PRSNT_NODEF; + /* fill in the range */ + cgua.rangStat.range.pres = PRSNT_NODEF; + cgua.rangStat.range.val = sngss7_span->rx_cgu.range; + /* fill in the status */ + cgua.rangStat.status.pres = PRSNT_NODEF; + cgua.rangStat.status.len = ((sngss7_span->rx_cgu.range + 1) >> 3) + (((sngss7_span->rx_cgu.range + 1) & 0x07) ? 1 : 0); + for(x = 0; x < cgua.rangStat.status.len; x++){ + cgua.rangStat.status.val[x] = sngss7_span->rx_cgu.status[x]; + } + + sng_cc_sta_request (1, + 0, + 0, + sngss7_span->rx_cgu.circuit, + 0, + SIT_STA_CGURSP, + &cgua); + + SS7_INFO_CHAN(ftdmchan, "Tx CGUA (%d:%d)\n", + sngss7_info->circuit->cic, + (sngss7_info->circuit->cic + sngss7_span->rx_cgu.range)); + + /* clean out the saved data */ + memset(&sngss7_span->rx_cgu, 0x0, sizeof(sngss7_group_data_t)); + + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 97957f3c82..4ec57fe049 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -57,6 +57,7 @@ unsigned long get_unique_id(void); ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan); +ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -451,6 +452,78 @@ unsigned long get_unique_id(void) } /******************************************************************************/ +ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan) +{ + ftdm_channel_t *ftdmchan = NULL; + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; + int i; + + ftdm_log(FTDM_LOG_DEBUG, "Found Rx GRS on span %d...checking circuits\n", ftdmspan->span_id); + + /* check all the circuits in the range to see if they are done resetting */ + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); + SS7_ASSERT; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a state change pending on the channel */ + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + /* check the state to the GRP_RESET_RX_DN flag */ + if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) { + /* this channel is still resetting...do nothing */ + goto GRS_UNLOCK_ALL; + } /* if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) */ + } else { + /* state change pending */ + goto GRS_UNLOCK_ALL; + } + } /* for ( i = circuit; i < (circuit + range + 1); i++) */ + + SS7_DEBUG("All circuits out of reset for GRS: circuit=%d, range=%d\n", + sngss7_span->rx_grs.circuit, + sngss7_span->rx_grs.range); + + /* check all the circuits in the range to see if they are done resetting */ + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n",i); + SS7_ASSERT; + } + + /* throw the GRP reset flag complete flag */ + sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT); + + /* move the channel to the down state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + } /* for ( i = circuit; i < (circuit + range + 1); i++) */ + +GRS_UNLOCK_ALL: + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); + SS7_ASSERT; + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ + /******************************************************************************/ /* For Emacs: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index aa639d1c3a..4ebf3b95fd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -551,6 +551,15 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * } else if (!strcasecmp(parm->val, "INDIA")) { mtpLink->mtp3.switchType = LSI_SW_INDIA; SS7_DEBUG("\tFoundmtpLink->switchType = \"INDIA\"\n"); + } else if (!strcasecmp(parm->val, "ansi88")) { + mtpLink->mtp3.switchType = LSI_SW_ANS88; + SS7_DEBUG("\tFoundmtpLink->switchType = \"ANSI88\"\n"); + } else if (!strcasecmp(parm->val, "ansi92")) { + mtpLink->mtp3.switchType = LSI_SW_ANS92; + SS7_DEBUG("\tFoundmtpLink->switchType = \"ANSI92\"\n"); + } else if (!strcasecmp(parm->val, "ansi95")) { + mtpLink->mtp3.switchType = LSI_SW_ANS95; + SS7_DEBUG("\tFoundmtpLink->switchType = \"ANSI95\"\n"); } else { SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -1159,6 +1168,11 @@ static int ftmod_ss7_fill_in_mtp3_route(sng_route_t *mtp3_route) } else { g_ftdm_sngss7_data.cfg.mtpRoute[i].t25 = 100; } + if (mtp3_route->t26 != 0) { + g_ftdm_sngss7_data.cfg.mtpRoute[i].t26 = mtp3_route->t26; + } else { + g_ftdm_sngss7_data.cfg.mtpRoute[i].t26 = 100; + } return 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index d8b3c7d40d..be99f94aff 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -259,7 +259,10 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start chan->physical_chan_id = x; chan->rate = 8000; - if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_B) { + if (type == FTDM_CHAN_TYPE_FXS + || type == FTDM_CHAN_TYPE_FXO + || type == FTDM_CHAN_TYPE_CAS + || type == FTDM_CHAN_TYPE_B) { int err; dtmf = "software"; diff --git a/libs/libdingaling/src/libdingaling.c b/libs/libdingaling/src/libdingaling.c index ef6e7447a1..11a9a8a5b8 100644 --- a/libs/libdingaling/src/libdingaling.c +++ b/libs/libdingaling/src/libdingaling.c @@ -1974,10 +1974,19 @@ unsigned int ldl_session_terminate(ldl_session_t *session) { iks *iq, *sess; unsigned int id; + apr_hash_t *hash = session->handle->sessions; new_session_iq(session, &iq, &sess, &id, "terminate"); schedule_packet(session->handle, id, iq, LDL_RETRY); + if (session->id) { + apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL); + } + + if (session->them) { + apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL); + } + return id; } @@ -2471,6 +2480,11 @@ int ldl_handle_running(ldl_handle_t *handle) } +void ldl_session_set_gateway(ldl_session_t *session) +{ + ldl_set_flag(session, LDL_FLAG_GATEWAY); +} + int ldl_session_gateway(ldl_session_t *session) { return ldl_test_flag(session, LDL_FLAG_GATEWAY) ? 1 : 0; diff --git a/libs/libdingaling/src/libdingaling.h b/libs/libdingaling/src/libdingaling.h index d78643810c..c32b9363d9 100644 --- a/libs/libdingaling/src/libdingaling.h +++ b/libs/libdingaling/src/libdingaling.h @@ -593,6 +593,7 @@ ldl_status ldl_handle_init(ldl_handle_t **handle, void ldl_handle_run(ldl_handle_t *handle); int ldl_session_gateway(ldl_session_t *handle); +void ldl_session_set_gateway(ldl_session_t *session); /*! \brief Stop a libDingaLing handle diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index 6e4ee0a704..e56753e07d 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -207,6 +207,13 @@ struct t30_state_s /*! \brief This is only used in full duplex (e.g. ISDN) modes. */ int timer_t8; + /* These fields are guessed based on compiler error forensics, I added them to fix the build -anthm */ + int remote_interrupts_allowed; + int rtp_events; + int rtn_events; + int retransmit_capable; + /* end guessed fields */ + /*! \brief TRUE once the far end FAX entity has been detected. */ int far_end_detected; diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index 9b01d3b62b..9df7321abd 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -682,6 +682,8 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t); \param state TRUE to enable interrupt request, else FALSE. */ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state); +SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state); + #if defined(__cplusplus) } #endif diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 97c7ed8cc7..45387b8585 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -2377,6 +2377,8 @@ static int send_response_to_pps(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ +#define VET_ALL_FCD_FRAMES + static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) { int page; @@ -2387,6 +2389,10 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) int frame_no; int first_bad_frame; int image_ended; +#if defined(VET_ALL_FCD_FRAMES) + int first; + int expected_len; +#endif if (len < 7) { @@ -2469,12 +2475,35 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) /* Build a bit map of which frames we now have stored OK */ first_bad_frame = 256; +#if defined(VET_ALL_FCD_FRAMES) + first = TRUE; + expected_len = 256; +#endif for (i = 0; i < 32; i++) { s->ecm_frame_map[i + 3] = 0; for (j = 0; j < 8; j++) { frame_no = (i << 3) + j; +#if defined(VET_ALL_FCD_FRAMES) + if (s->ecm_len[frame_no] >= 0) + { + if (frame_no < s->ecm_frames - 1) + { + if (first) + { + if (s->ecm_len[frame_no] == 64) + expected_len = 64; + first = FALSE; + } + if (s->ecm_len[frame_no] != expected_len) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length ECM frame - %d\n", s->ecm_len[frame_no]); + s->ecm_len[frame_no] = -1; + } + } + } +#endif if (s->ecm_len[frame_no] < 0) { s->ecm_frame_map[i + 3] |= (1 << j); @@ -2524,14 +2553,18 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) switch (s->last_pps_fcf2) { - case T30_NULL: - case T30_EOP: - case T30_PRI_EOP: - case T30_EOM: - case T30_PRI_EOM: - case T30_EOS: - case T30_MPS: case T30_PRI_MPS: + case T30_PRI_EOM: + case T30_PRI_EOP: + if (s->remote_interrupts_allowed) + { + } + /* Fall through */ + case T30_NULL: + case T30_MPS: + case T30_EOM: + case T30_EOS: + case T30_EOP: if (s->receiver_not_ready_count > 0) { s->receiver_not_ready_count--; @@ -2635,7 +2668,13 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len) switch (s->state) { case T30_STATE_F_DOC_ECM: - if (len <= 4 + 256) + if (len > 4 + 256) + { + /* For other frame types we kill the call on an unexpected frame length. For FCD frames it is better to just ignore + the frame, and let retries sort things out. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len); + } + else { frame_no = msg[3]; /* Just store the actual image data, and record its length */ @@ -2645,10 +2684,6 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len) /* In case we are just after a CTC/CTR exchange, which kicked us back to long training */ s->short_train = TRUE; } - else - { - unexpected_frame_length(s, msg, len); - } /* We have received something, so any missing carrier status is out of date */ if (s->current_status == T30_ERR_RX_NOCARRIER) s->current_status = T30_ERR_OK; @@ -2677,6 +2712,7 @@ static void process_rx_rcp(t30_state_t *s, const uint8_t *msg, int len) case T30_STATE_F_POST_DOC_ECM: /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance of receiving a correct one. */ + timer_t2_start(s); break; default: unexpected_non_final_frame(s, msg, len); @@ -3063,6 +3099,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int case T30_DCS: process_rx_dcs(s, msg, len); break; + case T30_PRI_MPS: + if (s->remote_interrupts_allowed) + { + } + /* Fall through */ case T30_MPS: /* Treat this as a bad quality page. */ if (s->phase_d_handler) @@ -3072,16 +3113,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; - case T30_PRI_MPS: - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) + case T30_PRI_EOM: + if (s->remote_interrupts_allowed) { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); } - s->next_rx_step = msg[2] & 0xFE; - set_state(s, T30_STATE_III_Q_RTN); - break; + /* Fall through */ case T30_EOM: case T30_EOS: /* Treat this as a bad quality page. */ @@ -3093,16 +3129,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; - case T30_PRI_EOM: - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) + case T30_PRI_EOP: + if (s->remote_interrupts_allowed) { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); } - s->next_rx_step = T30_PRI_EOM; - set_state(s, T30_STATE_III_Q_RTN); - break; + /* Fall through */ case T30_EOP: /* Treat this as a bad quality page. */ if (s->phase_d_handler) @@ -3112,16 +3143,6 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; - case T30_PRI_EOP: - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - s->next_rx_step = msg[2] & 0xFE; - set_state(s, T30_STATE_III_Q_RTN); - break; case T30_DCN: s->current_status = T30_ERR_RX_DCNDATA; disconnect(s); @@ -3148,6 +3169,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PRI_MPS: + if (s->remote_interrupts_allowed) + { + } + /* Fall through */ case T30_MPS: s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); @@ -3179,41 +3205,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; } break; - case T30_PRI_MPS: - s->next_rx_step = fcf; - switch (copy_quality(s)) + case T30_PRI_EOM: + if (s->remote_interrupts_allowed) { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - set_state(s, T30_STATE_III_Q_RTN); - break; } - break; + /* Fall through */ case T30_EOM: case T30_EOS: s->next_rx_step = fcf; @@ -3247,41 +3243,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; } break; - case T30_PRI_EOM: - s->next_rx_step = fcf; - switch (copy_quality(s)) + case T30_PRI_EOP: + if (s->remote_interrupts_allowed) { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - set_state(s, T30_STATE_III_Q_RTN); - break; } - break; + /* Fall through */ case T30_EOP: s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); @@ -3312,41 +3278,6 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; } break; - case T30_PRI_EOP: - s->next_rx_step = fcf; - switch (copy_quality(s)) - { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - set_state(s, T30_STATE_III_Q_RTN); - break; - } - break; case T30_DCN: s->current_status = T30_ERR_RX_DCNFAX; disconnect(s); @@ -3384,21 +3315,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t * case T4_RCP: /* Return to control for partial page. These might come through with or without the final frame tag. Here we deal with the "final frame tag" case. */ - if (s->state == T30_STATE_F_DOC_ECM) - { - /* Return to control for partial page */ - set_state(s, T30_STATE_F_POST_DOC_ECM); - queue_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - /* We have received something, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - s->current_status = T30_ERR_OK; - } - else - { - /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance - of receiving a correct one. */ - } + process_rx_rcp(s, msg, len); break; case T30_EOR: if (len != 4) @@ -3413,7 +3330,10 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t * case T30_PRI_EOP: case T30_PRI_EOM: case T30_PRI_MPS: - /* TODO: Alert operator */ + if (s->remote_interrupts_allowed) + { + /* TODO: Alert operator */ + } /* Fall through */ case T30_NULL: case T30_EOP: @@ -3651,11 +3571,22 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PIP: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_MCF: switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3668,8 +3599,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) set_state(s, T30_STATE_I); queue_phase(s, T30_PHASE_C_NON_ECM_TX); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -3678,8 +3609,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3690,13 +3621,11 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) } break; case T30_RTP: -#if 0 s->rtp_events++; -#endif switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3717,8 +3646,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) queue_phase(s, T30_PHASE_B_TX); restart_sending_document(s); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -3727,8 +3656,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) /* TODO: should go back to T, and resend */ return_to_phase_b(s, TRUE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3737,20 +3666,27 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) break; } break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_RTN: -#if 0 s->rtn_events++; -#endif switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: s->retries = 0; if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); -#if 0 if (!s->retransmit_capable) -#endif { /* Send the next page, regardless of the problem with the current one. */ if (tx_start_page(s)) @@ -3771,29 +3707,26 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) queue_phase(s, T30_PHASE_B_TX); restart_sending_document(s); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: s->retries = 0; if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); -#if 0 if (s->retransmit_capable) { /* Wait for DIS */ } else -#endif { return_to_phase_b(s, TRUE); } break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: s->retries = 0; if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); -#if 0 if (s->retransmit_capable) { /* Send fresh training, and then repeat the last page */ @@ -3809,36 +3742,19 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) restart_sending_document(s); } else -#endif { send_dcn(s); } break; } break; - case T30_PIP: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_DCN: switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: - case T30_EOM: case T30_PRI_EOM: + case T30_MPS: + case T30_EOM: case T30_EOS: /* Unexpected DCN after EOM, EOS or MPS sequence */ s->current_status = T30_ERR_RX_DCNPHD; @@ -4019,8 +3935,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4036,8 +3952,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le send_first_ecm_frame(s); } break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -4046,8 +3962,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4094,6 +4010,17 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PIP: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_MCF: s->retries = 0; s->timer_t5 = 0; @@ -4112,8 +4039,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4129,8 +4056,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) send_first_ecm_frame(s); } break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -4139,8 +4066,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4158,22 +4085,6 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) set_state(s, T30_STATE_IV_PPS_RNR); send_rr(s); break; - case T30_PIP: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_PPR: process_rx_ppr(s, msg, len); break; @@ -4187,6 +4098,17 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4203,6 +4125,17 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PIP: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_MCF: s->retries = 0; s->timer_t5 = 0; @@ -4221,8 +4154,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4238,8 +4171,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len send_first_ecm_frame(s); } break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -4248,8 +4181,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4267,22 +4200,6 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len set_state(s, T30_STATE_IV_PPS_RNR); send_rr(s); break; - case T30_PIP: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_DCN: s->current_status = T30_ERR_RX_DCNRRD; disconnect(s); @@ -4293,6 +4210,17 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4345,14 +4273,6 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len) set_state(s, T30_STATE_IV_EOR_RNR); send_rr(s); break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_ERR: /* TODO: Continue with the next message if MPS or EOM? */ s->timer_t5 = 0; @@ -4364,6 +4284,17 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len) case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4386,14 +4317,6 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len set_state(s, T30_STATE_IV_EOR_RNR); send_rr(s); break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_ERR: /* TODO: Continue with the next message if MPS or EOM? */ s->timer_t5 = 0; @@ -4409,6 +4332,17 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4596,7 +4530,7 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len) /* The following handles context sensitive message types, which should occur at the end of message sequences. They should, therefore have the final frame flag set. */ - span_log(&s->logging, SPAN_LOG_FLOW, "In state %d\n", s->state); + span_log(&s->logging, SPAN_LOG_FLOW, "Rx final frame in state %d\n", s->state); switch (s->state) { @@ -5082,11 +5016,11 @@ static void timer_t2_expired(t30_state_t *s) case T30_STATE_F_POST_RCP_MCF: switch (s->next_rx_step) { - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: /* We didn't receive a response to our T30_MCF after T30_EOM, so we must be OK - to proceed to phase B, and pretty act like its the beginning of a call. */ + to proceed to phase B, and pretty much act like its the beginning of a call. */ span_log(&s->logging, SPAN_LOG_FLOW, "Returning to phase B after %s\n", t30_frametype(s->next_rx_step)); set_phase(s, T30_PHASE_B_TX); timer_t2_start(s); @@ -5109,6 +5043,8 @@ static void timer_t2_expired(t30_state_t *s) case T30_STATE_F_POST_DOC_ECM: case T30_STATE_F_POST_DOC_NON_ECM: /* While waiting for next FAX page */ + /* Figure 5-2b/T.30 and note 7 says we should allow 1 to 3 tries at this point. + The way we work now is effectively hard coding a 1 try limit */ s->current_status = T30_ERR_RX_T2EXPMPS; break; #if 0 @@ -5873,8 +5809,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) { switch (s->next_rx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: /* We should now start to get another page */ if (s->error_correcting_mode) { @@ -5888,15 +5824,15 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) } timer_t2_start(s); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: /* See if we get something back, before moving to phase B. */ timer_t2_start(s); set_phase(s, T30_PHASE_D_RX); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: /* Wait for a DCN. */ set_phase(s, T30_PHASE_D_RX); timer_t4_start(s); @@ -6256,6 +6192,12 @@ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state) +{ + s->remote_interrupts_allowed = state; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t30_restart(t30_state_t *s) { s->phase = T30_PHASE_IDLE; @@ -6276,10 +6218,9 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s) /* The page number is only reset at call establishment */ s->rx_page_number = 0; s->tx_page_number = 0; -#if 0 s->rtn_events = 0; s->rtp_events = 0; -#endif + s->local_interrupt_pending = FALSE; s->far_end_detected = FALSE; s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0); if (s->calling_party) diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 5c9c4066b2..22af0fcb66 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -2602,7 +2602,9 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, t38_tx_packet_handler_t *tx_t38_packet_handler, void *tx_t38_packet_user_data) { +#if 0 v8_parms_t v8_parms; +#endif int alloced; if (at_tx_handler == NULL || modem_control_handler == NULL) diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index a572b5dad9..d3539cddc1 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -426,7 +426,6 @@ static int set_next_tx_type(t38_gateway_state_t *s) t38_gateway_hdlc_state_t *u; t = &s->audio.modems; - u = &s->core.hdlc_to_modem; t38_non_ecm_buffer_report_output_status(&s->core.non_ecm_to_modem, &s->logging); if (t->next_tx_handler) { @@ -447,6 +446,7 @@ static int set_next_tx_type(t38_gateway_state_t *s) return TRUE; } /*endif*/ + u = &s->core.hdlc_to_modem; if (u->in == u->out) return FALSE; /*endif*/ @@ -1057,7 +1057,9 @@ static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_n static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator) { t38_gateway_state_t *s; - + t38_gateway_hdlc_state_t *u; + int immediate; + s = (t38_gateway_state_t *) user_data; t38_non_ecm_buffer_report_input_status(&s->core.non_ecm_to_modem, &s->logging); @@ -1067,25 +1069,50 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica return 0; } /*endif*/ - if (s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents) + + u = &s->core.hdlc_to_modem; + immediate = (u->in == u->out); + if (u->buf[u->in].contents) { - if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS) - s->core.hdlc_to_modem.in = 0; + if (++u->in >= T38_TX_HDLC_BUFS) + u->in = 0; /*endif*/ } /*endif*/ - s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents = (indicator | FLAG_INDICATOR); - if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS) - s->core.hdlc_to_modem.in = 0; + u->buf[u->in].contents = (indicator | FLAG_INDICATOR); + if (++u->in >= T38_TX_HDLC_BUFS) + u->in = 0; /*endif*/ - t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); - span_log(&s->logging, - SPAN_LOG_FLOW, - "Queued change - (%d) %s -> %s\n", - silence_gen_remainder(&(s->audio.modems.silence_gen)), - t38_indicator_to_str(t->current_rx_indicator), - t38_indicator_to_str(indicator)); + if (immediate) + { + span_log(&s->logging, + SPAN_LOG_FLOW, + "Changing - (%d) %s -> %s\n", + silence_gen_remainder(&(s->audio.modems.silence_gen)), + t38_indicator_to_str(t->current_rx_indicator), + t38_indicator_to_str(indicator)); + switch (s->t38x.current_rx_field_class) + { + case T38_FIELD_CLASS_NONE: + break; + case T38_FIELD_CLASS_HDLC: + span_log(&s->logging, SPAN_LOG_FLOW, "HDLC shutdown\n"); + hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0); + break; + case T38_FIELD_CLASS_NON_ECM: + break; + } + } + else + { + span_log(&s->logging, + SPAN_LOG_FLOW, + "Queued change - (%d) %s -> %s\n", + silence_gen_remainder(&(s->audio.modems.silence_gen)), + t38_indicator_to_str(t->current_rx_indicator), + t38_indicator_to_str(indicator)); + } s->t38x.current_rx_field_class = T38_FIELD_CLASS_NONE; /* We need to set this here, since we might have been called as a fake indication when the real one was missing */ @@ -1440,6 +1467,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->corrupt_current_frame[0] = FALSE; break; case T38_FIELD_T4_NON_ECM_DATA: + if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) + t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); xx->current_rx_field_class = T38_FIELD_CLASS_NON_ECM; hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; if (hdlc_buf->contents != (data_type | FLAG_DATA)) @@ -1454,6 +1483,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->corrupt_current_frame[0] = FALSE; break; case T38_FIELD_T4_NON_ECM_SIG_END: + if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) + t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; /* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with incrementing sequence numbers, which are actually repeats. They get through to this point because @@ -2432,8 +2463,8 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, s->core.to_t38.octets_per_data_packet = 1; s->core.ecm_allowed = TRUE; - t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0); //s->core.ms_per_tx_chunk = DEFAULT_MS_PER_TX_CHUNK; + t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0); restart_rx_modem(s); s->core.timed_mode = TIMED_MODE_STARTUP; s->core.samples_to_timeout = 1; diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c index 18d94b4b90..bb26644b62 100644 --- a/libs/spandsp/src/v18.c +++ b/libs/spandsp/src/v18.c @@ -111,7 +111,7 @@ static const struct dtmf_to_ascii_s dtmf_to_ascii[] = {"##8", 'W'}, {"##9", 'Z'}, {"##0", ' '}, -#if defined(WIN32) || ( defined(__SVR4) && defined (__sun)) +#if defined(WIN32) || ( defined(__SVR4) && defined (__sun)) {"#*1", 'X'}, // (Note 1) 111 1011 {"#*2", 'X'}, // (Note 1) 111 1100 {"#*3", 'X'}, // (Note 1) 111 1101 diff --git a/src/include/switch_caller.h b/src/include/switch_caller.h index b3002081da..f77f1b016d 100644 --- a/src/include/switch_caller.h +++ b/src/include/switch_caller.h @@ -103,6 +103,7 @@ SWITCH_BEGIN_EXTERN_C switch_caller_profile_flag_t flags; struct switch_caller_profile *originator_caller_profile; struct switch_caller_profile *originatee_caller_profile; + struct switch_caller_profile *origination_caller_profile; struct switch_caller_profile *hunt_caller_profile; struct switch_channel_timetable *times; struct switch_caller_extension *caller_extension; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 247beae460..3f92534e3e 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -215,6 +215,20 @@ SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel */ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_profile(switch_channel_t *channel); +/*! + \brief Set the given channel's origination caller profile + \param channel channel to assign the profile to + \param caller_profile the profile to assign +*/ +SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile); + +/*! + \brief Retrive the given channel's origination caller profile + \param channel channel to retrive the profile from + \return the requested profile +*/ +SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel); + /*! \brief Retrive the given channel's unique id diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 0c4241c5f3..e08757ba38 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -37,6 +37,7 @@ #define CC_AGENT_TYPE_UUID_STANDBY "uuid-standby" #define CC_SQLITE_DB_NAME "callcenter" +#define CC_MAX_TIME_DIFF_CHECK 5 /* TODO drop caller if no agent login dont allow new caller @@ -53,6 +54,16 @@ SWITCH_MODULE_DEFINITION(mod_callcenter, mod_callcenter_load, mod_callcenter_shu static const char *global_cf = "callcenter.conf"; +struct cc_status_table { + const char *name; + int status; +}; + +struct cc_state_table { + const char *name; + int state; +}; + typedef enum { CC_STATUS_SUCCESS, CC_STATUS_FALSE, @@ -77,12 +88,7 @@ typedef enum { CC_TIER_STATE_STANDBY = 5 } cc_tier_state_t; -struct cc_tier_state_table { - const char *name; - cc_tier_state_t state; -}; - -static struct cc_tier_state_table STATE_CHART[] = { +static struct cc_state_table STATE_CHART[] = { {"Unknown", CC_TIER_STATE_UNKNOWN}, {"No Answer", CC_TIER_STATE_NO_ANSWER}, {"Ready", CC_TIER_STATE_READY}, @@ -101,12 +107,7 @@ typedef enum { CC_AGENT_STATUS_ON_BREAK = 4 } cc_agent_status_t; -struct cc_agent_status_table { - const char *name; - cc_agent_status_t status; -}; - -static struct cc_agent_status_table AGENT_STATUS_CHART[] = { +static struct cc_status_table AGENT_STATUS_CHART[] = { {"Unknown", CC_AGENT_STATUS_UNKNOWN}, {"Logged Out", CC_AGENT_STATUS_LOGGED_OUT}, {"Available", CC_AGENT_STATUS_AVAILABLE}, @@ -124,12 +125,7 @@ typedef enum { CC_AGENT_STATE_IDLE = 4 } cc_agent_state_t; -struct cc_agent_state_table { - const char *name; - cc_agent_state_t state; -}; - -static struct cc_agent_state_table AGENT_STATE_CHART[] = { +static struct cc_state_table AGENT_STATE_CHART[] = { {"Unknown", CC_AGENT_STATE_UNKNOWN}, {"Waiting", CC_AGENT_STATE_WAITING}, {"Receiving", CC_AGENT_STATE_RECEIVING}, @@ -147,12 +143,7 @@ typedef enum { CC_MEMBER_STATE_ABANDONED = 4 } cc_member_state_t; -struct cc_member_state_table { - const char *name; - cc_member_state_t state; -}; - -static struct cc_member_state_table MEMBER_STATE_CHART[] = { +static struct cc_state_table MEMBER_STATE_CHART[] = { {"Unknown", CC_MEMBER_STATE_UNKNOWN}, {"Waiting", CC_MEMBER_STATE_WAITING}, {"Trying", CC_MEMBER_STATE_TRYING}, @@ -162,10 +153,24 @@ static struct cc_member_state_table MEMBER_STATE_CHART[] = { }; -/*static char queues_sql[] = - "CREATE TABLE queues (\n" - " name VARCHAR(255)\n" ");\n"; - */ +struct cc_member_cancel_reason_table { + const char *name; + int reason; +}; + +typedef enum { + CC_MEMBER_CANCEL_REASON_NONE, + CC_MEMBER_CANCEL_REASON_TIMEOUT, + CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT +} cc_member_cancel_reason_t; + +static struct cc_member_cancel_reason_table MEMBER_CANCEL_REASON_CHART[] = { + {"NONE", CC_MEMBER_CANCEL_REASON_NONE}, + {"TIMEOUT", CC_MEMBER_CANCEL_REASON_TIMEOUT}, + {"NO_AGENT_TIMEOUT", CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT}, + {NULL, 0} +}; + static char members_sql[] = "CREATE TABLE members (\n" " queue VARCHAR(255),\n" @@ -222,7 +227,6 @@ static char agents_sql[] = " ready_time INTEGER NOT NULL DEFAULT 0\n" ");\n"; - static char tiers_sql[] = "CREATE TABLE tiers (\n" " queue VARCHAR(255),\n" @@ -247,7 +251,7 @@ const char * cc_tier_state2str(cc_tier_state_t state) uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_tier_state_table)) - 1; x++) { + for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) { if (STATE_CHART[x].state == state) { str = STATE_CHART[x].name; break; @@ -262,7 +266,7 @@ cc_tier_state_t cc_tier_str2state(const char *str) uint8_t x; cc_tier_state_t state = CC_TIER_STATE_UNKNOWN; - for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_tier_state_table)) - 1 && STATE_CHART[x].name; x++) { + for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_state_table)) - 1 && STATE_CHART[x].name; x++) { if (!strcasecmp(STATE_CHART[x].name, str)) { state = STATE_CHART[x].state; break; @@ -271,12 +275,41 @@ cc_tier_state_t cc_tier_str2state(const char *str) return state; } +const char * cc_member_cancel_reason2str(cc_member_cancel_reason_t reason) +{ + uint8_t x; + const char *str = "NONE"; + + for (x = 0; x < (sizeof(MEMBER_CANCEL_REASON_CHART) / sizeof(struct cc_member_cancel_reason_table)) - 1; x++) { + if (MEMBER_CANCEL_REASON_CHART[x].reason == reason) { + str = MEMBER_CANCEL_REASON_CHART[x].name; + break; + } + } + + return str; +} + +cc_member_cancel_reason_t cc_member_cancel_str2reason(const char *str) +{ + uint8_t x; + cc_member_cancel_reason_t reason = CC_MEMBER_CANCEL_REASON_NONE; + + for (x = 0; x < (sizeof(MEMBER_CANCEL_REASON_CHART) / sizeof(struct cc_member_cancel_reason_table)) - 1 && MEMBER_CANCEL_REASON_CHART[x].name; x++) { + if (!strcasecmp(MEMBER_CANCEL_REASON_CHART[x].name, str)) { + reason = MEMBER_CANCEL_REASON_CHART[x].reason; + break; + } + } + return reason; +} + const char * cc_agent_status2str(cc_agent_status_t status) { uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_agent_status_table)) - 1; x++) { + for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_status_table)) - 1; x++) { if (AGENT_STATUS_CHART[x].status == status) { str = AGENT_STATUS_CHART[x].name; break; @@ -291,7 +324,7 @@ cc_agent_status_t cc_agent_str2status(const char *str) uint8_t x; cc_agent_status_t status = CC_AGENT_STATUS_UNKNOWN; - for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_agent_status_table)) - 1 && AGENT_STATUS_CHART[x].name; x++) { + for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_status_table)) - 1 && AGENT_STATUS_CHART[x].name; x++) { if (!strcasecmp(AGENT_STATUS_CHART[x].name, str)) { status = AGENT_STATUS_CHART[x].status; break; @@ -305,7 +338,7 @@ const char * cc_agent_state2str(cc_agent_state_t state) uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_agent_state_table)) - 1; x++) { + for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) { if (AGENT_STATE_CHART[x].state == state) { str = AGENT_STATE_CHART[x].name; break; @@ -320,7 +353,7 @@ cc_agent_state_t cc_agent_str2state(const char *str) uint8_t x; cc_agent_state_t state = CC_AGENT_STATE_UNKNOWN; - for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_agent_state_table)) - 1 && AGENT_STATE_CHART[x].name; x++) { + for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_state_table)) - 1 && AGENT_STATE_CHART[x].name; x++) { if (!strcasecmp(AGENT_STATE_CHART[x].name, str)) { state = AGENT_STATE_CHART[x].state; break; @@ -334,7 +367,7 @@ const char * cc_member_state2str(cc_member_state_t state) uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_member_state_table)) - 1; x++) { + for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) { if (MEMBER_STATE_CHART[x].state == state) { str = MEMBER_STATE_CHART[x].name; break; @@ -349,7 +382,7 @@ cc_member_state_t cc_member_str2state(const char *str) uint8_t x; cc_member_state_t state = CC_MEMBER_STATE_UNKNOWN; - for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_member_state_table)) - 1 && MEMBER_STATE_CHART[x].name; x++) { + for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_state_table)) - 1 && MEMBER_STATE_CHART[x].name; x++) { if (!strcasecmp(MEMBER_STATE_CHART[x].name, str)) { state = MEMBER_STATE_CHART[x].state; break; @@ -384,19 +417,27 @@ struct cc_queue { char *moh; char *record_template; char *time_base_score; + switch_bool_t tier_rules_apply; uint32_t tier_rule_wait_second; switch_bool_t tier_rule_wait_multiply_level; switch_bool_t tier_rule_no_agent_no_wait; + uint32_t discard_abandoned_after; switch_bool_t abandoned_resume_allowed; + uint32_t max_wait_time; + uint32_t max_wait_time_with_no_agent; + switch_mutex_t *mutex; switch_thread_rwlock_t *rwlock; switch_memory_pool_t *pool; uint32_t flags; + switch_time_t last_agent_exist; + switch_time_t last_agent_exist_check; + switch_xml_config_item_t config[CC_QUEUE_CONFIGITEM_COUNT]; switch_xml_config_string_options_t config_str_pool; @@ -488,6 +529,7 @@ cc_queue_t *queue_set_config(cc_queue_t *queue) SWITCH_CONFIG_SET_ITEM(queue->config[i++], "moh-sound", SWITCH_CONFIG_STRING, 0, &queue->moh, NULL, &queue->config_str_pool, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "record-template", SWITCH_CONFIG_STRING, 0, &queue->record_template, NULL, &queue->config_str_pool, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "time-base-score", SWITCH_CONFIG_STRING, 0, &queue->time_base_score, "queue", &queue->config_str_pool, NULL, NULL); + SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rules-apply", SWITCH_CONFIG_BOOL, 0, &queue->tier_rules_apply, SWITCH_FALSE, NULL, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rule-wait-second", SWITCH_CONFIG_INT, 0, &queue->tier_rule_wait_second, 0, &config_int_0_86400, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rule-wait-multiply-level", SWITCH_CONFIG_BOOL, 0, &queue->tier_rule_wait_multiply_level, SWITCH_FALSE, NULL, NULL, NULL); @@ -495,6 +537,9 @@ cc_queue_t *queue_set_config(cc_queue_t *queue) SWITCH_CONFIG_SET_ITEM(queue->config[i++], "discard-abandoned-after", SWITCH_CONFIG_INT, 0, &queue->discard_abandoned_after, 60, &config_int_0_86400, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "abandoned-resume-allowed", SWITCH_CONFIG_BOOL, 0, &queue->abandoned_resume_allowed, SWITCH_FALSE, NULL, NULL, NULL); + SWITCH_CONFIG_SET_ITEM(queue->config[i++], "max-wait-time", SWITCH_CONFIG_INT, 0, &queue->max_wait_time, 0, &config_int_0_86400, NULL, NULL); + SWITCH_CONFIG_SET_ITEM(queue->config[i++], "max-wait-time-with-no-agent", SWITCH_CONFIG_INT, 0, &queue->max_wait_time_with_no_agent, 0, &config_int_0_86400, NULL, NULL); + switch_assert(i < CC_QUEUE_CONFIGITEM_COUNT); return queue; @@ -646,6 +691,9 @@ static cc_queue_t *load_queue(const char *queue_name) switch_thread_rwlock_create(&queue->rwlock, pool); queue->name = switch_core_strdup(pool, queue_name); + queue->last_agent_exist = 0; + queue->last_agent_exist_check = 0; + if (!(dbh = cc_get_db_handle())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n"); goto end; @@ -702,7 +750,7 @@ static cc_queue_t *get_queue(const char *queue_name) struct call_helper { const char *member_uuid; - const char *queue; + const char *queue_name; const char *queue_strategy; const char *member_joined_epoch; const char *member_caller_name; @@ -744,7 +792,7 @@ int cc_queue_count(const char *queue) count = atoi(res); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Selection", event_name); @@ -827,7 +875,7 @@ cc_agent_status_t cc_agent_get(const char *key, const char *agent, char *ret_res result = CC_STATUS_SUCCESS; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-get"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", res); switch_event_fire(&event); @@ -894,7 +942,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen result = CC_STATUS_SUCCESS; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-change"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", value); switch_event_fire(&event); @@ -918,7 +966,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen result = CC_STATUS_SUCCESS; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-state-change"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-State", value); switch_event_fire(&event); @@ -1118,13 +1166,13 @@ done: return result; } -cc_status_t cc_tier_del(const char *queue, const char *agent) +cc_status_t cc_tier_del(const char *queue_name, const char *agent) { cc_status_t result = CC_STATUS_SUCCESS; char *sql; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue); - sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue, agent); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue_name); + sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue_name, agent); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1307,8 +1355,11 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa } if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_CALLBACK)) { switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS); + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_pre_answer_uuid", "%s", h->member_uuid); + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name); + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent_type", "%s", h->agent_type); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true"); t_agent_called = switch_epoch_time_now(NULL); @@ -1323,6 +1374,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_channel_t *agent_channel = switch_core_session_get_channel(agent_session); switch_event_t *event; const char *cc_warning_tone = switch_channel_get_variable(agent_channel, "cc_warning_tone"); + + switch_channel_set_variable(agent_channel, "cc_queue", h->queue_name); + switch_channel_set_variable(agent_channel, "cc_agent", h->agent_name); + switch_channel_set_variable(agent_channel, "cc_agent_type", h->agent_type); + switch_channel_set_variable(agent_channel, "cc_member_uuid", h->member_uuid); + /* Playback this to the agent */ if (cc_warning_tone && switch_event_create(&event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute"); @@ -1375,7 +1432,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(agent_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-start"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); @@ -1398,11 +1455,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_safe_free(sql); /* Change the agents Status in the tiers */ - sql = switch_mprintf("UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q'", - cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->agent_name, h->queue); - cc_execute_sql(NULL, sql, NULL); - switch_safe_free(sql); - + cc_tier_update("state", cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->queue_name, h->agent_name); cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_IN_A_QUEUE_CALL), h->agent_name); /* Record session if record-template is provided */ @@ -1415,9 +1468,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" (%s) from queue %s%s\n", - h->agent_name, h->member_caller_name, h->member_caller_number, h->queue, (h->record_template?" (Recorded)":"")); - switch_ivr_uuid_bridge(switch_core_session_get_uuid(agent_session), h->member_uuid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" <%s> from queue %s%s\n", + h->agent_name, h->member_caller_name, h->member_caller_number, h->queue_name, (h->record_template?" (Recorded)":"")); + switch_ivr_uuid_bridge(h->member_uuid, switch_core_session_get_uuid(agent_session)); + + /* This is used for the waiting caller to quit waiting for a agent */ + switch_channel_set_variable(member_channel, "cc_agent_uuid", agent_uuid); /* Wait until the member hangup or the agent hangup. This will quit also if the agent transfer the call */ while(switch_channel_up(member_channel) && switch_channel_up(agent_channel) && globals.running) { @@ -1427,7 +1483,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(agent_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-end"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); @@ -1443,7 +1499,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa /* Update Agents Items */ /* Do not remove uuid of the agent if we are a standby agent */ sql = switch_mprintf("UPDATE agents SET %q last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';" - , (strcasecmp(h->agent_type, "uuid-standby")?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system); + , (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1455,7 +1511,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa /* Caller off event */ if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Terminated"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answer-Time", "%ld", (long) (t_agent_answered - t_agent_called)); @@ -1463,8 +1519,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Talk-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_agent_answered)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Total-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); } @@ -1529,8 +1587,8 @@ done: sql = switch_mprintf( "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q' AND (state = '%q' OR state = '%q' OR state = '%q');" "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q'" - , cc_tier_state2str(tiers_state), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING), - cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_STANDBY)); + , cc_tier_state2str(tiers_state), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING), + cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_STANDBY)); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1558,7 +1616,7 @@ done: } struct agent_callback { - const char *queue; + const char *queue_name; const char *system; const char *uuid; const char *caller_number; @@ -1570,6 +1628,7 @@ struct agent_callback { uint32_t tier_rule_wait_second; switch_bool_t tier_rule_wait_multiply_level; switch_bool_t tier_rule_no_agent_no_wait; + switch_bool_t agent_found; int tier; int tier_agent_available; @@ -1593,6 +1652,8 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames switch_bool_t contact_agent = SWITCH_TRUE; + cbt->agent_found = SWITCH_TRUE; + /* Check if we switch to a different tier, if so, check if we should continue further for that member */ if (cbt->tier_rules_apply == SWITCH_TRUE && atoi(agent_tier_level) > cbt->tier) { @@ -1691,7 +1752,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames h->member_joined_epoch = switch_core_strdup(h->pool, cbt->joined_epoch); h->member_caller_name = switch_core_strdup(h->pool, cbt->caller_name); h->member_caller_number = switch_core_strdup(h->pool, cbt->caller_number); - h->queue = switch_core_strdup(h->pool, cbt->queue); + h->queue_name = switch_core_strdup(h->pool, cbt->queue_name); h->record_template = switch_core_strdup(h->pool, cbt->record_template); h->no_answer_count = atoi(argv[4]); h->max_no_answer = atoi(argv[5]); @@ -1704,8 +1765,8 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames sql = switch_mprintf( "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q';" "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q';", - cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue, - cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_READY)); + cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue_name, + cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_READY)); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1772,7 +1833,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName switch_safe_free(sql); } /* Skip this member */ - return 0; + goto end; } memset(&cbt, 0, sizeof(cbt)); cbt.tier = 0; @@ -1787,9 +1848,10 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName cbt.caller_number = argv[2]; cbt.caller_name = argv[3]; cbt.joined_epoch = argv[4]; - cbt.queue = argv[0]; + cbt.queue_name = argv[0]; cbt.strategy = queue_strategy; cbt.record_template = queue_record_template; + cbt.agent_found = SWITCH_FALSE; if (!strcasecmp(queue->strategy, "longest-idle-agent")) { sql_order_by = switch_mprintf("level, agents.last_offered_call, position"); @@ -1823,6 +1885,18 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName switch_safe_free(sql); switch_safe_free(sql_order_by); + /* We update a field in the queue struct so we can kick caller out if waiting for too long with no agent */ + if (!argv[0] || !(queue = get_queue(argv[0]))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", argv[0]); + goto end; + } else { + queue->last_agent_exist_check = switch_epoch_time_now(NULL); + if (cbt.agent_found) { + queue->last_agent_exist = queue->last_agent_exist_check; + } + queue_rwunlock(queue); + } + end: switch_safe_free(queue_name); switch_safe_free(queue_strategy); @@ -1902,30 +1976,53 @@ void cc_agent_dispatch_thread_start(void) switch_thread_create(&thread, thd_attr, cc_agent_dispatch_thread_run, NULL, globals.pool); } -struct member_helper { - const char *uuid; +struct member_thread_helper { + const char *member_uuid; + const char *queue_name; + switch_time_t t_member_called; + cc_member_cancel_reason_t member_cancel_reason; + int running; switch_memory_pool_t *pool; }; void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj) { - struct member_helper *m = (struct member_helper *) obj; - switch_core_session_t *member_session = switch_core_session_locate(m->uuid); - switch_channel_t *channel = NULL; + struct member_thread_helper *m = (struct member_thread_helper *) obj; + switch_core_session_t *member_session = switch_core_session_locate(m->member_uuid); + switch_channel_t *member_channel = NULL; switch_mutex_lock(globals.mutex); globals.threads++; switch_mutex_unlock(globals.mutex); if (member_session) { - channel = switch_core_session_get_channel(member_session); + member_channel = switch_core_session_get_channel(member_session); } else { switch_core_destroy_memory_pool(&m->pool); return NULL; } - while(switch_channel_ready(channel) && m->running && globals.running) { + while(switch_channel_ready(member_channel) && m->running && globals.running) { + cc_queue_t *queue = NULL; + + if (!m->queue_name || !(queue = get_queue(m->queue_name))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found\n", m->queue_name); + break; + } + /* Make the Caller Leave if he went over his max wait time */ + if (queue->max_wait_time > 0 && queue->max_wait_time <= switch_epoch_time_now(NULL) - m->t_member_called) { + m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_TIMEOUT; + switch_channel_set_flag_value(member_channel, CF_BREAK, 2); + } + + /* Will drop the caller if no agent was found for more than X secondes */ + if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - CC_MAX_TIME_DIFF_CHECK && + queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) { + m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT; + switch_channel_set_flag_value(member_channel, CF_BREAK, 2); + } + /* TODO Go thought the list of phrases */ /* SAMPLE CODE to playback something over the MOH @@ -1940,8 +2037,12 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj /* If Agent Logoff, we might need to recalculare score based on skill */ /* Play Announcement in order */ - switch_yield(100000); + + queue_rwunlock(queue); + + switch_yield(500000); } + switch_core_session_rwunlock(member_session); switch_core_destroy_memory_pool(&m->pool); @@ -1962,26 +2063,27 @@ SWITCH_STANDARD_APP(callcenter_function) char *mydata = NULL; cc_queue_t *queue = NULL; const char *queue_name = NULL; - switch_channel_t *member_channel = switch_core_session_get_channel(session); + switch_core_session_t *member_session = session; + switch_channel_t *member_channel = switch_core_session_get_channel(member_session); char *sql = NULL; - char *uuid = switch_core_session_get_uuid(session); - switch_input_args_t args = { 0 }; - struct member_helper *h = NULL; + char *member_uuid = switch_core_session_get_uuid(member_session); + struct member_thread_helper *h = NULL; switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; switch_memory_pool_t *pool; - int cc_base_score_int = 0; switch_channel_timetable_t *times = NULL; - const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score"); const char *cc_moh_override = switch_channel_get_variable(member_channel, "cc_moh_override"); + const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score"); + int cc_base_score_int = 0; const char *cur_moh = NULL; char start_epoch[64]; switch_event_t *event; switch_time_t t_member_called = switch_epoch_time_now(NULL); long abandoned_epoch = 0; + const char *agent_uuid = NULL; if (!zstr(data)) { - mydata = switch_core_session_strdup(session, data); + mydata = switch_core_session_strdup(member_session, data); argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Queue name provided\n"); @@ -2004,7 +2106,7 @@ SWITCH_STANDARD_APP(callcenter_function) times = switch_channel_get_timetable(member_channel); switch_snprintf(start_epoch, sizeof(start_epoch), "%" SWITCH_TIME_T_FMT, times->answered / 1000000); - /* Check of we have a queued abandoned member we can resume from */ + /* Check if we support and have a queued abandoned member we can resume from */ if (queue->abandoned_resume_allowed == SWITCH_TRUE) { char res[256]; @@ -2028,9 +2130,9 @@ SWITCH_STANDARD_APP(callcenter_function) if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-%s", (abandoned_epoch==0?"start":"resume")); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); @@ -2045,7 +2147,7 @@ SWITCH_STANDARD_APP(callcenter_function) " (queue,system,uuid,system_epoch,joined_epoch,base_score,skill_score,caller_number,caller_name,serving_agent,serving_system,state)" " VALUES('%q','single_box','%q','%q','%ld','%d','%d','%q','%q','%q','','%q')", queue_name, - uuid, + member_uuid, start_epoch, (long) switch_epoch_time_now(NULL), cc_base_score_int, @@ -2060,12 +2162,12 @@ SWITCH_STANDARD_APP(callcenter_function) char res[256]; /* Update abandoned member */ sql = switch_mprintf("UPDATE members SET uuid = '%q', state = '%q', rejoined_epoch = '%ld' WHERE caller_number = '%q' AND abandoned_epoch = '%ld' AND state = '%q' AND queue = '%q'", - uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), abandoned_epoch, cc_member_state2str(CC_MEMBER_STATE_ABANDONED), queue_name); + member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), abandoned_epoch, cc_member_state2str(CC_MEMBER_STATE_ABANDONED), queue_name); cc_execute_sql(queue, sql, NULL); switch_safe_free(sql); /* Confirm we took that member in */ - sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND state = '%q' AND queue = '%q'", uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name); + sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND state = '%q' AND queue = '%q'", member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name); cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res)); switch_safe_free(sql); @@ -2083,9 +2185,14 @@ SWITCH_STANDARD_APP(callcenter_function) /* Start Thread that will playback different prompt to the channel */ switch_core_new_memory_pool(&pool); h = switch_core_alloc(pool, sizeof(*h)); + h->pool = pool; - h->uuid = switch_core_strdup(h->pool, uuid); + h->member_uuid = switch_core_strdup(h->pool, member_uuid); + h->queue_name = switch_core_strdup(h->pool, queue_name); + h->t_member_called = t_member_called; + h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NONE; h->running = 1; + switch_threadattr_create(&thd_attr, h->pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); @@ -2095,16 +2202,37 @@ SWITCH_STANDARD_APP(callcenter_function) /* TODO Add DTMF callback support */ /* TODO add MOH infitite loop */ if (cc_moh_override) { - cur_moh = switch_core_session_strdup(session, cc_moh_override); + cur_moh = switch_core_session_strdup(member_session, cc_moh_override); } else { - cur_moh = switch_core_session_strdup(session, queue->moh); + cur_moh = switch_core_session_strdup(member_session, queue->moh); } queue_rwunlock(queue); - if (cur_moh) { - switch_ivr_play_file(session, NULL, cur_moh, &args); - } else { - switch_ivr_collect_digits_callback(session, &args, 0, 0); + while (switch_channel_ready(member_channel)) { + switch_input_args_t args = { 0 }; + + /* An agent was found, time to exit and let the bridge do it job */ + if ((agent_uuid = switch_channel_get_variable(member_channel, "cc_agent_uuid"))) { + break; + } + /* If the member thread set a different reason, we monitor it so we can quit the wait */ + if (h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) { + break; + } + + switch_core_session_flush_private_events(member_session); + + if (cur_moh) { + switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + } else { + switch_ivr_collect_digits_callback(session, &args, 0, 0); + } + } /* Stop Member Thread */ @@ -2114,33 +2242,42 @@ SWITCH_STANDARD_APP(callcenter_function) /* Hangup any agents been callback */ if (!switch_channel_up(member_channel)) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */ - switch_core_session_hupall_matching_var("cc_member_uuid", uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); + switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); sql = switch_mprintf("UPDATE members SET state = '%q', uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", - cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), uuid); + cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); + /* Generate an Event and update some channel variable */ if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called)); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Abort"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", uuid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), + queue_name, cc_member_cancel_reason2str(h->member_cancel_reason)); + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", cc_member_cancel_reason2str(h->member_cancel_reason)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); } + /* for xml_cdr needs */ switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%ld", (long) switch_epoch_time_now(NULL)); + switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", cc_member_cancel_reason2str(h->member_cancel_reason)); /* Send Event with queue count */ cc_queue_count(queue_name); } else { + switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered"); sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", - cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), uuid); + cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), member_uuid); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -2516,7 +2653,7 @@ SWITCH_STANDARD_API(cc_config_api_function) stream->write_function(stream, "%d\n", atoi(res)); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res); switch_event_fire(&event); diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 69ce125d0f..7558e1b1b8 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -1002,7 +1002,7 @@ static int do_candidates(struct private_object *tech_pvt, int force) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Send Candidate %s:%d [%s]\n", cand[0].address, cand[0].port, cand[0].username); - if (ldl_session_gateway(tech_pvt->dlsession)) { + if (ldl_session_gateway(tech_pvt->dlsession) && switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { tech_pvt->cand_id = ldl_session_transport(tech_pvt->dlsession, cand, 1); } else { tech_pvt->cand_id = ldl_session_candidates(tech_pvt->dlsession, cand, 1); @@ -1247,7 +1247,8 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session) tech_pvt->rtp_session = NULL; } - if (globals.auto_nat && tech_pvt->profile->local_network && !switch_check_network_list_ip(tech_pvt->remote_ip, tech_pvt->profile->local_network)) { + if (globals.auto_nat && tech_pvt->profile->local_network && tech_pvt->remote_ip && tech_pvt->profile->local_network && + !switch_check_network_list_ip(tech_pvt->remote_ip, tech_pvt->profile->local_network)) { switch_nat_del_mapping((switch_port_t) tech_pvt->local_port, SWITCH_NAT_UDP); } @@ -1259,6 +1260,10 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session) switch_core_codec_destroy(&tech_pvt->write_codec); } + if (tech_pvt->dlsession) { + ldl_session_destroy(&tech_pvt->dlsession); + } + switch_thread_rwlock_unlock(tech_pvt->profile->rwlock); if (tech_pvt->profile->purge) { @@ -1296,13 +1301,12 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) if ((tech_pvt->profile->user_flags & LDL_FLAG_COMPONENT) && is_special(tech_pvt->them)) { ldl_handle_send_presence(tech_pvt->profile->handle, tech_pvt->them, tech_pvt->us, NULL, NULL, "Click To Call", tech_pvt->profile->avatar); } - if (tech_pvt->dlsession) { - if (!switch_test_flag(tech_pvt, TFLAG_TERM)) { - ldl_session_terminate(tech_pvt->dlsession); - switch_set_flag_locked(tech_pvt, TFLAG_TERM); - } - ldl_session_destroy(&tech_pvt->dlsession); + + if (!switch_test_flag(tech_pvt, TFLAG_TERM) && tech_pvt->dlsession) { + ldl_session_terminate(tech_pvt->dlsession); + switch_set_flag_locked(tech_pvt, TFLAG_TERM); } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); @@ -1324,15 +1328,6 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); switch_set_flag_locked(tech_pvt, TFLAG_BYE); - if (tech_pvt->dlsession) { - if (!switch_test_flag(tech_pvt, TFLAG_TERM)) { - ldl_session_terminate(tech_pvt->dlsession); - switch_set_flag_locked(tech_pvt, TFLAG_TERM); - } - ldl_session_destroy(&tech_pvt->dlsession); - - } - if (switch_rtp_ready(tech_pvt->rtp_session)) { switch_rtp_kill_socket(tech_pvt->rtp_session); } @@ -2980,6 +2975,8 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi tech_pvt->flags |= profile->flags; channel = switch_core_session_get_channel(session); switch_core_session_set_private(session, tech_pvt); + tech_pvt->dlsession = dlsession; + tech_pvt->session = session; tech_pvt->codec_index = -1; tech_pvt->profile = profile; @@ -3025,6 +3022,24 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi cid_num = tech_pvt->recip; } + + if (switch_stristr("voice.google.com", from)) { + char *id = switch_core_session_strdup(session, from); + char *p; + + if ((p = strchr(id, '@'))) { + *p++ = '\0'; + cid_name = "Google Voice"; + cid_num = id; + } + + ldl_session_set_gateway(dlsession); + + do_candidates(tech_pvt, 1); + } + + + /* context of "_auto_" means set it to the domain */ if (profile->context && !strcmp(profile->context, "_auto_")) { context = profile->name; @@ -3047,7 +3062,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi switch_safe_free(tmp); } - + if (!tech_pvt->caller_profile) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Creating an identity for %s %s <%s> %s\n", ldl_session_get_id(dlsession), cid_name, cid_num, exten); @@ -3079,7 +3094,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Creating a session for %s\n", ldl_session_get_id(dlsession)); ldl_session_set_private(dlsession, session); - tech_pvt->dlsession = dlsession; + switch_channel_set_name(channel, "DingaLing/new"); switch_channel_set_state(channel, CS_INIT); if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { @@ -3230,6 +3245,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi } } } + } break; @@ -3259,7 +3275,15 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi if (profile->acl_count) { for (x = 0; x < len; x++) { uint32_t y = 0; + + if (strcasecmp(candidates[x].protocol, "udp")) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d has an unsupported protocol!\n", + candidates[x].address, candidates[x].port); + continue; + } + for (y = 0; y < profile->acl_count; y++) { + if (switch_check_network_list_ip(candidates[x].address, profile->acl[y])) { choice = x; ok = 1; @@ -3268,7 +3292,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi if (ok) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d PASS ACL %s\n", candidates[x].address, candidates[x].port, profile->acl[y]); - break; + goto end_candidates; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "candidate %s:%d FAIL ACL %s\n", candidates[x].address, candidates[x].port, profile->acl[y]); @@ -3311,6 +3335,8 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi } } + end_candidates: + if (ok) { ldl_payload_t payloads[5]; diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index cbeae6cf5a..165815078b 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -1233,7 +1233,6 @@ static void walk_listeners(skinny_listener_callback_func_t callback, void *pvt) switch_hash_index_t *hi; void *val; skinny_profile_t *profile; - listener_t *l; /* walk listeners */ switch_mutex_lock(globals.mutex); @@ -1241,11 +1240,7 @@ static void walk_listeners(skinny_listener_callback_func_t callback, void *pvt) switch_hash_this(hi, NULL, NULL, &val); profile = (skinny_profile_t *) val; - switch_mutex_lock(profile->listener_mutex); - for (l = profile->listeners; l; l = l->next) { - callback(l, pvt); - } - switch_mutex_unlock(profile->listener_mutex); + profile_walk_listeners(profile, callback, pvt); } switch_mutex_unlock(globals.mutex); } @@ -1509,6 +1504,7 @@ static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void new_socket: while(globals.running) { + switch_clear_flag_locked(profile, PFLAG_RESPAWN); rv = switch_sockaddr_info_get(&sa, profile->ip, SWITCH_INET, profile->port, 0, tmp_pool); if (rv) goto fail; @@ -1546,8 +1542,10 @@ new_socket: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting Down\n"); goto end; } else if (switch_test_flag(profile, PFLAG_RESPAWN)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Creating a new socket\n"); - switch_clear_flag_locked(profile, PFLAG_RESPAWN); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Respawn in progress. Waiting for socket to close.\n"); + while (profile->sock) { + switch_cond_next(); + } goto new_socket; } else { /* I wish we could use strerror_r here but its not defined everywhere =/ */ @@ -1619,6 +1617,18 @@ switch_endpoint_interface_t *skinny_get_endpoint_interface() return skinny_endpoint_interface; } +switch_status_t skinny_profile_respawn(skinny_profile_t *profile, int force) +{ + if (force || switch_test_flag(profile, PFLAG_SHOULD_RESPAWN)) { + switch_clear_flag_locked(profile, PFLAG_SHOULD_RESPAWN); + switch_set_flag_locked(profile, PFLAG_RESPAWN); + switch_clear_flag_locked(profile, PFLAG_LISTENER_READY); + profile_walk_listeners(profile, kill_listener, NULL); + close_socket(&profile->sock, profile); + } + return SWITCH_STATUS_SUCCESS; +} + switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, const char *val) { if (!var) @@ -1633,9 +1643,15 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c if (!strcasecmp(var, "domain")) { profile->domain = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "ip")) { - profile->ip = switch_core_strdup(profile->pool, val); + if (!profile->ip || strcmp(val, profile->ip)) { + profile->ip = switch_core_strdup(profile->pool, val); + switch_set_flag_locked(profile, PFLAG_SHOULD_RESPAWN); + } } else if (!strcasecmp(var, "port")) { - profile->port = atoi(val); + if (atoi(val) != profile->port) { + profile->port = atoi(val); + switch_set_flag_locked(profile, PFLAG_SHOULD_RESPAWN); + } } else if (!strcasecmp(var, "patterns-dialplan")) { profile->patterns_dialplan = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "patterns-context")) { @@ -1669,15 +1685,21 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c } else { return SWITCH_STATUS_FALSE; } - if (profile->sock && (!strcasecmp(var, "ip") || !strcasecmp(var, "port"))) { - switch_set_flag_locked(profile, PFLAG_RESPAWN); - switch_clear_flag_locked(profile, PFLAG_LISTENER_READY); - close_socket(&profile->sock, profile); - } return SWITCH_STATUS_SUCCESS; } +void profile_walk_listeners(skinny_profile_t *profile, skinny_listener_callback_func_t callback, void *pvt) +{ + listener_t *l; + + switch_mutex_lock(profile->listener_mutex); + for (l = profile->listeners; l; l = l->next) { + callback(l, pvt); + } + switch_mutex_unlock(profile->listener_mutex); +} + static switch_status_t load_skinny_config(void) { char *cf = "skinny.conf"; @@ -1692,8 +1714,7 @@ static switch_status_t load_skinny_config(void) if ((xprofiles = switch_xml_child(xcfg, "profiles"))) { for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) { char *profile_name = (char *) switch_xml_attr_soft(xprofile, "name"); - switch_xml_t xsettings; - switch_xml_t xdevice_types; + switch_xml_t xsettings, xdevice_types, xsoft_key_set_sets; if (zstr(profile_name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " is missing name attribute\n"); @@ -1749,6 +1770,96 @@ static switch_status_t load_skinny_config(void) profile->port = 2000; } + /* Soft Key Set Sets */ + switch_core_hash_init(&profile->soft_key_set_sets_hash, profile->pool); + if ((xsoft_key_set_sets = switch_xml_child(xprofile, "soft-key-set-sets"))) { + switch_xml_t xsoft_key_set_set; + for (xsoft_key_set_set = switch_xml_child(xsoft_key_set_sets, "soft-key-set-set"); xsoft_key_set_set; xsoft_key_set_set = xsoft_key_set_set->next) { + char *soft_key_set_set_name = (char *) switch_xml_attr_soft(xsoft_key_set_set, "name"); + if (soft_key_set_set_name) { + switch_xml_t xsoft_key_set; + skinny_message_t *message; + message = switch_core_alloc(profile->pool, 12+sizeof(message->data.soft_key_set)); + message->type = SOFT_KEY_SET_RES_MESSAGE; + message->length = 4 + sizeof(message->data.soft_key_set); + message->data.soft_key_set.soft_key_set_offset = 0; + message->data.soft_key_set.soft_key_set_count = 11; + message->data.soft_key_set.total_soft_key_set_count = 11; + for (xsoft_key_set = switch_xml_child(xsoft_key_set_set, "soft-key-set"); xsoft_key_set; xsoft_key_set = xsoft_key_set->next) { + uint32_t soft_key_set_id; + if ((soft_key_set_id = skinny_str2soft_key_set(switch_xml_attr_soft(xsoft_key_set, "name"))) != -1) { + char *val =switch_core_strdup(profile->pool, switch_xml_attr_soft(xsoft_key_set, "value")); + size_t string_len = strlen(val); + size_t string_pos, start = 0; + int field_no = 0; + if (soft_key_set_id > 15) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "soft-key-set name '%s' is greater than 15 in soft-key-set-set '%s' in profile %s.\n", + switch_xml_attr_soft(xsoft_key_set, "name"), soft_key_set_set_name, profile->name); + continue; + } + for (string_pos = 0; string_pos <= string_len; string_pos++) { + if ((val[string_pos] == ',') || (string_pos == string_len)) { + val[string_pos] = '\0'; + if (field_no > 15) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "soft-key-set name '%s' is limited to 16 buttons in soft-key-set-set '%s' in profile %s.\n", + switch_xml_attr_soft(xsoft_key_set, "name"), soft_key_set_set_name, profile->name); + break; + } + message->data.soft_key_set.soft_key_set[soft_key_set_id].soft_key_template_index[field_no++] = skinny_str2soft_key_event(&val[start]); + start = string_pos+1; + } + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unknown soft-key-set name '%s' in soft-key-set-set '%s' in profile %s.\n", + switch_xml_attr_soft(xsoft_key_set, "name"), soft_key_set_set_name, profile->name); + } + } /* soft-key-set */ + switch_core_hash_insert(profile->soft_key_set_sets_hash, soft_key_set_set_name, message); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + " is missing a name attribute in profile %s.\n", profile->name); + } + } /* soft-key-set-set */ + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + " is missing in profile %s.\n", profile->name); + } /* soft-key-set-sets */ + if (!switch_core_hash_find(profile->soft_key_set_sets_hash, "default")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Profile %s doesn't have a default . Profile ignored.\n", profile->name); + switch_core_destroy_memory_pool(&profile_pool); + continue; + } + + + /* Device types */ + switch_core_hash_init(&profile->device_type_params_hash, profile->pool); + if ((xdevice_types = switch_xml_child(xprofile, "device-types"))) { + switch_xml_t xdevice_type; + for (xdevice_type = switch_xml_child(xdevice_types, "device-type"); xdevice_type; xdevice_type = xdevice_type->next) { + uint32_t id = skinny_str2device_type(switch_xml_attr_soft(xdevice_type, "id")); + if (id != 0) { + char *id_str = switch_mprintf("%d", id); + skinny_device_type_params_t *params = switch_core_alloc(profile->pool, sizeof(skinny_device_type_params_t)); + for (param = switch_xml_child(xdevice_type, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcasecmp(var, "firmware-version")) { + strncpy(params->firmware_version, val, 16); + } + } /* param */ + switch_core_hash_insert(profile->device_type_params_hash, id_str, params); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unknow device type %s in profile %s.\n", switch_xml_attr_soft(xdevice_type, "id"), profile->name); + } + } + } + /* Database */ switch_snprintf(dbname, sizeof(dbname), "skinny_%s", profile->name); profile->dbname = switch_core_strdup(profile->pool, dbname); @@ -1787,30 +1898,7 @@ static switch_status_t load_skinny_config(void) skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_buttons", NULL, NULL); skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_active_lines", NULL, NULL); - /* Device types */ - switch_core_hash_init(&profile->device_type_params_hash, profile->pool); - if ((xdevice_types = switch_xml_child(xprofile, "device-types"))) { - switch_xml_t xdevice_type; - for (xdevice_type = switch_xml_child(xdevice_types, "device-type"); xdevice_type; xdevice_type = xdevice_type->next) { - uint32_t id = skinny_str2device_type(switch_xml_attr_soft(xdevice_type, "id")); - if (id != 0) { - char *id_str = switch_mprintf("%d", id); - skinny_device_type_params_t *params = switch_core_alloc(profile->pool, sizeof(skinny_device_type_params_t)); - for (param = switch_xml_child(xdevice_type, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - - if (!strcasecmp(var, "firmware-version")) { - strncpy(params->firmware_version, val, 16); - } - } /* param */ - switch_core_hash_insert(profile->device_type_params_hash, id_str, params); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Unknow device type %s in profile %s.\n", switch_xml_attr_soft(xdevice_type, "id"), profile->name); - } - } - } + skinny_profile_respawn(profile, 0); /* Register profile */ switch_mutex_lock(globals.mutex); @@ -2009,6 +2097,7 @@ static void skinny_trap_event_handler(switch_event_t *event) } else if (!strcmp(profile->ip, old_ip6)) { skinny_profile_set(profile, "ip", new_ip6); } + skinny_profile_respawn(profile, 0); } } } @@ -2034,9 +2123,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load) load_skinny_config(); + /* at least one profile */ + if (!switch_hash_first(NULL, globals.profile_hash)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No profile found!\n"); + return SWITCH_STATUS_TERM; + } /* bind to events */ if ((switch_event_bind_removable(modname, SWITCH_EVENT_HEARTBEAT, NULL, skinny_heartbeat_event_handler, NULL, &globals.heartbeat_node) != SWITCH_STATUS_SUCCESS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our heartbeat handler!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our heartbeat handler!\n"); /* Not such severe to prevent loading */ } if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE, skinny_call_state_event_handler, NULL, &globals.call_state_node) != SWITCH_STATUS_SUCCESS)) { @@ -2044,11 +2138,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load) return SWITCH_STATUS_TERM; } if ((switch_event_bind_removable(modname, SWITCH_EVENT_MESSAGE_WAITING, NULL, skinny_message_waiting_event_handler, NULL, &globals.message_waiting_node) != SWITCH_STATUS_SUCCESS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our message waiting handler!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our message waiting handler!\n"); /* Not such severe to prevent loading */ } if ((switch_event_bind_removable(modname, SWITCH_EVENT_TRAP, NULL, skinny_trap_event_handler, NULL, &globals.trap_node) != SWITCH_STATUS_SUCCESS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our trap handler!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our trap handler!\n"); /* Not such severe to prevent loading */ } diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index f52f171fdc..bbd318b746 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -61,7 +61,8 @@ extern skinny_globals_t globals; typedef enum { PFLAG_LISTENER_READY = (1 << 0), - PFLAG_RESPAWN = (1 << 1), + PFLAG_SHOULD_RESPAWN = (1 << 1), + PFLAG_RESPAWN = (1 << 2), } profile_flag_t; struct skinny_profile { @@ -78,6 +79,7 @@ struct skinny_profile { char date_format[6]; int debug; int auto_restart; + switch_hash_t *soft_key_set_sets_hash; switch_hash_t *device_type_params_hash; /* db */ char *dbname; @@ -133,6 +135,7 @@ struct listener { uint32_t device_type; char firmware_version[16]; + char *soft_key_set_set; switch_socket_t *sock; switch_memory_pool_t *pool; @@ -220,6 +223,9 @@ switch_core_session_t * skinny_profile_perform_find_session(skinny_profile_t *pr switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id); #endif switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream); +switch_status_t skinny_profile_respawn(skinny_profile_t *profile, int force); +switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, const char *val); +void profile_walk_listeners(skinny_profile_t *profile, skinny_listener_callback_func_t callback, void *pvt); /*****************************************************************************/ /* SQL FUNCTIONS */ @@ -262,7 +268,6 @@ switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); /* MODULE FUNCTIONS */ /*****************************************************************************/ switch_endpoint_interface_t *skinny_get_endpoint_interface(); -switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, const char *val); #endif /* _MOD_SKINNY_H */ diff --git a/src/mod/endpoints/mod_skinny/skinny_api.c b/src/mod/endpoints/mod_skinny/skinny_api.c index 86eea74fc8..90699d1ad2 100644 --- a/src/mod/endpoints/mod_skinny/skinny_api.c +++ b/src/mod/endpoints/mod_skinny/skinny_api.c @@ -275,6 +275,7 @@ static switch_status_t skinny_api_cmd_profile_device_send_ringer_message(const c skinny_profile_find_listener_by_device_name(profile, device_name, &listener); if(listener) { send_set_ringer(listener, skinny_str2ring_type(ring_type), skinny_str2ring_mode(ring_mode), 0, 0); + stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "Listener not found!\n"); } @@ -294,6 +295,7 @@ static switch_status_t skinny_api_cmd_profile_device_send_lamp_message(const cha skinny_profile_find_listener_by_device_name(profile, device_name, &listener); if(listener) { send_set_lamp(listener, skinny_str2button(stimulus), atoi(instance), skinny_str2lamp_mode(lamp_mode)); + stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "Listener not found!\n"); } @@ -313,6 +315,7 @@ static switch_status_t skinny_api_cmd_profile_device_send_speaker_mode_message(c skinny_profile_find_listener_by_device_name(profile, device_name, &listener); if(listener) { send_set_speaker_mode(listener, skinny_str2speaker_mode(speaker_mode)); + stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "Listener not found!\n"); } @@ -332,6 +335,7 @@ static switch_status_t skinny_api_cmd_profile_device_send_call_state_message(con skinny_profile_find_listener_by_device_name(profile, device_name, &listener); if(listener) { send_call_state(listener, skinny_str2call_state(call_state), atoi(line_instance), atoi(call_id)); + stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "Listener not found!\n"); } @@ -351,6 +355,7 @@ static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const ch skinny_profile_find_listener_by_device_name(profile, device_name, &listener); if(listener) { send_reset(listener, skinny_str2device_reset_type(reset_type)); + stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "Listener not found!\n"); } @@ -366,7 +371,10 @@ static switch_status_t skinny_api_cmd_profile_set(const char *profile_name, cons skinny_profile_t *profile; if ((profile = skinny_find_profile(profile_name))) { - if (skinny_profile_set(profile, name, value) != SWITCH_STATUS_SUCCESS) { + if (skinny_profile_set(profile, name, value) == SWITCH_STATUS_SUCCESS) { + skinny_profile_respawn(profile, 0); + stream->write_function(stream, "+OK\n"); + } else { stream->write_function(stream, "Unable to set skinny setting '%s'. Does it exists?\n", name); } } else { diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index c519dc4bf5..1aea812574 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -122,6 +122,9 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req) while (listener_is_ready(listener)) { uint8_t do_sleep = 1; + if (listener->expire_time && listener->expire_time < switch_epoch_time_now(NULL)) { + return SWITCH_STATUS_TIMEOUT; + } if(bytes < SKINNY_MESSAGE_FIELD_SIZE) { /* We have nothing yet, get length header field */ mlen = SKINNY_MESSAGE_FIELD_SIZE - bytes; @@ -171,9 +174,6 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req) } } } - if (listener->expire_time && listener->expire_time < switch_epoch_time_now(NULL)) { - return SWITCH_STATUS_TIMEOUT; - } if (do_sleep) { switch_cond_next(); } diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index fe001c7b4d..236c667509 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -151,7 +151,7 @@ struct PACKED open_receive_channel_ack_message { /* SoftKeyEventMessage */ #define SOFT_KEY_EVENT_MESSAGE 0x0026 struct PACKED soft_key_event_message { - uint32_t event; + uint32_t event; /* See enum skinny_soft_key_event */ uint32_t line_instance; uint32_t call_id; }; diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 2f640a8345..3fa4aab6c4 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -999,6 +999,8 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r const char *value = switch_xml_attr_soft(xparam, "value"); if (!strcasecmp(name, "skinny-firmware-version")) { strncpy(listener->firmware_version, value, 16); + } else if (!strcasecmp(name, "skinny-soft-key-set-set")) { + listener->soft_key_set_set = switch_core_strdup(profile->pool, value); } } } @@ -1693,49 +1695,20 @@ end: switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_message_t *request) { - skinny_message_t *message; - skinny_profile_t *profile; + skinny_message_t *message = NULL; - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_set)); - message->type = SOFT_KEY_SET_RES_MESSAGE; - message->length = 4 + sizeof(message->data.soft_key_set); - - message->data.soft_key_set.soft_key_set_offset = 0; - message->data.soft_key_set.soft_key_set_count = 11; - message->data.soft_key_set.total_soft_key_set_count = 11; - - /* TODO fill the set */ - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_NEWCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[2] = SOFTKEY_ENDCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[0] = SOFTKEY_BACKSPACE; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[2] = SOFTKEY_ENDCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[0] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[1] = SOFTKEY_HOLD; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[2] = SOFTKEY_NEWCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[3] = SOFTKEY_TRANSFER; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ANSWER; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[2] = SOFTKEY_NEWCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_NEWCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_RESUME; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[2] = SOFTKEY_ENDCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES].soft_key_template_index[1] = SOFTKEY_REDIAL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES].soft_key_template_index[2] = SOFTKEY_ENDCALL; - - skinny_send_reply(listener, message); + if (listener->soft_key_set_set) { + message = switch_core_hash_find(listener->profile->soft_key_set_sets_hash, listener->soft_key_set_set); + } + if (!message) { + message = switch_core_hash_find(listener->profile->soft_key_set_sets_hash, "default"); + } + if (message) { + skinny_send_reply(listener, message); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Profile %s doesn't have a default .\n", listener->profile->name); + } /* Init the states */ send_select_soft_keys(listener, 0, 0, SKINNY_KEY_SET_ON_HOOK, 0xffff); diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index f76e84320e..43b2290560 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -152,6 +152,32 @@ struct skinny_table SKINNY_BUTTONS[] = { SKINNY_DECLARE_ID2STR(skinny_button2str, SKINNY_BUTTONS, "Unknown") SKINNY_DECLARE_STR2ID(skinny_str2button, SKINNY_BUTTONS, -1) +struct skinny_table SKINNY_SOFT_KEY_EVENTS[] = { + {"SoftkeyRedial", SOFTKEY_REDIAL}, + {"SoftkeyNewcall", SOFTKEY_NEWCALL}, + {"SoftkeyHold", SOFTKEY_HOLD}, + {"SoftkeyTransfer", SOFTKEY_TRANSFER}, + {"SoftkeyCfwdall", SOFTKEY_CFWDALL}, + {"SoftkeyCfwdbusy", SOFTKEY_CFWDBUSY}, + {"SoftkeyCfwdnoanswer", SOFTKEY_CFWDNOANSWER}, + {"SoftkeyBackspace", SOFTKEY_BACKSPACE}, + {"SoftkeyEndcall", SOFTKEY_ENDCALL}, + {"SoftkeyResume", SOFTKEY_RESUME}, + {"SoftkeyAnswer", SOFTKEY_ANSWER }, + {"SoftkeyInfo", SOFTKEY_INFO}, + {"SoftkeyConfrm", SOFTKEY_CONFRM}, + {"SoftkeyPark", SOFTKEY_PARK}, + {"SoftkeyJoin", SOFTKEY_JOIN}, + {"SoftkeyMeetmeconfrm", SOFTKEY_MEETMECONFRM}, + {"SoftkeyCallpickup", SOFTKEY_CALLPICKUP}, + {"SoftkeyGrpcallpickup", SOFTKEY_GRPCALLPICKUP}, + {"SoftkeyDnd", SOFTKEY_DND}, + {"SoftkeyIdivert", SOFTKEY_IDIVERT}, + {NULL, 0} +}; +SKINNY_DECLARE_ID2STR(skinny_soft_key_event2str, SKINNY_SOFT_KEY_EVENTS, "SoftkeyUnknown") +SKINNY_DECLARE_STR2ID(skinny_str2soft_key_event, SKINNY_SOFT_KEY_EVENTS, 0) + struct skinny_table SKINNY_LAMP_MODES[] = { {"Off", SKINNY_LAMP_OFF}, {"On", SKINNY_LAMP_ON}, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index 6c9182516e..1747360264 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -194,6 +194,10 @@ enum skinny_soft_key_event { SOFTKEY_DND = 0x13, SOFTKEY_IDIVERT = 0x14, }; +extern struct skinny_table SKINNY_SOFT_KEY_EVENTS[21]; +const char *skinny_soft_key_event2str(uint32_t id); +uint32_t skinny_str2soft_key_event(const char *str); +#define SKINNY_PUSH_SOFT_KEY_EVENTS SKINNY_DECLARE_PUSH_MATCH(SOFT_KEY_EVENTS) enum skinny_key_set { SKINNY_KEY_SET_ON_HOOK = 0, diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index df88106262..c289d15a1f 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -697,7 +697,11 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX); - char *cid = generate_pai_str(session); + char *cid = NULL; + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) { + cid = generate_pai_str(session); + } if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) { /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless @@ -1761,7 +1765,14 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi nua_update(tech_pvt->nh, TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); - } + } else if ((ua && (switch_stristr("cisco", ua)))) { + snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" ", name, number, tech_pvt->profile->sipip); + + sofia_set_flag_locked(tech_pvt, TFLAG_UPDATING_DISPLAY); + nua_update(tech_pvt->nh, + TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); + } tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name); tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number); @@ -2158,7 +2169,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); - char *cid = generate_pai_str(session); + char *cid = NULL; + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) { + cid = generate_pai_str(session); + } if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 15efc1a3e4..82b933c981 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -4664,22 +4664,22 @@ void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *sess return; } - if (sofia_test_flag(tech_pvt, TFLAG_TRACKED)) { - sofia_glue_tech_untrack(profile, session, SWITCH_TRUE); - } - if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) { xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE); switch_xml_free(cdr); } if (xml_cdr_text) { - sql = switch_mprintf("insert into sip_recovery (runtime_uuid, profile_name, hostname, uuid, metadata) values ('%q','%q','%q','%q','%q')", - switch_core_get_uuid(), profile->name, mod_sofia_globals.hostname, switch_core_session_get_uuid(session), xml_cdr_text); - + if (sofia_test_flag(tech_pvt, TFLAG_TRACKED)) { + sql = switch_mprintf("update sip_recovery set metadata='%q' where uuid='%q'", xml_cdr_text, switch_core_session_get_uuid(session)); + } else { + + sql = switch_mprintf("insert into sip_recovery (runtime_uuid, profile_name, hostname, uuid, metadata) values ('%q','%q','%q','%q','%q')", + switch_core_get_uuid(), profile->name, mod_sofia_globals.hostname, switch_core_session_get_uuid(session), xml_cdr_text); + } + if (sofia_test_pflag(profile, PFLAG_TRACK_CALLS_EVENTS)) { switch_event_t *event = NULL; - if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_RECOVERY_SEND) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile_name", profile->name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sql", sql); @@ -4687,8 +4687,8 @@ void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *sess } } + sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); free(xml_cdr_text); sofia_set_flag(tech_pvt, TFLAG_TRACKED); diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index d22c79a9e4..c78ed90fe3 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -673,8 +673,8 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot) if (now && sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) { switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid," "expires,user_agent,server_user,server_host,profile_name" - " from sip_registrations where (status like '%%AUTO-NAT%%' " - "or status like '%%UDP-NAT%%') and hostname='%s'", mod_sofia_globals.hostname); + " from sip_registrations where (status like '%%NAT%%' " + "or contact like '%%fs_nat=true%%') and hostname='%s'", mod_sofia_globals.hostname); sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_nat_callback, profile); } @@ -1178,17 +1178,6 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET); - if (profile->reg_db_domain) { - if (!sofia_glue_profile_exists(to_host)) { - if (sofia_glue_add_profile(switch_core_strdup(profile->pool, to_host), profile) == SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Auto-Adding Alias [%s] for profile [%s]\n", to_host, profile->name); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Alias [%s] for profile [%s] (already exists)\n", - to_host, profile->name); - } - } - } - sql = switch_mprintf("insert into sip_registrations " "(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires," @@ -1430,6 +1419,17 @@ void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_h int network_port = 0; char *is_nat = NULL; + if (sip->sip_to && sip->sip_to->a_url && sip->sip_to->a_url->url_host) { + const char *to_host = sip->sip_to->a_url->url_host; + if (profile->reg_db_domain) { + if (!sofia_glue_profile_exists(to_host)) { + if (sofia_glue_add_profile(switch_core_strdup(profile->pool, to_host), profile) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Auto-Adding Alias [%s] for profile [%s]\n", to_host, profile->name); + } + } + } + } + sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); if (!(sip->sip_contact && sip->sip_contact->m_url)) { diff --git a/src/mod/languages/mod_lua/freeswitch.i b/src/mod/languages/mod_lua/freeswitch.i index 3631aca62f..383580103f 100644 --- a/src/mod/languages/mod_lua/freeswitch.i +++ b/src/mod/languages/mod_lua/freeswitch.i @@ -18,6 +18,10 @@ %} +/* Lua function typemap */ +%typemap(in,checkfn="lua_isfunction") SWIGLUA_FN +%{ $1.L=L; $1.idx=$input; %} + %ignore SwitchToMempool; %newobject EventConsumer::pop; @@ -25,6 +29,7 @@ %newobject CoreSession; %newobject Event; %newobject Stream; +%newobject Dbh; /** * tell swig to grok everything defined in these header files and @@ -66,9 +71,18 @@ class Session : public CoreSession { void setLUA(lua_State *state); }; + +class Dbh { + private: + switch_cache_db_handle_t *dbh; + bool connected; + static int query_callback(void *pArg, int argc, char **argv, char **cargv); + public: + Dbh(char *dsn, char *user = NULL, char *pass = NULL); + ~Dbh(); + bool release(); + bool query(char *sql, SWIGLUA_FN lua_fun); +}; + } - - - - diff --git a/src/mod/languages/mod_lua/freeswitch_lua.cpp b/src/mod/languages/mod_lua/freeswitch_lua.cpp index c73c88c553..17d12bc1cb 100644 --- a/src/mod/languages/mod_lua/freeswitch_lua.cpp +++ b/src/mod/languages/mod_lua/freeswitch_lua.cpp @@ -308,3 +308,69 @@ switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t ityp return SWITCH_STATUS_SUCCESS; } + +Dbh::Dbh(char *dsn, char *user, char *pass) +{ + switch_cache_db_connection_options_t options = { {0} }; + + options.odbc_options.dsn = dsn; + options.odbc_options.user = user; + options.odbc_options.pass = pass; + + if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) == SWITCH_STATUS_SUCCESS) { + connected = true; + } else { + connected = false; + } +} + +Dbh::~Dbh() +{ + release(); +} + +bool Dbh::release() +{ + if (connected) { + switch_cache_db_release_db_handle(&dbh); + connected = false; + return true; + } + return false; +} + +int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv) +{ + SWIGLUA_FN *lua_fun = (SWIGLUA_FN *)pArg; + + lua_pushvalue(lua_fun->L, lua_fun->idx); /* get the lua callback function onto the stack */ + + lua_newtable(lua_fun->L); /* push a row (table) */ + + for (int i = 0; i < argc; i++) { + lua_pushstring(lua_fun->L, switch_str_nil(cargv[i])); + lua_pushstring(lua_fun->L, switch_str_nil(argv[i])); + lua_settable(lua_fun->L, -3); + } + + lua_call(lua_fun->L, 1, 1); /* 1 in, 1 out */ + + if (lua_isnumber(lua_fun->L, -1)) { + if (lua_tonumber(lua_fun->L, -1) != 0) { + return 1; + } + } + + return 0; /* 0 to continue with next row */ +} + +bool Dbh::query(char *sql, SWIGLUA_FN lua_fun) +{ + if (connected) { + if (switch_cache_db_execute_sql_callback(dbh, sql, query_callback, &lua_fun, NULL) == SWITCH_STATUS_SUCCESS) { + return true; + } + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no workie workie :(\n"); + return false; +} diff --git a/src/mod/languages/mod_lua/freeswitch_lua.h b/src/mod/languages/mod_lua/freeswitch_lua.h index a1f4a85ce3..a0780b1537 100644 --- a/src/mod/languages/mod_lua/freeswitch_lua.h +++ b/src/mod/languages/mod_lua/freeswitch_lua.h @@ -8,6 +8,16 @@ extern "C" { #include "mod_lua_extra.h" } #include + + +typedef struct{ + lua_State* L; + int idx; +}SWIGLUA_FN; + +#define SWIGLUA_FN_GET(fn) {lua_pushvalue(fn.L,fn.idx);} + + namespace LUA { class Session:public CoreSession { private: @@ -41,5 +51,17 @@ namespace LUA { void setLUA(lua_State * state); }; + + class Dbh { + protected: + switch_cache_db_handle_t *dbh; + bool connected; + static int query_callback(void *pArg, int argc, char **argv, char **cargv); + public: + Dbh(char *dsn, char *user = NULL, char *pass = NULL); + ~Dbh(); + bool release(); + bool query(char *sql, SWIGLUA_FN lua_fun); + }; } #endif diff --git a/src/mod/languages/mod_lua/hack.diff b/src/mod/languages/mod_lua/hack.diff index afd37b086d..fc33ddb9d6 100644 --- a/src/mod/languages/mod_lua/hack.diff +++ b/src/mod/languages/mod_lua/hack.diff @@ -1,38 +1,38 @@ ---- mod_lua_wrap.cpp 2008-07-16 16:58:58.000000000 -0400 -+++ old.cpp 2008-07-16 16:58:42.000000000 -0400 -@@ -6731,7 +6731,7 @@ - SWIG_check_num_args("LUA::Session",0,0) +--- mod_lua_wrap.cpp.orig 2010-09-05 16:39:26.000000000 +0200 ++++ mod_lua_wrap.cpp 2010-09-05 16:39:44.000000000 +0200 +@@ -4913,7 +4913,7 @@ + result = (LUA::Session *)new LUA::Session(); SWIG_arg=0; - SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; result->setLUA(L); return SWIG_arg; - if(0) SWIG_fail; -@@ -6759,7 +6759,7 @@ - + fail: +@@ -4934,7 +4934,7 @@ + arg2=(CoreSession *)SWIG_MustGetPtr(L,2,SWIGTYPE_p_CoreSession,0,2,"new_Session"); result = (LUA::Session *)new LUA::Session(arg1,arg2); SWIG_arg=0; - SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; result->setLUA(L); return SWIG_arg; - if(0) SWIG_fail; -@@ -6780,7 +6780,7 @@ - arg1 = (char *)lua_tostring(L, 1); + fail: +@@ -4952,7 +4952,7 @@ + arg1 = (char*)lua_tostring(L, 1); result = (LUA::Session *)new LUA::Session(arg1); SWIG_arg=0; - SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; result->setLUA(L); return SWIG_arg; - if(0) SWIG_fail; -@@ -6805,7 +6805,7 @@ - + fail: +@@ -4970,7 +4970,7 @@ + arg1=(switch_core_session_t *)SWIG_MustGetPtr(L,1,SWIGTYPE_p_switch_core_session_t,0,1,"new_Session"); result = (LUA::Session *)new LUA::Session(arg1); SWIG_arg=0; - SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Session,1); SWIG_arg++; result->setLUA(L); return SWIG_arg; - if(0) SWIG_fail; + fail: diff --git a/src/mod/languages/mod_lua/mod_lua_wrap.cpp b/src/mod/languages/mod_lua/mod_lua_wrap.cpp index bdb50972a4..991b667a62 100644 --- a/src/mod/languages/mod_lua/mod_lua_wrap.cpp +++ b/src/mod/languages/mod_lua/mod_lua_wrap.cpp @@ -1490,29 +1490,31 @@ SWIG_Lua_dostring(lua_State *L, const char* str) { #define SWIGTYPE_p_Event swig_types[3] #define SWIGTYPE_p_EventConsumer swig_types[4] #define SWIGTYPE_p_IVRMenu swig_types[5] -#define SWIGTYPE_p_LUA__Session swig_types[6] -#define SWIGTYPE_p_Stream swig_types[7] -#define SWIGTYPE_p_input_callback_state swig_types[8] -#define SWIGTYPE_p_lua_State swig_types[9] -#define SWIGTYPE_p_p_switch_event_node_t swig_types[10] -#define SWIGTYPE_p_session_flag_t swig_types[11] -#define SWIGTYPE_p_switch_call_cause_t swig_types[12] -#define SWIGTYPE_p_switch_channel_state_t swig_types[13] -#define SWIGTYPE_p_switch_channel_t swig_types[14] -#define SWIGTYPE_p_switch_core_session_t swig_types[15] -#define SWIGTYPE_p_switch_event_t swig_types[16] -#define SWIGTYPE_p_switch_event_types_t swig_types[17] -#define SWIGTYPE_p_switch_input_args_t swig_types[18] -#define SWIGTYPE_p_switch_input_type_t swig_types[19] -#define SWIGTYPE_p_switch_priority_t swig_types[20] -#define SWIGTYPE_p_switch_queue_t swig_types[21] -#define SWIGTYPE_p_switch_state_handler_table_t swig_types[22] -#define SWIGTYPE_p_switch_status_t swig_types[23] -#define SWIGTYPE_p_switch_stream_handle_t swig_types[24] -#define SWIGTYPE_p_uint32_t swig_types[25] -#define SWIGTYPE_p_void swig_types[26] -static swig_type_info *swig_types[28]; -static swig_module_info swig_module = {swig_types, 27, 0, 0, 0, 0}; +#define SWIGTYPE_p_LUA__Dbh swig_types[6] +#define SWIGTYPE_p_LUA__Session swig_types[7] +#define SWIGTYPE_p_SWIGLUA_FN swig_types[8] +#define SWIGTYPE_p_Stream swig_types[9] +#define SWIGTYPE_p_input_callback_state swig_types[10] +#define SWIGTYPE_p_lua_State swig_types[11] +#define SWIGTYPE_p_p_switch_event_node_t swig_types[12] +#define SWIGTYPE_p_session_flag_t swig_types[13] +#define SWIGTYPE_p_switch_call_cause_t swig_types[14] +#define SWIGTYPE_p_switch_channel_state_t swig_types[15] +#define SWIGTYPE_p_switch_channel_t swig_types[16] +#define SWIGTYPE_p_switch_core_session_t swig_types[17] +#define SWIGTYPE_p_switch_event_t swig_types[18] +#define SWIGTYPE_p_switch_event_types_t swig_types[19] +#define SWIGTYPE_p_switch_input_args_t swig_types[20] +#define SWIGTYPE_p_switch_input_type_t swig_types[21] +#define SWIGTYPE_p_switch_priority_t swig_types[22] +#define SWIGTYPE_p_switch_queue_t swig_types[23] +#define SWIGTYPE_p_switch_state_handler_table_t swig_types[24] +#define SWIGTYPE_p_switch_status_t swig_types[25] +#define SWIGTYPE_p_switch_stream_handle_t swig_types[26] +#define SWIGTYPE_p_uint32_t swig_types[27] +#define SWIGTYPE_p_void swig_types[28] +static swig_type_info *swig_types[30]; +static swig_module_info swig_module = {swig_types, 29, 0, 0, 0, 0}; #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) @@ -7005,6 +7007,230 @@ static swig_lua_class *swig_LUA_Session_bases[] = {0,0}; static const char *swig_LUA_Session_base_names[] = {"CoreSession *",0}; static swig_lua_class _wrap_class_LUA_Session = { "Session", &SWIGTYPE_p_LUA__Session,_wrap_new_Session, swig_delete_Session, swig_LUA_Session_methods, swig_LUA_Session_attributes, swig_LUA_Session_bases, swig_LUA_Session_base_names }; +static int _wrap_new_Dbh__SWIG_0(lua_State* L) { + int SWIG_arg = -1; + char *arg1 = (char *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + LUA::Dbh *result = 0 ; + + SWIG_check_num_args("LUA::Dbh",3,3) + if(!lua_isstring(L,1)) SWIG_fail_arg("LUA::Dbh",1,"char *"); + if(!lua_isstring(L,2)) SWIG_fail_arg("LUA::Dbh",2,"char *"); + if(!lua_isstring(L,3)) SWIG_fail_arg("LUA::Dbh",3,"char *"); + arg1 = (char *)lua_tostring(L, 1); + arg2 = (char *)lua_tostring(L, 2); + arg3 = (char *)lua_tostring(L, 3); + result = (LUA::Dbh *)new LUA::Dbh(arg1,arg2,arg3); + SWIG_arg=0; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Dbh,1); SWIG_arg++; + return SWIG_arg; + + if(0) SWIG_fail; + +fail: + lua_error(L); + return SWIG_arg; +} + + +static int _wrap_new_Dbh__SWIG_1(lua_State* L) { + int SWIG_arg = -1; + char *arg1 = (char *) 0 ; + char *arg2 = (char *) 0 ; + LUA::Dbh *result = 0 ; + + SWIG_check_num_args("LUA::Dbh",2,2) + if(!lua_isstring(L,1)) SWIG_fail_arg("LUA::Dbh",1,"char *"); + if(!lua_isstring(L,2)) SWIG_fail_arg("LUA::Dbh",2,"char *"); + arg1 = (char *)lua_tostring(L, 1); + arg2 = (char *)lua_tostring(L, 2); + result = (LUA::Dbh *)new LUA::Dbh(arg1,arg2); + SWIG_arg=0; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Dbh,1); SWIG_arg++; + return SWIG_arg; + + if(0) SWIG_fail; + +fail: + lua_error(L); + return SWIG_arg; +} + + +static int _wrap_new_Dbh__SWIG_2(lua_State* L) { + int SWIG_arg = -1; + char *arg1 = (char *) 0 ; + LUA::Dbh *result = 0 ; + + SWIG_check_num_args("LUA::Dbh",1,1) + if(!lua_isstring(L,1)) SWIG_fail_arg("LUA::Dbh",1,"char *"); + arg1 = (char *)lua_tostring(L, 1); + result = (LUA::Dbh *)new LUA::Dbh(arg1); + SWIG_arg=0; + SWIG_NewPointerObj(L,result,SWIGTYPE_p_LUA__Dbh,1); SWIG_arg++; + return SWIG_arg; + + if(0) SWIG_fail; + +fail: + lua_error(L); + return SWIG_arg; +} + + +static int _wrap_new_Dbh(lua_State* L) { + int argc; + int argv[4]={ + 1,2,3,4 + }; + + argc = lua_gettop(L); + if (argc == 1) { + int _v; + { + _v = lua_isstring(L,argv[0]); + } + if (_v) { + return _wrap_new_Dbh__SWIG_2(L); + } + } + if (argc == 2) { + int _v; + { + _v = lua_isstring(L,argv[0]); + } + if (_v) { + { + _v = lua_isstring(L,argv[1]); + } + if (_v) { + return _wrap_new_Dbh__SWIG_1(L); + } + } + } + if (argc == 3) { + int _v; + { + _v = lua_isstring(L,argv[0]); + } + if (_v) { + { + _v = lua_isstring(L,argv[1]); + } + if (_v) { + { + _v = lua_isstring(L,argv[2]); + } + if (_v) { + return _wrap_new_Dbh__SWIG_0(L); + } + } + } + } + + lua_pushstring(L,"No matching function for overloaded 'new_Dbh'"); + lua_error(L);return 0; +} + + +static int _wrap_delete_Dbh(lua_State* L) { + int SWIG_arg = -1; + LUA::Dbh *arg1 = (LUA::Dbh *) 0 ; + + SWIG_check_num_args("LUA::~Dbh",1,1) + if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("LUA::~Dbh",1,"LUA::Dbh *"); + + if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,SWIG_POINTER_DISOWN))){ + SWIG_fail_ptr("delete_Dbh",1,SWIGTYPE_p_LUA__Dbh); + } + + delete arg1; + + SWIG_arg=0; + + return SWIG_arg; + + if(0) SWIG_fail; + +fail: + lua_error(L); + return SWIG_arg; +} + + +static int _wrap_Dbh_release(lua_State* L) { + int SWIG_arg = -1; + LUA::Dbh *arg1 = (LUA::Dbh *) 0 ; + bool result; + + SWIG_check_num_args("release",1,1) + if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("release",1,"LUA::Dbh *"); + + if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,0))){ + SWIG_fail_ptr("Dbh_release",1,SWIGTYPE_p_LUA__Dbh); + } + + result = (bool)(arg1)->release(); + SWIG_arg=0; + lua_pushboolean(L,(int)(result==true)); SWIG_arg++; + return SWIG_arg; + + if(0) SWIG_fail; + +fail: + lua_error(L); + return SWIG_arg; +} + + +static int _wrap_Dbh_query(lua_State* L) { + int SWIG_arg = -1; + LUA::Dbh *arg1 = (LUA::Dbh *) 0 ; + char *arg2 = (char *) 0 ; + SWIGLUA_FN arg3 ; + bool result; + + SWIG_check_num_args("query",3,3) + if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("query",1,"LUA::Dbh *"); + if(!lua_isstring(L,2)) SWIG_fail_arg("query",2,"char *"); + if(!lua_isfunction(L,3)) SWIG_fail_arg("query",3,"SWIGLUA_FN"); + + if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,0))){ + SWIG_fail_ptr("Dbh_query",1,SWIGTYPE_p_LUA__Dbh); + } + + arg2 = (char *)lua_tostring(L, 2); + (&arg3)->L=L; (&arg3)->idx=3; + result = (bool)(arg1)->query(arg2,arg3); + SWIG_arg=0; + lua_pushboolean(L,(int)(result==true)); SWIG_arg++; + return SWIG_arg; + + if(0) SWIG_fail; + +fail: + lua_error(L); + return SWIG_arg; +} + + +static void swig_delete_Dbh(void *obj) { +LUA::Dbh *arg1 = (LUA::Dbh *) obj; +delete arg1; +} +static swig_lua_method swig_LUA_Dbh_methods[] = { + {"release", _wrap_Dbh_release}, + {"query", _wrap_Dbh_query}, + {0,0} +}; +static swig_lua_attribute swig_LUA_Dbh_attributes[] = { + {0,0,0} +}; +static swig_lua_class *swig_LUA_Dbh_bases[] = {0}; +static const char *swig_LUA_Dbh_base_names[] = {0}; +static swig_lua_class _wrap_class_LUA_Dbh = { "Dbh", &SWIGTYPE_p_LUA__Dbh,_wrap_new_Dbh, swig_delete_Dbh, swig_LUA_Dbh_methods, swig_LUA_Dbh_attributes, swig_LUA_Dbh_bases, swig_LUA_Dbh_base_names }; + #ifdef __cplusplus } #endif @@ -7043,7 +7269,9 @@ static swig_type_info _swigt__p_DTMF = {"_p_DTMF", "DTMF *", 0, 0, (void*)&_wrap static swig_type_info _swigt__p_Event = {"_p_Event", "Event *", 0, 0, (void*)&_wrap_class_Event, 0}; static swig_type_info _swigt__p_EventConsumer = {"_p_EventConsumer", "EventConsumer *", 0, 0, (void*)&_wrap_class_EventConsumer, 0}; static swig_type_info _swigt__p_IVRMenu = {"_p_IVRMenu", "IVRMenu *", 0, 0, (void*)&_wrap_class_IVRMenu, 0}; +static swig_type_info _swigt__p_LUA__Dbh = {"_p_LUA__Dbh", "LUA::Dbh *", 0, 0, (void*)&_wrap_class_LUA_Dbh, 0}; static swig_type_info _swigt__p_LUA__Session = {"_p_LUA__Session", "LUA::Session *", 0, 0, (void*)&_wrap_class_LUA_Session, 0}; +static swig_type_info _swigt__p_SWIGLUA_FN = {"_p_SWIGLUA_FN", "SWIGLUA_FN *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_Stream = {"_p_Stream", "Stream *", 0, 0, (void*)&_wrap_class_Stream, 0}; static swig_type_info _swigt__p_input_callback_state = {"_p_input_callback_state", "input_callback_state_t *|input_callback_state *", 0, 0, (void*)&_wrap_class_input_callback_state_t, 0}; static swig_type_info _swigt__p_lua_State = {"_p_lua_State", "lua_State *", 0, 0, (void*)0, 0}; @@ -7072,7 +7300,9 @@ static swig_type_info *swig_type_initial[] = { &_swigt__p_Event, &_swigt__p_EventConsumer, &_swigt__p_IVRMenu, + &_swigt__p_LUA__Dbh, &_swigt__p_LUA__Session, + &_swigt__p_SWIGLUA_FN, &_swigt__p_Stream, &_swigt__p_input_callback_state, &_swigt__p_lua_State, @@ -7101,7 +7331,9 @@ static swig_cast_info _swigc__p_DTMF[] = { {&_swigt__p_DTMF, 0, 0, 0},{0, 0, 0, static swig_cast_info _swigc__p_Event[] = { {&_swigt__p_Event, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_EventConsumer[] = { {&_swigt__p_EventConsumer, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_IVRMenu[] = { {&_swigt__p_IVRMenu, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_LUA__Dbh[] = { {&_swigt__p_LUA__Dbh, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_LUA__Session[] = { {&_swigt__p_LUA__Session, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SWIGLUA_FN[] = { {&_swigt__p_SWIGLUA_FN, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_Stream[] = { {&_swigt__p_Stream, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_input_callback_state[] = { {&_swigt__p_input_callback_state, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_lua_State[] = { {&_swigt__p_lua_State, 0, 0, 0},{0, 0, 0, 0}}; @@ -7130,7 +7362,9 @@ static swig_cast_info *swig_cast_initial[] = { _swigc__p_Event, _swigc__p_EventConsumer, _swigc__p_IVRMenu, + _swigc__p_LUA__Dbh, _swigc__p_LUA__Session, + _swigc__p_SWIGLUA_FN, _swigc__p_Stream, _swigc__p_input_callback_state, _swigc__p_lua_State, diff --git a/src/mod/languages/mod_lua/my_swigable_cpp.h b/src/mod/languages/mod_lua/my_swigable_cpp.h index d4d3168a63..ebe597260f 100644 --- a/src/mod/languages/mod_lua/my_swigable_cpp.h +++ b/src/mod/languages/mod_lua/my_swigable_cpp.h @@ -49,6 +49,19 @@ class Event { }; +class Dbh { + protected: + switch_cache_db_handle_t *dbh; + bool connected; + static int query_callback(void *pArg, int argc, char **argv, char **cargv); + public: + Dbh(char *dsn, char *user = NULL, char *pass = NULL); + ~Dbh(); + bool release(); + bool query(char *sql, SWIGLUA_FN lua_fun); +}; + + class CoreSession { protected: switch_input_args_t args; diff --git a/src/switch_channel.c b/src/switch_channel.c index d1308a1e9f..e3d77d7239 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2035,6 +2035,36 @@ SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *ch switch_mutex_unlock(channel->profile_mutex); } +SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile) +{ + switch_assert(channel != NULL); + switch_assert(channel->caller_profile != NULL); + + switch_mutex_lock(channel->profile_mutex); + + if (channel->caller_profile) { + caller_profile->next = channel->caller_profile->origination_caller_profile; + channel->caller_profile->origination_caller_profile = caller_profile; + } + switch_assert(channel->caller_profile->origination_caller_profile->next != channel->caller_profile->origination_caller_profile); + switch_mutex_unlock(channel->profile_mutex); +} + +SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel) +{ + switch_caller_profile_t *profile = NULL; + switch_assert(channel != NULL); + + switch_mutex_lock(channel->profile_mutex); + if (channel->caller_profile) { + profile = channel->caller_profile->origination_caller_profile; + } + switch_mutex_unlock(channel->profile_mutex); + + return profile; +} + + SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile) { switch_assert(channel != NULL); diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 74131644f9..9e942fea5e 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -524,6 +524,14 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_ switch_channel_set_originator_caller_profile(peer_channel, cloned_profile); } } + + + if ((profile = switch_channel_get_caller_profile(peer_channel))) { + if ((cloned_profile = switch_caller_profile_clone(session, profile)) != 0) { + switch_channel_set_origination_caller_profile(channel, cloned_profile); + } + } + } if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_OUTGOING) == SWITCH_STATUS_SUCCESS) { diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index feb92b3c80..3a5e0bb6e2 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -35,6 +35,8 @@ #include #include "private/switch_core_pvt.h" +#define SQLLEN 32768 + static struct { switch_cache_db_handle_t *event_db; switch_queue_t *sql_queue[2]; @@ -537,7 +539,7 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql(switch_cache_db_hand switch (dbh->type) { default: { - status = switch_cache_db_execute_sql_chunked(dbh, (char *) sql, 32768, err); + status = switch_cache_db_execute_sql_chunked(dbh, (char *) sql, SQLLEN, err); } break; } @@ -845,7 +847,7 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand -#define SQLLEN 1024 * 1024 + static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, void *obj) { void *pop; @@ -853,13 +855,14 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, uint8_t trans = 0, nothing_in_queue = 0; uint32_t target = 100000; switch_size_t len = 0, sql_len = SQLLEN; - char *tmp, *sqlbuf = (char *) malloc(sql_len); - char *sql; + char *sqlbuf = (char *) malloc(sql_len); + char *sql = NULL; switch_size_t newlen; int lc = 0; uint32_t loops = 0, sec = 0; uint32_t l1 = 1000; uint32_t sanity = 120; + int item_remained = 0; switch_assert(sqlbuf); @@ -897,10 +900,17 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, continue; } - if (switch_queue_trypop(sql_manager.sql_queue[0], &pop) == SWITCH_STATUS_SUCCESS || - switch_queue_trypop(sql_manager.sql_queue[1], &pop) == SWITCH_STATUS_SUCCESS) { - sql = (char *) pop; + //printf("SIZE %d %d\n", switch_queue_size(sql_manager.sql_queue[0]), switch_queue_size(sql_manager.sql_queue[1])); + if (item_remained || switch_queue_trypop(sql_manager.sql_queue[0], &pop) == SWITCH_STATUS_SUCCESS || + switch_queue_trypop(sql_manager.sql_queue[1], &pop) == SWITCH_STATUS_SUCCESS) { + + if (item_remained) { + item_remained = 0; + } else { + sql = (char *) pop; + } + if (sql) { newlen = strlen(sql) + 2; @@ -911,20 +921,18 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, /* ignore abnormally large strings sql strings as potential buffer overflow */ if (newlen < SQLLEN) { itterations++; - if (len + newlen > sql_len) { - sql_len = len + SQLLEN; - if (!(tmp = realloc(sqlbuf, sql_len))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "SQL thread ending on mem err\n"); - abort(); - break; - } - sqlbuf = tmp; + + if (len + newlen < sql_len) { + sprintf(sqlbuf + len, "%s;\n", sql); + len += newlen; + } else { + item_remained = 1; } - sprintf(sqlbuf + len, "%s;\n", sql); - len += newlen; - } - free(sql); + + if (!item_remained) { + free(sql); + } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "SQL thread ending\n"); break; @@ -934,7 +942,8 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, } - if (trans && ((itterations == target) || (nothing_in_queue && ++lc >= 500))) { + if ((item_remained || (trans && ((itterations == target) || (nothing_in_queue && ++lc >= 500)))) && + (sql_manager.event_db->native_handle.core_db_dbh)) { if (switch_cache_db_persistant_execute_trans(sql_manager.event_db, sqlbuf, 1) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "SQL thread unable to commit transaction, records lost!\n"); } diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 61deece636..c1dc33651c 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -2012,6 +2012,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_ cp_off += switch_ivr_set_xml_profile_data(x_main_cp, caller_profile, 0); + if (caller_profile->origination_caller_profile) { + switch_caller_profile_t *cp = NULL; + int off = 0; + if (!(x_o = switch_xml_add_child_d(x_main_cp, "origination", cp_off++))) { + goto error; + } + + for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) { + if (!(x_caller_profile = switch_xml_add_child_d(x_o, "origination_caller_profile", off++))) { + goto error; + } + switch_ivr_set_xml_profile_data(x_caller_profile, cp, 0); + } + } + if (caller_profile->originator_caller_profile) { switch_caller_profile_t *cp = NULL; int off = 0; diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index 0ef3624326..67325648b2 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -1683,16 +1683,20 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * { switch_api_interface_t *api; switch_status_t status; - char *arg_no_spaces; - char *cmd_no_spaces; + char *arg_used; + char *cmd_used; switch_assert(stream != NULL); switch_assert(stream->data != NULL); switch_assert(stream->write_function != NULL); - - cmd_no_spaces = switch_strip_whitespace(cmd); - arg_no_spaces = switch_strip_whitespace(arg); + if (strcasecmp(cmd, "console_complete")) { + cmd_used = switch_strip_whitespace(cmd); + arg_used = switch_strip_whitespace(arg); + } else { + cmd_used = (char *) cmd; + arg_used = (char *) arg; + } if (!stream->param_event) { @@ -1700,17 +1704,17 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * } if (stream->param_event) { - if (cmd_no_spaces) { - switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command", cmd_no_spaces); + if (cmd_used) { + switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command", cmd_used); } - if (arg_no_spaces) { - switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_no_spaces); + if (arg_used) { + switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_used); } } - if (cmd_no_spaces && (api = switch_loadable_module_get_api_interface(cmd_no_spaces)) != 0) { - if ((status = api->function(arg_no_spaces, session, stream)) != SWITCH_STATUS_SUCCESS) { + if (cmd_used && (api = switch_loadable_module_get_api_interface(cmd_used)) != 0) { + if ((status = api->function(arg_used, session, stream)) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "COMMAND RETURNED ERROR!\n"); } UNPROTECT_INTERFACE(api); @@ -1723,8 +1727,13 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * switch_event_fire(&stream->param_event); } - switch_safe_free(cmd_no_spaces); - switch_safe_free(arg_no_spaces); + if (cmd_used != cmd) { + switch_safe_free(cmd_used); + } + + if (arg_used != arg) { + switch_safe_free(arg_used); + } return status; }