From f708ee1a0bb2a66b6e87e6fd0e0c496092eb1494 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 7 Sep 2010 21:21:11 -0400 Subject: [PATCH 01/12] freetdm: fix help message --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 56eebd7dd5..fb85b3515c 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3896,7 +3896,7 @@ SWITCH_STANDARD_API(ft_function) ftdm_channel_t *fchan = NULL; ftdm_span_t *span = NULL; if (argc < 2) { - stream->write_function(stream, "-ERR Usage: oz notrace []\n"); + stream->write_function(stream, "-ERR Usage: ftdm notrace []\n"); goto end; } ftdm_span_find_by_name(argv[1], &span); From 8114b3f18d4a6e8ec396774bd78cb50145b91158 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 7 Sep 2010 21:16:00 -0500 Subject: [PATCH 02/12] speed up db action in sofia recover --- src/mod/endpoints/mod_sofia/sofia_glue.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 15efc1a3e4..82b933c981 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -4664,22 +4664,22 @@ void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *sess return; } - if (sofia_test_flag(tech_pvt, TFLAG_TRACKED)) { - sofia_glue_tech_untrack(profile, session, SWITCH_TRUE); - } - if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) { xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE); switch_xml_free(cdr); } if (xml_cdr_text) { - sql = switch_mprintf("insert into sip_recovery (runtime_uuid, profile_name, hostname, uuid, metadata) values ('%q','%q','%q','%q','%q')", - switch_core_get_uuid(), profile->name, mod_sofia_globals.hostname, switch_core_session_get_uuid(session), xml_cdr_text); - + if (sofia_test_flag(tech_pvt, TFLAG_TRACKED)) { + sql = switch_mprintf("update sip_recovery set metadata='%q' where uuid='%q'", xml_cdr_text, switch_core_session_get_uuid(session)); + } else { + + sql = switch_mprintf("insert into sip_recovery (runtime_uuid, profile_name, hostname, uuid, metadata) values ('%q','%q','%q','%q','%q')", + switch_core_get_uuid(), profile->name, mod_sofia_globals.hostname, switch_core_session_get_uuid(session), xml_cdr_text); + } + if (sofia_test_pflag(profile, PFLAG_TRACK_CALLS_EVENTS)) { switch_event_t *event = NULL; - if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_RECOVERY_SEND) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile_name", profile->name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sql", sql); @@ -4687,8 +4687,8 @@ void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *sess } } + sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); free(xml_cdr_text); sofia_set_flag(tech_pvt, TFLAG_TRACKED); From 3482f95e72934dd96f80188cc04b008308bf73db Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Wed, 8 Sep 2010 00:07:19 -0400 Subject: [PATCH 03/12] mod_callcenter: Alot of cleanup. Added max-wait-time and max-wait-time-with-no-agent param to a queue. max-wait-time : allow to make the caller quit the queue after X number of waited second. The second one allow max-wait-time-with-no-agent : This will wait for a range of second with no agent before kicking the member out of the queue. This allow safe shift change with all agents login out and back in I've changed the Event value from CC-Name to either CC-Agent or CC-Queue. So watchout for your current event socket apps. Sorry about this change. Lot to be tested in this commit. Please use Jira to post problems, and new feature request can be added at the bottom of the wiki page. --- conf/autoload_configs/callcenter.conf.xml | 2 + .../mod_callcenter/mod_callcenter.c | 332 ++++++++++++------ 2 files changed, 232 insertions(+), 102 deletions(-) diff --git a/conf/autoload_configs/callcenter.conf.xml b/conf/autoload_configs/callcenter.conf.xml index 156ed374ca..e764d17f15 100644 --- a/conf/autoload_configs/callcenter.conf.xml +++ b/conf/autoload_configs/callcenter.conf.xml @@ -10,6 +10,8 @@ + + diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index e56309d005..e08757ba38 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -37,6 +37,7 @@ #define CC_AGENT_TYPE_UUID_STANDBY "uuid-standby" #define CC_SQLITE_DB_NAME "callcenter" +#define CC_MAX_TIME_DIFF_CHECK 5 /* TODO drop caller if no agent login dont allow new caller @@ -53,6 +54,16 @@ SWITCH_MODULE_DEFINITION(mod_callcenter, mod_callcenter_load, mod_callcenter_shu static const char *global_cf = "callcenter.conf"; +struct cc_status_table { + const char *name; + int status; +}; + +struct cc_state_table { + const char *name; + int state; +}; + typedef enum { CC_STATUS_SUCCESS, CC_STATUS_FALSE, @@ -77,12 +88,7 @@ typedef enum { CC_TIER_STATE_STANDBY = 5 } cc_tier_state_t; -struct cc_tier_state_table { - const char *name; - cc_tier_state_t state; -}; - -static struct cc_tier_state_table STATE_CHART[] = { +static struct cc_state_table STATE_CHART[] = { {"Unknown", CC_TIER_STATE_UNKNOWN}, {"No Answer", CC_TIER_STATE_NO_ANSWER}, {"Ready", CC_TIER_STATE_READY}, @@ -101,12 +107,7 @@ typedef enum { CC_AGENT_STATUS_ON_BREAK = 4 } cc_agent_status_t; -struct cc_agent_status_table { - const char *name; - cc_agent_status_t status; -}; - -static struct cc_agent_status_table AGENT_STATUS_CHART[] = { +static struct cc_status_table AGENT_STATUS_CHART[] = { {"Unknown", CC_AGENT_STATUS_UNKNOWN}, {"Logged Out", CC_AGENT_STATUS_LOGGED_OUT}, {"Available", CC_AGENT_STATUS_AVAILABLE}, @@ -124,12 +125,7 @@ typedef enum { CC_AGENT_STATE_IDLE = 4 } cc_agent_state_t; -struct cc_agent_state_table { - const char *name; - cc_agent_state_t state; -}; - -static struct cc_agent_state_table AGENT_STATE_CHART[] = { +static struct cc_state_table AGENT_STATE_CHART[] = { {"Unknown", CC_AGENT_STATE_UNKNOWN}, {"Waiting", CC_AGENT_STATE_WAITING}, {"Receiving", CC_AGENT_STATE_RECEIVING}, @@ -147,12 +143,7 @@ typedef enum { CC_MEMBER_STATE_ABANDONED = 4 } cc_member_state_t; -struct cc_member_state_table { - const char *name; - cc_member_state_t state; -}; - -static struct cc_member_state_table MEMBER_STATE_CHART[] = { +static struct cc_state_table MEMBER_STATE_CHART[] = { {"Unknown", CC_MEMBER_STATE_UNKNOWN}, {"Waiting", CC_MEMBER_STATE_WAITING}, {"Trying", CC_MEMBER_STATE_TRYING}, @@ -162,10 +153,24 @@ static struct cc_member_state_table MEMBER_STATE_CHART[] = { }; -/*static char queues_sql[] = - "CREATE TABLE queues (\n" - " name VARCHAR(255)\n" ");\n"; - */ +struct cc_member_cancel_reason_table { + const char *name; + int reason; +}; + +typedef enum { + CC_MEMBER_CANCEL_REASON_NONE, + CC_MEMBER_CANCEL_REASON_TIMEOUT, + CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT +} cc_member_cancel_reason_t; + +static struct cc_member_cancel_reason_table MEMBER_CANCEL_REASON_CHART[] = { + {"NONE", CC_MEMBER_CANCEL_REASON_NONE}, + {"TIMEOUT", CC_MEMBER_CANCEL_REASON_TIMEOUT}, + {"NO_AGENT_TIMEOUT", CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT}, + {NULL, 0} +}; + static char members_sql[] = "CREATE TABLE members (\n" " queue VARCHAR(255),\n" @@ -222,7 +227,6 @@ static char agents_sql[] = " ready_time INTEGER NOT NULL DEFAULT 0\n" ");\n"; - static char tiers_sql[] = "CREATE TABLE tiers (\n" " queue VARCHAR(255),\n" @@ -247,7 +251,7 @@ const char * cc_tier_state2str(cc_tier_state_t state) uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_tier_state_table)) - 1; x++) { + for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) { if (STATE_CHART[x].state == state) { str = STATE_CHART[x].name; break; @@ -262,7 +266,7 @@ cc_tier_state_t cc_tier_str2state(const char *str) uint8_t x; cc_tier_state_t state = CC_TIER_STATE_UNKNOWN; - for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_tier_state_table)) - 1 && STATE_CHART[x].name; x++) { + for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_state_table)) - 1 && STATE_CHART[x].name; x++) { if (!strcasecmp(STATE_CHART[x].name, str)) { state = STATE_CHART[x].state; break; @@ -271,12 +275,41 @@ cc_tier_state_t cc_tier_str2state(const char *str) return state; } +const char * cc_member_cancel_reason2str(cc_member_cancel_reason_t reason) +{ + uint8_t x; + const char *str = "NONE"; + + for (x = 0; x < (sizeof(MEMBER_CANCEL_REASON_CHART) / sizeof(struct cc_member_cancel_reason_table)) - 1; x++) { + if (MEMBER_CANCEL_REASON_CHART[x].reason == reason) { + str = MEMBER_CANCEL_REASON_CHART[x].name; + break; + } + } + + return str; +} + +cc_member_cancel_reason_t cc_member_cancel_str2reason(const char *str) +{ + uint8_t x; + cc_member_cancel_reason_t reason = CC_MEMBER_CANCEL_REASON_NONE; + + for (x = 0; x < (sizeof(MEMBER_CANCEL_REASON_CHART) / sizeof(struct cc_member_cancel_reason_table)) - 1 && MEMBER_CANCEL_REASON_CHART[x].name; x++) { + if (!strcasecmp(MEMBER_CANCEL_REASON_CHART[x].name, str)) { + reason = MEMBER_CANCEL_REASON_CHART[x].reason; + break; + } + } + return reason; +} + const char * cc_agent_status2str(cc_agent_status_t status) { uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_agent_status_table)) - 1; x++) { + for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_status_table)) - 1; x++) { if (AGENT_STATUS_CHART[x].status == status) { str = AGENT_STATUS_CHART[x].name; break; @@ -291,7 +324,7 @@ cc_agent_status_t cc_agent_str2status(const char *str) uint8_t x; cc_agent_status_t status = CC_AGENT_STATUS_UNKNOWN; - for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_agent_status_table)) - 1 && AGENT_STATUS_CHART[x].name; x++) { + for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_status_table)) - 1 && AGENT_STATUS_CHART[x].name; x++) { if (!strcasecmp(AGENT_STATUS_CHART[x].name, str)) { status = AGENT_STATUS_CHART[x].status; break; @@ -305,7 +338,7 @@ const char * cc_agent_state2str(cc_agent_state_t state) uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_agent_state_table)) - 1; x++) { + for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) { if (AGENT_STATE_CHART[x].state == state) { str = AGENT_STATE_CHART[x].name; break; @@ -320,7 +353,7 @@ cc_agent_state_t cc_agent_str2state(const char *str) uint8_t x; cc_agent_state_t state = CC_AGENT_STATE_UNKNOWN; - for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_agent_state_table)) - 1 && AGENT_STATE_CHART[x].name; x++) { + for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_state_table)) - 1 && AGENT_STATE_CHART[x].name; x++) { if (!strcasecmp(AGENT_STATE_CHART[x].name, str)) { state = AGENT_STATE_CHART[x].state; break; @@ -334,7 +367,7 @@ const char * cc_member_state2str(cc_member_state_t state) uint8_t x; const char *str = "Unknown"; - for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_member_state_table)) - 1; x++) { + for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) { if (MEMBER_STATE_CHART[x].state == state) { str = MEMBER_STATE_CHART[x].name; break; @@ -349,7 +382,7 @@ cc_member_state_t cc_member_str2state(const char *str) uint8_t x; cc_member_state_t state = CC_MEMBER_STATE_UNKNOWN; - for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_member_state_table)) - 1 && MEMBER_STATE_CHART[x].name; x++) { + for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_state_table)) - 1 && MEMBER_STATE_CHART[x].name; x++) { if (!strcasecmp(MEMBER_STATE_CHART[x].name, str)) { state = MEMBER_STATE_CHART[x].state; break; @@ -384,19 +417,27 @@ struct cc_queue { char *moh; char *record_template; char *time_base_score; + switch_bool_t tier_rules_apply; uint32_t tier_rule_wait_second; switch_bool_t tier_rule_wait_multiply_level; switch_bool_t tier_rule_no_agent_no_wait; + uint32_t discard_abandoned_after; switch_bool_t abandoned_resume_allowed; + uint32_t max_wait_time; + uint32_t max_wait_time_with_no_agent; + switch_mutex_t *mutex; switch_thread_rwlock_t *rwlock; switch_memory_pool_t *pool; uint32_t flags; + switch_time_t last_agent_exist; + switch_time_t last_agent_exist_check; + switch_xml_config_item_t config[CC_QUEUE_CONFIGITEM_COUNT]; switch_xml_config_string_options_t config_str_pool; @@ -488,6 +529,7 @@ cc_queue_t *queue_set_config(cc_queue_t *queue) SWITCH_CONFIG_SET_ITEM(queue->config[i++], "moh-sound", SWITCH_CONFIG_STRING, 0, &queue->moh, NULL, &queue->config_str_pool, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "record-template", SWITCH_CONFIG_STRING, 0, &queue->record_template, NULL, &queue->config_str_pool, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "time-base-score", SWITCH_CONFIG_STRING, 0, &queue->time_base_score, "queue", &queue->config_str_pool, NULL, NULL); + SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rules-apply", SWITCH_CONFIG_BOOL, 0, &queue->tier_rules_apply, SWITCH_FALSE, NULL, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rule-wait-second", SWITCH_CONFIG_INT, 0, &queue->tier_rule_wait_second, 0, &config_int_0_86400, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rule-wait-multiply-level", SWITCH_CONFIG_BOOL, 0, &queue->tier_rule_wait_multiply_level, SWITCH_FALSE, NULL, NULL, NULL); @@ -495,6 +537,9 @@ cc_queue_t *queue_set_config(cc_queue_t *queue) SWITCH_CONFIG_SET_ITEM(queue->config[i++], "discard-abandoned-after", SWITCH_CONFIG_INT, 0, &queue->discard_abandoned_after, 60, &config_int_0_86400, NULL, NULL); SWITCH_CONFIG_SET_ITEM(queue->config[i++], "abandoned-resume-allowed", SWITCH_CONFIG_BOOL, 0, &queue->abandoned_resume_allowed, SWITCH_FALSE, NULL, NULL, NULL); + SWITCH_CONFIG_SET_ITEM(queue->config[i++], "max-wait-time", SWITCH_CONFIG_INT, 0, &queue->max_wait_time, 0, &config_int_0_86400, NULL, NULL); + SWITCH_CONFIG_SET_ITEM(queue->config[i++], "max-wait-time-with-no-agent", SWITCH_CONFIG_INT, 0, &queue->max_wait_time_with_no_agent, 0, &config_int_0_86400, NULL, NULL); + switch_assert(i < CC_QUEUE_CONFIGITEM_COUNT); return queue; @@ -646,6 +691,9 @@ static cc_queue_t *load_queue(const char *queue_name) switch_thread_rwlock_create(&queue->rwlock, pool); queue->name = switch_core_strdup(pool, queue_name); + queue->last_agent_exist = 0; + queue->last_agent_exist_check = 0; + if (!(dbh = cc_get_db_handle())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n"); goto end; @@ -702,7 +750,7 @@ static cc_queue_t *get_queue(const char *queue_name) struct call_helper { const char *member_uuid; - const char *queue; + const char *queue_name; const char *queue_strategy; const char *member_joined_epoch; const char *member_caller_name; @@ -744,7 +792,7 @@ int cc_queue_count(const char *queue) count = atoi(res); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Selection", event_name); @@ -827,7 +875,7 @@ cc_agent_status_t cc_agent_get(const char *key, const char *agent, char *ret_res result = CC_STATUS_SUCCESS; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-get"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", res); switch_event_fire(&event); @@ -894,7 +942,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen result = CC_STATUS_SUCCESS; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-change"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", value); switch_event_fire(&event); @@ -918,7 +966,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen result = CC_STATUS_SUCCESS; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-state-change"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-State", value); switch_event_fire(&event); @@ -1118,13 +1166,13 @@ done: return result; } -cc_status_t cc_tier_del(const char *queue, const char *agent) +cc_status_t cc_tier_del(const char *queue_name, const char *agent) { cc_status_t result = CC_STATUS_SUCCESS; char *sql; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue); - sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue, agent); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue_name); + sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue_name, agent); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1307,7 +1355,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa } if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_CALLBACK)) { switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS); - switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue); + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_pre_answer_uuid", "%s", h->member_uuid); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name); @@ -1327,7 +1375,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_t *event; const char *cc_warning_tone = switch_channel_get_variable(agent_channel, "cc_warning_tone"); - switch_channel_set_variable(agent_channel, "cc_queue", h->queue); + switch_channel_set_variable(agent_channel, "cc_queue", h->queue_name); switch_channel_set_variable(agent_channel, "cc_agent", h->agent_name); switch_channel_set_variable(agent_channel, "cc_agent_type", h->agent_type); switch_channel_set_variable(agent_channel, "cc_member_uuid", h->member_uuid); @@ -1384,7 +1432,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(agent_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-start"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); @@ -1407,11 +1455,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_safe_free(sql); /* Change the agents Status in the tiers */ - sql = switch_mprintf("UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q'", - cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->agent_name, h->queue); - cc_execute_sql(NULL, sql, NULL); - switch_safe_free(sql); - + cc_tier_update("state", cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->queue_name, h->agent_name); cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_IN_A_QUEUE_CALL), h->agent_name); /* Record session if record-template is provided */ @@ -1424,10 +1468,13 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" (%s) from queue %s%s\n", - h->agent_name, h->member_caller_name, h->member_caller_number, h->queue, (h->record_template?" (Recorded)":"")); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" <%s> from queue %s%s\n", + h->agent_name, h->member_caller_name, h->member_caller_number, h->queue_name, (h->record_template?" (Recorded)":"")); switch_ivr_uuid_bridge(h->member_uuid, switch_core_session_get_uuid(agent_session)); + /* This is used for the waiting caller to quit waiting for a agent */ + switch_channel_set_variable(member_channel, "cc_agent_uuid", agent_uuid); + /* Wait until the member hangup or the agent hangup. This will quit also if the agent transfer the call */ while(switch_channel_up(member_channel) && switch_channel_up(agent_channel) && globals.running) { switch_yield(100000); @@ -1436,7 +1483,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(agent_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-end"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); @@ -1452,7 +1499,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa /* Update Agents Items */ /* Do not remove uuid of the agent if we are a standby agent */ sql = switch_mprintf("UPDATE agents SET %q last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';" - , (strcasecmp(h->agent_type, "uuid-standby")?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system); + , (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1464,7 +1511,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa /* Caller off event */ if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Terminated"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answer-Time", "%ld", (long) (t_agent_answered - t_agent_called)); @@ -1472,8 +1519,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Talk-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_agent_answered)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Total-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); } @@ -1538,8 +1587,8 @@ done: sql = switch_mprintf( "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q' AND (state = '%q' OR state = '%q' OR state = '%q');" "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q'" - , cc_tier_state2str(tiers_state), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING), - cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_STANDBY)); + , cc_tier_state2str(tiers_state), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING), + cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_STANDBY)); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1567,7 +1616,7 @@ done: } struct agent_callback { - const char *queue; + const char *queue_name; const char *system; const char *uuid; const char *caller_number; @@ -1579,6 +1628,7 @@ struct agent_callback { uint32_t tier_rule_wait_second; switch_bool_t tier_rule_wait_multiply_level; switch_bool_t tier_rule_no_agent_no_wait; + switch_bool_t agent_found; int tier; int tier_agent_available; @@ -1602,6 +1652,8 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames switch_bool_t contact_agent = SWITCH_TRUE; + cbt->agent_found = SWITCH_TRUE; + /* Check if we switch to a different tier, if so, check if we should continue further for that member */ if (cbt->tier_rules_apply == SWITCH_TRUE && atoi(agent_tier_level) > cbt->tier) { @@ -1700,7 +1752,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames h->member_joined_epoch = switch_core_strdup(h->pool, cbt->joined_epoch); h->member_caller_name = switch_core_strdup(h->pool, cbt->caller_name); h->member_caller_number = switch_core_strdup(h->pool, cbt->caller_number); - h->queue = switch_core_strdup(h->pool, cbt->queue); + h->queue_name = switch_core_strdup(h->pool, cbt->queue_name); h->record_template = switch_core_strdup(h->pool, cbt->record_template); h->no_answer_count = atoi(argv[4]); h->max_no_answer = atoi(argv[5]); @@ -1713,8 +1765,8 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames sql = switch_mprintf( "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q';" "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q';", - cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue, - cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_READY)); + cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue_name, + cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_READY)); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -1796,9 +1848,10 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName cbt.caller_number = argv[2]; cbt.caller_name = argv[3]; cbt.joined_epoch = argv[4]; - cbt.queue = argv[0]; + cbt.queue_name = argv[0]; cbt.strategy = queue_strategy; cbt.record_template = queue_record_template; + cbt.agent_found = SWITCH_FALSE; if (!strcasecmp(queue->strategy, "longest-idle-agent")) { sql_order_by = switch_mprintf("level, agents.last_offered_call, position"); @@ -1832,6 +1885,18 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName switch_safe_free(sql); switch_safe_free(sql_order_by); + /* We update a field in the queue struct so we can kick caller out if waiting for too long with no agent */ + if (!argv[0] || !(queue = get_queue(argv[0]))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", argv[0]); + goto end; + } else { + queue->last_agent_exist_check = switch_epoch_time_now(NULL); + if (cbt.agent_found) { + queue->last_agent_exist = queue->last_agent_exist_check; + } + queue_rwunlock(queue); + } + end: switch_safe_free(queue_name); switch_safe_free(queue_strategy); @@ -1911,30 +1976,53 @@ void cc_agent_dispatch_thread_start(void) switch_thread_create(&thread, thd_attr, cc_agent_dispatch_thread_run, NULL, globals.pool); } -struct member_helper { - const char *uuid; +struct member_thread_helper { + const char *member_uuid; + const char *queue_name; + switch_time_t t_member_called; + cc_member_cancel_reason_t member_cancel_reason; + int running; switch_memory_pool_t *pool; }; void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj) { - struct member_helper *m = (struct member_helper *) obj; - switch_core_session_t *member_session = switch_core_session_locate(m->uuid); - switch_channel_t *channel = NULL; + struct member_thread_helper *m = (struct member_thread_helper *) obj; + switch_core_session_t *member_session = switch_core_session_locate(m->member_uuid); + switch_channel_t *member_channel = NULL; switch_mutex_lock(globals.mutex); globals.threads++; switch_mutex_unlock(globals.mutex); if (member_session) { - channel = switch_core_session_get_channel(member_session); + member_channel = switch_core_session_get_channel(member_session); } else { switch_core_destroy_memory_pool(&m->pool); return NULL; } - while(switch_channel_ready(channel) && m->running && globals.running) { + while(switch_channel_ready(member_channel) && m->running && globals.running) { + cc_queue_t *queue = NULL; + + if (!m->queue_name || !(queue = get_queue(m->queue_name))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found\n", m->queue_name); + break; + } + /* Make the Caller Leave if he went over his max wait time */ + if (queue->max_wait_time > 0 && queue->max_wait_time <= switch_epoch_time_now(NULL) - m->t_member_called) { + m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_TIMEOUT; + switch_channel_set_flag_value(member_channel, CF_BREAK, 2); + } + + /* Will drop the caller if no agent was found for more than X secondes */ + if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - CC_MAX_TIME_DIFF_CHECK && + queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) { + m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT; + switch_channel_set_flag_value(member_channel, CF_BREAK, 2); + } + /* TODO Go thought the list of phrases */ /* SAMPLE CODE to playback something over the MOH @@ -1949,8 +2037,12 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj /* If Agent Logoff, we might need to recalculare score based on skill */ /* Play Announcement in order */ - switch_yield(100000); + + queue_rwunlock(queue); + + switch_yield(500000); } + switch_core_session_rwunlock(member_session); switch_core_destroy_memory_pool(&m->pool); @@ -1971,26 +2063,27 @@ SWITCH_STANDARD_APP(callcenter_function) char *mydata = NULL; cc_queue_t *queue = NULL; const char *queue_name = NULL; - switch_channel_t *member_channel = switch_core_session_get_channel(session); + switch_core_session_t *member_session = session; + switch_channel_t *member_channel = switch_core_session_get_channel(member_session); char *sql = NULL; - char *uuid = switch_core_session_get_uuid(session); - switch_input_args_t args = { 0 }; - struct member_helper *h = NULL; + char *member_uuid = switch_core_session_get_uuid(member_session); + struct member_thread_helper *h = NULL; switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; switch_memory_pool_t *pool; - int cc_base_score_int = 0; switch_channel_timetable_t *times = NULL; - const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score"); const char *cc_moh_override = switch_channel_get_variable(member_channel, "cc_moh_override"); + const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score"); + int cc_base_score_int = 0; const char *cur_moh = NULL; char start_epoch[64]; switch_event_t *event; switch_time_t t_member_called = switch_epoch_time_now(NULL); long abandoned_epoch = 0; + const char *agent_uuid = NULL; if (!zstr(data)) { - mydata = switch_core_session_strdup(session, data); + mydata = switch_core_session_strdup(member_session, data); argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Queue name provided\n"); @@ -2013,7 +2106,7 @@ SWITCH_STANDARD_APP(callcenter_function) times = switch_channel_get_timetable(member_channel); switch_snprintf(start_epoch, sizeof(start_epoch), "%" SWITCH_TIME_T_FMT, times->answered / 1000000); - /* Check of we have a queued abandoned member we can resume from */ + /* Check if we support and have a queued abandoned member we can resume from */ if (queue->abandoned_resume_allowed == SWITCH_TRUE) { char res[256]; @@ -2037,9 +2130,9 @@ SWITCH_STANDARD_APP(callcenter_function) if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-%s", (abandoned_epoch==0?"start":"resume")); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); @@ -2054,7 +2147,7 @@ SWITCH_STANDARD_APP(callcenter_function) " (queue,system,uuid,system_epoch,joined_epoch,base_score,skill_score,caller_number,caller_name,serving_agent,serving_system,state)" " VALUES('%q','single_box','%q','%q','%ld','%d','%d','%q','%q','%q','','%q')", queue_name, - uuid, + member_uuid, start_epoch, (long) switch_epoch_time_now(NULL), cc_base_score_int, @@ -2069,12 +2162,12 @@ SWITCH_STANDARD_APP(callcenter_function) char res[256]; /* Update abandoned member */ sql = switch_mprintf("UPDATE members SET uuid = '%q', state = '%q', rejoined_epoch = '%ld' WHERE caller_number = '%q' AND abandoned_epoch = '%ld' AND state = '%q' AND queue = '%q'", - uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), abandoned_epoch, cc_member_state2str(CC_MEMBER_STATE_ABANDONED), queue_name); + member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), abandoned_epoch, cc_member_state2str(CC_MEMBER_STATE_ABANDONED), queue_name); cc_execute_sql(queue, sql, NULL); switch_safe_free(sql); /* Confirm we took that member in */ - sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND state = '%q' AND queue = '%q'", uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name); + sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND state = '%q' AND queue = '%q'", member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name); cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res)); switch_safe_free(sql); @@ -2092,9 +2185,14 @@ SWITCH_STANDARD_APP(callcenter_function) /* Start Thread that will playback different prompt to the channel */ switch_core_new_memory_pool(&pool); h = switch_core_alloc(pool, sizeof(*h)); + h->pool = pool; - h->uuid = switch_core_strdup(h->pool, uuid); + h->member_uuid = switch_core_strdup(h->pool, member_uuid); + h->queue_name = switch_core_strdup(h->pool, queue_name); + h->t_member_called = t_member_called; + h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NONE; h->running = 1; + switch_threadattr_create(&thd_attr, h->pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); @@ -2104,16 +2202,37 @@ SWITCH_STANDARD_APP(callcenter_function) /* TODO Add DTMF callback support */ /* TODO add MOH infitite loop */ if (cc_moh_override) { - cur_moh = switch_core_session_strdup(session, cc_moh_override); + cur_moh = switch_core_session_strdup(member_session, cc_moh_override); } else { - cur_moh = switch_core_session_strdup(session, queue->moh); + cur_moh = switch_core_session_strdup(member_session, queue->moh); } queue_rwunlock(queue); - if (cur_moh) { - switch_ivr_play_file(session, NULL, cur_moh, &args); - } else { - switch_ivr_collect_digits_callback(session, &args, 0, 0); + while (switch_channel_ready(member_channel)) { + switch_input_args_t args = { 0 }; + + /* An agent was found, time to exit and let the bridge do it job */ + if ((agent_uuid = switch_channel_get_variable(member_channel, "cc_agent_uuid"))) { + break; + } + /* If the member thread set a different reason, we monitor it so we can quit the wait */ + if (h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) { + break; + } + + switch_core_session_flush_private_events(member_session); + + if (cur_moh) { + switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + } else { + switch_ivr_collect_digits_callback(session, &args, 0, 0); + } + } /* Stop Member Thread */ @@ -2123,33 +2242,42 @@ SWITCH_STANDARD_APP(callcenter_function) /* Hangup any agents been callback */ if (!switch_channel_up(member_channel)) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */ - switch_core_session_hupall_matching_var("cc_member_uuid", uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); + switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); sql = switch_mprintf("UPDATE members SET state = '%q', uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", - cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), uuid); + cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); + /* Generate an Event and update some channel variable */ if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called)); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Abort"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", uuid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), + queue_name, cc_member_cancel_reason2str(h->member_cancel_reason)); + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", cc_member_cancel_reason2str(h->member_cancel_reason)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); } + /* for xml_cdr needs */ switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%ld", (long) switch_epoch_time_now(NULL)); + switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", cc_member_cancel_reason2str(h->member_cancel_reason)); /* Send Event with queue count */ cc_queue_count(queue_name); } else { + switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered"); sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", - cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), uuid); + cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), member_uuid); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); @@ -2525,7 +2653,7 @@ SWITCH_STANDARD_API(cc_config_api_function) stream->write_function(stream, "%d\n", atoi(res)); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res); switch_event_fire(&event); From ac20528816a74aa2a7619a2425edd5a389161d13 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Sep 2010 09:44:40 -0500 Subject: [PATCH 04/12] MODSOFIA-85 --- src/mod/endpoints/mod_sofia/mod_sofia.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 58308225ff..5954a8436a 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1761,7 +1761,14 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi nua_update(tech_pvt->nh, TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); - } + } else if ((ua && (switch_stristr("cisco", ua)))) { + snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" ", name, number, tech_pvt->profile->sipip); + + sofia_set_flag_locked(tech_pvt, TFLAG_UPDATING_DISPLAY); + nua_update(tech_pvt->nh, + TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); + } tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name); tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number); From 381233ae0becc99ee1a4801883f94b704f1e2bc9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Sep 2010 10:30:39 -0500 Subject: [PATCH 05/12] fix fs_cli tab complete regression --- src/switch_loadable_module.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index 0ef3624326..67325648b2 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -1683,16 +1683,20 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * { switch_api_interface_t *api; switch_status_t status; - char *arg_no_spaces; - char *cmd_no_spaces; + char *arg_used; + char *cmd_used; switch_assert(stream != NULL); switch_assert(stream->data != NULL); switch_assert(stream->write_function != NULL); - - cmd_no_spaces = switch_strip_whitespace(cmd); - arg_no_spaces = switch_strip_whitespace(arg); + if (strcasecmp(cmd, "console_complete")) { + cmd_used = switch_strip_whitespace(cmd); + arg_used = switch_strip_whitespace(arg); + } else { + cmd_used = (char *) cmd; + arg_used = (char *) arg; + } if (!stream->param_event) { @@ -1700,17 +1704,17 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * } if (stream->param_event) { - if (cmd_no_spaces) { - switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command", cmd_no_spaces); + if (cmd_used) { + switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command", cmd_used); } - if (arg_no_spaces) { - switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_no_spaces); + if (arg_used) { + switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_used); } } - if (cmd_no_spaces && (api = switch_loadable_module_get_api_interface(cmd_no_spaces)) != 0) { - if ((status = api->function(arg_no_spaces, session, stream)) != SWITCH_STATUS_SUCCESS) { + if (cmd_used && (api = switch_loadable_module_get_api_interface(cmd_used)) != 0) { + if ((status = api->function(arg_used, session, stream)) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "COMMAND RETURNED ERROR!\n"); } UNPROTECT_INTERFACE(api); @@ -1723,8 +1727,13 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * switch_event_fire(&stream->param_event); } - switch_safe_free(cmd_no_spaces); - switch_safe_free(arg_no_spaces); + if (cmd_used != cmd) { + switch_safe_free(cmd_used); + } + + if (arg_used != arg) { + switch_safe_free(arg_used); + } return status; } From 4d3357e18cee30293a77fdf7f4ba8fcc9df9a2c5 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 8 Sep 2010 07:21:56 -0400 Subject: [PATCH 06/12] freetdm: set outbound flag in individual channel open too --- libs/freetdm/src/ftdm_io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index fc32a0ff0f..b275403c85 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1805,6 +1805,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, status = FTDM_SUCCESS; } ftdm_set_flag(check, FTDM_CHANNEL_INUSE); + ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND); *ftdmchan = check; } From 86de47ff3140d2d04e72c9977a3b3fc21cff54d0 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Sep 2010 10:41:50 -0500 Subject: [PATCH 07/12] dont put an rpid in 183 or 200 if pass-callee-id is false --- src/mod/endpoints/mod_sofia/mod_sofia.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 5954a8436a..19a44f43e1 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -697,7 +697,11 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX); - char *cid = generate_pai_str(session); + char *cid = NULL; + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) { + cid = generate_pai_str(session); + } if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) { /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless @@ -2165,7 +2169,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); - char *cid = generate_pai_str(session); + char *cid = NULL; + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) { + cid = generate_pai_str(session); + } if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) { From 84ee0ae61be9c88267e818685df3d7743a050881 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Thu, 9 Sep 2010 00:16:18 +0800 Subject: [PATCH 08/12] Fix for T.30 processing of operator interrupts, to improve compatibility with some machines, which seem to send them when no operator is around. Fix for T.38 gateway not kicking off or ending transmission under certain timing conditions. --- libs/spandsp/src/t30.c | 455 ++++++++++++++------------------- libs/spandsp/src/t31.c | 2 + libs/spandsp/src/t38_gateway.c | 63 +++-- libs/spandsp/src/v18.c | 2 +- 4 files changed, 248 insertions(+), 274 deletions(-) diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 97c7ed8cc7..45387b8585 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -2377,6 +2377,8 @@ static int send_response_to_pps(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ +#define VET_ALL_FCD_FRAMES + static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) { int page; @@ -2387,6 +2389,10 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) int frame_no; int first_bad_frame; int image_ended; +#if defined(VET_ALL_FCD_FRAMES) + int first; + int expected_len; +#endif if (len < 7) { @@ -2469,12 +2475,35 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) /* Build a bit map of which frames we now have stored OK */ first_bad_frame = 256; +#if defined(VET_ALL_FCD_FRAMES) + first = TRUE; + expected_len = 256; +#endif for (i = 0; i < 32; i++) { s->ecm_frame_map[i + 3] = 0; for (j = 0; j < 8; j++) { frame_no = (i << 3) + j; +#if defined(VET_ALL_FCD_FRAMES) + if (s->ecm_len[frame_no] >= 0) + { + if (frame_no < s->ecm_frames - 1) + { + if (first) + { + if (s->ecm_len[frame_no] == 64) + expected_len = 64; + first = FALSE; + } + if (s->ecm_len[frame_no] != expected_len) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Bad length ECM frame - %d\n", s->ecm_len[frame_no]); + s->ecm_len[frame_no] = -1; + } + } + } +#endif if (s->ecm_len[frame_no] < 0) { s->ecm_frame_map[i + 3] |= (1 << j); @@ -2524,14 +2553,18 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) switch (s->last_pps_fcf2) { - case T30_NULL: - case T30_EOP: - case T30_PRI_EOP: - case T30_EOM: - case T30_PRI_EOM: - case T30_EOS: - case T30_MPS: case T30_PRI_MPS: + case T30_PRI_EOM: + case T30_PRI_EOP: + if (s->remote_interrupts_allowed) + { + } + /* Fall through */ + case T30_NULL: + case T30_MPS: + case T30_EOM: + case T30_EOS: + case T30_EOP: if (s->receiver_not_ready_count > 0) { s->receiver_not_ready_count--; @@ -2635,7 +2668,13 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len) switch (s->state) { case T30_STATE_F_DOC_ECM: - if (len <= 4 + 256) + if (len > 4 + 256) + { + /* For other frame types we kill the call on an unexpected frame length. For FCD frames it is better to just ignore + the frame, and let retries sort things out. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len); + } + else { frame_no = msg[3]; /* Just store the actual image data, and record its length */ @@ -2645,10 +2684,6 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len) /* In case we are just after a CTC/CTR exchange, which kicked us back to long training */ s->short_train = TRUE; } - else - { - unexpected_frame_length(s, msg, len); - } /* We have received something, so any missing carrier status is out of date */ if (s->current_status == T30_ERR_RX_NOCARRIER) s->current_status = T30_ERR_OK; @@ -2677,6 +2712,7 @@ static void process_rx_rcp(t30_state_t *s, const uint8_t *msg, int len) case T30_STATE_F_POST_DOC_ECM: /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance of receiving a correct one. */ + timer_t2_start(s); break; default: unexpected_non_final_frame(s, msg, len); @@ -3063,6 +3099,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int case T30_DCS: process_rx_dcs(s, msg, len); break; + case T30_PRI_MPS: + if (s->remote_interrupts_allowed) + { + } + /* Fall through */ case T30_MPS: /* Treat this as a bad quality page. */ if (s->phase_d_handler) @@ -3072,16 +3113,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; - case T30_PRI_MPS: - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) + case T30_PRI_EOM: + if (s->remote_interrupts_allowed) { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); } - s->next_rx_step = msg[2] & 0xFE; - set_state(s, T30_STATE_III_Q_RTN); - break; + /* Fall through */ case T30_EOM: case T30_EOS: /* Treat this as a bad quality page. */ @@ -3093,16 +3129,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; - case T30_PRI_EOM: - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) + case T30_PRI_EOP: + if (s->remote_interrupts_allowed) { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); } - s->next_rx_step = T30_PRI_EOM; - set_state(s, T30_STATE_III_Q_RTN); - break; + /* Fall through */ case T30_EOP: /* Treat this as a bad quality page. */ if (s->phase_d_handler) @@ -3112,16 +3143,6 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; - case T30_PRI_EOP: - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - s->next_rx_step = msg[2] & 0xFE; - set_state(s, T30_STATE_III_Q_RTN); - break; case T30_DCN: s->current_status = T30_ERR_RX_DCNDATA; disconnect(s); @@ -3148,6 +3169,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PRI_MPS: + if (s->remote_interrupts_allowed) + { + } + /* Fall through */ case T30_MPS: s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); @@ -3179,41 +3205,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; } break; - case T30_PRI_MPS: - s->next_rx_step = fcf; - switch (copy_quality(s)) + case T30_PRI_EOM: + if (s->remote_interrupts_allowed) { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - set_state(s, T30_STATE_III_Q_RTN); - break; } - break; + /* Fall through */ case T30_EOM: case T30_EOS: s->next_rx_step = fcf; @@ -3247,41 +3243,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; } break; - case T30_PRI_EOM: - s->next_rx_step = fcf; - switch (copy_quality(s)) + case T30_PRI_EOP: + if (s->remote_interrupts_allowed) { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - set_state(s, T30_STATE_III_Q_RTN); - break; } - break; + /* Fall through */ case T30_EOP: s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); @@ -3312,41 +3278,6 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; } break; - case T30_PRI_EOP: - s->next_rx_step = fcf; - switch (copy_quality(s)) - { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - set_state(s, T30_STATE_III_Q_RTN); - break; - } - break; case T30_DCN: s->current_status = T30_ERR_RX_DCNFAX; disconnect(s); @@ -3384,21 +3315,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t * case T4_RCP: /* Return to control for partial page. These might come through with or without the final frame tag. Here we deal with the "final frame tag" case. */ - if (s->state == T30_STATE_F_DOC_ECM) - { - /* Return to control for partial page */ - set_state(s, T30_STATE_F_POST_DOC_ECM); - queue_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - /* We have received something, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - s->current_status = T30_ERR_OK; - } - else - { - /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance - of receiving a correct one. */ - } + process_rx_rcp(s, msg, len); break; case T30_EOR: if (len != 4) @@ -3413,7 +3330,10 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t * case T30_PRI_EOP: case T30_PRI_EOM: case T30_PRI_MPS: - /* TODO: Alert operator */ + if (s->remote_interrupts_allowed) + { + /* TODO: Alert operator */ + } /* Fall through */ case T30_NULL: case T30_EOP: @@ -3651,11 +3571,22 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PIP: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_MCF: switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3668,8 +3599,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) set_state(s, T30_STATE_I); queue_phase(s, T30_PHASE_C_NON_ECM_TX); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -3678,8 +3609,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3690,13 +3621,11 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) } break; case T30_RTP: -#if 0 s->rtp_events++; -#endif switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3717,8 +3646,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) queue_phase(s, T30_PHASE_B_TX); restart_sending_document(s); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -3727,8 +3656,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) /* TODO: should go back to T, and resend */ return_to_phase_b(s, TRUE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -3737,20 +3666,27 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) break; } break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_RTN: -#if 0 s->rtn_events++; -#endif switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: s->retries = 0; if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); -#if 0 if (!s->retransmit_capable) -#endif { /* Send the next page, regardless of the problem with the current one. */ if (tx_start_page(s)) @@ -3771,29 +3707,26 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) queue_phase(s, T30_PHASE_B_TX); restart_sending_document(s); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: s->retries = 0; if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); -#if 0 if (s->retransmit_capable) { /* Wait for DIS */ } else -#endif { return_to_phase_b(s, TRUE); } break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: s->retries = 0; if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); -#if 0 if (s->retransmit_capable) { /* Send fresh training, and then repeat the last page */ @@ -3809,36 +3742,19 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) restart_sending_document(s); } else -#endif { send_dcn(s); } break; } break; - case T30_PIP: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_DCN: switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: - case T30_EOM: case T30_PRI_EOM: + case T30_MPS: + case T30_EOM: case T30_EOS: /* Unexpected DCN after EOM, EOS or MPS sequence */ s->current_status = T30_ERR_RX_DCNPHD; @@ -4019,8 +3935,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4036,8 +3952,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le send_first_ecm_frame(s); } break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -4046,8 +3962,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4094,6 +4010,17 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PIP: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_MCF: s->retries = 0; s->timer_t5 = 0; @@ -4112,8 +4039,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4129,8 +4056,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) send_first_ecm_frame(s); } break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -4139,8 +4066,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4158,22 +4085,6 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) set_state(s, T30_STATE_IV_PPS_RNR); send_rr(s); break; - case T30_PIP: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_PPR: process_rx_ppr(s, msg, len); break; @@ -4187,6 +4098,17 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4203,6 +4125,17 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len fcf = msg[2] & 0xFE; switch (fcf) { + case T30_PIP: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ case T30_MCF: s->retries = 0; s->timer_t5 = 0; @@ -4221,8 +4154,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); switch (s->next_tx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4238,8 +4171,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len send_first_ecm_frame(s); } break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: tx_end_page(s); if (s->phase_d_handler) @@ -4248,8 +4181,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len report_tx_result(s, TRUE); return_to_phase_b(s, FALSE); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: tx_end_page(s); if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); @@ -4267,22 +4200,6 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len set_state(s, T30_STATE_IV_PPS_RNR); send_rr(s); break; - case T30_PIP: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_DCN: s->current_status = T30_ERR_RX_DCNRRD; disconnect(s); @@ -4293,6 +4210,17 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4345,14 +4273,6 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len) set_state(s, T30_STATE_IV_EOR_RNR); send_rr(s); break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_ERR: /* TODO: Continue with the next message if MPS or EOM? */ s->timer_t5 = 0; @@ -4364,6 +4284,17 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len) case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4386,14 +4317,6 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len set_state(s, T30_STATE_IV_EOR_RNR); send_rr(s); break; - case T30_PIN: - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s, s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - break; case T30_ERR: /* TODO: Continue with the next message if MPS or EOM? */ s->timer_t5 = 0; @@ -4409,6 +4332,17 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len case T30_FNV: process_rx_fnv(s, msg, len); break; + case T30_PIN: + if (s->remote_interrupts_allowed) + { + s->retries = 0; + if (s->phase_d_handler) + { + s->phase_d_handler(s, s->phase_d_user_data, fcf); + s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); + } + } + /* Fall through */ default: /* We don't know what to do with this. */ unexpected_final_frame(s, msg, len); @@ -4596,7 +4530,7 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len) /* The following handles context sensitive message types, which should occur at the end of message sequences. They should, therefore have the final frame flag set. */ - span_log(&s->logging, SPAN_LOG_FLOW, "In state %d\n", s->state); + span_log(&s->logging, SPAN_LOG_FLOW, "Rx final frame in state %d\n", s->state); switch (s->state) { @@ -5082,11 +5016,11 @@ static void timer_t2_expired(t30_state_t *s) case T30_STATE_F_POST_RCP_MCF: switch (s->next_rx_step) { - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: /* We didn't receive a response to our T30_MCF after T30_EOM, so we must be OK - to proceed to phase B, and pretty act like its the beginning of a call. */ + to proceed to phase B, and pretty much act like its the beginning of a call. */ span_log(&s->logging, SPAN_LOG_FLOW, "Returning to phase B after %s\n", t30_frametype(s->next_rx_step)); set_phase(s, T30_PHASE_B_TX); timer_t2_start(s); @@ -5109,6 +5043,8 @@ static void timer_t2_expired(t30_state_t *s) case T30_STATE_F_POST_DOC_ECM: case T30_STATE_F_POST_DOC_NON_ECM: /* While waiting for next FAX page */ + /* Figure 5-2b/T.30 and note 7 says we should allow 1 to 3 tries at this point. + The way we work now is effectively hard coding a 1 try limit */ s->current_status = T30_ERR_RX_T2EXPMPS; break; #if 0 @@ -5873,8 +5809,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) { switch (s->next_rx_step) { - case T30_MPS: case T30_PRI_MPS: + case T30_MPS: /* We should now start to get another page */ if (s->error_correcting_mode) { @@ -5888,15 +5824,15 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) } timer_t2_start(s); break; - case T30_EOM: case T30_PRI_EOM: + case T30_EOM: case T30_EOS: /* See if we get something back, before moving to phase B. */ timer_t2_start(s); set_phase(s, T30_PHASE_D_RX); break; - case T30_EOP: case T30_PRI_EOP: + case T30_EOP: /* Wait for a DCN. */ set_phase(s, T30_PHASE_D_RX); timer_t4_start(s); @@ -6256,6 +6192,12 @@ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state) +{ + s->remote_interrupts_allowed = state; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t30_restart(t30_state_t *s) { s->phase = T30_PHASE_IDLE; @@ -6276,10 +6218,9 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s) /* The page number is only reset at call establishment */ s->rx_page_number = 0; s->tx_page_number = 0; -#if 0 s->rtn_events = 0; s->rtp_events = 0; -#endif + s->local_interrupt_pending = FALSE; s->far_end_detected = FALSE; s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0); if (s->calling_party) diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 5c9c4066b2..22af0fcb66 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -2602,7 +2602,9 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, t38_tx_packet_handler_t *tx_t38_packet_handler, void *tx_t38_packet_user_data) { +#if 0 v8_parms_t v8_parms; +#endif int alloced; if (at_tx_handler == NULL || modem_control_handler == NULL) diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index a572b5dad9..d3539cddc1 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -426,7 +426,6 @@ static int set_next_tx_type(t38_gateway_state_t *s) t38_gateway_hdlc_state_t *u; t = &s->audio.modems; - u = &s->core.hdlc_to_modem; t38_non_ecm_buffer_report_output_status(&s->core.non_ecm_to_modem, &s->logging); if (t->next_tx_handler) { @@ -447,6 +446,7 @@ static int set_next_tx_type(t38_gateway_state_t *s) return TRUE; } /*endif*/ + u = &s->core.hdlc_to_modem; if (u->in == u->out) return FALSE; /*endif*/ @@ -1057,7 +1057,9 @@ static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_n static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator) { t38_gateway_state_t *s; - + t38_gateway_hdlc_state_t *u; + int immediate; + s = (t38_gateway_state_t *) user_data; t38_non_ecm_buffer_report_input_status(&s->core.non_ecm_to_modem, &s->logging); @@ -1067,25 +1069,50 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica return 0; } /*endif*/ - if (s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents) + + u = &s->core.hdlc_to_modem; + immediate = (u->in == u->out); + if (u->buf[u->in].contents) { - if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS) - s->core.hdlc_to_modem.in = 0; + if (++u->in >= T38_TX_HDLC_BUFS) + u->in = 0; /*endif*/ } /*endif*/ - s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents = (indicator | FLAG_INDICATOR); - if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS) - s->core.hdlc_to_modem.in = 0; + u->buf[u->in].contents = (indicator | FLAG_INDICATOR); + if (++u->in >= T38_TX_HDLC_BUFS) + u->in = 0; /*endif*/ - t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); - span_log(&s->logging, - SPAN_LOG_FLOW, - "Queued change - (%d) %s -> %s\n", - silence_gen_remainder(&(s->audio.modems.silence_gen)), - t38_indicator_to_str(t->current_rx_indicator), - t38_indicator_to_str(indicator)); + if (immediate) + { + span_log(&s->logging, + SPAN_LOG_FLOW, + "Changing - (%d) %s -> %s\n", + silence_gen_remainder(&(s->audio.modems.silence_gen)), + t38_indicator_to_str(t->current_rx_indicator), + t38_indicator_to_str(indicator)); + switch (s->t38x.current_rx_field_class) + { + case T38_FIELD_CLASS_NONE: + break; + case T38_FIELD_CLASS_HDLC: + span_log(&s->logging, SPAN_LOG_FLOW, "HDLC shutdown\n"); + hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0); + break; + case T38_FIELD_CLASS_NON_ECM: + break; + } + } + else + { + span_log(&s->logging, + SPAN_LOG_FLOW, + "Queued change - (%d) %s -> %s\n", + silence_gen_remainder(&(s->audio.modems.silence_gen)), + t38_indicator_to_str(t->current_rx_indicator), + t38_indicator_to_str(indicator)); + } s->t38x.current_rx_field_class = T38_FIELD_CLASS_NONE; /* We need to set this here, since we might have been called as a fake indication when the real one was missing */ @@ -1440,6 +1467,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->corrupt_current_frame[0] = FALSE; break; case T38_FIELD_T4_NON_ECM_DATA: + if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) + t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); xx->current_rx_field_class = T38_FIELD_CLASS_NON_ECM; hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; if (hdlc_buf->contents != (data_type | FLAG_DATA)) @@ -1454,6 +1483,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->corrupt_current_frame[0] = FALSE; break; case T38_FIELD_T4_NON_ECM_SIG_END: + if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) + t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; /* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with incrementing sequence numbers, which are actually repeats. They get through to this point because @@ -2432,8 +2463,8 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, s->core.to_t38.octets_per_data_packet = 1; s->core.ecm_allowed = TRUE; - t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0); //s->core.ms_per_tx_chunk = DEFAULT_MS_PER_TX_CHUNK; + t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0); restart_rx_modem(s); s->core.timed_mode = TIMED_MODE_STARTUP; s->core.samples_to_timeout = 1; diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c index 18d94b4b90..bb26644b62 100644 --- a/libs/spandsp/src/v18.c +++ b/libs/spandsp/src/v18.c @@ -111,7 +111,7 @@ static const struct dtmf_to_ascii_s dtmf_to_ascii[] = {"##8", 'W'}, {"##9", 'Z'}, {"##0", ' '}, -#if defined(WIN32) || ( defined(__SVR4) && defined (__sun)) +#if defined(WIN32) || ( defined(__SVR4) && defined (__sun)) {"#*1", 'X'}, // (Note 1) 111 1011 {"#*2", 'X'}, // (Note 1) 111 1100 {"#*3", 'X'}, // (Note 1) 111 1101 From 4d448c979eadb63578ab7fc07949ac7aff9ec144 Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 8 Sep 2010 11:57:57 -0500 Subject: [PATCH 09/12] move enum to the bottom of default. --- conf/dialplan/default.xml | 16 ++++++---------- conf/dialplan/default/99999_enum.xml | 8 -------- 2 files changed, 6 insertions(+), 18 deletions(-) delete mode 100644 conf/dialplan/default/99999_enum.xml diff --git a/conf/dialplan/default.xml b/conf/dialplan/default.xml index 9862eed711..8abb8d8348 100644 --- a/conf/dialplan/default.xml +++ b/conf/dialplan/default.xml @@ -715,15 +715,6 @@ --> - - - + + + + + + diff --git a/conf/dialplan/default/99999_enum.xml b/conf/dialplan/default/99999_enum.xml deleted file mode 100644 index 6fd2151859..0000000000 --- a/conf/dialplan/default/99999_enum.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - From f3c6512ca08c3d4aac9c266e89929f8ab2a6d8d4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Sep 2010 12:59:31 -0500 Subject: [PATCH 10/12] fix build by guessing types of missing values -feeling lucky --- libs/spandsp/src/spandsp/private/t30.h | 7 +++++++ libs/spandsp/src/spandsp/t30.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index 6e4ee0a704..e56753e07d 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -207,6 +207,13 @@ struct t30_state_s /*! \brief This is only used in full duplex (e.g. ISDN) modes. */ int timer_t8; + /* These fields are guessed based on compiler error forensics, I added them to fix the build -anthm */ + int remote_interrupts_allowed; + int rtp_events; + int rtn_events; + int retransmit_capable; + /* end guessed fields */ + /*! \brief TRUE once the far end FAX entity has been detected. */ int far_end_detected; diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index 9b01d3b62b..9df7321abd 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -682,6 +682,8 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t); \param state TRUE to enable interrupt request, else FALSE. */ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state); +SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state); + #if defined(__cplusplus) } #endif From 977a8ad7ce7e72eca118df331ab0c53fda7b3a03 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Sep 2010 13:19:56 -0500 Subject: [PATCH 11/12] add origination_caller_profile to log all attempted calls for a paticular leg --- src/include/switch_caller.h | 1 + src/include/switch_channel.h | 14 ++++++++++++++ src/switch_channel.c | 30 ++++++++++++++++++++++++++++++ src/switch_core_session.c | 8 ++++++++ src/switch_ivr.c | 15 +++++++++++++++ 5 files changed, 68 insertions(+) diff --git a/src/include/switch_caller.h b/src/include/switch_caller.h index b3002081da..f77f1b016d 100644 --- a/src/include/switch_caller.h +++ b/src/include/switch_caller.h @@ -103,6 +103,7 @@ SWITCH_BEGIN_EXTERN_C switch_caller_profile_flag_t flags; struct switch_caller_profile *originator_caller_profile; struct switch_caller_profile *originatee_caller_profile; + struct switch_caller_profile *origination_caller_profile; struct switch_caller_profile *hunt_caller_profile; struct switch_channel_timetable *times; struct switch_caller_extension *caller_extension; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 247beae460..3f92534e3e 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -215,6 +215,20 @@ SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel */ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_profile(switch_channel_t *channel); +/*! + \brief Set the given channel's origination caller profile + \param channel channel to assign the profile to + \param caller_profile the profile to assign +*/ +SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile); + +/*! + \brief Retrive the given channel's origination caller profile + \param channel channel to retrive the profile from + \return the requested profile +*/ +SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel); + /*! \brief Retrive the given channel's unique id diff --git a/src/switch_channel.c b/src/switch_channel.c index d1308a1e9f..e3d77d7239 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2035,6 +2035,36 @@ SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *ch switch_mutex_unlock(channel->profile_mutex); } +SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile) +{ + switch_assert(channel != NULL); + switch_assert(channel->caller_profile != NULL); + + switch_mutex_lock(channel->profile_mutex); + + if (channel->caller_profile) { + caller_profile->next = channel->caller_profile->origination_caller_profile; + channel->caller_profile->origination_caller_profile = caller_profile; + } + switch_assert(channel->caller_profile->origination_caller_profile->next != channel->caller_profile->origination_caller_profile); + switch_mutex_unlock(channel->profile_mutex); +} + +SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel) +{ + switch_caller_profile_t *profile = NULL; + switch_assert(channel != NULL); + + switch_mutex_lock(channel->profile_mutex); + if (channel->caller_profile) { + profile = channel->caller_profile->origination_caller_profile; + } + switch_mutex_unlock(channel->profile_mutex); + + return profile; +} + + SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile) { switch_assert(channel != NULL); diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 74131644f9..9e942fea5e 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -524,6 +524,14 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_ switch_channel_set_originator_caller_profile(peer_channel, cloned_profile); } } + + + if ((profile = switch_channel_get_caller_profile(peer_channel))) { + if ((cloned_profile = switch_caller_profile_clone(session, profile)) != 0) { + switch_channel_set_origination_caller_profile(channel, cloned_profile); + } + } + } if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_OUTGOING) == SWITCH_STATUS_SUCCESS) { diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 61deece636..c1dc33651c 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -2012,6 +2012,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_ cp_off += switch_ivr_set_xml_profile_data(x_main_cp, caller_profile, 0); + if (caller_profile->origination_caller_profile) { + switch_caller_profile_t *cp = NULL; + int off = 0; + if (!(x_o = switch_xml_add_child_d(x_main_cp, "origination", cp_off++))) { + goto error; + } + + for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) { + if (!(x_caller_profile = switch_xml_add_child_d(x_o, "origination_caller_profile", off++))) { + goto error; + } + switch_ivr_set_xml_profile_data(x_caller_profile, cp, 0); + } + } + if (caller_profile->originator_caller_profile) { switch_caller_profile_t *cp = NULL; int off = 0; From d18c3a8a60bac15869fcf76cb3a93c238fa7f071 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Sep 2010 15:09:09 -0500 Subject: [PATCH 12/12] fix sql stmt --- src/mod/endpoints/mod_sofia/sofia_reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index eb9b03d958..c78ed90fe3 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -673,8 +673,8 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot) if (now && sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) { switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid," "expires,user_agent,server_user,server_host,profile_name" - " from sip_registrations where (status like '%%AUTO-NAT%%' " - "or status like '%%UDP-NAT%%') and hostname='%s'", mod_sofia_globals.hostname); + " from sip_registrations where (status like '%%NAT%%' " + "or contact like '%%fs_nat=true%%') and hostname='%s'", mod_sofia_globals.hostname); sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_nat_callback, profile); }