[asterisk-commits] twilson: branch 1.6.1 r152645 - /branches/1.6.1/apps/app_queue.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Oct 29 15:16:10 CDT 2008
Author: twilson
Date: Wed Oct 29 15:16:09 2008
New Revision: 152645
URL: http://svn.digium.com/view/asterisk?view=rev&rev=152645
Log:
Small modification to putnopvut's patch to fix this issue. Thanks for all the help, putnopvut!
(closes issue #12884)
Reported by: bcnit
Patches:
12884v4-1.6.0-branch.patch uploaded by otherwiseguy (license 396)
Tested by: otherwiseguy
Modified:
branches/1.6.1/apps/app_queue.c
Modified: branches/1.6.1/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.1/apps/app_queue.c?view=diff&rev=152645&r1=152644&r2=152645
==============================================================================
--- branches/1.6.1/apps/app_queue.c (original)
+++ branches/1.6.1/apps/app_queue.c Wed Oct 29 15:16:09 2008
@@ -543,6 +543,8 @@
static struct ao2_container *queues;
+static void copy_rules(struct queue_ent *qe, const char *rulename);
+static void update_qe_rule(struct queue_ent *qe);
static void update_realtime_members(struct call_queue *q);
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
@@ -1677,7 +1679,7 @@
ast_config_destroy(member_config);
}
-static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
+static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, const char *overriding_rule)
{
struct call_queue *q;
struct queue_ent *cur, *prev = NULL;
@@ -1685,6 +1687,7 @@
int pos = 0;
int inserted = 0;
enum queue_member_status status;
+ int exit = 0;
if (!(q = load_realtime_queue(queuename)))
return res;
@@ -1692,50 +1695,63 @@
ao2_lock(queues);
ao2_lock(q);
+ copy_rules(qe, S_OR(overriding_rule, q->defaultrule));
+ qe->pr = AST_LIST_FIRST(&qe->qe_rules);
+
/* This is our one */
- status = get_member_status(q, qe->max_penalty, qe->min_penalty);
- if (!q->joinempty && (status == QUEUE_NO_MEMBERS))
- *reason = QUEUE_JOINEMPTY;
- else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS))
- *reason = QUEUE_JOINUNAVAIL;
- else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS))
- *reason = QUEUE_JOINUNAVAIL;
- else if (q->maxlen && (q->count >= q->maxlen))
- *reason = QUEUE_FULL;
- else {
- /* There's space for us, put us at the right position inside
- * the queue.
- * Take into account the priority of the calling user */
- inserted = 0;
- prev = NULL;
- cur = q->head;
- while (cur) {
- /* We have higher priority than the current user, enter
- * before him, after all the other users with priority
- * higher or equal to our priority. */
- if ((!inserted) && (qe->prio > cur->prio)) {
+ while (!exit) {
+ status = get_member_status(q, qe->max_penalty, qe->min_penalty);
+ if (!q->joinempty && (status == QUEUE_NO_MEMBERS))
+ *reason = QUEUE_JOINEMPTY;
+ else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS))
+ *reason = QUEUE_JOINUNAVAIL;
+ else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS))
+ *reason = QUEUE_JOINUNAVAIL;
+ else if (q->maxlen && (q->count >= q->maxlen))
+ *reason = QUEUE_FULL;
+ else {
+ /* There's space for us, put us at the right position inside
+ * the queue.
+ * Take into account the priority of the calling user */
+ inserted = 0;
+ prev = NULL;
+ cur = q->head;
+ while (cur) {
+ /* We have higher priority than the current user, enter
+ * before him, after all the other users with priority
+ * higher or equal to our priority. */
+ if ((!inserted) && (qe->prio > cur->prio)) {
+ insert_entry(q, prev, qe, &pos);
+ inserted = 1;
+ }
+ cur->pos = ++pos;
+ prev = cur;
+ cur = cur->next;
+ }
+ /* No luck, join at the end of the queue */
+ if (!inserted)
insert_entry(q, prev, qe, &pos);
- inserted = 1;
- }
- cur->pos = ++pos;
- prev = cur;
- cur = cur->next;
- }
- /* No luck, join at the end of the queue */
- if (!inserted)
- insert_entry(q, prev, qe, &pos);
- ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
- ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
- ast_copy_string(qe->context, q->context, sizeof(qe->context));
- q->count++;
- res = 0;
- manager_event(EVENT_FLAG_CALL, "Join",
- "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
- qe->chan->name,
- S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
- S_OR(qe->chan->cid.cid_name, "unknown"),
- q->name, qe->pos, q->count, qe->chan->uniqueid );
- ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
+ ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
+ ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
+ ast_copy_string(qe->context, q->context, sizeof(qe->context));
+ q->count++;
+ res = 0;
+ manager_event(EVENT_FLAG_CALL, "Join",
+ "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
+ qe->chan->name,
+ S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
+ S_OR(qe->chan->cid.cid_name, "unknown"),
+ q->name, qe->pos, q->count, qe->chan->uniqueid );
+ ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
+ }
+ if (!exit && qe->pr && res) {
+ /* We failed to join the queue, but perhaps we can join if we move
+ * to the next defined penalty rule
+ */
+ update_qe_rule(qe);
+ } else {
+ exit = 1;
+ }
}
ao2_unlock(q);
ao2_unlock(queues);
@@ -2856,7 +2872,8 @@
/* This is the holding pen for callers 2 through maxlen */
for (;;) {
- enum queue_member_status status;
+ enum queue_member_status status = QUEUE_NORMAL;
+ int exit = 0;
if (is_our_turn(qe))
break;
@@ -2867,9 +2884,27 @@
break;
}
- status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
-
- /* leave the queue if no agents, if enabled */
+ /* If we are going to exit due to a leavewhenempty condition, we should
+ * actually attempt to keep the caller in the queue until we have
+ * exhausted all penalty rules.
+ */
+ for (; !exit || qe->pr; update_qe_rule(qe)) {
+ status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
+
+ if (!qe->pr || status == QUEUE_NORMAL) {
+ break;
+ }
+
+ /* leave the queue if no agents, if enabled */
+ if ((qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) ||
+ ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) ||
+ ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) {
+ continue;
+ } else {
+ exit = 1;
+ }
+ }
+
if (qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) {
*reason = QUEUE_LEAVEEMPTY;
ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
@@ -4558,7 +4593,10 @@
{
struct penalty_rule *pr_iter;
struct rule_list *rl_iter;
- const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
+ const char *tmp = rulename;
+ if (ast_strlen_zero(tmp)) {
+ return;
+ }
AST_LIST_LOCK(&rule_lists);
AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
if (!strcasecmp(rl_iter->name, tmp))
@@ -4704,15 +4742,13 @@
qe.last_periodic_announce_time = time(NULL);
qe.last_periodic_announce_sound = 0;
qe.valid_digits = 0;
- if (join_queue(args.queuename, &qe, &reason)) {
+ if (join_queue(args.queuename, &qe, &reason, args.rule)) {
ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
set_queue_result(chan, reason);
return 0;
}
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
S_OR(chan->cid.cid_num, ""));
- copy_rules(&qe, args.rule);
- qe.pr = AST_LIST_FIRST(&qe.qe_rules);
check_turns:
if (ringing) {
ast_indicate(chan, AST_CONTROL_RINGING);
@@ -4734,7 +4770,8 @@
/* they may dial a digit from the queue context; */
/* or, they may timeout. */
- enum queue_member_status status;
+ enum queue_member_status status = QUEUE_NORMAL;
+ int exit = 0;
/* Leave if we have exceeded our queuetimeout */
if (qe.expire && (time(NULL) >= qe.expire)) {
@@ -4779,8 +4816,6 @@
goto stop;
}
- status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty);
-
/* exit after 'timeout' cycle if 'n' option enabled */
if (noption && tries >= qe.parent->membercount) {
ast_verb(3, "Exiting on time-out cycle\n");
@@ -4789,6 +4824,22 @@
reason = QUEUE_TIMEOUT;
res = 0;
break;
+ }
+
+ for (; !exit || qe.pr; update_qe_rule(&qe)) {
+ status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty);
+
+ if (!qe.pr || status == QUEUE_NORMAL) {
+ break;
+ }
+
+ if ((qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) ||
+ ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) ||
+ ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) {
+ continue;
+ } else {
+ exit = 1;
+ }
}
/* leave the queue if no agents, if enabled */
@@ -5276,10 +5327,11 @@
ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
- if(!strcasecmp(rulevar->name, "penaltychange"))
+ if(!strcasecmp(rulevar->name, "penaltychange")) {
insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
- else
+ } else {
ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
+ }
}
}
AST_LIST_UNLOCK(&rule_lists);
More information about the asterisk-commits
mailing list