Newer
Older
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);
LOCAL_USER_ADD(lu);
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");
LOCAL_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");
LOCAL_USER_REMOVE(lu);
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_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;
}
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);
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);
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
static int ql_exec(struct ast_channel *chan, void *data)
{
struct localuser *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;
}
LOCAL_USER_ADD(u);
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");
LOCAL_USER_REMOVE(u);
return -1;
}
ast_queue_log(args.queuename, args.uniqueid, args.peer, args.event,
"%s", args.params ? args.params : "");
LOCAL_USER_REMOVE(u);
return 0;
}
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, ""),
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;
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 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);
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);
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 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);
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 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);
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';
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>)",
"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;
if (!(cfg = ast_config_load("queues.conf"))) {
ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
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);
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)) {
if (q->callscompleted > 0)
sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
astman_append(s, "Event: QueueParams\r\n"