Added CLI and manager commands for changing a queue member's penalty
(closes issue #9374, reported and initially patched by wuwu, intermediate patch by eliel, and final patch by me) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89068 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
ebf9f0bc0e
commit
01e1f6cc94
267
apps/app_queue.c
267
apps/app_queue.c
|
@ -3421,6 +3421,79 @@ static int set_member_paused(const char *queuename, const char *interface, const
|
|||
return found ? RESULT_SUCCESS : RESULT_FAILURE;
|
||||
}
|
||||
|
||||
/* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
|
||||
static int set_member_penalty(char *queuename, char *interface, int penalty)
|
||||
{
|
||||
int foundinterface = 0, foundqueue = 0;
|
||||
struct call_queue *q;
|
||||
struct member *mem;
|
||||
struct ao2_iterator queue_iter;
|
||||
|
||||
queue_iter = ao2_iterator_init(queues, 0);
|
||||
while ((q = ao2_iterator_next(&queue_iter))) {
|
||||
ao2_lock(q);
|
||||
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
|
||||
foundqueue++;
|
||||
if ((mem = interface_exists(q, interface))) {
|
||||
foundinterface++;
|
||||
mem->penalty = penalty;
|
||||
|
||||
ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
|
||||
manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
|
||||
"Queue: %s\r\n"
|
||||
"Location: %s\r\n"
|
||||
"Penalty: %d\r\n",
|
||||
q->name, mem->interface, penalty);
|
||||
|
||||
}
|
||||
}
|
||||
ao2_unlock(q);
|
||||
queue_unref(q);
|
||||
}
|
||||
|
||||
if (foundinterface) {
|
||||
return RESULT_SUCCESS;
|
||||
} else if (foundqueue) {
|
||||
ast_log (LOG_ERROR, "Invalid queuename\n");
|
||||
} else {
|
||||
ast_log (LOG_ERROR, "Invalid interface\n");
|
||||
}
|
||||
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
|
||||
/* \brief Gets members penalty.
|
||||
*
|
||||
* \return Return the members penalty or RESULT_FAILURE on error. */
|
||||
static int get_member_penalty(char *queuename, char *interface)
|
||||
{
|
||||
int foundqueue = 0, penalty;
|
||||
struct call_queue *q, tmpq;
|
||||
struct member *mem;
|
||||
|
||||
ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
|
||||
if((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
|
||||
foundqueue = 1;
|
||||
ao2_lock(q);
|
||||
if ((mem = interface_exists(q, interface))) {
|
||||
penalty = mem->penalty;
|
||||
ao2_unlock(q);
|
||||
queue_unref(q);
|
||||
return penalty;
|
||||
}
|
||||
ao2_unlock(q);
|
||||
queue_unref(q);
|
||||
}
|
||||
|
||||
/* some useful debuging */
|
||||
if (foundqueue)
|
||||
ast_log (LOG_ERROR, "Invalid queuename\n");
|
||||
else
|
||||
ast_log (LOG_ERROR, "Invalid interface\n");
|
||||
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
|
||||
/* Reload dynamic queue members persisted into the astdb */
|
||||
static void reload_queue_members(void)
|
||||
{
|
||||
|
@ -4197,6 +4270,88 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char *
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Dialplan function QUEUE_MEMBER_PENALTY()
|
||||
* Gets the members penalty. */
|
||||
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) {
|
||||
struct ast_module_user *lu;
|
||||
int penalty;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(queuename);
|
||||
AST_APP_ARG(interface);
|
||||
);
|
||||
/* Make sure the returned value on error is NULL. */
|
||||
buf[0] = '\0';
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lu = ast_module_user_add(chan);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, data);
|
||||
|
||||
if (args.argc < 2) {
|
||||
ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
|
||||
ast_module_user_remove(lu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
penalty = get_member_penalty (args.queuename, args.interface);
|
||||
|
||||
if (penalty >= 0) /* remember that buf is already '\0' */
|
||||
snprintf (buf, len, "%d", penalty);
|
||||
|
||||
ast_module_user_remove(lu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Dialplan function QUEUE_MEMBER_PENALTY()
|
||||
* Sets the members penalty. */
|
||||
static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) {
|
||||
struct ast_module_user *lu;
|
||||
int penalty;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(queuename);
|
||||
AST_APP_ARG(interface);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lu = ast_module_user_add(chan);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, data);
|
||||
|
||||
if (args.argc < 2) {
|
||||
ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
|
||||
ast_module_user_remove(lu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
penalty = atoi(value);
|
||||
if (penalty < 0) {
|
||||
ast_log(LOG_ERROR, "Invalid penalty\n");
|
||||
ast_module_user_remove(lu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.interface)) {
|
||||
ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
|
||||
ast_module_user_remove(lu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if queuename = NULL then penalty will be set for interface in all the queues. */
|
||||
set_member_penalty(args.queuename, args.interface, penalty);
|
||||
|
||||
ast_module_user_remove(lu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function queuevar_function = {
|
||||
.name = "QUEUE_VARIABLES",
|
||||
.synopsis = "Return Queue information in variables",
|
||||
|
@ -4256,6 +4411,17 @@ static struct ast_custom_function queuememberlist_function = {
|
|||
.read = queue_function_queuememberlist,
|
||||
};
|
||||
|
||||
static struct ast_custom_function queuememberpenalty_function = {
|
||||
.name = "QUEUE_MEMBER_PENALTY",
|
||||
.synopsis = "Gets or sets queue members penalty.",
|
||||
.syntax = "QUEUE_MEMBER_PENALTY(<queuename>,<interface>)",
|
||||
.desc =
|
||||
"Gets or sets queue members penalty\n",
|
||||
.read = queue_function_memberpenalty_read,
|
||||
.write = queue_function_memberpenalty_write,
|
||||
};
|
||||
|
||||
|
||||
static int reload_queues(int reload)
|
||||
{
|
||||
struct call_queue *q, tmpq;
|
||||
|
@ -4944,6 +5110,31 @@ static char *complete_queue_add_member(const char *line, const char *word, int p
|
|||
}
|
||||
}
|
||||
|
||||
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
|
||||
{
|
||||
const char *queuename, *interface, *penalty_s;
|
||||
int penalty;
|
||||
|
||||
interface = astman_get_header(m, "Interface");
|
||||
penalty_s = astman_get_header(m, "Penalty");
|
||||
/* Optional - if not supplied, set the penalty value for the given Interface in all queues */
|
||||
queuename = astman_get_header(m, "Queue");
|
||||
|
||||
if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
|
||||
astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
penalty = atoi(penalty_s);
|
||||
|
||||
if (set_member_penalty((char *)queuename, (char *)interface, penalty))
|
||||
astman_send_error(s, m, "Invalid interface or queuename");
|
||||
else
|
||||
astman_send_ack(s, m, "Interface penalty set successfully");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
char *queuename, *interface, *membername = NULL;
|
||||
|
@ -5163,17 +5354,89 @@ static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct
|
|||
}
|
||||
}
|
||||
|
||||
static char *complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
|
||||
{
|
||||
/* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
|
||||
switch (pos) {
|
||||
case 4:
|
||||
if (state == 0) {
|
||||
return ast_strdup("on");
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
case 6:
|
||||
if (state == 0) {
|
||||
return ast_strdup("in");
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
case 7:
|
||||
return complete_queue(line, word, pos, state);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
char *queuename = NULL, *interface;
|
||||
int penalty = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "queue set penalty";
|
||||
e->usage =
|
||||
"Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
|
||||
"Set a member's penalty in the queue specified. If no queue is specified\n"
|
||||
"then that interface's penalty is set in all queues to which that interface is a member\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
|
||||
}
|
||||
|
||||
if (a->argc != 6 && a->argc != 8) {
|
||||
return CLI_SHOWUSAGE;
|
||||
} else if (strcmp(a->argv[5], "from")) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
if(a->argc == 8)
|
||||
queuename = a->argv[7];
|
||||
interface = a->argv[5];
|
||||
penalty = atoi(a->argv[3]);
|
||||
|
||||
if (penalty < 0) {
|
||||
ast_cli(a->fd, "Invalid penalty (%d)\n", penalty);
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
switch (set_member_penalty(queuename, interface, penalty)) {
|
||||
case RESULT_SUCCESS:
|
||||
ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
|
||||
return CLI_SUCCESS;
|
||||
case RESULT_FAILURE:
|
||||
ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
|
||||
return CLI_FAILURE;
|
||||
default:
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
static const char qpm_cmd_usage[] =
|
||||
"Usage: queue pause member <channel> in <queue> reason <reason>\n";
|
||||
|
||||
static const char qum_cmd_usage[] =
|
||||
"Usage: queue unpause member <channel> in <queue> reason <reason>\n";
|
||||
|
||||
static const char qsmp_cmd_usage[] =
|
||||
"Usage: queue set member penalty <channel> from <queue> <penalty>\n";
|
||||
|
||||
static struct ast_cli_entry cli_queue[] = {
|
||||
AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
|
||||
AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
|
||||
AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
|
||||
AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
|
||||
AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
|
@ -5198,6 +5461,7 @@ static int unload_module(void)
|
|||
res |= ast_manager_unregister("QueueRemove");
|
||||
res |= ast_manager_unregister("QueuePause");
|
||||
res |= ast_manager_unregister("QueueLog");
|
||||
res |= ast_manager_unregister("QueuePenalty");
|
||||
res |= ast_unregister_application(app_aqm);
|
||||
res |= ast_unregister_application(app_rqm);
|
||||
res |= ast_unregister_application(app_pqm);
|
||||
|
@ -5209,6 +5473,7 @@ static int unload_module(void)
|
|||
res |= ast_custom_function_unregister(&queuemembercount_dep);
|
||||
res |= ast_custom_function_unregister(&queuememberlist_function);
|
||||
res |= ast_custom_function_unregister(&queuewaitingcount_function);
|
||||
res |= ast_custom_function_unregister(&queuememberpenalty_function);
|
||||
|
||||
if (device_state_sub)
|
||||
ast_event_unsubscribe(device_state_sub);
|
||||
|
@ -5263,11 +5528,13 @@ static int load_module(void)
|
|||
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_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log");
|
||||
res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member");
|
||||
res |= ast_custom_function_register(&queuevar_function);
|
||||
res |= ast_custom_function_register(&queuemembercount_function);
|
||||
res |= ast_custom_function_register(&queuemembercount_dep);
|
||||
res |= ast_custom_function_register(&queuememberlist_function);
|
||||
res |= ast_custom_function_register(&queuewaitingcount_function);
|
||||
res |= ast_custom_function_register(&queuememberpenalty_function);
|
||||
if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END)))
|
||||
res = -1;
|
||||
|
||||
|
|
Loading…
Reference in New Issue