diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index a90df113d8..5b780d3700 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -107,21 +107,23 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre switch_assert(profile); stream->write_function(stream, "%s\n", line); /* prefs */ - stream->write_function(stream, "Name \t%s\n", profile->name); - stream->write_function(stream, "Domain Name \t%s\n", profile->domain); - stream->write_function(stream, "IP \t%s\n", profile->ip); - stream->write_function(stream, "Port \t%d\n", profile->port); - stream->write_function(stream, "Dialplan \t%s\n", profile->dialplan); - stream->write_function(stream, "Context \t%s\n", profile->context); - stream->write_function(stream, "Keep-Alive \t%d\n", profile->keep_alive); - stream->write_function(stream, "Date-Format \t%s\n", profile->date_format); - stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); - stream->write_function(stream, "Debug \t%d\n", profile->debug); + stream->write_function(stream, "Name \t%s\n", profile->name); + stream->write_function(stream, "Domain Name \t%s\n", profile->domain); + stream->write_function(stream, "IP \t%s\n", profile->ip); + stream->write_function(stream, "Port \t%d\n", profile->port); + stream->write_function(stream, "Dialplan \t%s\n", profile->dialplan); + stream->write_function(stream, "Context \t%s\n", profile->context); + stream->write_function(stream, "Patterns-Dialplan \t%s\n", profile->patterns_dialplan); + stream->write_function(stream, "Patterns-Context \t%s\n", profile->patterns_context); + stream->write_function(stream, "Keep-Alive \t%d\n", profile->keep_alive); + stream->write_function(stream, "Date-Format \t%s\n", profile->date_format); + stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); + stream->write_function(stream, "Debug \t%d\n", profile->debug); /* stats */ - stream->write_function(stream, "CALLS-IN \t%d\n", profile->ib_calls); - stream->write_function(stream, "FAILED-CALLS-IN \t%d\n", profile->ib_failed_calls); - stream->write_function(stream, "CALLS-OUT \t%d\n", profile->ob_calls); - stream->write_function(stream, "FAILED-CALLS-OUT \t%d\n", profile->ob_failed_calls); + stream->write_function(stream, "CALLS-IN \t%d\n", profile->ib_calls); + stream->write_function(stream, "FAILED-CALLS-IN \t%d\n", profile->ib_failed_calls); + stream->write_function(stream, "CALLS-OUT \t%d\n", profile->ob_calls); + stream->write_function(stream, "FAILED-CALLS-OUT \t%d\n", profile->ob_failed_calls); /* listener */ stream->write_function(stream, "Listener-Threads \t%d\n", profile->listener_threads); stream->write_function(stream, "%s\n", line); @@ -1429,6 +1431,10 @@ static void skinny_profile_set(skinny_profile_t *profile, char *var, char *val) profile->dialplan = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "context")) { profile->context = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "patterns-dialplan")) { + profile->patterns_dialplan = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "patterns-context")) { + profile->patterns_context = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "date-format")) { strncpy(profile->date_format, val, 6); } else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) { @@ -1499,6 +1505,10 @@ static switch_status_t load_skinny_config(void) skinny_profile_set(profile, "dialplan", val); } else if (!strcmp(var, "context")) { skinny_profile_set(profile, "context", val); + } else if (!strcmp(var, "patterns-dialplan")) { + skinny_profile_set(profile, "patterns-dialplan", val); + } else if (!strcmp(var, "patterns-context")) { + skinny_profile_set(profile, "patterns-context", val); } else if (!strcmp(var, "keep-alive")) { profile->keep_alive = atoi(val); } else if (!strcmp(var, "date-format")) { @@ -1511,11 +1521,19 @@ static switch_status_t load_skinny_config(void) } /* param */ if (!profile->dialplan) { - skinny_profile_set(profile, "dialplan","default"); + skinny_profile_set(profile, "dialplan","XML"); } if (!profile->context) { - skinny_profile_set(profile, "context","public"); + skinny_profile_set(profile, "context","default"); + } + + if (!profile->patterns_dialplan) { + skinny_profile_set(profile, "patterns-dialplan","XML"); + } + + if (!profile->patterns_context) { + skinny_profile_set(profile, "patterns-context","skinny-patterns"); } if (profile->port == 0) { diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index d8728510a6..314e29ba73 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -64,6 +64,8 @@ struct skinny_profile { unsigned int port; char *dialplan; char *context; + char *patterns_dialplan; + char *patterns_context; uint32_t keep_alive; char date_format[6]; int debug; @@ -99,6 +101,12 @@ struct skinny_device_type_params { }; typedef struct skinny_device_type_params skinny_device_type_params_t; +typedef enum { + SKINNY_ACTION_ROUTE, + SKINNY_ACTION_DROP, + SKINNY_ACTION_WAIT +} skinny_action_t; + /*****************************************************************************/ /* LISTENERS TYPES */ /*****************************************************************************/ diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 261ef98789..7acede0da5 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -500,12 +500,13 @@ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *li "Error Locking Session\n"); goto error; } + /* First create the caller profile in the patterns Dialplan */ if (!(tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(nsession), - NULL, listener->profile->dialplan, + NULL, listener->profile->patterns_dialplan, button->shortname, button->name, listener->remote_ip, NULL, NULL, NULL, "skinny" /* modname */, - listener->profile->context, + listener->profile->patterns_context, "")) != 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, "Error Creating Session caller profile\n"); @@ -548,6 +549,75 @@ done: return SWITCH_STATUS_SUCCESS; } +skinny_action_t skinny_session_dest_match_pattern(switch_core_session_t *session, char **data) +{ + skinny_action_t action = SKINNY_ACTION_DROP; + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + /* this part of the code is similar to switch_core_standard_on_routing() */ + if (!zstr(tech_pvt->profile->patterns_dialplan)) { + switch_dialplan_interface_t *dialplan_interface = NULL; + switch_caller_extension_t *extension = NULL; + char *expanded = NULL; + char *dpstr = NULL; + char *dp[25]; + int argc, x; + + if ((dpstr = switch_core_session_strdup(session, tech_pvt->profile->patterns_dialplan))) { + expanded = switch_channel_expand_variables(channel, dpstr); + argc = switch_separate_string(expanded, ',', dp, (sizeof(dp) / sizeof(dp[0]))); + for (x = 0; x < argc; x++) { + char *dpname = dp[x]; + char *dparg = NULL; + + if (dpname) { + if ((dparg = strchr(dpname, ':'))) { + *dparg++ = '\0'; + } + } else { + continue; + } + if (!(dialplan_interface = switch_loadable_module_get_dialplan_interface(dpname))) { + continue; + } + + extension = dialplan_interface->hunt_function(session, dparg, NULL); + UNPROTECT_INTERFACE(dialplan_interface); + + if (extension) { + goto found; + } + } + } +found: + while (extension && extension->current_application) { + switch_caller_application_t *current_application = extension->current_application; + + extension->current_application = extension->current_application->next; + + if (!strcmp(current_application->application_name, "skinny-route")) { + action = SKINNY_ACTION_ROUTE; + } else if (!strcmp(current_application->application_name, "skinny-drop")) { + action = SKINNY_ACTION_DROP; + } else if (!strcmp(current_application->application_name, "skinny-wait")) { + action = SKINNY_ACTION_WAIT; + *data = switch_core_session_strdup(session, current_application->application_data); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Unknown skinny dialplan application %s\n", current_application->application_name); + } + } + } + return action; +} + + struct skinny_session_process_dest_helper { private_t *tech_pvt; listener_t *listener; @@ -597,8 +667,11 @@ int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace) { + skinny_action_t action; switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; + char *data = NULL; + struct skinny_session_process_dest_helper helper = {0}; switch_assert(session); switch_assert(listener); @@ -633,19 +706,32 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list tech_pvt->caller_profile->destination_number = switch_core_strdup(tech_pvt->caller_profile->pool, dest); } - /* TODO Number is complete -> check against dialplan */ - if ((strlen(tech_pvt->caller_profile->destination_number) >= 4) || dest) { - struct skinny_session_process_dest_helper helper = {0}; - send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); - skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); - skinny_send_call_info(session, listener, line_instance); + if(dest) { + action = SKINNY_ACTION_ROUTE; + } else { + action = skinny_session_dest_match_pattern(session, &data); + } + switch(action) { + case SKINNY_ACTION_ROUTE: + tech_pvt->caller_profile->dialplan = switch_core_strdup(tech_pvt->caller_profile->pool, listener->profile->dialplan); + tech_pvt->caller_profile->context = switch_core_strdup(tech_pvt->caller_profile->pool, listener->profile->context); + send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); + skinny_send_call_info(session, listener, line_instance); - skinny_session_start_media(session, listener, line_instance); - - helper.tech_pvt = tech_pvt; - helper.listener = listener; - helper.line_instance = line_instance; - skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_process_dest_callback, &helper); + skinny_session_start_media(session, listener, line_instance); + + helper.tech_pvt = tech_pvt; + helper.listener = listener; + helper.line_instance = line_instance; + skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_process_dest_callback, &helper); + break; + case SKINNY_ACTION_WAIT: + /* for now, wait forever */ + break; + case SKINNY_ACTION_DROP: + default: + switch_channel_hangup(channel, SWITCH_CAUSE_UNALLOCATED_NUMBER); } return SWITCH_STATUS_SUCCESS;