Newer
Older
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
lu = ast_module_user_add(chan);
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
if (ast_strlen_zero(args.interface)) {
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
ast_module_user_remove(lu);
if (set_member_paused(args.queuename, args.interface, 0)) {
ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
Russell Bryant
committed
if (priority_jump || ast_opt_priority_jumping) {
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
ast_module_user_remove(lu);
ast_module_user_remove(lu);
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
ast_module_user_remove(lu);
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
static int rqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct ast_module_user *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);
lu = ast_module_user_add(chan);
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_DEBUG, "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_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
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;
}
ast_module_user_remove(lu);
return res;
}
static int aqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct ast_module_user *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);
lu = ast_module_user_add(chan);
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);
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;
}
ast_module_user_remove(lu);
static int ql_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(uniqueid);
AST_APP_ARG(peer);
AST_APP_ARG(event);
AST_APP_ARG(params);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|peer|event[|additionalinfo]\n");
return -1;
}
u = ast_module_user_add(chan);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
|| ast_strlen_zero(args.peer) || ast_strlen_zero(args.event)) {
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|peer|event[|additionalinfo])\n");
ast_module_user_remove(u);
return -1;
}
ast_queue_log(args.queuename, args.uniqueid, args.peer, args.event,
"%s", args.params ? args.params : "");
ast_module_user_remove(u);
return 0;
}
static int queue_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct ast_module_user *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
lu = ast_module_user_add(chan);
/* 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, ""),
if (ringing) {
ast_indicate(chan, AST_CONTROL_RINGING);
Kevin P. Fleming
committed
ast_moh_start(chan, qe.moh, NULL);
/* 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",
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 &&
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;
* 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;
ast_module_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_module_user *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
}
lu = ast_module_user_add(chan);
AST_LIST_LOCK(&queues);
AST_LIST_TRAVERSE(&queues, q, list) {
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);
} else
ast_log(LOG_WARNING, "queue %s was not found\n", data);
snprintf(buf, len, "%d", count);
ast_module_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_module_user *lu;
buf[0] = '\0';
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
return -1;
}
lu = ast_module_user_add(chan);
AST_LIST_LOCK(&queues);
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);
ast_module_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 ast_module_user *u;
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");
u = ast_module_user_add(chan);
AST_LIST_LOCK(&queues);
AST_LIST_TRAVERSE(&queues, q, list) {
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';
ast_module_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>)",
"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,
};
static int reload_queues(void)
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;
if (!(cfg = ast_config_load("queues.conf"))) {
ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
return 0;
memset(interface, 0, sizeof(interface));
AST_LIST_TRAVERSE(&queues, q, list)
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);
return 1;
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");
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)",
} 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)
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");
float sl = 0;
struct member *mem;
astman_send_ack(s, m, "Queue status will follow");
if (!ast_strlen_zero(id))
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
ast_mutex_lock(&q->lock);
if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {