[asterisk-commits] irroot: branch irroot/distrotech-customers r318986 - in /team/irroot/distrote...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat May 14 10:12:13 CDT 2011
Author: irroot
Date: Sat May 14 10:12:09 2011
New Revision: 318986
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=318986
Log:
app_queue changes
Modified:
team/irroot/distrotech-customers/ (props changed)
team/irroot/distrotech-customers/apps/app_queue.c
team/irroot/distrotech-customers/configs/queues.conf.sample
Propchange: team/irroot/distrotech-customers/
------------------------------------------------------------------------------
automerge = *
Propchange: team/irroot/distrotech-customers/
------------------------------------------------------------------------------
automerge-email = gregory at distrotech.co.za
Propchange: team/irroot/distrotech-customers/
------------------------------------------------------------------------------
svnmerge-integrated = /branches/1.8:1-318981
Modified: team/irroot/distrotech-customers/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers/apps/app_queue.c?view=diff&rev=318986&r1=318985&r2=318986
==============================================================================
--- team/irroot/distrotech-customers/apps/app_queue.c (original)
+++ team/irroot/distrotech-customers/apps/app_queue.c Sat May 14 10:12:09 2011
@@ -521,11 +521,25 @@
<enum name="count">
<para>Returns the total number of members for the specified queue.</para>
</enum>
+ <enum name="penalty">
+ <para>Gets or sets queue member penalty.</para>
+ </enum>
+ <enum name="paused">
+ <para>Gets or sets queue member paused status.</para>
+ </enum>
+ <enum name="ignorebusy">
+ <para>Gets or sets queue member ignorebusy.</para>
+ </enum>
</enumlist>
</parameter>
+ <parameter name="interface" required="false" />
</syntax>
<description>
- <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
+ <para>Allows access to queue counts [R] and member information [R/W].</para>
+ <para>
+ <replaceable>queuename</replaceable> is required for all operations
+ <replaceable>interface</replaceable> is required for all member operations.
+ </para>
</description>
<see-also>
<ref type="application">Queue</ref>
@@ -934,6 +948,9 @@
/*! \brief queues.conf [general] option */
static int update_cdr = 0;
+/*! \brief queues.conf [genral] option */
+static int negitive_penalty_invalid = 0;
+
enum queue_result {
QUEUE_UNKNOWN = 0,
QUEUE_TIMEOUT = 1,
@@ -1043,6 +1060,7 @@
unsigned int dead:1; /*!< Used to detect members deleted in realtime */
unsigned int delme:1; /*!< Flag to delete entry on reload */
char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
+ unsigned int ignorebusy:1; /*!< Flag to ignore member if the status is not available */
};
enum empty_conditions {
@@ -1160,6 +1178,7 @@
int timeout; /*!< How long to wait for an answer */
int weight; /*!< Respective weight */
int autopause; /*!< Auto pause queue members if they fail to answer */
+ int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
/* Queue strategy things */
@@ -1190,6 +1209,7 @@
static struct ao2_container *queues;
static void update_realtime_members(struct call_queue *q);
+static struct member *interface_exists(struct call_queue *q, const char *interface);
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
@@ -1698,6 +1718,7 @@
q->numperiodicannounce = 0;
q->autopause = QUEUE_AUTOPAUSE_OFF;
q->timeoutpriority = TIMEOUT_PRIORITY_APP;
+ q->autopausedelay = 0;
if (!q->members) {
if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED)
/* linear strategy depends on order, so we have to place all members in a single bucket */
@@ -2003,6 +2024,8 @@
q->montype = 1;
} else if (!strcasecmp(param, "autopause")) {
q->autopause = autopause2int(val);
+ } else if (!strcasecmp(param, "autopausedelay")) {
+ q->autopausedelay = atoi(val);
} else if (!strcasecmp(param, "maxlen")) {
q->maxlen = atoi(val);
if (q->maxlen < 0)
@@ -2074,13 +2097,21 @@
* Search for member in queue, if found update penalty/paused state,
* if no member exists create one flag it as a RT member and add to queue member list.
*/
-static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
+static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
{
struct member *m;
struct ao2_iterator mem_iter;
int penalty = 0;
int paused = 0;
int found = 0;
+ int ignorebusy = 0;
+
+ const char *config_val;
+ const char *rt_uniqueid=ast_variable_retrieve(member_config, interface, "uniqueid");
+ const char *membername=S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface);
+ const char *state_interface=S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface);
+ const char *penalty_str=ast_variable_retrieve(member_config, interface, "penalty");
+ const char *paused_str=ast_variable_retrieve(member_config, interface, "paused");
if (ast_strlen_zero(rt_uniqueid)) {
ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
@@ -2089,7 +2120,9 @@
if (penalty_str) {
penalty = atoi(penalty_str);
- if (penalty < 0)
+ if ((penalty < 0) && negitive_penalty_invalid)
+ return;
+ else if (penalty < 0)
penalty = 0;
}
@@ -2098,6 +2131,11 @@
if (paused < 0)
paused = 0;
}
+
+ if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy")))
+ ignorebusy=ast_true(config_val);
+ else
+ ignorebusy=1;
/* Find member by realtime uniqueid and update */
mem_iter = ao2_iterator_init(q->members, 0);
@@ -2111,6 +2149,7 @@
ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
}
m->penalty = penalty;
+ m->ignorebusy = ignorebusy;
found = 1;
ao2_ref(m, -1);
break;
@@ -2124,6 +2163,7 @@
if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
m->dead = 0;
m->realtime = 1;
+ m->ignorebusy = ignorebusy;
ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
ao2_link(q->members, m);
@@ -2299,12 +2339,7 @@
ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
- rt_handle_member_record(q, interface,
- ast_variable_retrieve(member_config, interface, "uniqueid"),
- S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
- ast_variable_retrieve(member_config, interface, "penalty"),
- ast_variable_retrieve(member_config, interface, "paused"),
- S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
+ rt_handle_member_record(q, interface, member_config);
}
/* Delete all realtime members that have been deleted in DB. */
@@ -2426,12 +2461,7 @@
ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
- rt_handle_member_record(q, interface,
- ast_variable_retrieve(member_config, interface, "uniqueid"),
- S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
- ast_variable_retrieve(member_config, interface, "penalty"),
- ast_variable_retrieve(member_config, interface, "paused"),
- S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
+ rt_handle_member_record(q, interface, member_config);
}
/* Delete all realtime members that have been deleted in DB. */
@@ -2867,16 +2897,23 @@
mem_iter = ao2_iterator_init(q->members, 0);
while ((mem = ao2_iterator_next(&mem_iter))) {
switch (mem->status) {
- case AST_DEVICE_INUSE:
- if (!q->ringinuse)
+ case AST_DEVICE_INVALID:
+ case AST_DEVICE_UNAVAILABLE:
break;
- /* else fall through */
- case AST_DEVICE_NOT_INUSE:
- case AST_DEVICE_UNKNOWN:
- if (!mem->paused) {
- avl++;
- }
- break;
+ case AST_DEVICE_INUSE:
+ case AST_DEVICE_BUSY:
+ case AST_DEVICE_RINGING:
+ case AST_DEVICE_RINGINUSE:
+ case AST_DEVICE_ONHOLD:
+ if ((!q->ringinuse) || (!mem->ignorebusy))
+ break;
+ /* else fall through */
+ case AST_DEVICE_NOT_INUSE:
+ case AST_DEVICE_UNKNOWN:
+ if (!mem->paused) {
+ avl++;
+ }
+ break;
}
ao2_ref(mem, -1);
@@ -3004,8 +3041,17 @@
char tech[256];
char *location;
const char *macrocontext, *macroexten;
+ enum ast_device_state newstate;
/* on entry here, we know that tmp->chan == NULL */
+ if (tmp->member->paused) {
+ ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
+ if (qe->chan->cdr)
+ ast_cdr_busy(qe->chan->cdr);
+ tmp->stillgoing = 0;
+ return 0;
+ }
+
if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
(!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
@@ -3017,21 +3063,24 @@
return 0;
}
- if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
- ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
- if (qe->chan->cdr)
- ast_cdr_busy(qe->chan->cdr);
- tmp->stillgoing = 0;
- return 0;
- }
-
- if (tmp->member->paused) {
- ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
- if (qe->chan->cdr)
- ast_cdr_busy(qe->chan->cdr);
- tmp->stillgoing = 0;
- return 0;
- }
+ if (!qe->parent->ringinuse || !tmp->member->ignorebusy) {
+ if ((tmp->member->status == AST_DEVICE_UNKNOWN) || (tmp->member->status == AST_DEVICE_NOT_INUSE)) {
+ newstate = ast_parse_device_state(tmp->member->interface);
+ if (newstate != tmp->member->status) {
+ ast_log(LOG_ERROR, "Found a channel matching iterface %s while status was %i changed to %i\n",
+ tmp->member->interface, tmp->member->status, newstate);
+ update_status(qe->parent, tmp->member, newstate);
+ }
+ }
+ if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
+ ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
+ if (qe->chan->cdr)
+ ast_cdr_busy(qe->chan->cdr);
+ tmp->stillgoing = 0;
+ return 0;
+ }
+ }
+
if (use_weight && compare_weight(qe->parent,tmp->member)) {
ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
if (qe->chan->cdr)
@@ -3386,6 +3435,18 @@
}
ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
+ if (qe->parent->autopausedelay > 0) {
+ struct member *mem;
+ ao2_lock(qe->parent);
+ if ((mem = interface_exists(qe->parent, interface))) {
+ time_t idletime = time(&idletime)-mem->lastcall;
+ if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
+ ao2_unlock(qe->parent);
+ return;
+ }
+ }
+ ao2_unlock(qe->parent);
+ }
if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
@@ -5168,7 +5229,10 @@
ao2_lock(q);
if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
/* XXX future changes should beware of this assumption!! */
- if (!mem->dynamic) {
+ /*Change Penalty on realtime users*/
+ if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negitive_penalty_invalid) {
+ update_realtime_member_field(mem, q->name, "penalty", "-1");
+ } else if (!mem->dynamic) {
ao2_ref(mem, -1);
ao2_unlock(q);
queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
@@ -5344,6 +5408,7 @@
struct call_queue *q;
struct member *mem;
struct ao2_iterator queue_iter;
+ char rtpenalty[80];
if (penalty < 0) {
ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
@@ -5357,8 +5422,12 @@
foundqueue++;
if ((mem = interface_exists(q, interface))) {
foundinterface++;
- mem->penalty = penalty;
-
+ if (!mem->realtime)
+ mem->penalty = penalty;
+ else {
+ sprintf(rtpenalty,"%i",penalty);
+ update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
+ }
ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
"Queue: %s\r\n"
@@ -6147,29 +6216,35 @@
/*!
* \brief Get number either busy / free / ready or total members of a specific queue
- * \retval number of members (busy / free / ready / total)
+ * \brief Get or set member properties penalty / paused / ignorebusy
+ * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy)
* \retval -1 on error
*/
-static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
int count = 0;
struct member *m;
struct ao2_iterator mem_iter;
struct call_queue *q;
- char *option;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(option);
+ AST_APP_ARG(interface);
+ );
+ /* Make sure the returned value on error is NULL. */
+ buf[0] = '\0';
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
return -1;
}
- if ((option = strchr(data, ',')))
- *option++ = '\0';
- else
- option = "logged";
- if ((q = load_realtime_queue(data))) {
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if ((q = load_realtime_queue(args.queuename))) {
ao2_lock(q);
- if (!strcasecmp(option, "logged")) {
+ if (!strcasecmp(args.option, "logged")) {
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
/* Count the agents who are logged in and presently answering calls */
@@ -6179,7 +6254,7 @@
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
- } else if (!strcasecmp(option, "free")) {
+ } else if (!strcasecmp(args.option, "free")) {
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
/* Count the agents who are logged in and presently answering calls */
@@ -6189,7 +6264,7 @@
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
- } else if (!strcasecmp(option, "ready")) {
+ } else if (!strcasecmp(args.option, "ready")) {
time_t now;
time(&now);
mem_iter = ao2_iterator_init(q->members, 0);
@@ -6202,15 +6277,94 @@
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
- } else /* must be "count" */
+ } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) {
count = q->membercount;
+ } else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface)) {
+ if ((m = interface_exists(q, args.interface)))
+ count = m->penalty;
+ } else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface)) {
+ if ((m = interface_exists(q, args.interface)))
+ count = m->paused;
+ } else if (!strcasecmp(args.option, "ignorebusy") && !ast_strlen_zero(args.interface)) {
+ if ((m = interface_exists(q, args.interface)))
+ count = m->ignorebusy;
+ }
ao2_unlock(q);
queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
} else
- ast_log(LOG_WARNING, "queue %s was not found\n", data);
+ ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
snprintf(buf, len, "%d", count);
+ return 0;
+}
+
+/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy. */
+static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ int memvalue;
+ struct call_queue *q;
+ struct member *m;
+ char rtvalue[80];
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(option);
+ AST_APP_ARG(interface);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n");
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (args.argc < 3) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
+ return -1;
+ }
+
+ if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) {
+ ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n");
+ return -1;
+ }
+
+ memvalue = atoi(value);
+
+ if (!strcasecmp(args.option, "penalty")) {
+ /* if queuename = NULL then penalty will be set for interface in all the queues. */
+ if (set_member_penalty(args.queuename, args.interface, memvalue)) {
+ ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
+ return -1;
+ }
+ } else if ((q = load_realtime_queue(args.queuename))) {
+ ao2_lock(q);
+ if ((m = interface_exists(q, args.interface))) {
+ sprintf(rtvalue, "%s",(memvalue <= 0)?"0":"1");
+ if (!strcasecmp(args.option, "paused")) {
+ if (m->realtime)
+ update_realtime_member_field(m, q->name, args.option, rtvalue);
+ else
+ m->paused = (memvalue <= 0)?0:1;
+ } else if (!strcasecmp(args.option, "ignorebusy")) {
+ if (m->realtime)
+ update_realtime_member_field(m, q->name, args.option, rtvalue);
+ else
+ m->ignorebusy = (memvalue <= 0)?0:1;
+ } else {
+ ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ignorebusy are valid\n");
+ return -1;
+ }
+ } else {
+ ast_log(LOG_ERROR, "Invalid interface or queue\n");
+ return -1;
+ }
+ ao2_unlock(q);
+ } else {
+ ast_log(LOG_ERROR, "Invalid queue\n");
+ return -1;
+ }
return 0;
}
@@ -6423,7 +6577,8 @@
static struct ast_custom_function queuemembercount_function = {
.name = "QUEUE_MEMBER",
- .read = queue_function_qac,
+ .read = queue_function_mem_read,
+ .write = queue_function_mem_write,
};
static struct ast_custom_function queuemembercount_dep = {
@@ -6521,6 +6676,9 @@
shared_lastcall = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
shared_lastcall = ast_true(general_val);
+ negitive_penalty_invalid = 0;
+ if ((general_val = ast_variable_retrieve(cfg, "general", "negitive_penalty_invalid")))
+ negitive_penalty_invalid = ast_true(general_val);
}
/*! \brief reload information pertaining to a single member
Modified: team/irroot/distrotech-customers/configs/queues.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers/configs/queues.conf.sample?view=diff&rev=318986&r1=318985&r2=318986
==============================================================================
--- team/irroot/distrotech-customers/configs/queues.conf.sample (original)
+++ team/irroot/distrotech-customers/configs/queues.conf.sample Sat May 14 10:12:09 2011
@@ -60,6 +60,10 @@
; The default value is yes.
;
;shared_lastcall=no
+;
+; Negitive penalty invalid will treat members with a negative penalty as logged off
+;
+;negitive_penalty_invalid = no
;
;[markq]
;
@@ -195,6 +199,10 @@
; yes: Member will be paused only in the queue where the timeout took place
; all: Memeber will be paused in all queues he/she is a member
;autopause=yes
+;
+; Autopausedelay delay autopause for autopause delay seconds from the
+; last call if a member has not taken a call the delay has no effect.
+;autopausedelay=60
;
; Maximum number of people waiting in the queue (0 for unlimited)
;
@@ -457,6 +465,9 @@
; uncomment this option. (Note: only the SIP channel driver currently is able
; to report 'in use'.)
;
+; A member can have the ignorebusy flag set or unset when ringinuse is set to
+; allow a per member control.
+;
; ringinuse = no
;
; If you wish to have a delay before the member is connected to the caller (or
More information about the asterisk-commits
mailing list