From a65ba2429833eda44fbd286806a14cc5350d0391 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Jul 2014 21:45:24 -0400 Subject: [PATCH 01/91] mod_freetdm: Added 'ftdm cas' command to read/write raw CAS bits --- libs/freetdm/mod_freetdm/mod_freetdm.c | 93 ++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 227d5a698f..57e11718bb 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -5243,6 +5243,98 @@ end: return SWITCH_STATUS_SUCCESS; } +#define CASINTS(cas) ((cas) & (1 << 3)) ? 1 : 0, \ + ((cas) & (1 << 2)) ? 1 : 0, \ + ((cas) & (1 << 1)) ? 1 : 0, \ + ((cas) & (1 << 0)) ? 1 : 0 +FTDM_CLI_DECLARE(ftdm_cmd_cas) +{ + uint32_t chan_id = 0; + switch_bool_t do_read = SWITCH_FALSE; + ftdm_channel_t *chan; + ftdm_iterator_t *iter = NULL; + ftdm_iterator_t *curr = NULL; + ftdm_span_t *span = NULL; + const char *write_bits_str = ""; + int32_t abcd_bits = 0; + + if (argc < 3) { + print_usage(stream, cli); + goto end; + } + + if (!strcasecmp(argv[1], "read")) { + do_read = SWITCH_TRUE; + chan_id = argc > 3 ? atoi(argv[3]) : 0; + } else if (!strcasecmp(argv[1], "write") && argc >= 4) { + const char *str = NULL; + int mask = 0x08; + do_read = SWITCH_FALSE; + if (argc == 4) { + chan_id = 0; + write_bits_str = argv[3]; + } else { + chan_id = atoi(argv[3]); + write_bits_str = argv[4]; + } + if (strlen(write_bits_str) != 4) { + stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str); + goto end; + } + str = write_bits_str; + while (*str) { + if (*str == '1') { + abcd_bits |= mask; + } else if (*str != '0') { + stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str); + goto end; + } + str++; + mask = (mask >> 1); + } + } else { + print_usage(stream, cli); + goto end; + } + + ftdm_span_find_by_name(argv[2], &span); + if (!span) { + stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]); + goto end; + } + + if (chan_id) { + if (chan_id > ftdm_span_get_chan_count(span)) { + stream->write_function(stream, "-ERR invalid channel\n"); + goto end; + } + chan = ftdm_span_get_channel(span, chan_id); + if (do_read) { + ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits); + stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits); + } else { + stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id); + } + } else { + iter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = iter; curr; curr = ftdm_iterator_next(curr)) { + chan = ftdm_iterator_current(curr); + //ftdm_channel_command(); + chan_id = ftdm_channel_get_id(chan); + if (do_read) { + ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits); + stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits); + } else { + stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id); + } + } + ftdm_iterator_free(iter); + } + stream->write_function(stream, "+OK\n"); +end: + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(ftdm_api_exec_usage) { char *mycmd = NULL, *argv[10] = { 0 }; @@ -5323,6 +5415,7 @@ static ftdm_cli_entry_t ftdm_cli_options[] = { "queuesize", " []", "", NULL, ftdm_cmd_queuesize, NULL }, { "iostats", "enable|disable|flush|print ", "::[enable:disable:flush:print", NULL, ftdm_cmd_iostats, NULL }, { "ioread", " [num_times] [interval]", "", NULL, ftdm_cmd_ioread, NULL }, + { "cas", "read|write [] []", "::[read:write", NULL, ftdm_cmd_cas, NULL }, /* Stand-alone commands (not part of the generic ftdm API */ { "ftdm_usage", " ", "", "Return channel call count", NULL, ftdm_api_exec_usage }, From 61101e325f93259da0369e60f6857cfb64c3ca38 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Jul 2014 21:51:32 -0400 Subject: [PATCH 02/91] freetdm: ftmod_analog_em: Added support for suspending channels that are offhook --- .../ftmod/ftmod_analog_em/ftdm_analog_em.h | 6 +- .../ftmod/ftmod_analog_em/ftmod_analog_em.c | 60 ++++++++++++++----- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h b/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h index 121381d522..e52a319155 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h @@ -44,10 +44,12 @@ #define MAX_DIALSTRING 256 typedef enum { - FTDM_ANALOG_EM_RUNNING = (1 << 0) + FTDM_ANALOG_EM_RUNNING = (1 << 0), + FTDM_ANALOG_EM_LOCAL_WRITE = (1 << 2), + FTDM_ANALOG_EM_LOCAL_SUSPEND = (1 << 3), + FTDM_ANALOG_EM_REMOTE_SUSPEND = (1 << 4), } ftdm_analog_em_flag_t; - struct ftdm_analog_data { uint32_t flags; uint32_t max_dialstr; diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c index 8a537bb5e6..146885f271 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c @@ -178,8 +178,7 @@ static ftdm_status_t ftdm_analog_em_sig_write(ftdm_channel_t *ftdmchan, void *da ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data; if (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA && analog_data->immediate_ringback - && ftdmchan->call_data) { - /* DO NOT USE ftdmchan->call_data, as is a dummy non-null pointer */ + && ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE)) { /* ringback is being played in the analog thread, ignore user data for now */ return FTDM_BREAK; } @@ -283,7 +282,7 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_em_get_span_sig_status) return FTDM_SUCCESS; } -static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) +static ftdm_status_t analog_em_set_channel_sig_status_ex(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status, ftdm_bool_t remote) { switch (status) { case FTDM_SIG_STATE_DOWN: @@ -299,17 +298,30 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) } ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED); } + if (remote) { + ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND); + } else { + ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND); + } break; case FTDM_SIG_STATE_UP: if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { - int cas_bits = 0x00; - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); - ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) { - ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); + if (remote) { + ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND); + } else { + ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND); } - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { - ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); + if (!ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND) && + !ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND)) { + int cas_bits = 0x00; + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) { + ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); + } + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { + ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); + } } } break; @@ -320,6 +332,11 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) return FTDM_SUCCESS; } +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) +{ + return analog_em_set_channel_sig_status_ex(ftdmchan, status, FTDM_FALSE); +} + static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status) { ftdm_iterator_t *chaniter = NULL; @@ -335,7 +352,7 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status) ftdm_channel_t *fchan = ftdm_iterator_current(citer); /* we set channel's state through analog_em_set_channel_sig_status(), since it already takes care of notifying the user when appropriate */ ftdm_channel_lock(fchan); - if ((analog_em_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) { + if ((analog_em_set_channel_sig_status_ex(fchan, status, FTDM_FALSE)) != FTDM_SUCCESS) { ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status)); } ftdm_channel_unlock(fchan); @@ -496,6 +513,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) uint32_t cas_hangup = 0; int cas_answer_ms = 500; int cas_hangup_ms = 500; + ftdm_bool_t busy_timeout = FTDM_FALSE; FILE *ringback_f = NULL; ftdm_bool_t digits_sent = FTDM_FALSE; @@ -762,6 +780,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) indicate = 1; } else { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + busy_timeout = FTDM_TRUE; } } break; @@ -925,17 +944,25 @@ read_try: } } - /* we must lock the channel and make sure we let our own generated audio thru (ftdmchan->call_data is tested in the ftdm_analog_em_sig_write handler)*/ + /* we must lock the channel and make sure we let our own generated audio thru (FTDM_ANALOG_EM_LOCAL_WRITE is tested in the ftdm_analog_em_sig_write handler)*/ ftdm_channel_lock(ftdmchan); - ftdmchan->call_data = (void *)0xFF; /* ugh! */ + ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE); ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen); - ftdmchan->call_data = NULL; + ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE); ftdm_channel_unlock(ftdmchan); } done: ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); + if (busy_timeout) { + ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CAS_BITS, &cas_bits); + if (cas_bits == 0XF) { + /* the remote end never sent any digits, neither moved to onhook, let's stay suspended */ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Moving channel to suspended after timeout, remote end still offhook\n"); + analog_em_set_channel_sig_status_ex(ftdmchan, FTDM_SIG_STATE_SUSPENDED, FTDM_TRUE); + } + } closed_chan = ftdmchan; ftdm_channel_close(&ftdmchan); @@ -984,6 +1011,11 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_mutex_lock(event->channel->mutex); locked++; + if (event->enum_id == FTDM_OOB_ONHOOK && ftdm_test_sflag(event->channel, FTDM_ANALOG_EM_REMOTE_SUSPEND)) { + /* We've got remote suspend, now we're back on hook, lift the remote suspend status */ + analog_em_set_channel_sig_status_ex(event->channel, FTDM_SIG_STATE_UP, FTDM_TRUE); + } + if (ftdm_test_flag(event->channel, FTDM_CHANNEL_SUSPENDED)) { ftdm_log(FTDM_LOG_WARNING, "Ignoring event %s on channel %d:%d in state %s, channel is suspended\n", ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state)); From 09198ee3572f4c99d07eed5512dec2ebfd6f2104 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 22 Jul 2014 23:44:17 -0400 Subject: [PATCH 03/91] freetdm: Raise some buffer limits --- libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h | 2 +- libs/freetdm/src/include/freetdm.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h index 9a4046bf3d..b42d72bcfd 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h @@ -43,7 +43,7 @@ typedef enum { FTDM_ANALOG_POLARITY_CALLERID = (1 << 4) } ftdm_analog_flag_t; -#define FTDM_MAX_HOTLINE_STR 20 +#define FTDM_MAX_HOTLINE_STR 32 #define MAX_DTMF 256 struct ftdm_analog_data { diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 1aa337b943..2b29d4f396 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -74,10 +74,10 @@ extern "C" { #endif /*! \brief Limit to span names */ -#define FTDM_MAX_NAME_STR_SZ 80 +#define FTDM_MAX_NAME_STR_SZ 128 /*! \brief Limit to channel number strings */ -#define FTDM_MAX_NUMBER_STR_SZ 20 +#define FTDM_MAX_NUMBER_STR_SZ 32 /*! \brief Hangup cause codes */ typedef enum { @@ -343,7 +343,7 @@ typedef enum { FTDM_STR2ENUM_P(ftdm_str2ftdm_transfer_response, ftdm_transfer_response2str, ftdm_transfer_response_t) /*! \brief Digit limit used in DNIS/ANI */ -#define FTDM_DIGITS_LIMIT 25 +#define FTDM_DIGITS_LIMIT 64 #define FTDM_SILENCE_VALUE(fchan) (fchan)->native_codec == FTDM_CODEC_ULAW ? 255 : (fchan)->native_codec == FTDM_CODEC_ALAW ? 0xD5 : 0x00 From b80cdd45d5e3a255871074e4b1acff8f61a13262 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 23 Jul 2014 00:40:27 -0400 Subject: [PATCH 04/91] freetdm: Added release guard time configuration Currently only enabled in the analog e&m module but any signaling module can easily take advantage of it with a small modification to the signaling module to set span->sig_release_guard_time_ms --- libs/freetdm/mod_freetdm/mod_freetdm.c | 12 ++++++++++-- libs/freetdm/src/ftdm_io.c | 14 ++++++++++++++ .../src/ftmod/ftmod_analog_em/ftmod_analog_em.c | 7 +++++++ libs/freetdm/src/include/private/ftdm_core.h | 2 ++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 57e11718bb..e9fbba34d4 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -566,7 +566,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) } if (!uuid_found) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s. Nothing to do.\n", span_id, chan_id, name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s\n", span_id, chan_id, name); goto end; } @@ -3827,6 +3827,7 @@ static switch_status_t load_config(void) const char *tonegroup = NULL; char *digit_timeout = NULL; char *dial_timeout = NULL; + char *release_guard_time_ms = NULL; char *max_digits = NULL; char *dial_regex = NULL; char *hold_music = NULL; @@ -3836,7 +3837,7 @@ static switch_status_t load_config(void) char *answer_supervision = str_false; char *immediate_ringback = str_false; char *ringback_file = str_empty; - uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0; + uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0, release_guard_time_ms_int = 0; ftdm_span_t *span = NULL; analog_option_t analog_options = ANALOG_OPTION_NONE; @@ -3850,6 +3851,8 @@ static switch_status_t load_config(void) digit_timeout = val; } else if (!strcasecmp(var, "dial-timeout")) { dial_timeout = val; + } else if (!strcasecmp(var, "release-guard-time-ms")) { + release_guard_time_ms = val; } else if (!strcasecmp(var, "context")) { context = val; } else if (!strcasecmp(var, "dialplan")) { @@ -3890,6 +3893,10 @@ static switch_status_t load_config(void) dial_timeout_int = atoi(dial_timeout); } + if (release_guard_time_ms) { + release_guard_time_ms_int = atoi(release_guard_time_ms); + } + if (max_digits) { max = atoi(max_digits); } @@ -3925,6 +3932,7 @@ static switch_status_t load_config(void) "ringback_file", ringback_file, "digit_timeout", &to, "dial_timeout", &dial_timeout_int, + "release_guard_time_ms", &release_guard_time_ms_int, "max_dialstr", &max, FTDM_TAG_END) != FTDM_SUCCESS) { LOAD_ERROR("Error starting FreeTDM span %d\n", span_id); diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 57d5af1b85..ec6c2fb757 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1490,6 +1490,15 @@ static __inline__ int chan_is_avail(ftdm_channel_t *check) return 0; } } + /* release guard time check */ + if (check->span->sig_release_guard_time_ms && check->last_release_time) { + ftdm_time_t time_diff = (check->last_release_time - ftdm_current_time_in_ms()); + if (time_diff < check->span->sig_release_guard_time_ms) { + return 0; + } + /* circuit now available for outbound dialing */ + check->last_release_time = 0; + } return 1; } @@ -2982,6 +2991,11 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE); } + + if (ftdmchan->span->sig_release_guard_time_ms) { + ftdmchan->last_release_time = ftdm_current_time_in_ms(); + } + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n"); return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c index 146885f271..98fde2a514 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c @@ -378,6 +378,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) uint32_t digit_timeout = 2000; uint32_t max_dialstr = 11; uint32_t dial_timeout = 0; + uint32_t release_guard_time_ms = 500; ftdm_bool_t answer_supervision = FTDM_FALSE; const char *var, *val; int *intval; @@ -429,6 +430,11 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) break; } max_dialstr = *intval; + } else if (!strcasecmp(var, "release_guard_time_ms")) { + if (!(intval = va_arg(ap, int *))) { + break; + } + release_guard_time_ms = *intval; } else { ftdm_log(FTDM_LOG_ERROR, "Invalid parameter for analog em span: '%s'\n", var); return FTDM_FAIL; @@ -460,6 +466,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) span->get_span_sig_status = analog_em_get_span_sig_status; span->set_channel_sig_status = analog_em_set_channel_sig_status; span->set_span_sig_status = analog_em_set_span_sig_status; + span->sig_release_guard_time_ms = release_guard_time_ms; ftdm_span_load_tones(span, tonemap); if (immediate_ringback || !ftdm_strlen_zero(ringback_file)) { analog_data->immediate_ringback = FTDM_TRUE; diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 728390dd54..15d8ff248b 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -477,6 +477,7 @@ struct ftdm_channel { int32_t rxdrops; ftdm_usrmsg_t *usrmsg; ftdm_time_t last_state_change_time; + ftdm_time_t last_release_time; }; struct ftdm_span { @@ -514,6 +515,7 @@ struct ftdm_span { ftdm_channel_sig_read_t sig_read; ftdm_channel_sig_write_t sig_write; ftdm_channel_sig_dtmf_t sig_dtmf; + uint32_t sig_release_guard_time_ms; ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */ void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */ char *type; From d65716d83ad3546bde2b459d75a7f23a8dba4025 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 27 Jul 2014 13:29:58 -0400 Subject: [PATCH 05/91] freetdm: Added dtmf_time_on and dtmf_time_off parameters to tweak DTMF duration in milliseconds --- libs/freetdm/src/ftdm_io.c | 18 ++++++++++++++++-- libs/freetdm/src/include/freetdm.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index ec6c2fb757..099035409f 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -3457,7 +3457,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdmchan->dtmf_on = val; GOTO_STATUS(done, FTDM_SUCCESS); } else { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "invalid value %d range 10-1000", val); GOTO_STATUS(done, FTDM_FAIL); } } @@ -3471,7 +3471,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdmchan->dtmf_off = val; GOTO_STATUS(done, FTDM_SUCCESS); } else { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "invalid value %d range 10-1000", val); GOTO_STATUS(done, FTDM_FAIL); } } @@ -5108,6 +5108,12 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const if (chan_config->dtmf_on_start) { span->channels[chan_index]->dtmfdetect.trigger_on_start = 1; } + if (chan_config->dtmf_time_on) { + ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_DTMF_ON_PERIOD, &chan_config->dtmf_time_on); + } + if (chan_config->dtmf_time_off) { + ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_DTMF_OFF_PERIOD, &chan_config->dtmf_time_off); + } } return FTDM_SUCCESS; @@ -5347,6 +5353,14 @@ static ftdm_status_t load_config(void) chan_config.dtmf_on_start = FTDM_FALSE; } } + } else if (!strcasecmp(var, "dtmf_time_on")) { + if (sscanf(val, "%u", &(chan_config.dtmf_time_on)) != 1) { + ftdm_log(FTDM_LOG_ERROR, "invalid dtmf_time_on: '%s'\n", val); + } + } else if (!strcasecmp(var, "dtmf_time_off")) { + if (sscanf(val, "%u", &(chan_config.dtmf_time_off)) != 1) { + ftdm_log(FTDM_LOG_ERROR, "invalid dtmf_time_off: '%s'\n", val); + } } else if (!strncasecmp(var, "iostats", sizeof("iostats")-1)) { if (ftdm_true(val)) { chan_config.iostats = FTDM_TRUE; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 2b29d4f396..443afc7fd0 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -521,6 +521,8 @@ typedef struct ftdm_channel_config { uint8_t debugdtmf; uint8_t dtmf_on_start; uint32_t dtmfdetect_ms; + uint32_t dtmf_time_on; + uint32_t dtmf_time_off; uint8_t iostats; } ftdm_channel_config_t; From 69d5cda6d67074d6e5c1b7038b4dd7cab0adf60f Mon Sep 17 00:00:00 2001 From: Antonio Date: Tue, 9 Sep 2014 15:33:19 +0200 Subject: [PATCH 06/91] resolve FS-6809 --- src/mod/endpoints/mod_sofia/mod_sofia.c | 46 ++++++++++++++++++------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index aff86a6331..43d486e575 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -2919,15 +2919,27 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl for (x = 0; x < profile->rtpip_index; x++) { stream->write_function(stream, " %s\n", switch_str_nil(profile->rtpip[x])); } - stream->write_function(stream, " %s\n", profile->extrtpip); + if (profile->extrtpip) { + stream->write_function(stream, " %s\n", profile->extrtpip); + } stream->write_function(stream, " %s\n", switch_str_nil(profile->sipip)); - stream->write_function(stream, " %s\n", profile->extsipip); - stream->write_function(stream, " %s\n", switch_str_nil(profile->url)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->bindurl)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_url)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_bindurl)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->ws_bindurl)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->wss_bindurl)); + if (profile->extsipip) { + stream->write_function(stream, " %s\n", profile->extsipip); + } + if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->url)); + stream->write_function(stream, " %s\n", switch_str_nil(profile->bindurl)); + } + if (sofia_test_pflag(profile, PFLAG_TLS)) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_url)); + stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_bindurl)); + } + if (profile->ws_bindurl) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->ws_bindurl)); + } + if (profile->wss_bindurl) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->wss_bindurl)); + } stream->write_function(stream, " %s\n", zstr(profile->hold_music) ? "N/A" : profile->hold_music); stream->write_function(stream, " %s\n", zstr(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy); @@ -2935,9 +2947,13 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl stream->write_function(stream, " %s\n", switch_str_nil(profile->outbound_codec_string)); stream->write_function(stream, " %d\n", profile->te); - stream->write_function(stream, " rfc2833\n"); - stream->write_function(stream, " info\n"); - stream->write_function(stream, " none\n"); + if (profile->dtmf_type == DTMF_2833) { + stream->write_function(stream, " rfc2833\n"); + } else if (profile->dtmf_type == DTMF_INFO) { + stream->write_function(stream, " info\n"); + } else { + stream->write_function(stream, " none\n"); + } stream->write_function(stream, " %d\n", profile->cng_pt); stream->write_function(stream, " %d\n", profile->session_timeout); stream->write_function(stream, " %d\n", profile->max_proceeding); @@ -2947,9 +2963,13 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl stream->write_function(stream, " %s\n", sofia_test_flag(profile, TFLAG_ZRTP_PASSTHRU) ? "true" : "false"); stream->write_function(stream, " %s\n", sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false"); - stream->write_function(stream, " %s\n", switch_str_nil(profile->user_agent_filter)); - stream->write_function(stream, " %d\n", + if (profile->user_agent_filter) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->user_agent_filter)); + } + if (profile->max_registrations_perext > 0) { + stream->write_function(stream, " %d\n", profile->max_registrations_perext); + } stream->write_function(stream, " %u\n", profile->ib_calls); stream->write_function(stream, " %u\n", profile->ob_calls); stream->write_function(stream, " %u\n", profile->ib_failed_calls); From 8e4423f126b9476123c6fa8c41c5f8ebfe1d0cb5 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 15 Sep 2014 15:36:48 +0200 Subject: [PATCH 07/91] Document Dbh.test_reactive, return saner values In the FreeSWITCH core, the return value of switch_case_db_test_reactive is ignored, but it is usable in LUA modules (and other bindings via SWIG). The LUA API example[1] shows how to check the return value, but that example miserably fails if the database did not exist before. Changes: - Document the expected behavior of the test_reactive function. - Assert that test_sql and sql_reactive are both given. If either query is not given, the caller is using the wrong API. - When SCF_AUTO_SCHEMAS is cleared, use the return value of the test_sql execution. Does anybody use this? Why not remove it? - Do not unconditionally return SWITCH_FALSE when test_sql fails, instead allow it to become SWITCH_TRUE when reactive_sql passes. - Remove the unnecessary test_sql check for SCDB_TYPE_CORE_DB (this is now enforced through an assert check). (+reindent) - Clarify the error message of drop_sql, prepending "Ignoring" to the "SQL ERR" message. - LUA: Do not print "DBH NOT Connected" if the query fails. This was the initial source of confusion. [1]: https://confluence.freeswitch.org/display/FREESWITCH/Lua+API+Reference --- src/mod/languages/mod_lua/freeswitch_lua.cpp | 4 +- .../languages/mod_lua/freeswitch_lua.cpp | 4 +- src/switch_core_sqldb.c | 65 ++++++++++++------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/mod/languages/mod_lua/freeswitch_lua.cpp b/src/mod/languages/mod_lua/freeswitch_lua.cpp index 12a663c3a7..593ff8a6c4 100644 --- a/src/mod/languages/mod_lua/freeswitch_lua.cpp +++ b/src/mod/languages/mod_lua/freeswitch_lua.cpp @@ -394,9 +394,9 @@ bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql) if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) { return true; } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); return false; } diff --git a/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp b/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp index efef9679e7..39076e6225 100644 --- a/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp +++ b/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp @@ -394,9 +394,9 @@ bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql) if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) { return true; } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); return false; } diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 31e835e760..adcfbcf300 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1267,20 +1267,36 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback_err(switch_ return status; } +/*! + * \brief Performs test_sql and if it fails performs drop_sql and reactive_sql. + * + * If auto-clear-sql is disabled, then this function will do nothing and it is + * assumed that the queries are not needed. If auto-create-schemas is disabled, + * then just test_sql is executed, but drop_sql and reactive_sql are not. + * + * Otherwise, test_sql gets executed. If that succeeds, then there is nothing to + * do. Otherwise drop_sql is executed (its result is ignored) and then finally + * reactive_sql is executed. + * + * \return If auto-create-schemas is enabled, SWITCH_TRUE is returned if + * test_sql succeeds, SWITCH_FALSE otherwise. If reactive_sql is executed + * successfully SWITCH_TRUE is returned, otherwise SWITCH_FALSE is returned. + */ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_handle_t *dbh, const char *test_sql, const char *drop_sql, const char *reactive_sql) { - char *errmsg; switch_bool_t r = SWITCH_TRUE; switch_mutex_t *io_mutex = dbh->io_mutex; + switch_assert(test_sql != NULL); + switch_assert(reactive_sql != NULL); + if (!switch_test_flag((&runtime), SCF_CLEAR_SQL)) { return SWITCH_TRUE; } if (!switch_test_flag((&runtime), SCF_AUTO_SCHEMAS)) { - switch_cache_db_execute_sql(dbh, (char *)test_sql, NULL); - return SWITCH_TRUE; + return switch_cache_db_execute_sql(dbh, (char *)test_sql, NULL); } if (io_mutex) switch_mutex_lock(io_mutex); @@ -1289,49 +1305,48 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand case SCDB_TYPE_PGSQL: { if (switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, test_sql, NULL) != SWITCH_PGSQL_SUCCESS) { - r = SWITCH_FALSE; if (drop_sql) { switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, drop_sql, NULL); } - switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, reactive_sql, NULL); + r = switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, reactive_sql, NULL) == SWITCH_PGSQL_SUCCESS; } } break; case SCDB_TYPE_ODBC: { if (switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, test_sql, NULL, NULL) != SWITCH_ODBC_SUCCESS) { - r = SWITCH_FALSE; if (drop_sql) { switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, drop_sql, NULL, NULL); } - switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, reactive_sql, NULL, NULL); + r = switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, reactive_sql, NULL, NULL) == SWITCH_ODBC_SUCCESS; } } break; case SCDB_TYPE_CORE_DB: { - if (test_sql) { - switch_core_db_exec(dbh->native_handle.core_db_dbh, test_sql, NULL, NULL, &errmsg); + char *errmsg = NULL; + switch_core_db_exec(dbh->native_handle.core_db_dbh, test_sql, NULL, NULL, &errmsg); + if (errmsg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\nAuto Generating Table!\n", errmsg, test_sql); + switch_core_db_free(errmsg); + errmsg = NULL; + if (drop_sql) { + switch_core_db_exec(dbh->native_handle.core_db_dbh, drop_sql, NULL, NULL, &errmsg); + } if (errmsg) { - r = SWITCH_FALSE; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\nAuto Generating Table!\n", errmsg, test_sql); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring SQL ERR [%s]\n[%s]\n", errmsg, drop_sql); switch_core_db_free(errmsg); errmsg = NULL; - if (drop_sql) { - switch_core_db_exec(dbh->native_handle.core_db_dbh, drop_sql, NULL, NULL, &errmsg); - } - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\n", errmsg, drop_sql); - switch_core_db_free(errmsg); - errmsg = NULL; - } - switch_core_db_exec(dbh->native_handle.core_db_dbh, reactive_sql, NULL, NULL, &errmsg); - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\n", errmsg, reactive_sql); - switch_core_db_free(errmsg); - errmsg = NULL; - } + } + switch_core_db_exec(dbh->native_handle.core_db_dbh, reactive_sql, NULL, NULL, &errmsg); + if (errmsg) { + r = SWITCH_FALSE; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\n", errmsg, reactive_sql); + switch_core_db_free(errmsg); + errmsg = NULL; + } else { + r = SWITCH_TRUE; } } } From 3695bdd9e4e0d925ab7296d2f4ce120bf656f623 Mon Sep 17 00:00:00 2001 From: Hristo Trendev Date: Wed, 24 Sep 2014 14:55:50 +0200 Subject: [PATCH 08/91] set conference flags from a dial plan variable or via +flags{ } This patch allows conference flags to be set dynamically from the dial plan by either passing them to the conference application in the +flags{ } string or by setting the "conference_flags" dial plan variable. The +flags{ } string is currently used to set *user* flags only. This patch changes this by allowing the +flags{ } string to contain conference related flags as well (for example wait_mod). It shouldn't be a problem to pass both types of flags via +flags{ } as long as the user and conference flag names are kept unique. FS-5099 #resolve --- .../applications/mod_conference/mod_conference.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index c431f11286..9ac4dd18ae 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -9066,6 +9066,7 @@ SWITCH_STANDARD_APP(conference_function) char *profile_name = NULL; switch_xml_t cxml = NULL, cfg = NULL, profiles = NULL; const char *flags_str, *v_flags_str; + const char *cflags_str, *v_cflags_str; member_flag_t mflags = 0; switch_core_session_message_t msg = { 0 }; uint8_t rl = 0, isbr = 0; @@ -9129,6 +9130,16 @@ SWITCH_STANDARD_APP(conference_function) } } + cflags_str = flags_str; + + if ((v_cflags_str = switch_channel_get_variable(channel, "conference_flags"))) { + if (zstr(cflags_str)) { + cflags_str = v_cflags_str; + } else { + cflags_str = switch_core_session_sprintf(session, "%s|%s", cflags_str, v_cflags_str); + } + } + /* is this a bridging conference ? */ if (!strncasecmp(mydata, bridge_prefix, strlen(bridge_prefix))) { isbr = 1; @@ -9219,6 +9230,8 @@ SWITCH_STANDARD_APP(conference_function) goto done; } + set_cflags(cflags_str, &conference->flags); + if (locked) { switch_mutex_unlock(globals.setup_mutex); locked = 0; @@ -9294,6 +9307,8 @@ SWITCH_STANDARD_APP(conference_function) goto done; } + set_cflags(cflags_str, &conference->flags); + if (locked) { switch_mutex_unlock(globals.setup_mutex); locked = 0; From afb00b2ecc8a9b049801f3f475c80e1111070fa8 Mon Sep 17 00:00:00 2001 From: Spencer Thomason Date: Tue, 16 Sep 2014 19:53:12 +0000 Subject: [PATCH 09/91] Force rport on ADTRAN TA Devices ADTRAN Total Access devices do not support sending the rport parameter in the Via header. This allows us to detect the device and force rport when using the "safe" parameter, enabling the device to be used behind NAT. FS-6823 #resolve --- libs/sofia-sip/libsofia-sip-ua/nta/nta.c | 4 +++- src/mod/endpoints/mod_sofia/sofia_reg.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 98d1ad25e1..bb68025749 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -3188,7 +3188,9 @@ int agent_check_request_via(nta_agent_t *agent, else if (agent->sa_server_rport == 2 || (agent->sa_server_rport == 3 && sip && sip->sip_user_agent && sip->sip_user_agent->g_string && - (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20)))) { + (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || + !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || + !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) { rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port)); msg_header_replace_param(msg_home(msg), v->v_common, rport); } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 053ddd9a9e..9eacc1f576 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1499,7 +1499,9 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu if (!is_tcp && !is_tls && (zstr(network_ip) || !switch_check_network_list_ip(network_ip, profile->local_network)) && profile->server_rport_level >= 2 && sip->sip_user_agent && sip->sip_user_agent->g_string && - ( !strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) )) { + ( !strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || + !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || + !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19) )) { if (sip && sip->sip_via) { const char *host = sip->sip_via->v_host; const char *c_port = sip->sip_via->v_port; From 544c5faf5e6ce6fe2b87523304d1f00e2d201d90 Mon Sep 17 00:00:00 2001 From: "E. Schmidbauer" Date: Wed, 8 Oct 2014 08:31:35 -0400 Subject: [PATCH 10/91] Add module mod_odbc_cdr --- build/modules.conf.in | 1 + configure.ac | 1 + .../event_handlers/mod_odbc_cdr/Makefile.am | 9 + .../conf/autoload_configs/odbc_cdr.conf.xml | 58 ++ .../mod_odbc_cdr/mod_odbc_cdr.c | 565 ++++++++++++++++++ 5 files changed, 634 insertions(+) create mode 100644 src/mod/event_handlers/mod_odbc_cdr/Makefile.am create mode 100644 src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml create mode 100644 src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c diff --git a/build/modules.conf.in b/build/modules.conf.in index 71ece983ef..ecade12ef5 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -105,6 +105,7 @@ event_handlers/mod_event_socket #event_handlers/mod_format_cdr #event_handlers/mod_json_cdr #event_handlers/mod_radius_cdr +#event_handlers/mod_odbc_cdr #event_handlers/mod_rayo #event_handlers/mod_snmp formats/mod_local_stream diff --git a/configure.ac b/configure.ac index e8f9efade0..11b68a3a8e 100644 --- a/configure.ac +++ b/configure.ac @@ -1564,6 +1564,7 @@ AC_CONFIG_FILES([Makefile src/mod/event_handlers/mod_format_cdr/Makefile src/mod/event_handlers/mod_json_cdr/Makefile src/mod/event_handlers/mod_radius_cdr/Makefile + src/mod/event_handlers/mod_odbc_cdr/Makefile src/mod/event_handlers/mod_rayo/Makefile src/mod/event_handlers/mod_snmp/Makefile src/mod/event_handlers/mod_event_zmq/Makefile diff --git a/src/mod/event_handlers/mod_odbc_cdr/Makefile.am b/src/mod/event_handlers/mod_odbc_cdr/Makefile.am new file mode 100644 index 0000000000..ce799a3e1e --- /dev/null +++ b/src/mod/event_handlers/mod_odbc_cdr/Makefile.am @@ -0,0 +1,9 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_odbc_cdr + +mod_LTLIBRARIES = mod_odbc_cdr.la +mod_odbc_cdr_la_SOURCES = mod_odbc_cdr.c +mod_odbc_cdr_la_CFLAGS = $(AM_CFLAGS) +mod_odbc_cdr_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_odbc_cdr_la_LDFLAGS = -avoid-version -module -no-undefined -shared + diff --git a/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml b/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml new file mode 100644 index 0000000000..0e764d14ec --- /dev/null +++ b/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + +
+
+
diff --git a/src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c b/src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c new file mode 100644 index 0000000000..edfdbf08c4 --- /dev/null +++ b/src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c @@ -0,0 +1,565 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Emmanuel Schmidbauer + * + * mod_odbc_cdr.c + * + */ + +#include "switch.h" + +#define ODBC_CDR_SQLITE_DB_NAME "odbc_cdr" + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_odbc_cdr_shutdown); +SWITCH_MODULE_LOAD_FUNCTION(mod_odbc_cdr_load); +SWITCH_MODULE_DEFINITION(mod_odbc_cdr, mod_odbc_cdr_load, mod_odbc_cdr_shutdown, NULL); + +static const char *global_cf = "odbc_cdr.conf"; + +typedef enum { + ODBC_CDR_LOG_A, + ODBC_CDR_LOG_B, + ODBC_CDR_LOG_BOTH +} odbc_cdr_log_leg_t; + +typedef enum { + ODBC_CDR_CSV_ALWAYS, + ODBC_CDR_CSV_NEVER, + ODBC_CDR_CSV_ON_FAIL +} odbc_cdr_write_csv_t; + +static struct { + char *odbc_dsn; + char *dbname; + char *csv_path; + char *csv_fail_path; + odbc_cdr_log_leg_t log_leg; + odbc_cdr_write_csv_t write_csv; + switch_bool_t debug_sql; + switch_hash_t *table_hash; + uint32_t running; + switch_mutex_t *mutex; + switch_memory_pool_t *pool; +} globals; + +struct table_profile { + char *name; + odbc_cdr_log_leg_t log_leg; + switch_hash_t *field_hash; + uint32_t flags; + switch_mutex_t *mutex; + switch_memory_pool_t *pool; +}; +typedef struct table_profile table_profile_t; + +static table_profile_t *load_table(const char *table_name) +{ + table_profile_t *table = NULL; + switch_xml_t x_tables, cfg, xml, x_table, x_field; + + if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); + return table; + } + + if (!(x_tables = switch_xml_child(cfg, "tables"))) { + goto end; + } + + if ((x_table = switch_xml_find_child(x_tables, "table", "name", table_name))) { + switch_memory_pool_t *pool; + char *table_log_leg = (char *) switch_xml_attr_soft(x_table, "log-leg"); + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n"); + goto end; + } + + if (!(table = switch_core_alloc(pool, sizeof(table_profile_t)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n"); + switch_core_destroy_memory_pool(&pool); + goto end; + } + + table->pool = pool; + + switch_mutex_init(&table->mutex, SWITCH_MUTEX_NESTED, table->pool); + + table->name = switch_core_strdup(pool, table_name); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Found table [%s]\n", table->name); + + if (!strcasecmp(table_log_leg, "a-leg")) { + table->log_leg = ODBC_CDR_LOG_A; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set table [%s] to log A-legs only\n", table->name); + } else if (!strcasecmp(table_log_leg, "b-leg")) { + table->log_leg = ODBC_CDR_LOG_B; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set table [%s] to log B-legs only\n", table->name); + } else { + table->log_leg = ODBC_CDR_LOG_BOTH; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set table [%s] to log both legs\n", table->name); + } + + switch_core_hash_init(&table->field_hash); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding fields to table [%s]\n", table->name); + + for (x_field = switch_xml_child(x_table, "field"); x_field; x_field = x_field->next) { + char *var = (char *) switch_xml_attr_soft(x_field, "name"); + char *val = (char *) switch_xml_attr_soft(x_field, "chan-var-name"); + char *value = NULL; + if (zstr(var) || zstr(val)) { + continue; // Ignore empty entries + } + value = switch_core_strdup(pool, val); + switch_core_hash_insert_locked(table->field_hash, var, value, table->mutex); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Field [%s] (%s) added to [%s]\n", var, val, table->name); + } + + switch_core_hash_insert(globals.table_hash, table->name, table); + } + +end: + + if (xml) { + switch_xml_free(xml); + } + + return table; +} + +switch_cache_db_handle_t *get_db_handle(void) +{ + switch_cache_db_handle_t *dbh = NULL; + char *dsn; + if (!zstr(globals.odbc_dsn)) { + dsn = globals.odbc_dsn; + } else { + dsn = globals.dbname; + } + if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n"); + dbh = NULL; + } + return dbh; +} + +static switch_status_t odbc_cdr_execute_sql_no_callback(char *sql) +{ + switch_cache_db_handle_t *dbh = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!(dbh = get_db_handle())) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n"); + goto end; + } + + status = switch_cache_db_execute_sql(dbh, sql, NULL); + +end: + + switch_cache_db_release_db_handle(&dbh); + + return status; +} + +static void write_cdr(const char *path, const char *log_line) +{ + int fd = -1; +#ifdef _MSC_VER + if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { +#else + if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { +#endif + int wrote; + wrote = write(fd, log_line, (unsigned) strlen(log_line)); + wrote += write(fd, "\n", 1); + wrote++; + close(fd); + fd = -1; + } +} + +static switch_status_t odbc_cdr_reporting(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_memory_pool_t *pool = switch_core_session_get_pool(session); + switch_caller_profile_t *caller_profile = switch_channel_get_caller_profile(channel); + switch_hash_index_t *hi; + const void *var; + void *val; + switch_console_callback_match_t *matches = NULL; + switch_console_callback_match_node_t *m; + const char *uuid = NULL; + + if (globals.log_leg == ODBC_CDR_LOG_A && caller_profile->direction == SWITCH_CALL_DIRECTION_OUTBOUND) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Only logging A-Leg, ignoring B-leg\n"); + return SWITCH_STATUS_SUCCESS; + } else if (globals.log_leg == ODBC_CDR_LOG_B && caller_profile->direction == SWITCH_CALL_DIRECTION_INBOUND) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Only logging B-Leg, ignoring A-leg\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (!(uuid = switch_channel_get_variable(channel, "uuid"))) { + uuid = switch_core_strdup(pool, caller_profile->uuid); + } + + // copy all table names from global hash + switch_mutex_lock(globals.mutex); + for (hi = switch_core_hash_first(globals.table_hash); hi; hi = switch_core_hash_next(&hi)) { + switch_core_hash_this(hi, &var, NULL, &val); + switch_console_push_match(&matches, (const char *) var); + } + switch_mutex_unlock(globals.mutex); + + if (matches) { + table_profile_t *table = NULL; + + // loop through table names + for (m = matches->head; m; m = m->next) { + char *table_name = m->val; + switch_bool_t started = SWITCH_FALSE; + switch_bool_t skip_leg = SWITCH_FALSE; + + switch_mutex_lock(globals.mutex); + table = switch_core_hash_find(globals.table_hash, table_name); + switch_mutex_unlock(globals.mutex); + + if (!table) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Table [%s] not found, ignoring leg\n", table_name); + skip_leg = SWITCH_TRUE; + } + + if (table->log_leg == ODBC_CDR_LOG_A && caller_profile->direction == SWITCH_CALL_DIRECTION_OUTBOUND) { + skip_leg = SWITCH_TRUE; + } + + if (table->log_leg == ODBC_CDR_LOG_B && caller_profile->direction == SWITCH_CALL_DIRECTION_INBOUND) { + skip_leg = SWITCH_TRUE; + } + + if (skip_leg == SWITCH_FALSE) { + switch_hash_index_t *i_hi = NULL; + const void *i_var; + void *i_val; + char *field_hash_key; + char *field_hash_val; + char *sql = NULL; + char *full_path = NULL; + switch_stream_handle_t stream_field = { 0 }; + switch_stream_handle_t stream_value = { 0 }; + switch_bool_t insert_fail = SWITCH_FALSE; + + SWITCH_STANDARD_STREAM(stream_field); + SWITCH_STANDARD_STREAM(stream_value); + + for (i_hi = switch_core_hash_first_iter( table->field_hash, i_hi); i_hi; i_hi = switch_core_hash_next(&i_hi)) { + const char *tmp; + switch_core_hash_this(i_hi, &i_var, NULL, &i_val); + field_hash_key = (char *) i_var; + field_hash_val = (char *) i_val; + + if ((tmp = switch_channel_get_variable(channel, field_hash_val))) { + if (started == SWITCH_FALSE) { + stream_field.write_function(&stream_field, "%s", field_hash_key); + stream_value.write_function(&stream_value, "'%s'", tmp); + } else { + stream_field.write_function(&stream_field, ", %s", field_hash_key); + stream_value.write_function(&stream_value, ", '%s'", tmp); + } + started = SWITCH_TRUE; + } + + } + switch_safe_free(i_hi); + + sql = switch_mprintf("INSERT INTO %s (%s) VALUES (%s)", table_name, stream_field.data, stream_value.data); + if (globals.debug_sql == SWITCH_TRUE) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sql %s\n", sql); + } + if (odbc_cdr_execute_sql_no_callback(sql) == SWITCH_STATUS_FALSE) { + insert_fail = SWITCH_TRUE; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error executing query %s\n", sql); + } + + if (globals.write_csv == ODBC_CDR_CSV_ALWAYS) { + if (insert_fail == SWITCH_TRUE) { + full_path = switch_mprintf("%s%s%s.csv", globals.csv_fail_path, SWITCH_PATH_SEPARATOR, uuid); + } else { + full_path = switch_mprintf("%s%s%s.csv", globals.csv_path, SWITCH_PATH_SEPARATOR, uuid); + } + assert(full_path); + write_cdr(full_path, stream_value.data); + switch_safe_free(full_path); + } else if (globals.write_csv == ODBC_CDR_CSV_ON_FAIL && insert_fail == SWITCH_TRUE) { + full_path = switch_mprintf("%s%s%s.csv", globals.csv_fail_path, SWITCH_PATH_SEPARATOR, uuid); + assert(full_path); + write_cdr(full_path, stream_value.data); + switch_safe_free(full_path); + } + + switch_safe_free(sql); + + switch_safe_free(stream_field.data); + switch_safe_free(stream_value.data); + + } + + } + + switch_console_free_matches(&matches); + } + + switch_safe_free(hi); + + return SWITCH_STATUS_SUCCESS; +} + + +switch_state_handler_table_t odbc_cdr_state_handlers = { + /*.on_init */ NULL, + /*.on_routing */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ NULL, + /*.on_exchange_media */ NULL, + /*.on_soft_execute */ NULL, + /*.on_consume_media */ NULL, + /*.on_hibernate */ NULL, + /*.on_reset */ NULL, + /*.on_park */ NULL, + /*.on_reporting */ odbc_cdr_reporting, + /*.on_destroy */ NULL +}; + +static switch_status_t odbc_cdr_load_config(void) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_xml_t cfg, xml, settings, param, tables, table; + switch_cache_db_handle_t *dbh = NULL; + + switch_mutex_lock(globals.mutex); + + if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); + status = SWITCH_STATUS_TERM; + goto end; + } + + globals.debug_sql = SWITCH_FALSE; + globals.log_leg = ODBC_CDR_LOG_BOTH; + globals.write_csv = ODBC_CDR_CSV_NEVER; + + if ((settings = switch_xml_child(cfg, "settings")) != NULL) { + for (param = switch_xml_child(settings, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (zstr(var) || zstr(val)) { + continue; // Ignore empty entries + } + if (!strcasecmp(var, "dbname")) { + globals.dbname = strdup(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set dbname [%s]\n", globals.dbname); + } else if (!strcasecmp(var, "odbc-dsn")) { + globals.odbc_dsn = strdup(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set odbc-dsn [%s]\n", globals.odbc_dsn); + } else if (!strcasecmp(var, "log-leg")) { + if (!strcasecmp(val, "a-leg")) { + globals.log_leg = ODBC_CDR_LOG_A; + } else if (!strcasecmp(val, "b-leg")) { + globals.log_leg = ODBC_CDR_LOG_B; + } + } else if (!strcasecmp(var, "debug-sql") && switch_true(val)) { + globals.debug_sql = SWITCH_TRUE; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set debug-sql [true]\n"); + } else if (!strcasecmp(var, "write-csv") && !zstr(val)) { + if (!strcasecmp(val, "always")) { + globals.write_csv = ODBC_CDR_CSV_ALWAYS; + } else if (!strcasecmp(val, "on-db-fail")) { + globals.write_csv = ODBC_CDR_CSV_ON_FAIL; + } + } else if (!strcasecmp(var, "csv-path") && !zstr(val)) { + globals.csv_path = switch_mprintf("%s%s", val, SWITCH_PATH_SEPARATOR); + } else if (!strcasecmp(var, "csv-path-on-fail") && !zstr(val)) { + globals.csv_fail_path = switch_mprintf("%s%s", val, SWITCH_PATH_SEPARATOR); + } + } + } + + if (globals.log_leg == ODBC_CDR_LOG_A) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set log-leg [a-leg]\n"); + } else if (globals.log_leg == ODBC_CDR_LOG_B) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set log-leg [b-leg]\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set log-leg [both]\n"); + } + + if (!globals.csv_path) { + globals.csv_path = switch_mprintf("%s%sodbc-cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } + + if (!globals.csv_fail_path) { + globals.csv_fail_path = switch_mprintf("%s%sodbc-cdr-failed", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set csv-path [%s]\n", globals.csv_path); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set csv-path-on-fail [%s]\n", globals.csv_fail_path); + + if ((tables = switch_xml_child(cfg, "tables"))) { + for (table = switch_xml_child(tables, "table"); table; table = table->next) { + load_table(switch_xml_attr_soft(table, "name")); + } + } + + if (!globals.dbname) { + globals.dbname = strdup(ODBC_CDR_SQLITE_DB_NAME); + } + + // Initialize database + if (!(dbh = get_db_handle())) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n"); + status = SWITCH_STATUS_TERM; + goto end; + } + + switch_cache_db_release_db_handle(&dbh); + +end: + switch_mutex_unlock(globals.mutex); + + if (xml) { + switch_xml_free(xml); + } + + return status; +} + + +SWITCH_MODULE_LOAD_FUNCTION(mod_odbc_cdr_load) +{ + switch_status_t status; + + memset(&globals, 0, sizeof(globals)); + switch_core_hash_init(&globals.table_hash); + if (switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to initialize mutex\n"); + } + globals.pool = pool; + + if ((status = odbc_cdr_load_config()) != SWITCH_STATUS_SUCCESS) { + return status; + } + + if (globals.write_csv != ODBC_CDR_CSV_NEVER) { + if ((status = switch_dir_make_recursive(globals.csv_path, SWITCH_DEFAULT_DIR_PERMS, pool)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.csv_path); + return status; + } + if (strcasecmp(globals.csv_path, globals.csv_fail_path)) { + if ((status = switch_dir_make_recursive(globals.csv_fail_path, SWITCH_DEFAULT_DIR_PERMS, pool)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.csv_path); + return status; + } + } + } + + switch_mutex_lock(globals.mutex); + globals.running = 1; + switch_mutex_unlock(globals.mutex); + + switch_core_add_state_handler(&odbc_cdr_state_handlers); + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* + Called when the system shuts down + Macro expands to: switch_status_t mod_odbc_cdr_shutdown() */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_odbc_cdr_shutdown) +{ + switch_hash_index_t *hi = NULL; + table_profile_t *table; + void *val = NULL; + const void *key; + switch_ssize_t keylen; + + switch_mutex_lock(globals.mutex); + if (globals.running == 1) { + globals.running = 0; + } + + while ((hi = switch_core_hash_first_iter(globals.table_hash, hi))) { + switch_hash_index_t *field_hi = NULL; + void *field_val = NULL; + const void *field_key; + switch_ssize_t field_keylen; + + switch_core_hash_this(hi, &key, &keylen, &val); + table = (table_profile_t *) val; + + while ((field_hi = switch_core_hash_first_iter(table->field_hash, field_hi))) { + switch_core_hash_this(field_hi, &field_key, &field_keylen, &field_val); + switch_core_hash_delete_locked(table->field_hash, field_key, table->mutex); + } + switch_core_hash_destroy(&table->field_hash); + switch_safe_free(field_hi); + + switch_core_hash_delete(globals.table_hash, table->name); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying table %s\n", table->name); + + switch_core_destroy_memory_pool(&table->pool); + table = NULL; + } + switch_core_hash_destroy(&globals.table_hash); + switch_safe_free(hi); + + switch_safe_free(globals.csv_path) + switch_safe_free(globals.csv_fail_path) + switch_safe_free(globals.odbc_dsn); + switch_safe_free(globals.dbname); + + switch_mutex_unlock(globals.mutex); + switch_mutex_destroy(globals.mutex); + + switch_core_remove_state_handler(&odbc_cdr_state_handlers); + + return SWITCH_STATUS_SUCCESS; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ From 7c0cf506d84430bebb3923b8e43eae4871bcd87a Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:17:57 +0300 Subject: [PATCH 11/91] mod_managed: managedlist command must return value to api stream instead of log --- .../languages/mod_managed/managed/Loader.cs | 46 ++++++++++++------- src/mod/languages/mod_managed/mod_managed.cpp | 8 ++-- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index 19ab3a52db..c655c9c867 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -26,6 +26,7 @@ * Michael Giagnocavo * David Brazier * Jeff Lenk + * Artur Kraev * * Loader.cs -- mod_managed loader * @@ -33,7 +34,6 @@ using System; using System.Collections.Generic; -using System.Text; using System.IO; using System.Linq; using System.Reflection; @@ -46,16 +46,15 @@ namespace FreeSWITCH { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteDelegate(string cmd, IntPtr streamH, IntPtr eventH); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteBackgroundDelegate(string cmd); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool RunDelegate(string cmd, IntPtr session); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ListDelegate(string cmd); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); static readonly ExecuteDelegate _execute = Execute; static readonly ExecuteBackgroundDelegate _executeBackground = ExecuteBackground; static readonly RunDelegate _run = Run; static readonly ReloadDelegate _reload = Reload; - static readonly ListDelegate _list = List; + static readonly ExecuteDelegate _list = List; [DllImport("mod_managed", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ListDelegate list); + static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ExecuteDelegate list); static readonly object loaderLock = new object(); @@ -408,18 +407,33 @@ namespace FreeSWITCH { } } - public static bool List(string command) { - try { - Log.WriteLine(LogLevel.Info, "Available APIs:"); - getApiExecs().Values.ForEach(x => { - Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())); - }); - Log.WriteLine(LogLevel.Info, "Available Apps:"); - getAppExecs().Values.ForEach(x => { - Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())); - }); + public static bool List(string command, IntPtr streamHandle, IntPtr eventHandle) + { + try + { + if (streamHandle != IntPtr.Zero) + { + using (var stream = new Native.Stream(new Native.switch_stream_handle(streamHandle, false))) + { + stream.Write("Available APIs:\n"); + + getApiExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); + + stream.Write("Available Apps:\n"); + getAppExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); + } + } + else + { + Log.WriteLine(LogLevel.Info, "Available APIs:"); + getApiExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); + Log.WriteLine(LogLevel.Info, "Available Apps:"); + getAppExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); + } return true; - } catch (Exception ex) { + } + catch (Exception ex) + { Log.WriteLine(LogLevel.Error, "Exception listing managed modules: {0}", ex.ToString()); return false; } diff --git a/src/mod/languages/mod_managed/mod_managed.cpp b/src/mod/languages/mod_managed/mod_managed.cpp index 215a98336b..6718265d53 100644 --- a/src/mod/languages/mod_managed/mod_managed.cpp +++ b/src/mod/languages/mod_managed/mod_managed.cpp @@ -26,6 +26,7 @@ * Michael Giagnocavo * David Brazier * Jeff Lenk + * Artur Kraev * * mod_mono.cpp -- FreeSWITCH mod_mono main class * @@ -73,14 +74,13 @@ typedef int (*runFunction)(const char *data, void *sessionPtr); typedef int (*executeFunction)(const char *cmd, void *stream, void *Event); typedef int (*executeBackgroundFunction)(const char* cmd); typedef int (*reloadFunction)(const char* cmd); -typedef int (*listFunction)(const char* cmd); static runFunction runDelegate; static executeFunction executeDelegate; static executeBackgroundFunction executeBackgroundDelegate; static reloadFunction reloadDelegate; -static listFunction listDelegate; +static executeFunction listDelegate; -SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, listFunction list) +SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, executeFunction list) { runDelegate = run; executeDelegate = execute; @@ -451,7 +451,7 @@ SWITCH_STANDARD_API(managedlist_api_function) #ifndef _MANAGED mono_thread_attach(globals.domain); #endif - listDelegate(cmd); + listDelegate(cmd, stream, stream->param_event); #ifndef _MANAGED mono_thread_detach(mono_thread_current()); #endif From f3d089a998d52d07ff23110a86e0b57fd1b76c33 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:24:49 +0300 Subject: [PATCH 12/91] mod_managed: not crash when cannot remove shadow directory (this sometimes happens when restarting from FS console) --- src/mod/languages/mod_managed/managed/Loader.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index c655c9c867..a3d48fd1d1 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -64,13 +64,23 @@ namespace FreeSWITCH { public static bool Load() { managedDir = Path.Combine(Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir, "managed"); shadowDir = Path.Combine(managedDir, "shadow"); - if (Directory.Exists(shadowDir)) { - Directory.Delete(shadowDir, true); + if (Directory.Exists(shadowDir)) + { + try + { + Directory.Delete(shadowDir, true); + } + catch (Exception ex) + { + Log.WriteLine(LogLevel.Warning, "Cannot delete shadow directory: {0}", ex); + } + Directory.CreateDirectory(shadowDir); } Log.WriteLine(LogLevel.Debug, "FreeSWITCH.Managed loader is starting with directory '{0}'.", managedDir); - if (!Directory.Exists(managedDir)) { + if (!Directory.Exists(managedDir)) + { Log.WriteLine(LogLevel.Error, "Managed directory not found: {0}", managedDir); return false; } From 4037e782a586ba5862bd3666ff53a00906444399 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:32:30 +0300 Subject: [PATCH 13/91] mod_managed: support per-module references directory --- .../languages/mod_managed/managed/Loader.cs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index a3d48fd1d1..cee7af86c2 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -229,11 +229,38 @@ namespace FreeSWITCH { setup.ConfigurationFile = fileName + ".config"; } setup.ApplicationBase = Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir; - setup.ShadowCopyDirectories = managedDir + ";"; setup.LoaderOptimization = LoaderOptimization.MultiDomainHost; // TODO: would MultiDomain work better since FreeSWITCH.Managed isn't gac'd? setup.CachePath = shadowDir; setup.ShadowCopyFiles = "true"; - setup.PrivateBinPath = "managed"; + + // computing private bin path + var binPath = setup.PrivateBinPath ?? string.Empty; + + var binPaths = binPath.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + // adding "managed" (modules) directory + if (!binPaths.Contains("managed", StringComparer.OrdinalIgnoreCase)) + { + binPaths.Add("managed"); + } + + // adding "managed/" directory for per-module references support + var moduleRefsDir = Path.GetFileName(fileName); + moduleRefsDir = Path.GetFileNameWithoutExtension(moduleRefsDir); + + if (moduleRefsDir != null && moduleRefsDir.Trim() != "") + { + moduleRefsDir = Path.Combine("managed", moduleRefsDir); + if (!binPaths.Contains(moduleRefsDir, StringComparer.OrdinalIgnoreCase)) + { + binPaths.Add(moduleRefsDir); + } + } + + // bringing all together + setup.PrivateBinPath = string.Join(";", binPaths); // Create domain and load PM inside System.Threading.Interlocked.Increment(ref appDomainCount); From 10ebebaae0eacaed1fccf5b72185b09bb25cd210 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:34:04 +0300 Subject: [PATCH 14/91] mod_managed: added console log level --- src/mod/languages/mod_managed/managed/Log.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/languages/mod_managed/managed/Log.cs b/src/mod/languages/mod_managed/managed/Log.cs index 1c58ff1458..aa2bacf57e 100644 --- a/src/mod/languages/mod_managed/managed/Log.cs +++ b/src/mod/languages/mod_managed/managed/Log.cs @@ -57,6 +57,7 @@ namespace FreeSWITCH static string ToLogString(this LogLevel level) { switch (level) { + case LogLevel.Console: return "CONSOLE"; case LogLevel.Alert: return "ALERT"; case LogLevel.Critical: return "CRIT"; case LogLevel.Debug: return "DEBUG"; @@ -85,6 +86,7 @@ namespace FreeSWITCH };*/ public enum LogLevel { + Console, Debug, Info, Error, From 33cb9505003899c94386ae532e748616cba7c266 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:42:00 +0300 Subject: [PATCH 15/91] mod_managed: Added pure CreateStateHandlerDelegate in ManagedSession for native api usage --- .../mod_managed/managed/ManagedSession.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/mod/languages/mod_managed/managed/ManagedSession.cs b/src/mod/languages/mod_managed/managed/ManagedSession.cs index bed7a03878..84718df60f 100644 --- a/src/mod/languages/mod_managed/managed/ManagedSession.cs +++ b/src/mod/languages/mod_managed/managed/ManagedSession.cs @@ -149,6 +149,23 @@ namespace FreeSWITCH.Native }; return del; } + + /// Wraps a nice handler into a delegate suitable for reverse P/Invoke. For native api using + public static switch_state_handler_t_delegate CreateStateHandlerDelegate(Action handler) + { + // We create a ManagedSession on top of the session so callbacks can use it "nicely" + // Then we sort of dispose it. + switch_state_handler_t_delegate del = ptr => + { + using (var sess = new ManagedSession(new SWIGTYPE_p_switch_core_session(ptr, false))) + { + handler(sess); + return switch_status_t.SWITCH_STATUS_SUCCESS; + } + }; + return del; + } + public static SWIGTYPE_p_f_p_switch_core_session__switch_status_t WrapStateHandlerDelegate(switch_state_handler_t_delegate del) { return new SWIGTYPE_p_f_p_switch_core_session__switch_status_t(Marshal.GetFunctionPointerForDelegate(del), false); } From 889b678e58bf38eb86df7885b8f054d3d9d92d74 Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Mon, 3 Nov 2014 00:43:59 +0300 Subject: [PATCH 16/91] mod_managed: Added GetPtr to Util class for internal pointers extraction (very useful when using native api) --- src/mod/languages/mod_managed/managed/Util.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/mod/languages/mod_managed/managed/Util.cs b/src/mod/languages/mod_managed/managed/Util.cs index 18c2d89369..7fd5194770 100644 --- a/src/mod/languages/mod_managed/managed/Util.cs +++ b/src/mod/languages/mod_managed/managed/Util.cs @@ -46,5 +46,31 @@ namespace FreeSWITCH { if (cons == null) throw new ArgumentException(ty.Name + " constructor not found."); return (T)cons.Invoke(new object[] { cPtr, false }); } + + /// + /// Getting IntPtr from wrapper + /// + /// swig generated class + /// instance + /// Original pointer + public static IntPtr GetPtr(T obj) + { + // internal static HandleRef getCPtr(CoreSession obj) + var ty = typeof(T); + var bflags = BindingFlags.Static | BindingFlags.NonPublic; + var getCPtr = ty.GetMethod("getCPtr", bflags, null, new[] { typeof(T) }, null); + + if (getCPtr != null) + { + var handleRef = getCPtr.Invoke(null, new object[] { obj }); + + if (handleRef is HandleRef) + { + return ((HandleRef)handleRef).Handle; + } + } + + return IntPtr.Zero; + } } } From b5d8fa9f46efed950d69a353a193a87105a683f2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 3 Nov 2014 14:03:04 -0600 Subject: [PATCH 17/91] FS-6956 modify commit 16365501 to use one single line which is only tolerable way to have bracket-less if stmts. --- src/switch_stun.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/switch_stun.c b/src/switch_stun.c index 55f8a65eac..b29c48d325 100644 --- a/src/switch_stun.c +++ b/src/switch_stun.c @@ -129,9 +129,7 @@ SWITCH_DECLARE(switch_stun_packet_t *) switch_stun_packet_parse(uint8_t *buf, ui packet = (switch_stun_packet_t *) buf; packet->header.type = ntohs(packet->header.type); packet->header.length = ntohs(packet->header.length); - if (packet->header.length > (bytes_left -= 20)) - return NULL; - + if (packet->header.length > (bytes_left -= 20)) return NULL; /* * Check packet type (RFC3489(bis?) values) From 91bc09525f933954b4e998f5c6650e4d9c21adb1 Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 3 Nov 2014 14:15:04 -0600 Subject: [PATCH 18/91] Fix copy and paste error CID 1250786 --- src/mod/endpoints/mod_verto/mod_verto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 7fb0039188..c784d8d1a2 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -4286,7 +4286,7 @@ static switch_status_t parse_config(const char *cf) } if (zstr(vhost->script_root)) { - vhost->root = SWITCH_GLOBAL_dirs.script_dir; + vhost->script_root = SWITCH_GLOBAL_dirs.script_dir; } if (zstr(vhost->index)) { From 4b87056625ff1d6812f27b9ae8f6d0968809f986 Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 3 Nov 2014 14:17:24 -0600 Subject: [PATCH 19/91] remove debugging printf --- src/switch_channel.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/switch_channel.c b/src/switch_channel.c index 7fae7f16a2..3b96dcdc4d 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -4303,7 +4303,6 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_safe_free(substituted); substituted = switch_string_replace(substituted ? substituted : dtstr, replace, X); - printf("WTF [%s][%s]\n", replace, substituted); pcre_free_substring(replace); } } From a74e29affae4a882fa203655b047634dfe224dc8 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Tue, 4 Nov 2014 15:18:11 -0500 Subject: [PATCH 20/91] added mod_graylog2 and mod_mongo to RPM package. Added graylog.conf.xml to vanilla config, but disabled in modules.conf.xml --- .../autoload_configs/graylog2.conf.xml | 24 ++++++++++++ .../vanilla/autoload_configs/modules.conf.xml | 2 + freeswitch.spec | 39 ++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 conf/vanilla/autoload_configs/graylog2.conf.xml diff --git a/conf/vanilla/autoload_configs/graylog2.conf.xml b/conf/vanilla/autoload_configs/graylog2.conf.xml new file mode 100644 index 0000000000..0a05482bf8 --- /dev/null +++ b/conf/vanilla/autoload_configs/graylog2.conf.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml index e5a297e8af..092372d68c 100644 --- a/conf/vanilla/autoload_configs/modules.conf.xml +++ b/conf/vanilla/autoload_configs/modules.conf.xml @@ -3,6 +3,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/freeswitch.spec b/freeswitch.spec index 37cf8111b9..08596a8f4f 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -482,6 +482,14 @@ is a "high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load." +%package application-mongo +Summary: FreeSWITCH mod_mongo +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description application-mongo +Provides FreeSWITCH mod_mongo, which implements an API interface to mongodb. + %package application-nibblebill Summary: FreeSWITCH mod_nibblebill Group: System/Libraries @@ -1028,6 +1036,18 @@ BuildRequires: net-snmp-devel %description event-snmp SNMP stats reporter for the FreeSWITCH open source telephony platform +###################################################################################################################### +# FreeSWITCH Logger Modules +###################################################################################################################### + +%package logger-graylog2 +Summary: GELF logger for Graylog2 and Logstash +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description logger-graylog2 +GELF logger for Graylog2 and Logstash + ###################################################################################################################### # FreeSWITCH Media Format Modules ###################################################################################################################### @@ -1371,7 +1391,7 @@ APPLICATION_MODULES_DE+="applications/mod_esl" APPLICATION_MODULES_FR="applications/mod_fifo applications/mod_fsk applications/mod_fsv applications/mod_hash \ applications/mod_httapi applications/mod_http_cache applications/mod_lcr applications/mod_limit \ - applications/mod_memcache applications/mod_nibblebill applications/mod_redis applications/mod_rss" + applications/mod_memcache applications/mod_mongo applications/mod_nibblebill applications/mod_redis applications/mod_rss" APPLICATION_MODULES_SZ="applications/mod_sms applications/mod_snapshot applications/mod_snom applications/mod_soundtouch \ applications/mod_spandsp applications/mod_spy applications/mod_stress \ @@ -1463,7 +1483,7 @@ LANGUAGES_MODULES="languages/mod_lua languages/mod_perl languages/mod_python " # Logging Modules # ###################################################################################################################### -LOGGERS_MODULES="loggers/mod_console loggers/mod_logfile loggers/mod_syslog" +LOGGERS_MODULES="loggers/mod_console loggers/mod_graylog2 loggers/mod_logfile loggers/mod_syslog" ###################################################################################################################### # @@ -1807,6 +1827,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/fax.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/fifo.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/format_cdr.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/graylog2.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/hash.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/httapi.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/http_cache.conf.xml @@ -1968,6 +1989,9 @@ fi %files application-memcache %{MODINSTDIR}/mod_memcache.so* +%files application-mongo +%{MODINSTDIR}/mod_mongo.so* + %files application-nibblebill %{MODINSTDIR}/mod_nibblebill.so* @@ -2339,6 +2363,15 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/lang/sv/vm/*.xml %{MODINSTDIR}/mod_say_sv.so* +###################################################################################################################### +# +# Logger Modules +# +###################################################################################################################### + +%files logger-graylog2 +%{MODINSTDIR}/mod_graylog2.so* + ###################################################################################################################### # # Timer Modules @@ -2371,6 +2404,8 @@ fi # ###################################################################################################################### %changelog +* Tue Nov 04 2014 - crienzo@grasshopper.com +- add mod_graylog2 and mod_mongo * Thu Sep 11 2014 - krice@freeswitch.org - add and fix mod_verto and mod_rtc * Mon Jun 02 2014 - krice@freeswitch.org From 831832c2c62aaec9039bfc5e2d081b960d5856f4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 4 Nov 2014 18:31:39 -0600 Subject: [PATCH 21/91] FS-6890 #please test --- libs/sofia-sip/.update | 2 +- .../libsofia-sip-ua/nua/nua_session.c | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index fb3ae1977e..cc65611429 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Fri Oct 31 13:48:09 CDT 2014 +Tue Nov 4 18:30:40 CST 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index 933d76249e..c589722ebd 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -1543,38 +1543,48 @@ static void nua_session_usage_refresh(nua_handle_t *nh, nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); nua_client_request_t const *cr = du->du_cr; nua_server_request_t const *sr; + + SU_DEBUG_3(("nua(%p): Checking Session Refresh\n", (void *)nh)); if (ss->ss_state >= nua_callstate_terminating || /* INVITE is in progress or being authenticated */ - nua_client_request_in_progress(cr)) - return; + nua_client_request_in_progress(cr)) { + SU_DEBUG_3(("nua(%p): client has a request in progress\n", (void *)nh)); + return; + } /* UPDATE has been queued */ - for (cr = ds->ds_cr; cr; cr = cr->cr_next) - if (cr->cr_method == sip_method_update) - return; + for (cr = ds->ds_cr; cr; cr = cr->cr_next) { + if (cr->cr_method == sip_method_update) { + SU_DEBUG_3(("nua(%p): client has an update queued\n", (void *)nh)); + return; + } + } /* INVITE or UPDATE in progress on server side */ - for (sr = ds->ds_sr; sr; sr = sr->sr_next) + for (sr = ds->ds_sr; sr; sr = sr->sr_next) { if (sr->sr_usage == du && - (sr->sr_method == sip_method_invite || - sr->sr_method == sip_method_update)) - return; + (sr->sr_method == sip_method_invite || + sr->sr_method == sip_method_update)) { + SU_DEBUG_3(("nua(%p): client has an INVITE OR UPDATE in progress\n", (void *)nh)); + return; + } + } if (ss->ss_timer->refresher == nua_remote_refresher) { SU_DEBUG_3(("nua(%p): session almost expired, sending BYE before timeout.\n", (void *)nh)); ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL); return; - } - else if (NH_PGET(nh, update_refresh)) { - nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); - } - else if (du->du_cr) { - nua_client_resend_request(du->du_cr, 0); - } - else { - nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); + } else if (NH_PGET(nh, update_refresh)) { + SU_DEBUG_3(("nua(%p): STACK UPDATE\n", (void *)nh)); + nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); + } else if (du->du_cr && du->du_cr->cr_method == sip_method_invite) { + SU_DEBUG_3(("nua(%p): RESEND REQUEST\n", (void *)nh)); + nua_client_resend_request(du->du_cr, 0); + } else { + SU_DEBUG_3(("nua(%p): STACK INVITE\n", (void *)nh)); + nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); } } From a17be38e07a3f55ca01bf2fa8577bab03f2240e9 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 5 Nov 2014 09:44:04 -0500 Subject: [PATCH 22/91] add reconf target --- Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile.am b/Makefile.am index 1a1befe7e0..886c5edf63 100644 --- a/Makefile.am +++ b/Makefile.am @@ -640,6 +640,11 @@ python-reconf: rm -f src/mod/languages/mod_python/Makefile ./config.status +reconf: + rm config.cache + sh ./config.status --recheck + sh ./config.status + srtp-reconf: cd libs/srtp && $(MAKE) clean cd libs/srtp && sh ./config.status --recheck From 46e74e58531c47298207ce0390088ab744aac7a9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 5 Nov 2014 09:26:33 -0600 Subject: [PATCH 23/91] revert 831832c2c62aaec9039bfc5e2d081b960d5856f4 --- libs/sofia-sip/.update | 2 +- .../libsofia-sip-ua/nua/nua_session.c | 46 ++++++++----------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index cc65611429..169ce799b0 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Tue Nov 4 18:30:40 CST 2014 +Wed Nov 5 09:25:53 CST 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index c589722ebd..933d76249e 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -1543,48 +1543,38 @@ static void nua_session_usage_refresh(nua_handle_t *nh, nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); nua_client_request_t const *cr = du->du_cr; nua_server_request_t const *sr; - - SU_DEBUG_3(("nua(%p): Checking Session Refresh\n", (void *)nh)); if (ss->ss_state >= nua_callstate_terminating || /* INVITE is in progress or being authenticated */ - nua_client_request_in_progress(cr)) { - SU_DEBUG_3(("nua(%p): client has a request in progress\n", (void *)nh)); - return; - } + nua_client_request_in_progress(cr)) + return; /* UPDATE has been queued */ - for (cr = ds->ds_cr; cr; cr = cr->cr_next) { - if (cr->cr_method == sip_method_update) { - SU_DEBUG_3(("nua(%p): client has an update queued\n", (void *)nh)); - return; - } - } + for (cr = ds->ds_cr; cr; cr = cr->cr_next) + if (cr->cr_method == sip_method_update) + return; /* INVITE or UPDATE in progress on server side */ - for (sr = ds->ds_sr; sr; sr = sr->sr_next) { + for (sr = ds->ds_sr; sr; sr = sr->sr_next) if (sr->sr_usage == du && - (sr->sr_method == sip_method_invite || - sr->sr_method == sip_method_update)) { - SU_DEBUG_3(("nua(%p): client has an INVITE OR UPDATE in progress\n", (void *)nh)); - return; - } - } + (sr->sr_method == sip_method_invite || + sr->sr_method == sip_method_update)) + return; if (ss->ss_timer->refresher == nua_remote_refresher) { SU_DEBUG_3(("nua(%p): session almost expired, sending BYE before timeout.\n", (void *)nh)); ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL); return; - } else if (NH_PGET(nh, update_refresh)) { - SU_DEBUG_3(("nua(%p): STACK UPDATE\n", (void *)nh)); - nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); - } else if (du->du_cr && du->du_cr->cr_method == sip_method_invite) { - SU_DEBUG_3(("nua(%p): RESEND REQUEST\n", (void *)nh)); - nua_client_resend_request(du->du_cr, 0); - } else { - SU_DEBUG_3(("nua(%p): STACK INVITE\n", (void *)nh)); - nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); + } + else if (NH_PGET(nh, update_refresh)) { + nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); + } + else if (du->du_cr) { + nua_client_resend_request(du->du_cr, 0); + } + else { + nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); } } From 8478874ab9192d2ef6f192d24fb818f05202cf81 Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 5 Nov 2014 09:44:24 -0600 Subject: [PATCH 24/91] FS-6831 while you can already unset by calling set with var=, same with set in dialplan this is a convience function similar to our unset in dialplan --- src/mod/applications/mod_sms/mod_sms.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/mod/applications/mod_sms/mod_sms.c b/src/mod/applications/mod_sms/mod_sms.c index cb1d3a49dc..2283e5d3a2 100644 --- a/src/mod/applications/mod_sms/mod_sms.c +++ b/src/mod/applications/mod_sms/mod_sms.c @@ -522,6 +522,25 @@ SWITCH_STANDARD_CHAT_APP(set_function) return SWITCH_STATUS_SUCCESS; } +SWITCH_STANDARD_CHAT_APP(unset_function) +{ + char *var; + + if (!data) return SWITCH_STATUS_SUCCESS; + + var = strdup(data); + + if (!var) return SWITCH_STATUS_SUCCESS; + + if (!zstr(var)) { + switch_event_del_header(message, var); + } + + free(var); + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_CHAT_APP(fire_function) { switch_event_t *fireme; @@ -573,6 +592,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load) SWITCH_ADD_CHAT_APP(chat_app_interface, "reply", "reply to a message", "reply to a message", reply_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "stop", "stop execution", "stop execution", stop_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "set", "set a variable", "set a variable", set_function, "", SCAF_NONE); + SWITCH_ADD_CHAT_APP(chat_app_interface, "unset", "unset a variable", "unset a variable", unset_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "send", "send the message as-is", "send the message as-is", send_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "fire", "fire the message", "fire the message", fire_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "system", "execute a system command", "execute a sytem command", system_function, "", SCAF_NONE); From 01395c508b180b313efb57ad11396676511c21d2 Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 5 Nov 2014 10:58:35 -0600 Subject: [PATCH 25/91] FS-6916 fix typos in code --- src/mod/xml_int/mod_xml_radius/mod_xml_radius.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c index bc75843800..94e127a12e 100644 --- a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c +++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c @@ -201,7 +201,7 @@ switch_status_t do_config() goto err; } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_invite' section in config file.\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_reg' section in config file.\n"); } if ((tmp = switch_xml_child(cfg, "global")) != NULL ) { @@ -741,7 +741,7 @@ switch_xml_t mod_xml_radius_auth_reg(switch_event_t *params) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting registration authentication\n"); } - if ( mod_xml_radius_new_handle(&new_handle, globals.auth_invite_configs) != SWITCH_STATUS_SUCCESS ) { + if ( mod_xml_radius_new_handle(&new_handle, globals.auth_reg_configs) != SWITCH_STATUS_SUCCESS ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load radius handle for registration authentication\n"); goto err; } @@ -849,7 +849,7 @@ static switch_xml_t mod_xml_radius_directory_search(const char *section, const c switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting authentication\n"); switch_event_serialize(params, &event_buf, SWITCH_TRUE); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event: %s \n", event_buf); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Section: %s \nTag: %s\nKey_name: %s\nKey_value: %s\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\nSection: %s \nTag: %s\nKey_name: %s\nKey_value: %s\n", section, tag_name, key_name, key_value); } @@ -1087,7 +1087,7 @@ SWITCH_STANDARD_APP(radius_auth_handle) temp = NULL; if ( result != 0 ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to authenticate\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to authenticate, authentication result: %d \n", result); goto err; } @@ -1169,7 +1169,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_xml_radius_load) return SWITCH_STATUS_TERM; } - if ( globals.auth_invite_configs ) { + if ( globals.auth_invite_configs && globals.auth_reg_configs ) { status = switch_xml_bind_search_function(mod_xml_radius_directory_search, switch_xml_parse_section_string("directory"), NULL); } From 4eb5b3884888d6350f839580be893c2eb5caf809 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 5 Nov 2014 11:34:00 -0600 Subject: [PATCH 26/91] fix bug where re-invites needlessly re-init the codec and jb --- src/switch_core_media.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 32956df273..81b22fa381 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -235,7 +235,7 @@ SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t static int get_channels(const char *name, int dft) { - if (!switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) { + if (!zstr(name) && switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) { return 2; /* IKR???*/ } @@ -3827,7 +3827,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->recv_pt); switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp); - if (switch_core_codec_ready(&a_engine->read_codec)) { + if (switch_core_codec_ready(&a_engine->read_codec) && strcasecmp(matches[0].imp->iananame, a_engine->read_codec.implementation->iananame)) { a_engine->reset_codec = 1; } @@ -4071,7 +4071,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_channel_set_variable(session->channel, "rtp_video_recv_pt", tmp); if (!match && vmatch) match = 1; - if (switch_core_codec_ready(&v_engine->read_codec)) { + if (switch_core_codec_ready(&v_engine->read_codec) && strcasecmp(matches[0].imp->iananame, v_engine->read_codec.implementation->iananame)) { v_engine->reset_codec = 1; } From a4971693d3900de3f352dea66dfddf43443ae93b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 5 Nov 2014 11:35:13 -0600 Subject: [PATCH 27/91] FS-6890 #comment please test --- src/mod/endpoints/mod_sofia/mod_sofia.c | 43 ++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index e116aaca73..4ba0181d95 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1559,18 +1559,53 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (ok) { char *headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_INFO_HEADER_PREFIX); const char *pl = NULL; + uint32_t callsequence; + nua_handle_t *nh; + sip_cseq_t *cseq = NULL; + const char *uri = NULL; + char *to, *from; + char *contact; + const char *invite_contact_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_contact_params"); if (!zstr(msg->string_array_arg[2])) { pl = msg->string_array_arg[2]; } - nua_info(tech_pvt->nh, + uri = switch_core_session_sprintf(tech_pvt->session, "sip:%s", + switch_channel_get_variable_dup(tech_pvt->channel, "sip_contact_uri", SWITCH_FALSE, -1)); + + if (tech_pvt->invite_contact) { + contact = sofia_overcome_sip_uri_weakness(tech_pvt->session, + tech_pvt->invite_contact, tech_pvt->transport, SWITCH_FALSE, invite_contact_params, NULL); + } else { + contact = tech_pvt->reply_contact; + } + + callsequence = sofia_presence_get_cseq(tech_pvt->profile); + nh = nua_handle(tech_pvt->profile->nua, NULL, + NUTAG_URL(uri), + TAG_IF(contact, SIPTAG_CONTACT_STR(contact)), + TAG_END()); + + + cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + nua_handle_bind(nh, &mod_sofia_globals.destroy_private); + + from = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_to"); + to = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_from"); + + nua_info(nh, + TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)), + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + SIPTAG_FROM_STR(from), + SIPTAG_TO_STR(to), + SIPTAG_CALL_ID_STR(switch_channel_get_variable(tech_pvt->channel, "sip_call_id")), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(headers), SIPTAG_HEADER_STR(headers)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), - TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), + TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), + SIPTAG_CSEQ(cseq), TAG_END()); - + switch_safe_free(headers); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s send_info is not supported.\n", switch_channel_get_name(channel)); From 9c1e6037c97c119ba82211eb6f9bddd3da6e089f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 5 Nov 2014 11:51:30 -0600 Subject: [PATCH 28/91] FS-6954 #comment we fixed another bug and this is the side effect which is completely valid, too bad you can never fix broken t38 endpoints. Can you please test this patch --- src/mod/endpoints/mod_sofia/sofia_glue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f4fbfddb8a..17edf89353 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1268,6 +1268,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_ADDRESS(tech_pvt->mparams.adv_sdp_audio_ip)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1)), + TAG_IF(switch_channel_get_private(tech_pvt->channel, "t38_options"), SOATAG_ORDERED_USER(1)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL)), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), From 14bf6c160429328baaf7ca52e3f484ff3e14241a Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Thu, 6 Nov 2014 12:27:34 +0300 Subject: [PATCH 29/91] Fixed code formatting. Return ListDelegate --- .../languages/mod_managed/managed/Loader.cs | 46 +++++++------------ src/mod/languages/mod_managed/mod_managed.cpp | 5 +- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index cee7af86c2..942431e989 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -46,15 +46,16 @@ namespace FreeSWITCH { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteDelegate(string cmd, IntPtr streamH, IntPtr eventH); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteBackgroundDelegate(string cmd); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool RunDelegate(string cmd, IntPtr session); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ListDelegate(string cmd, IntPtr streamH, IntPtr eventH); static readonly ExecuteDelegate _execute = Execute; static readonly ExecuteBackgroundDelegate _executeBackground = ExecuteBackground; static readonly RunDelegate _run = Run; static readonly ReloadDelegate _reload = Reload; - static readonly ExecuteDelegate _list = List; + static readonly ListDelegate _list = List; [DllImport("mod_managed", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ExecuteDelegate list); + static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ListDelegate list); static readonly object loaderLock = new object(); @@ -64,14 +65,10 @@ namespace FreeSWITCH { public static bool Load() { managedDir = Path.Combine(Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir, "managed"); shadowDir = Path.Combine(managedDir, "shadow"); - if (Directory.Exists(shadowDir)) - { - try - { + if (Directory.Exists(shadowDir)) { + try { Directory.Delete(shadowDir, true); - } - catch (Exception ex) - { + } catch (Exception ex) { Log.WriteLine(LogLevel.Warning, "Cannot delete shadow directory: {0}", ex); } @@ -79,8 +76,7 @@ namespace FreeSWITCH { } Log.WriteLine(LogLevel.Debug, "FreeSWITCH.Managed loader is starting with directory '{0}'.", managedDir); - if (!Directory.Exists(managedDir)) - { + if (!Directory.Exists(managedDir)) { Log.WriteLine(LogLevel.Error, "Managed directory not found: {0}", managedDir); return false; } @@ -241,8 +237,7 @@ namespace FreeSWITCH { .ToList(); // adding "managed" (modules) directory - if (!binPaths.Contains("managed", StringComparer.OrdinalIgnoreCase)) - { + if (!binPaths.Contains("managed", StringComparer.OrdinalIgnoreCase)) { binPaths.Add("managed"); } @@ -250,11 +245,9 @@ namespace FreeSWITCH { var moduleRefsDir = Path.GetFileName(fileName); moduleRefsDir = Path.GetFileNameWithoutExtension(moduleRefsDir); - if (moduleRefsDir != null && moduleRefsDir.Trim() != "") - { + if (moduleRefsDir != null && moduleRefsDir.Trim() != "") { moduleRefsDir = Path.Combine("managed", moduleRefsDir); - if (!binPaths.Contains(moduleRefsDir, StringComparer.OrdinalIgnoreCase)) - { + if (!binPaths.Contains(moduleRefsDir, StringComparer.OrdinalIgnoreCase)) { binPaths.Add(moduleRefsDir); } } @@ -446,12 +439,9 @@ namespace FreeSWITCH { public static bool List(string command, IntPtr streamHandle, IntPtr eventHandle) { - try - { - if (streamHandle != IntPtr.Zero) - { - using (var stream = new Native.Stream(new Native.switch_stream_handle(streamHandle, false))) - { + try { + if (streamHandle != IntPtr.Zero) { + using (var stream = new Native.Stream(new Native.switch_stream_handle(streamHandle, false))) { stream.Write("Available APIs:\n"); getApiExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); @@ -459,18 +449,14 @@ namespace FreeSWITCH { stream.Write("Available Apps:\n"); getAppExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); } - } - else - { + } else { Log.WriteLine(LogLevel.Info, "Available APIs:"); getApiExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); Log.WriteLine(LogLevel.Info, "Available Apps:"); getAppExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); } return true; - } - catch (Exception ex) - { + } catch (Exception ex) { Log.WriteLine(LogLevel.Error, "Exception listing managed modules: {0}", ex.ToString()); return false; } diff --git a/src/mod/languages/mod_managed/mod_managed.cpp b/src/mod/languages/mod_managed/mod_managed.cpp index 6718265d53..6831aec930 100644 --- a/src/mod/languages/mod_managed/mod_managed.cpp +++ b/src/mod/languages/mod_managed/mod_managed.cpp @@ -74,13 +74,14 @@ typedef int (*runFunction)(const char *data, void *sessionPtr); typedef int (*executeFunction)(const char *cmd, void *stream, void *Event); typedef int (*executeBackgroundFunction)(const char* cmd); typedef int (*reloadFunction)(const char* cmd); +typedef int (*listFunction)(const char *cmd, void *stream, void *Event); static runFunction runDelegate; static executeFunction executeDelegate; static executeBackgroundFunction executeBackgroundDelegate; static reloadFunction reloadDelegate; -static executeFunction listDelegate; +static listFunction listDelegate; -SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, executeFunction list) +SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, listFunction list) { runDelegate = run; executeDelegate = execute; From c97c0e8a7805f15fd52e7400b3a984d981e2524a Mon Sep 17 00:00:00 2001 From: Artur Kraev Date: Thu, 6 Nov 2014 12:36:02 +0300 Subject: [PATCH 30/91] Fix for case-sensitive filesystems --- src/mod/languages/mod_managed/managed/Loader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index 942431e989..e3803ae427 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -237,7 +237,7 @@ namespace FreeSWITCH { .ToList(); // adding "managed" (modules) directory - if (!binPaths.Contains("managed", StringComparer.OrdinalIgnoreCase)) { + if (!binPaths.Contains("managed")) { binPaths.Add("managed"); } From bc767bb35a55637034e43b05720cbe58d566235b Mon Sep 17 00:00:00 2001 From: Brian West Date: Thu, 6 Nov 2014 08:55:03 -0600 Subject: [PATCH 31/91] Adding rfc6598.auto and adding rfc6598 space to nat.auto acl, This is the NAT444 carrier grade nat space --- src/switch_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/switch_core.c b/src/switch_core.c index bf07f46451..cbf3175679 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1,3 +1,4 @@ + /* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2014, Anthony Minessale II @@ -1300,6 +1301,12 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_core_hash_init(&IP_LIST.hash); + tmp_name = "rfc6598.auto"; + switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name); + switch_network_list_add_cidr(rfc_list, "100.64.0.0/10", SWITCH_TRUE); + switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); + tmp_name = "rfc1918.auto"; switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name); @@ -1327,6 +1334,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_network_list_add_cidr(rfc_list, "10.0.0.0/8", SWITCH_TRUE); switch_network_list_add_cidr(rfc_list, "172.16.0.0/12", SWITCH_TRUE); switch_network_list_add_cidr(rfc_list, "192.168.0.0/16", SWITCH_TRUE); + switch_network_list_add_cidr(rfc_list, "100.64.0.0/10", SWITCH_TRUE); switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); tmp_name = "loopback.auto"; From 1190e59adfd1151d6307fb678a5604df344e4dae Mon Sep 17 00:00:00 2001 From: Brian West Date: Thu, 6 Nov 2014 09:47:54 -0600 Subject: [PATCH 32/91] FS-6965 #resolve --- src/mod/endpoints/mod_sofia/sofia.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 6e384ed215..b0107b200e 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -9913,7 +9913,15 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia /* Loop thru unknown Headers Here so we can do something with them */ for (un = sip->sip_unknown; un; un = un->un_next) { - if (!strncasecmp(un->un_name, "Diversion", 9)) { + if (!strncasecmp(un->un_name, "Accept-Language", 15)) { + if (!zstr(un->un_value)) { + char *tmp_name; + if ((tmp_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) { + switch_channel_set_variable(channel, tmp_name, un->un_value); + free(tmp_name); + } + } + } else if (!strncasecmp(un->un_name, "Diversion", 9)) { /* Basic Diversion Support for Diversion Indication in SIP */ /* draft-levy-sip-diversion-08 */ if (!zstr(un->un_value)) { From b0050f519e9be4d676523453d9bcb5c947193216 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 6 Nov 2014 16:30:44 +0000 Subject: [PATCH 33/91] Improve init error message when FS is unconfigured Depending on which packages are installed, the README.Debian file might not be there, so we'll spell out the instructions more directly. --- debian/freeswitch-sysvinit.freeswitch.init | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/freeswitch-sysvinit.freeswitch.init b/debian/freeswitch-sysvinit.freeswitch.init index 3a2089ad21..f393ff48a6 100644 --- a/debian/freeswitch-sysvinit.freeswitch.init +++ b/debian/freeswitch-sysvinit.freeswitch.init @@ -35,7 +35,9 @@ WORKDIR=/var/lib/$NAME do_start() { if ! [ -f $CONFDIR/freeswitch.xml ]; then echo "$NAME is not configured so not starting.">&2 - echo "Please review /usr/share/doc/$NAME/README.Debian">&2 + echo "Please add configuration under /etc/freeswitch">&2 + echo "e.g. Install freeswitch-conf-vanilla, then:">&2 + echo "cp -a /usr/share/freeswitch/conf/vanilla /etc/freeswitch">&2 return 3 fi From 94278b5e545b58bad784a95da6181fc5f299457f Mon Sep 17 00:00:00 2001 From: Hristo Trendev Date: Wed, 24 Sep 2014 14:25:39 +0200 Subject: [PATCH 34/91] allow enter and exit sounds to interrupt the MOH in a wait_mod conference This patch does the following: * only starts MOH if no other file (sync or async) is currently playing * adds a variable "conference_permanent_wait_mod_moh" that controls the behavior of how the enter and exit sounds interact with the MOH when wait_mod is set. When the variable is set, the MOH keeps playing and the enter and exit sounds are mixed with the MOH. When the variable is unset, then any playing MOH is first stopped, then the enter or exit sound is played and the MOH is started again. This functionality is useful in case the enter and exit sounds are used to announce the name of the caller, who is joining or leaving a conference. FS-5159 #resolve --- .../mod_conference/mod_conference.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 1ea3045de6..38b2f893d4 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -2277,7 +2277,8 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe } if (conference->count > 1) { - if (conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) { + if ((conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) || + (switch_test_flag(conference, CFLAG_WAIT_MOD) && !switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")))) { /* stop MoH if any */ conference_stop_file(conference, FILE_STOP_ASYNC); } @@ -2287,10 +2288,9 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) { if (!zstr(enter_sound)) { conference_play_file(conference, (char *)enter_sound, CONF_DEFAULT_LEADIN, - switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1); + switch_core_session_get_channel(member->session), 0); } else { - conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session), - !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1); + conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session), 0); } } } @@ -2316,7 +2316,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe if (conference->alone_sound && !switch_test_flag(member, MFLAG_GHOST)) { conference_stop_file(conference, FILE_STOP_ASYNC); conference_play_file(conference, conference->alone_sound, CONF_DEFAULT_LEADIN, - switch_core_session_get_channel(member->session), 1); + switch_core_session_get_channel(member->session), 0); } else { switch_snprintf(msg, sizeof(msg), "You are currently the only person in this conference."); conference_member_say(member, msg, CONF_DEFAULT_LEADIN); @@ -2683,7 +2683,7 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe if (member->session && (exit_sound = switch_channel_get_variable(switch_core_session_get_channel(member->session), "conference_exit_sound"))) { conference_play_file(conference, (char *)exit_sound, CONF_DEFAULT_LEADIN, - switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1); + switch_core_session_get_channel(member->session), 0); } @@ -2786,12 +2786,16 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe || (switch_test_flag(conference, CFLAG_DYNAMIC) && (conference->count + conference->count_ghosts == 0))) { switch_set_flag(conference, CFLAG_DESTRUCT); } else { + if (!switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")) && switch_test_flag(conference, CFLAG_WAIT_MOD)) { + /* Stop MOH if any */ + conference_stop_file(conference, FILE_STOP_ASYNC); + } if (!exit_sound && conference->exit_sound && switch_test_flag(conference, CFLAG_EXIT_SOUND)) { conference_play_file(conference, conference->exit_sound, 0, channel, 0); } if (conference->count == 1 && conference->alone_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD) && !switch_test_flag(member, MFLAG_GHOST)) { conference_stop_file(conference, FILE_STOP_ASYNC); - conference_play_file(conference, conference->alone_sound, 0, channel, 1); + conference_play_file(conference, conference->alone_sound, 0, channel, 0); } } @@ -3146,7 +3150,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v if (conference->perpetual_sound && !conference->async_fnode) { conference_play_file(conference, conference->perpetual_sound, CONF_DEFAULT_LEADIN, NULL, 1); } else if (conference->moh_sound && ((nomoh == 0 && conference->count == 1) - || switch_test_flag(conference, CFLAG_WAIT_MOD)) && !conference->async_fnode) { + || switch_test_flag(conference, CFLAG_WAIT_MOD)) && !conference->async_fnode && !conference->fnode) { conference_play_file(conference, conference->moh_sound, CONF_DEFAULT_LEADIN, NULL, 1); } From 0e9e8a9bd65807185a7ce55e487bd6d39a2f082b Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Thu, 6 Nov 2014 14:46:56 -0500 Subject: [PATCH 35/91] Renaming mod_spandsp's cadence + tone detection APPs and APIs (start_tone_detect / stop_tone_detect) to spandsp_start_tone_detect and spandsp_stop_tone_detect to resolve conflict with mod_dptools' tone_detect/stop_tone_detect APPs. --- src/mod/applications/mod_spandsp/mod_spandsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.c b/src/mod/applications/mod_spandsp/mod_spandsp.c index 5cd3b1ebf8..12a8a95948 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp.c @@ -788,12 +788,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init) if (mod_spandsp_dsp_load(module_interface, pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load or process spandsp.conf, not adding tone_detect applications\n"); } else { - SWITCH_ADD_APP(app_interface, "start_tone_detect", "Start background tone detection with cadence", "", start_tone_detect_app, "", SAF_NONE); - SWITCH_ADD_APP(app_interface, "stop_tone_detect", "Stop background tone detection with cadence", "", stop_tone_detect_app, "", SAF_NONE); - SWITCH_ADD_API(api_interface, "start_tone_detect", "Start background tone detection with cadence", start_tone_detect_api, " "); - SWITCH_ADD_API(api_interface, "stop_tone_detect", "Stop background tone detection with cadence", stop_tone_detect_api, ""); - switch_console_set_complete("add start_tone_detect ::console::list_uuid"); - switch_console_set_complete("add stop_tone_detect ::console::list_uuid"); + SWITCH_ADD_APP(app_interface, "spandsp_start_tone_detect", "Start background tone detection with cadence", "", start_tone_detect_app, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "spandsp_stop_tone_detect", "Stop background tone detection with cadence", "", stop_tone_detect_app, "", SAF_NONE); + SWITCH_ADD_API(api_interface, "spandsp_start_tone_detect", "Start background tone detection with cadence", start_tone_detect_api, " "); + SWITCH_ADD_API(api_interface, "spandsp_stop_tone_detect", "Stop background tone detection with cadence", stop_tone_detect_api, ""); + switch_console_set_complete("add spandsp_start_tone_detect ::console::list_uuid"); + switch_console_set_complete("add spandsp_stop_tone_detect ::console::list_uuid"); } SWITCH_ADD_API(api_interface, "start_tdd_detect", "Start background tdd detection", start_tdd_detect_api, ""); From cf1424cfe55816acb4efc0771147a9ae5de80011 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Thu, 6 Nov 2014 14:54:55 -0500 Subject: [PATCH 36/91] mod_rayo: update config to use spandsp_start_tone_detect and spandsp_stop_tone_detect --- conf/rayo/autoload_configs/rayo.conf.xml | 4 ++-- .../mod_rayo/conf/autoload_configs/rayo.conf.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index 50af0f7ecd..47a3a14bc1 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -52,8 +52,8 @@ - - + + diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index 50af0f7ecd..47a3a14bc1 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -52,8 +52,8 @@ - - + + From e75d0675afd8974687931143709814544299fadc Mon Sep 17 00:00:00 2001 From: Joao Mesquita Date: Tue, 9 Sep 2014 13:44:50 -0300 Subject: [PATCH 37/91] FS-6967 New mod_say_es_AR to support Argentina Spanish variant. --- build/modules.conf.in | 1 + configure.ac | 1 + src/mod/say/mod_say_es_ar/Makefile.am | 8 + src/mod/say/mod_say_es_ar/mod_say_es_ar.c | 718 ++++++++++++++++++++++ 4 files changed, 728 insertions(+) create mode 100644 src/mod/say/mod_say_es_ar/Makefile.am create mode 100644 src/mod/say/mod_say_es_ar/mod_say_es_ar.c diff --git a/build/modules.conf.in b/build/modules.conf.in index 71ece983ef..a088f0f676 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -131,6 +131,7 @@ loggers/mod_syslog #say/mod_say_de say/mod_say_en #say/mod_say_es +#say/mod_say_es_ar #say/mod_say_fa #say/mod_say_fr #say/mod_say_he diff --git a/configure.ac b/configure.ac index e8f9efade0..e19d9893f9 100644 --- a/configure.ac +++ b/configure.ac @@ -1592,6 +1592,7 @@ AC_CONFIG_FILES([Makefile src/mod/say/mod_say_de/Makefile src/mod/say/mod_say_en/Makefile src/mod/say/mod_say_es/Makefile + src/mod/say/mod_say_es_ar/Makefile src/mod/say/mod_say_fa/Makefile src/mod/say/mod_say_fr/Makefile src/mod/say/mod_say_he/Makefile diff --git a/src/mod/say/mod_say_es_ar/Makefile.am b/src/mod/say/mod_say_es_ar/Makefile.am new file mode 100644 index 0000000000..8386be0913 --- /dev/null +++ b/src/mod/say/mod_say_es_ar/Makefile.am @@ -0,0 +1,8 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_say_es_ar + +mod_LTLIBRARIES = mod_say_es_ar.la +mod_say_es_AR_la_SOURCES = mod_say_es_ar.c +mod_say_es_AR_la_CFLAGS = $(AM_CFLAGS) +mod_say_es_AR_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_say_es_AR_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/say/mod_say_es_ar/mod_say_es_ar.c b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c new file mode 100644 index 0000000000..f2dcb9cdb9 --- /dev/null +++ b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2007-2014, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Michael B. Murdock + * François Delawarde + * Joao Mesquita + * + * mod_say_es_ar.c -- Say for Spanish (Argentina) + * + */ + +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load); +SWITCH_MODULE_DEFINITION(mod_say_es_ar, mod_say_es_ar_load, NULL, NULL); + + +#define say_num(_sh, num, meth) { \ + char tmp[80]; \ + switch_status_t tstatus; \ + switch_say_method_t smeth = say_args->method; \ + switch_say_type_t stype = say_args->type; \ + say_args->type = SST_ITEMS; say_args->method = meth; \ + switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \ + if ((tstatus = \ + es_say_general_count(_sh, tmp, say_args)) \ + != SWITCH_STATUS_SUCCESS) { \ + return tstatus; \ + } \ + say_args->method = smeth; say_args->type = stype; \ + } \ + + + +static switch_status_t play_group(switch_say_method_t method, switch_say_gender_t gender, int a, int b, int c, char *what, switch_say_file_handle_t *sh) +{ + + if (a) { + if (a == 1 && b == 0 && c == 0) { + switch_say_file(sh, "digits/hundred"); + } else { + switch_say_file(sh, "digits/%d00", a); + } + } + + if (b) { + if (method == SSM_COUNTED) { + /* Numeros no redondos es masculino siempre. */ + if (gender == SSG_FEMININE && c == 0) { + switch_say_file(sh, "digits/h-%d0_a", b); + + } else { + switch_say_file(sh, "digits/h-%d0", b); + } + } else { + /* Veinti */ + if (b == 2) { + switch_say_file(sh, "digits/%d0_i", b); + } else if(b == 1) { + switch_say_file(sh, "digits/%d%d", b, c); + } else { + switch_say_file(sh, "digits/%d0", b); + if (c > 0) { + switch_say_file(sh, "digits/y"); + } + } + } + } + + if (c && b != 1) { + if (method == SSM_COUNTED) { + if (gender == SSG_FEMININE) { + switch_say_file(sh, "digits/h-%d_a", c); + } else { + switch_say_file(sh, "digits/h-%d", c); + } + } else { + if (c == 1) { + if (gender == SSG_NEUTER) { + switch_say_file(sh, "digits/%d_n", c); + } else if (gender == SSG_FEMININE) { + switch_say_file(sh, "digits/%d_a", c); + } else { + switch_say_file(sh, "digits/%d", c); + } + } else { + switch_say_file(sh, "digits/%d", c); + } + } + } + + if (what && (a || b || c)) { + switch_say_file(sh, what); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t es_say_general_count(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int in; + int x = 0; + int places[9] = { 0 }; + char sbuf[128] = ""; + switch_status_t status; + + if (say_args->method == SSM_ITERATED) { + if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) { + char *p; + for (p = tosay; p && *p; p++) { + char *n_p = p+1; + switch_say_file(sh, "digits/%c", *p); + if (n_p && *n_p) { + switch_say_file(sh, "silence_stream://100"); + } + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + return SWITCH_STATUS_SUCCESS; + } + + if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + in = atoi(tosay); + + if (in != 0) { + for (x = 8; x >= 0; x--) { + int num = (int) pow(10, x); + if ((places[(uint32_t) x] = in / num)) { + in -= places[(uint32_t) x] * num; + } + } + + + switch (say_args->method) { + case SSM_PRONOUNCED_YEAR: + { + int num = atoi(tosay); + int a = num / 100; + int b = num % 100; + + if (!b || !(a % 10)) { + say_num(sh, num, SSM_PRONOUNCED); + return SWITCH_STATUS_SUCCESS; + } + + say_num(sh, a, SSM_PRONOUNCED); + say_num(sh, b, SSM_PRONOUNCED); + + return SWITCH_STATUS_SUCCESS; + } + break; + case SSM_COUNTED: + case SSM_PRONOUNCED: + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[8], places[7], places[6], "digits/million", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[5], places[4], places[3], "digits/thousand", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(say_args->method, say_args->gender, places[2], places[1], places[0], NULL, sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + break; + default: + break; + } + } else { + switch_say_file(sh, "digits/0"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t es_say_time(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int32_t t; + switch_time_t target = 0, target_now = 0; + switch_time_exp_t tm, tm_now; + uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0; + const char *tz = NULL; + + tz = switch_say_file_handle_get_variable(sh, "timezone"); + + if (say_args->type == SST_TIME_MEASUREMENT) { + int64_t hours = 0; + int64_t minutes = 0; + int64_t seconds = 0; + int64_t r = 0; + + if (strchr(tosay, ':')) { + char *tme = strdup(tosay); + char *p; + + if ((p = strrchr(tme, ':'))) { + *p++ = '\0'; + seconds = atoi(p); + if ((p = strchr(tme, ':'))) { + *p++ = '\0'; + minutes = atoi(p); + hours = atoi(tme); + } else { + minutes = atoi(tme); + } + } + free(tme); + } else { + if ((seconds = atol(tosay)) <= 0) { + seconds = (int64_t) switch_epoch_time_now(NULL); + } + + if (seconds >= 60) { + minutes = seconds / 60; + r = seconds % 60; + seconds = r; + } + + if (minutes >= 60) { + hours = minutes / 60; + r = minutes % 60; + minutes = r; + } + } + + if (hours) { + say_num(sh, hours, SSM_PRONOUNCED); + if (hours == 1) { + switch_say_file(sh, "time/hour"); + } else { + switch_say_file(sh, "time/hours"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/hours"); + } + + if (minutes) { + say_num(sh, minutes, SSM_PRONOUNCED); + if (minutes == 1) { + switch_say_file(sh, "time/minute"); + } else { + switch_say_file(sh, "time/minutes"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/minutes"); + } + + if (seconds) { + say_num(sh, seconds, SSM_PRONOUNCED); + if (seconds == 1) { + switch_say_file(sh, "time/second"); + } else { + switch_say_file(sh, "time/seconds"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/seconds"); + } + + return SWITCH_STATUS_SUCCESS; + } + + if ((t = atol(tosay)) > 0) { + target = switch_time_make(t, 0); + target_now = switch_micro_time_now(); + } else { + target = switch_micro_time_now(); + target_now = switch_micro_time_now(); + } + + if (tz) { + int check = atoi(tz); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz); + if (check) { + switch_time_exp_tz(&tm, target, check); + switch_time_exp_tz(&tm_now, target_now, check); + } else { + switch_time_exp_tz_name(tz, &tm, target); + switch_time_exp_tz_name(tz, &tm_now, target_now); + } + } else { + switch_time_exp_lt(&tm, target); + switch_time_exp_lt(&tm_now, target_now); + } + + switch (say_args->type) { + case SST_CURRENT_DATE_TIME: + say_date = say_time = 1; + break; + case SST_CURRENT_DATE: + say_date = 1; + break; + case SST_CURRENT_TIME: + say_time = 1; + break; + case SST_SHORT_DATE_TIME: + say_time = 1; + //Time is in the future + if ((tm.tm_year > tm_now.tm_year) || + (tm.tm_year == tm_now.tm_year && tm.tm_mon > tm_now.tm_mon) || + (tm.tm_year == tm_now.tm_year && tm.tm_mon == tm_now.tm_mon && tm.tm_mday > tm_now.tm_mday)) + { + say_date = 1; + break; + } + //Time is today or earlier + if (tm.tm_year != tm_now.tm_year) { + say_date = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday) { + say_today = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday - 1) { + say_yesterday = 1; + break; + } + if (tm.tm_yday >= tm_now.tm_yday - 5) { + say_dow = 1; + break; + } + if (tm.tm_mon != tm_now.tm_mon) { + say_month = say_day = say_dow = 1; + break; + } + + say_month = say_day = say_dow = 1; + + break; + default: + break; + } + + if (say_today) { + switch_say_file(sh, "time/today"); + } + if (say_yesterday) { + switch_say_file(sh, "time/yesterday"); + } + if (say_dow) { + switch_say_file(sh, "time/day-%d", tm.tm_wday); + } + + if (say_date) { + say_year = say_month = say_day = say_dow = 1; + say_today = say_yesterday = 0; + } + + if (say_day) { + if (tm.tm_mday == 1) { + say_num(sh, tm.tm_mday, SSM_COUNTED); + } else { + say_num(sh, tm.tm_mday, SSM_PRONOUNCED); + } + switch_say_file(sh, "time/de"); + } + if (say_month) { + switch_say_file(sh, "time/mon-%d", tm.tm_mon); + } + if (say_year) { + switch_say_file(sh, "time/de"); + say_num(sh, tm.tm_year + 1900, SSM_PRONOUNCED_YEAR); + } + + if (say_time) { + + if (say_date || say_today || say_yesterday || say_dow) { + switch_say_file(sh, "time/at"); + } + + + if (tm.tm_hour == 1) { + switch_say_file(sh, "digits/1"); + switch_say_file(sh, "time/hour"); + } else { + say_num(sh, tm.tm_hour, SSM_PRONOUNCED); + switch_say_file(sh, "time/hours"); + } + + if (tm.tm_min == 1) { + switch_say_file(sh, "digits/1_1a"); + switch_say_file(sh, "time/minute"); + } else { + say_num(sh, tm.tm_min, SSM_PRONOUNCED); + switch_say_file(sh, "time/minutes"); + } + + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t es_say_money(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */ + char *dollars = NULL; + char *cents = NULL; + + if (strlen(tosay) > 15 || !switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + dollars = sbuf; + + if ((cents = strchr(sbuf, '.'))) { + *cents++ = '\0'; + if (strlen(cents) > 2) { + cents[2] = '\0'; + } + } + + /* If positive sign - skip over" */ + if (sbuf[0] == '+') { + dollars++; + } + + /* If negative say "negative" */ + if (sbuf[0] == '-') { + switch_say_file(sh, "currency/negative"); + dollars++; + } + + /* Say dollar amount */ + es_say_general_count(sh, dollars, say_args); + if (atoi(dollars) == 1) { + switch_say_file(sh, "currency/dollar"); + } else { + switch_say_file(sh, "currency/dollars"); + } + + /* Say cents */ + if (cents) { + /* Say "and" */ + switch_say_file(sh, "currency/and"); + + es_say_general_count(sh, cents, say_args); + if (atoi(cents) == 1) { + switch_say_file(sh, "currency/cent"); + } else { + switch_say_file(sh, "currency/cents"); + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t say_ip(switch_say_file_handle_t *sh, + char *tosay, + switch_say_args_t *say_args) + +{ + char *a, *b, *c, *d; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!(a = strdup(tosay))) { + abort(); + } + + if (!(b = strchr(a, '.'))) { + goto end; + } + + *b++ = '\0'; + + if (!(c = strchr(b, '.'))) { + goto end; + } + + *c++ = '\0'; + + if (!(d = strchr(c, '.'))) { + goto end; + } + + *d++ = '\0'; + + say_num(sh, atoi(a), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(b), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(c), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(d), say_args->method); + + end: + + free(a); + + return status; +} + + +static switch_status_t say_telephone_number(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int silence = 0; + char *p; + + for (p = tosay; !zstr(p); p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + silence = 0; + } else if (a == '+' || (a >= 'a' && a <= 'z')) { + switch_say_file(sh, "ascii/%d", a); + silence = 0; + } else if (!silence) { + switch_say_file(sh, "silence_stream://100"); + silence = 1; + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t say_spell(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char *p; + + for (p = tosay; p && *p; p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + } else { + if (say_args->type == SST_NAME_SPELLED) { + switch_say_file(sh, "ascii/%d", a); + } else if (say_args->type == SST_NAME_PHONETIC) { + switch_say_file(sh, "phonetic-ascii/%d", a); + } + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_new_say_callback_t choose_callback(switch_say_args_t *say_args) +{ + switch_new_say_callback_t say_cb = NULL; + + switch (say_args->type) { + case SST_NUMBER: + case SST_ITEMS: + case SST_PERSONS: + case SST_MESSAGES: + say_cb = es_say_general_count; + break; + case SST_TIME_MEASUREMENT: + case SST_CURRENT_DATE: + case SST_CURRENT_TIME: + case SST_CURRENT_DATE_TIME: + case SST_SHORT_DATE_TIME: + say_cb = es_say_time; + break; + case SST_IP_ADDRESS: + say_cb = say_ip; + break; + case SST_NAME_SPELLED: + case SST_NAME_PHONETIC: + say_cb = say_spell; + break; + case SST_CURRENCY: + say_cb = es_say_money; + break; + case SST_TELEPHONE_NUMBER: + say_cb = say_telephone_number; + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type); + break; + } + + return say_cb; +} + + +static switch_status_t run_callback(switch_new_say_callback_t say_cb, char *tosay, switch_say_args_t *say_args, switch_core_session_t *session, char **rstr) +{ + switch_say_file_handle_t *sh; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_event_t *var_event = NULL; + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_get_variables(channel, &var_event); + } + + switch_say_file_handle_create(&sh, say_args->ext, &var_event); + + status = say_cb(sh, tosay, say_args); + + if ((*rstr = switch_say_file_handle_detach_path(sh))) { + status = SWITCH_STATUS_SUCCESS; + } + + switch_say_file_handle_destroy(&sh); + + return status; +} + + +static switch_status_t es_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (session && string) { + status = switch_ivr_play_file(session, NULL, string, args); + } + + switch_safe_free(string); + } + + return status; +} + + +static switch_status_t es_say_string(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, char **rstr) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (string) { + status = SWITCH_STATUS_SUCCESS; + *rstr = string; + } + } + + return status; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load) +{ + switch_say_interface_t *say_interface; + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE); + say_interface->interface_name = "es_ar"; + say_interface->say_function = es_say; + say_interface->say_string_function = es_say_string; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ From f66f2cae8cae4ed510878eb8de88ee08bf60344b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 6 Nov 2014 17:13:02 -0600 Subject: [PATCH 38/91] FS-6890 #comment please test --- src/mod/endpoints/mod_sofia/mod_sofia.c | 11 ++++++++--- src/mod/endpoints/mod_sofia/mod_sofia.h | 2 ++ src/mod/endpoints/mod_sofia/sofia.c | 4 ++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 77273fe039..7ccfe9ee74 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1591,9 +1591,14 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); - from = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_to"); - to = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_from"); - + if (tech_pvt->sent_last_invite || !tech_pvt->recv_invites) { + from = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_from"); + to = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_to"); + } else { + from = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_to"); + to = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_from"); + } + nua_info(nh, TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 6e9b70cc44..52307a2800 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -810,6 +810,8 @@ struct private_object { time_t last_vid_info; uint32_t keepalive; uint32_t sent_invites; + uint32_t recv_invites; + uint8_t sent_last_invite; }; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index b0107b200e..44995792f4 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6688,6 +6688,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, case nua_callstate_authenticating: break; case nua_callstate_calling: + tech_pvt->sent_last_invite = 1; + tech_pvt->sent_invites++; break; case nua_callstate_proceeding: @@ -6826,6 +6828,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } goto done; case nua_callstate_received: + tech_pvt->recv_invites++; + tech_pvt->sent_last_invite = 0; if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) { if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { private_object_t *other_tech_pvt = switch_core_session_get_private(other_session); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 17edf89353..f20f1a1e8c 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1233,7 +1233,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) switch_channel_get_name(tech_pvt->channel), switch_version_full_human(), tech_pvt->mparams.local_sdp_str ? tech_pvt->mparams.local_sdp_str : "NO SDP PRESENT\n"); - tech_pvt->sent_invites++; + if (sofia_use_soa(tech_pvt)) { nua_invite(tech_pvt->nh, From 1944f9a5ee63ec51bed1bfb900072d168a81d004 Mon Sep 17 00:00:00 2001 From: Aaron Paolozzi Date: Thu, 6 Nov 2014 19:21:58 -0500 Subject: [PATCH 39/91] FS-6968 Changes to mod_fifo.c to add outbound_per_cycle_min --- src/mod/applications/mod_fifo/mod_fifo.c | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index ac0d1167b7..d6877ef8dc 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -79,6 +79,15 @@ SWITCH_MODULE_DEFINITION(mod_fifo, mod_fifo_load, mod_fifo_shutdown, NULL); * The /enterprise/ outbound strategy does not preserve the caller ID * of the caller thereby allowing deliver of callers to agents at the * fastest possible rate. + * + * outbound_per_cycle is used to define the maximum number of agents + * who will be available to answer a single caller. In ringall this + * maximum is the number who will be called, in enterprise the need defines + * how many agents will be called. outbound_per_cycle_min will define + * the minimum agents who will be called to answer a caller regardless of + * need, giving the enterprise strategy the ability to ring through more + * than one agent for one caller. + * * ## Manual calls * @@ -391,6 +400,7 @@ struct fifo_node { long busy; int is_static; int outbound_per_cycle; + int outbound_per_cycle_min; char *outbound_name; outbound_strategy_t outbound_strategy; int ring_timeout; @@ -1985,6 +1995,21 @@ static int place_call_enterprise_callback(void *pArg, int argc, char **argv, cha * the results. The enterprise strategy handler can simply take each * member one at a time, so the `place_call_enterprise_callback` takes * care of invoking the handler. + * + * Within the ringall call strategy outbound_per_cycle is used to define + * how many agents exactly are assigned to the caller. With ringall if + * multiple callers are calling in and one is answered, because the call + * is assigned to all agents the call to the agents that is not answered + * will be lose raced and the other agents will drop the call before the + * next one will begin to ring. When oubound_per_cycle is used in the + * enterprise strategy it acts as a maximum value for how many agents + * are rung at once on any call, the caller is not assigned to any agent + * until the call is answered. Enterprise only rings the number of phones + * that are needed, so outbound_per_cycle as a max does not give you the + * effect of ringall. outbound_per_cycle_min defines how many agents minimum + * will be rung by an incoming caller through fifo, which can give a ringall + * effect. outbound_per_cycle and outbound_per_cycle_min both default to 1. + * */ static void find_consumers(fifo_node_t *node) { @@ -2005,6 +2030,8 @@ static void find_consumers(fifo_node_t *node) if (node->outbound_per_cycle && node->outbound_per_cycle < need) { need = node->outbound_per_cycle; + } else if (node->outbound_per_cycle_min && node->outbound_per_cycle_min > need) { + need = node->outbound_per_cycle_min; } fifo_execute_sql_callback(globals.sql_mutex, sql, place_call_enterprise_callback, &need); @@ -4045,6 +4072,9 @@ static void list_node(fifo_node_t *node, switch_xml_t x_report, int *off, int ve switch_snprintf(tmp, sizeof(buffer), "%u", node->outbound_per_cycle); switch_xml_set_attr_d(x_fifo, "outbound_per_cycle", tmp); + switch_snprintf(tmp, sizeof(buffer), "%u", node->outbound_per_cycle_min); + switch_xml_set_attr_d(x_fifo, "outbound_per_cycle_min", tmp); + switch_snprintf(tmp, sizeof(buffer), "%u", node->ring_timeout); switch_xml_set_attr_d(x_fifo, "ring_timeout", tmp); @@ -4088,6 +4118,7 @@ void node_dump(switch_stream_handle_t *stream) stream->write_function(stream, "node: %s\n" " outbound_name: %s\n" " outbound_per_cycle: %d" + " outbound_per_cycle_min: %d" " outbound_priority: %d" " outbound_strategy: %s\n" " has_outbound: %d\n" @@ -4096,7 +4127,7 @@ void node_dump(switch_stream_handle_t *stream) " ready: %d\n" " waiting: %d\n" , - node->name, node->outbound_name, node->outbound_per_cycle, + node->name, node->outbound_name, node->outbound_per_cycle, node->outbound_per_cycle_min, node->outbound_priority, print_strategy(node->outbound_strategy), node->has_outbound, node->outbound_priority, @@ -4508,6 +4539,13 @@ static switch_status_t load_config(int reload, int del_all) node->has_outbound = 1; } + node->outbound_per_cycle_min = 1; + if ((val = switch_xml_attr(fifo, "outbound_per_cycle_min"))) { + if (!((i = atoi(val)) < 0)) { + node->outbound_per_cycle_min = i; + } + } + if ((val = switch_xml_attr(fifo, "retry_delay"))) { if ((i = atoi(val)) < 0) i = 0; node->retry_delay = i; From 415f82fe93918167e2853d2a70b56bb3a9b749c4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 6 Nov 2014 18:26:16 -0600 Subject: [PATCH 40/91] FS-6954 #resolve #comment please test --- src/mod/endpoints/mod_sofia/sofia.c | 14 +++++++++++--- src/mod/endpoints/mod_sofia/sofia_glue.c | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index b0107b200e..a482d107f0 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6538,9 +6538,17 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (!tech_pvt || !tech_pvt->nh) { goto done; } - - if ((status > 100 || switch_channel_test_flag(channel, CF_ANSWERED)) && status < 300 && !r_sdp && tech_pvt->mparams.last_sdp_str) { - r_sdp = tech_pvt->mparams.last_sdp_str; + + if (!r_sdp && (status > 100 || switch_channel_test_flag(channel, CF_ANSWERED)) && status < 300) { + if (ss_state == nua_callstate_ready) { + if (tech_pvt->mparams.last_sdp_response) { + r_sdp = tech_pvt->mparams.last_sdp_response; + } + } else { + if (tech_pvt->mparams.last_sdp_str) { + r_sdp = tech_pvt->mparams.last_sdp_str; + } + } } tech_pvt->mparams.last_sdp_str = NULL; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 17edf89353..49079f106d 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1235,6 +1235,10 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) tech_pvt->sent_invites++; + if (switch_channel_get_private(tech_pvt->channel, "t38_options")) { + sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA); + } + if (sofia_use_soa(tech_pvt)) { nua_invite(tech_pvt->nh, NUTAG_AUTOANSWER(0), From 08ff88ec31572071c5e5dbe6fad51578814c4bd9 Mon Sep 17 00:00:00 2001 From: Brian West Date: Fri, 7 Nov 2014 07:26:31 -0600 Subject: [PATCH 41/91] Might needs this for testing. --- scripts/perl/mkgws.pl | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/perl/mkgws.pl diff --git a/scripts/perl/mkgws.pl b/scripts/perl/mkgws.pl new file mode 100644 index 0000000000..6743c969d0 --- /dev/null +++ b/scripts/perl/mkgws.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +# +# Make bulk gateway xml from csv file. +# + +open(CSV, "gateways.csv"); +my @data = ; +close(CSV); + +foreach my $line (@data) { + chomp($line); + my ($gwname, $username, $password) = split(/,/, $line); + print < + + + + + + + + + + + + + + + + + + + + +XML + +} From 5ce5199be9b7255ebcbfae7e3e3f62a8eb914310 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 7 Nov 2014 08:37:53 -0600 Subject: [PATCH 42/91] FS-6969 #resolve #comment This patch should accomplish the same and handle other platforms, please test --- src/include/switch_utils.h | 22 ++++++++++++++++++++++ src/switch_utils.c | 24 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index e8b6843d14..523e3a4768 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -541,6 +541,28 @@ SWITCH_DECLARE(int) switch_build_uri(char *uri, switch_size_t size, const char * #define SWITCH_STATUS_IS_BREAK(x) (x == SWITCH_STATUS_BREAK || x == 730035 || x == 35 || x == SWITCH_STATUS_INTR) + +#ifdef _MSC_VER + +#define switch_errno() WSAGetLastError() + +static inline int switch_errno_is_break(int errcode) +{ + return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == WSAEINTR; +} + +#else + +#define switch_errno() errno + +static inline int switch_errno_is_break(int errcode) +{ + return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT; +} + +#endif + + /*! \brief Return a printable name of a switch_priority_t \param priority the priority to get the name of diff --git a/src/switch_utils.c b/src/switch_utils.c index 3cde97a127..444333ec12 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -2567,6 +2567,12 @@ SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switc s = poll(pfds, 1, ms); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { @@ -2645,6 +2651,12 @@ SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t *waitlist, uint32_t l s = poll(pfds, len, ms); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { @@ -2758,6 +2770,12 @@ SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switc s = select(sock + 1, (flags & SWITCH_POLL_READ) ? rfds : NULL, (flags & SWITCH_POLL_WRITE) ? wfds : NULL, (flags & SWITCH_POLL_ERROR) ? efds : NULL, &tv); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { @@ -2858,6 +2876,12 @@ SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t *waitlist, uint32_t l s = select(max_fd + 1, (flags & SWITCH_POLL_READ) ? rfds : NULL, (flags & SWITCH_POLL_WRITE) ? wfds : NULL, (flags & SWITCH_POLL_ERROR) ? efds : NULL, &tv); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { From e3a647810c8e90e5b4dc379521a9a3275d27d71e Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 15 Sep 2014 20:49:42 +0200 Subject: [PATCH 43/91] debian: Allow use of secondary groups When '-g' is passed, freeswitch drops all other groups except for the given group. This impacts people who depend on FS having access to resources that would be allowed by membership to those other groups. It was possible to override this by setting DAEMON_ARGS in /etc/default/freeswitch, but we'll go ahead and make this the default. Since freeswitch uses the primary group of a user when `-g` is omitted, we'll just omit it, and do similarly when setting the ownership of our directory in /var/run. Edited-by: Travis Cross --- debian/freeswitch-sysvinit.freeswitch.init | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/freeswitch-sysvinit.freeswitch.init b/debian/freeswitch-sysvinit.freeswitch.init index f393ff48a6..98be1af324 100644 --- a/debian/freeswitch-sysvinit.freeswitch.init +++ b/debian/freeswitch-sysvinit.freeswitch.init @@ -19,8 +19,7 @@ DESC=freeswitch NAME=freeswitch DAEMON=/usr/bin/freeswitch USER=freeswitch -GROUP=freeswitch -DAEMON_ARGS="-u $USER -g $GROUP -ncwait" +DAEMON_ARGS="-u $USER -ncwait" CONFDIR=/etc/$NAME RUNDIR=/var/run/$NAME PIDFILE=$RUNDIR/$NAME.pid @@ -43,7 +42,7 @@ do_start() { # Directory in /var/run may disappear on reboot (e.g. when tmpfs used for /var/run). mkdir -p $RUNDIR - chown -R $USER:$GROUP $RUNDIR + chown -R $USER: $RUNDIR chmod -R ug=rwX,o= $RUNDIR start-stop-daemon --start --quiet \ From 070aaefaeba3232023286983833acd309022521a Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Fri, 7 Nov 2014 18:17:46 +0000 Subject: [PATCH 44/91] Fix whitespace inconsistency --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f4ba7ac252..a11de35c84 100644 --- a/configure.ac +++ b/configure.ac @@ -1587,7 +1587,7 @@ AC_CONFIG_FILES([Makefile src/mod/say/mod_say_de/Makefile src/mod/say/mod_say_en/Makefile src/mod/say/mod_say_es/Makefile - src/mod/say/mod_say_es_ar/Makefile + src/mod/say/mod_say_es_ar/Makefile src/mod/say/mod_say_fa/Makefile src/mod/say/mod_say_fr/Makefile src/mod/say/mod_say_he/Makefile From 185e6ec5e185f1e68426798d61102f822d108d74 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 7 Nov 2014 13:22:22 -0500 Subject: [PATCH 45/91] RPM packaging - add mongo C driver to list of sources --- freeswitch.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/freeswitch.spec b/freeswitch.spec index 08596a8f4f..ca95e20657 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -129,6 +129,7 @@ Source10: http://files.freeswitch.org/downloads/libs/libmemcached-0.32.tar.gz Source11: http://files.freeswitch.org/downloads/libs/json-c-0.9.tar.gz Source12: http://files.freeswitch.org/downloads/libs/opus-1.1-p2.tar.gz Source13: http://files.freeswitch.org/downloads/libs/v8-3.24.14.tar.bz2 +Source14: http://files.freeswitch.org/downloads/libs/mongo-c-driver-0.92.2.tar.gz Prefix: %{prefix} From 51f61c78342be6bfbab2c5719772874ded389510 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 30 Jul 2014 19:20:08 +0200 Subject: [PATCH 46/91] debian: Remove duplicate clean command `dh clean` invokes `dh_testdir`, `dh_auto_clean` and `dh_clean`. We don't need to invoke dh_clean twice. Acked-by: Travis Cross --- debian/rules | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/rules b/debian/rules index eefc3bc277..cf6a7ed1ea 100755 --- a/debian/rules +++ b/debian/rules @@ -55,7 +55,6 @@ clean: dh $@ override_dh_auto_clean: - dh_clean .stamp-bootstrap: @$(call show_vars) From f4527d77cb41e4cb74798f6a92861dc87d6d1c6b Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Fri, 7 Nov 2014 18:52:11 +0000 Subject: [PATCH 47/91] Fix placement of build-dep for libsngtc-dev Since we compare our generated control-modules to the one in tree, we want to match the exact format we use to generate the file. --- debian/control-modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control-modules b/debian/control-modules index a494304f6e..c025bd071e 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -333,9 +333,9 @@ Description: mod_opus Adds mod_opus. Module: codecs/mod_sangoma_codec -Build-Depends: libsngtc-dev Description: mod_sangoma_codec Adds mod_sangoma_codec. +Build-Depends: libsngtc-dev Module: codecs/mod_silk Description: mod_silk From 4b76c2aea9da5ac1e30e248095faeed5e380fff9 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Fri, 7 Nov 2014 18:53:33 +0000 Subject: [PATCH 48/91] Add mod_odbc_cdr to debian packaging --- debian/control-modules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/control-modules b/debian/control-modules index c025bd071e..64ca7c0363 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -500,6 +500,10 @@ Module: event_handlers/mod_json_cdr Description: mod_json_cdr Adds mod_json_cdr. +Module: event_handlers/mod_odbc_cdr +Description: mod_odbc_cdr + Adds mod_odbc_cdr. + Module: event_handlers/mod_radius_cdr Description: mod_radius_cdr Adds mod_radius_cdr. From ebb3c8fbfa3ec8b9f4b4a2ef20d62d343c8ff6c4 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Fri, 7 Nov 2014 18:53:46 +0000 Subject: [PATCH 49/91] Add mod_say_es_ar to debian packaging --- debian/control-modules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/control-modules b/debian/control-modules index 64ca7c0363..84b7d8d140 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -634,6 +634,10 @@ Module: say/mod_say_es Description: mod_say_es Adds mod_say_es. +Module: say/mod_say_es_ar +Description: mod_say_es_ar + Adds mod_say_es_ar. + Module: say/mod_say_fa Description: mod_say_fa Adds mod_say_fa. From 300b8d86aba4340e614fbe3fd73fb9b9e0017d8f Mon Sep 17 00:00:00 2001 From: Brian West Date: Fri, 7 Nov 2014 16:45:32 -0600 Subject: [PATCH 50/91] FS-6973 #resolve --- build/buildopal.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/buildopal.sh b/build/buildopal.sh index 6009f1048d..4528097401 100755 --- a/build/buildopal.sh +++ b/build/buildopal.sh @@ -18,7 +18,7 @@ cd `dirname $0` cd .. FS_DIR=`pwd` -export PKG_CONFIG_PATH=$INSTALLDIR/lib/pkgconfig +#export PKG_CONFIG_PATH=$INSTALLDIR/lib/pkgconfig # Version and patch for PTLib and OPAL. These are almost always in lock @@ -42,7 +42,7 @@ fi cd $FS_DIR/libs -svn co https://opalvoip.svn.sourceforge.net/svnroot/opalvoip/ptlib/$PTLIB_VERSION ptlib +svn co https://svn.code.sf.net/p/opalvoip/code/ptlib/$PTLIB_VERSION ptlib cd $FS_DIR/libs/ptlib # LDAP disabled due to conflict wit libs in spidermonkey ./configure --disable-plugins --disable-openldap --prefix=$INSTALLDIR @@ -50,7 +50,7 @@ ${MAKE} sudo ${MAKE} install cd $FS_DIR/libs -svn co https://opalvoip.svn.sourceforge.net/svnroot/opalvoip/opal/$OPAL_VERSION opal +svn co https://svn.code.sf.net/p/opalvoip/code/opal/$OPAL_VERSION opal cd $FS_DIR/libs/opal ./configure --disable-plugins --prefix=$INSTALLDIR $MAKE From 0f2816d18b2308ca1fc6f42617fd1728fa4905c1 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 7 Nov 2014 17:10:53 -0600 Subject: [PATCH 51/91] add command to comppile non-minified js file for testing --- html5/verto/js/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/html5/verto/js/Makefile b/html5/verto/js/Makefile index 9ee3be803f..d5144b1193 100644 --- a/html5/verto/js/Makefile +++ b/html5/verto/js/Makefile @@ -8,8 +8,14 @@ jsmin: jsmin.c verto-min.js: jsmin $(JSFILES) cat $(JSFILES) | ./jsmin > $@ +verto-max.js: jsmin $(JSFILES) + cat $(JSFILES) > $@ + clean: - rm -f verto-min.js jsmin *~ + rm -f verto-min.js verto-max.js jsmin *~ install-demo: all cp verto-min.js ../demo/js + +install-maxdemo: all verto-max.js + cp verto-max.js ../demo/js/verto-min.js From a3a80401fd7bb0cf4df124cf4e50040bb9c7be7b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 7 Nov 2014 17:11:40 -0600 Subject: [PATCH 52/91] fix regression caused by missing ! char in commit: 4eb5b388 --- src/switch_core_media.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 81b22fa381..b5a0398308 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -235,7 +235,7 @@ SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t static int get_channels(const char *name, int dft) { - if (!zstr(name) && switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) { + if (!zstr(name) && !switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) { return 2; /* IKR???*/ } From 9618ff16b42fa622ca3d7192778902178d8b0399 Mon Sep 17 00:00:00 2001 From: Brian West Date: Fri, 7 Nov 2014 17:41:29 -0600 Subject: [PATCH 53/91] FS-6973 revert this line --- build/buildopal.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/buildopal.sh b/build/buildopal.sh index 4528097401..f5845a7ce8 100755 --- a/build/buildopal.sh +++ b/build/buildopal.sh @@ -18,7 +18,7 @@ cd `dirname $0` cd .. FS_DIR=`pwd` -#export PKG_CONFIG_PATH=$INSTALLDIR/lib/pkgconfig +export PKG_CONFIG_PATH=$INSTALLDIR/lib/pkgconfig # Version and patch for PTLib and OPAL. These are almost always in lock From d9d9510ce4783879ea10a06114d5695a637dcd87 Mon Sep 17 00:00:00 2001 From: Ken Rice Date: Sat, 8 Nov 2014 15:13:05 -0600 Subject: [PATCH 54/91] Revert "FS-6967 New mod_say_es_AR to support Argentina Spanish variant." This reverts commit e75d0675afd8974687931143709814544299fadc. Revert "Add mod_say_es_ar to debian packaging" This reverts commit ebb3c8fbfa3ec8b9f4b4a2ef20d62d343c8ff6c4. Conflicts: configure.ac --- build/modules.conf.in | 1 - configure.ac | 1 - debian/control-modules | 4 - src/mod/say/mod_say_es_ar/Makefile.am | 8 - src/mod/say/mod_say_es_ar/mod_say_es_ar.c | 718 ---------------------- 5 files changed, 732 deletions(-) delete mode 100644 src/mod/say/mod_say_es_ar/Makefile.am delete mode 100644 src/mod/say/mod_say_es_ar/mod_say_es_ar.c diff --git a/build/modules.conf.in b/build/modules.conf.in index 1af56eef31..23ba9b84c8 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -132,7 +132,6 @@ loggers/mod_syslog #say/mod_say_de say/mod_say_en #say/mod_say_es -#say/mod_say_es_ar #say/mod_say_fa #say/mod_say_fr #say/mod_say_he diff --git a/configure.ac b/configure.ac index a11de35c84..efcbba28c8 100644 --- a/configure.ac +++ b/configure.ac @@ -1587,7 +1587,6 @@ AC_CONFIG_FILES([Makefile src/mod/say/mod_say_de/Makefile src/mod/say/mod_say_en/Makefile src/mod/say/mod_say_es/Makefile - src/mod/say/mod_say_es_ar/Makefile src/mod/say/mod_say_fa/Makefile src/mod/say/mod_say_fr/Makefile src/mod/say/mod_say_he/Makefile diff --git a/debian/control-modules b/debian/control-modules index 84b7d8d140..64ca7c0363 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -634,10 +634,6 @@ Module: say/mod_say_es Description: mod_say_es Adds mod_say_es. -Module: say/mod_say_es_ar -Description: mod_say_es_ar - Adds mod_say_es_ar. - Module: say/mod_say_fa Description: mod_say_fa Adds mod_say_fa. diff --git a/src/mod/say/mod_say_es_ar/Makefile.am b/src/mod/say/mod_say_es_ar/Makefile.am deleted file mode 100644 index 8386be0913..0000000000 --- a/src/mod/say/mod_say_es_ar/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -include $(top_srcdir)/build/modmake.rulesam -MODNAME=mod_say_es_ar - -mod_LTLIBRARIES = mod_say_es_ar.la -mod_say_es_AR_la_SOURCES = mod_say_es_ar.c -mod_say_es_AR_la_CFLAGS = $(AM_CFLAGS) -mod_say_es_AR_la_LIBADD = $(switch_builddir)/libfreeswitch.la -mod_say_es_AR_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/say/mod_say_es_ar/mod_say_es_ar.c b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c deleted file mode 100644 index f2dcb9cdb9..0000000000 --- a/src/mod/say/mod_say_es_ar/mod_say_es_ar.c +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * Michael B. Murdock - * François Delawarde - * Joao Mesquita - * - * mod_say_es_ar.c -- Say for Spanish (Argentina) - * - */ - -#include -#include -#include - -SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load); -SWITCH_MODULE_DEFINITION(mod_say_es_ar, mod_say_es_ar_load, NULL, NULL); - - -#define say_num(_sh, num, meth) { \ - char tmp[80]; \ - switch_status_t tstatus; \ - switch_say_method_t smeth = say_args->method; \ - switch_say_type_t stype = say_args->type; \ - say_args->type = SST_ITEMS; say_args->method = meth; \ - switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \ - if ((tstatus = \ - es_say_general_count(_sh, tmp, say_args)) \ - != SWITCH_STATUS_SUCCESS) { \ - return tstatus; \ - } \ - say_args->method = smeth; say_args->type = stype; \ - } \ - - - -static switch_status_t play_group(switch_say_method_t method, switch_say_gender_t gender, int a, int b, int c, char *what, switch_say_file_handle_t *sh) -{ - - if (a) { - if (a == 1 && b == 0 && c == 0) { - switch_say_file(sh, "digits/hundred"); - } else { - switch_say_file(sh, "digits/%d00", a); - } - } - - if (b) { - if (method == SSM_COUNTED) { - /* Numeros no redondos es masculino siempre. */ - if (gender == SSG_FEMININE && c == 0) { - switch_say_file(sh, "digits/h-%d0_a", b); - - } else { - switch_say_file(sh, "digits/h-%d0", b); - } - } else { - /* Veinti */ - if (b == 2) { - switch_say_file(sh, "digits/%d0_i", b); - } else if(b == 1) { - switch_say_file(sh, "digits/%d%d", b, c); - } else { - switch_say_file(sh, "digits/%d0", b); - if (c > 0) { - switch_say_file(sh, "digits/y"); - } - } - } - } - - if (c && b != 1) { - if (method == SSM_COUNTED) { - if (gender == SSG_FEMININE) { - switch_say_file(sh, "digits/h-%d_a", c); - } else { - switch_say_file(sh, "digits/h-%d", c); - } - } else { - if (c == 1) { - if (gender == SSG_NEUTER) { - switch_say_file(sh, "digits/%d_n", c); - } else if (gender == SSG_FEMININE) { - switch_say_file(sh, "digits/%d_a", c); - } else { - switch_say_file(sh, "digits/%d", c); - } - } else { - switch_say_file(sh, "digits/%d", c); - } - } - } - - if (what && (a || b || c)) { - switch_say_file(sh, what); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t es_say_general_count(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) -{ - int in; - int x = 0; - int places[9] = { 0 }; - char sbuf[128] = ""; - switch_status_t status; - - if (say_args->method == SSM_ITERATED) { - if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) { - char *p; - for (p = tosay; p && *p; p++) { - char *n_p = p+1; - switch_say_file(sh, "digits/%c", *p); - if (n_p && *n_p) { - switch_say_file(sh, "silence_stream://100"); - } - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); - return SWITCH_STATUS_GENERR; - } - return SWITCH_STATUS_SUCCESS; - } - - if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); - return SWITCH_STATUS_GENERR; - } - - in = atoi(tosay); - - if (in != 0) { - for (x = 8; x >= 0; x--) { - int num = (int) pow(10, x); - if ((places[(uint32_t) x] = in / num)) { - in -= places[(uint32_t) x] * num; - } - } - - - switch (say_args->method) { - case SSM_PRONOUNCED_YEAR: - { - int num = atoi(tosay); - int a = num / 100; - int b = num % 100; - - if (!b || !(a % 10)) { - say_num(sh, num, SSM_PRONOUNCED); - return SWITCH_STATUS_SUCCESS; - } - - say_num(sh, a, SSM_PRONOUNCED); - say_num(sh, b, SSM_PRONOUNCED); - - return SWITCH_STATUS_SUCCESS; - } - break; - case SSM_COUNTED: - case SSM_PRONOUNCED: - if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[8], places[7], places[6], "digits/million", sh)) != SWITCH_STATUS_SUCCESS) { - return status; - } - if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[5], places[4], places[3], "digits/thousand", sh)) != SWITCH_STATUS_SUCCESS) { - return status; - } - if ((status = play_group(say_args->method, say_args->gender, places[2], places[1], places[0], NULL, sh)) != SWITCH_STATUS_SUCCESS) { - return status; - } - break; - default: - break; - } - } else { - switch_say_file(sh, "digits/0"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t es_say_time(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) -{ - int32_t t; - switch_time_t target = 0, target_now = 0; - switch_time_exp_t tm, tm_now; - uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0; - const char *tz = NULL; - - tz = switch_say_file_handle_get_variable(sh, "timezone"); - - if (say_args->type == SST_TIME_MEASUREMENT) { - int64_t hours = 0; - int64_t minutes = 0; - int64_t seconds = 0; - int64_t r = 0; - - if (strchr(tosay, ':')) { - char *tme = strdup(tosay); - char *p; - - if ((p = strrchr(tme, ':'))) { - *p++ = '\0'; - seconds = atoi(p); - if ((p = strchr(tme, ':'))) { - *p++ = '\0'; - minutes = atoi(p); - hours = atoi(tme); - } else { - minutes = atoi(tme); - } - } - free(tme); - } else { - if ((seconds = atol(tosay)) <= 0) { - seconds = (int64_t) switch_epoch_time_now(NULL); - } - - if (seconds >= 60) { - minutes = seconds / 60; - r = seconds % 60; - seconds = r; - } - - if (minutes >= 60) { - hours = minutes / 60; - r = minutes % 60; - minutes = r; - } - } - - if (hours) { - say_num(sh, hours, SSM_PRONOUNCED); - if (hours == 1) { - switch_say_file(sh, "time/hour"); - } else { - switch_say_file(sh, "time/hours"); - } - } else { - switch_say_file(sh, "digits/0"); - switch_say_file(sh, "time/hours"); - } - - if (minutes) { - say_num(sh, minutes, SSM_PRONOUNCED); - if (minutes == 1) { - switch_say_file(sh, "time/minute"); - } else { - switch_say_file(sh, "time/minutes"); - } - } else { - switch_say_file(sh, "digits/0"); - switch_say_file(sh, "time/minutes"); - } - - if (seconds) { - say_num(sh, seconds, SSM_PRONOUNCED); - if (seconds == 1) { - switch_say_file(sh, "time/second"); - } else { - switch_say_file(sh, "time/seconds"); - } - } else { - switch_say_file(sh, "digits/0"); - switch_say_file(sh, "time/seconds"); - } - - return SWITCH_STATUS_SUCCESS; - } - - if ((t = atol(tosay)) > 0) { - target = switch_time_make(t, 0); - target_now = switch_micro_time_now(); - } else { - target = switch_micro_time_now(); - target_now = switch_micro_time_now(); - } - - if (tz) { - int check = atoi(tz); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz); - if (check) { - switch_time_exp_tz(&tm, target, check); - switch_time_exp_tz(&tm_now, target_now, check); - } else { - switch_time_exp_tz_name(tz, &tm, target); - switch_time_exp_tz_name(tz, &tm_now, target_now); - } - } else { - switch_time_exp_lt(&tm, target); - switch_time_exp_lt(&tm_now, target_now); - } - - switch (say_args->type) { - case SST_CURRENT_DATE_TIME: - say_date = say_time = 1; - break; - case SST_CURRENT_DATE: - say_date = 1; - break; - case SST_CURRENT_TIME: - say_time = 1; - break; - case SST_SHORT_DATE_TIME: - say_time = 1; - //Time is in the future - if ((tm.tm_year > tm_now.tm_year) || - (tm.tm_year == tm_now.tm_year && tm.tm_mon > tm_now.tm_mon) || - (tm.tm_year == tm_now.tm_year && tm.tm_mon == tm_now.tm_mon && tm.tm_mday > tm_now.tm_mday)) - { - say_date = 1; - break; - } - //Time is today or earlier - if (tm.tm_year != tm_now.tm_year) { - say_date = 1; - break; - } - if (tm.tm_yday == tm_now.tm_yday) { - say_today = 1; - break; - } - if (tm.tm_yday == tm_now.tm_yday - 1) { - say_yesterday = 1; - break; - } - if (tm.tm_yday >= tm_now.tm_yday - 5) { - say_dow = 1; - break; - } - if (tm.tm_mon != tm_now.tm_mon) { - say_month = say_day = say_dow = 1; - break; - } - - say_month = say_day = say_dow = 1; - - break; - default: - break; - } - - if (say_today) { - switch_say_file(sh, "time/today"); - } - if (say_yesterday) { - switch_say_file(sh, "time/yesterday"); - } - if (say_dow) { - switch_say_file(sh, "time/day-%d", tm.tm_wday); - } - - if (say_date) { - say_year = say_month = say_day = say_dow = 1; - say_today = say_yesterday = 0; - } - - if (say_day) { - if (tm.tm_mday == 1) { - say_num(sh, tm.tm_mday, SSM_COUNTED); - } else { - say_num(sh, tm.tm_mday, SSM_PRONOUNCED); - } - switch_say_file(sh, "time/de"); - } - if (say_month) { - switch_say_file(sh, "time/mon-%d", tm.tm_mon); - } - if (say_year) { - switch_say_file(sh, "time/de"); - say_num(sh, tm.tm_year + 1900, SSM_PRONOUNCED_YEAR); - } - - if (say_time) { - - if (say_date || say_today || say_yesterday || say_dow) { - switch_say_file(sh, "time/at"); - } - - - if (tm.tm_hour == 1) { - switch_say_file(sh, "digits/1"); - switch_say_file(sh, "time/hour"); - } else { - say_num(sh, tm.tm_hour, SSM_PRONOUNCED); - switch_say_file(sh, "time/hours"); - } - - if (tm.tm_min == 1) { - switch_say_file(sh, "digits/1_1a"); - switch_say_file(sh, "time/minute"); - } else { - say_num(sh, tm.tm_min, SSM_PRONOUNCED); - switch_say_file(sh, "time/minutes"); - } - - } - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t es_say_money(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) -{ - char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */ - char *dollars = NULL; - char *cents = NULL; - - if (strlen(tosay) > 15 || !switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); - return SWITCH_STATUS_GENERR; - } - - dollars = sbuf; - - if ((cents = strchr(sbuf, '.'))) { - *cents++ = '\0'; - if (strlen(cents) > 2) { - cents[2] = '\0'; - } - } - - /* If positive sign - skip over" */ - if (sbuf[0] == '+') { - dollars++; - } - - /* If negative say "negative" */ - if (sbuf[0] == '-') { - switch_say_file(sh, "currency/negative"); - dollars++; - } - - /* Say dollar amount */ - es_say_general_count(sh, dollars, say_args); - if (atoi(dollars) == 1) { - switch_say_file(sh, "currency/dollar"); - } else { - switch_say_file(sh, "currency/dollars"); - } - - /* Say cents */ - if (cents) { - /* Say "and" */ - switch_say_file(sh, "currency/and"); - - es_say_general_count(sh, cents, say_args); - if (atoi(cents) == 1) { - switch_say_file(sh, "currency/cent"); - } else { - switch_say_file(sh, "currency/cents"); - } - } - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t say_ip(switch_say_file_handle_t *sh, - char *tosay, - switch_say_args_t *say_args) - -{ - char *a, *b, *c, *d; - switch_status_t status = SWITCH_STATUS_FALSE; - - if (!(a = strdup(tosay))) { - abort(); - } - - if (!(b = strchr(a, '.'))) { - goto end; - } - - *b++ = '\0'; - - if (!(c = strchr(b, '.'))) { - goto end; - } - - *c++ = '\0'; - - if (!(d = strchr(c, '.'))) { - goto end; - } - - *d++ = '\0'; - - say_num(sh, atoi(a), say_args->method); - switch_say_file(sh, "digits/dot"); - say_num(sh, atoi(b), say_args->method); - switch_say_file(sh, "digits/dot"); - say_num(sh, atoi(c), say_args->method); - switch_say_file(sh, "digits/dot"); - say_num(sh, atoi(d), say_args->method); - - end: - - free(a); - - return status; -} - - -static switch_status_t say_telephone_number(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) -{ - int silence = 0; - char *p; - - for (p = tosay; !zstr(p); p++) { - int a = tolower((int) *p); - if (a >= '0' && a <= '9') { - switch_say_file(sh, "digits/%c", a); - silence = 0; - } else if (a == '+' || (a >= 'a' && a <= 'z')) { - switch_say_file(sh, "ascii/%d", a); - silence = 0; - } else if (!silence) { - switch_say_file(sh, "silence_stream://100"); - silence = 1; - } - } - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t say_spell(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) -{ - char *p; - - for (p = tosay; p && *p; p++) { - int a = tolower((int) *p); - if (a >= '0' && a <= '9') { - switch_say_file(sh, "digits/%c", a); - } else { - if (say_args->type == SST_NAME_SPELLED) { - switch_say_file(sh, "ascii/%d", a); - } else if (say_args->type == SST_NAME_PHONETIC) { - switch_say_file(sh, "phonetic-ascii/%d", a); - } - } - } - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_new_say_callback_t choose_callback(switch_say_args_t *say_args) -{ - switch_new_say_callback_t say_cb = NULL; - - switch (say_args->type) { - case SST_NUMBER: - case SST_ITEMS: - case SST_PERSONS: - case SST_MESSAGES: - say_cb = es_say_general_count; - break; - case SST_TIME_MEASUREMENT: - case SST_CURRENT_DATE: - case SST_CURRENT_TIME: - case SST_CURRENT_DATE_TIME: - case SST_SHORT_DATE_TIME: - say_cb = es_say_time; - break; - case SST_IP_ADDRESS: - say_cb = say_ip; - break; - case SST_NAME_SPELLED: - case SST_NAME_PHONETIC: - say_cb = say_spell; - break; - case SST_CURRENCY: - say_cb = es_say_money; - break; - case SST_TELEPHONE_NUMBER: - say_cb = say_telephone_number; - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type); - break; - } - - return say_cb; -} - - -static switch_status_t run_callback(switch_new_say_callback_t say_cb, char *tosay, switch_say_args_t *say_args, switch_core_session_t *session, char **rstr) -{ - switch_say_file_handle_t *sh; - switch_status_t status = SWITCH_STATUS_FALSE; - switch_event_t *var_event = NULL; - - if (session) { - switch_channel_t *channel = switch_core_session_get_channel(session); - switch_channel_get_variables(channel, &var_event); - } - - switch_say_file_handle_create(&sh, say_args->ext, &var_event); - - status = say_cb(sh, tosay, say_args); - - if ((*rstr = switch_say_file_handle_detach_path(sh))) { - status = SWITCH_STATUS_SUCCESS; - } - - switch_say_file_handle_destroy(&sh); - - return status; -} - - -static switch_status_t es_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) -{ - - switch_new_say_callback_t say_cb = NULL; - char *string = NULL; - - switch_status_t status = SWITCH_STATUS_FALSE; - - say_cb = choose_callback(say_args); - - if (say_cb) { - status = run_callback(say_cb, tosay, say_args, session, &string); - if (session && string) { - status = switch_ivr_play_file(session, NULL, string, args); - } - - switch_safe_free(string); - } - - return status; -} - - -static switch_status_t es_say_string(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, char **rstr) -{ - - switch_new_say_callback_t say_cb = NULL; - char *string = NULL; - - switch_status_t status = SWITCH_STATUS_FALSE; - - say_cb = choose_callback(say_args); - - if (say_cb) { - status = run_callback(say_cb, tosay, say_args, session, &string); - if (string) { - status = SWITCH_STATUS_SUCCESS; - *rstr = string; - } - } - - return status; -} - -SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load) -{ - switch_say_interface_t *say_interface; - /* connect my internal structure to the blank pointer passed to me */ - *module_interface = switch_loadable_module_create_module_interface(pool, modname); - say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE); - say_interface->interface_name = "es_ar"; - say_interface->say_function = es_say; - say_interface->say_string_function = es_say_string; - - /* indicate that the module should continue to be loaded */ - return SWITCH_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ From 2f1b12fdc0f74b10fe8f38f3dc59f875ad4a072c Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 9 Nov 2014 03:33:08 -0500 Subject: [PATCH 55/91] OPENZAP-232 #resolve Patched-By: Florian Richter Check for digits received on sangoma isdn stack to avoid delaying moving to the ring state if all digits are received at once in overlap dialing mode --- .../ftmod_sangoma_isdn_stack_hndl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 b414d4dfb1..f9516235b7 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 @@ -203,8 +203,17 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) } } #endif - if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + if (signal_data->overlap_dial == SNGISDN_OPT_TRUE) { + ftdm_size_t min_digits = ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->min_digits; + ftdm_size_t num_digits; + + num_digits = strlen(ftdmchan->caller_data.dnis.digits); + + if (conEvnt->sndCmplt.eh.pres || num_digits >= min_digits) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } else { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + } } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); } From 6b8d5b2b100946e2a23eacacbd88ae595097697d Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 9 Nov 2014 00:41:59 -0800 Subject: [PATCH 56/91] freetdm: Fix release guard timer check --- libs/freetdm/src/ftdm_io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 099035409f..cbc04eb894 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1492,12 +1492,13 @@ static __inline__ int chan_is_avail(ftdm_channel_t *check) } /* release guard time check */ if (check->span->sig_release_guard_time_ms && check->last_release_time) { - ftdm_time_t time_diff = (check->last_release_time - ftdm_current_time_in_ms()); + ftdm_time_t time_diff = (ftdm_current_time_in_ms() - check->last_release_time); if (time_diff < check->span->sig_release_guard_time_ms) { return 0; } /* circuit now available for outbound dialing */ check->last_release_time = 0; + ftdm_log_chan(check, FTDM_LOG_DEBUG, "Channel is now available, release guard timer expired %zdms ago\n", (time_diff - check->span->sig_release_guard_time_ms)); } return 1; } From 11e62dd40de9c466ace8c21c16395a1da7663459 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Mon, 10 Nov 2014 11:12:15 -0500 Subject: [PATCH 57/91] Revert "Revert "FS-6967 New mod_say_es_AR to support Argentina Spanish variant."" This reverts commit d9d9510ce4783879ea10a06114d5695a637dcd87. --- build/modules.conf.in | 1 + configure.ac | 1 + debian/control-modules | 4 + src/mod/say/mod_say_es_ar/Makefile.am | 8 + src/mod/say/mod_say_es_ar/mod_say_es_ar.c | 718 ++++++++++++++++++++++ 5 files changed, 732 insertions(+) create mode 100644 src/mod/say/mod_say_es_ar/Makefile.am create mode 100644 src/mod/say/mod_say_es_ar/mod_say_es_ar.c diff --git a/build/modules.conf.in b/build/modules.conf.in index 23ba9b84c8..1af56eef31 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -132,6 +132,7 @@ loggers/mod_syslog #say/mod_say_de say/mod_say_en #say/mod_say_es +#say/mod_say_es_ar #say/mod_say_fa #say/mod_say_fr #say/mod_say_he diff --git a/configure.ac b/configure.ac index efcbba28c8..a11de35c84 100644 --- a/configure.ac +++ b/configure.ac @@ -1587,6 +1587,7 @@ AC_CONFIG_FILES([Makefile src/mod/say/mod_say_de/Makefile src/mod/say/mod_say_en/Makefile src/mod/say/mod_say_es/Makefile + src/mod/say/mod_say_es_ar/Makefile src/mod/say/mod_say_fa/Makefile src/mod/say/mod_say_fr/Makefile src/mod/say/mod_say_he/Makefile diff --git a/debian/control-modules b/debian/control-modules index 64ca7c0363..84b7d8d140 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -634,6 +634,10 @@ Module: say/mod_say_es Description: mod_say_es Adds mod_say_es. +Module: say/mod_say_es_ar +Description: mod_say_es_ar + Adds mod_say_es_ar. + Module: say/mod_say_fa Description: mod_say_fa Adds mod_say_fa. diff --git a/src/mod/say/mod_say_es_ar/Makefile.am b/src/mod/say/mod_say_es_ar/Makefile.am new file mode 100644 index 0000000000..8386be0913 --- /dev/null +++ b/src/mod/say/mod_say_es_ar/Makefile.am @@ -0,0 +1,8 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_say_es_ar + +mod_LTLIBRARIES = mod_say_es_ar.la +mod_say_es_AR_la_SOURCES = mod_say_es_ar.c +mod_say_es_AR_la_CFLAGS = $(AM_CFLAGS) +mod_say_es_AR_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_say_es_AR_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/say/mod_say_es_ar/mod_say_es_ar.c b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c new file mode 100644 index 0000000000..f2dcb9cdb9 --- /dev/null +++ b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2007-2014, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Michael B. Murdock + * François Delawarde + * Joao Mesquita + * + * mod_say_es_ar.c -- Say for Spanish (Argentina) + * + */ + +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load); +SWITCH_MODULE_DEFINITION(mod_say_es_ar, mod_say_es_ar_load, NULL, NULL); + + +#define say_num(_sh, num, meth) { \ + char tmp[80]; \ + switch_status_t tstatus; \ + switch_say_method_t smeth = say_args->method; \ + switch_say_type_t stype = say_args->type; \ + say_args->type = SST_ITEMS; say_args->method = meth; \ + switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \ + if ((tstatus = \ + es_say_general_count(_sh, tmp, say_args)) \ + != SWITCH_STATUS_SUCCESS) { \ + return tstatus; \ + } \ + say_args->method = smeth; say_args->type = stype; \ + } \ + + + +static switch_status_t play_group(switch_say_method_t method, switch_say_gender_t gender, int a, int b, int c, char *what, switch_say_file_handle_t *sh) +{ + + if (a) { + if (a == 1 && b == 0 && c == 0) { + switch_say_file(sh, "digits/hundred"); + } else { + switch_say_file(sh, "digits/%d00", a); + } + } + + if (b) { + if (method == SSM_COUNTED) { + /* Numeros no redondos es masculino siempre. */ + if (gender == SSG_FEMININE && c == 0) { + switch_say_file(sh, "digits/h-%d0_a", b); + + } else { + switch_say_file(sh, "digits/h-%d0", b); + } + } else { + /* Veinti */ + if (b == 2) { + switch_say_file(sh, "digits/%d0_i", b); + } else if(b == 1) { + switch_say_file(sh, "digits/%d%d", b, c); + } else { + switch_say_file(sh, "digits/%d0", b); + if (c > 0) { + switch_say_file(sh, "digits/y"); + } + } + } + } + + if (c && b != 1) { + if (method == SSM_COUNTED) { + if (gender == SSG_FEMININE) { + switch_say_file(sh, "digits/h-%d_a", c); + } else { + switch_say_file(sh, "digits/h-%d", c); + } + } else { + if (c == 1) { + if (gender == SSG_NEUTER) { + switch_say_file(sh, "digits/%d_n", c); + } else if (gender == SSG_FEMININE) { + switch_say_file(sh, "digits/%d_a", c); + } else { + switch_say_file(sh, "digits/%d", c); + } + } else { + switch_say_file(sh, "digits/%d", c); + } + } + } + + if (what && (a || b || c)) { + switch_say_file(sh, what); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t es_say_general_count(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int in; + int x = 0; + int places[9] = { 0 }; + char sbuf[128] = ""; + switch_status_t status; + + if (say_args->method == SSM_ITERATED) { + if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) { + char *p; + for (p = tosay; p && *p; p++) { + char *n_p = p+1; + switch_say_file(sh, "digits/%c", *p); + if (n_p && *n_p) { + switch_say_file(sh, "silence_stream://100"); + } + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + return SWITCH_STATUS_SUCCESS; + } + + if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + in = atoi(tosay); + + if (in != 0) { + for (x = 8; x >= 0; x--) { + int num = (int) pow(10, x); + if ((places[(uint32_t) x] = in / num)) { + in -= places[(uint32_t) x] * num; + } + } + + + switch (say_args->method) { + case SSM_PRONOUNCED_YEAR: + { + int num = atoi(tosay); + int a = num / 100; + int b = num % 100; + + if (!b || !(a % 10)) { + say_num(sh, num, SSM_PRONOUNCED); + return SWITCH_STATUS_SUCCESS; + } + + say_num(sh, a, SSM_PRONOUNCED); + say_num(sh, b, SSM_PRONOUNCED); + + return SWITCH_STATUS_SUCCESS; + } + break; + case SSM_COUNTED: + case SSM_PRONOUNCED: + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[8], places[7], places[6], "digits/million", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[5], places[4], places[3], "digits/thousand", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(say_args->method, say_args->gender, places[2], places[1], places[0], NULL, sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + break; + default: + break; + } + } else { + switch_say_file(sh, "digits/0"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t es_say_time(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int32_t t; + switch_time_t target = 0, target_now = 0; + switch_time_exp_t tm, tm_now; + uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0; + const char *tz = NULL; + + tz = switch_say_file_handle_get_variable(sh, "timezone"); + + if (say_args->type == SST_TIME_MEASUREMENT) { + int64_t hours = 0; + int64_t minutes = 0; + int64_t seconds = 0; + int64_t r = 0; + + if (strchr(tosay, ':')) { + char *tme = strdup(tosay); + char *p; + + if ((p = strrchr(tme, ':'))) { + *p++ = '\0'; + seconds = atoi(p); + if ((p = strchr(tme, ':'))) { + *p++ = '\0'; + minutes = atoi(p); + hours = atoi(tme); + } else { + minutes = atoi(tme); + } + } + free(tme); + } else { + if ((seconds = atol(tosay)) <= 0) { + seconds = (int64_t) switch_epoch_time_now(NULL); + } + + if (seconds >= 60) { + minutes = seconds / 60; + r = seconds % 60; + seconds = r; + } + + if (minutes >= 60) { + hours = minutes / 60; + r = minutes % 60; + minutes = r; + } + } + + if (hours) { + say_num(sh, hours, SSM_PRONOUNCED); + if (hours == 1) { + switch_say_file(sh, "time/hour"); + } else { + switch_say_file(sh, "time/hours"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/hours"); + } + + if (minutes) { + say_num(sh, minutes, SSM_PRONOUNCED); + if (minutes == 1) { + switch_say_file(sh, "time/minute"); + } else { + switch_say_file(sh, "time/minutes"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/minutes"); + } + + if (seconds) { + say_num(sh, seconds, SSM_PRONOUNCED); + if (seconds == 1) { + switch_say_file(sh, "time/second"); + } else { + switch_say_file(sh, "time/seconds"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/seconds"); + } + + return SWITCH_STATUS_SUCCESS; + } + + if ((t = atol(tosay)) > 0) { + target = switch_time_make(t, 0); + target_now = switch_micro_time_now(); + } else { + target = switch_micro_time_now(); + target_now = switch_micro_time_now(); + } + + if (tz) { + int check = atoi(tz); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz); + if (check) { + switch_time_exp_tz(&tm, target, check); + switch_time_exp_tz(&tm_now, target_now, check); + } else { + switch_time_exp_tz_name(tz, &tm, target); + switch_time_exp_tz_name(tz, &tm_now, target_now); + } + } else { + switch_time_exp_lt(&tm, target); + switch_time_exp_lt(&tm_now, target_now); + } + + switch (say_args->type) { + case SST_CURRENT_DATE_TIME: + say_date = say_time = 1; + break; + case SST_CURRENT_DATE: + say_date = 1; + break; + case SST_CURRENT_TIME: + say_time = 1; + break; + case SST_SHORT_DATE_TIME: + say_time = 1; + //Time is in the future + if ((tm.tm_year > tm_now.tm_year) || + (tm.tm_year == tm_now.tm_year && tm.tm_mon > tm_now.tm_mon) || + (tm.tm_year == tm_now.tm_year && tm.tm_mon == tm_now.tm_mon && tm.tm_mday > tm_now.tm_mday)) + { + say_date = 1; + break; + } + //Time is today or earlier + if (tm.tm_year != tm_now.tm_year) { + say_date = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday) { + say_today = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday - 1) { + say_yesterday = 1; + break; + } + if (tm.tm_yday >= tm_now.tm_yday - 5) { + say_dow = 1; + break; + } + if (tm.tm_mon != tm_now.tm_mon) { + say_month = say_day = say_dow = 1; + break; + } + + say_month = say_day = say_dow = 1; + + break; + default: + break; + } + + if (say_today) { + switch_say_file(sh, "time/today"); + } + if (say_yesterday) { + switch_say_file(sh, "time/yesterday"); + } + if (say_dow) { + switch_say_file(sh, "time/day-%d", tm.tm_wday); + } + + if (say_date) { + say_year = say_month = say_day = say_dow = 1; + say_today = say_yesterday = 0; + } + + if (say_day) { + if (tm.tm_mday == 1) { + say_num(sh, tm.tm_mday, SSM_COUNTED); + } else { + say_num(sh, tm.tm_mday, SSM_PRONOUNCED); + } + switch_say_file(sh, "time/de"); + } + if (say_month) { + switch_say_file(sh, "time/mon-%d", tm.tm_mon); + } + if (say_year) { + switch_say_file(sh, "time/de"); + say_num(sh, tm.tm_year + 1900, SSM_PRONOUNCED_YEAR); + } + + if (say_time) { + + if (say_date || say_today || say_yesterday || say_dow) { + switch_say_file(sh, "time/at"); + } + + + if (tm.tm_hour == 1) { + switch_say_file(sh, "digits/1"); + switch_say_file(sh, "time/hour"); + } else { + say_num(sh, tm.tm_hour, SSM_PRONOUNCED); + switch_say_file(sh, "time/hours"); + } + + if (tm.tm_min == 1) { + switch_say_file(sh, "digits/1_1a"); + switch_say_file(sh, "time/minute"); + } else { + say_num(sh, tm.tm_min, SSM_PRONOUNCED); + switch_say_file(sh, "time/minutes"); + } + + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t es_say_money(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */ + char *dollars = NULL; + char *cents = NULL; + + if (strlen(tosay) > 15 || !switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + dollars = sbuf; + + if ((cents = strchr(sbuf, '.'))) { + *cents++ = '\0'; + if (strlen(cents) > 2) { + cents[2] = '\0'; + } + } + + /* If positive sign - skip over" */ + if (sbuf[0] == '+') { + dollars++; + } + + /* If negative say "negative" */ + if (sbuf[0] == '-') { + switch_say_file(sh, "currency/negative"); + dollars++; + } + + /* Say dollar amount */ + es_say_general_count(sh, dollars, say_args); + if (atoi(dollars) == 1) { + switch_say_file(sh, "currency/dollar"); + } else { + switch_say_file(sh, "currency/dollars"); + } + + /* Say cents */ + if (cents) { + /* Say "and" */ + switch_say_file(sh, "currency/and"); + + es_say_general_count(sh, cents, say_args); + if (atoi(cents) == 1) { + switch_say_file(sh, "currency/cent"); + } else { + switch_say_file(sh, "currency/cents"); + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t say_ip(switch_say_file_handle_t *sh, + char *tosay, + switch_say_args_t *say_args) + +{ + char *a, *b, *c, *d; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!(a = strdup(tosay))) { + abort(); + } + + if (!(b = strchr(a, '.'))) { + goto end; + } + + *b++ = '\0'; + + if (!(c = strchr(b, '.'))) { + goto end; + } + + *c++ = '\0'; + + if (!(d = strchr(c, '.'))) { + goto end; + } + + *d++ = '\0'; + + say_num(sh, atoi(a), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(b), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(c), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(d), say_args->method); + + end: + + free(a); + + return status; +} + + +static switch_status_t say_telephone_number(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int silence = 0; + char *p; + + for (p = tosay; !zstr(p); p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + silence = 0; + } else if (a == '+' || (a >= 'a' && a <= 'z')) { + switch_say_file(sh, "ascii/%d", a); + silence = 0; + } else if (!silence) { + switch_say_file(sh, "silence_stream://100"); + silence = 1; + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t say_spell(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char *p; + + for (p = tosay; p && *p; p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + } else { + if (say_args->type == SST_NAME_SPELLED) { + switch_say_file(sh, "ascii/%d", a); + } else if (say_args->type == SST_NAME_PHONETIC) { + switch_say_file(sh, "phonetic-ascii/%d", a); + } + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_new_say_callback_t choose_callback(switch_say_args_t *say_args) +{ + switch_new_say_callback_t say_cb = NULL; + + switch (say_args->type) { + case SST_NUMBER: + case SST_ITEMS: + case SST_PERSONS: + case SST_MESSAGES: + say_cb = es_say_general_count; + break; + case SST_TIME_MEASUREMENT: + case SST_CURRENT_DATE: + case SST_CURRENT_TIME: + case SST_CURRENT_DATE_TIME: + case SST_SHORT_DATE_TIME: + say_cb = es_say_time; + break; + case SST_IP_ADDRESS: + say_cb = say_ip; + break; + case SST_NAME_SPELLED: + case SST_NAME_PHONETIC: + say_cb = say_spell; + break; + case SST_CURRENCY: + say_cb = es_say_money; + break; + case SST_TELEPHONE_NUMBER: + say_cb = say_telephone_number; + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type); + break; + } + + return say_cb; +} + + +static switch_status_t run_callback(switch_new_say_callback_t say_cb, char *tosay, switch_say_args_t *say_args, switch_core_session_t *session, char **rstr) +{ + switch_say_file_handle_t *sh; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_event_t *var_event = NULL; + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_get_variables(channel, &var_event); + } + + switch_say_file_handle_create(&sh, say_args->ext, &var_event); + + status = say_cb(sh, tosay, say_args); + + if ((*rstr = switch_say_file_handle_detach_path(sh))) { + status = SWITCH_STATUS_SUCCESS; + } + + switch_say_file_handle_destroy(&sh); + + return status; +} + + +static switch_status_t es_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (session && string) { + status = switch_ivr_play_file(session, NULL, string, args); + } + + switch_safe_free(string); + } + + return status; +} + + +static switch_status_t es_say_string(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, char **rstr) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (string) { + status = SWITCH_STATUS_SUCCESS; + *rstr = string; + } + } + + return status; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load) +{ + switch_say_interface_t *say_interface; + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE); + say_interface->interface_name = "es_ar"; + say_interface->say_function = es_say; + say_interface->say_string_function = es_say_string; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ From 0f8b99376916135a31ec6547c22b2e1f3cb077d1 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Mon, 10 Nov 2014 11:12:56 -0500 Subject: [PATCH 58/91] fix mod_say_es_ar Makefile.am --- src/mod/say/mod_say_es_ar/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod/say/mod_say_es_ar/Makefile.am b/src/mod/say/mod_say_es_ar/Makefile.am index 8386be0913..ca206db7c2 100644 --- a/src/mod/say/mod_say_es_ar/Makefile.am +++ b/src/mod/say/mod_say_es_ar/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/build/modmake.rulesam MODNAME=mod_say_es_ar mod_LTLIBRARIES = mod_say_es_ar.la -mod_say_es_AR_la_SOURCES = mod_say_es_ar.c -mod_say_es_AR_la_CFLAGS = $(AM_CFLAGS) -mod_say_es_AR_la_LIBADD = $(switch_builddir)/libfreeswitch.la -mod_say_es_AR_la_LDFLAGS = -avoid-version -module -no-undefined -shared +mod_say_es_ar_la_SOURCES = mod_say_es_ar.c +mod_say_es_ar_la_CFLAGS = $(AM_CFLAGS) +mod_say_es_ar_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_say_es_ar_la_LDFLAGS = -avoid-version -module -no-undefined -shared From 34cf3b9069b4b73f04bb946b28e0c28b9d982f67 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 11 Nov 2014 07:45:50 -0600 Subject: [PATCH 59/91] FS-6980 #resolve don't crash when using native recording on recordstop --- src/switch_ivr_async.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index dcea776c83..1b209ae196 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1088,17 +1088,17 @@ static void send_record_stop_event(switch_channel_t *channel, switch_codec_imple { switch_event_t *event; - if (read_impl->actual_samples_per_second) { - switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl->actual_samples_per_second); - switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl->actual_samples_per_second / 1000)); + if (rh->fh) { + switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out); + if (read_impl->actual_samples_per_second) { + switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl->actual_samples_per_second); + switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl->actual_samples_per_second / 1000)); + } } - if (!zstr(rh->completion_cause)) { switch_channel_set_variable_printf(channel, "record_completion_cause", "%s", rh->completion_cause); } - switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out); - if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file); From ab24bde262f928277a35c557304a7d78d2b4baf3 Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 11 Nov 2014 08:41:16 -0600 Subject: [PATCH 60/91] FS-5533 fix issue with busy signal being sent back to all shared lines instead of just the calling device --- src/mod/endpoints/mod_skinny/mod_skinny.c | 42 ++++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 5f6bf1f14e..5925abebe4 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -954,27 +954,29 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN send_clear_prompt_status(listener, line_instance, call_id); } send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF); - switch (helper->cause) { - case SWITCH_CAUSE_UNALLOCATED_NUMBER: - send_start_tone(listener, SKINNY_TONE_REORDER, 0, line_instance, call_id); - skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); - label = skinny_textid2raw(SKINNY_TEXTID_UNKNOWN_NUMBER); - send_display_prompt_status(listener, 0, label, line_instance, call_id); - switch_safe_free(label); - break; - case SWITCH_CAUSE_USER_BUSY: - send_start_tone(listener, SKINNY_TONE_BUSYTONE, 0, line_instance, call_id); - label = skinny_textid2raw(SKINNY_TEXTID_BUSY); - send_display_prompt_status(listener, 0, label, line_instance, call_id); - switch_safe_free(label); - break; - case SWITCH_CAUSE_NORMAL_CLEARING: - send_clear_prompt_status(listener, line_instance, call_id); - break; - default: - send_display_prompt_status(listener, 0, switch_channel_cause2str(helper->cause), line_instance, call_id); - } + if((call_state == SKINNY_PROCEED) || (call_state == SKINNY_RING_OUT) || (call_state == SKINNY_CONNECTED)) { /* calling parties */ + switch (helper->cause) { + case SWITCH_CAUSE_UNALLOCATED_NUMBER: + send_start_tone(listener, SKINNY_TONE_REORDER, 0, line_instance, call_id); + skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); + label = skinny_textid2raw(SKINNY_TEXTID_UNKNOWN_NUMBER); + send_display_prompt_status(listener, 0, label, line_instance, call_id); + switch_safe_free(label); + break; + case SWITCH_CAUSE_USER_BUSY: + send_start_tone(listener, SKINNY_TONE_BUSYTONE, 0, line_instance, call_id); + label = skinny_textid2raw(SKINNY_TEXTID_BUSY); + send_display_prompt_status(listener, 0, label, line_instance, call_id); + switch_safe_free(label); + break; + case SWITCH_CAUSE_NORMAL_CLEARING: + send_clear_prompt_status(listener, line_instance, call_id); + break; + default: + send_display_prompt_status(listener, 0, switch_channel_cause2str(helper->cause), line_instance, call_id); + } + skinny_session_stop_media(helper->tech_pvt->session, listener, line_instance); } From c79360c5964afc1d9c8f235b24f66b713c573df0 Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 11 Nov 2014 09:11:44 -0600 Subject: [PATCH 61/91] reduce logging when level is below 9 for less important messages --- .../endpoints/mod_skinny/skinny_protocol.c | 51 ++++++++++++------- src/mod/endpoints/mod_skinny/skinny_server.c | 41 ++++++++++----- 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index fc4ee532a0..1e1c539150 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -506,9 +506,11 @@ switch_status_t perform_send_register_ack(listener_t *listener, message->data.reg_ack.secondary_keep_alive = keep_alive; switch_copy_string(message->data.reg_ack.reserved2, reserved2, 4); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Sending Register Ack with Keep Alive (%d), Date Format (%s), Secondary Keep Alive (%d)\n", - keep_alive, date_format, secondary_keep_alive); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Sending Register Ack with Keep Alive (%d), Date Format (%s), Secondary Keep Alive (%d)\n", + keep_alive, date_format, secondary_keep_alive); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -527,9 +529,11 @@ switch_status_t perform_send_speed_dial_stat_res(listener_t *listener, switch_copy_string(message->data.speed_dial_res.line, speed_line, 24); switch_copy_string(message->data.speed_dial_res.label, speed_label, 40); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Sending Speed Dial Stat Res with Number (%d), Line (%s), Label (%s)\n", - number, speed_line, speed_label); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Sending Speed Dial Stat Res with Number (%d), Line (%s), Label (%s)\n", + number, speed_line, speed_label); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -791,8 +795,10 @@ switch_status_t perform_send_call_info(listener_t *listener, message->data.call_info.call_security_status = call_security_status; message->data.call_info.party_pi_restriction_bits = party_pi_restriction_bits; - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Call Info with Line Instance (%d)...\n", line_instance); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Call Info with Line Instance (%d)...\n", line_instance); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -823,9 +829,11 @@ switch_status_t perform_send_define_time_date(listener_t *listener, message->data.define_time_date.milliseconds = milliseconds; message->data.define_time_date.timestamp = timestamp; - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Define Time Date with %.4d-%.2d-%.2d %.2d:%.2d:%.2d.%d, Timestamp (%d), DOW (%d)\n", - year, month, day, hour, minute, seconds, milliseconds, timestamp, day_of_week); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Define Time Date with %.4d-%.2d-%.2d %.2d:%.2d:%.2d.%d, Timestamp (%d), DOW (%d)\n", + year, month, day, hour, minute, seconds, milliseconds, timestamp, day_of_week); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -857,8 +865,10 @@ switch_status_t perform_send_capabilities_req(listener_t *listener, skinny_create_empty_message(message, CAPABILITIES_REQ_MESSAGE); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Capabilities Req%s\n", ""); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Capabilities Req%s\n", ""); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -873,8 +883,10 @@ switch_status_t perform_send_version(listener_t *listener, memcpy(message->data.version.version, version, 16); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Version with Version(%s)\n", version); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Version with Version(%s)\n", version); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -973,9 +985,11 @@ switch_status_t perform_send_select_soft_keys(listener_t *listener, message->data.select_soft_keys.soft_key_set = soft_key_set; message->data.select_soft_keys.valid_key_mask = valid_key_mask; - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Select Soft Keys with Line Instance (%d), Call ID (%d), Soft Key Set (%d), Valid Key Mask (%x)\n", + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Select Soft Keys with Line Instance (%d), Call ID (%d), Soft Key Set (%d), Valid Key Mask (%x)\n", line_instance, call_id, soft_key_set, valid_key_mask); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -1299,7 +1313,8 @@ switch_status_t skinny_perform_send_reply(listener_t *listener, const char *file ptr = (char *) reply; if (listener_is_ready(listener)) { - if (listener->profile->debug >= 10 || reply->type != KEEP_ALIVE_ACK_MESSAGE) { + if (listener->profile->debug >= 10 || + (listener->profile->debug >= 9 && reply->type != KEEP_ALIVE_ACK_MESSAGE)) { skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, "Sending %s (type=%x,length=%d).\n", skinny_message_type2str(reply->type), reply->type, reply->length); diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 64b6d16831..5a581de463 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -1621,8 +1621,10 @@ switch_status_t skinny_handle_forward_stat_req_message(listener_t *listener, ski message->data.forward_stat.line_instance = request->data.forward_stat_req.line_instance; - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Forward Stat Req Message with Line Instance (%d)\n", - request->data.forward_stat_req.line_instance); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Forward Stat Req Message with Line Instance (%d)\n", + request->data.forward_stat_req.line_instance); + } skinny_send_reply_quiet(listener, message, SWITCH_TRUE); return SWITCH_STATUS_SUCCESS; @@ -1634,7 +1636,9 @@ switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skin skinny_check_data_length(request, sizeof(request->data.speed_dial_req)); - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Speed Dial Stat Request for Number (%d)\n", request->data.speed_dial_req.number); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Speed Dial Stat Request for Number (%d)\n", request->data.speed_dial_req.number); + } skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); @@ -1906,7 +1910,9 @@ switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Codecs %s supported.\n", codec_string); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Codecs %s supported.\n", codec_string); + } switch_safe_free(codec_string); return SWITCH_STATUS_SUCCESS; } @@ -2036,11 +2042,15 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ if (listener->soft_key_set_set) { message = switch_core_hash_find(listener->profile->soft_key_set_sets_hash, listener->soft_key_set_set); - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", listener->soft_key_set_set); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", listener->soft_key_set_set); + } } if (!message) { message = switch_core_hash_find(listener->profile->soft_key_set_sets_hash, "default"); - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", "default"); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", "default"); + } } if (message) { skinny_send_reply_quiet(listener, message, SWITCH_FALSE); @@ -2231,7 +2241,9 @@ switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, sk message->data.soft_key_template.soft_key[i].soft_key_event = soft_key_template_default_events[i]; } - skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Template Request with Default Template\n"); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Template Request with Default Template\n"); + } skinny_send_reply_quiet(listener, message, SWITCH_TRUE); @@ -2254,8 +2266,10 @@ switch_status_t skinny_headset_status_message(listener_t *listener, skinny_messa switch_safe_free(sql); } - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Update headset accessory status (%s)\n", - skinny_accessory_state2str(request->data.headset_status.mode)); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Update headset accessory status (%s)\n", + skinny_accessory_state2str(request->data.headset_status.mode)); + } return SWITCH_STATUS_SUCCESS; } @@ -2274,7 +2288,9 @@ switch_status_t skinny_handle_register_available_lines_message(listener_t *liste { skinny_check_data_length(request, sizeof(request->data.reg_lines)); - skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Register Available Lines\n"); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Register Available Lines\n"); + } /* Do nothing */ return SWITCH_STATUS_SUCCESS; @@ -2531,7 +2547,7 @@ switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t * switch_event_t *event = NULL; char *tmp = NULL; - skinny_log_l(listener, SWITCH_LOG_INFO, "Received XML alarm (length=%d).\n", request->length); + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Received XML alarm (length=%d).\n", request->length); /* skinny::xml_alarm event */ skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_XML_ALARM); /* Ensure that the body is null-terminated */ @@ -2547,7 +2563,8 @@ switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t * switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request) { - if (listener->profile->debug >= 10 || request->type != KEEP_ALIVE_MESSAGE) { + if (listener->profile->debug >= 10 || + (listener->profile->debug >= 9 && request->type != KEEP_ALIVE_MESSAGE)) { skinny_log_l(listener, SWITCH_LOG_DEBUG, "Received %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length); } From eb3a27ccee10f72df4bc237d5254a5c8636f3205 Mon Sep 17 00:00:00 2001 From: Seven Du Date: Tue, 11 Nov 2014 23:33:03 +0800 Subject: [PATCH 62/91] use 4 spaces indent to match the default of jslint this is the first step of making the code follow the default jslint behaviour, I also manually changed some { } to make it reasonable in addition to replacing tabs --- html5/verto/js/src/jquery.FSRTC.js | 112 +- html5/verto/js/src/jquery.jsonrpcclient.js | 1158 ++++++++++---------- html5/verto/js/src/jquery.verto.js | 567 +++++----- 3 files changed, 908 insertions(+), 929 deletions(-) diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js index d4f25f4fb9..4635106069 100644 --- a/html5/verto/js/src/jquery.FSRTC.js +++ b/html5/verto/js/src/jquery.FSRTC.js @@ -64,8 +64,9 @@ var newLine = []; var index = 0; for (var i = 0; i < elements.length; i++) { - if (index === 3) // Format of media starts from the fourth. - newLine[index++] = payload; // Put target payload to the first. + if (index === 3) { // Format of media starts from the fourth. + newLine[index++] = payload; // Put target payload to the first. + } if (elements[i] !== payload) newLine[index++] = elements[i]; } return newLine.join(' '); @@ -76,7 +77,7 @@ useVideo: null, useStereo: false, userData: null, - iceServers: false, + iceServers: false, videoParams: {}, audioParams: {}, callbacks: { @@ -84,8 +85,7 @@ onICE: function() {}, onOfferSDP: function() {} } - }, - options); + }, options); this.mediaData = { SDP: null, @@ -163,9 +163,9 @@ function setCompat() { $.FSRTC.moz = !!navigator.mozGetUserMedia; //navigator.getUserMedia || (navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia); - if (!navigator.getUserMedia) { - navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia; - } + if (!navigator.getUserMedia) { + navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia; + } } function checkCompat() { @@ -307,7 +307,7 @@ return onChannelError(self, e); }, constraints: self.constraints, - iceServers: self.options.iceServers, + iceServers: self.options.iceServers, offerSDP: { type: "offer", sdp: self.remoteSDP @@ -324,9 +324,9 @@ getUserMedia({ constraints: { audio: { - mandatory: this.options.audioParams, - optional: [] - }, + mandatory: this.options.audioParams, + optional: [] + }, video: this.options.useVideo ? { mandatory: this.options.videoParams, optional: [] @@ -371,7 +371,7 @@ return onChannelError(self, e); }, constraints: self.constraints, - iceServers: self.options.iceServers, + iceServers: self.options.iceServers, }); onStreamSuccess(self); @@ -384,9 +384,9 @@ getUserMedia({ constraints: { audio: { - mandatory: this.options.audioParams, - optional: [] - }, + mandatory: this.options.audioParams, + optional: [] + }, video: this.options.useVideo ? { mandatory: this.options.videoParams, optional: [] @@ -398,11 +398,11 @@ }); /* - navigator.getUserMedia({ + navigator.getUserMedia({ video: this.options.useVideo, audio: true - }, onSuccess, onError); -*/ + }, onSuccess, onError); + */ }; @@ -428,34 +428,34 @@ credential: 'homeo' }; - var iceServers = null; + var iceServers = null; - if (options.iceServers) { - var tmp = options.iceServers;; + if (options.iceServers) { + var tmp = options.iceServers;; - if (typeof(tmp) === "boolean") { - tmp = null; - } + if (typeof(tmp) === "boolean") { + tmp = null; + } - if (tmp && typeof(tmp) !== "array") { - console.warn("iceServers must be an array, reverting to default ice servers"); - tmp = null; - } + if (tmp && typeof(tmp) !== "array") { + console.warn("iceServers must be an array, reverting to default ice servers"); + tmp = null; + } iceServers = { - iceServers: tmp || [STUN] + iceServers: tmp || [STUN] }; if (!moz && !tmp) { - if (parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 28) TURN = { + if (parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 28) TURN = { url: 'turn:turn.bistri.com:80', credential: 'homeo', username: 'homeo' - }; + }; - iceServers.iceServers = [STUN]; + iceServers.iceServers = [STUN]; } - } + } var optional = { optional: [] @@ -488,30 +488,30 @@ options.onICESDP(peer.localDescription); //x = 1; /* - x = 1; - peer.createOffer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onICESDP) { - options.onICESDP(sessionDescription); - } - }, onSdpError, constraints); - */ + x = 1; + peer.createOffer(function(sessionDescription) { + sessionDescription.sdp = serializeSdp(sessionDescription.sdp); + peer.setLocalDescription(sessionDescription); + if (options.onICESDP) { + options.onICESDP(sessionDescription); + } + }, onSdpError, constraints); + */ } } else { if (!x && options.onICESDP) { options.onICESDP(peer.localDescription); //x = 1; /* - x = 1; - peer.createAnswer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onICESDP) { - options.onICESDP(sessionDescription); - } - }, onSdpError, constraints); - */ + x = 1; + peer.createAnswer(function(sessionDescription) { + sessionDescription.sdp = serializeSdp(sessionDescription.sdp); + peer.setLocalDescription(sessionDescription); + if (options.onICESDP) { + options.onICESDP(sessionDescription); + } + }, onSdpError, constraints); + */ } } } @@ -730,8 +730,8 @@ channel: channel, sendData: function(message) { if (channel) { - channel.send(message); - } + channel.send(message); + } }, stop: function() { @@ -770,8 +770,8 @@ //video.play(); } if (options.onsuccess) { - options.onsuccess(stream); - } + options.onsuccess(stream); + } media = stream; } diff --git a/html5/verto/js/src/jquery.jsonrpcclient.js b/html5/verto/js/src/jquery.jsonrpcclient.js index be2a7a2620..51244e1672 100644 --- a/html5/verto/js/src/jquery.jsonrpcclient.js +++ b/html5/verto/js/src/jquery.jsonrpcclient.js @@ -62,605 +62,599 @@ * The returned instance must have readyState <= 1, and if less than 1, * react to onopen binding. */ - $.JsonRpcClient = function(options) { - var self = this; - this.options = $.extend({ - ajaxUrl : null, - socketUrl : null, ///< The ws-url for default getSocket. - onmessage : null, ///< Other onmessage-handler. - login : null, /// auth login - passwd : null, /// auth passwd - sessid : null, - getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } - }, options); - - self.ws_cnt = 0; + $.JsonRpcClient = function(options) { + var self = this; + this.options = $.extend({ + ajaxUrl : null, + socketUrl : null, ///< The ws-url for default getSocket. + onmessage : null, ///< Other onmessage-handler. + login : null, /// auth login + passwd : null, /// auth passwd + sessid : null, + getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } + }, options); - // Declare an instance version of the onmessage callback to wrap 'this'. - this.wsOnMessage = function(event) { self._wsOnMessage(event); }; - }; + self.ws_cnt = 0; - /// Holding the WebSocket on default getsocket. - $.JsonRpcClient.prototype._ws_socket = null; - - /// Object : { success_cb: cb, error_cb: cb } - $.JsonRpcClient.prototype._ws_callbacks = {}; - - /// The next JSON-RPC request id. - $.JsonRpcClient.prototype._current_id = 1; - - /** - * @fn call - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - * @param success_cb A callback for successful request. - * @param error_cb A callback for error. - */ - $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { - // Construct the JSON-RPC 2.0 request. - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc : '2.0', - method : method, - params : params, - id : this._current_id++ // Increase the id counter to match request/response + // Declare an instance version of the onmessage callback to wrap 'this'. + this.wsOnMessage = function(event) { self._wsOnMessage(event); }; }; - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } + /// Holding the WebSocket on default getsocket. + $.JsonRpcClient.prototype._ws_socket = null; - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } + /// Object : { success_cb: cb, error_cb: cb } + $.JsonRpcClient.prototype._ws_callbacks = {}; - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request, success_cb, error_cb); - return; - } + /// The next JSON-RPC request id. + $.JsonRpcClient.prototype._current_id = 1; - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false, - - success : function(data) { - if ('error' in data) error_cb(data.error, this); - success_cb(data.result, this); - }, - - // JSON-RPC Server could return non-200 on error - error : function(jqXHR, textStatus, errorThrown) { - try { - var response = $.parseJSON(jqXHR.responseText); - if ('console' in window) console.log(response); - error_cb(response.error, this); - } - catch (err) { - // Perhaps the responseText wasn't really a jsonrpc-error. - error_cb({ error: jqXHR.responseText }, this); - } - } - }); - }; - - /** - * Notify sends a command to the server that won't need a response. In http, there is probably - * an empty response - that will be dropped, but in ws there should be no response at all. - * - * This is very similar to call, but has no id and no handling of callbacks. - * - * @fn notify - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - */ - $.JsonRpcClient.prototype.notify = function(method, params) { + /** + * @fn call + * @memberof $.JsonRpcClient + * + * @param method The method to run on JSON-RPC server. + * @param params The params; an array or object. + * @param success_cb A callback for successful request. + * @param error_cb A callback for error. + */ + $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { // Construct the JSON-RPC 2.0 request. - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc: '2.0', - method: method, - params: params - }; - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false - }); - }; - - /** - * Make a batch-call by using a callback. - * - * The callback will get an object "batch" as only argument. On batch, you can call the methods - * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be - * sent as a batch call then the callback is done. - * - * @fn batch - * @memberof $.JsonRpcClient - * - * @param callback The main function which will get a batch handler to run call and notify on. - * @param all_done_cb A callback function to call after all results have been handled. - * @param error_cb A callback function to call if there is an error from the server. - * Note, that batch calls should always get an overall success, and the - * only error - */ - $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { - var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); - callback(batch); - batch._execute(); - }; - - /** - * The default getSocket handler. - * - * @param onmessage_cb The callback to be bound to onmessage events on the socket. - * - * @fn _getSocket - * @memberof $.JsonRpcClient - */ - - $.JsonRpcClient.prototype.socketReady = function() { - if (this._ws_socket === null || this._ws_socket.readyState > 1) { - return false; - } - - return true; - } - - $.JsonRpcClient.prototype.closeSocket = function() { - if (self.socketReady()) { - this._ws_socket.onclose = function (w) {console.log("Closing Socket")} - this._ws_socket.close(); - } - } - - $.JsonRpcClient.prototype.loginData = function(params) { - self.options.login = params.login; - self.options.passwd = params.passwd; - } - - $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { - var self = this; - - if (self.to) { - clearTimeout(self.to); - } - - if (!self.socketReady()) { - self.authing = false; - - if (self._ws_socket) { - delete self._ws_socket; - } - - // No socket, or dying socket, let's get a new one. - self._ws_socket = new WebSocket(self.options.socketUrl); - - if (self._ws_socket) { - // Set up onmessage handler. - self._ws_socket.onmessage = onmessage_cb; - self._ws_socket.onclose = function (w) { - if (!self.ws_sleep) { - self.ws_sleep = 1000; - } - - if (self.options.onWSClose) { - self.options.onWSClose(self); - } - - console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); - - self.to = setTimeout(function() { - console.log("Attempting Reconnection...."); - self.connectSocket(onmessage_cb); - }, self.ws_sleep); - - self.ws_cnt++; - - if (self.ws_sleep < 3000 && (self.ws_cnt % 10) == 0) { - self.ws_sleep += 1000; - } - } - - // Set up sending of message for when the socket is open. - self._ws_socket.onopen = function() { - if (self.to) { - clearTimeout(self.to); - } - self.ws_sleep = 1000; - self.ws_cnt = 0; - if (self.options.onWSConnect) { - self.options.onWSConnect(self); - } - - var req; - // Send the requests. - while (req = $.JsonRpcClient.q.pop()) { - self._ws_socket.send(req); - } - } - } - } - - return self._ws_socket ? true : false; - } - - $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { - // If there is no ws url set, we don't have a socket. - // Likewise, if there is no window.WebSocket. - if (this.options.socketUrl === null || !("WebSocket" in window)) return null; - - this.connectSocket(onmessage_cb); - - return this._ws_socket; - }; - - /** - * Queue to save messages delivered when websocket is not ready - */ - $.JsonRpcClient.q = []; - - /** - * Internal handler to dispatch a JRON-RPC request through a websocket. - * - * @fn _wsCall - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { - var request_json = $.toJSON(request); - - if (socket.readyState < 1) { - // The websocket is not open yet; we have to set sending of the message in onopen. - self = this; // In closure below, this is set to the WebSocket. Use self instead. - - $.JsonRpcClient.q.push(request_json); - - - } - else { - // We have a socket and it should be ready to send on. - socket.send(request_json); - } - - // Setup callbacks. If there is an id, this is a call and not a notify. - if ('id' in request && typeof success_cb !== 'undefined') { - this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; - } - }; - - /** - * Internal handler for the websocket messages. It determines if the message is a JSON-RPC - * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to - * given external onmessage-handler, if any. - * - * @param event The websocket onmessage-event. - */ - $.JsonRpcClient.prototype._wsOnMessage = function(event) { - // Check if this could be a JSON RPC message. - var response; - try { - response = $.parseJSON(event.data); - - /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. - - if (typeof response === 'object' - && 'jsonrpc' in response - && response.jsonrpc === '2.0') { - - /// @todo Handle bad response (without id). - - // If this is an object with result, it is a response. - if ('result' in response && this._ws_callbacks[response.id]) { - // Get the success callback. - var success_cb = this._ws_callbacks[response.id].success_cb; - -/* - // set the sessid if present - if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { - this.options.sessid = response.result.sessid; - if (this.options.sessid) { - console.log("setting session UUID to: " + this.options.sessid); - } - } -*/ - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with result as parameter. - success_cb(response.result, this); - return; + if (!params) { + params = {}; } - // If this is an object with error, it is an error response. - else if ('error' in response && this._ws_callbacks[response.id]) { - - // Get the error callback. - var error_cb = this._ws_callbacks[response.id].error_cb; - var orig_req = this._ws_callbacks[response.id].request; - - // if this is an auth request, send the credentials and resend the failed request - if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { - self.authing = true; - - this.call("login", { login: self.options.login, passwd: self.options.passwd}, - this._ws_callbacks[response.id].request_obj.method == "login" - ? - function(e) { - self.authing = false; - console.log("logged in"); - delete self._ws_callbacks[response.id]; - - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - } - - : - - function(e) { - self.authing = false; - console.log("logged in, resending request id: " + response.id); - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send(orig_req); - } - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - }, - - function(e) { - console.log("error logging in, request id:", response.id); - delete self._ws_callbacks[response.id]; - error_cb(response.error, this); - if (self.options.onWSLogin) { - self.options.onWSLogin(false, self); - } - } - - ); - return; - } - - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with the error object as parameter. - error_cb(response.error, this); - - return; + if (this.options.sessid) { + params.sessid = this.options.sessid; } - } - } - catch (err) { - // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are - // handled above, and the fallback method is called below. - console.log("ERROR: "+ err); - return; - } - // This is not a JSON-RPC response. Call the fallback message handler, if given. - if (typeof this.options.onmessage === 'function') { - event.eventData = response; - if (!event.eventData) { - event.eventData = {}; - } - - var reply = this.options.onmessage(event); - - if (reply && typeof reply === "object" && event.eventData.id) { - var msg = { - jsonrpc: "2.0", - id: event.eventData.id, - result: reply - }; - - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send($.toJSON(msg)); - } - } - - } - }; - - - /************************************************************************************************ - * Batch object with methods - ************************************************************************************************/ - - /** - * Handling object for batch calls. - */ - $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { - // Array of objects to hold the call and notify requests. Each objects will have the request - // object, and unless it is a notify, success_cb and error_cb. - this._requests = []; - - this.jsonrpcclient = jsonrpcclient; - this.all_done_cb = all_done_cb; - this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; - - }; - - /** - * @sa $.JsonRpcClient.prototype.call - */ - $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params, - id : this.jsonrpcclient._current_id++ // Use the client's id series. - }, - success_cb : success_cb, - error_cb : error_cb - }); - }; - - /** - * @sa $.JsonRpcClient.prototype.notify - */ - $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params - } - }); - }; - - /** - * Executes the batched up calls. - */ - $.JsonRpcClient._batchObject.prototype._execute = function() { - var self = this; - - if (this._requests.length === 0) return; // All done :P - - // Collect all request data and sort handlers by request id. - var batch_request = []; - var handlers = {}; - - // If we have a WebSocket, just send the requests individually like normal calls. - var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); - if (socket !== null) { - for (var i = 0; i < this._requests.length; i++) { - var call = this._requests[i]; - var success_cb = ('success_cb' in call) ? call.success_cb : undefined; - var error_cb = ('error_cb' in call) ? call.error_cb : undefined; - self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); - } - if (typeof all_done_cb === 'function') all_done_cb(result); - return; - } - - for (var i = 0; i < this._requests.length; i++) { - var call = this._requests[i]; - batch_request.push(call.request); - - // If the request has an id, it should handle returns (otherwise it's a notify). - if ('id' in call.request) { - handlers[call.request.id] = { - success_cb : call.success_cb, - error_cb : call.error_cb + var request = { + jsonrpc : '2.0', + method : method, + params : params, + id : this._current_id++ // Increase the id counter to match request/response }; - } - } - var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; - - // No WebSocket, and no HTTP backend? This won't work. - if (self.jsonrpcclient.options.ajaxUrl === null) { - throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; - } - - // Send request - $.ajax({ - url : self.jsonrpcclient.options.ajaxUrl, - data : $.toJSON(batch_request), - dataType : 'json', - cache : false, - type : 'POST', - - // Batch-requests should always return 200 - error : function(jqXHR, textStatus, errorThrown) { - self.error_cb(jqXHR, textStatus, errorThrown); - }, - success : success_cb - }); - }; - - /** - * Internal helper to match the result array from a batch call to their respective callbacks. - * - * @fn _batchCb - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { - for (var i = 0; i < result.length; i++) { - var response = result[i]; - - // Handle error - if ('error' in response) { - if (response.id === null || !(response.id in handlers)) { - // An error on a notify? Just log it to the console. - if ('console' in window) console.log(response); + if (!success_cb) { + success_cb = function(e){console.log("Success: ", e);}; } - else handlers[response.id].error_cb(response.error, this); - } - else { - // Here we should always have a correct id and no error. - if (!(response.id in handlers) && 'console' in window) console.log(response); - else handlers[response.id].success_cb(response.result, this); - } + + if (!error_cb) { + error_cb = function(e){console.log("Error: ", e);}; + } + + // Try making a WebSocket call. + var socket = this.options.getSocket(this.wsOnMessage); + if (socket !== null) { + this._wsCall(socket, request, success_cb, error_cb); + return; + } + + // No WebSocket, and no HTTP backend? This won't work. + if (this.options.ajaxUrl === null) { + throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; + } + + $.ajax({ + type : 'POST', + url : this.options.ajaxUrl, + data : $.toJSON(request), + dataType : 'json', + cache : false, + + success : function(data) { + if ('error' in data) error_cb(data.error, this); + success_cb(data.result, this); + }, + + // JSON-RPC Server could return non-200 on error + error : function(jqXHR, textStatus, errorThrown) { + try { + var response = $.parseJSON(jqXHR.responseText); + + if ('console' in window) console.log(response); + + error_cb(response.error, this); + } catch (err) { + // Perhaps the responseText wasn't really a jsonrpc-error. + error_cb({ error: jqXHR.responseText }, this); + } + } + }); + }; + + /** + * Notify sends a command to the server that won't need a response. In http, there is probably + * an empty response - that will be dropped, but in ws there should be no response at all. + * + * This is very similar to call, but has no id and no handling of callbacks. + * + * @fn notify + * @memberof $.JsonRpcClient + * + * @param method The method to run on JSON-RPC server. + * @param params The params; an array or object. + */ + $.JsonRpcClient.prototype.notify = function(method, params) { + // Construct the JSON-RPC 2.0 request. + + if (this.options.sessid) { + params.sessid = this.options.sessid; + } + + var request = { + jsonrpc: '2.0', + method: method, + params: params + }; + + // Try making a WebSocket call. + var socket = this.options.getSocket(this.wsOnMessage); + if (socket !== null) { + this._wsCall(socket, request); + return; + } + + // No WebSocket, and no HTTP backend? This won't work. + if (this.options.ajaxUrl === null) { + throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; + } + + $.ajax({ + type : 'POST', + url : this.options.ajaxUrl, + data : $.toJSON(request), + dataType : 'json', + cache : false + }); + }; + + /** + * Make a batch-call by using a callback. + * + * The callback will get an object "batch" as only argument. On batch, you can call the methods + * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be + * sent as a batch call then the callback is done. + * + * @fn batch + * @memberof $.JsonRpcClient + * + * @param callback The main function which will get a batch handler to run call and notify on. + * @param all_done_cb A callback function to call after all results have been handled. + * @param error_cb A callback function to call if there is an error from the server. + * Note, that batch calls should always get an overall success, and the + * only error + */ + $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { + var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); + callback(batch); + batch._execute(); + }; + + /** + * The default getSocket handler. + * + * @param onmessage_cb The callback to be bound to onmessage events on the socket. + * + * @fn _getSocket + * @memberof $.JsonRpcClient + */ + + $.JsonRpcClient.prototype.socketReady = function() { + if (this._ws_socket === null || this._ws_socket.readyState > 1) { + return false; + } + + return true; } - if (typeof all_done_cb === 'function') all_done_cb(result); - }; + $.JsonRpcClient.prototype.closeSocket = function() { + if (self.socketReady()) { + this._ws_socket.onclose = function (w) {console.log("Closing Socket")} + this._ws_socket.close(); + } + } + + $.JsonRpcClient.prototype.loginData = function(params) { + self.options.login = params.login; + self.options.passwd = params.passwd; + } + + $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { + var self = this; + + if (self.to) { + clearTimeout(self.to); + } + + if (!self.socketReady()) { + self.authing = false; + + if (self._ws_socket) { + delete self._ws_socket; + } + + // No socket, or dying socket, let's get a new one. + self._ws_socket = new WebSocket(self.options.socketUrl); + + if (self._ws_socket) { + // Set up onmessage handler. + self._ws_socket.onmessage = onmessage_cb; + self._ws_socket.onclose = function (w) { + if (!self.ws_sleep) { + self.ws_sleep = 1000; + } + + if (self.options.onWSClose) { + self.options.onWSClose(self); + } + + console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); + + self.to = setTimeout(function() { + console.log("Attempting Reconnection...."); + self.connectSocket(onmessage_cb); + }, self.ws_sleep); + + self.ws_cnt++; + + if (self.ws_sleep < 3000 && (self.ws_cnt % 10) == 0) { + self.ws_sleep += 1000; + } + } + + // Set up sending of message for when the socket is open. + self._ws_socket.onopen = function() { + if (self.to) { + clearTimeout(self.to); + } + self.ws_sleep = 1000; + self.ws_cnt = 0; + if (self.options.onWSConnect) { + self.options.onWSConnect(self); + } + + var req; + // Send the requests. + while (req = $.JsonRpcClient.q.pop()) { + self._ws_socket.send(req); + } + } + } + } + + return self._ws_socket ? true : false; + } + + $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { + // If there is no ws url set, we don't have a socket. + // Likewise, if there is no window.WebSocket. + if (this.options.socketUrl === null || !("WebSocket" in window)) return null; + + this.connectSocket(onmessage_cb); + + return this._ws_socket; + }; + + /** + * Queue to save messages delivered when websocket is not ready + */ + $.JsonRpcClient.q = []; + + /** + * Internal handler to dispatch a JRON-RPC request through a websocket. + * + * @fn _wsCall + * @memberof $.JsonRpcClient + */ + $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { + var request_json = $.toJSON(request); + + if (socket.readyState < 1) { + // The websocket is not open yet; we have to set sending of the message in onopen. + self = this; // In closure below, this is set to the WebSocket. Use self instead. + $.JsonRpcClient.q.push(request_json); + } else { + // We have a socket and it should be ready to send on. + socket.send(request_json); + } + + // Setup callbacks. If there is an id, this is a call and not a notify. + if ('id' in request && typeof success_cb !== 'undefined') { + this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; + } + }; + + /** + * Internal handler for the websocket messages. It determines if the message is a JSON-RPC + * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to + * given external onmessage-handler, if any. + * + * @param event The websocket onmessage-event. + */ + $.JsonRpcClient.prototype._wsOnMessage = function(event) { + // Check if this could be a JSON RPC message. + var response; + try { + response = $.parseJSON(event.data); + + /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. + + if (typeof response === 'object' + && 'jsonrpc' in response + && response.jsonrpc === '2.0') { + + /// @todo Handle bad response (without id). + + // If this is an object with result, it is a response. + if ('result' in response && this._ws_callbacks[response.id]) { + // Get the success callback. + var success_cb = this._ws_callbacks[response.id].success_cb; + + /* + // set the sessid if present + if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { + this.options.sessid = response.result.sessid; + if (this.options.sessid) { + console.log("setting session UUID to: " + this.options.sessid); + } + } + */ + // Delete the callback from the storage. + delete this._ws_callbacks[response.id]; + + // Run callback with result as parameter. + success_cb(response.result, this); + return; + } else if ('error' in response && this._ws_callbacks[response.id]) { + // If this is an object with error, it is an error response. + + // Get the error callback. + var error_cb = this._ws_callbacks[response.id].error_cb; + var orig_req = this._ws_callbacks[response.id].request; + + // if this is an auth request, send the credentials and resend the failed request + if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { + self.authing = true; + + this.call("login", { login: self.options.login, passwd: self.options.passwd}, + this._ws_callbacks[response.id].request_obj.method == "login" + ? + function(e) { + self.authing = false; + console.log("logged in"); + delete self._ws_callbacks[response.id]; + + if (self.options.onWSLogin) { + self.options.onWSLogin(true, self); + } + } + + : + + function(e) { + self.authing = false; + console.log("logged in, resending request id: " + response.id); + var socket = self.options.getSocket(self.wsOnMessage); + if (socket !== null) { + socket.send(orig_req); + } + if (self.options.onWSLogin) { + self.options.onWSLogin(true, self); + } + }, + + function(e) { + console.log("error logging in, request id:", response.id); + delete self._ws_callbacks[response.id]; + error_cb(response.error, this); + if (self.options.onWSLogin) { + self.options.onWSLogin(false, self); + } + }); + return; + } + + // Delete the callback from the storage. + delete this._ws_callbacks[response.id]; + + // Run callback with the error object as parameter. + error_cb(response.error, this); + return; + } + } + } catch (err) { + // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are + // handled above, and the fallback method is called below. + console.log("ERROR: "+ err); + return; + } + + // This is not a JSON-RPC response. Call the fallback message handler, if given. + if (typeof this.options.onmessage === 'function') { + event.eventData = response; + if (!event.eventData) { + event.eventData = {}; + } + + var reply = this.options.onmessage(event); + + if (reply && typeof reply === "object" && event.eventData.id) { + var msg = { + jsonrpc: "2.0", + id: event.eventData.id, + result: reply + }; + + var socket = self.options.getSocket(self.wsOnMessage); + if (socket !== null) { + socket.send($.toJSON(msg)); + } + } + } + }; + + + /************************************************************************************************ + * Batch object with methods + ************************************************************************************************/ + + /** + * Handling object for batch calls. + */ + $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { + // Array of objects to hold the call and notify requests. Each objects will have the request + // object, and unless it is a notify, success_cb and error_cb. + this._requests = []; + + this.jsonrpcclient = jsonrpcclient; + this.all_done_cb = all_done_cb; + this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; + + }; + + /** + * @sa $.JsonRpcClient.prototype.call + */ + $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { + + if (!params) { + params = {}; + } + + if (this.options.sessid) { + params.sessid = this.options.sessid; + } + + if (!success_cb) { + success_cb = function(e){console.log("Success: ", e);}; + } + + if (!error_cb) { + error_cb = function(e){console.log("Error: ", e);}; + } + + this._requests.push({ + request : { + jsonrpc : '2.0', + method : method, + params : params, + id : this.jsonrpcclient._current_id++ // Use the client's id series. + }, + success_cb : success_cb, + error_cb : error_cb + }); + }; + + /** + * @sa $.JsonRpcClient.prototype.notify + */ + $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { + if (this.options.sessid) { + params.sessid = this.options.sessid; + } + + this._requests.push({ + request : { + jsonrpc : '2.0', + method : method, + params : params + } + }); + }; + + /** + * Executes the batched up calls. + */ + $.JsonRpcClient._batchObject.prototype._execute = function() { + var self = this; + + if (this._requests.length === 0) return; // All done :P + + // Collect all request data and sort handlers by request id. + var batch_request = []; + var handlers = {}; + + // If we have a WebSocket, just send the requests individually like normal calls. + var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); + if (socket !== null) { + for (var i = 0; i < this._requests.length; i++) { + var call = this._requests[i]; + var success_cb = ('success_cb' in call) ? call.success_cb : undefined; + var error_cb = ('error_cb' in call) ? call.error_cb : undefined; + self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); + } + + if (typeof all_done_cb === 'function') all_done_cb(result); + return; + } + + for (var i = 0; i < this._requests.length; i++) { + var call = this._requests[i]; + batch_request.push(call.request); + + // If the request has an id, it should handle returns (otherwise it's a notify). + if ('id' in call.request) { + handlers[call.request.id] = { + success_cb : call.success_cb, + error_cb : call.error_cb + }; + } + } + + var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; + + // No WebSocket, and no HTTP backend? This won't work. + if (self.jsonrpcclient.options.ajaxUrl === null) { + throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; + } + + // Send request + $.ajax({ + url : self.jsonrpcclient.options.ajaxUrl, + data : $.toJSON(batch_request), + dataType : 'json', + cache : false, + type : 'POST', + + // Batch-requests should always return 200 + error : function(jqXHR, textStatus, errorThrown) { + self.error_cb(jqXHR, textStatus, errorThrown); + }, + success : success_cb + }); + }; + + /** + * Internal helper to match the result array from a batch call to their respective callbacks. + * + * @fn _batchCb + * @memberof $.JsonRpcClient + */ + $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { + for (var i = 0; i < result.length; i++) { + var response = result[i]; + + // Handle error + if ('error' in response) { + if (response.id === null || !(response.id in handlers)) { + // An error on a notify? Just log it to the console. + if ('console' in window) console.log(response); + } else { + handlers[response.id].error_cb(response.error, this); + } + } else { + // Here we should always have a correct id and no error. + if (!(response.id in handlers) && 'console' in window) { + console.log(response); + } else { + handlers[response.id].success_cb(response.result, this); + } + } + } + + if (typeof all_done_cb === 'function') all_done_cb(result); + }; })(jQuery); diff --git a/html5/verto/js/src/jquery.verto.js b/html5/verto/js/src/jquery.verto.js index a9f028d6d9..4beedc6548 100644 --- a/html5/verto/js/src/jquery.verto.js +++ b/html5/verto/js/src/jquery.verto.js @@ -73,10 +73,9 @@ tag: null, videoParams: {}, audioParams: {}, - iceServers: false, + iceServers: false, ringSleep: 6000 - }, - options); + }, options); verto.sessid = $.cookie('verto_session_uuid') || generateGUID(); $.cookie('verto_session_uuid', verto.sessid, { @@ -84,9 +83,7 @@ }); verto.dialogs = {}; - verto.callbacks = callbacks || {}; - verto.eventSUBS = {}; verto.rpcClient = new $.JsonRpcClient({ @@ -123,7 +120,6 @@ $.verto.prototype.iceServers = function(on) { var verto = this; - verto.options.iceServers = on; }; @@ -172,7 +168,7 @@ $.verto.prototype.processReply = function(method, success, e) { var verto = this; - var i; + var i; //console.log("Response: " + method, success, e); @@ -228,7 +224,7 @@ } var SERNO = 1; - + function do_subscribe(verto, channel, subChannels, sparams) { var params = sparams || {}; @@ -298,7 +294,7 @@ $.verto.prototype.unsubscribe = function(handle) { var verto = this; - var i; + var i; if (!handle) { for (i in verto.eventSUBS) { @@ -309,7 +305,7 @@ } else { var unsubChannels = {}; var sendChannels = []; - var channel; + var channel; if (typeof(handle) == "string") { delete verto.eventSUBS[handle]; @@ -368,13 +364,13 @@ $.verto.prototype.purge = function(callID) { var verto = this; var x = 0; - var i; + var i; for (i in verto.dialogs) { if (!x) { console.log("purging dialogs"); } - x++; + x++; verto.dialogs[i].setState($.verto.enum.state.purge); } @@ -423,10 +419,10 @@ $.verto.prototype.handleMessage = function(data) { var verto = this; - if (!(data && data.method)) { - console.error("Invalid Data", data); - return; - } + if (!(data && data.method)) { + console.error("Invalid Data", data); + return; + } if (data.params.callID) { var dialog = verto.dialogs[data.params.callID]; @@ -467,10 +463,10 @@ data.params.useStereo = true; } - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); + dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); dialog.setState($.verto.enum.state.recovering); - break; + break; case 'verto.invite': if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { @@ -510,10 +506,10 @@ } } - if (!list && key && key === verto.sessid) { - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); - } + if (!list && key && key === verto.sessid) { + if (verto.callbacks.onMessage) { + verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); + } } else if (!list && key && verto.dialogs[key]) { verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params); } else if (!list) { @@ -944,21 +940,21 @@ la.verto.unsubscribe(binding); }; - la.sendCommand = function(cmd, obj) { + la.sendCommand = function(cmd, obj) { var self = la; - self.broadcast(self.context, { - liveArray: { + self.broadcast(self.context, { + liveArray: { command: cmd, context: self.context, name: self.name, obj: obj } - }); - }; + }); + }; la.bootstrap = function(obj) { var self = la; - la.sendCommand("bootstrap", obj); + la.sendCommand("bootstrap", obj); //self.heartbeat(); }; @@ -1128,7 +1124,7 @@ } else { obj.errs = 0; } - + }; la.onChange(la, { @@ -1138,211 +1134,205 @@ }; var CONFMAN_SERNO = 1; - + $.verto.confMan = function(verto, params) { - var confMan = this; - conf + var confMan = this; + conf confMan.params = $.extend({ - tableID: null, - statusID: null, - mainModID: null, - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, - params); + tableID: null, + statusID: null, + mainModID: null, + dialog: null, + hasVid: false, + laData: null, + onBroadcast: null, + onLaChange: null, + onLaRow: null + }, params); - confMan.verto = verto; - confMan.serno = CONFMAN_SERNO++; + confMan.verto = verto; + confMan.serno = CONFMAN_SERNO++; - function genMainMod(jq) { - var play_id = "play_" + confMan.serno; - var stop_id = "stop_" + confMan.serno; - var recording_id = "recording_" + confMan.serno; - var rec_stop_id = "recording_stop" + confMan.serno; - var div_id = "confman_" + confMan.serno; + function genMainMod(jq) { + var play_id = "play_" + confMan.serno; + var stop_id = "stop_" + confMan.serno; + var recording_id = "recording_" + confMan.serno; + var rec_stop_id = "recording_stop" + confMan.serno; + var div_id = "confman_" + confMan.serno; - var html = "

