From 792a89a9f74b0ddf18fac3f9076e55ae0ca79239 Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Thu, 20 Sep 2012 18:59:05 +0000 Subject: [PATCH] app_queue: Support an 'agent available' hint Sets INUSE when no free agents, NOT_INUSE when an agent is free. modifes handle_statechange() scan members loop to scan for a free agent and updates the Queue:queuename_avial devstate. Previously exited early if the member was found in the queue. Now Exits later when both a member was found, and a free agent was found. alecdavis (license 585) Reported by: Alec Davis Tested by: alecdavis Review: https://reviewboard.asterisk.org/r/2121/ ~~~~ Support all ways a member can be available for 'agent available' hints Alec's patch in r373188 added the ability to subscribe to a hint for when Queue members are available. This patch modifies the check that determines when a Queue member is available by refactoring the availability checks in num_available_members into a shared function is_member_available. This should now handle the ringinuse option, as well as device state values other than AST_DEVICE_NOT_INUSE. git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@373240 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 7 +++ apps/app_queue.c | 105 ++++++++++++++++++++++++--------- configs/extensions.conf.sample | 6 ++ 3 files changed, 89 insertions(+), 29 deletions(-) diff --git a/CHANGES b/CHANGES index df8bd4ffa5..c0a5c37045 100644 --- a/CHANGES +++ b/CHANGES @@ -690,6 +690,13 @@ Scripts the source tree. If the variable is not set, it defaults to the current behavior and uses the current working directory. +Queue +------------------- + * Add queue available hint. exten => 8501,hint,Queue:markq_avail + Note: the suffix '_avail' after the queuename. + Reports 'InUse' for no logged in agents or no free agents. + Reports 'Idle' when an agent is free. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 1.8 to Asterisk 10 ------------------- ------------------------------------------------------------------------------ diff --git a/apps/app_queue.c b/apps/app_queue.c index 707cd79147..13ad196491 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1652,6 +1652,39 @@ static int update_status(struct call_queue *q, struct member *m, const int statu return 0; } +/*! + * \internal \brief Determine if a queue member is available + * \retval 1 if the member is available + * \retval 0 if the member is not available + */ +static int is_member_available(struct member *mem) +{ + int available = 0; + + switch (mem->status) { + case AST_DEVICE_INVALID: + case AST_DEVICE_UNAVAILABLE: + break; + case AST_DEVICE_INUSE: + case AST_DEVICE_BUSY: + case AST_DEVICE_RINGING: + case AST_DEVICE_RINGINUSE: + case AST_DEVICE_ONHOLD: + if (!mem->ringinuse) { + break; + } + /* else fall through */ + case AST_DEVICE_NOT_INUSE: + case AST_DEVICE_UNKNOWN: + if (!mem->paused) { + available = 1; + } + break; + } + + return available; +} + /*! \brief set a member's status based on device state of that member's interface*/ static int handle_statechange(void *datap) { @@ -1660,29 +1693,53 @@ static int handle_statechange(void *datap) struct member *m; struct call_queue *q; char interface[80], *slash_pos; - int found = 0; + int found = 0; /* Found this member in any queue */ + int found_member; /* Found this member in this queue */ + int avail = 0; /* Found an available member in this queue */ qiter = ao2_iterator_init(queues, 0); while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) { ao2_lock(q); + avail = 0; + found_member = 0; miter = ao2_iterator_init(q->members, 0); for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { - ast_copy_string(interface, m->state_interface, sizeof(interface)); + if (!found_member) { + ast_copy_string(interface, m->state_interface, sizeof(interface)); + + if ((slash_pos = strchr(interface, '/'))) { + if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) { + *slash_pos = '\0'; + } + } - if ((slash_pos = strchr(interface, '/'))) { - if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) { - *slash_pos = '\0'; + if (!strcasecmp(interface, sc->dev)) { + found_member = 1; + update_status(q, m, sc->state); } } - if (!strcasecmp(interface, sc->dev)) { - found = 1; - update_status(q, m, sc->state); + /* check every member until we find one NOT_INUSE */ + if (!avail) { + avail = is_member_available(m); + } + if (avail && found_member) { + /* early exit as we've found an available member and the member of interest */ ao2_ref(m, -1); break; } } + + if (found_member) { + found = 1; + if (avail) { + ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Queue:%s_avail", q->name); + } else { + ast_devstate_changed(AST_DEVICE_INUSE, "Queue:%s_avail", q->name); + } + } + ao2_iterator_destroy(&miter); ao2_unlock(q); @@ -3234,26 +3291,8 @@ static int num_available_members(struct call_queue *q) mem_iter = ao2_iterator_init(q->members, 0); while ((mem = ao2_iterator_next(&mem_iter))) { - switch (mem->status) { - case AST_DEVICE_INVALID: - case AST_DEVICE_UNAVAILABLE: - break; - case AST_DEVICE_INUSE: - case AST_DEVICE_BUSY: - case AST_DEVICE_RINGING: - case AST_DEVICE_RINGINUSE: - case AST_DEVICE_ONHOLD: - if (!mem->ringinuse) { - break; - } - /* else fall through */ - case AST_DEVICE_NOT_INUSE: - case AST_DEVICE_UNKNOWN: - if (!mem->paused) { - avl++; - } - break; - } + + avl += is_member_available(mem); ao2_ref(mem, -1); /* If autofill is not enabled or if the queue's strategy is ringall, then @@ -5859,7 +5898,11 @@ static int remove_from_queue(const char *queuename, const char *interface) if (queue_persistent_members) { dump_queue_members(q); } - + + if (!ao2_container_count(q->members)) { + ast_devstate_changed(AST_DEVICE_INUSE, "Queue:%s_avail", q->name); + } + res = RES_OKAY; } else { res = RES_EXISTS; @@ -5940,6 +5983,10 @@ static int add_to_queue(const char *queuename, const char *interface, const char dump_queue_members(q); } + if (ao2_container_count(q->members) == 1) { + ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Queue:%s_avail", q->name); + } + res = RES_OKAY; } else { res = RES_OUTOFMEMORY; diff --git a/configs/extensions.conf.sample b/configs/extensions.conf.sample index 75ef33607f..4eed9c90c1 100644 --- a/configs/extensions.conf.sample +++ b/configs/extensions.conf.sample @@ -713,6 +713,12 @@ include => demo ;exten => 8502,hint,Queue:markq ;exten => 8502,1,Queue(markq) ; + +;To subscribe to the availability of a free member in the 'markq' queue. +;Note: '_avail' is added to the QueueName +;exten => 8501,hint,Queue:markq_avail +;exten => 8501,1,Queue(markq) + ; Some other handy things are an extension for checking voicemail via ; voicemailmain ; -- 2.47.2