mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-21 01:01:02 +00:00
Pass concept of status back, permit "leaveempty" to work with static agents who are not loggedon (bug #2719)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4106 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -51,6 +51,7 @@ LOCAL_USER_DECL;
|
||||
static int chanavail_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=-1;
|
||||
int status;
|
||||
struct localuser *u;
|
||||
char info[512], tmp[512], *peers, *tech, *number, *rest, *cur;
|
||||
struct ast_channel *tempchan;
|
||||
@@ -80,20 +81,24 @@ static int chanavail_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
*number = '\0';
|
||||
number++;
|
||||
if ((tempchan = ast_request(tech, chan->nativeformats, number))) {
|
||||
if ((tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
|
||||
pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
|
||||
/* Store the originally used channel too */
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
|
||||
pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
|
||||
snprintf(tmp, sizeof(tmp), "%d", status);
|
||||
pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
|
||||
ast_hangup(tempchan);
|
||||
tempchan = NULL;
|
||||
res = 1;
|
||||
break;
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "%d", status);
|
||||
pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
|
||||
}
|
||||
cur = rest;
|
||||
} while (cur);
|
||||
}
|
||||
|
||||
if (res < 1) {
|
||||
pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
|
||||
pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/causes.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
@@ -134,14 +135,32 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
|
||||
|
||||
#define AST_MAX_WATCHERS 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_in, int *allowdisconnect_out, int *sentringing, char *status, size_t statussize)
|
||||
#define HANDLE_CAUSE(blah, bleh) do { \
|
||||
switch(cause) { \
|
||||
case AST_CAUSE_BUSY: \
|
||||
if (bleh->cdr) \
|
||||
ast_cdr_busy(bleh->cdr); \
|
||||
numbusy++; \
|
||||
case AST_CAUSE_CONGESTION: \
|
||||
case AST_CAUSE_UNREGISTERED: \
|
||||
if (bleh->cdr) \
|
||||
ast_cdr_busy(bleh->cdr); \
|
||||
numcongestion++; \
|
||||
default: \
|
||||
numnochan++; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart)
|
||||
{
|
||||
struct localuser *o;
|
||||
int found;
|
||||
int numlines;
|
||||
int numbusy = 0;
|
||||
int numcongestion = 0;
|
||||
int numnochan = 0;
|
||||
int numbusy = busystart;
|
||||
int numcongestion = congestionstart;
|
||||
int numnochan = nochanstart;
|
||||
int cause;
|
||||
int orig = *to;
|
||||
struct ast_frame *f;
|
||||
struct ast_channel *peer = NULL;
|
||||
@@ -227,11 +246,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
|
||||
/* Setup parameters */
|
||||
o->chan = ast_request(tech, in->nativeformats, stuff);
|
||||
o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
|
||||
if (!o->chan) {
|
||||
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
|
||||
o->stillgoing = 0;
|
||||
numnochan++;
|
||||
HANDLE_CAUSE(cause, in);
|
||||
} else {
|
||||
if (o->chan->cid.cid_num)
|
||||
free(o->chan->cid.cid_num);
|
||||
@@ -317,9 +336,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
||||
ast_hangup(o->chan);
|
||||
o->chan = NULL;
|
||||
o->stillgoing = 0;
|
||||
if (in->cdr)
|
||||
ast_cdr_busy(in->cdr);
|
||||
numbusy++;
|
||||
HANDLE_CAUSE(AST_CAUSE_BUSY, in);
|
||||
break;
|
||||
case AST_CONTROL_CONGESTION:
|
||||
if (option_verbose > 2)
|
||||
@@ -328,9 +345,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
||||
ast_hangup(o->chan);
|
||||
o->chan = NULL;
|
||||
o->stillgoing = 0;
|
||||
if (in->cdr)
|
||||
ast_cdr_busy(in->cdr);
|
||||
numcongestion++;
|
||||
HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
|
||||
break;
|
||||
case AST_CONTROL_RINGING:
|
||||
if (option_verbose > 2)
|
||||
@@ -433,6 +448,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
||||
int privacy=0;
|
||||
int announce=0;
|
||||
int resetcdr=0;
|
||||
int numbusy = 0;
|
||||
int numcongestion = 0;
|
||||
int numnochan = 0;
|
||||
int cause;
|
||||
char numsubst[AST_MAX_EXTENSION];
|
||||
char restofit[AST_MAX_EXTENSION];
|
||||
char *transfer = NULL;
|
||||
@@ -738,14 +757,11 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
||||
ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
|
||||
}
|
||||
/* Request the peer */
|
||||
tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
|
||||
tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
|
||||
if (!tmp->chan) {
|
||||
/* If we can't, just go on to the next call */
|
||||
ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
|
||||
if (chan->cdr)
|
||||
ast_cdr_busy(chan->cdr);
|
||||
free(tmp);
|
||||
cur = rest;
|
||||
HANDLE_CAUSE(cause, chan);
|
||||
continue;
|
||||
}
|
||||
if (!ast_strlen_zero(tmp->chan->call_forward)) {
|
||||
@@ -767,11 +783,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
|
||||
/* Setup parameters */
|
||||
ast_hangup(tmp->chan);
|
||||
tmp->chan = ast_request(tech, chan->nativeformats, stuff);
|
||||
tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
|
||||
if (!tmp->chan) {
|
||||
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
|
||||
free(tmp);
|
||||
cur = rest;
|
||||
HANDLE_CAUSE(cause, chan);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -847,8 +862,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
||||
else if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
|
||||
ast_hangup(tmp->chan);
|
||||
free(tmp);
|
||||
cur = rest;
|
||||
tmp->chan = NULL;
|
||||
continue;
|
||||
} else
|
||||
if (option_verbose > 2)
|
||||
@@ -888,7 +902,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
||||
strncpy(status, "CHANUNAVAIL", sizeof(status) - 1);
|
||||
|
||||
time(&start_time);
|
||||
peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &sentringing, status, sizeof(status));
|
||||
peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion);
|
||||
|
||||
if (!peer) {
|
||||
if (to)
|
||||
|
||||
@@ -222,7 +222,7 @@ static struct ast_conference *build_conf(char *confno, char *pin, int make, int
|
||||
strncpy(cnf->confno, confno, sizeof(cnf->confno) - 1);
|
||||
strncpy(cnf->pin, pin, sizeof(cnf->pin) - 1);
|
||||
cnf->markedusers = 0;
|
||||
cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo");
|
||||
cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL);
|
||||
if (cnf->chan) {
|
||||
cnf->fd = cnf->chan->fds[0]; /* for use by conf_play() */
|
||||
} else {
|
||||
|
||||
107
apps/app_queue.c
107
apps/app_queue.c
@@ -45,6 +45,7 @@
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/monitor.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/causes.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
@@ -145,6 +146,7 @@ struct localuser {
|
||||
char tech[40];
|
||||
int stillgoing;
|
||||
int metric;
|
||||
int oldstatus;
|
||||
int allowredirect_in;
|
||||
int allowredirect_out;
|
||||
int ringbackonly;
|
||||
@@ -182,6 +184,7 @@ struct member {
|
||||
int penalty; /* Are we a last resort? */
|
||||
int calls; /* Number of calls serviced by this member */
|
||||
int dynamic; /* Are we dynamically added? */
|
||||
int status; /* Status of queue member */
|
||||
time_t lastcall; /* When last successful call was hungup */
|
||||
struct member *next; /* Next member */
|
||||
};
|
||||
@@ -280,6 +283,26 @@ static inline void insert_entry(struct ast_call_queue *q,
|
||||
new->opos = *pos;
|
||||
}
|
||||
|
||||
static int has_no_members(struct ast_call_queue *q)
|
||||
{
|
||||
struct member *member;
|
||||
int empty = 1;
|
||||
member = q->members;
|
||||
while(empty && member) {
|
||||
switch(member->status) {
|
||||
case AST_CAUSE_NOSUCHDRIVER:
|
||||
case AST_CAUSE_UNREGISTERED:
|
||||
/* Not logged on, etc */
|
||||
break;
|
||||
default:
|
||||
/* Not empty */
|
||||
empty = 0;
|
||||
}
|
||||
member = member->next;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
static int join_queue(char *queuename, struct queue_ent *qe)
|
||||
{
|
||||
struct ast_call_queue *q;
|
||||
@@ -293,7 +316,7 @@ static int join_queue(char *queuename, struct queue_ent *qe)
|
||||
if (!strcasecmp(q->name, queuename)) {
|
||||
/* This is our one */
|
||||
ast_mutex_lock(&q->lock);
|
||||
if ((q->members || q->joinempty) && (!q->maxlen || (q->count < q->maxlen))) {
|
||||
if ((!has_no_members(q) || q->joinempty || !q->head) && (!q->maxlen || (q->count < q->maxlen))) {
|
||||
/* There's space for us, put us at the right position inside
|
||||
* the queue.
|
||||
* Take into account the priority of the calling user */
|
||||
@@ -551,9 +574,29 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
|
||||
}
|
||||
}
|
||||
|
||||
static int update_status(struct ast_call_queue *q, struct member *member, int status)
|
||||
{
|
||||
struct member *cur;
|
||||
/* Since a reload could have taken place, we have to traverse the list to
|
||||
be sure it's still valid */
|
||||
ast_mutex_lock(&q->lock);
|
||||
cur = q->members;
|
||||
while(cur) {
|
||||
if (member == cur) {
|
||||
cur->status = status;
|
||||
break;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
q->callscompleted++;
|
||||
ast_mutex_unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
|
||||
{
|
||||
int res;
|
||||
int status;
|
||||
if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
|
||||
ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s/%s\n", tmp->tech, tmp->numsubst);
|
||||
if (qe->chan->cdr)
|
||||
@@ -562,7 +605,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
|
||||
return 0;
|
||||
}
|
||||
/* Request the peer */
|
||||
tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
|
||||
tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst, &status);
|
||||
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);
|
||||
@@ -570,8 +613,11 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
|
||||
if (qe->chan->cdr)
|
||||
ast_cdr_busy(qe->chan->cdr);
|
||||
tmp->stillgoing = 0;
|
||||
update_status(qe->parent, tmp->member, status);
|
||||
return 0;
|
||||
}
|
||||
} else if (status != tmp->oldstatus)
|
||||
update_status(qe->parent, tmp->member, status);
|
||||
|
||||
tmp->chan->appl = "AppQueue";
|
||||
tmp->chan->data = "(Outgoing Line)";
|
||||
tmp->chan->whentohangup = 0;
|
||||
@@ -728,6 +774,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
|
||||
struct localuser *o;
|
||||
int found;
|
||||
int numlines;
|
||||
int status;
|
||||
int sentringing = 0;
|
||||
int numbusies = 0;
|
||||
int numnochan = 0;
|
||||
@@ -795,7 +842,9 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
|
||||
/* Setup parameters */
|
||||
o->chan = ast_request(tech, in->nativeformats, stuff);
|
||||
o->chan = ast_request(tech, in->nativeformats, stuff, &status);
|
||||
if (status != o->oldstatus)
|
||||
update_status(qe->parent, o->member, status);
|
||||
if (!o->chan) {
|
||||
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
|
||||
o->stillgoing = 0;
|
||||
@@ -997,7 +1046,7 @@ static int wait_our_turn(struct queue_ent *qe, int ringing)
|
||||
}
|
||||
|
||||
/* leave the queue if no agents, if enabled */
|
||||
if (!(qe->parent->members) && qe->parent->leavewhenempty) {
|
||||
if (has_no_members(qe->parent) && qe->parent->leavewhenempty) {
|
||||
leave_queue(qe);
|
||||
break;
|
||||
}
|
||||
@@ -1163,6 +1212,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
|
||||
tmp->member = cur; /* Never directly dereference! Could change on reload */
|
||||
strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
|
||||
strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
|
||||
tmp->oldstatus = cur->status;
|
||||
tmp->lastcall = cur->lastcall;
|
||||
/* If we're dialing by extension, look at the extension to know what to dial */
|
||||
if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
|
||||
@@ -1728,6 +1778,7 @@ check_turns:
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
int makeannouncement = 0;
|
||||
for (;;) {
|
||||
/* This is the wait loop for the head caller*/
|
||||
/* To exit, they may get their call answered; */
|
||||
@@ -1740,15 +1791,12 @@ check_turns:
|
||||
break;
|
||||
}
|
||||
|
||||
/* leave the queue if no agents, if enabled */
|
||||
if (!((qe.parent)->members) && (qe.parent)->leavewhenempty) {
|
||||
leave_queue(&qe);
|
||||
break;
|
||||
if (makeannouncement) {
|
||||
/* Make a position announcement, if enabled */
|
||||
if (qe.parent->announcefrequency && !ringing)
|
||||
say_position(&qe);
|
||||
}
|
||||
|
||||
/* Make a position announcement, if enabled */
|
||||
if (qe.parent->announcefrequency && !ringing)
|
||||
say_position(&qe);
|
||||
makeannouncement = 1;
|
||||
|
||||
/* Try calling all queue members for 'timeout' seconds */
|
||||
res = try_calling(&qe, options, announceoverride, url, &go_on);
|
||||
@@ -1761,6 +1809,12 @@ check_turns:
|
||||
break;
|
||||
}
|
||||
|
||||
/* leave the queue if no agents, if enabled */
|
||||
if (has_no_members(qe.parent) && (qe.parent->leavewhenempty)) {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Leave if we have exceeded our queuetimeout */
|
||||
if (qe.queuetimeout && ( (time(NULL) - qe.start) >= qe.queuetimeout) ) {
|
||||
res = 0;
|
||||
@@ -2037,6 +2091,30 @@ static void reload_queues(void)
|
||||
ast_mutex_unlock(&qlock);
|
||||
}
|
||||
|
||||
static char *status2str(int status, char *buf, int buflen)
|
||||
{
|
||||
switch(status) {
|
||||
case AST_CAUSE_BUSY:
|
||||
strncpy(buf, "busy", buflen - 1);
|
||||
break;
|
||||
case AST_CAUSE_CONGESTION:
|
||||
strncpy(buf, "congestion", buflen - 1);
|
||||
break;
|
||||
case AST_CAUSE_FAILURE:
|
||||
strncpy(buf, "failure", buflen - 1);
|
||||
break;
|
||||
case AST_CAUSE_UNREGISTERED:
|
||||
strncpy(buf, "unregistered", buflen - 1);
|
||||
break;
|
||||
case AST_CAUSE_NOSUCHDRIVER:
|
||||
strncpy(buf, "nosuchdriver", buflen - 1);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, buflen, "unknown status %d", status);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int __queues_show(int fd, int argc, char **argv, int queue_show)
|
||||
{
|
||||
struct ast_call_queue *q;
|
||||
@@ -2046,6 +2124,7 @@ static int __queues_show(int fd, int argc, char **argv, int queue_show)
|
||||
time_t now;
|
||||
char max[80] = "";
|
||||
char calls[80] = "";
|
||||
char tmpbuf[80] = "";
|
||||
float sl = 0;
|
||||
|
||||
time(&now);
|
||||
@@ -2092,6 +2171,8 @@ static int __queues_show(int fd, int argc, char **argv, int queue_show)
|
||||
max[0] = '\0';
|
||||
if (mem->dynamic)
|
||||
strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
|
||||
if (mem->status)
|
||||
snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
|
||||
if (mem->calls) {
|
||||
snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
|
||||
mem->calls, (long)(time(NULL) - mem->lastcall));
|
||||
|
||||
Reference in New Issue
Block a user