|
|
|
@ -420,20 +420,24 @@ static void set_queue_result(struct ast_channel *chan, enum queue_result res)
|
|
|
|
|
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(const 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -587,8 +591,6 @@ static struct member *create_queue_member(char *interface, int penalty, int paus
|
|
|
|
|
{
|
|
|
|
|
struct member *cur;
|
|
|
|
|
|
|
|
|
|
/* Add a new member */
|
|
|
|
|
|
|
|
|
|
if ((cur = ast_calloc(1, sizeof(*cur)))) {
|
|
|
|
|
cur->penalty = penalty;
|
|
|
|
|
cur->paused = paused;
|
|
|
|
@ -615,6 +617,7 @@ static struct ast_call_queue *alloc_queue(const char *queuename)
|
|
|
|
|
static void init_queue(struct ast_call_queue *q)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
q->dead = 0;
|
|
|
|
|
q->retry = DEFAULT_RETRY;
|
|
|
|
|
q->timeout = -1;
|
|
|
|
@ -749,6 +752,7 @@ static void queue_set_param(struct ast_call_queue *q, const char *param, const c
|
|
|
|
|
int i = 0;
|
|
|
|
|
char *c, *lastc;
|
|
|
|
|
char buff[80];
|
|
|
|
|
|
|
|
|
|
if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
|
|
|
|
|
ast_copy_string(q->moh, val, sizeof(q->moh));
|
|
|
|
|
} else if (!strcasecmp(param, "announce")) {
|
|
|
|
@ -905,17 +909,13 @@ static void rt_handle_member_record(struct ast_call_queue *q, char *interface, c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find the member, or the place to put a new one. */
|
|
|
|
|
prev_m = NULL;
|
|
|
|
|
m = q->members;
|
|
|
|
|
while (m && strcmp(m->interface, interface)) {
|
|
|
|
|
prev_m = m;
|
|
|
|
|
m = m->next;
|
|
|
|
|
}
|
|
|
|
|
for (m = q->members, prev_m = NULL;
|
|
|
|
|
m && strcmp(m->interface, interface);
|
|
|
|
|
prev_m = m, m = m->next);
|
|
|
|
|
|
|
|
|
|
/* Create a new one if not found, else update penalty */
|
|
|
|
|
if (!m) {
|
|
|
|
|
m = create_queue_member(interface, penalty, 0);
|
|
|
|
|
if (m) {
|
|
|
|
|
if ((m = create_queue_member(interface, penalty, 0))) {
|
|
|
|
|
m->dead = 0;
|
|
|
|
|
add_to_interfaces(interface);
|
|
|
|
|
if (prev_m) {
|
|
|
|
@ -970,10 +970,9 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
|
|
|
|
|
|
|
|
|
|
/* Find the queue in the in-core list (we will create a new one if not found). */
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
if (!strcasecmp(q->name, queuename)) {
|
|
|
|
|
if (!strcasecmp(q->name, queuename))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Static queues override realtime. */
|
|
|
|
|
if (q) {
|
|
|
|
@ -1024,38 +1023,32 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
|
|
|
|
|
}
|
|
|
|
|
init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
|
|
|
|
|
|
|
|
|
|
v = queue_vars;
|
|
|
|
|
memset(tmpbuf, 0, sizeof(tmpbuf));
|
|
|
|
|
while(v) {
|
|
|
|
|
for (v = queue_vars; v; v = v->next) {
|
|
|
|
|
/* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
|
|
|
|
|
if((tmp = strchr(v->name, '_')) != NULL) {
|
|
|
|
|
if ((tmp = strchr(v->name, '_'))) {
|
|
|
|
|
ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
|
|
|
|
|
tmp_name = tmpbuf;
|
|
|
|
|
tmp = tmp_name;
|
|
|
|
|
while((tmp = strchr(tmp, '_')) != NULL)
|
|
|
|
|
while ((tmp = strchr(tmp, '_')))
|
|
|
|
|
*tmp++ = '-';
|
|
|
|
|
} else
|
|
|
|
|
tmp_name = v->name;
|
|
|
|
|
queue_set_param(q, tmp_name, v->value, -1, 0);
|
|
|
|
|
v = v->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
|
|
|
|
|
rr_dep_warning();
|
|
|
|
|
|
|
|
|
|
/* Temporarily set non-dynamic members dead so we can detect deleted ones. */
|
|
|
|
|
m = q->members;
|
|
|
|
|
while (m) {
|
|
|
|
|
for (m = q->members; m; m = m->next) {
|
|
|
|
|
if (!m->dynamic)
|
|
|
|
|
m->dead = 1;
|
|
|
|
|
m = m->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface = ast_category_browse(member_config, NULL);
|
|
|
|
|
while (interface) {
|
|
|
|
|
interface = NULL;
|
|
|
|
|
while (ast_category_browse(member_config, interface))
|
|
|
|
|
rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
|
|
|
|
|
interface = ast_category_browse(member_config, interface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Delete all realtime members that have been deleted in DB. */
|
|
|
|
|
m = q->members;
|
|
|
|
@ -1083,7 +1076,7 @@ static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struc
|
|
|
|
|
|
|
|
|
|
static struct ast_call_queue *load_realtime_queue(char *queuename)
|
|
|
|
|
{
|
|
|
|
|
struct ast_variable *queue_vars = NULL;
|
|
|
|
|
struct ast_variable *queue_vars;
|
|
|
|
|
struct ast_config *member_config = NULL;
|
|
|
|
|
struct ast_call_queue *q;
|
|
|
|
|
|
|
|
|
@ -1137,8 +1130,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
|
|
|
|
int inserted = 0;
|
|
|
|
|
enum queue_member_status stat;
|
|
|
|
|
|
|
|
|
|
q = load_realtime_queue(queuename);
|
|
|
|
|
if (!q)
|
|
|
|
|
if (!(q = load_realtime_queue(queuename)))
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
@ -1179,7 +1171,6 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
|
|
|
|
ast_copy_string(qe->context, q->context, sizeof(qe->context));
|
|
|
|
|
q->count++;
|
|
|
|
|
res = 0;
|
|
|
|
|
/* XXX missing CalledIDnum ? */
|
|
|
|
|
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,
|
|
|
|
@ -1191,6 +1182,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1200,12 +1192,8 @@ static int play_file(struct ast_channel *chan, char *filename)
|
|
|
|
|
|
|
|
|
|
ast_stopstream(chan);
|
|
|
|
|
res = ast_streamfile(chan, filename, chan->language);
|
|
|
|
|
|
|
|
|
|
if (!res)
|
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
|
else
|
|
|
|
|
res = 0;
|
|
|
|
|
|
|
|
|
|
ast_stopstream(chan);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
@ -1239,6 +1227,7 @@ static int valid_exit(struct queue_ent *qe, char digit)
|
|
|
|
|
/* Return 1 on a successful goto */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1303,11 +1292,11 @@ static int say_position(struct queue_ent *qe)
|
|
|
|
|
if (res && valid_exit(qe, res))
|
|
|
|
|
goto playout;
|
|
|
|
|
|
|
|
|
|
res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
|
|
|
|
|
res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
|
|
|
|
|
if (res && valid_exit(qe, res))
|
|
|
|
|
goto playout;
|
|
|
|
|
} else {
|
|
|
|
|
res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
|
|
|
|
|
res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
|
|
|
|
|
if (res && valid_exit(qe, res))
|
|
|
|
|
goto playout;
|
|
|
|
|
}
|
|
|
|
@ -1317,7 +1306,7 @@ static int say_position(struct queue_ent *qe)
|
|
|
|
|
goto playout;
|
|
|
|
|
}
|
|
|
|
|
if (avgholdsecs>0) {
|
|
|
|
|
res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
|
|
|
|
|
res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
|
|
|
|
|
if (res && valid_exit(qe, res))
|
|
|
|
|
goto playout;
|
|
|
|
|
|
|
|
|
@ -1373,14 +1362,12 @@ static void leave_queue(struct queue_ent *qe)
|
|
|
|
|
struct queue_ent *cur, *prev = NULL;
|
|
|
|
|
int pos = 0;
|
|
|
|
|
|
|
|
|
|
q = qe->parent;
|
|
|
|
|
if (!q)
|
|
|
|
|
if (!(q = qe->parent))
|
|
|
|
|
return;
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
|
|
|
|
|
prev = NULL;
|
|
|
|
|
cur = q->head;
|
|
|
|
|
while(cur) {
|
|
|
|
|
for (cur = q->head; cur; cur = cur->next) {
|
|
|
|
|
if (cur == qe) {
|
|
|
|
|
q->count--;
|
|
|
|
|
|
|
|
|
@ -1400,9 +1387,9 @@ static void leave_queue(struct queue_ent *qe)
|
|
|
|
|
cur->pos = ++pos;
|
|
|
|
|
prev = cur;
|
|
|
|
|
}
|
|
|
|
|
cur = cur->next;
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
|
|
|
|
|
if (q->dead && !q->count) {
|
|
|
|
|
/* It's dead and nobody is in it, so kill it */
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
@ -1435,7 +1422,9 @@ static int update_status(struct ast_call_queue *q, struct member *member, int st
|
|
|
|
|
be sure it's still valid */
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
for (cur = q->members; cur; cur = cur->next) {
|
|
|
|
|
if (member == cur) {
|
|
|
|
|
if (member != cur)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
cur->status = status;
|
|
|
|
|
if (!q->maskmemberstatus) {
|
|
|
|
|
manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
|
|
|
|
@ -1450,8 +1439,6 @@ static int update_status(struct ast_call_queue *q, struct member *member, int st
|
|
|
|
|
q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
|
|
|
|
|
cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
return 0;
|
|
|
|
@ -1486,7 +1473,9 @@ static int compare_weight(struct ast_call_queue *rq, struct member *member)
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
if (q->count && q->members) {
|
|
|
|
|
for (mem = q->members; mem; mem = mem->next) {
|
|
|
|
|
if (!strcmp(mem->interface, member->interface)) {
|
|
|
|
|
if (strcmp(mem->interface, member->interface))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
|
|
|
|
|
if (q->weight > rq->weight) {
|
|
|
|
|
ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
|
|
|
|
@ -1495,7 +1484,6 @@ static int compare_weight(struct ast_call_queue *rq, struct member *member)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
if (found)
|
|
|
|
|
break;
|
|
|
|
@ -1564,9 +1552,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|
|
|
|
/* Request the peer */
|
|
|
|
|
tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &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' for Queue\n", cur->tech);
|
|
|
|
|
#endif
|
|
|
|
|
if (qe->chan->cdr)
|
|
|
|
|
ast_cdr_busy(qe->chan->cdr);
|
|
|
|
|
tmp->stillgoing = 0;
|
|
|
|
@ -1596,8 +1581,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|
|
|
|
tmp->chan->adsicpe = qe->chan->adsicpe;
|
|
|
|
|
|
|
|
|
|
/* Place the call, but don't wait on the answer */
|
|
|
|
|
res = ast_call(tmp->chan, location, 0);
|
|
|
|
|
if (res) {
|
|
|
|
|
if ((res = ast_call(tmp->chan, location, 0))) {
|
|
|
|
|
/* Again, keep going even if there's an error */
|
|
|
|
|
if (option_debug)
|
|
|
|
|
ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
|
|
|
|
@ -1624,6 +1608,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|
|
|
|
if (option_verbose > 2)
|
|
|
|
|
ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1639,6 +1624,7 @@ static struct callattempt *find_best(struct callattempt *outgoing)
|
|
|
|
|
best = cur;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return best;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1672,6 +1658,7 @@ static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *bus
|
|
|
|
|
if (best->chan) /* break out with result = 1 */
|
|
|
|
|
ret = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1695,6 +1682,7 @@ static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
qe->parent->wrapped = 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1713,15 +1701,8 @@ static int background_file(struct queue_ent *qe, struct ast_channel *chan, char
|
|
|
|
|
|
|
|
|
|
/* Stop playback */
|
|
|
|
|
ast_stopstream(chan);
|
|
|
|
|
} else {
|
|
|
|
|
res = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*if (res) {
|
|
|
|
|
ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
|
|
|
|
|
res = 0;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1782,7 +1763,6 @@ static void record_abandoned(struct queue_ent *qe)
|
|
|
|
|
/*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
|
|
|
|
|
static void rna(int rnatime, struct queue_ent *qe, char *membername)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (option_verbose > 2)
|
|
|
|
|
ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
|
|
|
|
|
ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
|
|
|
|
@ -1863,9 +1843,10 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|
|
|
|
} else if (o->chan && (o->chan == winner)) {
|
|
|
|
|
ast_copy_string(on, o->member->interface, sizeof(on));
|
|
|
|
|
if (!ast_strlen_zero(o->chan->call_forward)) {
|
|
|
|
|
char tmpchan[256]="";
|
|
|
|
|
char tmpchan[256];
|
|
|
|
|
char *stuff;
|
|
|
|
|
char *tech;
|
|
|
|
|
|
|
|
|
|
ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
|
|
|
|
|
if ((stuff = strchr(tmpchan, '/'))) {
|
|
|
|
|
*stuff++ = '\0';
|
|
|
|
@ -1979,8 +1960,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|
|
|
|
}
|
|
|
|
|
ast_frfree(f);
|
|
|
|
|
} else {
|
|
|
|
|
endtime = (long)time(NULL);
|
|
|
|
|
endtime -= starttime;
|
|
|
|
|
endtime = (long) time(NULL) - starttime;
|
|
|
|
|
rna(endtime * 1000, qe, on);
|
|
|
|
|
do_hang(o);
|
|
|
|
|
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
|
|
|
|
@ -1993,12 +1973,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|
|
|
|
}
|
|
|
|
|
if (winner == in) {
|
|
|
|
|
f = ast_read(in);
|
|
|
|
|
#if 0
|
|
|
|
|
if (f && (f->frametype != AST_FRAME_VOICE))
|
|
|
|
|
printf("Frame type: %d, %d\n", f->frametype, f->subclass);
|
|
|
|
|
else if (!f || (f->frametype != AST_FRAME_VOICE))
|
|
|
|
|
printf("Hangup received on %s\n", in->name);
|
|
|
|
|
#endif
|
|
|
|
|
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
|
|
|
|
|
/* Got hung up */
|
|
|
|
|
*to = -1;
|
|
|
|
@ -2028,7 +2002,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return peer;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int is_our_turn(struct queue_ent *qe)
|
|
|
|
@ -2054,29 +2027,27 @@ static int is_our_turn(struct queue_ent *qe)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* This needs a lock. How many members are available to be served? */
|
|
|
|
|
|
|
|
|
|
ast_mutex_lock(&qe->parent->lock);
|
|
|
|
|
|
|
|
|
|
ch = qe->parent->head;
|
|
|
|
|
cur = qe->parent->members;
|
|
|
|
|
|
|
|
|
|
if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
|
|
|
|
|
if (option_debug)
|
|
|
|
|
ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl);
|
|
|
|
|
avl = 1;
|
|
|
|
|
} else {
|
|
|
|
|
cur = qe->parent->members;
|
|
|
|
|
while (cur) {
|
|
|
|
|
if (cur->status == 1)
|
|
|
|
|
avl++;
|
|
|
|
|
cur = cur->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (option_debug)
|
|
|
|
|
ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
|
|
|
|
|
|
|
|
|
|
if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
|
|
|
|
|
if (option_debug)
|
|
|
|
|
ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in!\n", avl);
|
|
|
|
|
avl = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((idx < avl) && (ch) && (ch != qe)) {
|
|
|
|
|
idx++;
|
|
|
|
|
ch = ch->next;
|
|
|
|
@ -2149,6 +2120,7 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r
|
|
|
|
|
if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000)))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2231,7 +2203,7 @@ static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, st
|
|
|
|
|
static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on, const char *agi)
|
|
|
|
|
{
|
|
|
|
|
struct member *cur;
|
|
|
|
|
struct callattempt *outgoing=NULL; /* the queue we are building */
|
|
|
|
|
struct callattempt *outgoing = NULL; /* the list of calls we are building */
|
|
|
|
|
int to;
|
|
|
|
|
char oldexten[AST_MAX_EXTENSION]="";
|
|
|
|
|
char oldcontext[AST_MAX_CONTEXT]="";
|
|
|
|
@ -2261,7 +2233,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
struct ast_app *mixmonapp = NULL;
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset(&bridge_config, 0, sizeof(bridge_config));
|
|
|
|
|
time(&now);
|
|
|
|
|
|
|
|
|
@ -2310,6 +2281,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
|
|
|
|
|
for (; cur; cur = cur->next) {
|
|
|
|
|
struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
|
|
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
|
ast_mutex_unlock(&qe->parent->lock);
|
|
|
|
|
if (use_weight)
|
|
|
|
@ -2317,13 +2289,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
tmp->stillgoing = -1;
|
|
|
|
|
if (option_debug) {
|
|
|
|
|
if (url)
|
|
|
|
|
ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
|
|
|
|
|
else
|
|
|
|
|
ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmp->member = cur; /* Never directly dereference! Could change on reload */
|
|
|
|
|
tmp->oldstatus = cur->status;
|
|
|
|
|
tmp->lastcall = cur->lastcall;
|
|
|
|
@ -2383,6 +2348,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
outgoing = NULL;
|
|
|
|
|
if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
|
|
|
|
|
int res2;
|
|
|
|
|
|
|
|
|
|
res2 = ast_autoservice_start(qe->chan);
|
|
|
|
|
if (!res2) {
|
|
|
|
|
if (qe->parent->memberdelay) {
|
|
|
|
@ -2514,14 +2480,13 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!monitor_options)
|
|
|
|
|
monitor_options = ast_strdupa("");
|
|
|
|
|
monitor_options = "";
|
|
|
|
|
|
|
|
|
|
if (strchr(monitor_options, '|')) {
|
|
|
|
|
ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
|
|
|
|
|
mixmonapp = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mixmonapp) {
|
|
|
|
|
if (!ast_strlen_zero(monitor_exec) && !ast_strlen_zero(monitor_options))
|
|
|
|
|
snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
|
|
|
|
@ -2576,7 +2541,8 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
|
|
|
|
|
if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
|
|
|
|
|
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s|%ld|%ld",
|
|
|
|
|
qe->chan->exten, qe->chan->context, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
|
|
|
|
|
qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
|
|
|
|
|
(long) (time(NULL) - callstart));
|
|
|
|
|
} else if (qe->chan->_softhangup) {
|
|
|
|
|
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
|
|
|
|
|
(long) (callstart - qe->start), (long) (time(NULL) - callstart));
|
|
|
|
@ -2592,7 +2558,8 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
queuename, qe->chan->uniqueid, peer->name, member->interface,
|
|
|
|
|
(long) (callstart - qe->start), (long) (time(NULL) - callstart));
|
|
|
|
|
} else {
|
|
|
|
|
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
|
|
|
|
|
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld",
|
|
|
|
|
(long) (callstart - qe->start), (long) (time(NULL) - callstart));
|
|
|
|
|
if (qe->parent->eventwhencalled)
|
|
|
|
|
manager_event(EVENT_FLAG_AGENT, "AgentComplete",
|
|
|
|
|
"Queue: %s\r\n"
|
|
|
|
@ -2612,6 +2579,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|
|
|
|
}
|
|
|
|
|
out:
|
|
|
|
|
hangupcalls(outgoing, NULL);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2627,10 +2595,13 @@ static struct member * interface_exists(struct ast_call_queue *q, char *interfac
|
|
|
|
|
{
|
|
|
|
|
struct member *mem;
|
|
|
|
|
|
|
|
|
|
if (q)
|
|
|
|
|
for (mem = q->members; mem; mem = mem->next)
|
|
|
|
|
if (!q)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (mem = q->members; mem; mem = mem->next) {
|
|
|
|
|
if (!strcasecmp(interface, mem->interface))
|
|
|
|
|
return mem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@ -2684,7 +2655,11 @@ static int remove_from_queue(char *queuename, char *interface)
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
if (!strcmp(q->name, queuename)) {
|
|
|
|
|
if (strcmp(q->name, queuename)) {
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((last_member = interface_exists(q, interface))) {
|
|
|
|
|
if ((look = q->members) == last_member) {
|
|
|
|
|
q->members = last_member->next;
|
|
|
|
@ -2714,12 +2689,12 @@ static int remove_from_queue(char *queuename, char *interface)
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
}
|
|
|
|
|
if (res == RES_OKAY) {
|
|
|
|
|
|
|
|
|
|
if (res == RES_OKAY)
|
|
|
|
|
remove_from_interfaces(interface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2732,19 +2707,15 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause
|
|
|
|
|
|
|
|
|
|
/* \note Ensure the appropriate realtime queue is loaded. Note that this
|
|
|
|
|
* short-circuits if the queue is already in memory. */
|
|
|
|
|
q = load_realtime_queue(queuename);
|
|
|
|
|
if (!(q = load_realtime_queue(queuename)))
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
|
|
|
|
|
if (q) {
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
if (interface_exists(q, interface) == NULL) {
|
|
|
|
|
|
|
|
|
|
add_to_interfaces(interface);
|
|
|
|
|
|
|
|
|
|
new_member = create_queue_member(interface, penalty, paused);
|
|
|
|
|
|
|
|
|
|
if (new_member != NULL) {
|
|
|
|
|
if ((new_member = create_queue_member(interface, penalty, paused))) {
|
|
|
|
|
new_member->dynamic = 1;
|
|
|
|
|
new_member->next = q->members;
|
|
|
|
|
q->members = new_member;
|
|
|
|
@ -2758,7 +2729,8 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause
|
|
|
|
|
"Status: %d\r\n"
|
|
|
|
|
"Paused: %d\r\n",
|
|
|
|
|
q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
|
|
|
|
|
new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
|
|
|
|
|
new_member->penalty, new_member->calls, (int) new_member->lastcall,
|
|
|
|
|
new_member->status, new_member->paused);
|
|
|
|
|
|
|
|
|
|
if (dump)
|
|
|
|
|
dump_queue_members(q);
|
|
|
|
@ -2771,8 +2743,8 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause
|
|
|
|
|
res = RES_EXISTS;
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2813,10 +2785,7 @@ static int set_member_paused(char *queuename, char *interface, int paused)
|
|
|
|
|
}
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
|
return RESULT_SUCCESS;
|
|
|
|
|
else
|
|
|
|
|
return RESULT_FAILURE;
|
|
|
|
|
return found ? RESULT_SUCCESS : RESULT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reload dynamic queue members persisted into the astdb */
|
|
|
|
@ -2956,6 +2925,7 @@ static int pqm_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
|
|
|
|
|
LOCAL_USER_REMOVE(lu);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3008,6 +2978,7 @@ static int upqm_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
|
|
|
|
|
LOCAL_USER_REMOVE(lu);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3071,6 +3042,7 @@ static int rqm_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOCAL_USER_REMOVE(lu);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3143,6 +3115,7 @@ static int aqm_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOCAL_USER_REMOVE(lu);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3156,10 +3129,8 @@ static int queue_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
int prio;
|
|
|
|
|
int max_penalty;
|
|
|
|
|
enum queue_result reason = QUEUE_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
/* whether to exit Queue application after the timeout hits */
|
|
|
|
|
int go_on = 0;
|
|
|
|
|
|
|
|
|
|
char *parse;
|
|
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
|
AST_APP_ARG(queuename);
|
|
|
|
@ -3169,7 +3140,6 @@ static int queue_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
AST_APP_ARG(queuetimeoutstr);
|
|
|
|
|
AST_APP_ARG(agi);
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Our queue entry */
|
|
|
|
|
struct queue_ent qe;
|
|
|
|
|
|
|
|
|
@ -3257,7 +3227,8 @@ check_turns:
|
|
|
|
|
if (res < 0) {
|
|
|
|
|
/* Record this abandoned call */
|
|
|
|
|
record_abandoned(&qe);
|
|
|
|
|
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
|
|
|
|
|
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld",
|
|
|
|
|
qe.pos, qe.opos, (long) time(NULL) - qe.start);
|
|
|
|
|
if (option_verbose > 2) {
|
|
|
|
|
ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", args.queuename);
|
|
|
|
|
}
|
|
|
|
@ -3273,6 +3244,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; */
|
|
|
|
@ -3314,10 +3286,13 @@ check_turns:
|
|
|
|
|
if (res < 0) {
|
|
|
|
|
if (!qe.handled) {
|
|
|
|
|
record_abandoned(&qe);
|
|
|
|
|
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
|
|
|
|
|
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
|
|
|
|
|
"%d|%d|%ld", qe.pos, qe.opos,
|
|
|
|
|
(long) time(NULL) - qe.start);
|
|
|
|
|
}
|
|
|
|
|
} else if (valid_exit(&qe, res)) {
|
|
|
|
|
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
|
|
|
|
|
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
|
|
|
|
|
"%s|%d", qe.digits, qe.pos);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -3405,6 +3380,7 @@ check_turns:
|
|
|
|
|
res = 0;
|
|
|
|
|
}
|
|
|
|
|
LOCAL_USER_REMOVE(lu);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3425,15 +3401,12 @@ static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, c
|
|
|
|
|
LOCAL_USER_ADD(lu);
|
|
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
|
|
|
|
|
/* Find the right queue */
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
if (!strcasecmp(q->name, data)) {
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
if (q) {
|
|
|
|
@ -3449,6 +3422,7 @@ static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, c
|
|
|
|
|
|
|
|
|
|
snprintf(buf, len, "%d", count);
|
|
|
|
|
LOCAL_USER_REMOVE(lu);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3468,15 +3442,12 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd,
|
|
|
|
|
LOCAL_USER_ADD(lu);
|
|
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
|
|
|
|
|
/* Find the right queue */
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
if (!strcasecmp(q->name, data)) {
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
if (q) {
|
|
|
|
@ -3507,19 +3478,17 @@ static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, c
|
|
|
|
|
LOCAL_USER_ADD(u);
|
|
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
|
|
|
|
|
/* Find the right queue */
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
if (!strcasecmp(q->name, data)) {
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST_LIST_UNLOCK(&queues);
|
|
|
|
|
|
|
|
|
|
if (q) {
|
|
|
|
|
int buflen = 0, count = 0;
|
|
|
|
|
|
|
|
|
|
for (m = q->members; m; m = m->next) {
|
|
|
|
|
/* strcat() is always faster than printf() */
|
|
|
|
|
if (count++) {
|
|
|
|
@ -3541,6 +3510,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, c
|
|
|
|
|
/* We should already be terminated, but let's make sure. */
|
|
|
|
|
buf[len - 1] = '\0';
|
|
|
|
|
LOCAL_USER_REMOVE(u);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3593,8 +3563,7 @@ static void reload_queues(void)
|
|
|
|
|
char interface[80];
|
|
|
|
|
int penalty;
|
|
|
|
|
|
|
|
|
|
cfg = ast_config_load("queues.conf");
|
|
|
|
|
if (!cfg) {
|
|
|
|
|
if (!(cfg = ast_config_load("queues.conf"))) {
|
|
|
|
|
ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -3602,9 +3571,9 @@ static void reload_queues(void)
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
use_weight=0;
|
|
|
|
|
/* Mark all queues as dead for the moment */
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list)
|
|
|
|
|
q->dead = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Chug through config file */
|
|
|
|
|
cat = NULL;
|
|
|
|
|
while ((cat = ast_category_browse(cfg, cat)) ) {
|
|
|
|
@ -3795,7 +3764,8 @@ static int __queues_show(struct mansession *s, int manager, int fd, int argc, ch
|
|
|
|
|
sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
|
|
|
|
|
if (s)
|
|
|
|
|
astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
|
|
|
|
|
q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
|
|
|
|
|
q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
|
|
|
|
|
q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
|
|
|
|
|
else
|
|
|
|
|
ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
|
|
|
|
|
q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
|
|
|
|
@ -3837,11 +3807,13 @@ static int __queues_show(struct mansession *s, int manager, int fd, int argc, ch
|
|
|
|
|
ast_cli(fd, " Callers: %s", term);
|
|
|
|
|
for (qe = q->head; qe; qe = qe->next) {
|
|
|
|
|
if (s)
|
|
|
|
|
astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
|
|
|
|
|
(long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
|
|
|
|
|
astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
|
|
|
|
|
pos++, qe->chan->name, (long) (now - qe->start) / 60,
|
|
|
|
|
(long) (now - qe->start) % 60, qe->prio, term);
|
|
|
|
|
else
|
|
|
|
|
ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
|
|
|
|
|
(long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
|
|
|
|
|
ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
|
|
|
|
|
qe->chan->name, (long) (now - qe->start) / 60,
|
|
|
|
|
(long) (now - qe->start) % 60, qe->prio, term);
|
|
|
|
|
}
|
|
|
|
|
} else if (s)
|
|
|
|
|
astman_append(s, " No Callers%s", term);
|
|
|
|
@ -3894,6 +3866,7 @@ static char *complete_queue(const char *line, const char *word, int pos, int sta
|
|
|
|
|
static int manager_queues_show( struct mansession *s, struct message *m )
|
|
|
|
|
{
|
|
|
|
|
char *a[] = { "show", "queues" };
|
|
|
|
|
|
|
|
|
|
__queues_show(s, 1, -1, 2, a, 0);
|
|
|
|
|
astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
|
|
|
|
|
|
|
|
|
@ -3917,9 +3890,9 @@ static int manager_queues_status( struct mansession *s, struct message *m )
|
|
|
|
|
astman_send_ack(s, m, "Queue status will follow");
|
|
|
|
|
time(&now);
|
|
|
|
|
AST_LIST_LOCK(&queues);
|
|
|
|
|
if (!ast_strlen_zero(id)) {
|
|
|
|
|
snprintf(idText,256,"ActionID: %s\r\n",id);
|
|
|
|
|
}
|
|
|
|
|
if (!ast_strlen_zero(id))
|
|
|
|
|
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
|
|
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
|
|
|
|
ast_mutex_lock(&q->lock);
|
|
|
|
|
|
|
|
|
@ -4035,6 +4008,7 @@ static int manager_add_queue_member(struct mansession *s, struct message *m)
|
|
|
|
|
astman_send_error(s, m, "Out of memory");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -4064,6 +4038,7 @@ static int manager_remove_queue_member(struct mansession *s, struct message *m)
|
|
|
|
|
astman_send_error(s, m, "Out of memory");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -4223,6 +4198,7 @@ static char *complete_remove_queue_member(const char *line, const char *word, in
|
|
|
|
|
ast_mutex_unlock(&q->lock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -4260,7 +4236,6 @@ static int unload_module(void *mod)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
clear_and_free_interfaces();
|
|
|
|
|
res = ast_cli_unregister(&cli_show_queue);
|
|
|
|
|
res |= ast_cli_unregister(&cli_show_queues);
|
|
|
|
|
res |= ast_cli_unregister(&cli_add_queue_member);
|
|
|
|
@ -4280,6 +4255,8 @@ static int unload_module(void *mod)
|
|
|
|
|
res |= ast_custom_function_unregister(&queuewaitingcount_function);
|
|
|
|
|
res |= ast_unregister_application(app);
|
|
|
|
|
|
|
|
|
|
clear_and_free_interfaces();
|
|
|
|
|
|
|
|
|
|
STANDARD_HANGUP_LOCALUSERS;
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|