diff --git a/src/mod/event_handlers/mod_rayo/Makefile.am b/src/mod/event_handlers/mod_rayo/Makefile.am index abaa612e67..5c0c5b4008 100644 --- a/src/mod/event_handlers/mod_rayo/Makefile.am +++ b/src/mod/event_handlers/mod_rayo/Makefile.am @@ -7,7 +7,7 @@ IKS_LA=$(IKS_BUILDDIR)/src/libiksemel.la mod_LTLIBRARIES = mod_rayo.la mod_rayo_la_SOURCES = mod_rayo.c iks_helpers.c nlsml.c rayo_components.c rayo_cpa_component.c rayo_cpa_detector.c rayo_elements.c rayo_fax_components.c -mod_rayo_la_SOURCES += rayo_input_component.c rayo_output_component.c rayo_prompt_component.c rayo_record_component.c sasl.c srgs.c xmpp_streams.c +mod_rayo_la_SOURCES += rayo_input_component.c rayo_output_component.c rayo_prompt_component.c rayo_record_component.c sasl.c srgs.c xmpp_streams.c rayo_exec_component.c mod_rayo_la_CFLAGS = $(AM_CFLAGS) -I$(IKS_DIR)/include $(PCRE_CFLAGS) mod_rayo_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(IKS_LA) $(PCRE_LIBS) mod_rayo_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/event_handlers/mod_rayo/rayo_components.c b/src/mod/event_handlers/mod_rayo/rayo_components.c index 1232bee47a..2d303fe3bb 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_components.c +++ b/src/mod/event_handlers/mod_rayo/rayo_components.c @@ -228,7 +228,8 @@ switch_status_t rayo_components_load(switch_loadable_module_interface_t **module rayo_output_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS || rayo_prompt_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS || rayo_record_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS || - rayo_fax_components_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) { + rayo_fax_components_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS || + rayo_exec_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_TERM; } return SWITCH_STATUS_SUCCESS; @@ -244,6 +245,7 @@ switch_status_t rayo_components_shutdown(void) rayo_prompt_component_shutdown(); rayo_record_component_shutdown(); rayo_fax_components_shutdown(); + rayo_exec_component_shutdown(); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/event_handlers/mod_rayo/rayo_components.h b/src/mod/event_handlers/mod_rayo/rayo_components.h index 5d1367d645..6cd30757a1 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_components.h +++ b/src/mod/event_handlers/mod_rayo/rayo_components.h @@ -1,6 +1,6 @@ /* * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2018, Grasshopper * * Version: MPL 1.1 * @@ -52,9 +52,13 @@ #define RAYO_FAX_NS RAYO_BASE "fax:" RAYO_VERSION #define RAYO_FAX_COMPLETE_NS RAYO_BASE "fax:complete:" RAYO_VERSION +#define RAYO_EXEC_NS RAYO_BASE "exec:" RAYO_VERSION +#define RAYO_EXEC_COMPLETE_NS RAYO_BASE "exec:complete:" RAYO_VERSION + #define COMPONENT_COMPLETE_STOP "stop", RAYO_EXT_COMPLETE_NS #define COMPONENT_COMPLETE_ERROR "error", RAYO_EXT_COMPLETE_NS #define COMPONENT_COMPLETE_HANGUP "hangup", RAYO_EXT_COMPLETE_NS +#define COMPONENT_COMPLETE_DONE "done", RAYO_EXT_COMPLETE_NS extern switch_status_t rayo_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); extern switch_status_t rayo_input_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); @@ -62,6 +66,7 @@ extern switch_status_t rayo_output_component_load(switch_loadable_module_interfa extern switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); extern switch_status_t rayo_record_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); extern switch_status_t rayo_fax_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); +extern switch_status_t rayo_exec_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); extern switch_status_t rayo_components_shutdown(void); extern switch_status_t rayo_input_component_shutdown(void); @@ -69,6 +74,7 @@ extern switch_status_t rayo_output_component_shutdown(void); extern switch_status_t rayo_prompt_component_shutdown(void); extern switch_status_t rayo_record_component_shutdown(void); extern switch_status_t rayo_fax_components_shutdown(void); +extern switch_status_t rayo_exec_component_shutdown(void); extern void rayo_component_send_start(struct rayo_component *component, iks *iq); extern void rayo_component_send_iq_error(struct rayo_component *component, iks *iq, const char *error_name, const char *error_type); diff --git a/src/mod/event_handlers/mod_rayo/rayo_elements.c b/src/mod/event_handlers/mod_rayo/rayo_elements.c index 1720471e31..d0892dca80 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_elements.c +++ b/src/mod/event_handlers/mod_rayo/rayo_elements.c @@ -121,6 +121,17 @@ ELEMENT(RAYO_SENDFAX) ATTRIB(xmlns,, any) ELEMENT_END +/** + * command validation + */ +ELEMENT(RAYO_APP) + ATTRIB(xmlns,, any) + ATTRIB(app,, any) + OPTIONAL_ATTRIB(args,, any) +ELEMENT_END + + + /* For Emacs: * Local Variables: diff --git a/src/mod/event_handlers/mod_rayo/rayo_elements.h b/src/mod/event_handlers/mod_rayo/rayo_elements.h index e76809cc9e..dc67a9fa4b 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_elements.h +++ b/src/mod/event_handlers/mod_rayo/rayo_elements.h @@ -39,6 +39,7 @@ ELEMENT_DECL(RAYO_PROMPT) ELEMENT_DECL(RAYO_RECEIVEFAX) ELEMENT_DECL(RAYO_RECORD) ELEMENT_DECL(RAYO_SENDFAX) +ELEMENT_DECL(RAYO_APP) #endif diff --git a/src/mod/event_handlers/mod_rayo/rayo_exec_component.c b/src/mod/event_handlers/mod_rayo/rayo_exec_component.c new file mode 100644 index 0000000000..a918f0136d --- /dev/null +++ b/src/mod/event_handlers/mod_rayo/rayo_exec_component.c @@ -0,0 +1,176 @@ +/* + * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2013-2018, Grasshopper + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is Grasshopper + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Rienzo + * + * rayo_exec_component.c -- Rayo call application execution component + * + */ +#include "rayo_components.h" +#include "rayo_elements.h" + + +/** + * An exec component + */ +struct exec_component { + /** component base class */ + struct rayo_component base; + /** Dialplan app */ + const char *app; + /** Dialplan app args */ + char *args; +}; + +#define EXEC_COMPONENT(x) ((struct exec_component *)x) + +/** + * Wrapper for executing dialplan app + */ +SWITCH_STANDARD_APP(rayo_app_exec) +{ + if (!zstr(data)) { + struct rayo_component *component = RAYO_COMPONENT_LOCATE(data); + if (component) { + switch_status_t status; + switch_channel_set_variable(switch_core_session_get_channel(session), SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, ""); + status = switch_core_session_execute_application(session, EXEC_COMPONENT(component)->app, EXEC_COMPONENT(component)->args); + if (status != SWITCH_STATUS_SUCCESS) { + rayo_component_send_complete(component, COMPONENT_COMPLETE_ERROR); + } else { + const char *resp = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE); + if (zstr(resp)) { + rayo_component_send_complete(component, COMPONENT_COMPLETE_DONE); + } else { + /* send complete event to client */ + iks *response = iks_new("app"); + iks_insert_attrib(response, "xmlns", RAYO_EXEC_COMPLETE_NS); + iks_insert_attrib(response, "response", resp); + rayo_component_send_complete_with_metadata(component, COMPONENT_COMPLETE_DONE, response, 1); + iks_delete(response); + } + } + RAYO_RELEASE(component); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing rayo exec component JID\n"); + } + switch_channel_set_variable(switch_core_session_get_channel(session), SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, ""); +} + +/** + * Create a record component + */ +static struct rayo_component *exec_component_create(struct rayo_actor *call, const char *client_jid, iks *exec) +{ + switch_memory_pool_t *pool; + struct exec_component *exec_component = NULL; + + switch_core_new_memory_pool(&pool); + exec_component = switch_core_alloc(pool, sizeof(*exec_component)); + exec_component = EXEC_COMPONENT(rayo_component_init(RAYO_COMPONENT(exec_component), pool, RAT_CALL_COMPONENT, "exec", NULL, call, client_jid)); + if (exec_component) { + exec_component->app = switch_core_strdup(pool, iks_find_attrib_soft(exec, "app")); + exec_component->args = switch_core_strdup(pool, iks_find_attrib_soft(exec, "args")); + } else { + switch_core_destroy_memory_pool(&pool); + return NULL; + } + + return RAYO_COMPONENT(exec_component); +} + +/** + * Execute dialplan APP on rayo call + */ +static iks *start_exec_app_component(struct rayo_actor *call, struct rayo_message *msg, void *data) +{ + iks *iq = msg->payload; + iks *exec = iks_find(iq, "app"); + struct rayo_component *exec_component = NULL; + switch_core_session_t *session = NULL; + + /* validate record attributes */ + if (!VALIDATE_RAYO_APP(exec)) { + return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); + } + + exec_component = exec_component_create(call, iks_find_attrib(iq, "from"), exec); + if (!exec_component) { + return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create exec entity"); + } + + session = switch_core_session_locate(call->id); + if (session) { + if (switch_core_session_execute_application_async(session, switch_core_session_strdup(session, "rayo-app-exec"), switch_core_session_strdup(session, RAYO_JID(exec_component))) != SWITCH_STATUS_SUCCESS) { + switch_core_session_rwunlock(session); + RAYO_RELEASE(exec_component); + RAYO_DESTROY(exec_component); + return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to execute app"); + } + switch_core_session_rwunlock(session); + } else { + RAYO_RELEASE(exec_component); + RAYO_DESTROY(exec_component); + return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Call is gone"); + } + + rayo_component_send_start(exec_component, iq); + + return NULL; +} + +/** + * Initialize exec component + * @param module_interface + * @param pool memory pool to allocate from + * @param config_file to use + * @return SWITCH_STATUS_SUCCESS if successful + */ +switch_status_t rayo_exec_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file) +{ + switch_application_interface_t *app_interface; + SWITCH_ADD_APP(app_interface, "rayo-app-exec", "Wrapper dialplan app for internal use only", "", rayo_app_exec, "", SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC); + rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_EXEC_NS":app", start_exec_app_component); + return SWITCH_STATUS_SUCCESS; +} + +/** + * Shutdown exec component + * @return SWITCH_STATUS_SUCCESS if successful + */ +switch_status_t rayo_exec_component_shutdown(void) +{ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet + */