mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
Add alternate queueing strategies. Implment ringall, roundrobin, and random
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1238 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -178,7 +178,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
winner = ast_waitfor_n(watchers, pos, to);
|
winner = ast_waitfor_n(watchers, pos, to);
|
||||||
o = outgoing;
|
o = outgoing;
|
||||||
while(o) {
|
while(o) {
|
||||||
if (o->stillgoing && (o->chan->_state == AST_STATE_UP)) {
|
if (o->stillgoing && o->chan && (o->chan->_state == AST_STATE_UP)) {
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
if (option_verbose > 2)
|
if (option_verbose > 2)
|
||||||
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
|
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
|
||||||
@@ -206,7 +206,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
o->stillgoing = 0;
|
o->stillgoing = 0;
|
||||||
ast_hangup(o->chan);
|
ast_hangup(o->chan);
|
||||||
o->chan = NULL;
|
o->chan = NULL;
|
||||||
numbusies++;
|
numbusies++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
255
apps/app_queue.c
255
apps/app_queue.c
@@ -43,6 +43,17 @@
|
|||||||
#define QUEUE_STRATEGY_FEWESTCALLS 3
|
#define QUEUE_STRATEGY_FEWESTCALLS 3
|
||||||
#define QUEUE_STRATEGY_RANDOM 4
|
#define QUEUE_STRATEGY_RANDOM 4
|
||||||
|
|
||||||
|
static struct strategy {
|
||||||
|
int strategy;
|
||||||
|
char *name;
|
||||||
|
} strategies[] = {
|
||||||
|
{ QUEUE_STRATEGY_RINGALL, "ringall" },
|
||||||
|
{ QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
|
||||||
|
{ QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
|
||||||
|
{ QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
|
||||||
|
{ QUEUE_STRATEGY_RANDOM, "random" },
|
||||||
|
};
|
||||||
|
|
||||||
#define DEFAULT_RETRY 5
|
#define DEFAULT_RETRY 5
|
||||||
#define DEFAULT_TIMEOUT 15
|
#define DEFAULT_TIMEOUT 15
|
||||||
#define RECHECK 1 /* Recheck every second to see we we're at the top yet */
|
#define RECHECK 1 /* Recheck every second to see we we're at the top yet */
|
||||||
@@ -100,6 +111,7 @@ struct localuser {
|
|||||||
char numsubst[256];
|
char numsubst[256];
|
||||||
char tech[40];
|
char tech[40];
|
||||||
int stillgoing;
|
int stillgoing;
|
||||||
|
int penalty;
|
||||||
int metric;
|
int metric;
|
||||||
int allowredirect_in;
|
int allowredirect_in;
|
||||||
int allowredirect_out;
|
int allowredirect_out;
|
||||||
@@ -126,6 +138,7 @@ struct queue_ent {
|
|||||||
struct member {
|
struct member {
|
||||||
char tech[80]; /* Technology */
|
char tech[80]; /* Technology */
|
||||||
char loc[256]; /* Location */
|
char loc[256]; /* Location */
|
||||||
|
int penalty; /* Are we a last resort? */
|
||||||
struct timeval lastcall; /* When last successful call was hungup */
|
struct timeval lastcall; /* When last successful call was hungup */
|
||||||
struct member *next; /* Next member */
|
struct member *next; /* Next member */
|
||||||
};
|
};
|
||||||
@@ -144,6 +157,11 @@ struct ast_call_queue {
|
|||||||
int dead; /* Whether this queue is dead or not */
|
int dead; /* Whether this queue is dead or not */
|
||||||
int retry; /* Retry calling everyone after this amount of time */
|
int retry; /* Retry calling everyone after this amount of time */
|
||||||
int timeout; /* How long to wait for an answer */
|
int timeout; /* How long to wait for an answer */
|
||||||
|
|
||||||
|
/* Queue strategy things */
|
||||||
|
|
||||||
|
int rrpos; /* Round Robin - position */
|
||||||
|
int wrapped; /* Round Robin - wrapped around? */
|
||||||
|
|
||||||
struct member *members; /* Member channels to be tried */
|
struct member *members; /* Member channels to be tried */
|
||||||
struct queue_ent *head; /* Start of the actual queue */
|
struct queue_ent *head; /* Start of the actual queue */
|
||||||
@@ -153,6 +171,25 @@ struct ast_call_queue {
|
|||||||
static struct ast_call_queue *queues = NULL;
|
static struct ast_call_queue *queues = NULL;
|
||||||
static pthread_mutex_t qlock = AST_MUTEX_INITIALIZER;
|
static pthread_mutex_t qlock = AST_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static char *int2strat(int strategy)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
|
||||||
|
if (strategy == strategies[x].strategy)
|
||||||
|
return strategies[x].name;
|
||||||
|
}
|
||||||
|
return "<unknown>";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int strat2int(char *strategy)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
|
||||||
|
if (!strcasecmp(strategy, strategies[x].name))
|
||||||
|
return strategies[x].strategy;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int join_queue(char *queuename, struct queue_ent *qe)
|
static int join_queue(char *queuename, struct queue_ent *qe)
|
||||||
{
|
{
|
||||||
@@ -295,7 +332,88 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
|
|||||||
|
|
||||||
#define MAX 256
|
#define MAX 256
|
||||||
|
|
||||||
static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect, char *queue)
|
static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
/* Request the peer */
|
||||||
|
tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
|
||||||
|
if (!tmp->chan) { /* If we can't, just go on to the next call */
|
||||||
|
#if 0
|
||||||
|
ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
|
||||||
|
#endif
|
||||||
|
if (qe->chan->cdr)
|
||||||
|
ast_cdr_busy(qe->chan->cdr);
|
||||||
|
tmp->stillgoing = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
tmp->chan->appl = "AppQueue";
|
||||||
|
tmp->chan->data = "(Outgoing Line)";
|
||||||
|
tmp->chan->whentohangup = 0;
|
||||||
|
if (tmp->chan->callerid)
|
||||||
|
free(tmp->chan->callerid);
|
||||||
|
if (tmp->chan->ani)
|
||||||
|
free(tmp->chan->ani);
|
||||||
|
if (qe->chan->callerid)
|
||||||
|
tmp->chan->callerid = strdup(qe->chan->callerid);
|
||||||
|
else
|
||||||
|
tmp->chan->callerid = NULL;
|
||||||
|
if (qe->chan->ani)
|
||||||
|
tmp->chan->ani = strdup(qe->chan->ani);
|
||||||
|
else
|
||||||
|
tmp->chan->ani = NULL;
|
||||||
|
/* Presense of ADSI CPE on outgoing channel follows ours */
|
||||||
|
tmp->chan->adsicpe = qe->chan->adsicpe;
|
||||||
|
/* Place the call, but don't wait on the answer */
|
||||||
|
res = ast_call(tmp->chan, tmp->numsubst, 0);
|
||||||
|
if (res) {
|
||||||
|
/* Again, keep going even if there's an error */
|
||||||
|
if (option_debug)
|
||||||
|
ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
|
||||||
|
else if (option_verbose > 2)
|
||||||
|
ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->numsubst);
|
||||||
|
ast_hangup(tmp->chan);
|
||||||
|
tmp->chan = NULL;
|
||||||
|
tmp->stillgoing = 0;
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
if (option_verbose > 2)
|
||||||
|
ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->numsubst);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
|
||||||
|
{
|
||||||
|
struct localuser *cur;
|
||||||
|
struct localuser *best;
|
||||||
|
int bestmetric=0;
|
||||||
|
do {
|
||||||
|
best = NULL;
|
||||||
|
cur = outgoing;
|
||||||
|
while(cur) {
|
||||||
|
if (cur->stillgoing && /* Not already done */
|
||||||
|
!cur->chan && /* Isn't already going */
|
||||||
|
(!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
|
||||||
|
bestmetric = cur->metric;
|
||||||
|
best = cur;
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
if (best) {
|
||||||
|
/* Ring the best channel, and remember the best
|
||||||
|
metric for the next pass */
|
||||||
|
ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n", best->tech, best->numsubst, best->metric);
|
||||||
|
ring_entry(qe, best);
|
||||||
|
}
|
||||||
|
} while (best && !best->chan);
|
||||||
|
|
||||||
|
if (!best) {
|
||||||
|
ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_channel *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect, char *queue)
|
||||||
{
|
{
|
||||||
struct localuser *o;
|
struct localuser *o;
|
||||||
int found;
|
int found;
|
||||||
@@ -308,7 +426,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
struct ast_channel *watchers[MAX];
|
struct ast_channel *watchers[MAX];
|
||||||
int pos;
|
int pos;
|
||||||
struct ast_channel *winner;
|
struct ast_channel *winner;
|
||||||
|
struct ast_channel *in = qe->chan;
|
||||||
|
|
||||||
while(*to && !peer) {
|
while(*to && !peer) {
|
||||||
o = outgoing;
|
o = outgoing;
|
||||||
found = -1;
|
found = -1;
|
||||||
@@ -336,7 +455,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
winner = ast_waitfor_n(watchers, pos, to);
|
winner = ast_waitfor_n(watchers, pos, to);
|
||||||
o = outgoing;
|
o = outgoing;
|
||||||
while(o) {
|
while(o) {
|
||||||
if (o->stillgoing && (o->chan->_state == AST_STATE_UP)) {
|
if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
if (option_verbose > 2)
|
if (option_verbose > 2)
|
||||||
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
|
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
|
||||||
@@ -367,6 +486,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
o->stillgoing = 0;
|
o->stillgoing = 0;
|
||||||
if (in->cdr)
|
if (in->cdr)
|
||||||
ast_cdr_busy(in->cdr);
|
ast_cdr_busy(in->cdr);
|
||||||
|
ast_hangup(o->chan);
|
||||||
|
o->chan = NULL;
|
||||||
|
if (qe->parent->strategy)
|
||||||
|
ring_one(qe, outgoing);
|
||||||
numbusies++;
|
numbusies++;
|
||||||
break;
|
break;
|
||||||
case AST_CONTROL_CONGESTION:
|
case AST_CONTROL_CONGESTION:
|
||||||
@@ -375,6 +498,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
o->stillgoing = 0;
|
o->stillgoing = 0;
|
||||||
if (in->cdr)
|
if (in->cdr)
|
||||||
ast_cdr_busy(in->cdr);
|
ast_cdr_busy(in->cdr);
|
||||||
|
ast_hangup(o->chan);
|
||||||
|
o->chan = NULL;
|
||||||
|
if (qe->parent->strategy)
|
||||||
|
ring_one(qe, outgoing);
|
||||||
numbusies++;
|
numbusies++;
|
||||||
break;
|
break;
|
||||||
case AST_CONTROL_RINGING:
|
case AST_CONTROL_RINGING:
|
||||||
@@ -397,6 +524,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
ast_frfree(f);
|
ast_frfree(f);
|
||||||
} else {
|
} else {
|
||||||
o->stillgoing = 0;
|
o->stillgoing = 0;
|
||||||
|
ast_hangup(o->chan);
|
||||||
|
o->chan = NULL;
|
||||||
|
if (qe->parent->strategy)
|
||||||
|
ring_one(qe, outgoing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o = o->next;
|
o = o->next;
|
||||||
@@ -450,61 +581,37 @@ static int wait_our_turn(struct queue_ent *qe)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
|
static int calc_metric(struct ast_call_queue *q, int pos, struct queue_ent *qe, struct localuser *tmp)
|
||||||
{
|
|
||||||
int res;
|
|
||||||
/* Request the peer */
|
|
||||||
tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
|
|
||||||
if (!tmp->chan) { /* If we can't, just go on to the next call */
|
|
||||||
#if 0
|
|
||||||
ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
|
|
||||||
#endif
|
|
||||||
if (qe->chan->cdr)
|
|
||||||
ast_cdr_busy(qe->chan->cdr);
|
|
||||||
tmp->stillgoing = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
tmp->chan->appl = "AppQueue";
|
|
||||||
tmp->chan->data = "(Outgoing Line)";
|
|
||||||
tmp->chan->whentohangup = 0;
|
|
||||||
if (tmp->chan->callerid)
|
|
||||||
free(tmp->chan->callerid);
|
|
||||||
if (tmp->chan->ani)
|
|
||||||
free(tmp->chan->ani);
|
|
||||||
if (qe->chan->callerid)
|
|
||||||
tmp->chan->callerid = strdup(qe->chan->callerid);
|
|
||||||
else
|
|
||||||
tmp->chan->callerid = NULL;
|
|
||||||
if (qe->chan->ani)
|
|
||||||
tmp->chan->ani = strdup(qe->chan->ani);
|
|
||||||
else
|
|
||||||
tmp->chan->ani = NULL;
|
|
||||||
/* Presense of ADSI CPE on outgoing channel follows ours */
|
|
||||||
tmp->chan->adsicpe = qe->chan->adsicpe;
|
|
||||||
/* Place the call, but don't wait on the answer */
|
|
||||||
res = ast_call(tmp->chan, tmp->numsubst, 0);
|
|
||||||
if (res) {
|
|
||||||
/* Again, keep going even if there's an error */
|
|
||||||
if (option_debug)
|
|
||||||
ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
|
|
||||||
else if (option_verbose > 2)
|
|
||||||
ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->numsubst);
|
|
||||||
ast_hangup(tmp->chan);
|
|
||||||
tmp->chan = NULL;
|
|
||||||
tmp->stillgoing = 0;
|
|
||||||
return 0;
|
|
||||||
} else
|
|
||||||
if (option_verbose > 2)
|
|
||||||
ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->numsubst);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calc_metric(struct ast_call_queue *q, struct queue_ent *qe, struct localuser *tmp)
|
|
||||||
{
|
{
|
||||||
switch (q->strategy) {
|
switch (q->strategy) {
|
||||||
case QUEUE_STRATEGY_RINGALL:
|
case QUEUE_STRATEGY_RINGALL:
|
||||||
ast_log(LOG_WARNING, "Can't calculate metric for ringall strategy\n");
|
ast_log(LOG_WARNING, "Can't calculate metric for ringall strategy\n");
|
||||||
break;
|
break;
|
||||||
|
case QUEUE_STRATEGY_ROUNDROBIN:
|
||||||
|
if (!pos) {
|
||||||
|
/* rrpos > number of queue entries */
|
||||||
|
if (!q->wrapped)
|
||||||
|
q->rrpos = 1;
|
||||||
|
else
|
||||||
|
q->rrpos++;
|
||||||
|
q->wrapped = 0;
|
||||||
|
}
|
||||||
|
if (pos < q->rrpos) {
|
||||||
|
tmp->metric = 1000 + pos;
|
||||||
|
} else {
|
||||||
|
if (pos > q->rrpos)
|
||||||
|
q->wrapped = 1;
|
||||||
|
tmp->metric = pos;
|
||||||
|
}
|
||||||
|
tmp->metric += tmp->penalty * 1000000;
|
||||||
|
break;
|
||||||
|
case QUEUE_STRATEGY_RANDOM:
|
||||||
|
tmp->metric = rand() % 1000;
|
||||||
|
tmp->metric += tmp->penalty * 1000000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -522,6 +629,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
|
|||||||
struct ast_channel *peer;
|
struct ast_channel *peer;
|
||||||
int res = 0, bridge = 0;
|
int res = 0, bridge = 0;
|
||||||
int zapx = 2;
|
int zapx = 2;
|
||||||
|
int x=0;
|
||||||
char *announce = NULL;
|
char *announce = NULL;
|
||||||
/* Hold the lock while we setup the outgoing calls */
|
/* Hold the lock while we setup the outgoing calls */
|
||||||
ast_pthread_mutex_lock(&qe->parent->lock);
|
ast_pthread_mutex_lock(&qe->parent->lock);
|
||||||
@@ -560,6 +668,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
|
|||||||
|
|
||||||
strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
|
strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
|
||||||
strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
|
strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
|
||||||
|
tmp->penalty = cur->penalty;
|
||||||
/* If we're dialing by extension, look at the extension to know what to dial */
|
/* If we're dialing by extension, look at the extension to know what to dial */
|
||||||
if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
|
if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
|
||||||
strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
|
strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
|
||||||
@@ -572,7 +681,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
|
|||||||
if (!qe->parent->strategy)
|
if (!qe->parent->strategy)
|
||||||
ring_entry(qe, tmp);
|
ring_entry(qe, tmp);
|
||||||
else
|
else
|
||||||
calc_metric(qe->parent, qe, tmp);
|
calc_metric(qe->parent, x++, qe, tmp);
|
||||||
/* Put them in the list of outgoing thingies... We're ready now.
|
/* Put them in the list of outgoing thingies... We're ready now.
|
||||||
XXX If we're forcibly removed, these outgoing calls won't get
|
XXX If we're forcibly removed, these outgoing calls won't get
|
||||||
hung up XXX */
|
hung up XXX */
|
||||||
@@ -588,9 +697,10 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
|
|||||||
to = qe->parent->timeout * 1000;
|
to = qe->parent->timeout * 1000;
|
||||||
else
|
else
|
||||||
to = -1;
|
to = -1;
|
||||||
|
if (qe->parent->strategy)
|
||||||
|
ring_one(qe, outgoing);
|
||||||
ast_pthread_mutex_unlock(&qe->parent->lock);
|
ast_pthread_mutex_unlock(&qe->parent->lock);
|
||||||
|
peer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, qe->parent->name);
|
||||||
peer = wait_for_answer(qe->chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, qe->parent->name);
|
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
if (to)
|
if (to)
|
||||||
/* Musta gotten hung up */
|
/* Musta gotten hung up */
|
||||||
@@ -619,12 +729,13 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
|
|||||||
outgoing = NULL;
|
outgoing = NULL;
|
||||||
if (announce) {
|
if (announce) {
|
||||||
int res2;
|
int res2;
|
||||||
res2 = ast_streamfile(peer, announce, peer->language);
|
res2 = ast_autoservice_start(qe->chan);
|
||||||
|
if (!res2)
|
||||||
|
res2 = ast_streamfile(peer, announce, peer->language);
|
||||||
/* XXX Need a function to wait on *both* streams XXX */
|
/* XXX Need a function to wait on *both* streams XXX */
|
||||||
if (!res2)
|
if (!res2)
|
||||||
res2 = ast_waitstream(peer, "");
|
res2 = ast_waitstream(peer, "");
|
||||||
else
|
res2 |= ast_autoservice_stop(qe->chan);
|
||||||
res2 = 0;
|
|
||||||
if (res2) {
|
if (res2) {
|
||||||
/* Agent must have hung up */
|
/* Agent must have hung up */
|
||||||
ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
|
ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
|
||||||
@@ -1058,11 +1169,20 @@ static void reload_queues(void)
|
|||||||
if (cur) {
|
if (cur) {
|
||||||
memset(cur, 0, sizeof(struct member));
|
memset(cur, 0, sizeof(struct member));
|
||||||
strncpy(cur->tech, var->value, sizeof(cur->tech) - 1);
|
strncpy(cur->tech, var->value, sizeof(cur->tech) - 1);
|
||||||
|
if ((tmp = strchr(cur->tech, ','))) {
|
||||||
|
*tmp = '\0';
|
||||||
|
tmp++;
|
||||||
|
cur->penalty = atoi(tmp);
|
||||||
|
if (cur->penalty < 0)
|
||||||
|
cur->penalty = 0;
|
||||||
|
}
|
||||||
if ((tmp = strchr(cur->tech, '/')))
|
if ((tmp = strchr(cur->tech, '/')))
|
||||||
*tmp = '\0';
|
*tmp = '\0';
|
||||||
if ((tmp = strchr(var->value, '/'))) {
|
if ((tmp = strchr(var->value, '/'))) {
|
||||||
tmp++;
|
tmp++;
|
||||||
strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
|
strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
|
||||||
|
if ((tmp = strchr(cur->loc, ',')))
|
||||||
|
*tmp = '\0';
|
||||||
} else
|
} else
|
||||||
ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
|
ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
|
||||||
if (prev)
|
if (prev)
|
||||||
@@ -1083,6 +1203,12 @@ static void reload_queues(void)
|
|||||||
q->retry = atoi(var->value);
|
q->retry = atoi(var->value);
|
||||||
} else if (!strcasecmp(var->name, "maxlen")) {
|
} else if (!strcasecmp(var->name, "maxlen")) {
|
||||||
q->maxlen = atoi(var->value);
|
q->maxlen = atoi(var->value);
|
||||||
|
} else if (!strcasecmp(var->name, "strategy")) {
|
||||||
|
q->strategy = strat2int(var->value);
|
||||||
|
if (q->strategy < 0) {
|
||||||
|
ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
|
||||||
|
q->strategy = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
|
ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
|
||||||
}
|
}
|
||||||
@@ -1148,11 +1274,16 @@ static int queues_show(int fd, int argc, char **argv)
|
|||||||
snprintf(max, sizeof(max), "%d", q->maxlen);
|
snprintf(max, sizeof(max), "%d", q->maxlen);
|
||||||
else
|
else
|
||||||
strcpy(max, "unlimited");
|
strcpy(max, "unlimited");
|
||||||
ast_cli(fd, "%-12.12s has %d calls (max %s)\n", q->name, q->count, max);
|
ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy\n", q->name, q->count, max, int2strat(q->strategy));
|
||||||
if (q->members) {
|
if (q->members) {
|
||||||
ast_cli(fd, " Members: \n");
|
ast_cli(fd, " Members: \n");
|
||||||
for (mem = q->members; mem; mem = mem->next)
|
for (mem = q->members; mem; mem = mem->next) {
|
||||||
ast_cli(fd, " %s/%s\n", mem->tech, mem->loc);
|
if (mem->penalty)
|
||||||
|
snprintf(max, sizeof(max), " with penalty %d", mem->penalty);
|
||||||
|
else
|
||||||
|
strcpy(max, "");
|
||||||
|
ast_cli(fd, " %s/%s%s\n", mem->tech, mem->loc, max);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
ast_cli(fd, " No Members\n");
|
ast_cli(fd, " No Members\n");
|
||||||
if (q->head) {
|
if (q->head) {
|
||||||
|
@@ -25,6 +25,16 @@
|
|||||||
;
|
;
|
||||||
;announce = queue-markq
|
;announce = queue-markq
|
||||||
;
|
;
|
||||||
|
; A strategy may be specified. Valid strategies include:
|
||||||
|
;
|
||||||
|
; ringall - ring all available channels until one answers (default)
|
||||||
|
; roundrobin - take turns ringing each available interface
|
||||||
|
; leastrecent - ring interface which least recently had a call
|
||||||
|
; fewestcalls - ring interface which has had fewest completed calls
|
||||||
|
; random - ring random interface
|
||||||
|
;
|
||||||
|
;strategy = ringall
|
||||||
|
;
|
||||||
; A context may be specified, in which if the user types a SINGLE
|
; A context may be specified, in which if the user types a SINGLE
|
||||||
; digit extension while they are in the queue, they will be taken out
|
; digit extension while they are in the queue, they will be taken out
|
||||||
; of the queue and sent to that extension in this context.
|
; of the queue and sent to that extension in this context.
|
||||||
@@ -44,7 +54,9 @@
|
|||||||
;maxlen = 0
|
;maxlen = 0
|
||||||
;
|
;
|
||||||
; Each member of this call queue is listed on a separate line in
|
; Each member of this call queue is listed on a separate line in
|
||||||
; the form technology/dialstring
|
; the form technology/dialstring. "member" means a normal member of a
|
||||||
|
; queue. An optional penalty may be specified after a comma, such that
|
||||||
|
; entries with higher penalties are considered last.
|
||||||
;
|
;
|
||||||
;member => Zap/1
|
;member => Zap/1
|
||||||
;member => Zap/2
|
;member => Zap/2
|
||||||
@@ -52,4 +64,6 @@
|
|||||||
;member => Agent/1002
|
;member => Agent/1002
|
||||||
|
|
||||||
;member => Agent/@1 ; Any agent in group 1
|
;member => Agent/@1 ; Any agent in group 1
|
||||||
;member => Agent/:1 ; Any agent in group 1, wait for first.
|
;member => Agent/:1,1 ; Any agent in group 1, wait for first
|
||||||
|
; available, but consider with penalty
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user