diff --git a/conf/autoload_configs/event_multicast.conf.xml b/conf/autoload_configs/event_multicast.conf.xml index b362ebc459..eac0392607 100644 --- a/conf/autoload_configs/event_multicast.conf.xml +++ b/conf/autoload_configs/event_multicast.conf.xml @@ -4,6 +4,7 @@ + diff --git a/conf/autoload_configs/mongo.conf.xml b/conf/autoload_configs/mongo.conf.xml index a7fdecae8d..ff8daed72a 100644 --- a/conf/autoload_configs/mongo.conf.xml +++ b/conf/autoload_configs/mongo.conf.xml @@ -3,5 +3,12 @@ + + + diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml index dd426b089a..d8fa55c8cb 100644 --- a/libs/freetdm/conf/freetdm.conf.xml +++ b/libs/freetdm/conf/freetdm.conf.xml @@ -75,6 +75,11 @@ with the signaling protocols that you can run on top of your I/O interfaces. --> + + + diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index c3ca4786d5..9d6eac94f5 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3021,6 +3021,7 @@ static switch_status_t load_config(void) const char *enable_callerid = "true"; const char *answer_polarity = "false"; const char *hangup_polarity = "false"; + const char *polarity_callerid = "false"; int polarity_delay = 600; int callwaiting = 1; int dialtone_timeout = 5000; @@ -3102,6 +3103,8 @@ static switch_status_t load_config(void) hangup_polarity = val; } else if (!strcasecmp(var, "polarity-delay")) { polarity_delay = atoi(val); + } else if (!strcasecmp(var, "polarity-callerid")) { + polarity_callerid = val; } else if (!strcasecmp(var, "fail-dial-regex")) { fail_dial_regex = val; } else if (!strcasecmp(var, "hold-music")) { @@ -3164,6 +3167,7 @@ static switch_status_t load_config(void) "enable_callerid", enable_callerid, "answer_polarity_reverse", answer_polarity, "hangup_polarity_reverse", hangup_polarity, + "polarity_callerid", polarity_callerid, "polarity_delay", &polarity_delay, "callwaiting", &callwaiting, "wait_dialtone_timeout", &dialtone_timeout, diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h index 39cbc5ff2b..a2339120c5 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h @@ -39,7 +39,8 @@ typedef enum { FTDM_ANALOG_RUNNING = (1 << 0), FTDM_ANALOG_CALLERID = (1 << 1), FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2), - FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3) + FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3), + FTDM_ANALOG_POLARITY_CALLERID = (1 << 4) } ftdm_analog_flag_t; #define FTDM_MAX_HOTLINE_STR 20 diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c index 27eecb4f7f..85da471739 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c @@ -275,6 +275,15 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) break; } hotline = val; + } else if (!strcasecmp(var, "polarity_callerid")) { + if (!(val = va_arg(ap, char *))) { + break; + } + if (ftdm_true(val)) { + flags |= FTDM_ANALOG_POLARITY_CALLERID; + } else { + flags &= ~FTDM_ANALOG_POLARITY_CALLERID; + } } else { ftdm_log(FTDM_LOG_ERROR, "Unknown parameter %s in span %s\n", var, span->name); } @@ -1130,8 +1139,18 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e break; } if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) { - ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, - "Ignoring polarity reversal because this channel is down\n"); + if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID) + && ftdm_test_flag(analog_data, FTDM_ANALOG_POLARITY_CALLERID)) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, "Polarity reversal detected while down, getting caller id now\n"); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID); + event->channel->ring_count = 1; + ftdm_mutex_unlock(event->channel->mutex); + locked = 0; + ftdm_thread_create_detached(ftdm_analog_channel_run, event->channel); + } else { + ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, + "Ignoring polarity reversal because this channel is down\n"); + } break; } /* we have a good channel, set the polarity flag and let the channel thread deal with it */ diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c index 982412d334..4e7914685b 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -29,6 +29,12 @@ * 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. + * + * Contributors: + * + * Moises Silva + * W McRoberts + * */ #include "private/ftdm_core.h" @@ -94,6 +100,7 @@ struct ioctl_codes { ioctlcmd ECHOTRAIN; ioctlcmd SETTXBITS; ioctlcmd GETRXBITS; + ioctlcmd SETPOLARITY; }; /** @@ -169,7 +176,8 @@ static struct ioctl_codes dahdi_ioctl_codes = { .GETCONFMUTE = DAHDI_GETCONFMUTE, .ECHOTRAIN = DAHDI_ECHOTRAIN, .SETTXBITS = DAHDI_SETTXBITS, - .GETRXBITS = DAHDI_GETRXBITS + .GETRXBITS = DAHDI_GETRXBITS, + .SETPOLARITY = DAHDI_SETPOLARITY }; #define ZT_INVALID_SOCKET -1 @@ -826,6 +834,15 @@ static FIO_COMMAND_FUNCTION(zt_command) err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode); } break; + case FTDM_COMMAND_SET_POLARITY: + { + ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT; + err = ioctl(ftdmchan->sockfd, codes.SETPOLARITY, polarity); + if (!err) { + ftdmchan->polarity = polarity; + } + } + break; case FTDM_COMMAND_FLUSH_RX_BUFFERS: { int flushmode = ZT_FLUSH_READ; @@ -1088,6 +1105,12 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, *event_id = FTDM_OOB_NOOP; /* What else could we do? */ } break; + case ZT_EVENT_POLARITY: + { + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Got polarity reverse (ZT_EVENT_POLARITY)\n"); + *event_id = FTDM_OOB_POLARITY_REVERSE; + } + break; case ZT_EVENT_NONE: { ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "No event\n"); diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h index cf5479dba1..065d7e63e2 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h @@ -29,6 +29,12 @@ * 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. + * + * Contributors: + * + * Moises Silva + * W McRoberts + * */ #ifndef FTDM_ZT_H @@ -349,6 +355,7 @@ ZT_ABIT = 8 #define DAHDI_SETTXBITS _IOW (DAHDI_CODE, 43, int) #define DAHDI_GETRXBITS _IOR (DAHDI_CODE, 43, int) +#define DAHDI_SETPOLARITY _IOW (DAHDI_CODE, 92, int) /* Polarity setting for FXO lines */ #endif diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 0948f16e29..238314c560 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -926,20 +926,20 @@ typedef enum { /*! \brief IO statistics */ typedef struct { struct { + uint64_t packets; uint32_t errors; uint16_t flags; uint8_t queue_size; /*!< max queue size configured */ uint8_t queue_len; /*!< Current number of elements in queue */ - uint64_t packets; } rx; struct { + uint64_t idle_packets; + uint64_t packets; uint32_t errors; uint16_t flags; - uint8_t idle_packets; uint8_t queue_size; /*!< max queue size configured */ uint8_t queue_len; /*!< Current number of elements in queue */ - uint64_t packets; } tx; } ftdm_channel_iostats_t; diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index d62db97e13..39e6380399 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -3084,8 +3084,10 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session, } } - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", user); - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain); + if (var_event) { + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", user); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain); + } if (!dest) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No dial-string available, please check your user directory.\n"); diff --git a/src/mod/applications/mod_lcr/mod_lcr.c b/src/mod/applications/mod_lcr/mod_lcr.c index c0d99dfc35..a12f9a0ed6 100644 --- a/src/mod/applications/mod_lcr/mod_lcr.c +++ b/src/mod/applications/mod_lcr/mod_lcr.c @@ -127,6 +127,7 @@ struct callback_obj { int matches; switch_memory_pool_t *pool; char *lookup_number; + char *lrn_number; char *cid; switch_bool_t intrastate; switch_bool_t intralata; @@ -622,6 +623,8 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa additional->carrier_name = switch_core_strdup(pool, switch_str_nil(argv[i])); } else if (CF("lcr_rate_field")) { if (!argv[i] || zstr(argv[i])) { + /* maybe we want to consider saying which carriers have null rate fields... maybe they can run the query and find out */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "rate field is null, skipping\n"); goto end; } additional->rate = (float)atof(switch_str_nil(argv[i])); @@ -798,7 +801,7 @@ static switch_status_t is_intrastatelata(callback_t *cb_struct) cb_struct->lookup_number+1, cb_struct->lookup_number+4, cb_struct->cid+1, cb_struct->cid+4); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", sql); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", sql); return(lcr_execute_sql_callback(sql, intrastatelata_callback, cb_struct)); @@ -808,8 +811,9 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct) { switch_stream_handle_t sql_stream = { 0 }; char *digits = cb_struct->lookup_number; - char *digits_copy; - char *digits_expanded; + char *digits_copy = NULL; + char *digits_expanded = NULL; + char *lrn_digits_expanded = NULL; profile_t *profile = cb_struct->profile; switch_bool_t lookup_status; switch_channel_t *channel; @@ -832,6 +836,11 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct) } digits_expanded = expand_digits(cb_struct->pool, digits_copy, cb_struct->profile->quote_in_list); + if (cb_struct->lrn_number) { + lrn_digits_expanded = expand_digits(cb_struct->pool, cb_struct->lrn_number, cb_struct->profile->quote_in_list); + } else { + lrn_digits_expanded = switch_core_strdup(cb_struct->pool, digits_expanded); + } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "Has NPA NXX: [%u == %u]\n", profile->profile_has_npanxx, SWITCH_TRUE); if (profile->profile_has_npanxx == SWITCH_TRUE) { @@ -866,6 +875,10 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct) id_str = switch_core_sprintf(cb_struct->pool, "%d", cb_struct->profile->id); switch_channel_set_variable_var_check(channel, "lcr_query_profile", id_str, SWITCH_FALSE); switch_channel_set_variable_var_check(channel, "lcr_query_expanded_digits", digits_expanded, SWITCH_FALSE); + switch_channel_set_variable_var_check(channel, "lcr_query_expanded_lrn_digits", lrn_digits_expanded, SWITCH_FALSE); + if ( cb_struct->lrn_number ) { + switch_channel_set_variable_var_check(channel, "lcr_lrn", cb_struct->lrn_number, SWITCH_FALSE); + } } } if (cb_struct->event) { @@ -876,6 +889,10 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct) id_str = switch_core_sprintf(cb_struct->pool, "%d", cb_struct->profile->id); switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_query_profile", id_str); switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_query_expanded_digits", digits_expanded); + switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_query_expanded_lrn_digits", lrn_digits_expanded); + if ( cb_struct->lrn_number ) { + switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_lrn", cb_struct->lrn_number); + } } /* set up the query to be executed */ @@ -998,7 +1015,7 @@ static switch_status_t lcr_load_config() char *export_fields = NULL; char *limit_type = NULL; int argc, x = 0; - char *argv[4] = { 0 }; + char *argv[32] = { 0 }; SWITCH_STANDARD_STREAM(order_by); @@ -1078,29 +1095,48 @@ static switch_status_t lcr_load_config() SWITCH_STANDARD_STREAM(sql_stream); if (zstr(custom_sql)) { /* use default sql */ + + /* Checking for codec field, adding if needed */ + if (db_check("SELECT codec FROM carrier_gateway LIMIT 1") == SWITCH_TRUE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec field defined.\n"); + } else { + if (db_check("ALTER TABLE carrier_gateway add codec varchar(255);") == SWITCH_TRUE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "adding codec field your lcr carrier_gateway database schema.\n"); + } else { + return SWITCH_FALSE; + } + } + + /* Checking for cid field, adding if needed */ + if (db_check("SELECT cid FROM lcr LIMIT 1") == SWITCH_TRUE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cid field defined.\n"); + } else { + if (db_check("ALTER TABLE lcr add cid varchar(32);") == SWITCH_TRUE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "adding cid field to your lcr database schema.\n"); + } else { + return SWITCH_FALSE; + } + } + + if (db_check("SELECT lrn FROM lcr LIMIT 1") != SWITCH_TRUE) { + if (db_check("ALTER TABLE lcr ADD lrn BOOLEAN NOT NULL DEFAULT false")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "adding lrn field to your lcr database schema.\n"); + } else { + return SWITCH_FALSE; + } + } + sql_stream.write_function(&sql_stream, "SELECT l.digits AS lcr_digits, c.carrier_name AS lcr_carrier_name, l.${lcr_rate_field} AS lcr_rate_field, \ cg.prefix AS lcr_gw_prefix, cg.suffix AS lcr_gw_suffix, l.lead_strip AS lcr_lead_strip, \ - l.trail_strip AS lcr_trail_strip, l.prefix AS lcr_prefix, l.suffix AS lcr_suffix " - ); - if (db_check("SELECT codec from carrier_gateway limit 1") == SWITCH_TRUE) { - sql_stream.write_function(&sql_stream, ", cg.codec AS lcr_codec "); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec field defined.\n"); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "codec field not defined, please update your lcr carrier_gateway database schema.\n" - ); - } - if (db_check("SELECT cid from lcr limit 1") == SWITCH_TRUE) { - sql_stream.write_function(&sql_stream, ", l.cid AS lcr_cid "); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cid field defined.\n"); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cid field not defined, please update your lcr database schema.\n"); - } + l.trail_strip AS lcr_trail_strip, l.prefix AS lcr_prefix, l.suffix AS lcr_suffix, \ + cg.codec AS lcr_codec, l.cid AS lcr_cid "); sql_stream.write_function(&sql_stream, "FROM lcr l JOIN carriers c ON l.carrier_id=c.id \ - JOIN carrier_gateway cg ON c.id=cg.carrier_id WHERE \ - c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND digits IN ("); - sql_stream.write_function(&sql_stream, "${lcr_query_expanded_digits}"); + JOIN carrier_gateway cg ON c.id=cg.carrier_id \ + WHERE c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND (\ + (digits IN (${lcr_query_expanded_digits}) AND lrn = false) OR \ + (digits IN (${lcr_query_expanded_lrn_digits}) AND lrn = true)"); + sql_stream.write_function(&sql_stream, ") AND CURRENT_TIMESTAMP BETWEEN date_start AND date_end "); if (profile->id > 0) { sql_stream.write_function(&sql_stream, "AND lcr_profile=%d ", profile->id); @@ -1430,6 +1466,7 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt) switch_event_t *event = NULL; const char *intrastate = NULL; const char *intralata = NULL; + const char *lrn = NULL; if (session) { pool = switch_core_session_get_pool(session); @@ -1443,8 +1480,12 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt) intrastate = switch_channel_get_variable(channel, "intrastate"); intralata = switch_channel_get_variable(channel, "intralata"); + lrn = switch_channel_get_variable(channel, "lrn"); + routes.lrn_number = (char *) lrn; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", intrastate); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intralata channel var is [%s]\n", intralata); + if (!zstr(intralata) && !strcasecmp((char *)intralata, "true")) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on intralata rates\n"); routes.intralata = SWITCH_FALSE; @@ -1531,7 +1572,7 @@ void str_repeat(size_t how_many, char *what, switch_stream_handle_t *str_stream) SWITCH_STANDARD_APP(lcr_app_function) { int argc = 0; - char *argv[4] = { 0 }; + char *argv[32] = { 0 }; char *mydata = NULL; char *dest = NULL; char vbuf[1024] = ""; @@ -1544,6 +1585,7 @@ SWITCH_STANDARD_APP(lcr_app_function) switch_memory_pool_t *pool; switch_event_t *event; const char *intra = NULL; + const char *lrn = NULL; if (!(mydata = switch_core_session_strdup(session, data))) { return; @@ -1557,11 +1599,15 @@ SWITCH_STANDARD_APP(lcr_app_function) switch_event_create(&event, SWITCH_EVENT_MESSAGE); routes.event = event; } + routes.pool = pool; + + lrn = switch_channel_get_variable(channel, "lrn"); + routes.lrn_number = (char *) lrn; + intra = switch_channel_get_variable(channel, "intrastate"); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", - zstr(intra) ? "undef" : intra); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", zstr(intra) ? "undef" : intra); if (zstr(intra) || strcasecmp((char *)intra, "true")) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on interstate rates\n"); routes.intrastate = SWITCH_FALSE; @@ -1578,6 +1624,7 @@ SWITCH_STANDARD_APP(lcr_app_function) if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { dest = argv[0]; + if (argc > 1) { lcr_profile = argv[1]; } @@ -1664,21 +1711,20 @@ static void write_data(switch_stream_handle_t *stream, switch_bool_t as_xml, con SWITCH_STANDARD_API(dialplan_lcr_function) { - char *argv[9] = { 0 }; + char *argv[32] = { 0 }; int argc; - char *mydata = NULL; - //char *dialstring = NULL; - char *lcr_profile = NULL; - lcr_route current = NULL; - max_obj_t maximum_lengths = { 0 }; - callback_t cb_struct = { 0 }; - switch_memory_pool_t *pool = NULL; + char *mydata = NULL; + char *lcr_profile = NULL; + lcr_route current = NULL; + max_obj_t maximum_lengths = { 0 }; + callback_t cb_struct = { 0 }; + switch_memory_pool_t *pool = NULL; switch_event_t *event; switch_status_t lookup_status = SWITCH_STATUS_SUCCESS; - switch_bool_t as_xml = SWITCH_FALSE; - char *event_str = NULL; - switch_xml_t event_xml = NULL; - int rowcount=0; + switch_bool_t as_xml = SWITCH_FALSE; + char *event_str = NULL; + switch_xml_t event_xml = NULL; + int rowcount = 0; if (zstr(cmd)) { goto usage; @@ -1708,10 +1754,18 @@ SWITCH_STANDARD_API(dialplan_lcr_function) } if (argc > 2) { int i; - for (i=2; i #include "mod_mongo.h" +#define DELIMITER ';' +#define FIND_ONE_SYNTAX "mongo_find_one ns; query; fields" +#define MAPREDUCE_SYNTAX "mongo_mapreduce ns; query" static struct { mongo_connection_pool_t *conn_pool; + char *map; + char *reduce; + char *finalize; } globals; +SWITCH_STANDARD_API(mongo_mapreduce_function) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + DBClientConnection *conn = NULL; + char *ns = NULL, *json_query = NULL; + + ns = strdup(cmd); + switch_assert(ns != NULL); + + if ((json_query = strchr(ns, DELIMITER))) { + *json_query++ = '\0'; + } + + if (!zstr(ns) && !zstr(json_query)) { + try { + BSONObj query = fromjson(json_query); + BSONObj out; + BSONObjBuilder cmd; + + cmd.append("mapreduce", conn->nsGetCollection(ns)); + if (!zstr(globals.map)) { + cmd.appendCode("map", globals.map); + } + if (!zstr(globals.reduce)) { + cmd.appendCode("reduce", globals.reduce); + } + if (!zstr(globals.finalize)) { + cmd.appendCode("finalize", globals.finalize); + } + if(!query.isEmpty()) { + cmd.append("query", query); + } + cmd.append("out", BSON("inline" << 1)); + + conn = mongo_connection_pool_get(globals.conn_pool); + if (conn) { + conn->runCommand(conn->nsGetDB(ns), cmd.done(), out); + mongo_connection_pool_put(globals.conn_pool, conn); + + stream->write_function(stream, "-OK\n%s\n", out.toString().c_str()); + } else { + stream->write_function(stream, "-ERR\nNo connection\n"); + } + } catch (DBException &e) { + if (conn) { + mongo_connection_destroy(&conn); + } + stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str()); + } + } else { + stream->write_function(stream, "-ERR\n%s\n", MAPREDUCE_SYNTAX); + } + + switch_safe_free(ns); + + return status; +} -static const char *SYNTAX = "mongo_find_one ns; query; fields"; SWITCH_STANDARD_API(mongo_find_one_function) { switch_status_t status = SWITCH_STATUS_SUCCESS; char *ns = NULL, *json_query = NULL, *json_fields = NULL; - char delim = ';'; ns = strdup(cmd); switch_assert(ns != NULL); - if ((json_query = strchr(ns, delim))) { + if ((json_query = strchr(ns, DELIMITER))) { *json_query++ = '\0'; - if ((json_fields = strchr(json_query, delim))) { + if ((json_fields = strchr(json_query, DELIMITER))) { *json_fields++ = '\0'; } } @@ -49,9 +110,8 @@ SWITCH_STANDARD_API(mongo_find_one_function) stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str()); } - } else { - stream->write_function(stream, "-ERR\n%s\n", SYNTAX); + stream->write_function(stream, "-ERR\n%s\n", FIND_ONE_SYNTAX); } switch_safe_free(ns); @@ -88,6 +148,12 @@ static switch_status_t config(void) if ((tmp = atoi(val)) > 0) { max_connections = tmp; } + } else if (!strcmp(var, "map")) { + globals.map = strdup(val); + } else if (!strcmp(var, "reduce")) { + globals.reduce = strdup(val); + } else if (!strcmp(var, "finalize")) { + globals.finalize = strdup(val); } } } @@ -125,7 +191,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load) return SWITCH_STATUS_TERM; } - SWITCH_ADD_API(api_interface, "mongo_find_one", "mongo", mongo_find_one_function, SYNTAX); + SWITCH_ADD_API(api_interface, "mongo_find_one", "findOne", mongo_find_one_function, FIND_ONE_SYNTAX); + SWITCH_ADD_API(api_interface, "mongo_mapreduce", "Map/Reduce", mongo_mapreduce_function, MAPREDUCE_SYNTAX); return SWITCH_STATUS_SUCCESS; } @@ -133,6 +200,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mongo_shutdown) { mongo_connection_pool_destroy(&globals.conn_pool); + switch_safe_free(globals.map); + switch_safe_free(globals.reduce); + switch_safe_free(globals.finalize); + return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c index 97684b6f10..17f0b91e7a 100644 --- a/src/mod/endpoints/mod_loopback/mod_loopback.c +++ b/src/mod/endpoints/mod_loopback/mod_loopback.c @@ -802,15 +802,20 @@ static switch_status_t loopback_bowout_on_execute_state_handler(switch_core_sess switch_core_session_read_lock(tech_pvt->other_session); b_channel = switch_core_session_get_channel(tech_pvt->other_session); + /* Wait for b_channel to be fully bridged */ + switch_channel_wait_for_flag(b_channel, CF_BRIDGED, SWITCH_TRUE, 5000, NULL); + uuid = switch_channel_get_variable(b_channel, SWITCH_SIGNAL_BOND_VARIABLE); if (uuid && (other_session = switch_core_session_locate(uuid))) { switch_channel_t *other_channel = switch_core_session_get_channel(other_session); switch_caller_profile_t *cp, *clone; - + + switch_channel_wait_for_state(other_channel, NULL, CS_EXCHANGE_MEDIA); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->other_session), SWITCH_LOG_INFO, "Replacing loopback channel: %s with real channel: %s\n", switch_channel_get_name(b_channel), switch_channel_get_name(other_channel)); - + if ((cp = switch_channel_get_caller_profile(channel))) { clone = switch_caller_profile_clone(other_session, cp); clone->originator_caller_profile = NULL; @@ -831,7 +836,7 @@ static switch_status_t loopback_bowout_on_execute_state_handler(switch_core_sess switch_core_session_rwunlock(tech_pvt->other_session); switch_core_event_hook_remove_state_change(session, loopback_bowout_on_execute_state_handler); - + } return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index bc4c19b614..04a3011d72 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -1324,7 +1324,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load) globals.read_frame.buflen = sizeof(globals.databuf); globals.cng_frame.data = globals.cngbuf; globals.cng_frame.buflen = sizeof(globals.cngbuf); - globals.cng_frame.datalen = switch_samples_per_packet(globals.sample_rate, globals.codec_ms) * 2; switch_set_flag((&globals.cng_frame), SFF_CNG); globals.flags = GFLAG_EAR | GFLAG_MOUTH; /* dual streams makes portaudio on solaris choke */ @@ -1750,6 +1749,8 @@ static switch_status_t load_config(void) globals.codec_ms = 20; } + globals.cng_frame.datalen = switch_samples_per_packet(globals.sample_rate, globals.codec_ms) * 2; + if (!globals.ring_interval) { globals.ring_interval = 5; } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index a7bd1e6843..190212a22b 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -321,7 +321,7 @@ typedef enum { TFLAG_MAX } TFLAGS; -#define SOFIA_MAX_MSG_QUEUE 51 +#define SOFIA_MAX_MSG_QUEUE 101 #define SOFIA_MSG_QUEUE_SIZE 5000 struct mod_sofia_globals { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 318ca29b7b..c225b2bf35 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1145,6 +1145,7 @@ void *SWITCH_THREAD_FUNC sofia_msg_thread_run(switch_thread_t *thread, void *obj while(switch_queue_pop(q, &pop) == SWITCH_STATUS_SUCCESS && pop) { sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) pop; sofia_process_dispatch_event(&de); + switch_cond_next(); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MSG Thread Ended\n"); @@ -1175,7 +1176,7 @@ static void sofia_msg_thread_start(int idx) switch_threadattr_create(&thd_attr, mod_sofia_globals.pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_threadattr_priority_increase(thd_attr); + //switch_threadattr_priority_increase(thd_attr); switch_thread_create(&mod_sofia_globals.msg_queue_thread[i], thd_attr, sofia_msg_thread_run, diff --git a/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c b/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c index 2c0b927c0f..f0635275f6 100644 --- a/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c +++ b/src/mod/event_handlers/mod_event_multicast/mod_event_multicast.c @@ -61,6 +61,7 @@ static struct { char *psk; switch_mutex_t *mutex; switch_hash_t *peer_hash; + int loopback; } globals; struct peer_status { @@ -88,6 +89,7 @@ static switch_status_t load_config(void) globals.ttl = 1; globals.key_count = 0; + globals.loopback = 0; if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf); @@ -119,6 +121,8 @@ static switch_status_t load_config(void) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid ttl '%s' specified, using default of 1\n", val); } + } else if (!strcasecmp(var, "loopback")) { + globals.loopback = switch_true(val); } } @@ -408,8 +412,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_event_multicast_load) switch_goto_status(SWITCH_STATUS_TERM, fail); } - if (switch_mcast_loopback(globals.udp_socket, 0) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to disable loopback\n"); + if (switch_mcast_loopback(globals.udp_socket, globals.loopback) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set loopback to '%d'\n", globals.loopback); switch_goto_status(SWITCH_STATUS_TERM, fail); } diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index 4ac6790933..bc72038db5 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -53,6 +53,9 @@ static struct { char decoder[256]; float vol; uint32_t outscale; + uint32_t brate; + uint32_t resample; + uint32_t quality; } globals; mpg123_handle *our_mpg123_new(const char *decoder, int *error) @@ -172,7 +175,7 @@ static inline void free_context(shout_context_t *context) } if (context->fp) { - unsigned char mp3buffer[8192]; + unsigned char mp3buffer[20480]; int len; int16_t blank[2048] = { 0 }, *r = NULL; @@ -494,7 +497,7 @@ static void *SWITCH_THREAD_FUNC write_stream_thread(switch_thread_t *thread, voi } while (!context->err && context->thread_running) { - unsigned char mp3buf[8192] = ""; + unsigned char mp3buf[20480] = ""; int16_t audio[9600] = { 0 }; switch_size_t audio_read = 0; int rlen = 0; @@ -667,17 +670,33 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char } context->channels = handle->channels; - lame_set_brate(context->gfp, 16 * (handle->samplerate / 8000) * handle->channels); + + if (globals.brate) { + lame_set_brate(context->gfp, globals.brate); + } else { + lame_set_brate(context->gfp, 16 * (handle->samplerate / 8000) * handle->channels); + } + lame_set_num_channels(context->gfp, handle->channels); lame_set_in_samplerate(context->gfp, handle->samplerate); - lame_set_out_samplerate(context->gfp, handle->samplerate); + + if (globals.resample) { + lame_set_out_samplerate(context->gfp, globals.resample); + } else { + lame_set_out_samplerate(context->gfp, handle->samplerate); + } if (handle->channels == 2) { lame_set_mode(context->gfp, STEREO); } else { lame_set_mode(context->gfp, MONO); } - lame_set_quality(context->gfp, 2); /* 2=high 5 = medium 7=low */ + + if (globals.quality) { + lame_set_quality(context->gfp, globals.quality); + } else { + lame_set_quality(context->gfp, 2); /* 2=high 5 = medium 7=low */ + } lame_set_errorf(context->gfp, log_error); lame_set_debugf(context->gfp, log_debug); @@ -1464,6 +1483,21 @@ static switch_status_t load_config(void) if (tmp > 0) { globals.outscale = tmp; } + } else if (!strcmp(var, "encode-brate")) { + int tmp = atoi(val); + if (tmp > 0) { + globals.brate = tmp; + } + } else if (!strcmp(var, "encode-resample")) { + int tmp = atoi(val); + if (tmp > 0) { + globals.resample = tmp; + } + } else if (!strcmp(var, "encode-quality")) { + int tmp = atoi(val); + if (tmp > 0) { + globals.quality = tmp; + } } } } diff --git a/src/switch_channel.c b/src/switch_channel.c index 7dd43672a9..4f272db7e2 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2842,10 +2842,6 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_ switch_channel_set_flag(channel, CF_EARLY_MEDIA); switch_channel_set_callstate(channel, CCS_EARLY); switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA"); - if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_data(channel, event); - switch_event_fire(&event); - } if (channel->caller_profile && channel->caller_profile->times) { switch_mutex_lock(channel->profile_mutex); @@ -2865,6 +2861,11 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_ switch_mutex_unlock(channel->profile_mutex); } + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + switch_channel_execute_on(channel, SWITCH_CHANNEL_EXECUTE_ON_PRE_ANSWER_VARIABLE); switch_channel_execute_on(channel, SWITCH_CHANNEL_EXECUTE_ON_MEDIA_VARIABLE); diff --git a/src/switch_core.c b/src/switch_core.c index e7cd60d58f..12850ce998 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -81,6 +81,7 @@ static void send_heartbeat(void) duration.ms, duration.ms == 1 ? "" : "s", duration.mms, duration.mms == 1 ? "" : "s"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Count", "%u", switch_core_session_count()); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Max-Sessions", "%u", switch_core_session_limit(0)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Per-Sec", "%u", runtime.sps); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Since-Startup", "%" SWITCH_SIZE_T_FMT, switch_core_session_id() - 1); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Idle-CPU", "%f", switch_core_idle_cpu()); diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index a55d3ee905..b23d082bdf 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1936,8 +1936,8 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ { char *err; switch_cache_db_test_reactive(dbh, "select call_uuid, read_bit_rate from channels", "DROP TABLE channels", create_channels_sql); - switch_cache_db_test_reactive(dbh, "select * from detailed_calls", "DROP VIEW detailed_calls", detailed_calls_sql); - switch_cache_db_test_reactive(dbh, "select * from basic_calls", "DROP VIEW basic_call", basic_calls_sql); + switch_cache_db_test_reactive(dbh, "select * from detailed_calls where sent_callee_name=''", "DROP VIEW detailed_calls", detailed_calls_sql); + switch_cache_db_test_reactive(dbh, "select * from basic_calls where sent_callee_name=''", "DROP VIEW basic_calls", basic_calls_sql); if (runtime.odbc_dbtype == DBTYPE_DEFAULT) { switch_cache_db_test_reactive(dbh, "select call_uuid from calls", "DROP TABLE calls", create_calls_sql); } else { diff --git a/src/switch_event.c b/src/switch_event.c index 629e67e9c3..b469b9f7b7 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -45,7 +45,7 @@ struct switch_event_node { /*! the event id enumeration to bind to */ switch_event_types_t event_id; /*! the event subclass to bind to for custom events */ - switch_event_subclass_t *subclass; + char *subclass_name; /*! a callback function to execute when the event is triggered */ switch_event_callback_t callback; /*! private data */ @@ -205,28 +205,28 @@ static int switch_events_match(switch_event_t *event, switch_event_node_t *node) if (node->event_id == SWITCH_EVENT_ALL) { match++; - if (!node->subclass) { + if (!node->subclass_name) { return match; } } if (match || event->event_id == node->event_id) { - if (event->subclass_name && node->subclass) { - if (!strncasecmp(node->subclass->name, "file:", 5)) { + if (event->subclass_name && node->subclass_name) { + if (!strncasecmp(node->subclass_name, "file:", 5)) { char *file_header; if ((file_header = switch_event_get_header(event, "file")) != 0) { - match = strstr(node->subclass->name + 5, file_header) ? 1 : 0; + match = strstr(node->subclass_name + 5, file_header) ? 1 : 0; } - } else if (!strncasecmp(node->subclass->name, "func:", 5)) { + } else if (!strncasecmp(node->subclass_name, "func:", 5)) { char *func_header; if ((func_header = switch_event_get_header(event, "function")) != 0) { - match = strstr(node->subclass->name + 5, func_header) ? 1 : 0; + match = strstr(node->subclass_name + 5, func_header) ? 1 : 0; } - } else if (event->subclass_name && node->subclass->name) { - match = strstr(event->subclass_name, node->subclass->name) ? 1 : 0; + } else if (event->subclass_name && node->subclass_name) { + match = strstr(event->subclass_name, node->subclass_name) ? 1 : 0; } - } else if ((event->subclass_name && !node->subclass) || (!event->subclass_name && !node->subclass)) { + } else if ((event->subclass_name && !node->subclass_name) || (!event->subclass_name && !node->subclass_name)) { match = 1; } else { match = 0; @@ -1732,7 +1732,9 @@ SWITCH_DECLARE(switch_status_t) switch_event_bind_removable(const char *id, swit /* ----------------------------------------------- */ event_node->id = DUP(id); event_node->event_id = event; - event_node->subclass = subclass; + if (subclass_name) { + event_node->subclass_name = DUP(subclass_name); + } event_node->callback = callback; event_node->user_data = user_data; @@ -1786,6 +1788,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_unbind_callback(switch_event_callba } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Event Binding deleted for %s:%s\n", n->id, switch_event_name(n->event_id)); + FREE(n->subclass_name); FREE(n->id); FREE(n); status = SWITCH_STATUS_SUCCESS; @@ -1825,7 +1828,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_unbind(switch_event_node_t **node) EVENT_NODES[n->event_id] = n->next; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Event Binding deleted for %s:%s\n", n->id, switch_event_name(n->event_id)); - n->subclass = NULL; + FREE(n->subclass_name); FREE(n->id); FREE(n); *node = NULL; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 84e077f27b..0989cbc4d4 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -2412,7 +2412,7 @@ SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint3 } stfu_n_eat(jb, ts, read_frame->payload, read_frame->data, read_frame->datalen, 0); - ts += interval; + ts += read_impl.samples_per_packet; if ((jb_frame = stfu_n_read_a_frame(jb))) { write_frame.data = jb_frame->data; diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 938be90db2..262d6d7a91 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -337,6 +337,7 @@ static switch_bool_t monitor_callback(switch_core_session_t *session, const char if (!bd) { bd = "monitor_early_media_fail"; } + switch_channel_set_variable(channel, "DIALSTATUS", "BUSY"); switch_channel_set_variable(channel, "originate_disposition", bd); switch_channel_hangup(channel, data ? switch_channel_str2cause(data) : SWITCH_CAUSE_USER_BUSY); } else if (!strcmp(app, "ring")) { @@ -346,6 +347,7 @@ static switch_bool_t monitor_callback(switch_core_session_t *session, const char bd = "monitor_early_media_ring"; } switch_channel_set_variable(channel, "originate_disposition", bd); + switch_channel_set_variable(channel, "DIALSTATUS", "EARLY"); if (oglobals) { if (oglobals->monitor_early_media_ring_total && ++oglobals->monitor_early_media_ring_count < oglobals->monitor_early_media_ring_total) { @@ -1843,6 +1845,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } } + if (caller_channel) { + switch_channel_process_export(caller_channel, NULL, var_event, SWITCH_EXPORT_VARS_VARIABLE); + } + /* strip leading spaces */ while (data && *data && *data == ' ') { data++; @@ -1963,6 +1969,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } switch_channel_set_variable(caller_channel, "originate_disposition", "failure"); + switch_channel_set_variable(caller_channel, "DIALSTATUS", "INVALIDARGS"); if (switch_channel_test_flag(caller_channel, CF_PROXY_MODE) || switch_channel_test_flag(caller_channel, CF_PROXY_MEDIA)) { ringback_data = NULL; @@ -3197,6 +3204,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_channel_set_variable(caller_channel, "originate_disposition", "call accepted"); if (peer_channel) { switch_process_import(oglobals.session, peer_channel, "import", NULL); + + if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) { + switch_channel_set_variable(caller_channel, "DIALSTATUS", "EARLY"); + } else { + switch_channel_set_variable(caller_channel, "DIALSTATUS", "ANSWER"); + } + } } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oglobals.session), SWITCH_LOG_DEBUG, "Originate Resulted in Success: [%s]\n", @@ -3300,6 +3314,27 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess if (caller_channel) { switch_channel_set_variable(caller_channel, "originate_disposition", switch_channel_cause2str(*cause)); + + switch (*cause) { + case SWITCH_CAUSE_ORIGINATOR_CANCEL: + switch_channel_set_variable(caller_channel, "DIALSTATUS", "CANCEL"); + break; + case SWITCH_CAUSE_USER_BUSY: + switch_channel_set_variable(caller_channel, "DIALSTATUS", "BUSY"); + break; + case SWITCH_CAUSE_NO_ANSWER: + switch_channel_set_variable(caller_channel, "DIALSTATUS", "NOANSWER"); + break; + case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER: + switch_channel_set_variable(caller_channel, "DIALSTATUS", "INVALIDARGS"); + break; + case SWITCH_CAUSE_CALL_REJECTED: + switch_channel_set_variable(caller_channel, "DIALSTATUS", "DONTCALL"); + break; + default: + switch_channel_set_variable(caller_channel, "DIALSTATUS", switch_channel_cause2str(*cause)); + break; + } } early_state.ready = 0;