Author: anthm Date: Fri Apr 20 19:45:14 2007 New Revision: 4993 Modified: freeswitch/trunk/src/include/switch_core.h freeswitch/trunk/src/include/switch_types.h freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c freeswitch/trunk/src/mod/dialplans/mod_dialplan_directory/mod_dialplan_directory.c freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c freeswitch/trunk/src/switch_core_session.c freeswitch/trunk/src/switch_core_state_machine.c Log: add new execute_extension application to execute another extension in the current scope Modified: freeswitch/trunk/src/include/switch_core.h ============================================================================== --- freeswitch/trunk/src/include/switch_core.h (original) +++ freeswitch/trunk/src/include/switch_core.h Fri Apr 20 19:45:14 2007 @@ -565,6 +565,8 @@ */ SWITCH_DECLARE(switch_status_t) switch_core_session_event_send(char *uuid_str, switch_event_t **event); +SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_session_t *session, char *exten, char *dialplan, char *context); + /*! \brief Send an event to a session translating it to it's native message format \param session the session to receive the event Modified: freeswitch/trunk/src/include/switch_types.h ============================================================================== --- freeswitch/trunk/src/include/switch_types.h (original) +++ freeswitch/trunk/src/include/switch_types.h Fri Apr 20 19:45:14 2007 @@ -999,7 +999,7 @@ typedef switch_bool_t (*switch_media_bug_callback_t) (switch_media_bug_t *, void *, switch_abc_type_t); typedef void (*switch_application_function_t) (switch_core_session_t *, char *); typedef void (*switch_event_callback_t) (switch_event_t *); -typedef switch_caller_extension_t *(*switch_dialplan_hunt_function_t) (switch_core_session_t *, void *); +typedef switch_caller_extension_t *(*switch_dialplan_hunt_function_t) (switch_core_session_t *, void *, switch_caller_profile_t *); typedef struct switch_scheduler_task switch_scheduler_task_t; typedef void (*switch_scheduler_func_t) (switch_scheduler_task_t *task); typedef switch_status_t (*switch_state_handler_t) (switch_core_session_t *); Modified: freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c ============================================================================== --- freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c (original) +++ freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c Fri Apr 20 19:45:14 2007 @@ -36,6 +36,7 @@ static const char modname[] = "mod_dptools"; static const switch_application_interface_t detect_speech_application_interface; +static const switch_application_interface_t exe_application_interface; static void detect_speech_function(switch_core_session_t *session, char *data) { @@ -64,6 +65,26 @@ } +static void exe_function(switch_core_session_t *session, char *data) +{ + char *argv[4]; + int argc; + char *lbuf = NULL; + char *extension; + char *context; + char *dialplan; + + if (data && (lbuf = switch_core_session_strdup(session, data)) + && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + extension = argv[0]; + dialplan = argv[1]; + context = argv[2]; + switch_core_session_execute_exten(session, extension, dialplan, context); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", exe_application_interface.syntax); + } +} + static void ring_ready_function(switch_core_session_t *session, char *data) { switch_channel_t *channel; @@ -606,7 +627,7 @@ } -static switch_api_interface_t strepoch_api_interface = { +static const switch_api_interface_t strepoch_api_interface = { /*.interface_name */ "strepoch", /*.desc */ "Convert a date string into epoch time", /*.function */ strepoch_api_function, @@ -614,7 +635,7 @@ /*.next */ NULL }; -static switch_api_interface_t chat_api_interface = { +static const switch_api_interface_t chat_api_interface = { /*.interface_name */ "chat", /*.desc */ "chat", /*.function */ chat_api_function, @@ -622,7 +643,7 @@ /*.next */ &strepoch_api_interface }; -static switch_api_interface_t dptools_api_interface = { +static const switch_api_interface_t dptools_api_interface = { /*.interface_name */ "strftime", /*.desc */ "strftime", /*.function */ strftime_api_function, @@ -630,7 +651,7 @@ /*.next */ &chat_api_interface }; -static switch_api_interface_t presence_api_interface = { +static const switch_api_interface_t presence_api_interface = { /*.interface_name */ "presence", /*.desc */ "presence", /*.function */ presence_api_function, @@ -639,18 +660,27 @@ }; +static const switch_application_interface_t exe_application_interface = { + /*.interface_name */ "execute_extension", + /*.application_function */ exe_function, + /*.long_desc */ "Execute an extension", + /*.short_desc */ "Execute an extension", + /*.syntax */ "<extension> <dialplan> <context>", + /* flags */ SAF_SUPPORT_NOMEDIA, + /*.next */ +}; -static switch_application_interface_t sched_transfer_application_interface = { +static const switch_application_interface_t sched_transfer_application_interface = { /*.interface_name */ "sched_transfer", /*.application_function */ sched_transfer_function, /*.long_desc */ "Schedule a transfer in the future", /*.short_desc */ "Schedule a transfer in the future", /*.syntax */ "[+]<time> <extension> <dialplan> <context>", /* flags */ SAF_SUPPORT_NOMEDIA, - /*.next */ NULL + /*.next */ &exe_application_interface }; -static switch_application_interface_t sched_broadcast_application_interface = { +static const switch_application_interface_t sched_broadcast_application_interface = { /*.interface_name */ "sched_broadcast", /*.application_function */ sched_broadcast_function, /*.long_desc */ "Schedule a broadcast in the future", @@ -660,7 +690,7 @@ /*.next */ &sched_transfer_application_interface }; -static switch_application_interface_t sched_hangup_application_interface = { +static const switch_application_interface_t sched_hangup_application_interface = { /*.interface_name */ "sched_hangup", /*.application_function */ sched_hangup_function, /*.long_desc */ "Schedule a hangup in the future", Modified: freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c ============================================================================== --- freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c (original) +++ freeswitch/trunk/src/mod/applications/mod_enum/mod_enum.c Fri Apr 20 19:45:14 2007 @@ -519,10 +519,9 @@ } -static switch_caller_extension_t *enum_dialplan_hunt(switch_core_session_t *session, void *arg) +static switch_caller_extension_t *enum_dialplan_hunt(switch_core_session_t *session, void *arg, switch_caller_profile_t *caller_profile) { switch_caller_extension_t *extension = NULL; - switch_caller_profile_t *caller_profile; enum_record_t *results, *rp; switch_channel_t *channel = switch_core_session_get_channel(session); enum_route_t *rtp; @@ -530,7 +529,9 @@ assert(channel != NULL); - caller_profile = switch_channel_get_caller_profile(channel); + if (!caller_profile) { + caller_profile = switch_channel_get_caller_profile(channel); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ENUM Lookup on %s\n", caller_profile->destination_number); Modified: freeswitch/trunk/src/mod/dialplans/mod_dialplan_directory/mod_dialplan_directory.c ============================================================================== --- freeswitch/trunk/src/mod/dialplans/mod_dialplan_directory/mod_dialplan_directory.c (original) +++ freeswitch/trunk/src/mod/dialplans/mod_dialplan_directory/mod_dialplan_directory.c Fri Apr 20 19:45:14 2007 @@ -83,9 +83,8 @@ switch_xml_free(xml); } -static switch_caller_extension_t *directory_dialplan_hunt(switch_core_session_t *session, void *arg) +static switch_caller_extension_t *directory_dialplan_hunt(switch_core_session_t *session, void *arg, switch_caller_profile_t *caller_profile) { - switch_caller_profile_t *caller_profile; switch_caller_extension_t *extension = NULL; switch_channel_t *channel; char *var, *val; @@ -97,8 +96,10 @@ channel = switch_core_session_get_channel(session); assert(channel != NULL); - caller_profile = switch_channel_get_caller_profile(channel); - + if (!caller_profile) { + caller_profile = switch_channel_get_caller_profile(channel); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Hello %s You Dialed %s!\n", caller_profile->caller_id_name, caller_profile->destination_number); Modified: freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c ============================================================================== --- freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c (original) +++ freeswitch/trunk/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c Fri Apr 20 19:45:14 2007 @@ -43,17 +43,15 @@ BREAK_NEVER } break_t; -static int parse_exten(switch_core_session_t *session, switch_xml_t xexten, switch_caller_extension_t **extension) +static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *caller_profile, switch_xml_t xexten, switch_caller_extension_t **extension) { switch_xml_t xcond, xaction; - switch_caller_profile_t *caller_profile; switch_channel_t *channel; char *exten_name = (char *) switch_xml_attr_soft(xexten, "name"); int proceed = 0; switch_stream_handle_t stream = { 0 }; channel = switch_core_session_get_channel(session); - caller_profile = switch_channel_get_caller_profile(channel); for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next) { char *field = NULL; @@ -291,24 +289,26 @@ return status; } -static switch_caller_extension_t *dialplan_hunt(switch_core_session_t *session, void *arg) +static switch_caller_extension_t *dialplan_hunt(switch_core_session_t *session, void *arg, switch_caller_profile_t *caller_profile) { - switch_caller_profile_t *caller_profile; switch_caller_extension_t *extension = NULL; switch_channel_t *channel; switch_xml_t alt_root = NULL, cfg, xml = NULL, xcontext, xexten; char *alt_path = (char *) arg; - + channel = switch_core_session_get_channel(session); - if ((caller_profile = switch_channel_get_caller_profile(channel))) { - if (!caller_profile->context) { - caller_profile->context = "default"; + if (!caller_profile) { + if (!(caller_profile = switch_channel_get_caller_profile(channel))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Obtaining Profile!\n"); + goto done; } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Obtaining Profile!\n"); - goto done; } + + if (!caller_profile->context) { + caller_profile->context = "default"; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Processing %s->%s!\n", caller_profile->caller_id_name, caller_profile->destination_number); @@ -352,7 +352,7 @@ int proceed = 0; char *cont = (char *) switch_xml_attr_soft(xexten, "continue"); - proceed = parse_exten(session, xexten, &extension); + proceed = parse_exten(session, caller_profile, xexten, &extension); if (proceed && !switch_true(cont)) { break; Modified: freeswitch/trunk/src/switch_core_session.c ============================================================================== --- freeswitch/trunk/src/switch_core_session.c (original) +++ freeswitch/trunk/src/switch_core_session.c Fri Apr 20 19:45:14 2007 @@ -871,3 +871,121 @@ switch_core_hash_init(&runtime.session_table, runtime.memory_pool); switch_mutex_init(&runtime.session_table_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool); } + + +SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_session_t *session, char *exten, char *dialplan, char *context) +{ + char *dp[25]; + char *dpstr; + int argc, x, count = 0; + char *expanded = NULL; + switch_caller_profile_t *profile, *new_profile; + switch_channel_t *channel; + switch_dialplan_interface_t *dialplan_interface = NULL; + switch_caller_extension_t *extension = NULL; + const switch_application_interface_t *application_interface; + switch_event_t *event; + + channel = switch_core_session_get_channel(session); + + if (!(profile = switch_channel_get_caller_profile(channel))) { + return SWITCH_STATUS_SUCCESS; + } + + new_profile = switch_caller_profile_clone(session, profile); + new_profile->destination_number = switch_core_session_strdup(session, exten); + + if (!switch_strlen_zero(dialplan)) { + new_profile->dialplan = switch_core_session_strdup(session, dialplan); + } + + if (!switch_strlen_zero(context)) { + new_profile->context = switch_core_session_strdup(session, context); + } + + if (!(dpstr = switch_core_session_strdup(session, new_profile->dialplan))) { + abort(); + } + + argc = switch_separate_string(dpstr, ',', 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'; + } + } + if (!(dialplan_interface = switch_loadable_module_get_dialplan_interface(dpname))) { + continue; + } + + count++; + + if ((extension = dialplan_interface->hunt_function(session, dparg, new_profile)) != 0) { + break; + } + } + + if (!extension) { + return SWITCH_STATUS_FALSE; + } + + while (switch_channel_ready(channel) && extension->current_application) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Execute %s(%s)\n", + extension->current_application->application_name, switch_str_nil(extension->current_application->application_data)); + if ((application_interface = switch_loadable_module_get_application_interface(extension->current_application->application_name)) == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Application %s\n", extension->current_application->application_name); + return SWITCH_STATUS_FALSE; + } + + if (switch_channel_test_flag(session->channel, CF_NOMEDIA) && !switch_test_flag(application_interface, SAF_SUPPORT_NOMEDIA)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Application %s Cannot be used with NO_MEDIA mode!\n", + extension->current_application->application_name); + return SWITCH_STATUS_FALSE; + } + + if (!application_interface->application_function) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Function for %s\n", extension->current_application->application_name); + return SWITCH_STATUS_FALSE; + } + + if ((expanded = + switch_channel_expand_variables(session->channel, + extension->current_application->application_data)) != extension->current_application->application_data) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Expanded String %s(%s)\n", extension->current_application->application_name, + expanded); + } + + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(session->channel, event); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "%s", extension->current_application->application_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data-Orig", "%s", extension->current_application->application_data); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", expanded); + switch_event_fire(&event); + } + + + if (switch_channel_get_variable(session->channel, "presence_id")) { + char *arg = switch_mprintf("%s(%s)", extension->current_application->application_name, expanded); + if (arg) { + switch_channel_presence(session->channel, "unknown", arg); + switch_safe_free(arg); + } + } + + application_interface->application_function(session, expanded); + + if (expanded != extension->current_application->application_data) { + switch_safe_free(expanded); + } + + extension->current_application = extension->current_application->next; + } + + return SWITCH_STATUS_SUCCESS; + +} + + Modified: freeswitch/trunk/src/switch_core_state_machine.c ============================================================================== --- freeswitch/trunk/src/switch_core_state_machine.c (original) +++ freeswitch/trunk/src/switch_core_state_machine.c Fri Apr 20 19:45:14 2007 @@ -82,7 +82,7 @@ count++; - if ((extension = dialplan_interface->hunt_function(session, dparg)) != 0) { + if ((extension = dialplan_interface->hunt_function(session, dparg, NULL)) != 0) { switch_channel_set_caller_extension(session->channel, extension); return; }