Newer
Older
LOCAL_USER_REMOVE(lu);
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
LOCAL_USER_REMOVE(lu);
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
static int rqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct localuser *lu;
char *parse, *temppos = NULL;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
LOCAL_USER_ADD(lu);
if (ast_strlen_zero(args.interface)) {
temppos = strrchr(args.interface, '-');
if (temppos)
*temppos = '\0';
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
switch (remove_from_queue(args.queuename, args.interface)) {
case RES_OKAY:
ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
res = 0;
break;
case RES_EXISTS:
ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
Russell Bryant
committed
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
res = 0;
break;
case RES_NOSUCHQUEUE:
ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
res = 0;
break;
case RES_OUTOFMEMORY:
ast_log(LOG_ERROR, "Out of memory\n");
break;
}
LOCAL_USER_REMOVE(lu);
return res;
}
static int aqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct localuser *lu;
char *parse, *temppos = NULL;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
AST_APP_ARG(penalty);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
LOCAL_USER_ADD(lu);
if (ast_strlen_zero(args.interface)) {
temppos = strrchr(args.interface, '-');
if (temppos)
*temppos = '\0';
}
if (!ast_strlen_zero(args.penalty)) {
if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
penalty = 0;
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
case RES_OKAY:
ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
res = 0;
break;
case RES_EXISTS:
ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
Russell Bryant
committed
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
res = 0;
break;
case RES_NOSUCHQUEUE:
ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
res = 0;
break;
case RES_OUTOFMEMORY:
ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
break;
}
LOCAL_USER_REMOVE(lu);
static int queue_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct localuser *lu;
const char *user_priority;
Kevin P. Fleming
committed
const char *max_penalty_str;
Kevin P. Fleming
committed
int max_penalty;
Mark Spencer
committed
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);
AST_APP_ARG(options);
AST_APP_ARG(url);
AST_APP_ARG(announceoverride);
AST_APP_ARG(queuetimeoutstr);
AST_APP_ARG(agi);
/* Our queue entry */
struct queue_ent qe;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
Russell Bryant
committed
LOCAL_USER_ADD(lu);
/* Setup our queue entry */
memset(&qe, 0, sizeof(qe));
qe.start = time(NULL);
/* set the expire time based on the supplied timeout; */
if (args.queuetimeoutstr)
qe.expire = qe.start + atoi(args.queuetimeoutstr);
else
qe.expire = 0;
/* Get the priority from the variable ${QUEUE_PRIO} */
user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
if (user_priority) {
if (sscanf(user_priority, "%d", &prio) == 1) {
if (option_debug)
ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
Mark Spencer
committed
chan->name, prio);
} else {
ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
Mark Spencer
committed
user_priority, chan->name);
prio = 0;
}
} else {
ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
prio = 0;
Kevin P. Fleming
committed
/* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
if (option_debug)
ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
chan->name, max_penalty);
} else {
ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
max_penalty_str, chan->name);
max_penalty = 0;
}
} else {
max_penalty = 0;
}
if (args.options && (strchr(args.options, 'r')))
Mark Spencer
committed
ringing = 1;
ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
Kevin P. Fleming
committed
qe.prio = prio;
qe.max_penalty = max_penalty;
qe.last_pos_said = 0;
qe.last_pos = 0;
qe.last_periodic_announce_time = time(NULL);
qe.last_periodic_announce_sound = 0;
if (!join_queue(args.queuename, &qe, &reason)) {
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
S_OR(chan->cid.cid_num, ""));
if (ringing) {
ast_indicate(chan, AST_CONTROL_RINGING);
ast_moh_start(chan, qe.moh);
}
/* This is the wait loop for callers 2 through maxlen */
Mark Spencer
committed
res = wait_our_turn(&qe, ringing, &reason);
/* If they hungup, return immediately */
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_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", args.queuename);
if (valid_exit(&qe, res)) {
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
Mark Spencer
committed
int makeannouncement = 0;
/* 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 timeout. */
Mark Spencer
committed
enum queue_member_status stat;
/* Leave if we have exceeded our queuetimeout */
if (qe.expire && (time(NULL) > qe.expire)) {
Mark Spencer
committed
reason = QUEUE_TIMEOUT;
ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
Mark Spencer
committed
if (makeannouncement) {
/* Make a position announcement, if enabled */
if (qe.parent->announcefrequency && !ringing &&
(res = say_position(&qe))) {
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
Kevin P. Fleming
committed
break;
}
Mark Spencer
committed
makeannouncement = 1;
/* Make a periodic announcement, if enabled */
if (qe.parent->periodicannouncefrequency && !ringing &&
(res = say_periodic_announcement(&qe))) {
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
/* Try calling all queue members for 'timeout' seconds */
res = try_calling(&qe, args.options, args.announceoverride, args.url, &go_on, args.agi);
if (res) {
if (res < 0) {
Mark Spencer
committed
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);
Mark Spencer
committed
}
} else if (valid_exit(&qe, res)) {
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
Kevin P. Fleming
committed
stat = get_member_status(qe.parent, qe.max_penalty);
Mark Spencer
committed
Mark Spencer
committed
/* leave the queue if no agents, if enabled */
Mark Spencer
committed
if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
Mark Spencer
committed
record_abandoned(&qe);
Mark Spencer
committed
reason = QUEUE_LEAVEEMPTY;
res = 0;
break;
}
/* leave the queue if no reachable agents, if enabled */
if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
Mark Spencer
committed
record_abandoned(&qe);
Mark Spencer
committed
reason = QUEUE_LEAVEUNAVAIL;
Mark Spencer
committed
res = 0;
break;
}
/* Leave if we have exceeded our queuetimeout */
if (qe.expire && (time(NULL) > qe.expire)) {
Mark Spencer
committed
record_abandoned(&qe);
Mark Spencer
committed
reason = QUEUE_TIMEOUT;
ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
break;
}
/* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
Mark Spencer
committed
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_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", args.queuename);
if (res && valid_exit(&qe, res)) {
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
/* exit after 'timeout' cycle if 'n' option enabled */
ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
Mark Spencer
committed
reason = QUEUE_TIMEOUT;
/* Since this is a priority queue and
* it is not sure that we are still at the head
* of the queue, go and check for our turn again.
*/
if (!is_our_turn(&qe)) {
if (option_debug)
ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
goto check_turns;
}
if (res >= 0 && res != AST_PBX_KEEPALIVE) {
if (ringing) {
ast_indicate(chan, -1);
} else {
ast_moh_stop(chan);
}
Mark Spencer
committed
if (reason != QUEUE_UNKNOWN)
set_queue_result(chan, reason);
ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
Mark Spencer
committed
set_queue_result(chan, reason);
res = 0;
LOCAL_USER_REMOVE(lu);
static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
Kevin P. Fleming
committed
{
int count = 0;
struct ast_call_queue *q;
struct localuser *lu;
Kevin P. Fleming
committed
struct member *m;
Russell Bryant
committed
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
Kevin P. Fleming
committed
}
LOCAL_USER_ADD(lu);
Kevin P. Fleming
committed
/* Find the right queue */
Kevin P. Fleming
committed
if (!strcasecmp(q->name, data)) {
ast_mutex_lock(&q->lock);
break;
}
}
Kevin P. Fleming
committed
if (q) {
for (m = q->members; m; m = m->next) {
/* Count the agents who are logged in and presently answering calls */
if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
count++;
}
}
ast_mutex_unlock(&q->lock);
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
snprintf(buf, len, "%d", count);
LOCAL_USER_REMOVE(lu);
return 0;
}
static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
int count = 0;
struct ast_call_queue *q;
struct localuser *lu;
buf[0] = '\0';
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
return -1;
}
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;
}
Kevin P. Fleming
committed
}
AST_LIST_UNLOCK(&queues);
if (q) {
count = q->count;
ast_mutex_unlock(&q->lock);
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
Kevin P. Fleming
committed
snprintf(buf, len, "%d", count);
LOCAL_USER_REMOVE(lu);
Kevin P. Fleming
committed
}
static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
struct localuser *u;
struct ast_call_queue *q;
struct member *m;
/* Ensure an otherwise empty list doesn't return garbage */
buf[0] = '\0';
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
LOCAL_USER_ADD(u);
/* Find the right queue */
if (!strcasecmp(q->name, data)) {
ast_mutex_lock(&q->lock);
break;
}
}
if (q) {
int buflen = 0, count = 0;
for (m = q->members; m; m = m->next) {
/* strcat() is always faster than printf() */
if (count++) {
strncat(buf + buflen, ",", len - buflen - 1);
buflen++;
}
strncat(buf + buflen, m->interface, len - buflen - 1);
buflen += strlen(m->interface);
/* Safeguard against overflow (negative length) */
if (buflen >= len - 2) {
ast_log(LOG_WARNING, "Truncating list\n");
break;
}
}
ast_mutex_unlock(&q->lock);
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
/* We should already be terminated, but let's make sure. */
buf[len - 1] = '\0';
LOCAL_USER_REMOVE(u);
Kevin P. Fleming
committed
static struct ast_custom_function queueagentcount_function = {
.name = "QUEUEAGENTCOUNT",
.synopsis = "Count number of agents answering a queue",
.syntax = "QUEUEAGENTCOUNT(<queuename>)",
.desc =
"Returns the number of members currently associated with the specified queue.\n"
"This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
Kevin P. Fleming
committed
.read = queue_function_qac,
};
static struct ast_custom_function queuemembercount_function = {
.name = "QUEUE_MEMBER_COUNT",
.synopsis = "Count number of members answering a queue",
.syntax = "QUEUE_MEMBER_COUNT(<queuename>)",
.desc =
"Returns the number of members currently associated with the specified queue.\n",
.read = queue_function_qac,
};
static struct ast_custom_function queuewaitingcount_function = {
.name = "QUEUE_WAITING_COUNT",
.synopsis = "Count number of calls currently waiting in a queue",
.syntax = "QUEUE_WAITING_COUNT(<queuename>)",
.desc =
"Returns the number of callers currently waiting in the specified queue.\n",
.read = queue_function_queuewaitingcount,
};
static struct ast_custom_function queuememberlist_function = {
.name = "QUEUE_MEMBER_LIST",
.synopsis = "Returns a list of interfaces on a queue",
.syntax = "QUEUE_MEMBER_LIST(<queuename>)",
.desc =
"Returns a comma-separated list of members associated with the specified queue.\n",
.read = queue_function_queuememberlist,
};
struct ast_config *cfg;
char *cat, *tmp;
struct ast_variable *var;
struct member *prev, *cur, *newm;
char *general_val = NULL;
char interface[80];
int penalty;
ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
memset(interface, 0, sizeof(interface));
Mark Spencer
committed
q->dead = 1;
cat = NULL;
while ((cat = ast_category_browse(cfg, cat)) ) {
if (!strcasecmp(cat, "general")) {
/* Initialize global settings */
queue_persistent_members = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
queue_persistent_members = ast_true(general_val);
autofill_default = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
autofill_default = ast_true(general_val);
montype_default = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
if (!strcasecmp(general_val, "mixmonitor"))
montype_default = 1;
} else { /* Define queue */
if (!strcmp(q->name, cat))
break;
}
if (!q) {
/* Make one then */
BJ Weschke
committed
if (!(q = alloc_queue(cat))) {
/* TODO: Handle memory allocation failure */
}
new = 1;
new = 0;
if (!new)
ast_mutex_lock(&q->lock);
/* Re-initialize the queue, and clear statistics */
init_queue(q);
clear_queue(q);
for (cur = q->members; cur; cur = cur->next) {
if (!cur->dynamic) {
cur->delme = 1;
}
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
if (!strcasecmp(var->name, "member")) {
/* Add a new member */
ast_copy_string(interface, var->value, sizeof(interface));
if ((tmp = strchr(interface, ','))) {
*tmp = '\0';
tmp++;
penalty = atoi(tmp);
if (penalty < 0) {
penalty = 0;
}
} else
penalty = 0;
/* Find the old position in the list */
for (prev = NULL, cur = q->members; cur; prev = cur, cur = cur->next) {
if (!strcmp(cur->interface, interface)) {
break;
}
}
newm = create_queue_member(interface, penalty, cur ? cur->paused : 0);
if (cur) {
/* Delete it now */
newm->next = cur->next;
if (prev) {
prev->next = newm;
} else {
q->members = newm;
}
free(cur);
} else {
BJ Weschke
committed
/* Add them to the master int list if necessary */
add_to_interfaces(interface);
newm->next = q->members;
q->members = newm;
queue_set_param(q, var->name, var->value, var->lineno, 1);
/* Free remaining members marked as delme */
for (prev = NULL, newm = NULL, cur = q->members; cur; prev = cur, cur = cur->next) {
if (newm) {
free(newm);
newm = NULL;
}
if (cur->delme) {
if (prev) {
prev->next = cur->next;
newm = cur;
} else {
q->members = cur->next;
newm = cur;
}
BJ Weschke
committed
remove_from_interfaces(cur->interface);
Kevin P. Fleming
committed
if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
rr_dep_warning();
AST_LIST_INSERT_HEAD(&queues, q, list);
} else
ast_mutex_unlock(&q->lock);
AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
Mark Spencer
committed
if (q->dead) {
Russell Bryant
committed
if (!q->count)
destroy_queue(q);
else
ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
for (cur = q->members; cur; cur = cur->next)
cur->status = ast_device_state(cur->interface);
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&queues);
static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv, int queue_show)
struct queue_ent *qe;
struct member *mem;
int pos;
time_t now;
char max_buf[80];
char *max;
size_t max_left;
char *term = manager ? "\r\n" : "\n";
if ((!queue_show && argc != 2) || (queue_show && argc != 3))
Tilghman Lesher
committed
/* We only want to load realtime queues when a specific queue is asked for. */
if (queue_show)
load_realtime_queue(argv[2]);
AST_LIST_LOCK(&queues);
if (AST_LIST_EMPTY(&queues)) {
AST_LIST_UNLOCK(&queues);
if (queue_show) {
if (s)
astman_append(s, "No such queue: %s.%s",argv[2], term);
else
ast_cli(fd, "No such queue: %s.%s",argv[2], term);
} else {
if (s)
astman_append(s, "No queues.%s", term);
else
ast_cli(fd, "No queues.%s", term);
}
ast_mutex_lock(&q->lock);
if (queue_show) {
if (strcasecmp(q->name, argv[2]) != 0) {
ast_mutex_unlock(&q->lock);
ast_cli(fd, "No such queue: %s.%s",argv[2], term);
break;
}
continue;
}
}
max_buf[0] = '\0';
max = max_buf;
max_left = sizeof(max_buf);
ast_build_string(&max, &max_left, "%d", q->maxlen);
ast_build_string(&max, &max_left, "unlimited");
sl = 0;
if(q->callscompleted > 0)
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);
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);
if (s)
astman_append(s, " Members: %s", term);
else
ast_cli(fd, " Members: %s", term);
for (mem = q->members; mem; mem = mem->next) {
max_buf[0] = '\0';
max = max_buf;
max_left = sizeof(max_buf);
if (mem->penalty)
ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
ast_build_string(&max, &max_left, " (dynamic)");
ast_build_string(&max, &max_left, " (paused)");
ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
if (mem->calls) {
ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
mem->calls, (long)(time(NULL) - mem->lastcall));
} else
ast_build_string(&max, &max_left, " has taken no calls yet");
if (s)
astman_append(s, " %s%s%s", mem->interface, max_buf, term);
else
ast_cli(fd, " %s%s%s", mem->interface, max_buf, term);
}
} else if (s)
astman_append(s, " No Members%s", term);
else
ast_cli(fd, " No Members%s", term);
if (s)
astman_append(s, " Callers: %s", term);
else
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);
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);
}
} else if (s)
astman_append(s, " No Callers%s", term);
else
ast_cli(fd, " No Callers%s", term);
if (s)
astman_append(s, "%s", term);
else
ast_cli(fd, "%s", term);
ast_mutex_unlock(&q->lock);
static int queues_show(int fd, int argc, char **argv)
{
return __queues_show(NULL, 0, fd, argc, argv, 0);
}
static int queue_show(int fd, int argc, char **argv)
{
return __queues_show(NULL, 0, fd, argc, argv, 1);
Russell Bryant
committed
static char *complete_queue(const char *line, const char *word, int pos, int state)
{
struct ast_call_queue *q;
char *ret = NULL;
int which = 0;
int wordlen = strlen(word);
AST_LIST_LOCK(&queues);
AST_LIST_TRAVERSE(&queues, q, list) {
if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
ret = ast_strdup(q->name);
break;
/*!\brief callback to display queues status in manager
\addtogroup Group_AMI
*/
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 */
Kevin P. Fleming
committed
return RESULT_SUCCESS;
}
/* Dump queue status */
static int manager_queues_status( struct mansession *s, struct message *m )
{
time_t now;
int pos;
char *id = astman_get_header(m,"ActionID");
char *queuefilter = astman_get_header(m,"Queue");
char *memberfilter = astman_get_header(m,"Member");
struct ast_call_queue *q;
struct queue_ent *qe;
float sl = 0;
struct member *mem;
astman_send_ack(s, m, "Queue status will follow");
if (!ast_strlen_zero(id)) {
snprintf(idText,256,"ActionID: %s\r\n",id);
}
ast_mutex_lock(&q->lock);
if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
if(q->callscompleted > 0)
sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
astman_append(s, "Event: QueueParams\r\n"
"Queue: %s\r\n"
"Max: %d\r\n"
"Calls: %d\r\n"
"Holdtime: %d\r\n"
"Completed: %d\r\n"
"Abandoned: %d\r\n"
"ServiceLevel: %d\r\n"
"ServicelevelPerf: %2.1f\r\n"
"Weight: %d\r\n"
"%s"
"\r\n",
q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
q->callsabandoned, q->servicelevel, sl, q->weight, idText);
/* List Queue Members */
for (mem = q->members; mem; mem = mem->next) {
if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
astman_append(s, "Event: QueueMember\r\n"
"Queue: %s\r\n"
"Location: %s\r\n"
"Membership: %s\r\n"
"Penalty: %d\r\n"
"CallsTaken: %d\r\n"
"Status: %d\r\n"
"Paused: %d\r\n"
"%s"
"\r\n",
q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
}
}
/* List Queue Entries */
pos = 1;
for (qe = q->head; qe; qe = qe->next) {
astman_append(s, "Event: QueueEntry\r\n"
"Position: %d\r\n"
"Channel: %s\r\n"
"CallerID: %s\r\n"
"CallerIDName: %s\r\n"
"Wait: %ld\r\n"
"\r\n",
q->name, pos++, qe->chan->name,
S_OR(qe->chan->cid.cid_num, "unknown"),
S_OR(qe->chan->cid.cid_name, "unknown"),
(long)(now - qe->start), idText);
}
}
ast_mutex_unlock(&q->lock);
astman_append(s,
"Event: QueueStatusComplete\r\n"
"%s"
"\r\n",idText);
BJ Weschke
committed
AST_LIST_UNLOCK(&queues);
static int manager_add_queue_member(struct mansession *s, struct message *m)
{
char *queuename, *interface, *penalty_s, *paused_s;
int paused, penalty = 0;
queuename = astman_get_header(m, "Queue");
interface = astman_get_header(m, "Interface");