diff --git a/UPGRADE.txt b/UPGRADE.txt index d4c059bae5..6c76841f01 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -35,6 +35,11 @@ res_ais: Dialplan Functions: - MAILBOX_EXISTS has been deprecated. Use VM_INFO with the 'exists' parameter instead. + - Macro has been deprecated in favor of GoSub. For redirecting and connected + line purposes use the following variables instead of their macro equivalents: + REDIRECTING_SEND_SUB, REDIRECTING_SEND_SUB_ARGS, + CONNECTED_LINE_SEND_SUB, CONNECTED_LINE_SEND_SUB_ARGS. + func_enum: - ENUM query functions now return a count of -1 on lookup error to @@ -62,6 +67,10 @@ AMI: - DBDelTree now correctly returns an error when 0 rows are deleted just as the DBDel action does. +CCSS: + - Macro is deprecated. Use cc_callback_sub instead of cc_callback_macro + in channel configurations. + app_meetme: - The 'c' option (announce user count) will now work even if the 'q' (quiet) option is enabled. diff --git a/apps/app_dial.c b/apps/app_dial.c index 03eae32ea1..20747c0f65 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -956,7 +956,8 @@ static void do_forward(struct chanlist *o, ast_party_redirecting_init(&redirecting); ast_party_redirecting_copy(&redirecting, &c->redirecting); ast_channel_unlock(c); - if (ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) { + if (ast_channel_redirecting_sub(c, in, &redirecting, 0) && + ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) { ast_channel_update_redirecting(in, &redirecting, NULL); } ast_party_redirecting_free(&redirecting); @@ -1105,7 +1106,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in)); if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { if (o->pending_connected_update) { - if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { + if (ast_channel_connected_line_sub(c, in, &o->connected, 0) && + ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); } } else if (!ast_test_flag64(o, DIAL_CALLERID_ABSENT)) { @@ -1175,7 +1177,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in)); if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { if (o->pending_connected_update) { - if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { + if (ast_channel_connected_line_sub(c, in, &o->connected, 0) && + ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); } } else if (!ast_test_flag64(o, DIAL_CALLERID_ABSENT)) { @@ -1308,7 +1311,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_party_connected_line_free(&connected); o->pending_connected_update = 1; } else { - if (ast_channel_connected_line_macro(c, in, f, 1, 1)) { + if (ast_channel_connected_line_sub(c, in, f, 1) && + ast_channel_connected_line_macro(c, in, f, 1, 1)) { ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); } } @@ -1329,7 +1333,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(in)); } else if (single) { ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ast_channel_name(c), ast_channel_name(in)); - if (ast_channel_redirecting_macro(c, in, f, 1, 1)) { + if (ast_channel_redirecting_sub(c, in, f, 1) && + ast_channel_redirecting_macro(c, in, f, 1, 1)) { ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); } pa->sentringing = 0; @@ -1488,12 +1493,14 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); break; case AST_CONTROL_CONNECTED_LINE: - if (ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) { + if (ast_channel_connected_line_sub(in, o->chan, f, 1) && + ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) { ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); } break; case AST_CONTROL_REDIRECTING: - if (ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) { + if (ast_channel_redirecting_sub(in, o->chan, f, 1) && + ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) { ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); } break; diff --git a/apps/app_followme.c b/apps/app_followme.c index 1bf9547a92..dc824f573e 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -1304,7 +1304,8 @@ static int app_exec(struct ast_channel *chan, const char *data) /* Update connected line to caller if available. */ if (targs.pending_out_connected_update) { - if (ast_channel_connected_line_macro(outbound, caller, &targs.connected_out, 1, 0)) { + if (ast_channel_connected_line_sub(outbound, caller, &targs.connected_out, 0) && + ast_channel_connected_line_macro(outbound, caller, &targs.connected_out, 1, 0)) { ast_channel_update_connected_line(caller, &targs.connected_out, NULL); } } @@ -1329,7 +1330,8 @@ static int app_exec(struct ast_channel *chan, const char *data) /* Update connected line to winner if changed. */ if (targs.pending_in_connected_update) { - if (ast_channel_connected_line_macro(caller, outbound, &targs.connected_in, 0, 0)) { + if (ast_channel_connected_line_sub(caller, outbound, &targs.connected_in, 0) && + ast_channel_connected_line_macro(caller, outbound, &targs.connected_in, 0, 0)) { ast_channel_update_connected_line(outbound, &targs.connected_in, NULL); } } diff --git a/apps/app_queue.c b/apps/app_queue.c index 0add6c2097..834e090829 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -3645,7 +3645,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); if (update_connectedline) { if (o->pending_connected_update) { - if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { + if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) && + ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); } } else if (!o->dial_callerid_absent) { @@ -3744,8 +3745,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_party_redirecting_init(&redirecting); ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); ast_channel_unlock(o->chan); - res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0); - if (res) { + if ((res = ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) && + (res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0))) { ast_channel_update_redirecting(in, &redirecting, NULL); } ast_party_redirecting_free(&redirecting); @@ -3774,7 +3775,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); if (update_connectedline) { if (o->pending_connected_update) { - if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { + if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) && + ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); } } else if (!o->dial_callerid_absent) { @@ -3858,7 +3860,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_party_connected_line_free(&connected); o->pending_connected_update = 1; } else { - if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { + if (ast_channel_connected_line_sub(o->chan, in, f, 1) && + ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); } } @@ -3879,7 +3882,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_verb(3, "Redirecting update to %s prevented\n", inchan_name); } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name); - if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { + if (ast_channel_redirecting_sub(o->chan, in, f, 1) && + ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); } } diff --git a/configs/ccss.conf.sample b/configs/ccss.conf.sample index 2636f7ec9e..21b0b0668d 100644 --- a/configs/ccss.conf.sample +++ b/configs/ccss.conf.sample @@ -187,6 +187,12 @@ ; ;cc_callback_macro= ; +; Alternatively, the administrator may run a subroutine. By default +; there is no callback subroutine configured. The subroutine should +; be specified in the format: [[context,]exten,]priority +; +;cc_callback_sub= +; ; When using an ISDN phone and a generic CC agent, Asterisk is unable ; to determine the dialstring that should be used when calling back ; the original caller. Furthermore, if you desire to use any dialstring- diff --git a/include/asterisk/app.h b/include/asterisk/app.h index 87f7c80ede..359c2b1a6e 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -131,9 +131,29 @@ int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int * \retval 0 success * \retval -1 failure */ -int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel +int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char * const macro_name, const char * const macro_args); +/*! + * \since 11 + * \brief Run a subroutine on a channel, placing a second channel into autoservice. + * + * This is a shorthand method that makes it very easy to run a subroutine on any given + * channel. It is perfectly reasonable to supply a NULL autoservice_chan here in case + * there is no channel to place into autoservice. It is very important that the + * autoservice_chan parameter is not locked prior to calling ast_app_run_sub. A + * deadlock could result, otherwise. + * + * \param autoservice_chan A channel to place into autoservice while the subroutine is run + * \param sub_chan The channel to run the subroutine on + * \param name The name of the subroutine to run + * \param args The arguments to pass to the subroutien + * \retval 0 success + * \retval -1 failure + */ +int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel + *sub_chan, const char * const name, const char * const args); + /*! * \brief Set voicemail function callbacks * \param[in] has_voicemail_func set function pointer diff --git a/include/asterisk/ccss.h b/include/asterisk/ccss.h index ae85e044f4..acb3148c7f 100644 --- a/include/asterisk/ccss.h +++ b/include/asterisk/ccss.h @@ -386,11 +386,28 @@ const char *ast_get_cc_callback_macro(struct ast_cc_config_params *config); * \since 1.8 * \brief Set the callback_macro name * \param config The configuration to set the callback_macro on - * \param value The new callback macro we want to change to + * \param value The new callback macro we want to change to * \retval void */ void ast_set_cc_callback_macro(struct ast_cc_config_params *config, const char * const value); +/*! + * \since 11 + * \brief Get the name of the callback subroutine + * \param config The configuration to retrieve the callback_sub from + * \return The callback_sub name + */ +const char *ast_get_cc_callback_sub(struct ast_cc_config_params *config); + +/*! + * \since 11 + * \brief Set the callback subroutine name + * \param config The configuration to set the callback_sub on + * \param value The new callback subroutine we want to change to + * \retval void + */ +void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char * const value); + /* END CONFIGURATION FUNCTIONS */ /* BEGIN AGENT/MONITOR REGISTRATION API */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 7b4313b2b9..20fcc43441 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -3418,30 +3418,56 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct * \since 1.8 * \brief Run a connected line interception macro and update a channel's connected line * information + * \deprecated You should use the ast_channel_connected_line_sub() function instead. * * Whenever we want to update a channel's connected line information, we may need to run * a macro so that an administrator can manipulate the information before sending it * out. This function both runs the macro and sends the update to the channel. * * \param autoservice_chan Channel to place into autoservice while the macro is running. - * It is perfectly safe for this to be NULL + * It is perfectly safe for this to be NULL * \param macro_chan The channel to run the macro on. Also the channel from which we - * determine which macro we need to run. + * determine which macro we need to run. * \param connected_info Either an ast_party_connected_line or ast_frame pointer of type - * AST_CONTROL_CONNECTED_LINE - * \param caller If true, then run CONNECTED_LINE_CALLER_SEND_MACRO, otherwise run - * CONNECTED_LINE_CALLEE_SEND_MACRO + * AST_CONTROL_CONNECTED_LINE + * \param is_caller If true, then run CONNECTED_LINE_CALLER_SEND_MACRO with arguments from + * CONNECTED_LINE_CALLER_SEND_MACRO_ARGS, otherwise run CONNECTED_LINE_CALLEE_SEND_MACRO + * with arguments from CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS * \param frame If true, then connected_info is an ast_frame pointer, otherwise it is an - * ast_party_connected_line pointer. + * ast_party_connected_line pointer. * \retval 0 Success * \retval -1 Either the macro does not exist, or there was an error while attempting to - * run the macro + * run the macro * * \todo Have multiple return codes based on the MACRO_RESULT * \todo Make constants so that caller and frame can be more expressive than just '1' and - * '0' + * '0' + */ +int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame); + +/*! + * \since 11 + * \brief Run a connected line interception subroutine and update a channel's connected line + * information + * + * Whenever we want to update a channel's connected line information, we may need to run + * a subroutine so that an administrator can manipulate the information before sending it + * out. This function both runs the subroutine specified by CONNECTED_LINE_SEND_SUB and + * sends the update to the channel. + * + * \param autoservice_chan Channel to place into autoservice while the sub is running. + * It is perfectly safe for this to be NULL + * \param sub_chan The channel to run the subroutine on. Also the channel from which we + * determine which subroutine we need to run. + * \param connected_info Either an ast_party_connected_line or ast_frame pointer of type + * AST_CONTROL_CONNECTED_LINE + * \param frame If true, then connected_info is an ast_frame pointer, otherwise it is an + * ast_party_connected_line pointer. + * \retval 0 Success + * \retval -1 Either the subroutine does not exist, or there was an error while attempting to + * run the subroutine */ -int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame); +int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame); /*! * \brief Insert into an astdata tree, the channel structure. @@ -3467,6 +3493,7 @@ int ast_channel_data_cmp_structure(const struct ast_data_search *tree, struct as /*! * \since 1.8 * \brief Run a redirecting interception macro and update a channel's redirecting information + * \deprecated You should use the ast_channel_redirecting_sub() function instead. * * \details * Whenever we want to update a channel's redirecting information, we may need to run @@ -3479,8 +3506,9 @@ int ast_channel_data_cmp_structure(const struct ast_data_search *tree, struct as * determine which macro we need to run. * \param redirecting_info Either an ast_party_redirecting or ast_frame pointer of type * AST_CONTROL_REDIRECTING - * \param is_caller If true, then run REDIRECTING_CALLER_SEND_MACRO, otherwise run - * REDIRECTING_CALLEE_SEND_MACRO + * \param is_caller If true, then run REDIRECTING_CALLER_SEND_MACRO with arguments from + * REDIRECTING_CALLER_SEND_MACRO_ARGS, otherwise run REDIRECTING_CALLEE_SEND_MACRO with + * arguments from REDIRECTING_CALLEE_SEND_MACRO_ARGS * \param is_frame If true, then redirecting_info is an ast_frame pointer, otherwise it is an * ast_party_redirecting pointer. * @@ -3494,6 +3522,31 @@ int ast_channel_data_cmp_structure(const struct ast_data_search *tree, struct as */ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame); +/*! + * \since 11 + * \brief Run a redirecting interception subroutine and update a channel's redirecting information + * + * \details + * Whenever we want to update a channel's redirecting information, we may need to run + * a subroutine so that an administrator can manipulate the information before sending it + * out. This function both runs the subroutine specified by REDIRECTING_SEND_SUB and + * sends the update to the channel. + * + * \param autoservice_chan Channel to place into autoservice while the subroutine is running. + * It is perfectly safe for this to be NULL + * \param sub_chan The channel to run the subroutine on. Also the channel from which we + * determine which subroutine we need to run. + * \param redirecting_info Either an ast_party_redirecting or ast_frame pointer of type + * AST_CONTROL_REDIRECTING + * \param is_frame If true, then redirecting_info is an ast_frame pointer, otherwise it is an + * ast_party_redirecting pointer. + * + * \retval 0 Success + * \retval -1 Either the subroutine does not exist, or there was an error while attempting to + * run the subroutine + */ +int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame); + #include "asterisk/ccss.h" /*! diff --git a/main/app.c b/main/app.c index d9f56a4aa3..f937b0e30b 100644 --- a/main/app.c +++ b/main/app.c @@ -247,28 +247,79 @@ int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int return res; } -int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char * const macro_name, const char * const macro_args) +static int app_exec_dialplan(struct ast_channel *autoservice_chan, struct ast_channel *exec_chan, const char * const args, int use_gosub) { - struct ast_app *macro_app; + + struct ast_app *app; int res; - char buf[1024]; + char * app_type = use_gosub ? "GoSub" : "Macro"; - macro_app = pbx_findapp("Macro"); - if (!macro_app) { - ast_log(LOG_WARNING, "Cannot run macro '%s' because the 'Macro' application in not available\n", macro_name); + app = pbx_findapp(app_type); + if (!app) { + ast_log(LOG_WARNING, "Cannot run '%s' because the '%s' application is not available\n", args, app_type); return -1; } - snprintf(buf, sizeof(buf), "%s%s%s", macro_name, ast_strlen_zero(macro_args) ? "" : ",", S_OR(macro_args, "")); if (autoservice_chan) { ast_autoservice_start(autoservice_chan); } - res = pbx_exec(macro_chan, macro_app, buf); + res = pbx_exec(exec_chan, app, args); + if (use_gosub && !res) { + struct ast_pbx_args gosub_args = {{0}}; + struct ast_pbx *pbx = ast_channel_pbx(exec_chan); + /* supress warning about a pbx already being on the channel */ + ast_channel_pbx_set(exec_chan, NULL); + gosub_args.no_hangup_chan = 1; + ast_pbx_run_args(exec_chan, &gosub_args); + if (ast_channel_pbx(exec_chan)) { + ast_free(ast_channel_pbx(exec_chan)); + } + ast_channel_pbx_set(exec_chan, pbx); + } if (autoservice_chan) { ast_autoservice_stop(autoservice_chan); } return res; } +int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char * const name, const char * const args) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "%s%s%s", name, ast_strlen_zero(args) ? "" : ",", S_OR(args, "")); + return app_exec_dialplan(autoservice_chan, macro_chan, buf, 0); +} + +int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char * const location, const char * const args) +{ + char buf[1024]; + size_t offset = snprintf(buf, sizeof(buf), "%s", location); + /* need to bump the priority by one if we already have a pbx */ + if (ast_channel_pbx(sub_chan)) { + int iprio; + const char * priority = location; + const char * next = strchr(priority,','); + /* jump to the priority portion of the location */ + if (next) { + priority = next + 1; + } + next = strchr(priority,','); + if (next) { + priority = next + 1; + } + /* if the priority isn't numeric, it's as if we never took this branch... */ + if (sscanf(priority, "%d", &iprio)) { + offset = priority - location; + iprio++; + if (offset < sizeof(buf)) { + offset += snprintf(buf + offset, sizeof(buf) - offset, "%d", iprio); + } + } + } + if (offset < sizeof(buf)) { + snprintf(buf + offset, sizeof(buf) - offset, "%s%s%s", ast_strlen_zero(args) ? "" : "(", S_OR(args, ""), ast_strlen_zero(args) ? "" : ")"); + } + return app_exec_dialplan(autoservice_chan, sub_chan, buf, 1); +} + static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL; static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL; static int (*ast_inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL; diff --git a/main/ccss.c b/main/ccss.c index f1965986d6..ad3e82ec0b 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -156,6 +156,7 @@ struct ast_cc_config_params { unsigned int cc_max_agents; unsigned int cc_max_monitors; char cc_callback_macro[AST_MAX_EXTENSION]; + char cc_callback_sub[AST_MAX_EXTENSION]; char cc_agent_dialstring[AST_MAX_EXTENSION]; }; @@ -654,6 +655,7 @@ static const struct ast_cc_config_params cc_default_params = { .cc_max_agents = CC_MAX_AGENTS_DEFAULT, .cc_max_monitors = CC_MAX_MONITORS_DEFAULT, .cc_callback_macro = "", + .cc_callback_sub = "", .cc_agent_dialstring = "", }; @@ -751,6 +753,8 @@ int ast_cc_get_param(struct ast_cc_config_params *params, const char * const nam if (!strcasecmp(name, "cc_callback_macro")) { value = ast_get_cc_callback_macro(params); + } else if (!strcasecmp(name, "cc_callback_sub")) { + value = ast_get_cc_callback_sub(params); } else if (!strcasecmp(name, "cc_agent_policy")) { value = agent_policy_to_str(ast_get_cc_agent_policy(params)); } else if (!strcasecmp(name, "cc_monitor_policy")) { @@ -800,6 +804,9 @@ int ast_cc_set_param(struct ast_cc_config_params *params, const char * const nam } else if (!strcasecmp(name, "cc_callback_macro")) { ast_set_cc_callback_macro(params, value); return 0; + } else if (!strcasecmp(name, "cc_callback_sub")) { + ast_set_cc_callback_sub(params, value); + return 0; } if (!sscanf(value, "%30u", &value_as_uint) == 1) { @@ -836,6 +843,7 @@ int ast_cc_is_config_param(const char * const name) !strcasecmp(name, "cc_max_agents") || !strcasecmp(name, "cc_max_monitors") || !strcasecmp(name, "cc_callback_macro") || + !strcasecmp(name, "cc_callback_sub") || !strcasecmp(name, "cc_agent_dialstring") || !strcasecmp(name, "cc_recall_timer")); } @@ -978,8 +986,14 @@ const char *ast_get_cc_callback_macro(struct ast_cc_config_params *config) return config->cc_callback_macro; } +const char *ast_get_cc_callback_sub(struct ast_cc_config_params *config) +{ + return config->cc_callback_sub; +} + void ast_set_cc_callback_macro(struct ast_cc_config_params *config, const char * const value) { + ast_log(LOG_WARNING, "Usage of cc_callback_macro is deprecated. Please use cc_callback_sub instead.\n"); if (ast_strlen_zero(value)) { config->cc_callback_macro[0] = '\0'; } else { @@ -987,6 +1001,15 @@ void ast_set_cc_callback_macro(struct ast_cc_config_params *config, const char * } } +void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char * const value) +{ + if (ast_strlen_zero(value)) { + config->cc_callback_sub[0] = '\0'; + } else { + ast_copy_string(config->cc_callback_sub, value, sizeof(config->cc_callback_sub)); + } +} + struct cc_monitor_backend { AST_LIST_ENTRY(cc_monitor_backend) next; const struct ast_cc_monitor_callbacks *callbacks; @@ -2651,6 +2674,7 @@ static void *generic_recall(void *data) int reason; struct ast_channel *chan; const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params); + const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params); unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000; struct ast_format tmp_fmt; struct ast_format_cap *tmp_cap = ast_format_cap_alloc_nolock(); @@ -2700,6 +2724,16 @@ static void *generic_recall(void *data) return NULL; } } + + if (!ast_strlen_zero(callback_sub)) { + ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback subroutine configured for agent %s\n", + agent->core_id, agent->device_name); + if (ast_app_run_sub(NULL, chan, callback_sub, NULL)) { + ast_cc_failed(agent->core_id, "Callback subroutine to %s failed. Maybe a hangup?", agent->device_name); + ast_hangup(chan); + return NULL; + } + } ast_cc_agent_recalling(agent->core_id, "Generic agent %s is recalling", agent->device_name); ast_pbx_start(chan); return NULL; diff --git a/main/channel.c b/main/channel.c index 95fb9259aa..f4717cc3d7 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3819,7 +3819,8 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_party_connected_line_free(&connected); break; } - if (ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) { + if (ast_channel_connected_line_sub(NULL, chan, &connected, 0) && + ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) { ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, read_action_payload->payload, read_action_payload->payload_size); @@ -5237,7 +5238,8 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe ast_channel_lock(orig); ast_party_redirecting_copy(&redirecting, &orig->redirecting); ast_channel_unlock(orig); - if (ast_channel_redirecting_macro(orig, parent, &redirecting, 1, 0)) { + if (ast_channel_redirecting_sub(orig, parent, &redirecting, 0) && + ast_channel_redirecting_macro(orig, parent, &redirecting, 1, 0)) { ast_channel_update_redirecting(parent, &redirecting, NULL); } ast_party_redirecting_free(&redirecting); @@ -7128,12 +7130,14 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); break; case AST_CONTROL_REDIRECTING: - if (ast_channel_redirecting_macro(who, other, f, other == c0, 1)) { + if (ast_channel_redirecting_sub(who, other, f, 1) && + ast_channel_redirecting_macro(who, other, f, other == c0, 1)) { ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); } break; case AST_CONTROL_CONNECTED_LINE: - if (ast_channel_connected_line_macro(who, other, f, other == c0, 1)) { + if (ast_channel_connected_line_sub(who, other, f, 1) && + ast_channel_connected_line_macro(who, other, f, other == c0, 1)) { ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); } break; @@ -9362,6 +9366,7 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int is_frame) { + static int deprecation_warning = 0; const char *macro; const char *macro_args; int retval; @@ -9379,6 +9384,10 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc return -1; } + if (!deprecation_warning) { + deprecation_warning = 1; + ast_log(LOG_WARNING, "Usage of CONNECTED_LINE_CALLE[ER]_SEND_MACRO is deprecated. Please use CONNECTED_LINE_SEND_SUB instead.\n"); + } if (is_frame) { const struct ast_frame *frame = connected_info; @@ -9401,6 +9410,7 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame) { + static int deprecation_warning = 0; const char *macro; const char *macro_args; int retval; @@ -9418,6 +9428,10 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a return -1; } + if (!deprecation_warning) { + deprecation_warning = 1; + ast_log(LOG_WARNING, "Usage of REDIRECTING_CALLE[ER]_SEND_MACRO is deprecated. Please use REDIRECTING_SEND_SUB instead.\n"); + } if (is_frame) { const struct ast_frame *frame = redirecting_info; @@ -9439,6 +9453,81 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a return retval; } +int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int is_frame) +{ + const char *sub; + const char *sub_args; + int retval; + + ast_channel_lock(sub_chan); + sub = pbx_builtin_getvar_helper(sub_chan, "CONNECTED_LINE_SEND_SUB"); + sub = ast_strdupa(S_OR(sub, "")); + sub_args = pbx_builtin_getvar_helper(sub_chan, "CONNECTED_LINE_SEND_SUB_ARGS"); + sub_args = ast_strdupa(S_OR(sub_args, "")); + + if (ast_strlen_zero(sub)) { + ast_channel_unlock(sub_chan); + return -1; + } + + if (is_frame) { + const struct ast_frame *frame = connected_info; + + ast_connected_line_parse_data(frame->data.ptr, frame->datalen, &sub_chan->connected); + } else { + const struct ast_party_connected_line *connected = connected_info; + + ast_party_connected_line_copy(&sub_chan->connected, connected); + } + ast_channel_unlock(sub_chan); + + if (!(retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args))) { + ast_channel_lock(sub_chan); + ast_channel_update_connected_line(sub_chan, &sub_chan->connected, NULL); + ast_channel_unlock(sub_chan); + } + + return retval; +} + +int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame) +{ + const char *sub; + const char *sub_args; + int retval; + + ast_channel_lock(sub_chan); + sub = pbx_builtin_getvar_helper(sub_chan, "REDIRECTING_SEND_SUB"); + sub = ast_strdupa(S_OR(sub, "")); + sub_args = pbx_builtin_getvar_helper(sub_chan, "REDIRECTING_SEND_SUB_ARGS"); + sub_args = ast_strdupa(S_OR(sub_args, "")); + + if (ast_strlen_zero(sub)) { + ast_channel_unlock(sub_chan); + return -1; + } + + if (is_frame) { + const struct ast_frame *frame = redirecting_info; + + ast_redirecting_parse_data(frame->data.ptr, frame->datalen, &sub_chan->redirecting); + } else { + const struct ast_party_redirecting *redirecting = redirecting_info; + + ast_party_redirecting_copy(&sub_chan->redirecting, redirecting); + } + ast_channel_unlock(sub_chan); + + retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args); + if (!retval) { + ast_channel_lock(sub_chan); + ast_channel_update_redirecting(sub_chan, &sub_chan->redirecting, NULL); + ast_channel_unlock(sub_chan); + } + + return retval; +} + static void *channel_cc_params_copy(void *data) { const struct ast_cc_config_params *src = data; diff --git a/main/dial.c b/main/dial.c index 3455ca329e..fe8a74fafc 100644 --- a/main/dial.c +++ b/main/dial.c @@ -437,13 +437,15 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel break; case AST_CONTROL_CONNECTED_LINE: ast_verb(3, "%s connected line has changed, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); - if (ast_channel_connected_line_macro(channel->owner, chan, fr, 1, 1)) { + if (ast_channel_connected_line_sub(channel->owner, chan, fr, 1) && + ast_channel_connected_line_macro(channel->owner, chan, fr, 1, 1)) { ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen); } break; case AST_CONTROL_REDIRECTING: ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ast_channel_name(channel->owner), ast_channel_name(chan)); - if (ast_channel_redirecting_macro(channel->owner, chan, fr, 1, 1)) { + if (ast_channel_redirecting_sub(channel->owner, chan, fr, 1) && + ast_channel_redirecting_macro(channel->owner, chan, fr, 1, 1)) { ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen); } break; diff --git a/main/features.c b/main/features.c index 9f257f7a01..6f3d0f9cb5 100644 --- a/main/features.c +++ b/main/features.c @@ -2408,7 +2408,8 @@ static void atxfer_fail_cleanup(struct ast_channel *transferee, struct ast_chann * Party B was the caller to party C and is the last known mode * for party B. */ - if (ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { + if (ast_channel_connected_line_sub(transferee, transferer, connected_line, 0) && + ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { ast_channel_update_connected_line(transferer, connected_line, NULL); } ast_party_connected_line_free(connected_line); @@ -2816,7 +2817,8 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st ast_party_connected_line_copy(&connected_line, &transferer->connected); ast_channel_unlock(transferer); connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { + if (ast_channel_connected_line_sub(newchan, xferchan, &connected_line, 0) && + ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { ast_channel_update_connected_line(xferchan, &connected_line, NULL); } @@ -2825,7 +2827,8 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st ast_connected_line_copy_from_caller(&connected_line, &xferchan->caller); ast_channel_unlock(xferchan); connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { + if (ast_channel_connected_line_sub(xferchan, newchan, &connected_line, 0) && + ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { ast_channel_update_connected_line(newchan, &connected_line, NULL); } @@ -3614,7 +3617,8 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, ast_party_connected_line_free(&connected); } else { ast_autoservice_start(transferee); - if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { + if (ast_channel_connected_line_sub(chan, caller, f, 1) && + ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); } @@ -3623,7 +3627,8 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { if (!caller_hungup) { ast_autoservice_start(transferee); - if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { + if (ast_channel_redirecting_sub(chan, caller, f, 1) && + ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { ast_indicate_data(caller, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); } @@ -4151,16 +4156,16 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct a ast_indicate(other, f->subclass.integer); break; case AST_CONTROL_CONNECTED_LINE: - if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { - break; + if (ast_channel_connected_line_sub(who, other, f, 1) && + ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { + ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); } - ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); break; case AST_CONTROL_REDIRECTING: - if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { - break; + if (ast_channel_redirecting_sub(who, other, f, 1) && + ast_channel_redirecting_macro(who, other, f, who != chan, 1)) { + ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); } - ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); break; case AST_CONTROL_AOC: case AST_CONTROL_HOLD: @@ -5172,7 +5177,8 @@ static int parked_call_exec(struct ast_channel *chan, const char *data) ast_connected_line_copy_from_caller(&connected, &chan->caller); ast_channel_unlock(chan); connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; - if (ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { + if (ast_channel_connected_line_sub(chan, peer, &connected, 0) && + ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) { ast_channel_update_connected_line(peer, &connected, NULL); } @@ -5187,7 +5193,8 @@ static int parked_call_exec(struct ast_channel *chan, const char *data) ast_connected_line_copy_from_caller(&connected, &peer->caller); ast_channel_unlock(peer); connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; - if (ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { + if (ast_channel_connected_line_sub(peer, chan, &connected, 0) && + ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) { ast_channel_update_connected_line(chan, &connected, NULL); } @@ -7319,7 +7326,8 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) ast_party_connected_line_copy(&connected_caller, &target->connected); ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; - if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { + if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) && + ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { ast_channel_update_connected_line(chan, &connected_caller, NULL); } ast_party_connected_line_free(&connected_caller); diff --git a/main/rtp_engine.c b/main/rtp_engine.c index d60790c41b..e739c7014a 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -917,12 +917,14 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a } ast_frfree(fr); } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) { - if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) { + if (ast_channel_connected_line_sub(who, other, fr, 1) && + ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) { ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); } ast_frfree(fr); } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) { - if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) { + if (ast_channel_redirecting_sub(who, other, fr, 1) && + ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) { ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); } ast_frfree(fr); @@ -1206,12 +1208,14 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, } ast_frfree(fr); } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) { - if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) { + if (ast_channel_connected_line_sub(who, other, fr, 1) && + ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) { ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); } ast_frfree(fr); } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) { - if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) { + if (ast_channel_redirecting_sub(who, other, fr, 1) && + ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) { ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); } ast_frfree(fr);