From 01e1f6cc94d0b7faa4eb42ea615458dffe5abea5 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 6 Nov 2007 22:05:56 +0000 Subject: [PATCH] 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 --- apps/app_queue.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/apps/app_queue.c b/apps/app_queue.c index 92374f8766..2082e4ed42 100644 --- a/apps/app_queue.c +++ b/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(,)\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(,)\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(,)\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(,)\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, " 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(,)", + .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 - ; 4 - on; 5 - ; 6 - in; 7 - ;*/ + 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 on [in ]\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 in reason \n"; static const char qum_cmd_usage[] = "Usage: queue unpause member in reason \n"; +static const char qsmp_cmd_usage[] = +"Usage: queue set member penalty from \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;