diff --git a/CHANGES b/CHANGES index 586555f0832a26d594bc8218b028dbb3e0a9bdce..26ece87c3570bd934cc05f39b0af9044e8539c73 100644 --- a/CHANGES +++ b/CHANGES @@ -59,3 +59,5 @@ Changes since Asterisk 1.4-beta was branched: setqueueentryvar options for each queue, see queues.conf.sample for details. * Brazilian Portuguese (pt-BR) in VM, and say.c was added via patch from cfassoni. * CID matching information is now shown when doing 'dialplan show'. + * app_queue now has a 'loose' option which is almost exactly like 'strict' except it + does not count paused queue members as unavailable. diff --git a/apps/app_queue.c b/apps/app_queue.c index 77ab09166e3616cbb2c3c87f6128fa7131c5dbd5..bdc5eefa4921e5e727ab207ad28acf50b60dcf4c 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -338,6 +338,7 @@ static AST_LIST_HEAD_STATIC(interfaces, member_interface); /* values used in multi-bit flags in call_queue */ #define QUEUE_EMPTY_NORMAL 1 #define QUEUE_EMPTY_STRICT 2 +#define QUEUE_EMPTY_LOOSE 3 #define ANNOUNCEHOLDTIME_ALWAYS 1 #define ANNOUNCEHOLDTIME_ONCE 2 #define QUEUE_EVENT_VARIABLES 3 @@ -488,6 +489,7 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st enum queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, + QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL }; @@ -501,18 +503,22 @@ static enum queue_member_status get_member_status(struct call_queue *q, int max_ if (max_penalty && (member->penalty > max_penalty)) continue; - if (member->paused) continue; - switch (member->status) { case AST_DEVICE_INVALID: /* nothing to do */ break; case AST_DEVICE_UNAVAILABLE: - result = QUEUE_NO_REACHABLE_MEMBERS; + if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS) + result = QUEUE_NO_REACHABLE_MEMBERS; break; default: - ast_mutex_unlock(&q->lock); - return QUEUE_NORMAL; + if (member->paused) { + result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS; + } else { + ast_mutex_unlock(&q->lock); + return QUEUE_NORMAL; + } + break; } } @@ -903,14 +909,18 @@ static void queue_set_param(struct call_queue *q, const char *param, const char q->strategy = QUEUE_STRATEGY_RINGALL; } } else if (!strcasecmp(param, "joinempty")) { - if (!strcasecmp(val, "strict")) + if (!strcasecmp(val, "loose")) + q->joinempty = QUEUE_EMPTY_LOOSE; + else if (!strcasecmp(val, "strict")) q->joinempty = QUEUE_EMPTY_STRICT; else if (ast_true(val)) q->joinempty = QUEUE_EMPTY_NORMAL; else q->joinempty = 0; } else if (!strcasecmp(param, "leavewhenempty")) { - if (!strcasecmp(val, "strict")) + if (!strcasecmp(val, "loose")) + q->leavewhenempty = QUEUE_EMPTY_LOOSE; + else if (!strcasecmp(val, "strict")) q->leavewhenempty = QUEUE_EMPTY_STRICT; else if (ast_true(val)) q->leavewhenempty = QUEUE_EMPTY_NORMAL; @@ -1189,7 +1199,9 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * stat = get_member_status(q, qe->max_penalty); if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) *reason = QUEUE_JOINEMPTY; - else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) + else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) + *reason = QUEUE_JOINUNAVAIL; + else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) *reason = QUEUE_JOINUNAVAIL; else if (q->maxlen && (q->count >= q->maxlen)) *reason = QUEUE_FULL; @@ -2207,7 +2219,13 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r } /* leave the queue if no reachable agents, if enabled */ - if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { + if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { + *reason = QUEUE_LEAVEUNAVAIL; + ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); + leave_queue(qe); + break; + } + if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { *reason = QUEUE_LEAVEUNAVAIL; ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); leave_queue(qe); @@ -3532,7 +3550,13 @@ check_turns: } /* leave the queue if no reachable agents, if enabled */ - if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { + if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { + record_abandoned(&qe); + reason = QUEUE_LEAVEUNAVAIL; + res = 0; + break; + } + if ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { record_abandoned(&qe); reason = QUEUE_LEAVEUNAVAIL; res = 0; diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index c9f3f9608d1a3d810c7a5e1d1ec2f03e92d3067f..a1238e55f85e236c19f21d3c8a4f86044c04c540 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -254,6 +254,8 @@ monitor-type = MixMonitor ; no - callers cannot join a queue with no members ; strict - callers cannot join a queue with no members or only unavailable ; members +; loose - same as strict, but paused queue members do not count as unavailable +; ; ; ----------------------- TYPE MIXMONITOR OPTIONS ----------------------------- ;