Newer
Older
if (ql)
ql->next = q->next;
else
queues = q->next;
if (!q->count) {
free(q);
} else
ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
for (cur = q->members; cur; cur = cur->next)
cur->status = ast_device_state(cur->interface);
ast_mutex_unlock(&qlock);
Mark Spencer
committed
static char *status2str(int status, char *buf, int buflen)
{
switch(status) {
ast_copy_string(buf, "available", buflen);
Mark Spencer
committed
break;
Kevin P. Fleming
committed
ast_copy_string(buf, "notinuse", buflen);
Mark Spencer
committed
break;
Kevin P. Fleming
committed
ast_copy_string(buf, "inuse", buflen);
Kevin P. Fleming
committed
ast_copy_string(buf, "busy", buflen);
Mark Spencer
committed
break;
Kevin P. Fleming
committed
ast_copy_string(buf, "invalid", buflen);
Mark Spencer
committed
break;
Kevin P. Fleming
committed
ast_copy_string(buf, "unavailable", buflen);
Mark Spencer
committed
break;
default:
snprintf(buf, buflen, "unknown status %d", status);
}
return buf;
}
static int __queues_show(int fd, int argc, char **argv, int queue_show)
struct queue_ent *qe;
struct member *mem;
int pos;
time_t now;
char max[80] = "";
char calls[80] = "";
Mark Spencer
committed
char tmpbuf[80] = "";
if ((!queue_show && argc != 2) || (queue_show && argc != 3))
if (queue_show)
ast_cli(fd, "No such queue: %s.\n",argv[2]);
else
ast_cli(fd, "No queues.\n");
ast_mutex_lock(&q->lock);
if (queue_show) {
if (strcasecmp(q->name, argv[2]) != 0) {
ast_mutex_unlock(&q->lock);
if (!q) {
ast_cli(fd, "No such queue: %s.\n",argv[2]);
break;
}
continue;
}
}
if (q->maxlen)
snprintf(max, sizeof(max), "%d", q->maxlen);
else
Kevin P. Fleming
committed
ast_copy_string(max, "unlimited", sizeof(max));
sl = 0;
if(q->callscompleted > 0)
sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
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\n",
q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
if (q->members) {
ast_cli(fd, " Members: \n");
for (mem = q->members; mem; mem = mem->next) {
if (mem->penalty)
snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
else
max[0] = '\0';
strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
if (mem->paused)
strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
if (mem->calls) {
snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
mem->calls, (long)(time(NULL) - mem->lastcall));
} else
Kevin P. Fleming
committed
ast_copy_string(calls, " has taken no calls yet", sizeof(calls));
ast_cli(fd, " %s%s%s\n", mem->interface, max, calls);
}
} else
ast_cli(fd, " No Members\n");
if (q->head) {
pos = 1;
ast_cli(fd, " Callers: \n");
for (qe = q->head; qe; qe = qe->next)
ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)\n", pos++, qe->chan->name,
(long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio);
} else
ast_cli(fd, " No Callers\n");
ast_cli(fd, "\n");
ast_mutex_unlock(&q->lock);
static int queues_show(int fd, int argc, char **argv)
{
return __queues_show(fd, argc, argv, 0);
}
static int queue_show(int fd, int argc, char **argv)
{
return __queues_show(fd, argc, argv, 1);
}
static char *complete_queue(char *line, char *word, int pos, int state)
{
struct ast_call_queue *q;
int which=0;
ast_mutex_lock(&qlock);
for (q = queues; q; q = q->next) {
if (!strncasecmp(word, q->name, strlen(word))) {
if (++which > state)
break;
}
}
ast_mutex_unlock(&qlock);
return q ? strdup(q->name) : NULL;
}
/* JDG: callback to display queues status in manager */
static int manager_queues_show( struct mansession *s, struct message *m )
{
char *a[] = { "show", "queues" };
Kevin P. Fleming
committed
ast_mutex_lock(&s->lock);
queues_show(s->fd, 2, a);
ast_cli(s->fd, "\r\n\r\n"); /* Properly terminate Manager output */
ast_mutex_unlock(&s->lock);
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);
}
for (q = queues; q; q = q->next) {
ast_mutex_lock(&q->lock);
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
if(q->callscompleted > 0)
sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
ast_mutex_lock(&s->lock);
ast_cli(s->fd, "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)) {
ast_cli(s->fd, "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: %ld\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, mem->lastcall, mem->status, mem->paused, idText);
}
}
/* List Queue Entries */
pos = 1;
for (qe = q->head; qe; qe = qe->next) {
ast_cli(s->fd, "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,
qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
(long)(now - qe->start), idText);
}
}
ast_mutex_unlock(&q->lock);
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");
penalty_s = astman_get_header(m, "Penalty");
paused_s = astman_get_header(m, "Paused");
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));
switch (add_to_queue(queuename, interface, penalty, paused, queue_persistent_members)) {
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
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;
}
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;
}
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
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
if (paused)
astman_send_ack(s, m, "Interface paused successfully");
else
astman_send_ack(s, m, "Interface unpaused successfully");
return 0;
}
static int handle_add_queue_member(int fd, int argc, char *argv[])
{
char *queuename, *interface;
int penalty;
if ((argc != 6) && (argc != 8)) {
return RESULT_SHOWUSAGE;
} else if (strcmp(argv[4], "to")) {
return RESULT_SHOWUSAGE;
} else if ((argc == 8) && strcmp(argv[6], "penalty")) {
return RESULT_SHOWUSAGE;
}
queuename = argv[5];
interface = argv[3];
if (argc == 8) {
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;
}
switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
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
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
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_add_queue_member(char *line, char *word, int pos, int state)
{
/* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty> */
switch (pos) {
case 3:
/* Don't attempt to complete name of member (infinite possibilities) */
return NULL;
case 4:
if (state == 0) {
return strdup("to");
} else {
return NULL;
}
case 5:
/* No need to duplicate code */
return complete_queue(line, word, pos, state);
case 6:
if (state == 0) {
return strdup("penalty");
} else {
return NULL;
}
case 7:
if (state < 100) { /* 0-99 */
char *num = malloc(3);
if (num) {
sprintf(num, "%d", state);
}
return num;
} else {
return NULL;
}
default:
return NULL;
}
}
static int handle_remove_queue_member(int fd, int argc, char *argv[])
{
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_remove_queue_member(char *line, char *word, int pos, int state)
{
int which = 0;
struct ast_call_queue *q;
struct member *m;
/* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue> */
if ((pos > 5) || (pos < 3)) {
return NULL;
}
if (pos == 4) {
if (state == 0) {
return strdup("from");
} else {
return NULL;
}
}
if (pos == 5) {
/* No need to duplicate code */
return complete_queue(line, word, pos, state);
}
if (queues != NULL) {
for (q = queues ; q ; q = q->next) {
ast_mutex_lock(&q->lock);
for (m = q->members ; m ; m = m->next) {
if (++which > state) {
ast_mutex_unlock(&q->lock);
return strdup(m->interface);
}
}
ast_mutex_unlock(&q->lock);
}
}
return NULL;
}
static char show_queues_usage[] =
"Usage: show queues\n"
" Provides summary information on call queues.\n";
static struct ast_cli_entry cli_show_queues = {
{ "show", "queues", NULL }, queues_show,
"Show status of queues", show_queues_usage, NULL };
static char show_queue_usage[] =
"Usage: show queue\n"
" Provides summary information on a specified queue.\n";
static struct ast_cli_entry cli_show_queue = {
{ "show", "queue", NULL }, queue_show,
"Show status of a specified queue", show_queue_usage, complete_queue };
static char aqm_cmd_usage[] =
"Usage: add queue member <channel> to <queue> [penalty <penalty>]\n";
static struct ast_cli_entry cli_add_queue_member = {
{ "add", "queue", "member", NULL }, handle_add_queue_member,
"Add a channel to a specified queue", aqm_cmd_usage, complete_add_queue_member };
static char rqm_cmd_usage[] =
"Usage: remove queue member <channel> from <queue>\n";
static struct ast_cli_entry cli_remove_queue_member = {
{ "remove", "queue", "member", NULL }, handle_remove_queue_member,
"Removes a channel from a specified queue", rqm_cmd_usage, complete_remove_queue_member };
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
ast_cli_unregister(&cli_show_queue);
ast_cli_unregister(&cli_add_queue_member);
ast_cli_unregister(&cli_remove_queue_member);
ast_manager_unregister("Queues");
ast_manager_unregister("QueueStatus");
ast_manager_unregister("QueueAdd");
ast_manager_unregister("QueueRemove");
ast_manager_unregister("QueuePause");
ast_unregister_application(app_aqm);
ast_unregister_application(app_rqm);
ast_unregister_application(app_pqm);
ast_unregister_application(app_upqm);
return ast_unregister_application(app);
}
int load_module(void)
{
int res;
res = ast_register_application(app, queue_exec, synopsis, descrip);
ast_cli_register(&cli_show_queue);
ast_cli_register(&cli_add_queue_member);
ast_cli_register(&cli_remove_queue_member);
ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" );
ast_manager_register( "QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue." );
ast_manager_register( "QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue." );
ast_manager_register( "QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable" );
ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip) ;
ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip) ;
if (queue_persistent_members)
reload_queue_members();
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
int reload(void)
{
reload_queues();
return 0;
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}