diff --git a/apps/app_queue.c b/apps/app_queue.c index 9e21ab9613625c2b794313855729fc496eaf6924..c0ee9f35fe162542c3acc8d84cd75e19e0b80192 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -6972,6 +6972,55 @@ static int publish_queue_member_pause(struct call_queue *q, struct member *membe return 0; } +/*! + * \internal + * \brief Set the pause status of the specific queue member. + * + * \param q Which queue the member belongs. + * \param mem Queue member being paused/unpaused. + * \param reason Why is this happening (Can be NULL/empty for no reason given.) + * \param paused Set to 1 if the member is being paused or 0 to unpause. + * + * \pre The q is locked on entry. + * + * \return Nothing + */ +static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused) +{ + if (mem->paused == paused) { + ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", + (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface); + } + + if (mem->realtime) { + if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) { + ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n", + (paused ? "" : "un"), q->name, mem->interface); + } + } + + mem->paused = paused; + ast_devstate_changed(mem->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE, + AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface); + + if (queue_persistent_members) { + dump_queue_members(q); + } + + if (is_member_available(q, mem)) { + ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, + "Queue:%s_avail", q->name); + } else if (!num_available_members(q)) { + ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, + "Queue:%s_avail", q->name); + } + + ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), + "%s", S_OR(reason, "")); + + publish_queue_member_pause(q, mem, reason); +} + static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused) { int found = 0; @@ -6985,55 +7034,30 @@ static int set_member_paused(const char *queuename, const char *interface, const struct member *mem; if ((mem = interface_exists(q, interface))) { - if (mem->paused == paused) { - ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); - } - - if (mem->realtime) { - if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) { - ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); - ao2_ref(mem, -1); - ao2_unlock(q); - queue_t_unref(q, "Done with iterator"); - continue; - } - } - - mem->paused = paused; - ast_devstate_changed(mem->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE, - AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface); - found++; - - /* Before we do the PAUSE/UNPAUSE log, if this was a PAUSEALL/UNPAUSEALL, log that here, but only on the first found entry. */ - if (found == 1) { - - /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ - if (ast_strlen_zero(queuename)) { - ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); - } - } - - if (queue_persistent_members) { - dump_queue_members(q); + /* + * Before we do the PAUSE/UNPAUSE, log if this was a + * PAUSEALL/UNPAUSEALL but only on the first found entry. + */ + ++found; + if (found == 1 + && ast_strlen_zero(queuename)) { + /* + * XXX In all other cases, we use the queue name, + * but since this affects all queues, we cannot. + */ + ast_queue_log("NONE", "NONE", mem->membername, + (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); } - if (is_member_available(q, mem)) { - ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name); - } else if (!num_available_members(q)) { - ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name); - } - - ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); - - publish_queue_member_pause(q, mem, reason); + set_queue_member_pause(q, mem, reason, paused); ao2_ref(mem, -1); } - } - if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { - ao2_unlock(q); - queue_t_unref(q, "Done with iterator"); - break; + if (!ast_strlen_zero(queuename)) { + ao2_unlock(q); + queue_t_unref(q, "Done with iterator"); + break; + } } ao2_unlock(q); @@ -7079,6 +7103,31 @@ static int set_member_penalty_help_members(struct call_queue *q, const char *int return foundinterface; } +/*! + * \internal + * \brief Set the ringinuse value of the specific queue member. + * + * \param q Which queue the member belongs. + * \param mem Queue member being set. + * \param ringinuse Set to 1 if the member is called when inuse. + * + * \pre The q is locked on entry. + * + * \return Nothing + */ +static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse) +{ + if (mem->realtime) { + update_realtime_member_field(mem, q->name, realtime_ringinuse_field, + ringinuse ? "1" : "0"); + } + + mem->ringinuse = ringinuse; + + ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse); + queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem)); +} + static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse) { struct member *mem; @@ -7087,17 +7136,7 @@ static int set_member_ringinuse_help_members(struct call_queue *q, const char *i ao2_lock(q); if ((mem = interface_exists(q, interface))) { foundinterface++; - if (mem->realtime) { - char rtringinuse[80]; - - sprintf(rtringinuse, "%i", ringinuse); - update_realtime_member_field(mem, q->name, realtime_ringinuse_field, rtringinuse); - } - - mem->ringinuse = ringinuse; - - ast_queue_log(q->name, "NONE", interface, "RINGINUSE", "%d", ringinuse); - queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem)); + set_queue_member_ringinuse(q, mem, ringinuse); ao2_ref(mem, -1); } ao2_unlock(q); @@ -8008,12 +8047,29 @@ static int queue_function_exists(struct ast_channel *chan, const char *cmd, char return 0; } +static struct member *get_interface_helper(struct call_queue *q, const char *interface) +{ + struct member *m; + + if (ast_strlen_zero(interface)) { + ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n"); + return NULL; + } + + m = interface_exists(q, interface); + if (!m) { + ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n", + interface, q->name); + } + return m; +} + /*! * \brief Get number either busy / free / ready or total members of a specific queue * \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) { int count = 0; @@ -8030,14 +8086,18 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch buf[0] = '\0'; if (ast_strlen_zero(data)) { - ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd); + ast_log(LOG_ERROR, + "Missing required argument. %s(<queuename>,<option>[,<interface>])\n", + cmd); return -1; } AST_STANDARD_APP_ARGS(args, data); - if (args.argc < 2) { - ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd); + if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) { + ast_log(LOG_ERROR, + "Missing required argument. %s(<queuename>,<option>[,<interface>])\n", + cmd); return -1; } @@ -8076,27 +8136,29 @@ static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, ch ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) { + } else if (!strcasecmp(args.option, "count")) { count = ao2_container_count(q->members); - } else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface) && - ((m = interface_exists(q, args.interface)))) { - count = m->penalty; - ao2_ref(m, -1); - } else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) && - ((m = interface_exists(q, args.interface)))) { - count = m->paused; - ao2_ref(m, -1); - } else if ( (!strcasecmp(args.option, "ignorebusy") || !strcasecmp(args.option, "ringinuse")) && - !ast_strlen_zero(args.interface) && - ((m = interface_exists(q, args.interface)))) { - count = m->ringinuse; - ao2_ref(m, -1); - } else if (!ast_strlen_zero(args.interface)) { - ast_log(LOG_ERROR, "Queue member interface %s not in queue %s\n", - args.interface, args.queuename); + } else if (!strcasecmp(args.option, "penalty")) { + m = get_interface_helper(q, args.interface); + if (m) { + count = m->penalty; + ao2_ref(m, -1); + } + } else if (!strcasecmp(args.option, "paused")) { + m = get_interface_helper(q, args.interface); + if (m) { + count = m->paused; + ao2_ref(m, -1); + } + } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */ + || !strcasecmp(args.option, "ringinuse"))) { + m = get_interface_helper(q, args.interface); + if (m) { + 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, ringinuse\n", args.option, cmd); + ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option); } ao2_unlock(q); queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");