|
|
|
|
@ -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:
|
|
|
|
|
|