" + - "" + - "" + - "" + - "" + var html = "

" + + "" + + "" + + "" + + "" - + "

"; + + "

"; - jq.html(html); + jq.html(html); - $("#" + play_id).click(function() { - var file = prompt("Please enter file name", ""); - confMan.modCommand("play", null, file); - }); + $("#" + play_id).click(function() { + var file = prompt("Please enter file name", ""); + confMan.modCommand("play", null, file); + }); - $("#" + stop_id).click(function() { - confMan.modCommand("stop", null, "all"); - }); + $("#" + stop_id).click(function() { + confMan.modCommand("stop", null, "all"); + }); - $("#" + recording_id).click(function() { - var file = prompt("Please enter file name", ""); - confMan.modCommand("recording", null, ["start", file]); - }); + $("#" + recording_id).click(function() { + var file = prompt("Please enter file name", ""); + confMan.modCommand("recording", null, ["start", file]); + }); - $("#" + rec_stop_id).click(function() { - confMan.modCommand("recording", null, ["stop", "all"]); - }); + $("#" + rec_stop_id).click(function() { + confMan.modCommand("recording", null, ["stop", "all"]); + }); - } + } - function genControls(jq, rowid) { - var x = parseInt(rowid); - var kick_id = "kick_" + x; - var tmute_id = "tmute_" + x; - var box_id = "box_" + x; - var volup_id = "volume_in_up" + x; - var voldn_id = "volume_in_dn" + x; - var transfer_id = "transfer" + x; - - - var html = "
" + - "" + - "" + - "" + - "" + - "" + - "
" - ; - - jq.html(html); - - if (!jq.data("mouse")) { - $("#" + box_id).hide(); - } - - jq.mouseover(function(e) { - jq.data({"mouse": true}); - $("#" + box_id).show(); - }); - - jq.mouseout(function(e) { - jq.data({"mouse": false}); - $("#" + box_id).hide(); - }); - - $("#" + transfer_id).click(function() { - var xten = prompt("Enter Extension"); - confMan.modCommand("transfer", x, xten); - }); - - $("#" + kick_id).click(function() { - confMan.modCommand("kick", x); - }); - - $("#" + tmute_id).click(function() { - confMan.modCommand("tmute", x); - }); - - $("#" + volup_id).click(function() { - confMan.modCommand("volume_in", x, "up"); - }); - - $("#" + voldn_id).click(function() { - confMan.modCommand("volume_in", x, "down"); - }); - - return html; - } + function genControls(jq, rowid) { + var x = parseInt(rowid); + var kick_id = "kick_" + x; + var tmute_id = "tmute_" + x; + var box_id = "box_" + x; + var volup_id = "volume_in_up" + x; + var voldn_id = "volume_in_dn" + x; + var transfer_id = "transfer" + x; + var html = "
" + + "" + + "" + + "" + + "" + + "" + + "
" + ; + + jq.html(html); + + if (!jq.data("mouse")) { + $("#" + box_id).hide(); + } + + jq.mouseover(function(e) { + jq.data({"mouse": true}); + $("#" + box_id).show(); + }); + + jq.mouseout(function(e) { + jq.data({"mouse": false}); + $("#" + box_id).hide(); + }); + + $("#" + transfer_id).click(function() { + var xten = prompt("Enter Extension"); + confMan.modCommand("transfer", x, xten); + }); + + $("#" + kick_id).click(function() { + confMan.modCommand("kick", x); + }); + + $("#" + tmute_id).click(function() { + confMan.modCommand("tmute", x); + }); + + $("#" + volup_id).click(function() { + confMan.modCommand("volume_in", x, "up"); + }); + + $("#" + voldn_id).click(function() { + confMan.modCommand("volume_in", x, "down"); + }); + + return html; + } + + var atitle = ""; + var awidth = 0; - var atitle = ""; - var awidth = 0; - //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px"); - - if (confMan.params.laData.role === "moderator") { - atitle = "Action"; - awidth = 200; - - if (confMan.params.mainModID) { - genMainMod($(confMan.params.mainModID)); - $(confMan.params.displayID).html("Moderator Controls Ready

") - } else { - $(confMan.params.mainModID).html(""); - } - verto.subscribe(confMan.params.laData.modChannel, { - handler: function(v, e) { - console.error("MODDATA:", e.data); - if (confMan.params.onBroadcast) { - confMan.params.onBroadcast(verto, confMan, e.data); - } - if (!confMan.destroyed && confMan.params.displayID) { - $(confMan.params.displayID).html(e.data.response + "

"); - if (confMan.lastTimeout) { - clearTimeout(confMan.lastTimeout); - confMan.lastTimeout = 0; - } - confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

")}, 4000); - } + if (confMan.params.laData.role === "moderator") { + atitle = "Action"; + awidth = 200; - } - }); - - } - - var row_callback = null; + if (confMan.params.mainModID) { + genMainMod($(confMan.params.mainModID)); + $(confMan.params.displayID).html("Moderator Controls Ready

") + } else { + $(confMan.params.mainModID).html(""); + } - if (confMan.params.laData.role === "moderator") { - row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { - if (!aData[5]) { - var $row = $('td:eq(5)', nRow); - genControls($row, aData); - - if (confMan.params.onLaRow) { - confMan.params.onLaRow(verto, confMan, $row, aData); - } + verto.subscribe(confMan.params.laData.modChannel, { + handler: function(v, e) { + console.error("MODDATA:", e.data); + if (confMan.params.onBroadcast) { + confMan.params.onBroadcast(verto, confMan, e.data); + } + if (!confMan.destroyed && confMan.params.displayID) { + $(confMan.params.displayID).html(e.data.response + "

