--- apps/app_queue.c (revisión: 131) +++ apps/app_queue.c (copia de trabajo) @@ -287,6 +287,8 @@ /*! \brief queues.conf [general] option */ static int montype_default = 0; + + enum queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, @@ -401,6 +403,7 @@ unsigned int leavewhenempty:2; unsigned int ringinuse:1; unsigned int setinterfacevar:1; + unsigned int setqueuevar:1; unsigned int reportholdtime:1; unsigned int wrapped:1; unsigned int timeoutrestart:1; @@ -459,8 +462,69 @@ static int set_member_paused(const char *queuename, const char *interface, int paused); -static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); +static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); +static char *int2strat(int strategy); + +static inline struct call_queue *queue_ref(struct call_queue *q) +{ + ao2_ref(q, 1); + return q; +} + +static inline struct call_queue *queue_unref(struct call_queue *q) +{ + ao2_ref(q, -1); + return q; +} + +static void set_queue_variables(struct call_queue *q, struct ast_channel *chan) +{ + + char interfacevar[256]=""; + float sl = 0; + + if (q->setqueuevar) { + sl = 0; + if (q->callscompleted > 0) + sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); + + snprintf(interfacevar, sizeof(interfacevar), + "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", + q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); + + pbx_builtin_setvar_multiple(chan, interfacevar); + } +} + + +struct queue_end_bridge { + struct call_queue *q; + struct ast_channel *chan; +}; + +static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) +{ + struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; + ao2_ref(qeb, +1); + qeb->chan = originator; + +} + static void end_bridge_callback(void *data) + { + struct queue_end_bridge *qeb = data; + struct call_queue *q = qeb->q; + struct ast_channel *chan = qeb->chan; + + if (ao2_ref(qeb, -1) == 1) { + ao2_lock(q); + set_queue_variables(q, chan); + ao2_unlock(q); + /* This unrefs the reference we made in try_calling when we allocated qeb */ + queue_unref(q); + } + } + static void rr_dep_warning(void) { static unsigned int warned = 0; @@ -2830,6 +2894,7 @@ int callcompletedinsl; struct ao2_iterator memi; struct ast_datastore *datastore, *transfer_ds; + struct queue_end_bridge *queue_end_bridge = NULL; ast_channel_lock(qe->chan); datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); @@ -3256,6 +3321,19 @@ if (member->status == AST_DEVICE_NOT_INUSE) ast_log(LOG_WARNING, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member->membername); + + if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { + queue_end_bridge->q = qe->parent; + queue_end_bridge->chan = qe->chan; + bridge_config.end_bridge_callback = end_bridge_callback; + bridge_config.end_bridge_callback_data = queue_end_bridge; + bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; + /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need + * to make sure to increase the refcount of this queue so it cannot be freed until we + * are done with it. We remove this reference in end_bridge_callback. + */ + queue_ref(qe->parent); + } transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); bridge = ast_bridge_call(qe->chan,peer, &bridge_config); --- include/asterisk/pbx.h (revisión: 131) +++ include/asterisk/pbx.h (copia de trabajo) @@ -886,6 +886,7 @@ * \note Will lock the channel. */ int pbx_builtin_setvar(struct ast_channel *chan, void *data); +int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *data); void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count); void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count); --- main/pbx.c (revisión: 131) +++ main/pbx.c (copia de trabajo) @@ -236,6 +236,7 @@ static int pbx_builtin_saycharacters(struct ast_channel *, void *); static int pbx_builtin_sayphonetic(struct ast_channel *, void *); int pbx_builtin_setvar(struct ast_channel *, void *); +int pbx_builtin_setvar_multiple(struct ast_channel *, void *); static int pbx_builtin_importvar(struct ast_channel *, void *); AST_MUTEX_DEFINE_STATIC(globalslock); @@ -5938,6 +5939,43 @@ ast_mutex_unlock(&globalslock); } +int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *vdata) +{ + char *data; + int x; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(pair)[24]; + ); + AST_DECLARE_APP_ARGS(pair, + AST_APP_ARG(name); + AST_APP_ARG(value); + ); + + if (ast_strlen_zero(vdata)) { + ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n"); + return 0; + } + + data = ast_strdupa(vdata); + AST_STANDARD_APP_ARGS(args, data); + + for (x = 0; x < args.argc; x++) { + AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '='); + if (pair.argc == 2) { + pbx_builtin_setvar_helper(chan, pair.name, pair.value); + if (strchr(pair.name, ' ')) + ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value); + } else if (!chan) { + ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name); + } else { + ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority); + } + } + + return 0; +} + + void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value) { struct ast_var_t *newvariable;