]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
app_queue: Support an 'agent available' hint
authorMatthew Jordan <mjordan@digium.com>
Thu, 20 Sep 2012 18:59:05 +0000 (18:59 +0000)
committerMatthew Jordan <mjordan@digium.com>
Thu, 20 Sep 2012 18:59:05 +0000 (18:59 +0000)
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
apps/app_queue.c
configs/extensions.conf.sample

diff --git a/CHANGES b/CHANGES
index df8bd4ffa5af5f0ace488eee8c5a472b6eefda49..c0a5c370458428fd2b11c861884b09da6cb57f56 100644 (file)
--- 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 -------------------
 ------------------------------------------------------------------------------
index 707cd79147800f13749be8bed87b5b0fbc676d9c..13ad196491ce42e510362c55139ec6f6f117f9df 100644 (file)
@@ -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;
index 75ef33607f00f4d9911fdde6a0a7fa8294a5ce85..4eed9c90c16009acf94b724c263e69217e9360c1 100644 (file)
@@ -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
 ;