"); + if (confMan.lastTimeout) { + clearTimeout(confMan.lastTimeout); + confMan.lastTimeout = 0; + } + confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

")}, 4000); + } + } + }); + } + + var row_callback = null; + + if (confMan.params.laData.role === "moderator") { + row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { + if (!aData[5]) { + var $row = $('td:eq(5)', nRow); + genControls($row, aData); + + if (confMan.params.onLaRow) { + confMan.params.onLaRow(verto, confMan, $row, aData); + } + } + }; + } - } - }; - } - confMan.lt = new $.verto.liveTable(verto, confMan.params.laData.laChannel, confMan.params.laData.laName, $(confMan.params.tableID), { subParams: { callID: confMan.params.dialog ? confMan.params.dialog.callID : null }, - - + "onChange": function(obj, args) { $(confMan.params.statusID).text("Conference Members: " + " (" + obj.arrayLen() + " Total)"); - if (confMan.params.onLaChange) { - confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); - } + if (confMan.params.onLaChange) { + confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); + } }, "aaData": [], - "aoColumns": [{ - "sTitle": "ID" - }, - { - "sTitle": "Number" - }, - { - "sTitle": "Name" - }, - { - "sTitle": "Codec" - }, - { - "sTitle": "Status", - "sWidth": confMan.params.hasVid ? "300px" : "150px" - }, - { - "sTitle": atitle, - "sWidth": awidth, - - }], + "aoColumns": [ + { + "sTitle": "ID" + }, + { + "sTitle": "Number" + }, + { + "sTitle": "Name" + }, + { + "sTitle": "Codec" + }, + { + "sTitle": "Status", + "sWidth": confMan.params.hasVid ? "300px" : "150px" + }, + { + "sTitle": atitle, + "sWidth": awidth, + } + ], "bAutoWidth": true, "bDestroy": true, "bSort": false, @@ -1356,41 +1346,41 @@ "sEmptyTable": "The Conference is Empty....." }, - "fnRowCallback": row_callback + "fnRowCallback": row_callback }); } $.verto.confMan.prototype.modCommand = function(cmd, id, value) { - var confMan = this; - - confMan.verto.sendMethod("verto.broadcast", { - "eventChannel": confMan.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); + var confMan = this; + + confMan.verto.sendMethod("verto.broadcast", { + "eventChannel": confMan.params.laData.modChannel, + "data": { + "application": "conf-control", + "command": cmd, + "id": id, + "value": value + } + }); } $.verto.confMan.prototype.destroy = function() { - var confMan = this; + var confMan = this; - confMan.destroyed = true; + confMan.destroyed = true; - if (confMan.lt) { - confMan.lt.destroy(); - } + if (confMan.lt) { + confMan.lt.destroy(); + } - if (confMan.params.laData.modChannel) { - confMan.verto.unsubscribe(confMan.params.laData.modChannel); - } + if (confMan.params.laData.modChannel) { + confMan.verto.unsubscribe(confMan.params.laData.modChannel); + } - if (confMan.params.mainModID) { - $(confMan.params.mainModID).html(""); - } + if (confMan.params.mainModID) { + $(confMan.params.mainModID).html(""); + } } $.verto.dialog = function(direction, verto, params) { @@ -1400,9 +1390,8 @@ useVideo: verto.options.useVideo, useStereo: verto.options.useStereo, tag: verto.options.tag, - login: verto.options.login - }, - params); + login: verto.options.login + }, params); dialog.verto = verto; dialog.direction = direction; @@ -1431,13 +1420,13 @@ var RTCcallbacks = {}; if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.params.display_direction === "outbound") { - dialog.params.remote_caller_id_name = dialog.params.caller_id_name; - dialog.params.remote_caller_id_number = dialog.params.caller_id_number; - } else { - dialog.params.remote_caller_id_name = dialog.params.callee_id_name; - dialog.params.remote_caller_id_number = dialog.params.callee_id_number; - } + if (dialog.params.display_direction === "outbound") { + dialog.params.remote_caller_id_name = dialog.params.caller_id_name; + dialog.params.remote_caller_id_number = dialog.params.caller_id_number; + } else { + dialog.params.remote_caller_id_name = dialog.params.callee_id_name; + dialog.params.remote_caller_id_number = dialog.params.callee_id_number; + } if (!dialog.params.remote_caller_id_name) { dialog.params.remote_caller_id_name = "Nobody"; @@ -1469,14 +1458,13 @@ dialog.sendMethod("verto.invite", { sdp: rtc.mediaData.SDP }); - } else { //answer + } else { //answer dialog.setState($.verto.enum.state.answering); dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", { sdp: dialog.rtc.mediaData.SDP }); } - }; RTCcallbacks.onICE = function(rtc) { @@ -1485,7 +1473,6 @@ console.log("offer", rtc.mediaData.candidate); return; } - }; RTCcallbacks.onError = function(e) { @@ -1500,7 +1487,7 @@ useStereo: dialog.params.useStereo, videoParams: verto.options.videoParams, audioParams: verto.options.audioParams, - iceServers: verto.options.iceServers + iceServers: verto.options.iceServers }); dialog.rtc.verto = dialog.verto; @@ -1570,14 +1557,14 @@ dialog.lastState = dialog.state; dialog.state = state; - - if (!dialog.causeCode) { - dialog.causeCode = 16; - } - if (!dialog.cause) { - dialog.cause = "NORMAL CLEARING"; - } + if (!dialog.causeCode) { + dialog.causeCode = 16; + } + + if (!dialog.cause) { + dialog.cause = "NORMAL CLEARING"; + } if (dialog.callbacks.onDialogState) { dialog.callbacks.onDialogState(this); @@ -1585,12 +1572,12 @@ switch (dialog.state) { case $.verto.enum.state.trying: - setTimeout(function() { + setTimeout(function() { if (dialog.state == $.verto.enum.state.trying) { - dialog.setState($.verto.enum.state.hangup); + dialog.setState($.verto.enum.state.hangup); } }, 30000); - break; + break; case $.verto.enum.state.purge: dialog.setState($.verto.enum.state.destroy); break; @@ -1603,7 +1590,7 @@ dialog.setState($.verto.enum.state.destroy); break; case $.verto.enum.state.destroy: - delete dialog.verto.dialogs[dialog.callID]; + delete dialog.verto.dialogs[dialog.callID]; dialog.rtc.stop(); break; } @@ -1664,15 +1651,15 @@ $.verto.dialog.prototype.hangup = function(params) { var dialog = this; - if (params) { - if (params.causeCode) { - dialog.causeCode = params.causeCode; - } - - if (params.cause) { - dialog.cause = params.cause; - } - } + if (params) { + if (params.causeCode) { + dialog.causeCode = params.causeCode; + } + + if (params.cause) { + dialog.cause = params.cause; + } + } if (dialog.state.val > $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) { dialog.setState($.verto.enum.state.hangup); @@ -1784,7 +1771,7 @@ var dialog = this; var err = 0; - msg.from = dialog.params.login; + msg.from = dialog.params.login; if (!msg.to) { console.error("Missing To"); @@ -1815,8 +1802,8 @@ if (params.useVideo) { dialog.useVideo(true); } - dialog.params.callee_id_name = params.callee_id_name; - dialog.params.callee_id_number = params.callee_id_number; + dialog.params.callee_id_name = params.callee_id_name; + dialog.params.callee_id_number = params.callee_id_number; } dialog.rtc.createAnswer(dialog.params.sdp); dialog.answered = true; @@ -1826,7 +1813,7 @@ $.verto.dialog.prototype.handleAnswer = function(params) { var dialog = this; - dialog.gotAnswer = true; + dialog.gotAnswer = true; if (dialog.state.val >= $.verto.enum.state.active.val) { return; @@ -1835,20 +1822,19 @@ if (dialog.state.val >= $.verto.enum.state.early.val) { dialog.setState($.verto.enum.state.active); } else { - if (dialog.gotEarly) { - console.log("Dialog " + dialog.callID + "Got answer while still establishing early media, delaying..."); - } else { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.rtc.answer(params.sdp, function() { + if (dialog.gotEarly) { + console.log("Dialog " + dialog.callID + "Got answer while still establishing early media, delaying..."); + } else { + console.log("Dialog " + dialog.callID + "Answering Channel"); + dialog.rtc.answer(params.sdp, function() { dialog.setState($.verto.enum.state.active); - }, - function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); + }, function(e) { + console.error(e); + dialog.hangup(); + }); + console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); } - } + } }; $.verto.dialog.prototype.cidString = function(enc) { @@ -1891,18 +1877,17 @@ return; } - dialog.gotEarly = true; - - dialog.rtc.answer(params.sdp, function() { - console.log("Dialog " + dialog.callID + "Establishing early media"); - dialog.setState($.verto.enum.state.early); + dialog.gotEarly = true; - if (dialog.gotAnswer) { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.setState($.verto.enum.state.active); - } - }, - function(e) { + dialog.rtc.answer(params.sdp, function() { + console.log("Dialog " + dialog.callID + "Establishing early media"); + dialog.setState($.verto.enum.state.early); + + if (dialog.gotAnswer) { + console.log("Dialog " + dialog.callID + "Answering Channel"); + dialog.setState($.verto.enum.state.active); + } + }, function(e) { console.error(e); dialog.hangup(); }); @@ -1926,7 +1911,7 @@ $.verto.enum.states = Object.freeze({ new: { requesting: 1, - recovering: 1, + recovering: 1, ringing: 1, destroy: 1, answering: 1 @@ -1953,8 +1938,8 @@ hangup: 1 }, active: { - answering: 1, - requesting: 1, + answering: 1, + requesting: 1, hangup: 1, held: 1 }, From a279bf38af9ee37fff4b3829f3ce70c37c13182a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 11 Nov 2014 12:56:40 -0600 Subject: [PATCH 63/91] FS-6890 #comment please test --- src/mod/endpoints/mod_sofia/mod_sofia.c | 8 ++++---- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 7ccfe9ee74..bd9b362b54 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1559,14 +1559,14 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (ok) { char *headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_INFO_HEADER_PREFIX); const char *pl = NULL; - uint32_t callsequence; nua_handle_t *nh; sip_cseq_t *cseq = NULL; const char *uri = NULL; char *to, *from; char *contact; const char *invite_contact_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_contact_params"); - + + if (!zstr(msg->string_array_arg[2])) { pl = msg->string_array_arg[2]; } @@ -1581,14 +1581,14 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi contact = tech_pvt->reply_contact; } - callsequence = sofia_presence_get_cseq(tech_pvt->profile); + nh = nua_handle(tech_pvt->profile->nua, NULL, NUTAG_URL(uri), TAG_IF(contact, SIPTAG_CONTACT_STR(contact)), TAG_END()); - cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + cseq = sip_cseq_create(nh->nh_home, ++tech_pvt->info_cseq, SIP_METHOD_INFO); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); if (tech_pvt->sent_last_invite || !tech_pvt->recv_invites) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 52307a2800..c20a4e7a06 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -811,6 +811,7 @@ struct private_object { uint32_t keepalive; uint32_t sent_invites; uint32_t recv_invites; + uint32_t info_cseq; uint8_t sent_last_invite; }; From f175c7118879b882343da9b6f15075161923fcca Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 11 Nov 2014 13:25:47 -0600 Subject: [PATCH 64/91] FS-6805 add support for logging full timestamps with dialplan, defaults to old behavior unless requested --- conf/curl/autoload_configs/switch.conf.xml | 2 + .../autoload_configs/switch.conf.xml | 2 + conf/rayo/autoload_configs/switch.conf.xml | 3 + conf/sbc/autoload_configs/switch.conf.xml | 2 + conf/vanilla/autoload_configs/switch.conf.xml | 3 + src/include/switch_types.h | 3 +- .../mod_dialplan_xml/mod_dialplan_xml.c | 113 +++++++++++++++--- src/switch_core.c | 6 + src/switch_core_session.c | 7 +- 9 files changed, 124 insertions(+), 17 deletions(-) diff --git a/conf/curl/autoload_configs/switch.conf.xml b/conf/curl/autoload_configs/switch.conf.xml index 09d1c07393..bb9af4f3fa 100644 --- a/conf/curl/autoload_configs/switch.conf.xml +++ b/conf/curl/autoload_configs/switch.conf.xml @@ -18,6 +18,8 @@ + + diff --git a/conf/insideout/autoload_configs/switch.conf.xml b/conf/insideout/autoload_configs/switch.conf.xml index 09d1c07393..bb9af4f3fa 100644 --- a/conf/insideout/autoload_configs/switch.conf.xml +++ b/conf/insideout/autoload_configs/switch.conf.xml @@ -18,6 +18,8 @@ + + diff --git a/conf/rayo/autoload_configs/switch.conf.xml b/conf/rayo/autoload_configs/switch.conf.xml index ddf41f8996..e618069ab2 100644 --- a/conf/rayo/autoload_configs/switch.conf.xml +++ b/conf/rayo/autoload_configs/switch.conf.xml @@ -24,6 +24,9 @@ + + + diff --git a/conf/sbc/autoload_configs/switch.conf.xml b/conf/sbc/autoload_configs/switch.conf.xml index 09d1c07393..bb9af4f3fa 100644 --- a/conf/sbc/autoload_configs/switch.conf.xml +++ b/conf/sbc/autoload_configs/switch.conf.xml @@ -18,6 +18,8 @@ + + diff --git a/conf/vanilla/autoload_configs/switch.conf.xml b/conf/vanilla/autoload_configs/switch.conf.xml index d508ad1844..102a2a7f1e 100644 --- a/conf/vanilla/autoload_configs/switch.conf.xml +++ b/conf/vanilla/autoload_configs/switch.conf.xml @@ -24,6 +24,9 @@ + + + diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 6b9f303f47..69602de419 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -361,7 +361,8 @@ typedef enum { SCF_CORE_NON_SQLITE_DB_REQ = (1 << 20), SCF_DEBUG_SQL = (1 << 21), SCF_API_EXPANSION = (1 << 22), - SCF_SESSION_THREAD_POOL = (1 << 23) + SCF_SESSION_THREAD_POOL = (1 << 23), + SCF_DIALPLAN_TIMESTAMPS = (1 << 24) } switch_core_flag_enum_t; typedef uint32_t switch_core_flag_t; diff --git a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c index b5ff5e63a6..71908b36f0 100644 --- a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c +++ b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c @@ -148,10 +148,15 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * req_nest = switch_true(req_nesta); } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: Processing recursive conditions level:%d [%s] require-nested=%s\n", space, recur, exten_name, req_nest ? "TRUE" : "FALSE"); - + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: Processing recursive conditions level:%d [%s] require-nested=%s\n", space, + recur, exten_name, req_nest ? "TRUE" : "FALSE"); + } } else { if ((tmp = switch_xml_attr(xexten, "name"))) { exten_name = tmp; @@ -204,15 +209,27 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } if (time_match == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/Time Match (PASS) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/Time Match (PASS) [%s] break=%s\n", space, + switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } anti_action = SWITCH_FALSE; proceed = 1; } else if (time_match == 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", space, + switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } } @@ -230,14 +247,26 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * time_match = switch_xml_std_datetime_check(xregex, tzoff ? &offset : NULL, tzname_); if (time_match == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/Time Match (PASS) [%s]\n", space, switch_channel_get_name(channel), exten_name); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/Time Match (PASS) [%s]\n", space, + switch_channel_get_name(channel), exten_name); + } anti_action = SWITCH_FALSE; } else if (time_match == 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/TimeMatch (FAIL) [%s]\n", space, switch_channel_get_name(channel), exten_name); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/TimeMatch (FAIL) [%s]\n", space, + switch_channel_get_name(channel), exten_name); + } } @@ -273,22 +302,40 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } pass++; if (!all && !xor) break; } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } fail++; if (all && !xor) break; } } else if (time_match == -1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Absolute Condition [%s] match=%s\n", space, switch_channel_get_name(channel), exten_name, all ? "all" : "any"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Absolute Condition [%s] match=%s\n", space, + switch_channel_get_name(channel), exten_name, all ? "all" : "any"); + } pass++; proceed = 1; if (!all && !xor) break; @@ -367,19 +414,37 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } anti_action = SWITCH_FALSE; } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } } } else if (time_match == -1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Absolute Condition [%s]\n", space, switch_channel_get_name(channel), exten_name); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Absolute Condition [%s]\n", space, + switch_channel_get_name(channel), exten_name); + } anti_action = SWITCH_FALSE; proceed = 1; } @@ -427,9 +492,15 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } for (;loop_count > 0; loop_count--) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s ANTI-Action %s(%s) %s\n", space, switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s ANTI-Action %s(%s) %s\n", space, + switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); + } if (xinline) { exec_app(session, application, data); @@ -488,9 +559,15 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * loop_count = atoi(loop); } for (;loop_count > 0; loop_count--) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Action %s(%s) %s\n", space, switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Action %s(%s) %s\n", space, + switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); + } if (xinline) { exec_app(session, application, app_data); @@ -607,9 +684,15 @@ SWITCH_STANDARD_DIALPLAN(dialplan_hunt) exten_name = "UNKNOWN"; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Dialplan: %s parsing [%s->%s] continue=%s\n", switch_channel_get_name(channel), caller_profile->context, exten_name, cont ? cont : "false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "Dialplan: %s parsing [%s->%s] continue=%s\n", + switch_channel_get_name(channel), caller_profile->context, exten_name, cont ? cont : "false"); + } proceed = parse_exten(session, caller_profile, xexten, &extension, exten_name, 0); diff --git a/src/switch_core.c b/src/switch_core.c index cbf3175679..bccaadc2b2 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1980,6 +1980,12 @@ static void switch_load_core_config(const char *file) runtime.core_db_inner_pre_trans_execute = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "core-db-inner-post-trans-execute") && !zstr(val)) { runtime.core_db_inner_post_trans_execute = switch_core_strdup(runtime.memory_pool, val); + } else if (!strcasecmp(var, "dialplan-timestamps")) { + if (switch_true(val)) { + switch_set_flag((&runtime), SCF_DIALPLAN_TIMESTAMPS); + } else { + switch_clear_flag((&runtime), SCF_DIALPLAN_TIMESTAMPS); + } } else if (!strcasecmp(var, "mailer-app") && !zstr(val)) { runtime.mailer_app = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "mailer-app-args") && val) { diff --git a/src/switch_core_session.c b/src/switch_core_session.c index c5f1eaa718..a3728234e1 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -2811,8 +2811,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", + switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); + } if ((var = switch_channel_get_variable(session->channel, "verbose_presence")) && switch_true(var)) { char *myarg = NULL; From 0c68bb6d89018d12e68a9d8c524e229fc25ef25f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 11 Nov 2014 13:37:46 -0600 Subject: [PATCH 65/91] FS-6957 #resolve --- src/mod/applications/mod_conference/mod_conference.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 38b2f893d4..c3885dbe79 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -6147,7 +6147,7 @@ static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_str switch_clear_flag_locked(member, MFLAG_CAN_SPEAK); switch_clear_flag_locked(member, MFLAG_TALKING); - if (member->session && !switch_test_flag(member, MFLAG_INDICATE_MUTE)) { + if (member->session && !switch_test_flag(member, MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member->session, SWITCH_TRUE); } @@ -6245,7 +6245,7 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s switch_set_flag_locked(member, MFLAG_CAN_SPEAK); - if (member->session && !switch_test_flag(member, MFLAG_INDICATE_MUTE)) { + if (member->session && !switch_test_flag(member, MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member->session, SWITCH_FALSE); } @@ -8761,6 +8761,8 @@ static void set_mflags(const char *flags, member_flag_t *f) char *argv[10] = { 0 }; int i, argc = 0; + *f |= MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR; + for (p = dup; p && *p; p++) { if (*p == ',') { *p = '|'; @@ -9296,7 +9298,7 @@ SWITCH_STANDARD_APP(conference_function) set_mflags(flags_str,&mflags); if (!(mflags & MFLAG_CAN_SPEAK)) { - if (!(mflags & MFLAG_INDICATE_MUTE)) { + if (!(mflags & MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(session, SWITCH_TRUE); } } @@ -9601,7 +9603,7 @@ SWITCH_STANDARD_APP(conference_function) mflags |= MFLAG_RUNNING; if (!(mflags & MFLAG_CAN_SPEAK)) { - if (!(mflags & MFLAG_INDICATE_MUTE)) { + if (!(mflags & MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member.session, SWITCH_TRUE); } } @@ -10329,8 +10331,6 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound); } - conference->mflags = MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR; - if (!zstr(moh_sound) && switch_is_moh(moh_sound)) { conference->moh_sound = switch_core_strdup(conference->pool, moh_sound); } From 33d37ce0f55abe00d7e27fed904db019ebbf4590 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 11 Nov 2014 14:51:19 -0600 Subject: [PATCH 66/91] PLIV-13 #resolve --- src/mod/applications/mod_httapi/mod_httapi.c | 114 +++++++++++++++---- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index fede125ffb..4dade0f959 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -155,6 +155,7 @@ static struct { int not_found_expires; int cache_ttl; int abs_cache_ttl; + client_profile_t *profile; } globals; @@ -1624,10 +1625,15 @@ static switch_status_t httapi_sync(client_t *client) if (client->profile->ssl_version) { if (!strcasecmp(client->profile->ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); - } else if (!strcasecmp(client->profile->ssl_version, "TLSv1")) { - switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.1")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.2")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); } + } else { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); } + if (client->profile->ssl_cacert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, client->profile->ssl_cacert_file); @@ -2150,6 +2156,8 @@ static switch_status_t do_config(void) profile->name = switch_core_strdup(globals.pool, bname); + if (!globals.profile) globals.profile = profile; + switch_core_hash_insert(globals.profile_hash, bname, profile); x++; @@ -2429,16 +2437,33 @@ static size_t save_file_callback(void *ptr, size_t size, size_t nmemb, void *dat static switch_status_t fetch_cache_data(http_file_context_t *context, const char *url, switch_event_t **headers, const char *save_path) { switch_CURL *curl_handle = NULL; - client_t client = { 0 }; + client_t *client = NULL; long code; switch_status_t status = SWITCH_STATUS_FALSE; char *dup_creds = NULL, *dynamic_url = NULL, *use_url; char *ua = NULL; + const char *profile_name = NULL; + + + if (context->url_params) { + profile_name = switch_event_get_header(context->url_params, "profile_name"); + } + + if (zstr(profile_name)) { + if (globals.profile) profile_name = globals.profile->name; + } + + if (zstr(profile_name)) { + profile_name = "default"; + } + + if (!(client = client_create(NULL, profile_name, NULL))) { + return SWITCH_STATUS_FALSE; + } - client.fd = -1; if (save_path) { - if ((client.fd = open(save_path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) { + if ((client->fd = open(save_path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) { return SWITCH_STATUS_FALSE; } } @@ -2478,31 +2503,80 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); - switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); - switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); + if (!strncasecmp(url, "https", 5)) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); + } - client.max_bytes = HTTAPI_MAX_FILE_BYTES; + client->max_bytes = HTTAPI_MAX_FILE_BYTES; switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url); + if (client->profile->timeout) { + switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, client->profile->timeout); + } + + if (client->profile->ssl_cert_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, client->profile->ssl_cert_file); + } + + if (client->profile->ssl_key_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, client->profile->ssl_key_file); + } + + if (client->profile->ssl_key_password) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, client->profile->ssl_key_password); + } + + if (client->profile->ssl_version) { + if (!strcasecmp(client->profile->ssl_version, "SSLv3")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.1")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.2")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + } + } else { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + } + + if (client->profile->ssl_cacert_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, client->profile->ssl_cacert_file); + } + + if (client->profile->enable_ssl_verifyhost) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + } + + if (client->profile->cookie_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_COOKIEJAR, client->profile->cookie_file); + switch_curl_easy_setopt(curl_handle, CURLOPT_COOKIEFILE, client->profile->cookie_file); + } else { + switch_curl_easy_setopt(curl_handle, CURLOPT_COOKIE, ""); + } + + if (client->profile->bind_local) { + curl_easy_setopt(curl_handle, CURLOPT_INTERFACE, client->profile->bind_local); + } + if (save_path) { switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, save_file_callback); - switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &client); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) client); } else { switch_curl_easy_setopt(curl_handle, CURLOPT_HEADER, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOBODY, 1); } if (headers) { - switch_event_create(&client.headers, SWITCH_EVENT_CLONE); + switch_event_create(&client->headers, SWITCH_EVENT_CLONE); if (save_path) { switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_header_callback); - switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *) &client); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *) client); } else { switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, get_header_callback); - switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &client); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) client); } } @@ -2516,19 +2590,20 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &code); switch_curl_easy_cleanup(curl_handle); - if (client.fd > -1) { - close(client.fd); + if (client->fd > -1) { + close(client->fd); } - if (headers && client.headers) { - switch_event_add_header(client.headers, SWITCH_STACK_BOTTOM, "http-response-code", "%ld", code); - *headers = client.headers; + if (headers && client->headers) { + switch_event_add_header(client->headers, SWITCH_STACK_BOTTOM, "http-response-code", "%ld", code); + *headers = client->headers; + client->headers = NULL; } switch(code) { case 200: if (save_path) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "caching: url:%s to %s (%" SWITCH_SIZE_T_FMT " bytes)\n", url, save_path, client.bytes); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "caching: url:%s to %s (%" SWITCH_SIZE_T_FMT " bytes)\n", url, save_path, client->bytes); } status = SWITCH_STATUS_SUCCESS; break; @@ -2544,7 +2619,7 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char switch_safe_free(dynamic_url); switch_safe_free(dup_creds); - + client_destroy(&client); return status; } @@ -2704,6 +2779,7 @@ static switch_status_t locate_url_file(http_file_context_t *context, const char if (switch_file_exists(context->cache_file, context->pool) != SWITCH_STATUS_SUCCESS && unreachable) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File at url [%s] is unreachable!\n", url); + status = SWITCH_STATUS_NOTFOUND; goto end; } From dbc5571594eeacc4e3c7f2de3c78f8dd5c12f087 Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 11 Nov 2014 16:26:44 -0600 Subject: [PATCH 67/91] FS-6983 wrap new curl TLS macro usage with ifdefs --- src/mod/applications/mod_httapi/mod_httapi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index 4dade0f959..420b7578d9 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -1625,10 +1625,14 @@ static switch_status_t httapi_sync(client_t *client) if (client->profile->ssl_version) { if (!strcasecmp(client->profile->ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); +#ifdef CURL_SSLVERSION_TLSv1_1 } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.1")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); +#endif +#ifdef CURL_SSLVERSION_TLSv1_2 } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.2")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); +#endif } } else { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); @@ -2533,10 +2537,14 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char if (client->profile->ssl_version) { if (!strcasecmp(client->profile->ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); +#ifdef CURL_SSLVERSION_TLSv1_1 } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.1")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); +#endif +#ifdef CURL_SSLVERSION_TLSv1_2 } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.2")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); +#endif } } else { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); From fada4b893a41a9ea35230fff059ff2869a66450d Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 11 Nov 2014 18:18:27 -0600 Subject: [PATCH 68/91] FS-6977 #resolve --- src/switch_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/switch_core.c b/src/switch_core.c index bccaadc2b2..b23a35b542 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1559,6 +1559,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_thread_set_cpu_affinity(int cpu) } +#ifdef ENABLE_ZRTP static void switch_core_set_serial(void) { char buf[13] = ""; @@ -1604,7 +1605,7 @@ static void switch_core_set_serial(void) switch_core_set_variable("switch_serial", buf); } - +#endif SWITCH_DECLARE(int) switch_core_test_flag(int flag) { @@ -1748,8 +1749,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_core_set_variable("certs_dir", SWITCH_GLOBAL_dirs.certs_dir); switch_core_set_variable("storage_dir", SWITCH_GLOBAL_dirs.storage_dir); switch_core_set_variable("cache_dir", SWITCH_GLOBAL_dirs.cache_dir); +#ifdef ENABLE_ZRTP switch_core_set_serial(); - +#endif switch_console_init(runtime.memory_pool); switch_event_init(runtime.memory_pool); switch_channel_global_init(runtime.memory_pool); From dd629c15169c7d78e8f86658c1e32fcccff6eeb0 Mon Sep 17 00:00:00 2001 From: Seven Du Date: Wed, 12 Nov 2014 08:39:35 +0800 Subject: [PATCH 69/91] add external_video_source to media handle and expose switch_core_media_start_video_thread() to start the core video thread for non-rtp based media --- src/include/switch_core_media.h | 10 ++++++++++ src/switch_core_media.c | 18 +++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index d5baac404a..1915b742ae 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -146,6 +146,15 @@ typedef struct switch_core_media_params_s { switch_core_media_dtmf_t dtmf_type; switch_payload_t cng_pt; + /* a core_video_thread will be started automatically + when uses rtp based media, + external_video_source should be set to SWITCH_TRUE and + switch_core_media_start_video_thread() + should be explicitly called to start the video thread + if uses the media handle for non-rtp based media + */ + switch_bool_t external_video_source; + } switch_core_media_params_t; static inline const char *switch_media_type2str(switch_media_type_t type) @@ -252,6 +261,7 @@ SWITCH_DECLARE(void) switch_core_media_deinit(void); SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_media_start_video_thread(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core_session_t *session, switch_media_type_t type, diff --git a/src/switch_core_media.c b/src/switch_core_media.c index b5a0398308..1c7c369474 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -4375,7 +4375,10 @@ static switch_status_t start_video_thread(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s Starting Video thread\n", switch_core_session_get_name(session)); - switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt); + if (v_engine->rtp_session) { + switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt); + } + v_engine->mh.session = session; switch_threadattr_create(&thd_attr, pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); @@ -4388,7 +4391,10 @@ static switch_status_t start_video_thread(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } - +SWITCH_DECLARE(switch_status_t) switch_core_media_start_video_thread(switch_core_session_t *session) +{ + return start_video_thread(session); +} //? #define RA_PTR_LEN 512 @@ -4940,7 +4946,13 @@ SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; - if (!v_engine->rtp_session) { + if ((!smh->mparams->external_video_source) && (!v_engine->rtp_session)) { + return; + } + + if (!v_engine->mh.cond_mutex) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Channel %s has no cond?\n", + switch_channel_get_name(session->channel)); return; } From 07030c63f0448aae189759eb90001bcf65de75a3 Mon Sep 17 00:00:00 2001 From: Seven Du Date: Wed, 12 Nov 2014 13:31:30 +0800 Subject: [PATCH 70/91] fix compiler warning on unmatched return type --- src/switch_core_sqldb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index adcfbcf300..508b68643d 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1296,7 +1296,9 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand } if (!switch_test_flag((&runtime), SCF_AUTO_SCHEMAS)) { - return switch_cache_db_execute_sql(dbh, (char *)test_sql, NULL); + switch_status_t status = switch_cache_db_execute_sql(dbh, (char *)test_sql, NULL); + + return (status == SWITCH_STATUS_SUCCESS) ? SWITCH_TRUE : SWITCH_FALSE; } if (io_mutex) switch_mutex_lock(io_mutex); From 0eefdca47b127f8151c9b1a0b12eaf2d7e99def8 Mon Sep 17 00:00:00 2001 From: Julien Chavanton Date: Wed, 12 Nov 2014 09:06:11 +0100 Subject: [PATCH 71/91] FS-6947 Opus RTP payload fmtp settings ( maxaveragebitrate / maxplaybackrate ) --- src/mod/codecs/mod_opus/mod_opus.c | 94 +++++++++++++++--------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index dfb939f3b8..7fa8526219 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -42,6 +42,7 @@ struct opus_codec_settings { int useinbandfec; int usedtx; int maxaveragebitrate; + int maxplaybackrate; int stereo; int cbr; int sprop_maxcapturerate; @@ -57,6 +58,7 @@ static opus_codec_settings_t default_codec_settings = { /*.useinbandfec */ 1, /*.usedtx */ 1, /*.maxaveragebitrate */ 30000, + /*.maxplaybackrate */ 48000, /*.stereo*/ 0, /*.cbr*/ 0, /*.sprop_maxcapturerate*/ 0, @@ -151,52 +153,23 @@ static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmt if (!strcasecmp(data, "maxaveragebitrate")) { codec_settings->maxaveragebitrate = atoi(arg); - switch(codec_fmtp->actual_samples_per_second) { - case 8000: - { - if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) { - codec_settings->maxaveragebitrate = 20000; - } - break; - } - case 12000: - { - if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) { - codec_settings->maxaveragebitrate = 25000; - } - break; - } - case 16000: - { - if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) { - codec_settings->maxaveragebitrate = 30000; - } - break; - } - case 24000: - { - if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) { - codec_settings->maxaveragebitrate = 40000; - } - break; - } - - default: - /* this should never happen but 20000 is common among all rates */ - codec_settings->maxaveragebitrate = 20000; - break; + if ( codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 510000 ) { + codec_settings->maxaveragebitrate = 0; /* values outside the range between 6000 and 510000 SHOULD be ignored */ } - - - codec_fmtp->bits_per_second = codec_settings->maxaveragebitrate; } + if (!strcasecmp(data, "maxplaybackrate")) { + codec_settings->maxplaybackrate = atoi(arg); + if ( codec_settings->maxplaybackrate != 8000 && codec_settings->maxplaybackrate != 12000 && codec_settings->maxplaybackrate != 16000 + && codec_settings->maxplaybackrate != 24000 && codec_settings->maxplaybackrate != 48000) { + codec_settings->maxplaybackrate = 0; /* value not supported */ + } + } } } } free(fmtp_dup); } - //codec_fmtp->bits_per_second = bit_rate; return SWITCH_STATUS_SUCCESS; } return SWITCH_STATUS_FALSE; @@ -216,7 +189,10 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo if (settings->maxaveragebitrate) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d; ", settings->maxaveragebitrate); - + } + + if (settings->maxplaybackrate) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxplaybackrate=%d; ", settings->maxplaybackrate); } if (settings->ptime) { @@ -283,15 +259,41 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag return SWITCH_STATUS_GENERR; } - opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); - - if (codec->implementation->actual_samples_per_second == 8000) { - opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); - opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + + + + /* Setting documented in "RTP Payload Format for Opus Speech and Audio Codec" draft-spittka-payload-rtp-opus-03 */ + if( opus_codec_settings.maxaveragebitrate ) { /* Remote codec settings found in SDP "fmtp", we accept to tune the Encoder */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(opus_codec_settings.maxaveragebitrate)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate based on maxaveragebitrate found in SDP [%dbps]\n", opus_codec_settings.maxaveragebitrate); } else { - opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + /* Default codec settings used, may have been modified by SDP "samplerate" */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); + if (codec->implementation->actual_samples_per_second == 8000) { + opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + } else { + opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate to local settings [%dbps]\n", bitrate_bps); } - + + /* Another setting from "RTP Payload Format for Opus Speech and Audio Codec" */ + if ( opus_codec_settings.maxplaybackrate ) { + if (opus_codec_settings.maxplaybackrate == 8000) { /* Audio Bandwidth: 0-4000Hz Sampling Rate: 8000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + } else if (opus_codec_settings.maxplaybackrate == 12000) { /* Audio Bandwidth: 0-6000Hz Sampling Rate: 12000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + } else if (opus_codec_settings.maxplaybackrate == 16000) { /* Audio Bandwidth: 0-8000Hz Sampling Rate: 16000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + } else if (opus_codec_settings.maxplaybackrate == 24000) { /* Audio Bandwidth: 0-12000Hz Sampling Rate: 24000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + } else if (opus_codec_settings.maxplaybackrate == 48000) { /* Audio Bandwidth: 0-20000Hz Sampling Rate: 48000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bandwidth based on maxplaybackrate found in SDP [%dHz]\n", opus_codec_settings.maxplaybackrate); + } + if (use_vbr) { opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr)); } From 0699ea87c599b10d48e69526be8a3afb4f57f1cb Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 12 Nov 2014 12:49:57 -0600 Subject: [PATCH 72/91] fix a few issues --- support-d/fscore_pb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/support-d/fscore_pb b/support-d/fscore_pb index 80fd022fdf..c1c932d185 100755 --- a/support-d/fscore_pb +++ b/support-d/fscore_pb @@ -87,7 +87,8 @@ fi post_cmd="" command -v wget >/dev/null 2>&1 if [ $? -eq 0 ]; then - post_cmd="wget --output-file=/dev/null --output-document=/tmp/fscore_pb.tmp/pb_out --http-user=pastebin --http-password=freeswitch http://pastebin.freeswitch.org --post-file=$post_file" + post_cmd="wget --output-file=/dev/null --output-document=/tmp/fscore_pb.tmp/pb_out --http-user=pastebin --http-password=freeswitch https://pastebin.freeswitch.org --post-file=$post_file" + echo -n "paste=Send&remember=0&poster=$user&format=none&expiry=f&code2=" > $post_file fi if [ -z "$post_cmd" ]; then @@ -102,17 +103,15 @@ if [ -z "$post_cmd" ]; then exit 255 fi -if [[ "$post_cmd" == wget* ]]; then - echo -n "paste=Send&remember=0&poster=$user&format=none&expiry=f&code2=" > $post_file -fi - echo "Gathering Data Please Wait........." +UNAME=`uname`; + #Linux -if [ $(uname) == "Linux" ]; then +if [ "${UNAME}" = "Linux" ]; then echo "LSB RELEASE:" >> $post_file echo $line >> $post_file - if [ -f /etc/redhat-release ] ; then + if [ -f /etc/redhat-release ]; then cat /etc/redhat-release >> $post_file else lsb_release -a >> $post_file @@ -122,7 +121,7 @@ if [ $(uname) == "Linux" ]; then echo $line >> $post_file cat /proc/cpuinfo >> $post_file #Mac -elif [ $(uname) == "Darwin" ]; then +elif [ "${UNAME}" = "Darwin" ]; then system_profiler SPSoftwareDataType SPHardwareDataType >> $post_file fi; From 7b38b4f86b0e7351e2e773177797c7306561d5ff Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 30 Oct 2014 01:24:09 +0000 Subject: [PATCH 73/91] Avoid mod_shout on sid/jessie for now On sid the build breaks on "undefined reference to symbol 'ogg_sync_init'". We'll just avoid mod_shout on sid/jessie until this is worked out. --- debian/bootstrap.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index c749981770..b179f594c0 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -35,11 +35,13 @@ avoid_mods=( ) avoid_mods_sid=( directories/mod_ldap + formats/mod_shout languages/mod_java ) avoid_mods_jessie=( directories/mod_ldap languages/mod_java + formats/mod_shout ) avoid_mods_wheezy=( languages/mod_java From 65502293cf168ae4dc53292b3084cd2bdee471fe Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 12 Nov 2014 13:07:43 -0600 Subject: [PATCH 74/91] FS-6890 #comment revert --- src/mod/endpoints/mod_sofia/mod_sofia.c | 50 +++---------------------- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 - 2 files changed, 5 insertions(+), 46 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index bd9b362b54..1265d5a66c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1559,58 +1559,18 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (ok) { char *headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_INFO_HEADER_PREFIX); const char *pl = NULL; - nua_handle_t *nh; - sip_cseq_t *cseq = NULL; - const char *uri = NULL; - char *to, *from; - char *contact; - const char *invite_contact_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_contact_params"); - - + if (!zstr(msg->string_array_arg[2])) { pl = msg->string_array_arg[2]; } - uri = switch_core_session_sprintf(tech_pvt->session, "sip:%s", - switch_channel_get_variable_dup(tech_pvt->channel, "sip_contact_uri", SWITCH_FALSE, -1)); - - if (tech_pvt->invite_contact) { - contact = sofia_overcome_sip_uri_weakness(tech_pvt->session, - tech_pvt->invite_contact, tech_pvt->transport, SWITCH_FALSE, invite_contact_params, NULL); - } else { - contact = tech_pvt->reply_contact; - } - - - nh = nua_handle(tech_pvt->profile->nua, NULL, - NUTAG_URL(uri), - TAG_IF(contact, SIPTAG_CONTACT_STR(contact)), - TAG_END()); - - - cseq = sip_cseq_create(nh->nh_home, ++tech_pvt->info_cseq, SIP_METHOD_INFO); - nua_handle_bind(nh, &mod_sofia_globals.destroy_private); - - if (tech_pvt->sent_last_invite || !tech_pvt->recv_invites) { - from = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_from"); - to = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_to"); - } else { - from = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_to"); - to = (char *)switch_channel_get_variable(tech_pvt->channel, "sip_full_from"); - } - - nua_info(nh, - TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), - SIPTAG_FROM_STR(from), - SIPTAG_TO_STR(to), - SIPTAG_CALL_ID_STR(switch_channel_get_variable(tech_pvt->channel, "sip_call_id")), + nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(headers), SIPTAG_HEADER_STR(headers)), - TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), - SIPTAG_CSEQ(cseq), + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), TAG_END()); - + switch_safe_free(headers); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s send_info is not supported.\n", switch_channel_get_name(channel)); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index c20a4e7a06..52307a2800 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -811,7 +811,6 @@ struct private_object { uint32_t keepalive; uint32_t sent_invites; uint32_t recv_invites; - uint32_t info_cseq; uint8_t sent_last_invite; }; From 87a4670d16226557f75982544e419668368ebab9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 12 Nov 2014 13:09:23 -0600 Subject: [PATCH 75/91] FS-6890 #comment please test --- libs/sofia-sip/.update | 2 +- libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 169ce799b0..d3d7dac4b3 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Wed Nov 5 09:25:53 CST 2014 +Wed Nov 12 13:07:56 CST 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index 933d76249e..d9261324d5 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -1549,10 +1549,12 @@ static void nua_session_usage_refresh(nua_handle_t *nh, nua_client_request_in_progress(cr)) return; + if (ds->ds_cr) return; /* request queued */ + /* UPDATE has been queued */ - for (cr = ds->ds_cr; cr; cr = cr->cr_next) - if (cr->cr_method == sip_method_update) - return; + //for (cr = ds->ds_cr; cr; cr = cr->cr_next) + //if (cr->cr_method == sip_method_update) + // return; /* INVITE or UPDATE in progress on server side */ for (sr = ds->ds_sr; sr; sr = sr->sr_next) From 82aa33140e4177d28400ec0d951982f5e77c4941 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 12 Nov 2014 21:37:14 -0600 Subject: [PATCH 76/91] FS-6531: #resolve set to tag on auto answer notify to make grandstream happy, even tho they could have matched the dialog fine off the from tag like every other phone does. --- src/mod/endpoints/mod_sofia/sofia.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 17c06a30a0..3bff27e1cd 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6665,10 +6665,19 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (channel && (status == 180 || status == 183) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + const char *full_to = NULL; const char *val; if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) { - nua_notify(nh, NUTAG_NEWSUB(1), NUTAG_WITH_THIS_MSG(de->data->e_msg), - NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_EVENT_STR("talk"), TAG_END()); + full_to = switch_str_nil(switch_channel_get_variable(channel, "sip_full_to")); + + nua_notify(nh, + NUTAG_NEWSUB(1), + NUTAG_WITH_THIS_MSG(de->data->e_msg), + NUTAG_SUBSTATE(nua_substate_terminated), + TAG_IF((full_to), SIPTAG_TO_STR(full_to)), + SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), + SIPTAG_EVENT_STR("talk"), + TAG_END()); } } From 75473a70b6eba0bdd4d995fc4ac5f6bbf3e4f08e Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 12 Nov 2014 21:55:31 -0600 Subject: [PATCH 77/91] FS-6531: #resolve set to tag on uuid_phone_event notify to make grandstream happy, even tho they could have matched the dialog fine off the from tag like every other phone does. --- src/mod/endpoints/mod_sofia/mod_sofia.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 1265d5a66c..599ab45867 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1471,6 +1471,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_PHONE_EVENT: { const char *event = "talk"; + const char *full_to = NULL; if (!zstr(msg->string_arg) && strcasecmp(msg->string_arg, event)) { if (!strcasecmp(msg->string_arg, "hold")) { @@ -1484,7 +1485,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Operation not permitted on an inbound non-answered call leg!\n"); } else { - nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_SUBSCRIPTION_STATE_STR("active"), + full_to = switch_str_nil(switch_channel_get_variable(channel, "sip_full_to")); + nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), + TAG_IF((full_to), SIPTAG_TO_STR(full_to)),SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_EVENT_STR(event), TAG_END()); } From dd612321638b2a2f214344afb0de967862e02153 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Thu, 13 Nov 2014 10:20:02 -0500 Subject: [PATCH 78/91] FS-6979 #resolve #comment mod_http_cache: added base-domain config to s3 profiles so mod_http_cache can access self hosted s3 compatible service. Example configuration: --- src/mod/applications/mod_http_cache/aws.c | 40 +++++++--- src/mod/applications/mod_http_cache/aws.h | 10 +-- .../conf/autoload_configs/http_cache.conf.xml | 1 + .../mod_http_cache/mod_http_cache.c | 28 +++++-- .../mod_http_cache/test_aws/main.c | 76 +++++++++++-------- 5 files changed, 102 insertions(+), 53 deletions(-) diff --git a/src/mod/applications/mod_http_cache/aws.c b/src/mod/applications/mod_http_cache/aws.c index 58c4b4d917..cb637f8ad0 100644 --- a/src/mod/applications/mod_http_cache/aws.c +++ b/src/mod/applications/mod_http_cache/aws.c @@ -1,6 +1,6 @@ /* * aws.c for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2014, Grasshopper * * Version: MPL 1.1 * @@ -41,8 +41,18 @@ * @param url to check * @return true if this is an S3 url */ -int aws_s3_is_s3_url(const char *url) +int aws_s3_is_s3_url(const char *url, const char *base_domain) { + if (!zstr(base_domain)) { + char *base_domain_escaped; + char regex[1024]; + int result; + base_domain_escaped = switch_string_replace(base_domain, ".", "\\."); + switch_snprintf(regex, 1024, "^https?://\\w[-\\w.]{1,61}\\w\\.%s/.*$", base_domain_escaped); + result = !zstr(url) && switch_regex_match(url, regex) == SWITCH_STATUS_SUCCESS; + switch_safe_free(base_domain_escaped); + return result; + } /* AWS bucket naming rules are complex... this match only supports virtual hosting of buckets */ return !zstr(url) && switch_regex_match(url, "^https?://\\w[-\\w.]{1,61}\\w\\.s3([-\\w]+)?\\.amazonaws\\.com/.*$") == SWITCH_STATUS_SUCCESS; } @@ -141,10 +151,11 @@ static char *my_strrstr(const char *haystack, const char *needle) /** * Parse bucket and object from URL * @param url to parse. This value is modified. + * @param base_domain of URL (assumes s3.amazonaws.com if not specified) * @param bucket to store result in * @param bucket_length of result buffer */ -void aws_s3_parse_url(char *url, char **bucket, char **object) +void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object) { char *bucket_start = NULL; char *bucket_end; @@ -153,7 +164,7 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) *bucket = NULL; *object = NULL; - if (!aws_s3_is_s3_url(url)) { + if (!aws_s3_is_s3_url(url, base_domain)) { return; } @@ -167,8 +178,15 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) /* invalid URL */ return; } - - bucket_end = my_strrstr(bucket_start, ".s3"); + + { + char base_domain_match[1024]; + if (zstr(base_domain)) { + base_domain = "s3"; + } + switch_snprintf(base_domain_match, 1024, ".%s", base_domain); + bucket_end = my_strrstr(bucket_start, base_domain_match); + } if (!bucket_end) { /* invalid URL */ return; @@ -195,6 +213,7 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) * Create a pre-signed URL for AWS S3 * @param verb (PUT/GET) * @param url address (virtual-host-style) + * @param base_domain (optional - amazon aws assumed if not specified) * @param content_type optional content type * @param content_md5 optional content MD5 checksum * @param aws_access_key_id secret access key identifier @@ -202,7 +221,7 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) * @param expires seconds since the epoch * @return presigned_url */ -char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires) +char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires) { char signature[S3_SIGNATURE_LENGTH_MAX]; char signature_url_encoded[S3_SIGNATURE_LENGTH_MAX]; @@ -212,7 +231,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char char *object; /* create URL encoded signature */ - aws_s3_parse_url(url_dup, &bucket, &object); + aws_s3_parse_url(url_dup, base_domain, &bucket, &object); string_to_sign = aws_s3_string_to_sign(verb, bucket, object, content_type, content_md5, expires); signature[0] = '\0'; aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, string_to_sign, aws_secret_access_key); @@ -230,6 +249,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char * @param authentication_length maximum result length * @param verb (PUT/GET) * @param url address (virtual-host-style) + * @param base_domain (optional - amazon aws assumed if not specified) * @param content_type optional content type * @param content_md5 optional content MD5 checksum * @param aws_access_key_id secret access key identifier @@ -237,7 +257,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char * @param date header * @return signature for Authorization header */ -char *aws_s3_authentication_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date) +char *aws_s3_authentication_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date) { char signature[S3_SIGNATURE_LENGTH_MAX]; char *string_to_sign; @@ -246,7 +266,7 @@ char *aws_s3_authentication_create(const char *verb, const char *url, const char char *object; /* create base64 encoded signature */ - aws_s3_parse_url(url_dup, &bucket, &object); + aws_s3_parse_url(url_dup, base_domain, &bucket, &object); string_to_sign = aws_s3_string_to_sign(verb, bucket, object, content_type, content_md5, date); signature[0] = '\0'; aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, string_to_sign, aws_secret_access_key); diff --git a/src/mod/applications/mod_http_cache/aws.h b/src/mod/applications/mod_http_cache/aws.h index d86f75f1dc..e95001d026 100644 --- a/src/mod/applications/mod_http_cache/aws.h +++ b/src/mod/applications/mod_http_cache/aws.h @@ -1,6 +1,6 @@ /* * aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2014, Grasshopper * * Version: MPL 1.1 * @@ -34,12 +34,12 @@ /* (SHA1_LENGTH * 1.37 base64 bytes per byte * 3 url-encoded bytes per byte) */ #define S3_SIGNATURE_LENGTH_MAX 83 -int aws_s3_is_s3_url(const char *url); -void aws_s3_parse_url(char *url, char **bucket, char **object); +int aws_s3_is_s3_url(const char *url, const char *base_domain); +void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object); char *aws_s3_string_to_sign(const char *verb, const char *bucket, const char *object, const char *content_type, const char *content_md5, const char *date); char *aws_s3_signature(char *signature, int signature_length, const char *string_to_sign, const char *aws_secret_access_key); -char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires); -char *aws_s3_authentication_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date); +char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires); +char *aws_s3_authentication_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date); #endif diff --git a/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml b/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml index ce68ea09b0..6e2698bf90 100644 --- a/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml +++ b/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml @@ -18,6 +18,7 @@ + diff --git a/src/mod/applications/mod_http_cache/mod_http_cache.c b/src/mod/applications/mod_http_cache/mod_http_cache.c index f1ec2b69ed..8a7718ea49 100644 --- a/src/mod/applications/mod_http_cache/mod_http_cache.c +++ b/src/mod/applications/mod_http_cache/mod_http_cache.c @@ -1,6 +1,6 @@ /* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2005-2013, Anthony Minessale II + * Copyright (C) 2005-2014, Anthony Minessale II * * Version: MPL 1.1 * @@ -61,6 +61,7 @@ struct http_profile { const char *name; const char *aws_s3_access_key_id; const char *aws_s3_secret_access_key; + const char *aws_s3_base_domain; }; typedef struct http_profile http_profile_t; @@ -201,7 +202,7 @@ static void url_cache_unlock(url_cache_t *cache, switch_core_session_t *session) static void url_cache_clear(url_cache_t *cache, switch_core_session_t *session); static http_profile_t *url_cache_http_profile_find(url_cache_t *cache, const char *name); static http_profile_t *url_cache_http_profile_find_by_fqdn(url_cache_t *cache, const char *url); -static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key); +static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key, const char *aws_s3_base_domain); static switch_curl_slist_t *append_aws_s3_headers(switch_curl_slist_t *headers, http_profile_t *profile, const char *verb, const char *content_type, const char *url); @@ -792,7 +793,7 @@ static http_profile_t *url_cache_http_profile_find_by_fqdn(url_cache_t *cache, c /** * Add a profile to the cache */ -static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key) +static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key, const char *aws_s3_base_domain) { http_profile_t *profile = switch_core_alloc(cache->pool, sizeof(*profile)); profile->name = switch_core_strdup(cache->pool, name); @@ -802,6 +803,10 @@ static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char if (aws_s3_secret_access_key) { profile->aws_s3_secret_access_key = switch_core_strdup(cache->pool, aws_s3_secret_access_key); } + if (aws_s3_base_domain) { + profile->aws_s3_base_domain = switch_core_strdup(cache->pool, aws_s3_base_domain); + } + switch_core_hash_insert(cache->profiles, profile->name, profile); return profile; } @@ -919,7 +924,7 @@ static void cached_url_destroy(cached_url_t *url, switch_memory_pool_t *pool) static switch_curl_slist_t *append_aws_s3_headers(switch_curl_slist_t *headers, http_profile_t *profile, const char *verb, const char *content_type, const char *url) { /* check if Amazon headers are needed */ - if (profile && profile->aws_s3_access_key_id && aws_s3_is_s3_url(url)) { + if (profile && profile->aws_s3_access_key_id && aws_s3_is_s3_url(url, profile->aws_s3_base_domain)) { char date[256]; char header[1024]; char *authenticate; @@ -930,7 +935,7 @@ static switch_curl_slist_t *append_aws_s3_headers(switch_curl_slist_t *headers, headers = switch_curl_slist_append(headers, header); /* Authorization: */ - authenticate = aws_s3_authentication_create(verb, url, content_type, "", profile->aws_s3_access_key_id, profile->aws_s3_secret_access_key, date); + authenticate = aws_s3_authentication_create(verb, url, profile->aws_s3_base_domain, content_type, "", profile->aws_s3_access_key_id, profile->aws_s3_secret_access_key, date); snprintf(header, 1024, "Authorization: %s", authenticate); free(authenticate); headers = switch_curl_slist_append(headers, header); @@ -1397,7 +1402,9 @@ static switch_status_t do_config(url_cache_t *cache) switch_xml_t s3 = switch_xml_child(profile, "aws-s3"); char *access_key_id = NULL; char *secret_access_key = NULL; + char *base_domain = NULL; if (s3) { + switch_xml_t base_domain_xml = switch_xml_child(s3, "base-domain"); switch_xml_t id = switch_xml_child(s3, "access-key-id"); switch_xml_t secret = switch_xml_child(s3, "secret-access-key"); if (id && secret) { @@ -1412,12 +1419,21 @@ static switch_status_t do_config(url_cache_t *cache) } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing key id or secret\n"); + continue; + } + if (base_domain_xml) { + base_domain = switch_strip_whitespace(switch_xml_txt(base_domain_xml)); + if (zstr(base_domain)) { + switch_safe_free(base_domain); + base_domain = NULL; + } } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding profile \"%s\" to cache\n", name); - profile_obj = url_cache_http_profile_add(cache, name, access_key_id, secret_access_key); + profile_obj = url_cache_http_profile_add(cache, name, access_key_id, secret_access_key, base_domain); switch_safe_free(access_key_id); switch_safe_free(secret_access_key); + switch_safe_free(base_domain); domains = switch_xml_child(profile, "domains"); if (domains) { diff --git a/src/mod/applications/mod_http_cache/test_aws/main.c b/src/mod/applications/mod_http_cache/test_aws/main.c index f661c5954f..e36c746819 100644 --- a/src/mod/applications/mod_http_cache/test_aws/main.c +++ b/src/mod/applications/mod_http_cache/test_aws/main.c @@ -41,24 +41,28 @@ static void test_signature(void) */ static void test_check_url(void) { - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3-us-west-1.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3-us-west-1.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object")); - ASSERT_TRUE(aws_s3_is_s3_url("http://red.bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/recordings/1240fwjf8we.mp3")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/en/us/8000/1232345.mp3")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket_with_underscore.s3.amazonaws.com/en/us/8000/1232345.mp3")); - ASSERT_FALSE(aws_s3_is_s3_url("bucket.s3.amazonaws.com/object.ext")); - ASSERT_FALSE(aws_s3_is_s3_url("https://s3.amazonaws.com/bucket/object")); - ASSERT_FALSE(aws_s3_is_s3_url("http://s3.amazonaws.com/bucket/object")); - ASSERT_FALSE(aws_s3_is_s3_url("http://google.com/")); - ASSERT_FALSE(aws_s3_is_s3_url("http://phono.com/audio/troporocks.mp3")); - ASSERT_FALSE(aws_s3_is_s3_url("")); - ASSERT_FALSE(aws_s3_is_s3_url(NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3-us-west-1.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3-us-west-1.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://red.bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/recordings/1240fwjf8we.mp3", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/en/us/8000/1232345.mp3", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket_with_underscore.s3.amazonaws.com/en/us/8000/1232345.mp3", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("https://s3.amazonaws.com/bucket/object", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("http://s3.amazonaws.com/bucket/object", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("http://google.com/", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("http://phono.com/audio/troporocks.mp3", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url(NULL, NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("https://example.com/bucket/object", "example.com")); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.example.com/object", "example.com")); + ASSERT_FALSE(aws_s3_is_s3_url("", "example.com")); + ASSERT_FALSE(aws_s3_is_s3_url(NULL, "example.com")); } /** @@ -68,51 +72,55 @@ static void test_parse_url(void) { char *bucket; char *object; - aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/nelson"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/nelson"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("quotes", bucket); ASSERT_STRING_EQUALS("nelson", object); - aws_s3_parse_url(strdup("https://quotes.s3.amazonaws.com/nelson.mp3"), &bucket, &object); + aws_s3_parse_url(strdup("https://quotes.s3.amazonaws.com/nelson.mp3"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("quotes", bucket); ASSERT_STRING_EQUALS("nelson.mp3", object); - aws_s3_parse_url(strdup("http://s3.amazonaws.com/quotes/nelson"), &bucket, &object); + aws_s3_parse_url(strdup("http://s3.amazonaws.com/quotes/nelson"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes/quotes/nelson"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes/quotes/nelson"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup(""), &bucket, &object); + aws_s3_parse_url(strdup(""), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(NULL, &bucket, &object); + aws_s3_parse_url(NULL, NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://bucket.s3.amazonaws.com/voicemails/recording.wav"), &bucket, &object); + aws_s3_parse_url(strdup("http://bucket.s3.amazonaws.com/voicemails/recording.wav"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("bucket", bucket); ASSERT_STRING_EQUALS("voicemails/recording.wav", object); - aws_s3_parse_url(strdup("https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"), &bucket, &object); + aws_s3_parse_url(strdup("https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("my-bucket-with-dash", bucket); ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object); - aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, &bucket, &object); + ASSERT_STRING_EQUALS("quotes.s3.foo.bar", bucket); + ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object); + + aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.example.com/greeting/file/1002/Lumino.mp3"), "example.com", &bucket, &object); ASSERT_STRING_EQUALS("quotes.s3.foo.bar", bucket); ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object); } @@ -122,7 +130,9 @@ static void test_parse_url(void) */ static void test_authorization_header(void) { - ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", NULL, "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "s3.amazonaws.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.example.com/awesome.mp3", "example.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); } /** @@ -130,7 +140,9 @@ static void test_authorization_header(void) */ static void test_presigned_url(void) { - ASSERT_STRING_EQUALS("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", NULL, "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "s3.amazonaws.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("https://vault.example.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.example.com/awesome.mp3", "example.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); } /** From 826d42874139c59636de234d7021d485f03b81ee Mon Sep 17 00:00:00 2001 From: Julien Chavanton Date: Thu, 13 Nov 2014 13:48:04 +0100 Subject: [PATCH 79/91] FS-6992 [mod_opus] global configuration or maxplaybackrate and maxaveragebitrate from opus.conf.xml --- conf/vanilla/autoload_configs/opus.conf.xml | 13 +++++++++++ src/mod/codecs/mod_opus/mod_opus.c | 24 +++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/conf/vanilla/autoload_configs/opus.conf.xml b/conf/vanilla/autoload_configs/opus.conf.xml index 747a8f762f..2ac3f66f86 100644 --- a/conf/vanilla/autoload_configs/opus.conf.xml +++ b/conf/vanilla/autoload_configs/opus.conf.xml @@ -2,5 +2,18 @@ + + + + + diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index 7fa8526219..dc51a653f1 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -78,6 +78,8 @@ struct opus_context { struct { int use_vbr; int complexity; + int maxaveragebitrate; + int maxplaybackrate; switch_mutex_t *mutex; } opus_prefs; @@ -240,6 +242,15 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); codec_fmtp.private_info = &opus_codec_settings; switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp); + + /* Verify if the local or remote configuration are lowering maxaveragebitrate and/or maxplaybackrate */ + if ( opus_prefs.maxaveragebitrate && (opus_prefs.maxaveragebitrate < opus_codec_settings.maxaveragebitrate || !opus_codec_settings.maxaveragebitrate) ) { + opus_codec_settings.maxaveragebitrate = opus_prefs.maxaveragebitrate; + } + if ( opus_prefs.maxplaybackrate && (opus_prefs.maxplaybackrate < opus_codec_settings.maxplaybackrate || !opus_codec_settings.maxplaybackrate) ) { + opus_codec_settings.maxplaybackrate = opus_prefs.maxplaybackrate; + } + codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool); if (encoding) { @@ -260,8 +271,6 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag } - - /* Setting documented in "RTP Payload Format for Opus Speech and Audio Codec" draft-spittka-payload-rtp-opus-03 */ if( opus_codec_settings.maxaveragebitrate ) { /* Remote codec settings found in SDP "fmtp", we accept to tune the Encoder */ opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(opus_codec_settings.maxaveragebitrate)); @@ -430,6 +439,17 @@ static switch_status_t opus_load_config(switch_bool_t reload) opus_prefs.use_vbr = atoi(val); } else if (!strcasecmp(key, "complexity")) { opus_prefs.complexity = atoi(val); + } else if (!strcasecmp(key, "maxaveragebitrate")) { + opus_prefs.maxaveragebitrate = atoi(val); + if ( opus_prefs.maxaveragebitrate < 6000 || opus_prefs.maxaveragebitrate > 510000 ) { + opus_prefs.maxaveragebitrate = 0; /* values outside the range between 6000 and 510000 SHOULD be ignored */ + } + } else if (!strcasecmp(key, "maxplaybackrate")) { + opus_prefs.maxplaybackrate = atoi(val); + if ( opus_prefs.maxplaybackrate != 8000 && opus_prefs.maxplaybackrate != 12000 && opus_prefs.maxplaybackrate != 16000 + && opus_prefs.maxplaybackrate != 24000 && opus_prefs.maxplaybackrate != 48000) { + opus_prefs.maxplaybackrate = 0; /* value not supported */ + } } } } From e1c0ef5008112e3b4dd08c665d4297dcb9e7f4fc Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 14 Nov 2014 13:22:53 -0500 Subject: [PATCH 80/91] mod_rayo: new configuration parameter, add-variables-to-offer (default=false). When true, all channel variables are included in the offer to rayo client --- conf/rayo/autoload_configs/rayo.conf.xml | 6 ++++++ .../mod_rayo/conf/autoload_configs/rayo.conf.xml | 6 ++++++ src/mod/event_handlers/mod_rayo/mod_rayo.c | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index 47a3a14bc1..a5f8748416 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -2,8 +2,14 @@ + + + + + + diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index 47a3a14bc1..a5f8748416 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -2,8 +2,14 @@ + + + + + + diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index cc7fc65037..614975ee15 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -229,6 +229,8 @@ static struct { int pause_when_offline; /** flag to reduce log noise */ int offline_logged; + /** if true, channel variables are added to offer */ + int add_variables_to_offer; } globals; /** @@ -3682,18 +3684,23 @@ static iks *rayo_create_offer(struct rayo_call *call, switch_core_session_t *ses iks_insert_attrib(offer, "to", profile->destination_number); } - /* add signaling headers */ + /* add headers to offer */ { switch_event_header_t *var; add_header(offer, "from", switch_channel_get_variable(channel, "sip_full_from")); add_header(offer, "to", switch_channel_get_variable(channel, "sip_full_to")); add_header(offer, "via", switch_channel_get_variable(channel, "sip_full_via")); - /* get all variables prefixed with sip_h_ */ + /* add all SIP header variables and (if configured) all other variables */ for (var = switch_channel_variable_first(channel); var; var = var->next) { if (!strncmp("sip_h_", var->name, 6)) { add_header(offer, var->name + 6, var->value); } + if (globals.add_variables_to_offer) { + char var_name[1024]; + snprintf(var_name, 1024, "variable-%s", var->name); + add_header(offer, var_name, var->value); + } } switch_channel_variable_last(channel); } @@ -4066,6 +4073,7 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_ globals.num_message_threads = 8; globals.offer_uri = 1; globals.pause_when_offline = 0; + globals.add_variables_to_offer = 0; /* get params */ { @@ -4102,6 +4110,10 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_ if (switch_true(val)) { globals.pause_when_offline = 1; } + } else if (!strcasecmp(var, "add-variables-to-offer")) { + if (switch_true(val)) { + globals.add_variables_to_offer = 1; + } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var); } From 07c5cc18ba57a57ed082985a1a5f830dce7ee793 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 14 Nov 2014 14:20:48 -0500 Subject: [PATCH 81/91] FS-7003 #resolve #comment mod_rayo: fix infinite loop when output sent to server without SSML configured and repeat-times=0 --- src/mod/event_handlers/mod_rayo/rayo_output_component.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mod/event_handlers/mod_rayo/rayo_output_component.c b/src/mod/event_handlers/mod_rayo/rayo_output_component.c index 9d075dc6ae..ef097b6411 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_output_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_output_component.c @@ -368,6 +368,8 @@ struct rayo_file_context { struct rayo_component *component; /** number of times played */ int play_count; + /** have any files successfully opened? */ + int could_open; }; /** @@ -376,6 +378,7 @@ struct rayo_file_context { */ static switch_status_t next_file(switch_file_handle_t *handle) { + int loops = 0; struct rayo_file_context *context = handle->private_info; struct output_component *output = context->component ? OUTPUT_COMPONENT(context->component) : NULL; @@ -404,7 +407,7 @@ static switch_status_t next_file(switch_file_handle_t *handle) /* done? */ if (!context->cur_doc) { - if (output->repeat_times == 0 || ++context->play_count < output->repeat_times) { + if (context->could_open && ++loops < 2 && (output->repeat_times == 0 || ++context->play_count < output->repeat_times)) { /* repeat all document(s) */ if (!output->repeat_interval_ms) { goto top; @@ -464,6 +467,8 @@ static switch_status_t next_file(switch_file_handle_t *handle) if (switch_core_file_open(&context->fh, context->ssml, handle->channels, handle->samplerate, handle->flags, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Failed to open %s\n", context->ssml); goto top; + } else { + context->could_open = 1; } handle->samples = context->fh.samples; @@ -503,6 +508,7 @@ static switch_status_t rayo_file_open(switch_file_handle_t *handle, const char * handle->private_info = context; context->cur_doc = NULL; context->play_count = 0; + context->could_open = 0; status = next_file(handle); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "File error! %s\n", path); From 1ee325df48b3c71e8cf645aaf19138eae9a43ff6 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2014 19:16:39 +0000 Subject: [PATCH 82/91] Add `connect-timeout` option for curl API command This option sets the maximum number of seconds that curl will wait to connect with the server. Right now this is a synonym for the `timeout` option. --- src/mod/applications/mod_curl/mod_curl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c index bff5df864c..68c21f61e4 100644 --- a/src/mod/applications/mod_curl/mod_curl.c +++ b/src/mod/applications/mod_curl/mod_curl.c @@ -51,7 +51,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_curl_load); */ SWITCH_MODULE_DEFINITION(mod_curl, mod_curl_load, mod_curl_shutdown, NULL); -static char *SYNTAX = "curl url [headers|json|content-type |timeout ] [get|head|post|delete|put [data]]"; +static char *SYNTAX = "curl url [headers|json|content-type |connect-timeout |timeout ] [get|head|post|delete|put [data]]"; #define HTTP_SENDFILE_ACK_EVENT "curl_sendfile::ack" #define HTTP_SENDFILE_RESPONSE_SIZE 32768 @@ -944,6 +944,16 @@ SWITCH_STANDARD_API(curl_function) if (++i < argc) { content_type = switch_core_strdup(pool, argv[i]); } + } else if (!strcasecmp("connect-timeout", argv[i])) { + if (++i < argc) { + int tmp = atoi(argv[i]); + + if (tmp > 0) { + options.connect_timeout = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid connect-timeout!\n"); + } + } } else if (!strcasecmp("timeout", argv[i])) { if (++i < argc) { int tmp = atoi(argv[i]); From f1df8d609672094f3ce10a1a7de8b59a86d3db92 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2014 19:20:07 +0000 Subject: [PATCH 83/91] Allow setting CURL timeout from curl API command Previously the `timeout` option to the curl API command set only `CURLOPT_CONNECTTIMEOUT` -- the maximum amount of time that curl will wait to connect to the server. If the server accepted the connection but then never replied, curl would wait essentially forever. There was no way to set `CURLOPT_TIMEOUT` -- the maximum amount of time the entire request operation is allowed to take. With this change, the `timeout` option sets `CURLOPT_TIMEOUT`. We've earlier added a `connect-timeout` option to set `CURLOPT_CONNECTTIMEOUT`. This is a change to existing behavior. However, it's likely that this is what people expected it to do all along. The curl application call, for example, accepts both `curl_connect_timeout` and `curl_timeout` channel variables, with the latter setting `CURLOPT_TIMEOUT`. If people really were relying on this odd behavior, we'll rename the option with the new behavior to something else and come up with a transition plan. --- src/mod/applications/mod_curl/mod_curl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c index 68c21f61e4..86e2924073 100644 --- a/src/mod/applications/mod_curl/mod_curl.c +++ b/src/mod/applications/mod_curl/mod_curl.c @@ -959,7 +959,7 @@ SWITCH_STANDARD_API(curl_function) int tmp = atoi(argv[i]); if (tmp > 0) { - options.connect_timeout = tmp; + options.timeout = tmp; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid timeout!\n"); } From c73afe1c85f42d076c4b71c80251f7c888d47756 Mon Sep 17 00:00:00 2001 From: Flavio Grossi Date: Mon, 17 Nov 2014 11:11:42 +0100 Subject: [PATCH 84/91] FS-7004 mod_sndfile: respect umask when creating new files Files created by mod_sndfile use sf_open() which uses hardcoded permissions. To respect the process' umask, manually open files with the correct permissions and then call sf_open_fd(). --- src/mod/formats/mod_sndfile/mod_sndfile.c | 25 ++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c index 5d8d0865b5..4b6e9112a6 100644 --- a/src/mod/formats/mod_sndfile/mod_sndfile.c +++ b/src/mod/formats/mod_sndfile/mod_sndfile.c @@ -54,10 +54,13 @@ struct sndfile_context { typedef struct sndfile_context sndfile_context; +static switch_status_t sndfile_perform_open(sndfile_context *context, const char *path, const char *mask, int mode); + static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const char *path) { sndfile_context *context; int mode = 0; + const char *mask = "rb"; char *ext; struct format_map *map = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -84,8 +87,10 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER) || handle->offset_pos) { + mask = "ab+"; mode += SFM_RDWR; } else { + mask = "wb+"; mode += SFM_WRITE; } } @@ -181,7 +186,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha ldup = strdup(last); switch_assert(ldup); switch_snprintf(last, alt_len - (last - alt_path), "%d%s%s", handle->samplerate, SWITCH_PATH_SEPARATOR, ldup); - if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) { + if (sndfile_perform_open(context, alt_path, mask, mode) == SWITCH_STATUS_SUCCESS) { path = alt_path; } else { /* Try to find the file at the highest rate possible if we can't find one that matches the exact rate. @@ -189,7 +194,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha */ for (i = 3; i >= 0; i--) { switch_snprintf(last, alt_len - (last - alt_path), "%d%s%s", rates[i], SWITCH_PATH_SEPARATOR, ldup); - if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) { + if (sndfile_perform_open(context, alt_path, mask, mode) == SWITCH_STATUS_SUCCESS) { path = alt_path; break; } @@ -198,7 +203,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha } if (!context->handle) { - if ((context->handle = sf_open(path, mode, &context->sfinfo)) == 0) { + if (sndfile_perform_open(context, path, mask, mode) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s] [%s]\n", path, sf_strerror(context->handle)); status = SWITCH_STATUS_GENERR; goto end; @@ -236,6 +241,20 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha return status; } +static switch_status_t sndfile_perform_open(sndfile_context *context, const char *path, const char *mask, int mode) +{ + FILE *fd = NULL; + fd = fopen(path, mask); + if (!fd) { + return SWITCH_STATUS_FALSE; + } + if ((context->handle = sf_open_fd(fileno(fd), mode, &context->sfinfo, SWITCH_TRUE)) == 0) { + fclose(fd); + return SWITCH_STATUS_FALSE; + } + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t sndfile_file_truncate(switch_file_handle_t *handle, int64_t offset) { sndfile_context *context = handle->private_info; From 0cf770a8367e793d67cd7607cd66886d1d65fbcd Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Mon, 17 Nov 2014 09:27:22 -0500 Subject: [PATCH 85/91] FS-6996: #resolve fix define change as of glibc 2.20 for _BSD_SOURCE -> _DEFAULT_SOURCE --- libs/freetdm/src/ftdm_backtrace.c | 3 +++ libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 3 +++ libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 3 +++ libs/libnatpmp/natpmp.c | 3 +++ libs/xmlrpc-c/lib/abyss/src/conf.c | 3 +++ libs/xmlrpc-c/lib/abyss/src/http.c | 3 +++ libs/xmlrpc-c/lib/abyss/src/server.c | 3 +++ src/include/switch.h | 3 +++ 8 files changed, 24 insertions(+) diff --git a/libs/freetdm/src/ftdm_backtrace.c b/libs/freetdm/src/ftdm_backtrace.c index b27c8ebbe8..8f6756d939 100644 --- a/libs/freetdm/src/ftdm_backtrace.c +++ b/libs/freetdm/src/ftdm_backtrace.c @@ -2,6 +2,9 @@ * * */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE #include "private/ftdm_core.h" diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 026b7b17df..2dea680987 100755 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -38,6 +38,9 @@ */ #ifdef __linux__ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #ifndef _BSD_SOURCE #define _BSD_SOURCE /* for strsep() */ #endif diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index ca60e30352..0e8b73e9c0 100755 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -40,6 +40,9 @@ * */ #ifdef WP_DEBUG_IO +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE #include #endif diff --git a/libs/libnatpmp/natpmp.c b/libs/libnatpmp/natpmp.c index c79e92bdfd..d2ff9d5fd3 100644 --- a/libs/libnatpmp/natpmp.c +++ b/libs/libnatpmp/natpmp.c @@ -15,6 +15,9 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef __linux__ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE 1 #endif #include diff --git a/libs/xmlrpc-c/lib/abyss/src/conf.c b/libs/xmlrpc-c/lib/abyss/src/conf.c index e0feff9f6b..891aa96c1c 100644 --- a/libs/xmlrpc-c/lib/abyss/src/conf.c +++ b/libs/xmlrpc-c/lib/abyss/src/conf.c @@ -34,6 +34,9 @@ #define _XOPEN_SOURCE 600 /* For strdup() */ #define _BSD_SOURCE /* For xmlrpc_strcaseeq */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #include #include diff --git a/libs/xmlrpc-c/lib/abyss/src/http.c b/libs/xmlrpc-c/lib/abyss/src/http.c index 4f9ef10118..c4269e21cd 100644 --- a/libs/xmlrpc-c/lib/abyss/src/http.c +++ b/libs/xmlrpc-c/lib/abyss/src/http.c @@ -2,6 +2,9 @@ #define _XOPEN_SOURCE 600 /* For strdup() */ #define _BSD_SOURCE /* For xmlrpc_strcaseeq() */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #include #include diff --git a/libs/xmlrpc-c/lib/abyss/src/server.c b/libs/xmlrpc-c/lib/abyss/src/server.c index 392f36813a..6337dcfd78 100644 --- a/libs/xmlrpc-c/lib/abyss/src/server.c +++ b/libs/xmlrpc-c/lib/abyss/src/server.c @@ -2,6 +2,9 @@ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #define _BSD_SOURCE /* Make sure setgroups()is in */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #include #include diff --git a/src/include/switch.h b/src/include/switch.h index 2fda7e7ade..ca95045248 100644 --- a/src/include/switch.h +++ b/src/include/switch.h @@ -63,6 +63,9 @@ #ifndef _BSD_SOURCE #define _BSD_SOURCE #endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #endif #ifndef __BSD_VISIBLE #define __BSD_VISIBLE 1 From 6f660c3a10cbbc2df70f213ff4e8e7191a0693f8 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Mon, 17 Nov 2014 09:46:23 -0500 Subject: [PATCH 86/91] iksemel - remove support for SSLv23 in iks_proceed_tls (was a FS addition to iksemel). mod_rayo - updated to no longer support SSLv23 --- libs/iksemel/include/iksemel.h | 2 +- libs/iksemel/src/stream.c | 15 ++------------- src/mod/event_handlers/mod_rayo/xmpp_streams.c | 2 +- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/libs/iksemel/include/iksemel.h b/libs/iksemel/include/iksemel.h index 2b11070671..dc6df91022 100644 --- a/libs/iksemel/include/iksemel.h +++ b/libs/iksemel/include/iksemel.h @@ -226,7 +226,7 @@ void iks_disconnect (iksparser *prs); int iks_has_tls (void); int iks_is_secure (iksparser *prs); int iks_start_tls (iksparser *prs); -int iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, int use_ssl); +int iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file); int iks_start_sasl (iksparser *prs, enum ikssasltype type, char *username, char *pass); /***** jabber *****/ diff --git a/libs/iksemel/src/stream.c b/libs/iksemel/src/stream.c index 658c40207c..eda6cb0fe7 100644 --- a/libs/iksemel/src/stream.c +++ b/libs/iksemel/src/stream.c @@ -36,7 +36,6 @@ typedef unsigned __int32 uint32_t; #define SF_TRY_SECURE 2 #define SF_SECURE 4 #define SF_SERVER 8 -#define SF_SSLv23 16 struct stream_data { iksparser *prs; @@ -319,11 +318,7 @@ handshake (struct stream_data *data) SSL_load_error_strings(); if (data->flags & SF_SERVER) { - if (data->flags & SF_SSLv23) { - data->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - } else { - data->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); - } + data->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); if(!data->ssl_ctx) return IKS_NOMEM; if (SSL_CTX_use_certificate_file(data->ssl_ctx, data->cert_file, SSL_FILETYPE_PEM) <= 0) { @@ -985,7 +980,7 @@ iks_start_tls (iksparser *prs) } int -iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, int use_ssl) +iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file) { #ifdef HAVE_GNUTLS int ret; @@ -996,9 +991,6 @@ iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, in data->cert_file = iks_stack_strdup(data->s, cert_file, 0); data->key_file = iks_stack_strdup(data->s, key_file, 0); data->flags |= SF_TRY_SECURE | SF_SERVER; - if (use_ssl) { - data->flags |= SF_SSLv23; - } return handshake (data); #elif HAVE_SSL int ret; @@ -1009,9 +1001,6 @@ iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, in data->cert_file = iks_stack_strdup(data->s, cert_file, 0); data->key_file = iks_stack_strdup(data->s, key_file, 0); data->flags |= SF_TRY_SECURE | SF_SERVER; - if (use_ssl) { - data->flags |= SF_SSLv23; - } return handshake (data); #else return IKS_NET_NOTSUPP; diff --git a/src/mod/event_handlers/mod_rayo/xmpp_streams.c b/src/mod/event_handlers/mod_rayo/xmpp_streams.c index cf5aafb413..7fe27e22fb 100644 --- a/src/mod/event_handlers/mod_rayo/xmpp_streams.c +++ b/src/mod/event_handlers/mod_rayo/xmpp_streams.c @@ -450,7 +450,7 @@ static void xmpp_send_outbound_server_header(struct xmpp_stream *stream) static void on_stream_starttls(struct xmpp_stream *stream, iks *node) { /* wait for handshake to start */ - if (iks_proceed_tls(stream->parser, stream->context->cert_pem_file, stream->context->key_pem_file, 1) == IKS_OK) { + if (iks_proceed_tls(stream->parser, stream->context->cert_pem_file, stream->context->key_pem_file) == IKS_OK) { stream->state = XSS_SECURE; } else { stream->state = XSS_ERROR; From f198d82bacb67928ca61e0d2463b73a4456ac824 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Mon, 17 Nov 2014 10:29:39 -0500 Subject: [PATCH 87/91] FS-5666: [mod_redis] add ignore_connect_fail config setting to not kill the call when redis is down when using redis backend for limit --- src/mod/applications/mod_redis/mod_redis.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/mod/applications/mod_redis/mod_redis.c b/src/mod/applications/mod_redis/mod_redis.c index 5e84b196e9..1f8877b6a1 100644 --- a/src/mod/applications/mod_redis/mod_redis.c +++ b/src/mod/applications/mod_redis/mod_redis.c @@ -40,6 +40,7 @@ static struct{ char *host; int port; int timeout; + switch_bool_t ignore_connect_fail; } globals; static switch_xml_config_item_t instructions[] = { @@ -47,6 +48,7 @@ static switch_xml_config_item_t instructions[] = { SWITCH_CONFIG_ITEM_STRING_STRDUP("host", CONFIG_RELOAD, &globals.host, NULL, "localhost", "Hostname for redis server"), SWITCH_CONFIG_ITEM("port", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &globals.port, (void *) 6379, NULL,NULL, NULL), SWITCH_CONFIG_ITEM("timeout", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &globals.timeout, (void *) 10000, NULL,NULL, NULL), + SWITCH_CONFIG_ITEM("ignore_connect_fail", SWITCH_CONFIG_BOOL, CONFIG_RELOADABLE, &globals.ignore_connect_fail, SWITCH_FALSE, NULL, "true|false", "Set to true in order to continue when redis is not contactable"), SWITCH_CONFIG_ITEM_END() }; @@ -85,9 +87,14 @@ SWITCH_LIMIT_INCR(limit_incr_redis) REDIS redis; if (redis_factory(&redis) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; + if ( globals.ignore_connect_fail ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ignore_connect_fail=true, so ignoring the fact that redis was not contactabl and continuing with the call\n" ); + return SWITCH_STATUS_SUCCESS; + } else { + return SWITCH_STATUS_FALSE; + } } - + /* Get the keys for redis server */ uuid_rediskey = switch_core_session_sprintf(session,"%s_%s_%s", switch_core_get_switchname(), realm, resource); rediskey = switch_core_session_sprintf(session, "%s_%s", realm, resource); @@ -163,7 +170,13 @@ SWITCH_LIMIT_RELEASE(limit_release_redis) } if (redis_factory(&redis) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; + if ( globals.ignore_connect_fail ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ignore_connect_fail=true, so ignoring the fact that redis was not contactabl and continuing with the call\n" ); + return SWITCH_STATUS_SUCCESS; + } else { + return SWITCH_STATUS_FALSE; + } + } switch_mutex_lock(pvt->mutex); From 250234da76ce9438de15c59f8fde95dbb152e218 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Mon, 17 Nov 2014 11:01:35 -0500 Subject: [PATCH 88/91] FS-5800: [mod_curl] add support for additional curl auth methods --- src/mod/applications/mod_curl/mod_curl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c index 86e2924073..b5b49c0d7b 100644 --- a/src/mod/applications/mod_curl/mod_curl.c +++ b/src/mod/applications/mod_curl/mod_curl.c @@ -241,6 +241,7 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c } switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 15); + switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback); From 7c0da5cc404864a495fb5e2da872e2709621f4f1 Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 17 Nov 2014 10:36:03 -0600 Subject: [PATCH 89/91] FS-6957 fix regression --- src/mod/applications/mod_conference/mod_conference.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index c3885dbe79..1dfbe311d3 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -10331,6 +10331,8 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound); } + conference->mflags = MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR; + if (!zstr(moh_sound) && switch_is_moh(moh_sound)) { conference->moh_sound = switch_core_strdup(conference->pool, moh_sound); } From 424df190832b4ab2a1d4a2486d60e7572aa55c52 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Mon, 17 Nov 2014 15:25:39 -0500 Subject: [PATCH 90/91] FS-6695: fix build on mips --- libs/libzrtp/include/zrtp_config.h | 12 ++++++++++++ src/mod/codecs/mod_isac/typedefs.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/libs/libzrtp/include/zrtp_config.h b/libs/libzrtp/include/zrtp_config.h index 3f954fc836..0e2ee73b71 100644 --- a/libs/libzrtp/include/zrtp_config.h +++ b/libs/libzrtp/include/zrtp_config.h @@ -101,6 +101,18 @@ */ #define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN +#elif defined(__MIPSEB__) +/* + * mips, big endian + */ +#define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN + +#elif defined(__MIPSEL__) +/* + * mips, little endian + */ +#define ZRTP_BYTE_ORDER ZBO_LITTLE_ENDIAN + #endif /* Automatic byte order detection */ #endif diff --git a/src/mod/codecs/mod_isac/typedefs.h b/src/mod/codecs/mod_isac/typedefs.h index ba87309638..e4a85afe30 100644 --- a/src/mod/codecs/mod_isac/typedefs.h +++ b/src/mod/codecs/mod_isac/typedefs.h @@ -76,6 +76,10 @@ //#define WEBRTC_ARCH_ARMEL #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__MIPSEB__) +#define WEBRTC_ARCH_BIG_ENDIAN +#elif defined(__MIPSEL__) +#define WEBRTC_ARCH_LITTLE_ENDIAN #else #error Please add support for your architecture in typedefs.h #endif From 8eaaa083adf7091446c3e7338cc333c7ea7075bb Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 18 Nov 2014 09:47:43 -0600 Subject: [PATCH 91/91] FS-6622: [mod_shout] set buffer size for streams based on the number of channels to avoid buffer starvation --- src/mod/formats/mod_shout/mod_shout.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index 553ef4e889..e6ba9a94b2 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -123,6 +123,7 @@ struct shout_context { int lame_ready; int eof; int channels; + int stream_channels; int16_t *l; switch_size_t llen; int16_t *r; @@ -371,14 +372,25 @@ static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *data) shout_context_t *context = data; int decode_status = 0; size_t usedlen; - uint32_t buf_size = 1024 * 128; /* do not make this 64 or less, stutter will ensue after - first 64k buffer is dry */ + uint32_t buf_size = 1024 * 128; /* do not make this 64 or less, stutter will ensue after first 64k buffer is dry */ switch_size_t used; + if (!context->stream_channels) { + long rate = 0; + int channels = 0; + int encoding = 0; + mpg123_getformat(context->mh, &rate, &channels, &encoding); + context->stream_channels = channels; + } + if (context->prebuf) { buf_size = context->prebuf; } + if (context->stream_channels) { + buf_size = buf_size * context->stream_channels; + } + /* make sure we aren't over zealous by slowing down the stream when the buffer is too full */ while (!context->err) { switch_mutex_lock(context->audio_mutex);