diff --git a/CHANGES b/CHANGES index 23f8f7c0797194f54eb8976f6edc7435324c2b76..52906fcd0b44812c5101600525d24ccc62f42e01 100644 --- a/CHANGES +++ b/CHANGES @@ -125,6 +125,14 @@ Queue changes ------------- * Added queue options autopausebusy and autopauseunavail for automatically pausing a queue member when their device reports busy or congestion. + * The 'ignorebusy' option for queue members has been deprecated in favor of + the option 'ringinuse. Also a 'queue set ringinuse' CLI command has been + added as well as an AMI action 'QueueMemberRingInUse' to set this variable on a + per interface basis. Individual ringinuse values can now be set in + queues.conf via an argument to member definitions. Lastly, the queue + 'ringinuse' setting now only determines defaults for the per member + 'ringinuse' setting and does not override per member settings like it does + in earlier versions. Voicemail changes ----------------- diff --git a/apps/app_queue.c b/apps/app_queue.c index a566c9aed6f9a2ce7b5e0d6b14cef780fe0fdbf7..ae82bd9367ac5b81946a2c42f9c891b531e778e4 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -552,8 +552,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <enum name="paused"> <para>Gets or sets queue member paused status.</para> </enum> - <enum name="ignorebusy"> - <para>Gets or sets queue member ignorebusy.</para> + <enum name="ringinuse"> + <para>Gets or sets queue member ringinuse.</para> </enum> </enumlist> </parameter> @@ -817,6 +817,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <description> </description> </manager> + + <manager name="QueueMemberRingInUse" language="en_US"> + <synopsis> + Set the ringinuse value for a queue member. + </synopsis> + <syntax> + <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" /> + <parameter name="Interface" required="true" /> + <parameter name="RingInUse" required="true" /> + <parameter name="Queue" /> + </syntax> + <description> + </description> + </manager> + <manager name="QueueRule" language="en_US"> <synopsis> Queue Rules. @@ -1032,6 +1047,9 @@ static int log_membername_as_agent = 0; /*! \brief queues.conf [general] option */ static int check_state_unknown = 0; +/*! \brief name of the ringinuse field in the realtime database */ +static char *realtime_ringinuse_field; + enum queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, @@ -1141,7 +1159,7 @@ struct member { unsigned int dead:1; /*!< Used to detect members deleted in realtime */ unsigned int delme:1; /*!< Flag to delete entry on reload */ char rt_uniqueid[80]; /*!< Unique id of realtime member entry */ - unsigned int ignorebusy:1; /*!< Flag to ignore member if the status is not available */ + unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */ }; enum empty_conditions { @@ -1155,6 +1173,11 @@ enum empty_conditions { QUEUE_EMPTY_WRAPUP = (1 << 7), }; +enum member_properties { + MEMBER_PENALTY = 0, + MEMBER_RINGINUSE = 1, +}; + /* values used in multi-bit flags in call_queue */ #define ANNOUNCEHOLDTIME_ALWAYS 1 #define ANNOUNCEHOLDTIME_ONCE 2 @@ -1721,12 +1744,12 @@ static int get_queue_member_status(struct member *cur) } /*! \brief allocate space for new queue member and set fields based on parameters passed */ -static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface) +static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse) { struct member *cur; if ((cur = ao2_alloc(sizeof(*cur), NULL))) { - cur->ignorebusy = 1; + cur->ringinuse = ringinuse; cur->penalty = penalty; cur->paused = paused; ast_copy_string(cur->interface, interface, sizeof(cur->interface)); @@ -2252,7 +2275,7 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc int penalty = 0; int paused = 0; int found = 0; - int ignorebusy = 0; + int ringinuse = q->ringinuse; const char *config_val; const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid"); @@ -2282,10 +2305,14 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc } } - if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy"))) { - ignorebusy = ast_true(config_val); - } else { - ignorebusy = 1; + if ((config_val = ast_variable_retrieve(member_config, interface, realtime_ringinuse_field))) { + if (ast_true(config_val)) { + ringinuse = 1; + } else if (ast_false(config_val)) { + ringinuse = 0; + } else { + ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name); + } } /* Find member by realtime uniqueid and update */ @@ -2301,7 +2328,7 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); } m->penalty = penalty; - m->ignorebusy = ignorebusy; + m->ringinuse = ringinuse; found = 1; ao2_ref(m, -1); break; @@ -2312,10 +2339,9 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc /* Create a new member */ if (!found) { - if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { + if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse))) { m->dead = 0; m->realtime = 1; - m->ignorebusy = ignorebusy; ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); if (!log_membername_as_agent) { ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); @@ -3104,7 +3130,7 @@ static int num_available_members(struct call_queue *q) case AST_DEVICE_RINGING: case AST_DEVICE_RINGINUSE: case AST_DEVICE_ONHOLD: - if ((!q->ringinuse) || (!mem->ignorebusy)) { + if (!mem->ringinuse) { break; } /* else fall through */ @@ -3265,7 +3291,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies return 0; } - if (!qe->parent->ringinuse || !tmp->member->ignorebusy) { + if (tmp->member->ringinuse) { if (check_state_unknown && (tmp->member->status == AST_DEVICE_UNKNOWN)) { newstate = ast_device_state(tmp->member->interface); if (newstate != tmp->member->status) { @@ -5560,7 +5586,8 @@ static int add_to_queue(const char *queuename, const char *interface, const char ao2_lock(q); if ((old_member = interface_exists(q, interface)) == NULL) { - if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { + if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) { + new_member->ringinuse = q->ringinuse; new_member->dynamic = 1; ao2_link(q->members, new_member); manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", @@ -5714,23 +5741,71 @@ static int set_member_penalty_help_members(struct call_queue *q, const char *int return foundinterface; } +static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse) +{ + struct member *mem; + int foundinterface = 0; + char rtringinuse[80]; + + ao2_lock(q); + if ((mem = interface_exists(q, interface))) { + foundinterface++; + if (!mem->realtime) { + mem->ringinuse = ringinuse; + } else { + sprintf(rtringinuse, "%i", ringinuse); + update_realtime_member_field(mem, q->name, realtime_ringinuse_field, rtringinuse); + } + ast_queue_log(q->name, "NONE", interface, "RINGINUSE", "%d", ringinuse); + manager_event(EVENT_FLAG_AGENT, "QueueMemberRinginuse", + "Queue: %s\r\n" + "Location: %s\r\n" + "Ringinuse: %d\r\n", + q->name, mem->interface, ringinuse); + ao2_ref(mem, -1); + } + ao2_unlock(q); + + return foundinterface; +} + +static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value) +{ + switch(property) { + case MEMBER_PENALTY: + return set_member_penalty_help_members(q, interface, value); + + case MEMBER_RINGINUSE: + return set_member_ringinuse_help_members(q, interface, value); + + default: + ast_log(LOG_ERROR, "Attempted to set invalid property\n"); + return 0; + } +} + /*! * \internal * \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. - * \param[in] queuename If specified, only act on a member if it belongs to this queue + * \param[in] queuename If specified, only act on a mem`ber if it belongs to this queue * \param[in] interface Interface of queue member(s) having priority set. + * \param[in] property Which queue property is being set * \param[in] penalty Value penalty is being changed to for each member */ -static int set_member_penalty(const char *queuename, const char *interface, int penalty) +static int set_member_value(const char *queuename, const char *interface, int property, int value) { int foundinterface = 0, foundqueue = 0; struct call_queue *q; struct ast_config *queue_config = NULL; struct ao2_iterator queue_iter; - if (penalty < 0 && !negative_penalty_invalid) { - ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); - return RESULT_FAILURE; + /* property dependent restrictions on values should be checked in this switch */ + switch (property) { + case MEMBER_PENALTY: + if (value < 0 && !negative_penalty_invalid) { + ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value); + return RESULT_FAILURE; + } } if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */ @@ -5743,7 +5818,7 @@ static int set_member_penalty(const char *queuename, const char *interface, int name = ast_category_browse(queue_config, name)) { if ((q = find_load_queue_rt_friendly(name))) { foundqueue++; - foundinterface += set_member_penalty_help_members(q, interface, penalty); + foundinterface += set_member_value_help_members(q, interface, property, value); } } } @@ -5753,13 +5828,13 @@ static int set_member_penalty(const char *queuename, const char *interface, int queue_iter = ao2_iterator_init(queues, 0); while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { foundqueue++; - foundinterface += set_member_penalty_help_members(q, interface, penalty); + foundinterface += set_member_value_help_members(q, interface, property, value); } ao2_iterator_destroy(&queue_iter); } else { /* We actually have a queuename, so we can just act on the single queue. */ if ((q = find_load_queue_rt_friendly(queuename))) { foundqueue++; - foundinterface += set_member_penalty_help_members(q, interface, penalty); + foundinterface += set_member_value_help_members(q, interface, property, value); } } @@ -6569,8 +6644,8 @@ static int queue_function_exists(struct ast_channel *chan, const char *cmd, char /*! * \brief Get number either busy / free / ready or total members of a specific queue - * \brief Get or set member properties penalty / paused / ignorebusy - * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy) + * \brief Get or set member properties penalty / paused / ringinuse + * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ringinuse) * \retval -1 on error */ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) @@ -6645,13 +6720,14 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch ((m = interface_exists(q, args.interface)))) { count = m->paused; ao2_ref(m, -1); - } else if (!strcasecmp(args.option, "ignorebusy") && !ast_strlen_zero(args.interface) && + } else if ( (!strcasecmp(args.option, "ignorebusy") || !strcasecmp(args.option, "ringinuse")) && + !ast_strlen_zero(args.interface) && ((m = interface_exists(q, args.interface)))) { - count = m->ignorebusy; + count = m->ringinuse; ao2_ref(m, -1); } else { ast_log(LOG_ERROR, "Unknown option %s provided to %s, valid values are: " - "logged, free, ready, count, penalty, paused, ignorebusy\n", args.option, cmd); + "logged, free, ready, count, penalty, paused, ringinuse\n", args.option, cmd); } ao2_unlock(q); queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); @@ -6664,7 +6740,7 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch return 0; } -/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy. */ +/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. */ static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { int memvalue; @@ -6696,10 +6772,9 @@ static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, c } memvalue = atoi(value); - if (!strcasecmp(args.option, "penalty")) { /* if queuename = NULL then penalty will be set for interface in all the queues.*/ - if (set_member_penalty(args.queuename, args.interface, memvalue)) { + if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) { ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); return -1; } @@ -6713,14 +6788,14 @@ static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, c } else { m->paused = (memvalue <= 0) ? 0 : 1; } - } else if (!strcasecmp(args.option, "ignorebusy")) { + } else if ((!strcasecmp(args.option, "ignorebusy")) || (!strcasecmp(args.option, "ringinuse"))) { if (m->realtime) { update_realtime_member_field(m, q->name, args.option, rtvalue); } else { - m->ignorebusy = (memvalue <= 0) ? 0 : 1; + m->ringinuse = (memvalue <= 0) ? 0 : 1; } } else { - ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ignorebusy are valid\n"); + ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ringinuse/ignorebusy are valid\n"); ao2_ref(m, -1); ao2_unlock(q); ao2_ref(q, -1); @@ -6935,7 +7010,7 @@ static int queue_function_memberpenalty_write(struct ast_channel *chan, const ch } /* if queuename = NULL then penalty will be set for interface in all the queues. */ - if (set_member_penalty(args.queuename, args.interface, penalty)) { + if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) { ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); return -1; } @@ -7088,11 +7163,13 @@ static void reload_single_member(const char *memberdata, struct call_queue *q) struct member *cur, *newm; struct member tmpmem; int penalty; + int ringinuse; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(interface); AST_APP_ARG(penalty); AST_APP_ARG(membername); AST_APP_ARG(state_interface); + AST_APP_ARG(ringinuse); ); if (ast_strlen_zero(memberdata)) { @@ -7102,7 +7179,7 @@ static void reload_single_member(const char *memberdata, struct call_queue *q) /* Add a new member */ parse = ast_strdupa(memberdata); - + AST_STANDARD_APP_ARGS(args, parse); interface = args.interface; @@ -7131,10 +7208,26 @@ static void reload_single_member(const char *memberdata, struct call_queue *q) state_interface = interface; } + if (!ast_strlen_zero(args.ringinuse)) { + tmp = args.ringinuse; + ast_strip(tmp); + if (ast_true(tmp)) { + ringinuse = 1; + } else if (ast_false(tmp)) { + ringinuse = 0; + } else { + ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n", + membername, q->name); + ringinuse = q->ringinuse; + } + } else { + ringinuse = q->ringinuse; + } + /* Find the old position in the list */ ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); - if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { + if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse))) { ao2_link(q->members, newm); ao2_ref(newm, -1); } @@ -7242,13 +7335,21 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, if (member_reload) { ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); } + + /* On the first pass we just read the parameters of the queue */ + for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { + if (queue_reload && strcasecmp(var->name, "member")) { + queue_set_param(q, var->name, var->value, var->lineno, 1); + } + } + + /* On the second pass, we read members */ for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { if (member_reload && !strcasecmp(var->name, "member")) { reload_single_member(var->value, q); - } else if (queue_reload) { - queue_set_param(q, var->name, var->value, var->lineno, 1); } } + /* At this point, we've determined if the queue has a weight, so update use_weight * as appropriate */ @@ -7521,6 +7622,9 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char * if (mem->penalty) { ast_str_append(&out, 0, " with penalty %d", mem->penalty); } + + ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled"); + ast_str_append(&out, 0, "%s%s%s (%s)", mem->dynamic ? " (dynamic)" : "", mem->realtime ? " (realtime)" : "", @@ -8070,6 +8174,40 @@ static char *complete_queue_add_member(const char *line, const char *word, int p } } +static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m) +{ + const char *queuename, *interface, *ringinuse_s; + int ringinuse; + + interface = astman_get_header(m, "Interface"); + ringinuse_s = astman_get_header(m, "RingInUse"); + + /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */ + queuename = astman_get_header(m, "Queue"); + + if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) { + astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters."); + return 0; + } + + if (ast_true(ringinuse_s)) { + ringinuse = 1; + } else if (ast_false(ringinuse_s)) { + ringinuse = 0; + } else { + astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)"); + return 0; + } + + if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) { + astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n"); + } else { + astman_send_ack(s, m, "Interface ringinuse set successfully"); + } + + return 0; +} + static int manager_queue_member_penalty(struct mansession *s, const struct message *m) { const char *queuename, *interface, *penalty_s; @@ -8087,7 +8225,7 @@ static int manager_queue_member_penalty(struct mansession *s, const struct messa penalty = atoi(penalty_s); - if (set_member_penalty((char *)queuename, (char *)interface, penalty)) { + if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) { astman_send_error(s, m, "Invalid interface, queuename or penalty"); } else { astman_send_ack(s, m, "Interface penalty set successfully"); @@ -8353,9 +8491,9 @@ 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) +static char *complete_queue_set_member_value(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>;*/ + /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ switch (pos) { case 4: if (state == 0) { @@ -8375,7 +8513,64 @@ static char *complete_queue_set_member_penalty(const char *line, const char *wor return NULL; } } - + +static char *handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + const char *queuename = NULL, *interface; + int ringinuse; + + switch (cmd) { + case CLI_INIT: + e->command = "queue set ringinuse"; + e->usage = + "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n" + " Set a member's ringinuse 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"; + break; + return NULL; + case CLI_GENERATE: + return complete_queue_set_member_value(a->line, a->word, a->pos, a->n); + } + + /* Sensible argument counts */ + if (a->argc != 6 && a->argc != 8) { + return CLI_SHOWUSAGE; + } + + /* Uses proper indicational words */ + if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { + return CLI_SHOWUSAGE; + } + + /* Set the queue name if applicale */ + if (a->argc == 8) { + queuename = a->argv[7]; + } + + /* Interface being set */ + interface = a->argv[5]; + + /* Check and set the ringinuse value */ + if (ast_true(a->argv[3])) { + ringinuse = 1; + } else if (ast_false(a->argv[3])) { + ringinuse = 0; + } else { + return CLI_SHOWUSAGE; + } + + switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) { + case RESULT_SUCCESS: + ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename); + return CLI_SUCCESS; + case RESULT_FAILURE: + ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename); + return CLI_FAILURE; + default: + return CLI_FAILURE; + } +} + static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { const char *queuename = NULL, *interface; @@ -8390,7 +8585,7 @@ static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, s " 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); + return complete_queue_set_member_value(a->line, a->word, a->pos, a->n); } if (a->argc != 6 && a->argc != 8) { @@ -8405,7 +8600,7 @@ static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, s interface = a->argv[5]; penalty = atoi(a->argv[3]); - switch (set_member_penalty(queuename, interface, penalty)) { + switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) { case RESULT_SUCCESS: ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); return CLI_SUCCESS; @@ -8586,6 +8781,7 @@ static struct ast_cli_entry cli_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"), + AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"), AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"), AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"), AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"), @@ -8914,6 +9110,7 @@ static int load_module(void) { int res; struct ast_flags mask = {AST_FLAGS_ALL, }; + struct ast_config *member_config; queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); @@ -8942,6 +9139,7 @@ static int load_module(void) res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); + res |= ast_manager_register_xml("QueueMemberRingInUse", EVENT_FLAG_AGENT, manager_queue_member_ringinuse); res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); @@ -8966,6 +9164,29 @@ static int load_module(void) ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); + /* + * This section is used to determine which name for 'ringinuse' to use in realtime members + * Necessary for supporting older setups. + */ + member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL); + if (!member_config) { + realtime_ringinuse_field = "ringinuse"; + } else { + const char *config_val; + if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) { + ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n"); + realtime_ringinuse_field = "ringinuse"; + } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) { + ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n"); + realtime_ringinuse_field = "ignorebusy"; + } else { + ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n"); + realtime_ringinuse_field = "ringinuse"; + } + } + + ast_config_destroy(member_config); + return res ? AST_MODULE_LOAD_DECLINE : 0; } diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index 051a09fbea43b853442814d1681e246cdce14c45..e73dab200fb42e662e286dfeb35e76d106559488 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -73,8 +73,8 @@ monitor-type = MixMonitor ; ; app_queue allows calls to members in a "Unknown" state to be treated as available ; setting check_state_unknown = yes will cause app_queue to query the channel driver -; to better determine the state this only applies to queues with ringinuse or ignorebusy -; set appropriately. +; to better determine the state this only applies to queues with ringinuse set +; appropriately. ; ;check_state_unknown = no ; @@ -504,10 +504,11 @@ monitor-type = MixMonitor ; If you want the queue to avoid sending calls to members whose devices are ; known to be 'in use' (via the channel driver supporting that device state) ; uncomment this option. This can be controlled on a per member basis by -; setting 'ignorebusy' in the QUEUE_MEMBER function. (Note: only the SIP -; channel driver currently is able to report 'in use'.) (Note: if this option -; is set to 'no' it will override the per-member 'ignorebusy' setting. -; +; setting 'ringinuse' on that member. This can be done in the member definition, +; in the 'ringinuse' field on a realtime member, via the QUEUE_MEMBER dialplan +; function, or with CLI/AMI. By default, the per member value will be the same +; as the queue's ringinuse value if it isn't set on the member deliberately. +; (Note: only the SIP channel driver currently is able to report 'in use'.) ; ringinuse = no ; ; If you wish to have a delay before the member is connected to the caller (or @@ -551,12 +552,15 @@ monitor-type = MixMonitor ; must also preload pbx_config.so and chan_local.so (or pbx_ael.so, pbx_lua.so, ; or pbx_realtime.so, depending on how your dialplan is configured). ; +; syntax: member => interface,[,penalty][,membername][,state_interface][,ringinuse] +; ;member => DAHDI/1 ;member => DAHDI/2,10 ;member => DAHDI/3,10,Bob Johnson ;member => Agent/1001 ;member => Agent/1002 ;member => Local/1000@default,0,John Smith,SIP/1000 +;member => Local/2000@default,0,Lorem Ipsum,SIP/2000,no ; ; Note that using agent groups is probably not what you want. Strategies do