aboutsummaryrefslogtreecommitdiffstats
path: root/apps/app_queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/app_queue.c')
-rwxr-xr-xapps/app_queue.c95
1 files changed, 64 insertions, 31 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 542ede246..4d56b820d 100755
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -226,6 +226,7 @@ struct ast_call_queue {
int wrapped; /* Round Robin - wrapped around? */
int joinempty; /* Do we care if the queue has no members? */
int eventwhencalled; /* Generate an event when the agent is called (before pickup) */
+ int leavewhenempty; /* If all agents leave the queue, remove callers from the queue */
struct member *members; /* Member channels to be tried */
struct queue_ent *head; /* Start of the actual queue */
@@ -544,7 +545,7 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
}
}
-static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
+static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
{
int res;
if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
@@ -552,6 +553,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
if (qe->chan->cdr)
ast_cdr_busy(qe->chan->cdr);
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
}
/* Request the peer */
@@ -563,6 +565,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
if (qe->chan->cdr)
ast_cdr_busy(qe->chan->cdr);
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
}
tmp->chan->appl = "AppQueue";
@@ -593,6 +596,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
ast_hangup(tmp->chan);
tmp->chan = NULL;
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
} else {
if (qe->parent->eventwhencalled) {
@@ -610,10 +614,10 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Called %s/%s\n", tmp->tech, tmp->numsubst);
}
- return 0;
+ return 1;
}
-static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
+static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
{
struct localuser *cur;
struct localuser *best;
@@ -635,9 +639,9 @@ static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
/* Ring everyone who shares this best metric (for ringall) */
cur = outgoing;
while(cur) {
- if (cur->stillgoing && !cur->chan && (cur->metric == bestmetric)) {
+ if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
ast_log(LOG_DEBUG, "(Parallel) Trying '%s/%s' with metric %d\n", cur->tech, cur->numsubst, cur->metric);
- ring_entry(qe, cur);
+ ring_entry(qe, cur, busies);
}
cur = cur->next;
}
@@ -646,7 +650,7 @@ static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
if (option_debug)
ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n",
best->tech, best->numsubst, best->metric);
- ring_entry(qe, best);
+ ring_entry(qe, best, busies);
}
}
} while (best && !best->chan);
@@ -710,15 +714,36 @@ static int valid_exit(struct queue_ent *qe, char digit)
#define AST_MAX_WATCHERS 256
-static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, char *digit)
+#define BUILD_STATS do { \
+ o = outgoing; \
+ found = -1; \
+ pos = 1; \
+ numlines = 0; \
+ watchers[0] = in; \
+ while(o) { \
+ /* Keep track of important channels */ \
+ if (o->stillgoing) { \
+ stillgoing = 1; \
+ if (o->chan) { \
+ watchers[pos++] = o->chan; \
+ found = 1; \
+ } \
+ } \
+ o = o->next; \
+ numlines++; \
+ } \
+ } while(0)
+
+static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, char *digit, int prebusies)
{
char *queue = qe->parent->name;
struct localuser *o;
int found;
int numlines;
int sentringing = 0;
- int numbusies = 0;
+ int numbusies = prebusies;
int orig = *to;
+ int stillgoing = 0;
struct ast_frame *f;
struct localuser *peer = NULL;
struct ast_channel *watchers[AST_MAX_WATCHERS];
@@ -727,25 +752,18 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
struct ast_channel *in = qe->chan;
while(*to && !peer) {
- o = outgoing;
- found = -1;
- pos = 1;
- numlines = 0;
- watchers[0] = in;
- while(o) {
- /* Keep track of important channels */
- if (o->stillgoing && o->chan) {
- watchers[pos++] = o->chan;
- found = 1;
- }
- o = o->next;
- numlines++;
+ BUILD_STATS;
+ if ((found < 0) && stillgoing && !qe->parent->strategy) {
+ /* On "ringall" strategy we only move to the next penalty level
+ when *all* ringing phones are done in the current penalty level */
+ ring_one(qe, outgoing, &numbusies);
+ BUILD_STATS;
}
if (found < 0) {
if (numlines == numbusies) {
ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
} else {
- ast_log(LOG_NOTICE, "No one is answering queue '%s'\n", queue);
+ ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d)\n", queue, numlines, numbusies);
}
*to = 0;
return NULL;
@@ -789,7 +807,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
numbusies++;
break;
case AST_CONTROL_CONGESTION:
@@ -801,7 +819,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
numbusies++;
break;
case AST_CONTROL_RINGING:
@@ -827,7 +845,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
}
}
o = o->next;
@@ -912,6 +930,12 @@ static int wait_our_turn(struct queue_ent *qe, int ringing)
break;
}
+ /* leave the queue if no agents, if enabled */
+ if (!(qe->parent->members) && qe->parent->leavewhenempty) {
+ leave_queue(qe);
+ break;
+ }
+
/* Make a position announcement, if enabled */
if (qe->parent->announcefrequency && !ringing)
say_position(qe);
@@ -1017,6 +1041,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
struct member *member;
int res = 0, bridge = 0;
int zapx = 2;
+ int numbusies = 0;
int x=0;
char *announce = NULL;
char digit = 0;
@@ -1099,9 +1124,9 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
to = qe->parent->timeout * 1000;
else
to = -1;
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
ast_mutex_unlock(&qe->parent->lock);
- lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit);
+ lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit, numbusies);
ast_mutex_lock(&qe->parent->lock);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
store_next(qe, outgoing);
@@ -1626,7 +1651,7 @@ check_turns:
/* This is the wait loop for the head caller*/
/* To exit, they may get their call answered; */
/* they may dial a digit from the queue context; */
- /* or, they may may timeout. */
+ /* or, they may timeout. */
/* Leave if we have exceeded our queuetimeout */
if (qe.queuetimeout && ( (time(NULL) - qe.start) >= qe.queuetimeout) ) {
@@ -1634,6 +1659,12 @@ check_turns:
break;
}
+ /* leave the queue if no agents, if enabled */
+ if (!((qe.parent)->members) && (qe.parent)->leavewhenempty) {
+ leave_queue(&qe);
+ break;
+ }
+
/* Make a position announcement, if enabled */
if (qe.parent->announcefrequency && !ringing)
say_position(&qe);
@@ -1691,7 +1722,7 @@ check_turns:
}
}
/* Don't allow return code > 0 */
- if (res > 0 && res != AST_PBX_KEEPALIVE) {
+ if ((res == 0) || (res > 0 && res != AST_PBX_KEEPALIVE)) {
res = 0;
if (ringing) {
ast_indicate(chan, -1);
@@ -1781,7 +1812,7 @@ static void reload_queues(void)
strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
- strncpy(q->sound_lessthan, "queue-lessthan", sizeof(q->sound_lessthan) - 1);
+ strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
prev = q->members;
if (prev) {
/* find the end of any dynamic members */
@@ -1818,7 +1849,7 @@ static void reload_queues(void)
q->members = cur;
prev = cur;
}
- } else if (!strcasecmp(var->name, "music")) {
+ } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
strncpy(q->moh, var->value, sizeof(q->moh) - 1);
} else if (!strcasecmp(var->name, "announce")) {
strncpy(q->announce, var->value, sizeof(q->announce) - 1);
@@ -1872,6 +1903,8 @@ static void reload_queues(void)
}
} else if (!strcasecmp(var->name, "joinempty")) {
q->joinempty = ast_true(var->value);
+ } else if (!strcasecmp(var->name, "leavewhenempty")) {
+ q->leavewhenempty = ast_true(var->value);
} else if (!strcasecmp(var->name, "eventwhencalled")) {
q->eventwhencalled = ast_true(var->value);
} else {