mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-02 20:08:17 +00:00
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 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.1@152645 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
160
apps/app_queue.c
160
apps/app_queue.c
@@ -543,6 +543,8 @@ AST_LIST_HEAD_STATIC(rule_lists, rule_list);
|
||||
|
||||
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 @@ static void update_realtime_members(struct call_queue *q)
|
||||
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 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
||||
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 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
||||
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)) {
|
||||
insert_entry(q, prev, qe, &pos);
|
||||
inserted = 1;
|
||||
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;
|
||||
}
|
||||
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 );
|
||||
}
|
||||
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;
|
||||
}
|
||||
/* 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 );
|
||||
}
|
||||
ao2_unlock(q);
|
||||
ao2_unlock(queues);
|
||||
@@ -2856,7 +2872,8 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r
|
||||
|
||||
/* 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 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r
|
||||
break;
|
||||
}
|
||||
|
||||
status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* leave the queue if no agents, if enabled */
|
||||
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 @@ static void copy_rules(struct queue_ent *qe, const char *rulename)
|
||||
{
|
||||
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 @@ static int queue_exec(struct ast_channel *chan, void *data)
|
||||
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 @@ check_turns:
|
||||
/* 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 @@ check_turns:
|
||||
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");
|
||||
@@ -4791,6 +4826,22 @@ check_turns:
|
||||
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 */
|
||||
if (qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) {
|
||||
record_abandoned(&qe);
|
||||
@@ -5276,10 +5327,11 @@ static int reload_queue_rules(int reload)
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user