diff --git a/CHANGES b/CHANGES index e969d85bf47cb75b735f83aee29bbae2621967ac..5cfad794c9b67476ded359e0b1acd16815e85c5f 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,10 @@ app_queue When set the wrapuptime on the member is used instead of the wrapuptime defined for the queue itself. + * Added predial handler support for caller and callee channels with the + B and b options respectively. This is similar to the predial support + in app_dial. + res_config_sqlite ------------------ * The res_config_sqlite module is now deprecated, users should migrate to the diff --git a/apps/app_queue.c b/apps/app_queue.c index 3047648de40124dfbd66cc833601b4f97900372d..052d528b8bb92aaf1752929099a6785c6ab4436f 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -133,6 +133,27 @@ <parameter name="queuename" required="true" /> <parameter name="options"> <optionlist> + <option name="b" argsep="^"> + <para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified + location using the newly created channel. The <literal>Gosub</literal> will be + executed for each destination channel.</para> + <argument name="context" required="false" /> + <argument name="exten" required="false" /> + <argument name="priority" required="true" hasparams="optional" argsep="^"> + <argument name="arg1" multiple="true" required="true" /> + <argument name="argN" /> + </argument> + </option> + <option name="B" argsep="^"> + <para>Before initiating the outgoing call(s), <literal>Gosub</literal> to the + specified location using the current channel.</para> + <argument name="context" required="false" /> + <argument name="exten" required="false" /> + <argument name="priority" required="true" hasparams="optional" argsep="^"> + <argument name="arg1" multiple="true" required="true" /> + <argument name="argN" /> + </argument> + </option> <option name="C"> <para>Mark all calls as "answered elsewhere" when cancelled.</para> </option> @@ -1325,15 +1346,21 @@ enum { OPT_CALLER_AUTOMIXMON = (1 << 16), OPT_CALLEE_AUTOMON = (1 << 17), OPT_CALLER_AUTOMON = (1 << 18), + OPT_PREDIAL_CALLEE = (1 << 19), + OPT_PREDIAL_CALLER = (1 << 20), }; enum { OPT_ARG_CALLEE_GO_ON = 0, + OPT_ARG_PREDIAL_CALLEE, + OPT_ARG_PREDIAL_CALLER, /* note: this entry _MUST_ be the last one in the enum */ OPT_ARG_ARRAY_SIZE }; AST_APP_OPTIONS(queue_exec_options, BEGIN_OPTIONS + AST_APP_OPTION_ARG('b', OPT_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE), + AST_APP_OPTION_ARG('B', OPT_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER), AST_APP_OPTION('C', OPT_MARK_AS_ANSWERED), AST_APP_OPTION('c', OPT_GO_ON), AST_APP_OPTION('d', OPT_DATA_QUALITY), @@ -1545,6 +1572,7 @@ struct queue_ent { char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */ char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */ char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */ + const char *predial_callee; /*!< Gosub app arguments for outgoing calls. NULL if not supplied. */ int valid_digits; /*!< Digits entered correspond to valid extension. Exited */ int pos; /*!< Where we are in the queue */ int prio; /*!< Our priority */ @@ -4559,6 +4587,11 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies ast_channel_unlock(tmp->chan); ast_channel_unlock(qe->chan); + /* PREDIAL: Run gosub on the callee's channel */ + if (qe->predial_callee) { + ast_pre_call(tmp->chan, qe->predial_callee); + } + /* Place the call, but don't wait on the answer */ if ((res = ast_call(tmp->chan, location, 0))) { /* Again, keep going even if there's an error */ @@ -4615,6 +4648,16 @@ static struct callattempt *find_best(struct callattempt *outgoing) static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies) { int ret = 0; + struct callattempt *cur; + + if (qe->predial_callee) { + ast_autoservice_start(qe->chan); + for (cur = outgoing; cur; cur = cur->q_next) { + if (cur->stillgoing && cur->chan) { + ast_autoservice_start(cur->chan); + } + } + } while (ret == 0) { struct callattempt *best = find_best(outgoing); @@ -4623,18 +4666,23 @@ static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *bus break; } if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { - struct callattempt *cur; /* Ring everyone who shares this best metric (for ringall) */ for (cur = outgoing; cur; cur = cur->q_next) { if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); ret |= ring_entry(qe, cur, busies); + if (qe->predial_callee && cur->chan) { + ast_autoservice_start(cur->chan); + } } } } else { /* Ring just the best channel */ ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); ret = ring_entry(qe, best, busies); + if (qe->predial_callee && cur->chan) { + ast_autoservice_start(best->chan); + } } /* If we have timed out, break out */ @@ -4644,6 +4692,14 @@ static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *bus break; } } + if (qe->predial_callee) { + for (cur = outgoing; cur; cur = cur->q_next) { + if (cur->stillgoing && cur->chan) { + ast_autoservice_stop(cur->chan); + } + } + ast_autoservice_stop(qe->chan); + } return ret; } @@ -8270,6 +8326,21 @@ static int queue_exec(struct ast_channel *chan, const char *data) S_OR(args.url, ""), S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""), qe.opos); + + /* PREDIAL: Preprocess any callee gosub arguments. */ + if (ast_test_flag(&opts, OPT_PREDIAL_CALLEE) + && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) { + ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]); + qe.predial_callee = opt_args[OPT_ARG_PREDIAL_CALLEE]; + } + + /* PREDIAL: Run gosub on the caller's channel */ + if (ast_test_flag(&opts, OPT_PREDIAL_CALLER) + && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) { + ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]); + ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0); + } + copy_rules(&qe, args.rule); qe.pr = AST_LIST_FIRST(&qe.qe_rules); check_turns: