Newer
Older
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[] = { "queue", "list" };
__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;
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
/* Dump summary of queue info */
static int manager_queues_summary(struct mansession *s, struct message *m)
{
time_t now;
int qmemcount = 0;
int qmemavail = 0;
int qchancount = 0;
char *id = astman_get_header(m, "ActionID");
char *queuefilter = astman_get_header(m, "Queue");
char idText[256] = "";
struct call_queue *q;
struct queue_ent *qe;
struct member *mem;
astman_send_ack(s, m, "Queue summary will follow");
time(&now);
AST_LIST_LOCK(&queues);
if (!ast_strlen_zero(id))
snprintf(idText, 256, "ActionID: %s\r\n", id);
AST_LIST_TRAVERSE(&queues, q, list) {
ast_mutex_lock(&q->lock);
/* List queue properties */
if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
/* List Queue Members */
for (mem = q->members; mem; mem = mem->next) {
if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
++qmemcount;
if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
++qmemavail;
}
}
}
for (qe = q->head; qe; qe = qe->next) {
++qchancount;
}
astman_append(s, "Event: QueueSummary\r\n"
"Queue: %s\r\n"
"LoggedIn: %d\r\n"
"Available: %d\r\n"
"Callers: %d\r\n"
"HoldTime: %d\r\n"
"%s"
"\r\n",
q->name, qmemcount, qmemavail, qchancount, q->holdtime, idText);
}
ast_mutex_unlock(&q->lock);
}
astman_append(s,
"Event: QueueSummaryComplete\r\n"
"%s"
"\r\n", idText);
AST_LIST_UNLOCK(&queues);
return RESULT_SUCCESS;
}
static int manager_queues_status(struct mansession *s, struct message *m)
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"
"Strategy: %s\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",
Joshua Colp
committed
q->name, q->maxlen, int2strat(q->strategy), 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"
"LastCall: %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"
"Queue: %s\r\n"
"Position: %d\r\n"
"Channel: %s\r\n"
Joshua Colp
committed
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"Wait: %ld\r\n"
"%s"
"\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, *membername;
queuename = astman_get_header(m, "Queue");
interface = astman_get_header(m, "Interface");
penalty_s = astman_get_header(m, "Penalty");
paused_s = astman_get_header(m, "Paused");
membername = astman_get_header(m, "MemberName");
if (ast_strlen_zero(queuename)) {
astman_send_error(s, m, "'Queue' not specified.");
return 0;
}
if (ast_strlen_zero(interface)) {
astman_send_error(s, m, "'Interface' not specified.");
return 0;
}
if (ast_strlen_zero(penalty_s))
penalty = 0;
else if (sscanf(penalty_s, "%d", &penalty) != 1)
penalty = 0;
if (ast_strlen_zero(paused_s))
paused = 0;
else
paused = abs(ast_true(paused_s));
if (ast_strlen_zero(membername))
membername = interface;
switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
case RES_OKAY:
astman_send_ack(s, m, "Added interface to queue");
break;
case RES_EXISTS:
astman_send_error(s, m, "Unable to add interface: Already there");
break;
case RES_NOSUCHQUEUE:
astman_send_error(s, m, "Unable to add interface to queue: No such queue");
break;
case RES_OUTOFMEMORY:
astman_send_error(s, m, "Out of memory");
break;
}
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
return 0;
}
static int manager_remove_queue_member(struct mansession *s, struct message *m)
{
char *queuename, *interface;
queuename = astman_get_header(m, "Queue");
interface = astman_get_header(m, "Interface");
if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
return 0;
}
switch (remove_from_queue(queuename, interface)) {
case RES_OKAY:
astman_send_ack(s, m, "Removed interface from queue");
break;
case RES_EXISTS:
astman_send_error(s, m, "Unable to remove interface: Not there");
break;
case RES_NOSUCHQUEUE:
astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
break;
case RES_OUTOFMEMORY:
astman_send_error(s, m, "Out of memory");
break;
}
return 0;
}
static int manager_pause_queue_member(struct mansession *s, struct message *m)
{
char *queuename, *interface, *paused_s;
int paused;
interface = astman_get_header(m, "Interface");
paused_s = astman_get_header(m, "Paused");
queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
return 0;
}
paused = abs(ast_true(paused_s));
if (set_member_paused(queuename, interface, paused))
astman_send_error(s, m, "Interface not found");
else
astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
static int handle_queue_add_member(int fd, int argc, char *argv[])
char *queuename, *interface, *membername;
int penalty;
if ((argc != 6) && (argc != 8) && (argc != 10)) {
return RESULT_SHOWUSAGE;
} else if (strcmp(argv[4], "to")) {
return RESULT_SHOWUSAGE;
} else if ((argc == 8) && strcmp(argv[6], "penalty")) {
return RESULT_SHOWUSAGE;
} else if ((argc == 10) && strcmp(argv[8], "as")) {
return RESULT_SHOWUSAGE;
}
queuename = argv[5];
interface = argv[3];
if (sscanf(argv[7], "%d", &penalty) == 1) {
if (penalty < 0) {
ast_cli(fd, "Penalty must be >= 0\n");
penalty = 0;
}
} else {
ast_cli(fd, "Penalty must be an integer >= 0\n");
penalty = 0;
}
} else {
penalty = 0;
}
if (argc >= 10) {
membername = argv[9];
} else {
membername = interface;
}
switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
case RES_OKAY:
ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
return RESULT_SUCCESS;
case RES_EXISTS:
ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
return RESULT_FAILURE;
case RES_NOSUCHQUEUE:
ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
return RESULT_FAILURE;
case RES_OUTOFMEMORY:
ast_cli(fd, "Out of memory\n");
return RESULT_FAILURE;
default:
return RESULT_FAILURE;
}
}
static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
/* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
switch (pos) {
case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
return NULL;
case 4: /* only one possible match, "to" */
return state == 0 ? ast_strdup("to") : NULL;
case 5: /* <queue> */
return complete_queue(line, word, pos, state);
case 6: /* only one possible match, "penalty" */
return state == 0 ? ast_strdup("penalty") : NULL;
case 7:
if (state < 100) { /* 0-99 */
BJ Weschke
committed
char *num;
if ((num = ast_malloc(3))) {
sprintf(num, "%d", state);
}
return num;
} else {
return NULL;
}
case 8: /* only one possible match, "as" */
return state == 0 ? ast_strdup("as") : NULL;
case 9: /* Don't attempt to complete name of member (infinite possibilities) */
return NULL;
default:
return NULL;
}
}
static int handle_queue_remove_member(int fd, int argc, char *argv[])
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
{
char *queuename, *interface;
if (argc != 6) {
return RESULT_SHOWUSAGE;
} else if (strcmp(argv[4], "from")) {
return RESULT_SHOWUSAGE;
}
queuename = argv[5];
interface = argv[3];
switch (remove_from_queue(queuename, interface)) {
case RES_OKAY:
ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
return RESULT_SUCCESS;
case RES_EXISTS:
ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
return RESULT_FAILURE;
case RES_NOSUCHQUEUE:
ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
return RESULT_FAILURE;
case RES_OUTOFMEMORY:
ast_cli(fd, "Out of memory\n");
return RESULT_FAILURE;
default:
return RESULT_FAILURE;
}
}
static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
{
int which = 0;
struct member *m;
/* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
if (pos > 5 || pos < 3)
return NULL;
if (pos == 4) /* only one possible match, 'from' */
return state == 0 ? ast_strdup("from") : NULL;
if (pos == 5) /* No need to duplicate code */
return complete_queue(line, word, pos, state);
/* here is the case for 3, <member> */
if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
ast_mutex_lock(&q->lock);
for (m = q->members ; m ; m = m->next) {
if (++which > state) {
ast_mutex_unlock(&q->lock);
}
}
ast_mutex_unlock(&q->lock);
}
}
return NULL;
}
static char queue_list_usage[] =
"Usage: queue list\n"
" Provides summary information on call queues.\n";
static char queue_show_usage[] =
"Usage: queue show\n"
" Provides summary information on a specified queue.\n";
static char qam_cmd_usage[] =
"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
static char qrm_cmd_usage[] =
"Usage: queue remove member <channel> from <queue>\n";
static struct ast_cli_entry cli_queue[] = {
{ { "queue", "list", NULL },
queue_list, "Show status of queues",
queue_list_usage, NULL, NULL },
{ { "queue", "show", NULL },
queue_show, "Show status of a specified queue",
queue_show_usage, complete_queue, NULL },
{ { "queue", "add", "member", NULL },
handle_queue_add_member, "Add a channel to a specified queue",
qam_cmd_usage, complete_queue_add_member, NULL },
{ { "queue", "remove", "member", NULL },
handle_queue_remove_member, "Removes a channel from a specified queue",
qrm_cmd_usage, complete_queue_remove_member, NULL },
static int unload_module(void)
Russell Bryant
committed
int res;
ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
res = ast_manager_unregister("QueueStatus");
Russell Bryant
committed
res |= ast_manager_unregister("Queues");
res |= ast_manager_unregister("QueueStatus");
res |= ast_manager_unregister("QueueSummary");
Russell Bryant
committed
res |= ast_manager_unregister("QueueAdd");
res |= ast_manager_unregister("QueueRemove");
res |= ast_manager_unregister("QueuePause");
res |= ast_unregister_application(app_aqm);
res |= ast_unregister_application(app_rqm);
res |= ast_unregister_application(app_pqm);
res |= ast_unregister_application(app_upqm);
res |= ast_unregister_application(app_ql);
res |= ast_unregister_application(app);
res |= ast_custom_function_unregister(&queuemembercount_function);
res |= ast_custom_function_unregister(&queuememberlist_function);
res |= ast_custom_function_unregister(&queuewaitingcount_function);
Russell Bryant
committed
ast_module_user_hangup_all();
clear_and_free_interfaces();
Russell Bryant
committed
return res;
static int load_module(void)
if(!reload_queues())
return AST_MODULE_LOAD_DECLINE;
if (queue_persistent_members)
reload_queue_members();
ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
res = ast_register_application(app, queue_exec, synopsis, descrip);
res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary");
res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
res |= ast_custom_function_register(&queuemembercount_function);
res |= ast_custom_function_register(&queuememberlist_function);
res |= ast_custom_function_register(&queuewaitingcount_function);
BJ Weschke
committed
res |= ast_devstate_add(statechange_queue, NULL);
Russell Bryant
committed
static int reload(void)
{
reload_queues();
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
.load = load_module,
.unload = unload_module,
.reload = reload,
);