Replace direct access to channel name with accessor functions
[asterisk/asterisk.git] / apps / app_queue.c
index 4c7c422..ec9ad39 100644 (file)
@@ -57,7 +57,8 @@
  */
 
 /*** MODULEINFO
-       <depend>res_monitor</depend>
+       <use type="module">res_monitor</use>
+       <support_level>core</support_level>
  ***/
 
 #include "asterisk.h"
@@ -223,6 +224,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        up by another user.</para>
                        <para>This application will return to the dialplan if the queue does not exist, or
                        any of the join options cause the caller to not enter the queue.</para>
+                       <para>This application does not automatically answer and should be preceeded
+                       by an application such as Answer(), Progress(), or Ringing().</para>
                        <para>This application sets the following channel variable upon completion:</para>
                        <variablelist>
                                <variable name="QUEUESTATUS">
@@ -238,14 +241,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </variablelist>
                </description>
                <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
                        <ref type="application">AddQueueMember</ref>
                        <ref type="application">RemoveQueueMember</ref>
                        <ref type="application">PauseQueueMember</ref>
                        <ref type="application">UnpauseQueueMember</ref>
-                       <ref type="application">AgentLogin</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
                        <ref type="function">QUEUE_MEMBER_COUNT</ref>
-                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
                        <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </application>
        <application name="AddQueueMember" language="en_US">
@@ -274,10 +282,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </variablelist>
                </description>
                <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
                        <ref type="application">RemoveQueueMember</ref>
                        <ref type="application">PauseQueueMember</ref>
                        <ref type="application">UnpauseQueueMember</ref>
-                       <ref type="application">AgentLogin</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </application>
        <application name="RemoveQueueMember" language="en_US">
@@ -303,9 +320,18 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
                        <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
                        <ref type="application">PauseQueueMember</ref>
                        <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </application>
        <application name="PauseQueueMember" language="en_US">
@@ -337,7 +363,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Example: PauseQueueMember(,SIP/3000)</para>
                </description>
                <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
                        <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </application>
        <application name="UnpauseQueueMember" language="en_US">
@@ -366,7 +404,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Example: UnpauseQueueMember(,SIP/3000)</para>
                </description>
                <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
                        <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </application>
        <application name="QueueLog" language="en_US">
@@ -386,6 +436,18 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </description>
                <see-also>
                        <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </application>
        <function name="QUEUE_VARIABLES" language="en_US">
@@ -426,6 +488,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Makes the following queue variables available.</para>
                        <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
                </description>
+               <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
+               </see-also>
        </function>
        <function name="QUEUE_MEMBER" language="en_US">
                <synopsis>
@@ -447,12 +524,41 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <enum name="count">
                                                <para>Returns the total number of members for the specified queue.</para>
                                        </enum>
+                                       <enum name="penalty">
+                                               <para>Gets or sets queue member penalty.</para>
+                                       </enum>
+                                       <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>
                                </enumlist>
                        </parameter>
+                       <parameter name="interface" required="false" />
                </syntax>
                <description>
-                       <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
+                       <para>Allows access to queue counts [R] and member information [R/W].</para>
+                       <para>
+                               <replaceable>queuename</replaceable> is required for all operations
+                               <replaceable>interface</replaceable> is required for all member operations.
+                       </para>
                </description>
+               <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
+               </see-also>
        </function>
        <function name="QUEUE_MEMBER_COUNT" language="en_US">
                <synopsis>
@@ -466,7 +572,45 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
                </description>
                <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
+               </see-also>
+       </function>
+       <function name="QUEUE_EXISTS" language="en_US">
+               <synopsis>
+                       Check if a named queue exists on this server
+               </synopsis>
+               <syntax>
+                       <parameter name="queuename" />
+               </syntax>
+               <description>
+                       <para>Returns 1 if the specified queue exists, 0 if it does not</para>
+               </description>
+               <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
                        <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </function>
        <function name="QUEUE_WAITING_COUNT" language="en_US">
@@ -479,6 +623,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <description>
                        <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
                </description>
+               <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
+               </see-also>
        </function>
        <function name="QUEUE_MEMBER_LIST" language="en_US">
                <synopsis>
@@ -491,7 +650,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
                </description>
                <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
                        <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
                </see-also>
        </function>
        <function name="QUEUE_MEMBER_PENALTY" language="en_US">
@@ -504,14 +675,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                </syntax>
                <description>
                        <para>Gets or sets queue members penalty.</para>
+                       <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
                </description>
+               <see-also>
+                       <ref type="application">Queue</ref>
+                       <ref type="application">QueueLog</ref>
+                       <ref type="application">AddQueueMember</ref>
+                       <ref type="application">RemoveQueueMember</ref>
+                       <ref type="application">PauseQueueMember</ref>
+                       <ref type="application">UnpauseQueueMember</ref>
+                       <ref type="function">QUEUE_VARIABLES</ref>
+                       <ref type="function">QUEUE_MEMBER</ref>
+                       <ref type="function">QUEUE_MEMBER_COUNT</ref>
+                       <ref type="function">QUEUE_EXISTS</ref>
+                       <ref type="function">QUEUE_WAITING_COUNT</ref>
+                       <ref type="function">QUEUE_MEMBER_LIST</ref>
+                       <ref type="function">QUEUE_MEMBER_PENALTY</ref>
+               </see-also>
        </function>
        <manager name="Queues" language="en_US">
                <synopsis>
                        Queues.
                </synopsis>
                <syntax>
-                       <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
                </syntax>
                <description>
                </description>
@@ -669,7 +855,8 @@ enum {
        QUEUE_STRATEGY_RANDOM,
        QUEUE_STRATEGY_RRMEMORY,
        QUEUE_STRATEGY_LINEAR,
-       QUEUE_STRATEGY_WRANDOM
+       QUEUE_STRATEGY_WRANDOM,
+       QUEUE_STRATEGY_RRORDERED,
 };
 
 enum {
@@ -697,6 +884,7 @@ static const struct strategy {
        { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
        { QUEUE_STRATEGY_LINEAR, "linear" },
        { QUEUE_STRATEGY_WRANDOM, "wrandom"},
+       { QUEUE_STRATEGY_RRORDERED, "rrordered"},
 };
 
 static const struct autopause {
@@ -749,13 +937,13 @@ static int queue_persistent_members = 0;
 static int use_weight = 0;
 
 /*! \brief queues.conf [general] option */
-static int autofill_default = 0;
+static int autofill_default = 1;
 
 /*! \brief queues.conf [general] option */
 static int montype_default = 0;
 
 /*! \brief queues.conf [general] option */
-static int shared_lastcall = 0;
+static int shared_lastcall = 1;
 
 /*! \brief Subscription to device state change events */
 static struct ast_event_sub *device_state_sub;
@@ -763,6 +951,15 @@ static struct ast_event_sub *device_state_sub;
 /*! \brief queues.conf [general] option */
 static int update_cdr = 0;
 
+/*! \brief queues.conf [general] option */
+static int negative_penalty_invalid = 0;
+
+/*! \brief queues.conf [general] option */
+static int log_membername_as_agent = 0;
+
+/*! \brief queues.conf [general] option */
+static int check_state_unknown = 0;
+
 enum queue_result {
        QUEUE_UNKNOWN = 0,
        QUEUE_TIMEOUT = 1,
@@ -828,7 +1025,7 @@ struct callattempt {
 struct queue_ent {
        struct call_queue *parent;             /*!< What queue is our parent */
        char moh[80];                          /*!< Name of musiconhold to be used */
-       char announce[80];                     /*!< Announcement to play for member when call is answered */
+       char announce[PATH_MAX];               /*!< Announcement to play for member when call is answered */
        char context[AST_MAX_CONTEXT];         /*!< Context when user exits queue */
        char digits[AST_MAX_EXTENSION];        /*!< Digits entered while in queue */
        int valid_digits;                      /*!< Digits entered correspond to valid extension. Exited */
@@ -872,6 +1069,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 */
 };
 
 enum empty_conditions {
@@ -963,6 +1161,8 @@ struct call_queue {
        unsigned int realtime:1;
        unsigned int found:1;
        unsigned int relativeperiodicannounce:1;
+       unsigned int autopausebusy:1;
+       unsigned int autopauseunavail:1;
        enum empty_conditions joinempty;
        enum empty_conditions leavewhenempty;
        int announcepositionlimit;          /*!< How many positions we announce? */
@@ -989,6 +1189,7 @@ struct call_queue {
        int timeout;                        /*!< How long to wait for an answer */
        int weight;                         /*!< Respective weight */
        int autopause;                      /*!< Auto pause queue members if they fail to answer */
+       int autopausedelay;                 /*!< Delay auto pause for autopausedelay seconds since last call */
        int timeoutpriority;                /*!< Do we allow a fraction of the timeout to occur for a ring? */
 
        /* Queue strategy things */
@@ -997,12 +1198,6 @@ struct call_queue {
        int autofill;                       /*!< Ignore the head call status and ring an available agent */
        
        struct ao2_container *members;             /*!< Head of the list of members */
-       /*! 
-        * \brief Number of members _logged in_
-        * \note There will be members in the members container that are not logged
-        *       in, so this can not simply be replaced with ao2_container_count(). 
-        */
-       int membercount;
        struct queue_ent *head;             /*!< Head of the list of callers */
        AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
        AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
@@ -1019,9 +1214,12 @@ static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
 static struct ao2_container *queues;
 
 static void update_realtime_members(struct call_queue *q);
+static struct member *interface_exists(struct call_queue *q, const char *interface);
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
 
-static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); 
+static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
 /*! \brief sets the QUEUESTATUS channel variable */
 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
 {
@@ -1113,7 +1311,7 @@ static inline struct call_queue *queue_ref(struct call_queue *q)
 static inline struct call_queue *queue_unref(struct call_queue *q)
 {
        ao2_ref(q, -1);
-       return q;
+       return NULL;
 }
 #endif
 
@@ -1123,6 +1321,8 @@ static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
        char interfacevar[256]="";
        float sl = 0;
 
+       ao2_lock(q);
+
        if (q->setqueuevar) {
                sl = 0;
                if (q->callscompleted > 0) 
@@ -1131,8 +1331,12 @@ static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
                snprintf(interfacevar, sizeof(interfacevar),
                        "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
                        q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
+
+               ao2_unlock(q);
        
                pbx_builtin_setvar_multiple(chan, interfacevar); 
+       } else {
+               ao2_unlock(q);
        }
 }
 
@@ -1201,6 +1405,12 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena
                                break;
                        }
                        goto default_case;
+               case AST_DEVICE_RINGING:
+                       if (conditions & QUEUE_EMPTY_RINGING) {
+                               ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
+                               break;
+                       }
+                       goto default_case;
                case AST_DEVICE_UNKNOWN:
                        if (conditions & QUEUE_EMPTY_UNKNOWN) {
                                ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
@@ -1238,7 +1448,7 @@ struct statechange {
 };
 
 /*! \brief set a member's status based on device state of that member's state_interface.
- *  
+ *
  * Lock interface list find sc, iterate through each queues queue_member list for member to
  * update state inside queues
 */
@@ -1253,13 +1463,14 @@ static int update_status(struct call_queue *q, struct member *m, const int statu
                "Queue: %s\r\n"
                "Location: %s\r\n"
                "MemberName: %s\r\n"
+               "StateInterface: %s\r\n"
                "Membership: %s\r\n"
                "Penalty: %d\r\n"
                "CallsTaken: %d\r\n"
                "LastCall: %d\r\n"
                "Status: %d\r\n"
                "Paused: %d\r\n",
-               q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
+               q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
                m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
        );
 
@@ -1369,7 +1580,7 @@ static int extensionstate2devicestate(int state)
        return state;
 }
 
-static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
+static int extension_state_cb(const char *context, const char *exten, enum ast_extension_states state, void *data)
 {
        struct ao2_iterator miter, qiter;
        struct member *m;
@@ -1416,21 +1627,24 @@ static int get_queue_member_status(struct member *cur)
 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
 {
        struct member *cur;
-       
+
        if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
                cur->penalty = penalty;
                cur->paused = paused;
                ast_copy_string(cur->interface, interface, sizeof(cur->interface));
-               if (!ast_strlen_zero(state_interface))
+               if (!ast_strlen_zero(state_interface)) {
                        ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
-               else
+               } else {
                        ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
-               if (!ast_strlen_zero(membername))
+               }
+               if (!ast_strlen_zero(membername)) {
                        ast_copy_string(cur->membername, membername, sizeof(cur->membername));
-               else
+               } else {
                        ast_copy_string(cur->membername, interface, sizeof(cur->membername));
-               if (!strchr(cur->interface, '/'))
+               }
+               if (!strchr(cur->interface, '/')) {
                        ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
+               }
                if (!strncmp(cur->state_interface, "hint:", 5)) {
                        char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
                        char *exten = strsep(&context, "@") + 5;
@@ -1458,22 +1672,29 @@ static int compress_char(const char c)
 static int member_hash_fn(const void *obj, const int flags)
 {
        const struct member *mem = obj;
-       const char *chname = strchr(mem->interface, '/');
+       const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
+       const char *chname = strchr(interface, '/');
        int ret = 0, i;
-       if (!chname)
-               chname = mem->interface;
-       for (i = 0; i < 5 && chname[i]; i++)
+
+       if (!chname) {
+               chname = interface;
+       }
+       for (i = 0; i < 5 && chname[i]; i++) {
                ret += compress_char(chname[i]) << (i * 6);
+       }
        return ret;
 }
 
 static int member_cmp_fn(void *obj1, void *obj2, int flags)
 {
-       struct member *mem1 = obj1, *mem2 = obj2;
-       return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
+       struct member *mem1 = obj1;
+       struct member *mem2 = obj2;
+       const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
+
+       return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
 }
 
-/*! 
+/*!
  * \brief Initialize Queue default values.
  * \note the queue's lock  must be held before executing this function
 */
@@ -1515,8 +1736,9 @@ static void init_queue(struct call_queue *q)
        q->numperiodicannounce = 0;
        q->autopause = QUEUE_AUTOPAUSE_OFF;
        q->timeoutpriority = TIMEOUT_PRIORITY_APP;
+       q->autopausedelay = 0;
        if (!q->members) {
-               if (q->strategy == QUEUE_STRATEGY_LINEAR)
+               if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED)
                        /* linear strategy depends on order, so we have to place all members in a single bucket */
                        q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
                else
@@ -1536,8 +1758,13 @@ static void init_queue(struct call_queue *q)
        ast_string_field_set(q, sound_thanks, "queue-thankyou");
        ast_string_field_set(q, sound_reporthold, "queue-reporthold");
 
-       if ((q->sound_periodicannounce[0] = ast_str_create(32)))
+       if (!q->sound_periodicannounce[0]) {
+               q->sound_periodicannounce[0] = ast_str_create(32);
+       }
+
+       if (q->sound_periodicannounce[0]) {
                ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
+       }
 
        for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
                if (q->sound_periodicannounce[i])
@@ -1568,16 +1795,16 @@ static void clear_queue(struct call_queue *q)
        }
 }
 
-/*! 
+/*!
  * \brief Change queue penalty by adding rule.
  *
- * Check rule for errors with time or fomatting, see if rule is relative to rest 
+ * Check rule for errors with time or fomatting, see if rule is relative to rest
  * of queue, iterate list of rules to find correct insertion point, insert and return.
  * \retval -1 on failure
- * \retval 0 on success 
- * \note Call this with the rule_lists locked 
+ * \retval 0 on success
+ * \note Call this with the rule_lists locked
 */
-static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
+static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
 {
        char *timestr, *maxstr, *minstr, *contentdup;
        struct penalty_rule *rule = NULL, *rule_iter;
@@ -1820,6 +2047,12 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
                        q->montype = 1;
        } else if (!strcasecmp(param, "autopause")) {
                q->autopause = autopause2int(val);
+       } else if (!strcasecmp(param, "autopausedelay")) {
+               q->autopausedelay = atoi(val);
+       } else if (!strcasecmp(param, "autopausebusy")) {
+               q->autopausebusy = ast_true(val);
+       } else if (!strcasecmp(param, "autopauseunavail")) {
+               q->autopauseunavail = ast_true(val);
        } else if (!strcasecmp(param, "maxlen")) {
                q->maxlen = atoi(val);
                if (q->maxlen < 0)
@@ -1889,15 +2122,23 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
  * \brief Find rt member record to update otherwise create one.
  *
  * Search for member in queue, if found update penalty/paused state,
- * if no member exists create one flag it as a RT member and add to queue member list. 
+ * if no member exists create one flag it as a RT member and add to queue member list.
 */
-static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
+static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
 {
        struct member *m;
        struct ao2_iterator mem_iter;
        int penalty = 0;
        int paused  = 0;
        int found = 0;
+       int ignorebusy = 0;
+
+       const char *config_val;
+       const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
+       const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
+       const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
+       const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty");
+       const char *paused_str = ast_variable_retrieve(member_config, interface, "paused");
 
        if (ast_strlen_zero(rt_uniqueid)) {
                ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
@@ -1906,47 +2147,63 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
 
        if (penalty_str) {
                penalty = atoi(penalty_str);
-               if (penalty < 0)
+               if ((penalty < 0) && negative_penalty_invalid) {
+                       return;
+               } else if (penalty < 0) {
                        penalty = 0;
+               }
        }
 
        if (paused_str) {
                paused = atoi(paused_str);
-               if (paused < 0)
+               if (paused < 0) {
                        paused = 0;
+               }
        }
 
-       /* Find member by realtime uniqueid and update */
-       mem_iter = ao2_iterator_init(q->members, 0);
-       while ((m = ao2_iterator_next(&mem_iter))) {
-               if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
-                       m->dead = 0;    /* Do not delete this one. */
-                       ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
-                       if (paused_str)
-                               m->paused = paused;
-                       if (strcasecmp(state_interface, m->state_interface)) {
-                               ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
-                       }          
-                       m->penalty = penalty;
-                       found = 1;
-                       ao2_ref(m, -1);
-                       break;
-               }
-               ao2_ref(m, -1);
-       }
+       if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy"))) {
+               ignorebusy = ast_true(config_val);
+       } else {
+               ignorebusy = 1;
+       }
+
+       /* Find member by realtime uniqueid and update */
+       mem_iter = ao2_iterator_init(q->members, 0);
+       while ((m = ao2_iterator_next(&mem_iter))) {
+               if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
+                       m->dead = 0;    /* Do not delete this one. */
+                       ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
+                       if (paused_str) {
+                               m->paused = paused;
+                       }
+                       if (strcasecmp(state_interface, m->state_interface)) {
+                               ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+                       }
+                       m->penalty = penalty;
+                       m->ignorebusy = ignorebusy;
+                       found = 1;
+                       ao2_ref(m, -1);
+                       break;
+               }
+               ao2_ref(m, -1);
+       }
        ao2_iterator_destroy(&mem_iter);
 
-       /* Create a new member */
-       if (!found) {
+       /* Create a new member */
+       if (!found) {
                if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
                        m->dead = 0;
                        m->realtime = 1;
+                       m->ignorebusy = ignorebusy;
                        ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
-                       ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
+                       if (!log_membername_as_agent) {
+                               ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
+                       } else {
+                               ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
+                       }
                        ao2_link(q->members, m);
                        ao2_ref(m, -1);
                        m = NULL;
-                       q->membercount++;
                }
        }
 }
@@ -1961,7 +2218,6 @@ static void free_members(struct call_queue *q, int all)
        while ((cur = ao2_iterator_next(&mem_iter))) {
                if (all || !cur->dynamic) {
                        ao2_unlink(q->members, cur);
-                       q->membercount--;
                }
                ao2_ref(cur, -1);
        }
@@ -2003,15 +2259,15 @@ static struct call_queue *alloc_queue(const char *queuename)
  * Check for statically defined queue first, check if deleted RT queue,
  * check for new RT queue, if queue vars are not defined init them with defaults.
  * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
- * \retval the queue, 
+ * \retval the queue,
  * \retval NULL if it doesn't exist.
- * \note Should be called with the "queues" container locked. 
+ * \note Should be called with the "queues" container locked.
 */
 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 {
        struct ast_variable *v;
        struct call_queue *q, tmpq = {
-               .name = queuename,      
+               .name = queuename,
        };
        struct member *m;
        struct ao2_iterator mem_iter;
@@ -2034,10 +2290,10 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
                                return q;
                        }
                }
-       } else if (!member_config)
+       } else if (!member_config) {
                /* Not found in the list, and it's not realtime ... */
                return NULL;
-
+       }
        /* Check if queue is defined in realtime. */
        if (!queue_vars) {
                /* Delete queue from in-core list if it has been deleted in realtime. */
@@ -2059,12 +2315,12 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
        /* Create a new queue if an in-core entry does not exist yet. */
        if (!q) {
                struct ast_variable *tmpvar = NULL;
-               if (!(q = alloc_queue(queuename)))
+               if (!(q = alloc_queue(queuename))) {
                        return NULL;
+               }
                ao2_lock(q);
                clear_queue(q);
                q->realtime = 1;
-               q->membercount = 0;
                /*Before we initialize the queue, we need to set the strategy, so that linear strategy
                 * will allocate the members properly
                 */
@@ -2080,8 +2336,9 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
                        }
                }
                /* We traversed all variables and didn't find a strategy */
-               if (!tmpvar)
+               if (!tmpvar) {
                        q->strategy = QUEUE_STRATEGY_RINGALL;
+               }
                queues_t_link(queues, q, "Add queue to container");
        }
        init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
@@ -2098,39 +2355,36 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
                } else
                        tmp_name = v->name;
 
-               if (!ast_strlen_zero(v->value)) {
-                       /* Don't want to try to set the option if the value is empty */
-                       queue_set_param(q, tmp_name, v->value, -1, 0);
-               }
+               /* NULL values don't get returned from realtime; blank values should
+                * still get set.  If someone doesn't want a value to be set, they
+                * should set the realtime column to NULL, not blank. */
+               queue_set_param(q, tmp_name, v->value, -1, 0);
        }
 
-       /* Temporarily set realtime members dead so we can detect deleted ones. 
-        * Also set the membercount correctly for realtime*/
+       /* Temporarily set realtime members dead so we can detect deleted ones. */
        mem_iter = ao2_iterator_init(q->members, 0);
        while ((m = ao2_iterator_next(&mem_iter))) {
-               q->membercount++;
-               if (m->realtime)
+               if (m->realtime) {
                        m->dead = 1;
+               }
                ao2_ref(m, -1);
        }
        ao2_iterator_destroy(&mem_iter);
 
        while ((interface = ast_category_browse(member_config, interface))) {
-               rt_handle_member_record(q, interface,
-                       ast_variable_retrieve(member_config, interface, "uniqueid"),
-                       S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
-                       ast_variable_retrieve(member_config, interface, "penalty"),
-                       ast_variable_retrieve(member_config, interface, "paused"),
-                       S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
+               rt_handle_member_record(q, interface, member_config);
        }
 
        /* Delete all realtime members that have been deleted in DB. */
        mem_iter = ao2_iterator_init(q->members, 0);
        while ((m = ao2_iterator_next(&mem_iter))) {
                if (m->dead) {
-                       ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
+                       if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
+                               ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
+                       } else {
+                               ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
+                       }
                        ao2_unlink(q->members, m);
-                       q->membercount--;
                }
                ao2_ref(m, -1);
        }
@@ -2141,12 +2395,23 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
        return q;
 }
 
-static struct call_queue *load_realtime_queue(const char *queuename)
+/*!
+ * note  */
+
+/*!
+ * \internal
+ * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
+ * \param queuename - name of the desired queue
+ *
+ * \retval the queue
+ * \retval NULL if it doesn't exist
+ */
+static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
 {
        struct ast_variable *queue_vars;
        struct ast_config *member_config = NULL;
        struct call_queue *q = NULL, tmpq = {
-               .name = queuename,      
+               .name = queuename,
        };
        int prev_weight = 0;
 
@@ -2174,18 +2439,14 @@ static struct call_queue *load_realtime_queue(const char *queuename)
                }
                if (q) {
                        prev_weight = q->weight ? 1 : 0;
+                       queue_t_unref(q, "Need to find realtime queue");
                }
 
-               ao2_lock(queues);
-
                q = find_queue_by_name_rt(queuename, queue_vars, member_config);
-               if (member_config) {
-                       ast_config_destroy(member_config);
-               }
-               if (queue_vars) {
-                       ast_variables_destroy(queue_vars);
-               }
-               /* update the use_weight value if the queue's has gained or lost a weight */ 
+               ast_config_destroy(member_config);
+               ast_variables_destroy(queue_vars);
+
+               /* update the use_weight value if the queue's has gained or lost a weight */
                if (q) {
                        if (!q->weight && prev_weight) {
                                ast_atomic_fetchadd_int(&use_weight, -1);
@@ -2195,8 +2456,6 @@ static struct call_queue *load_realtime_queue(const char *queuename)
                        }
                }
                /* Other cases will end up with the proper value for use_weight */
-               ao2_unlock(queues);
-
        } else {
                update_realtime_members(q);
        }
@@ -2230,10 +2489,9 @@ static void update_realtime_members(struct call_queue *q)
                return;
        }
 
-       ao2_lock(queues);
        ao2_lock(q);
-       
-       /* Temporarily set realtime  members dead so we can detect deleted ones.*/ 
+
+       /* Temporarily set realtime  members dead so we can detect deleted ones.*/
        mem_iter = ao2_iterator_init(q->members, 0);
        while ((m = ao2_iterator_next(&mem_iter))) {
                if (m->realtime)
@@ -2243,27 +2501,24 @@ static void update_realtime_members(struct call_queue *q)
        ao2_iterator_destroy(&mem_iter);
 
        while ((interface = ast_category_browse(member_config, interface))) {
-               rt_handle_member_record(q, interface,
-                       ast_variable_retrieve(member_config, interface, "uniqueid"),
-                       S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
-                       ast_variable_retrieve(member_config, interface, "penalty"),
-                       ast_variable_retrieve(member_config, interface, "paused"),
-                       S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
+               rt_handle_member_record(q, interface, member_config);
        }
 
        /* Delete all realtime members that have been deleted in DB. */
        mem_iter = ao2_iterator_init(q->members, 0);
        while ((m = ao2_iterator_next(&mem_iter))) {
                if (m->dead) {
-                       ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
+                       if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
+                               ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
+                       } else {
+                               ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
+                       }
                        ao2_unlink(q->members, m);
-                       q->membercount--;
                }
                ao2_ref(m, -1);
        }
        ao2_iterator_destroy(&mem_iter);
        ao2_unlock(q);
-       ao2_unlock(queues);
        ast_config_destroy(member_config);
 }
 
@@ -2275,10 +2530,9 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
        int pos = 0;
        int inserted = 0;
 
-       if (!(q = load_realtime_queue(queuename)))
+       if (!(q = find_load_queue_rt_friendly(queuename))) {
                return res;
-
-       ao2_lock(queues);
+       }
        ao2_lock(q);
 
        /* This is our one */
@@ -2287,7 +2541,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
                if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
                        *reason = QUEUE_JOINEMPTY;
                        ao2_unlock(q);
-                       ao2_unlock(queues);
+                       queue_t_unref(q, "Done with realtime queue");
                        return res;
                }
        }
@@ -2332,15 +2586,25 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
                q->count++;
                res = 0;
                ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
-                       "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
-                       qe->chan->name,
-                       S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
-                       S_OR(qe->chan->cid.cid_name, "unknown"),
+                       "Channel: %s\r\n"
+                       "CallerIDNum: %s\r\n"
+                       "CallerIDName: %s\r\n"
+                       "ConnectedLineNum: %s\r\n"
+                       "ConnectedLineName: %s\r\n"
+                       "Queue: %s\r\n"
+                       "Position: %d\r\n"
+                       "Count: %d\r\n"
+                       "Uniqueid: %s\r\n",
+                       ast_channel_name(qe->chan),
+                       S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
+                       S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
+                       S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
+                       S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
                        q->name, qe->pos, q->count, qe->chan->uniqueid );
-               ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
+               ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
        }
        ao2_unlock(q);
-       ao2_unlock(queues);
+       queue_t_unref(q, "Done with realtime queue");
 
        return res;
 }
@@ -2391,7 +2655,8 @@ static int valid_exit(struct queue_ent *qe, char digit)
                return 0;
 
        /* If the extension is bad, then reset the digits to blank */
-       if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
+       if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
+               S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) {
                qe->digits[0] = '\0';
                return 0;
        }
@@ -2510,7 +2775,7 @@ static int say_position(struct queue_ent *qe, int ringing)
                        }
                }
                if (avgholdsecs >= 1) {
-                       res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
+                       res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
                        if (res)
                                goto playout;
 
@@ -2525,7 +2790,7 @@ static int say_position(struct queue_ent *qe, int ringing)
 posout:
        if (qe->parent->announceposition) {
                ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
-                       qe->chan->name, qe->parent->name, qe->pos);
+                       ast_channel_name(qe->chan), qe->parent->name, qe->pos);
        }
        if (say_thanks) {
                res = play_file(qe->chan, qe->parent->sound_thanks);
@@ -2576,8 +2841,9 @@ static void leave_queue(struct queue_ent *qe)
        struct penalty_rule *pr_iter;
        int pos = 0;
 
-       if (!(q = qe->parent))
+       if (!(q = qe->parent)) {
                return;
+       }
        queue_t_ref(q, "Copy queue pointer from queue entry");
        ao2_lock(q);
 
@@ -2590,8 +2856,8 @@ static void leave_queue(struct queue_ent *qe)
                        /* Take us out of the queue */
                        ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
                                "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
-                               qe->chan->name, q->name,  q->count, qe->pos, qe->chan->uniqueid);
-                       ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
+                               ast_channel_name(qe->chan), q->name,  q->count, qe->pos, qe->chan->uniqueid);
+                       ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
                        /* Take us out of the queue */
                        if (prev)
                                prev->next = current->next;
@@ -2620,7 +2886,7 @@ static void leave_queue(struct queue_ent *qe)
                }
        }
 
-       if (q->dead) {  
+       if (q->dead) {
                /* It's dead and nobody is in it, so kill it */
                queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
        }
@@ -2683,16 +2949,24 @@ 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_INUSE:
-                       if (!q->ringinuse)
+                       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 ((!q->ringinuse) || (!mem->ignorebusy)) {
+                                       break;
+                               }
+                               /* else fall through */
+                       case AST_DEVICE_NOT_INUSE:
+                       case AST_DEVICE_UNKNOWN:
+                               if (!mem->paused) {
+                                       avl++;
+                               }
                                break;
-                       /* else fall through */
-               case AST_DEVICE_NOT_INUSE:
-               case AST_DEVICE_UNKNOWN:
-                       if (!mem->paused) {
-                               avl++;
-                       }
-                       break;
                }
                ao2_ref(mem, -1);
 
@@ -2723,9 +2997,7 @@ static int compare_weight(struct call_queue *rq, struct member *member)
        struct member *mem;
        int found = 0;
        struct ao2_iterator queue_iter;
-       
-       /* q's lock and rq's lock already set by try_calling()
-        * to solve deadlock */
+
        queue_iter = ao2_iterator_init(queues, 0);
        while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
                if (q == rq) { /* don't check myself, could deadlock */
@@ -2820,38 +3092,54 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        char tech[256];
        char *location;
        const char *macrocontext, *macroexten;
+       enum ast_device_state newstate;
 
        /* on entry here, we know that tmp->chan == NULL */
-       if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
-               (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
-               ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 
-                               (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
-               if (qe->chan->cdr)
+       if (tmp->member->paused) {
+               ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
+               if (qe->chan->cdr) {
                        ast_cdr_busy(qe->chan->cdr);
+               }
                tmp->stillgoing = 0;
-               (*busies)++;
                return 0;
        }
 
-       if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
-               ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
-               if (qe->chan->cdr)
+       if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
+               (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
+               ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
+                               (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
+               if (qe->chan->cdr) {
                        ast_cdr_busy(qe->chan->cdr);
+               }
                tmp->stillgoing = 0;
+               (*busies)++;
                return 0;
        }
 
-       if (tmp->member->paused) {
-               ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
-               if (qe->chan->cdr)
-                       ast_cdr_busy(qe->chan->cdr);
-               tmp->stillgoing = 0;
-               return 0;
+       if (!qe->parent->ringinuse || !tmp->member->ignorebusy) {
+               if (check_state_unknown && (tmp->member->status == AST_DEVICE_UNKNOWN)) {
+                       newstate = ast_device_state(tmp->member->interface);
+                       if (newstate != tmp->member->status) {
+                               ast_log(LOG_WARNING, "Found a channel matching iterface %s while status was %s changed to %s\n",
+                                       tmp->member->interface, ast_devstate2str(tmp->member->status), ast_devstate2str(newstate));
+                               ast_devstate_changed_literal(newstate, tmp->member->interface);
+                       }
+               }
+               if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
+                       ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
+                       if (qe->chan->cdr) {
+                               ast_cdr_busy(qe->chan->cdr);
+                       }
+                       tmp->stillgoing = 0;
+                       return 0;
+               }
        }
+
        if (use_weight && compare_weight(qe->parent,tmp->member)) {
                ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
-               if (qe->chan->cdr)
+               if (qe->chan->cdr) {
                        ast_cdr_busy(qe->chan->cdr);
+               }
                tmp->stillgoing = 0;
                (*busies)++;
                return 0;
@@ -2866,9 +3154,10 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        /* Request the peer */
        tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
        if (!tmp->chan) {                       /* If we can't, just go on to the next call */
-               if (qe->chan->cdr)
+               if (qe->chan->cdr) {
                        ast_cdr_busy(qe->chan->cdr);
-               tmp->stillgoing = 0;    
+               }
+               tmp->stillgoing = 0;
 
                ao2_lock(qe->parent);
                update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
@@ -2880,10 +3169,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
                return 0;
        }
 
-       ast_channel_lock(tmp->chan);
-       while (ast_channel_trylock(qe->chan)) {
-               CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
-       }
+       ast_channel_lock_both(tmp->chan, qe->chan);
 
        if (qe->cancel_answered_elsewhere) {
                ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
@@ -2893,12 +3179,16 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
 
        /* If the new channel has no callerid, try to guess what it should be */
-       if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
-               if (!ast_strlen_zero(qe->chan->connected.id.number)) {
-                       ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
-                       tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
-               } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
-                       ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
+       if (!tmp->chan->caller.id.number.valid) {
+               if (qe->chan->connected.id.number.valid) {
+                       struct ast_party_caller caller;
+
+                       ast_party_caller_set_init(&caller, &tmp->chan->caller);
+                       caller.id = qe->chan->connected.id;
+                       caller.ani = qe->chan->connected.ani;
+                       ast_channel_set_caller_event(tmp->chan, &caller, NULL);
+               } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) {
+                       ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL);
                } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
                        ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 
                }
@@ -2907,9 +3197,9 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
 
        ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
 
-       tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
+       tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select;
 
-       ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
+       ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller);
 
        /* Inherit specially named variables from parent channel */
        ast_channel_inherit_variables(qe->chan, tmp->chan);
@@ -2929,7 +3219,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        if (ast_cdr_isset_unanswered()) {
                /* they want to see the unanswered dial attempts! */
                /* set up the CDR fields on all the CDRs to give sensical information */
-               ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
+               ast_cdr_setdestchan(tmp->chan->cdr, ast_channel_name(tmp->chan));
                strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
                strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
                strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
@@ -2942,13 +3232,14 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
                strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
        }
 
+       ast_channel_unlock(tmp->chan);
+       ast_channel_unlock(qe->chan);
+
        /* Place the call, but don't wait on the answer */
        if ((res = ast_call(tmp->chan, location, 0))) {
                /* Again, keep going even if there's an error */
                ast_debug(1, "ast call on peer returned %d\n", res);
                ast_verb(3, "Couldn't call %s\n", tmp->interface);
-               ast_channel_unlock(tmp->chan);
-               ast_channel_unlock(qe->chan);
                do_hang(tmp);
                (*busies)++;
                update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
@@ -2956,28 +3247,36 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        } else if (qe->parent->eventwhencalled) {
                char vars[2048];
 
+               ast_channel_lock_both(tmp->chan, qe->chan);
+
                manager_event(EVENT_FLAG_AGENT, "AgentCalled",
-                                       "Queue: %s\r\n"
-                                       "AgentCalled: %s\r\n"
-                                       "AgentName: %s\r\n"
-                                       "ChannelCalling: %s\r\n"
-                                       "DestinationChannel: %s\r\n"
-                                       "CallerIDNum: %s\r\n"
-                                       "CallerIDName: %s\r\n"
-                                       "Context: %s\r\n"
-                                       "Extension: %s\r\n"
-                                       "Priority: %d\r\n"
-                                       "Uniqueid: %s\r\n"
-                                       "%s",
-                                       qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
-                                       tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
-                                       tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
-                                       qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
-                                       qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+                       "Queue: %s\r\n"
+                       "AgentCalled: %s\r\n"
+                       "AgentName: %s\r\n"
+                       "ChannelCalling: %s\r\n"
+                       "DestinationChannel: %s\r\n"
+                       "CallerIDNum: %s\r\n"
+                       "CallerIDName: %s\r\n"
+                       "ConnectedLineNum: %s\r\n"
+                       "ConnectedLineName: %s\r\n"
+                       "Context: %s\r\n"
+                       "Extension: %s\r\n"
+                       "Priority: %d\r\n"
+                       "Uniqueid: %s\r\n"
+                       "%s",
+                       qe->parent->name, tmp->interface, tmp->member->membername, ast_channel_name(qe->chan), ast_channel_name(tmp->chan),
+                       S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
+                       S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
+                       S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
+                       S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
+                       qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
+                       qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+
+               ast_channel_unlock(tmp->chan);
+               ast_channel_unlock(qe->chan);
+
                ast_verb(3, "Called %s\n", tmp->interface);
        }
-       ast_channel_unlock(tmp->chan);
-       ast_channel_unlock(qe->chan);
 
        update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
        return 1;
@@ -3093,7 +3392,7 @@ static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
        return 0;
 }
 
-/*! \brief Playback announcement to queued members if peroid has elapsed */
+/*! \brief Playback announcement to queued members if period has elapsed */
 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
 {
        int res = 0;
@@ -3152,8 +3451,8 @@ static int say_periodic_announcement(struct queue_ent *qe, int ringing)
 /*! \brief Record that a caller gave up on waiting in queue */
 static void record_abandoned(struct queue_ent *qe)
 {
-       ao2_lock(qe->parent);
        set_queue_variables(qe->parent, qe->chan);
+       ao2_lock(qe->parent);
        manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
                "Queue: %s\r\n"
                "Uniqueid: %s\r\n"
@@ -3190,7 +3489,7 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
                                                "%s",
                                                qe->parent->name,
                                                qe->chan->uniqueid,
-                                               qe->chan->name,
+                                               ast_channel_name(qe->chan),
                                                interface,
                                                membername,
                                                rnatime,
@@ -3198,6 +3497,20 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
        }
        ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
        if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
+               if (qe->parent->autopausedelay > 0) {
+                       struct member *mem;
+                       ao2_lock(qe->parent);
+                       if ((mem = interface_exists(qe->parent, interface))) {
+                               time_t idletime = time(&idletime)-mem->lastcall;
+                               if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
+                                       ao2_unlock(qe->parent);
+                                       ao2_ref(mem, -1);
+                                       return;
+                               }
+                               ao2_ref(mem, -1);
+                       }
+                       ao2_unlock(qe->parent);
+               }
                if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
                        if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
                                ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
@@ -3261,7 +3574,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
        ast_party_connected_line_init(&connected_caller);
 
        ast_channel_lock(qe->chan);
-       inchan_name = ast_strdupa(qe->chan->name);
+       inchan_name = ast_strdupa(ast_channel_name(qe->chan));
        ast_channel_unlock(qe->chan);
 
        starttime = (long) time(NULL);
@@ -3284,7 +3597,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                if (o->stillgoing) {    /* Keep track of important channels */
                                        stillgoing = 1;
                                        if (o->chan) {
-                                               watchers[pos++] = o->chan;
+                                               if (pos < AST_MAX_WATCHERS) {
+                                                       watchers[pos++] = o->chan;
+                                               }
                                                if (!start)
                                                        start = o;
                                                else
@@ -3323,7 +3638,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                        char ochan_name[AST_CHANNEL_NAME];
                        if (o->chan) {
                                ast_channel_lock(o->chan);
-                               ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
+                               ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
                                ast_channel_unlock(o->chan);
                        }
                        if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
@@ -3332,14 +3647,14 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                        if (update_connectedline) {
                                                if (o->pending_connected_update) {
                                                        if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
-                                                               ast_channel_update_connected_line(in, &o->connected);
+                                                               ast_channel_update_connected_line(in, &o->connected, NULL);
                                                        }
                                                } else if (!o->dial_callerid_absent) {
                                                        ast_channel_lock(o->chan);
-                                                       ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
+                                                       ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
                                                        ast_channel_unlock(o->chan);
                                                        connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-                                                       ast_channel_update_connected_line(in, &connected_caller);
+                                                       ast_channel_update_connected_line(in, &connected_caller, NULL);
                                                        ast_party_connected_line_free(&connected_caller);
                                                }
                                        }
@@ -3387,33 +3702,37 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                        /* Setup parameters */
                                        o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
                                        if (!o->chan) {
-                                               ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
+                                               ast_log(LOG_NOTICE,
+                                                       "Forwarding failed to create channel to dial '%s/%s'\n",
+                                                       tech, stuff);
                                                o->stillgoing = 0;
                                                numnochan++;
                                        } else {
-                                               ast_channel_lock(o->chan);
-                                               while (ast_channel_trylock(in)) {
-                                                       CHANNEL_DEADLOCK_AVOIDANCE(o->chan);
-                                               }
+                                               struct ast_party_redirecting redirecting;
+
+                                               ast_channel_lock_both(o->chan, in);
                                                ast_channel_inherit_variables(in, o->chan);
                                                ast_channel_datastore_inherit(in, o->chan);
 
                                                ast_string_field_set(o->chan, accountcode, in->accountcode);
 
-                                               ast_channel_set_redirecting(o->chan, &original->redirecting);
-                                               if (ast_strlen_zero(o->chan->redirecting.from.number)) {
+                                               ast_channel_set_redirecting(o->chan, &original->redirecting, NULL);
+                                               if (!o->chan->redirecting.from.number.valid
+                                                       || ast_strlen_zero(o->chan->redirecting.from.number.str)) {
                                                        /*
                                                         * The call was not previously redirected so it is
                                                         * now redirected from this number.
                                                         */
-                                                       ast_free(o->chan->redirecting.from.number);
-                                                       o->chan->redirecting.from.number =
+                                                       ast_party_number_free(&o->chan->redirecting.from.number);
+                                                       ast_party_number_init(&o->chan->redirecting.from.number);
+                                                       o->chan->redirecting.from.number.valid = 1;
+                                                       o->chan->redirecting.from.number.str =
                                                                ast_strdup(S_OR(in->macroexten, in->exten));
                                                }
 
-                                               o->chan->cid.cid_tns = in->cid.cid_tns;
+                                               o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
 
-                                               ast_party_caller_copy(&o->chan->cid, &in->cid);
+                                               ast_party_caller_copy(&o->chan->caller, &in->caller);
                                                ast_party_connected_line_copy(&o->chan->connected, &original->connected);
 
                                                /*
@@ -3423,26 +3742,24 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                 * deadlock.  This is why the handling of o->chan's lock may
                                                 * seem a bit unusual here.
                                                 */
+                                               ast_party_redirecting_init(&redirecting);
+                                               ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
                                                ast_channel_unlock(o->chan);
-                                               res = ast_channel_redirecting_macro(o->chan, in, &o->chan->redirecting, 1, 0);
-                                               while (ast_channel_trylock(o->chan)) {
-                                                       CHANNEL_DEADLOCK_AVOIDANCE(in);
-                                               }
+                                               res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0);
                                                if (res) {
-                                                       ast_channel_update_redirecting(in, &o->chan->redirecting);
+                                                       ast_channel_update_redirecting(in, &redirecting, NULL);
                                                }
+                                               ast_party_redirecting_free(&redirecting);
+                                               ast_channel_unlock(in);
 
                                                update_connectedline = 1;
 
-                                               if (ast_call(o->chan, tmpchan, 0)) {
-                                                       ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
-                                                       ast_channel_unlock(o->chan);
+                                               if (ast_call(o->chan, stuff, 0)) {
+                                                       ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
+                                                               tech, stuff);
                                                        do_hang(o);
                                                        numnochan++;
-                                               } else {
-                                                       ast_channel_unlock(o->chan);
                                                }
-                                               ast_channel_unlock(in);
                                        }
                                        /* Hangup the original channel now, in case we needed it */
                                        ast_hangup(winner);
@@ -3459,14 +3776,14 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                                if (update_connectedline) {
                                                                        if (o->pending_connected_update) {
                                                                                if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
-                                                                                       ast_channel_update_connected_line(in, &o->connected);
+                                                                                       ast_channel_update_connected_line(in, &o->connected, NULL);
                                                                                }
                                                                        } else if (!o->dial_callerid_absent) {
                                                                                ast_channel_lock(o->chan);
-                                                                               ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
+                                                                               ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
                                                                                ast_channel_unlock(o->chan);
                                                                                connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-                                                                               ast_channel_update_connected_line(in, &connected_caller);
+                                                                               ast_channel_update_connected_line(in, &connected_caller, NULL);
                                                                                ast_party_connected_line_free(&connected_caller);
                                                                        }
                                                                }
@@ -3488,7 +3805,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                        do_hang(o);
                                                        endtime = (long) time(NULL);
                                                        endtime -= starttime;
-                                                       rna(endtime * 1000, qe, on, membername, 0);
+                                                       rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy);
                                                        if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
                                                                if (qe->parent->timeoutrestart)
                                                                        *to = orig;
@@ -3506,7 +3823,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                                ast_cdr_busy(in->cdr);
                                                        endtime = (long) time(NULL);
                                                        endtime -= starttime;
-                                                       rna(endtime * 1000, qe, on, membername, 0);
+                                                       rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail);
                                                        do_hang(o);
                                                        if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
                                                                if (qe->parent->timeoutrestart)
@@ -3538,7 +3855,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                                ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
                                                                ast_party_connected_line_set_init(&connected, &o->connected);
                                                                ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
-                                                               ast_party_connected_line_set(&o->connected, &connected);
+                                                               ast_party_connected_line_set(&o->connected, &connected, NULL);
                                                                ast_party_connected_line_free(&connected);
                                                                o->pending_connected_update = 1;
                                                        } else {
@@ -3561,7 +3878,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                case AST_CONTROL_REDIRECTING:
                                                        if (!update_connectedline) {
                                                                ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
-                                                       } else {
+                                                       } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
                                                                ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
                                                                if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
                                                                        ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
@@ -3673,10 +3990,10 @@ static int is_our_turn(struct queue_ent *qe)
         * from the front of the queue are valid when autofill is disabled)
         */
        if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
-               ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
+               ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
                res = 1;
        } else {
-               ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
+               ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
                res = 0;
        }
 
@@ -3707,7 +4024,7 @@ static void update_qe_rule(struct queue_ent *qe)
        pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
        qe->max_penalty = max_penalty;
        qe->min_penalty = min_penalty;
-       ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time);
+       ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
        qe->pr = AST_LIST_NEXT(qe->pr, list);
 }
 
@@ -3803,8 +4120,8 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
 
        struct member *mem;
        struct call_queue *qtmp;
-       struct ao2_iterator queue_iter; 
-       
+       struct ao2_iterator queue_iter;
+
        if (shared_lastcall) {
                queue_iter = ao2_iterator_init(queues, 0);
                while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
@@ -3848,7 +4165,8 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 {
        /* disregarding penalty on too few members? */
-       unsigned char usepenalty = (q->membercount <= q->penaltymemberslimit) ? 0 : 1;
+       int membercount = ao2_container_count(q->members);
+       unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
 
        if (usepenalty) {
                if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) ||
@@ -3857,7 +4175,7 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct
                }
        } else {
                ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
-                         q->membercount, q->penaltymemberslimit);
+                         membercount, q->penaltymemberslimit);
        }
 
        switch (q->strategy) {
@@ -3876,6 +4194,7 @@ static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct
                }
                tmp->metric += mem->penalty * 1000000 * usepenalty;
                break;
+       case QUEUE_STRATEGY_RRORDERED:
        case QUEUE_STRATEGY_RRMEMORY:
                if (pos < q->rrpos) {
                        tmp->metric = 1000 + pos;
@@ -3950,7 +4269,7 @@ static void send_agent_complete(const struct queue_ent *qe, const char *queuenam
                "TalkTime: %ld\r\n"
                "Reason: %s\r\n"
                "%s",
-               queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
+               queuename, qe->chan->uniqueid, ast_channel_name(peer), member->interface, member->membername,
                (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
 }
@@ -4070,16 +4389,14 @@ static void end_bridge_callback(void *data)
        struct ast_channel *chan = qeb->chan;
 
        if (ao2_ref(qeb, -1) == 1) {
-               ao2_lock(q);
                set_queue_variables(q, chan);
-               ao2_unlock(q);
                /* This unrefs the reference we made in try_calling when we allocated qeb */
                queue_t_unref(q, "Expire bridge_config reference");
        }
 }
 
 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
- * 
+ *
  * Here is the process of this function
  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
  * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
@@ -4131,7 +4448,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
        char *agiexec = NULL;
        char *macroexec = NULL;
        char *gosubexec = NULL;
-       int ret = 0;
        const char *monitorfilename;
        const char *monitor_exec;
        const char *monitor_options;
@@ -4147,7 +4463,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
        struct ao2_iterator memi;
        struct ast_datastore *datastore, *transfer_ds;
        struct queue_end_bridge *queue_end_bridge = NULL;
-       const int need_weight = use_weight;
 
        ast_channel_lock(qe->chan);
        datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
@@ -4200,10 +4515,10 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
                        break;
                case 'n':
-                       if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR)
+                       if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED)
                                (*tries)++;
                        else
-                               *tries = qe->parent->membercount;
+                               *tries = ao2_container_count(qe->parent->members);
                        *noption = 1;
                        break;
                case 'i':
@@ -4230,12 +4545,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                qe->cancel_answered_elsewhere = 1;
        }
 
-       /* Hold the lock while we setup the outgoing calls */
-       if (need_weight)
-               ao2_lock(queues);
        ao2_lock(qe->parent);
        ast_debug(1, "%s is trying to call a queue member.\n",
-                                                       qe->chan->name);
+                                                       ast_channel_name(qe->chan));
        ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
        if (!ast_strlen_zero(qe->announce))
                announce = qe->announce;
@@ -4251,8 +4563,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        ao2_ref(cur, -1);
                        ao2_unlock(qe->parent);
                        ao2_iterator_destroy(&memi);
-                       if (need_weight)
-                               ao2_unlock(queues);
                        goto out;
                }
                if (!datastore) {
@@ -4260,8 +4570,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                ao2_ref(cur, -1);
                                ao2_unlock(qe->parent);
                                ao2_iterator_destroy(&memi);
-                               if (need_weight)
-                                       ao2_unlock(queues);
                                callattempt_free(tmp);
                                goto out;
                        }
@@ -4270,8 +4578,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                ao2_ref(cur, -1);
                                ao2_unlock(&qe->parent);
                                ao2_iterator_destroy(&memi);
-                               if (need_weight)
-                                       ao2_unlock(queues);
                                callattempt_free(tmp);
                                goto out;
                        }
@@ -4308,8 +4614,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                ao2_ref(cur, -1);
                                ao2_unlock(qe->parent);
                                ao2_iterator_destroy(&memi);
-                               if (need_weight)
-                                       ao2_unlock(queues);
                                callattempt_free(tmp);
                                goto out;
                        }
@@ -4372,8 +4676,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
        ++qe->pending;
        ao2_unlock(qe->parent);
        ring_one(qe, outgoing, &numbusies);
-       if (need_weight)
-               ao2_unlock(queues);
        lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
        /* The ast_channel_datastore_remove() function could fail here if the
         * datastore was moved to another channel during a masquerade. If this is
@@ -4387,8 +4689,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
        }
        ast_channel_unlock(qe->chan);
        ao2_lock(qe->parent);
-       if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
+       if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
                store_next_rr(qe, outgoing);
+
        }
        if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
                store_next_lin(qe, outgoing);
@@ -4405,7 +4708,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        res = digit;
                }
                if (res == -1)
-                       ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
+                       ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
                if (ast_cdr_isset_unanswered()) {
                        /* channel contains the name of one of the outgoing channels
                           in its CDR; zero out this CDR to avoid a dual-posting */
@@ -4472,7 +4775,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        res2 |= ast_autoservice_stop(qe->chan);
                        if (ast_check_hangup(peer)) {
                                /* Agent must have hung up */
-                               ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
+                               ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
                                ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
                                if (qe->parent->eventwhencalled)
                                        manager_event(EVENT_FLAG_AGENT, "AgentDump",
@@ -4482,14 +4785,14 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                                        "Member: %s\r\n"
                                                        "MemberName: %s\r\n"
                                                        "%s",
-                                                       queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
+                                                       queuename, qe->chan->uniqueid, ast_channel_name(peer), member->interface, member->membername,
                                                        qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
                                ast_hangup(peer);
                                ao2_ref(member, -1);
                                goto out;
                        } else if (res2) {
                                /* Caller must have hung up just before being connected*/
-                               ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
+                               ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
                                ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
                                record_abandoned(qe);
                                ast_hangup(peer);
@@ -4503,13 +4806,14 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                else
                        ast_moh_stop(qe->chan);
                /* If appropriate, log that we have a destination channel */
-               if (qe->chan->cdr)
-                       ast_cdr_setdestchan(qe->chan->cdr, peer->name);
+               if (qe->chan->cdr) {
+                       ast_cdr_setdestchan(qe->chan->cdr, ast_channel_name(peer));
+               }
                /* Make sure channels are compatible */
                res = ast_channel_make_compatible(qe->chan, peer);
                if (res < 0) {
                        ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
-                       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
+                       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
                        record_abandoned(qe);
                        ast_cdr_failed(qe->chan->cdr);
                        ast_hangup(peer);
@@ -4542,10 +4846,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        pbx_builtin_setvar_multiple(peer, interfacevar);
                }
        
+               ao2_unlock(qe->parent);
+
                /* try to set queue variables if configured to do so*/
                set_queue_variables(qe->parent, qe->chan);
                set_queue_variables(qe->parent, peer);
-               ao2_unlock(qe->parent);
                
                ast_channel_lock(qe->chan);
                if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
@@ -4583,10 +4888,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                if (mixmonapp) {
                                        ast_debug(1, "Starting MixMonitor as requested.\n");
                                        if (!monitorfilename) {
-                                               if (qe->chan->cdr)
+                                               if (qe->chan->cdr) {
                                                        ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
-                                               else
+                                               } else {
                                                        snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
+                                               }
                                        } else {
                                                const char *m = monitorfilename;
                                                for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
@@ -4653,12 +4959,13 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                        
                                        ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
                                        /* We purposely lock the CDR so that pbx_exec does not update the application data */
-                                       if (qe->chan->cdr)
+                                       if (qe->chan->cdr) {
                                                ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
-                                       ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
-                                       if (qe->chan->cdr)
+                                       }
+                                       pbx_exec(qe->chan, mixmonapp, mixmonargs);
+                                       if (qe->chan->cdr) {
                                                ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
-
+                                       }
                                } else {
                                        ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
                                }
@@ -4736,14 +5043,24 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 
                                gosub_argstart = strchr(gosubexec, ',');
                                if (gosub_argstart) {
+                                       const char *what_is_s = "s";
                                        *gosub_argstart = 0;
-                                       if (asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1) < 0) {
+                                       if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
+                                                ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
+                                               what_is_s = "~~s~~";
+                                       }
+                                       if (asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
                                                ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
                                                gosub_args = NULL;
                                        }
                                        *gosub_argstart = ',';
                                } else {
-                                       if (asprintf(&gosub_args, "%s,s,1", gosubexec) < 0) {
+                                       const char *what_is_s = "s";
+                                       if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
+                                                ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
+                                               what_is_s = "~~s~~";
+                                       }
+                                       if (asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
                                                ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
                                                gosub_args = NULL;
                                        }
@@ -4777,15 +5094,41 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        application = pbx_findapp("agi");
                        if (application) {
                                agiexec = ast_strdupa(agi);
-                               ret = pbx_exec(qe->chan, application, agiexec);
+                               pbx_exec(qe->chan, application, agiexec);
                        } else
                                ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
                }
                qe->handled++;
                ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
                                                                                                        (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
-               if (update_cdr && qe->chan->cdr) 
-                       ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel));
+
+               if (qe->chan->cdr) {
+                       struct ast_cdr *cdr;
+                       struct ast_cdr *newcdr;
+
+                       /* Only work with the last CDR in the stack*/
+                       cdr = qe->chan->cdr;
+                       while (cdr->next) {
+                               cdr = cdr->next;
+                       }
+
+                       /* If this CDR is not related to us add new one*/
+                       if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) &&
+                           (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) &&
+                           (newcdr = ast_cdr_dup(cdr))) {
+                               ast_channel_lock(qe->chan);
+                               ast_cdr_init(newcdr, qe->chan);
+                               ast_cdr_reset(newcdr, 0);
+                               cdr = ast_cdr_append(cdr, newcdr);
+                               cdr = cdr->next;
+                               ast_channel_unlock(qe->chan);
+                       }
+
+                       if (update_cdr) {
+                               ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
+                       }
+               }
+
                if (qe->parent->eventwhencalled)
                        manager_event(EVENT_FLAG_AGENT, "AgentConnect",
                                        "Queue: %s\r\n"
@@ -4797,7 +5140,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                                        "BridgedChannel: %s\r\n"
                                        "Ringtime: %ld\r\n"
                                        "%s",
-                                       queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
+                                       queuename, qe->chan->uniqueid, ast_channel_name(peer), member->interface, member->membername,
                                        (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
                                        qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
                ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
@@ -4846,8 +5189,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 
                                ast_channel_datastore_remove(qe->chan, tds);
                        }
+                       ast_channel_unlock(qe->chan);
                        update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
                } else {
+                       ast_channel_unlock(qe->chan);
+
                        /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
                        send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
                }
@@ -4855,7 +5201,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                if (transfer_ds) {
                        ast_datastore_free(transfer_ds);
                }
-               ast_channel_unlock(qe->chan);
                ast_hangup(peer);
                res = bridge ? bridge : 1;
                ao2_ref(member, -1);
@@ -4883,9 +5228,9 @@ static struct member *interface_exists(struct call_queue *q, const char *interfa
        struct member *mem;
        struct ao2_iterator mem_iter;
 
-       if (!q)
+       if (!q) {
                return NULL;
-
+       }
        mem_iter = ao2_iterator_init(q->members, 0);
        while ((mem = ao2_iterator_next(&mem_iter))) {
                if (!strcasecmp(interface, mem->interface)) {
@@ -4954,25 +5299,25 @@ static void dump_queue_members(struct call_queue *pm_queue)
 static int remove_from_queue(const char *queuename, const char *interface)
 {
        struct call_queue *q, tmpq = {
-               .name = queuename,      
+               .name = queuename,
        };
        struct member *mem, tmpmem;
        int res = RES_NOSUCHQUEUE;
 
        ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
        if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
-               ao2_lock(queues);
                ao2_lock(q);
                if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
                        /* XXX future changes should beware of this assumption!! */
-                       if (!mem->dynamic) {
+                       /*Change Penalty on realtime users*/
+                       if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) {
+                               update_realtime_member_field(mem, q->name, "penalty", "-1");
+                       } else if (!mem->dynamic) {
                                ao2_ref(mem, -1);
                                ao2_unlock(q);
                                queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
-                               ao2_unlock(queues);
                                return RES_NOT_DYNAMIC;
                        }
-                       q->membercount--;
                        manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
                                "Queue: %s\r\n"
                                "Location: %s\r\n"
@@ -4989,7 +5334,6 @@ static int remove_from_queue(const char *queuename, const char *interface)
                        res = RES_EXISTS;
                }
                ao2_unlock(q);
-               ao2_unlock(queues);
                queue_t_unref(q, "Expiring temporary reference");
        }
 
@@ -5011,38 +5355,38 @@ static int add_to_queue(const char *queuename, const char *interface, const char
 
        /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
         * short-circuits if the queue is already in memory. */
-       if (!(q = load_realtime_queue(queuename)))
+       if (!(q = find_load_queue_rt_friendly(queuename))) {
                return res;
-
-       ao2_lock(queues);
+       }
 
        ao2_lock(q);
        if ((old_member = interface_exists(q, interface)) == NULL) {
                if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
                        new_member->dynamic = 1;
                        ao2_link(q->members, new_member);
-                       q->membercount++;
                        manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
                                "Queue: %s\r\n"
                                "Location: %s\r\n"
                                "MemberName: %s\r\n"
+                               "StateInterface: %s\r\n"
                                "Membership: %s\r\n"
                                "Penalty: %d\r\n"
                                "CallsTaken: %d\r\n"
                                "LastCall: %d\r\n"
                                "Status: %d\r\n"
                                "Paused: %d\r\n",
-                               q->name, new_member->interface, new_member->membername,
+                               q->name, new_member->interface, new_member->membername, state_interface,
                                "dynamic",
                                new_member->penalty, new_member->calls, (int) new_member->lastcall,
                                new_member->status, new_member->paused);
-                       
+
                        ao2_ref(new_member, -1);
                        new_member = NULL;
 
-                       if (dump)
+                       if (dump) {
                                dump_queue_members(q);
-                       
+                       }
+
                        res = RES_OKAY;
                } else {
                        res = RES_OUTOFMEMORY;
@@ -5052,7 +5396,7 @@ static int add_to_queue(const char *queuename, const char *interface, const char
                res = RES_EXISTS;
        }
        ao2_unlock(q);
-       ao2_unlock(queues);
+       queue_t_unref(q, "Expiring temporary reference");
 
        return res;
 }
@@ -5083,14 +5427,14 @@ static int set_member_paused(const char *queuename, const char *interface, const
                                if (mem->realtime) {
                                        failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
                                }
-                       
+
                                if (failed) {
                                        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;
-                               }       
+                               }
                                found++;
                                mem->paused = paused;
 
@@ -5098,7 +5442,7 @@ static int set_member_paused(const char *queuename, const char *interface, const
                                        dump_queue_members(q);
 
                                ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
-                               
+
                                if (!ast_strlen_zero(reason)) {
                                        manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
                                                "Queue: %s\r\n"
@@ -5118,13 +5462,13 @@ static int set_member_paused(const char *queuename, const char *interface, const
                                ao2_ref(mem, -1);
                        }
                }
-               
+
                if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
                        ao2_unlock(q);
                        queue_t_unref(q, "Done with iterator");
                        break;
                }
-               
+
                ao2_unlock(q);
                queue_t_unref(q, "Done with iterator");
        }
@@ -5133,64 +5477,113 @@ 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. */
+/*!
+ * \internal
+ * \brief helper function for set_member_penalty - given a queue, sets all member penalties with the interface
+ * \param[in] q queue which is having its member's penalty changed - must be unlocked prior to calling
+ * \param[in] interface String of interface used to search for queue members being changed
+ * \param[in] penalty Value penalty is being changed to for the member.
+ * \retval 0 if the there is no member with interface belonging to q and no change is made
+ * \retval 1 if the there is a member with interface belonging to q and changes are made
+ */
+static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
+{
+       struct member *mem;
+       int foundinterface = 0;
+       char rtpenalty[80];
+
+       ao2_lock(q);
+       if ((mem = interface_exists(q, interface))) {
+               foundinterface++;
+               if (!mem->realtime) {
+                       mem->penalty = penalty;
+               } else {
+                       sprintf(rtpenalty, "%i", penalty);
+                       update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
+               }
+               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_ref(mem, -1);
+       }
+       ao2_unlock(q);
+
+       return foundinterface;
+}
+
+/*!
+ * \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] interface Interface of queue member(s) having priority 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)
 {
        int foundinterface = 0, foundqueue = 0;
        struct call_queue *q;
-       struct member *mem;
+       struct ast_config *queue_config = NULL;
        struct ao2_iterator queue_iter;
 
-       if (penalty < 0) {
+       if (penalty < 0 && !negative_penalty_invalid) {
                ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
                return RESULT_FAILURE;
        }
 
-       queue_iter = ao2_iterator_init(queues, 0);
-       while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
-               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_ref(mem, -1);
+       if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
+               if (ast_check_realtime("queues")) {
+                       char *queuename;
+                       queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
+                       if (queue_config) {
+                               for (queuename = ast_category_browse(queue_config, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(queue_config, queuename)) {
+                                       if ((q = find_load_queue_rt_friendly(queuename))) {
+                                               foundqueue++;
+                                               foundinterface += set_member_penalty_help_members(q, interface, penalty);
+                                       }
+                               }
                        }
                }
-               ao2_unlock(q);
-               queue_t_unref(q, "Done with iterator");
+
+               /* After hitting realtime queues, go back and get the regular ones. */
+               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);
+               }
+
+       } 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);
+               }
        }
-       ao2_iterator_destroy(&queue_iter);
 
        if (foundinterface) {
                return RESULT_SUCCESS;
        } else if (!foundqueue) {
-               ast_log (LOG_ERROR, "Invalid queuename\n"); 
+               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. 
+/* \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 = {
-               .name = queuename,      
+               .name = queuename,
        };
        struct member *mem;
-       
+
        if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
                foundqueue = 1;
                ao2_lock(q);
@@ -5206,10 +5599,11 @@ static int get_member_penalty(char *queuename, char *interface)
        }
 
        /* some useful debuging */
-       if (foundqueue) 
+       if (foundqueue) {
                ast_log (LOG_ERROR, "Invalid queuename\n");
-       else 
+       } else {
                ast_log (LOG_ERROR, "Invalid interface\n");
+       }
 
        return RESULT_FAILURE;
 }
@@ -5232,8 +5626,6 @@ static void reload_queue_members(void)
        struct call_queue *cur_queue;
        char queue_data[PM_MAX_LEN];
 
-       ao2_lock(queues);
-
        /* Each key in 'pm_family' is the name of a queue */
        db_tree = ast_db_gettree(pm_family, NULL);
        for (entry = db_tree; entry; entry = entry->next) {
@@ -5245,10 +5637,11 @@ static void reload_queue_members(void)
                                .name = queue_name,
                        };
                        cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
-               }       
+               }
 
-               if (!cur_queue)
-                       cur_queue = load_realtime_queue(queue_name);
+               if (!cur_queue) {
+                       cur_queue = find_load_queue_rt_friendly(queue_name);
+               }
 
                if (!cur_queue) {
                        /* If the queue no longer exists, remove it from the
@@ -5256,7 +5649,7 @@ static void reload_queue_members(void)
                        ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
                        ast_db_del(pm_family, queue_name);
                        continue;
-               } 
+               }
 
                if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
                        queue_t_unref(cur_queue, "Expire reload reference");
@@ -5304,7 +5697,6 @@ static void reload_queue_members(void)
                queue_t_unref(cur_queue, "Expire reload reference");
        }
 
-       ao2_unlock(queues);
        if (db_tree) {
                ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
                ast_db_freetree(db_tree);
@@ -5388,6 +5780,8 @@ static int rqm_exec(struct ast_channel *chan, const char *data)
 {
        int res=-1;
        char *parse, *temppos = NULL;
+       struct member *mem = NULL;
+
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(queuename);
                AST_APP_ARG(interface);
@@ -5405,7 +5799,7 @@ static int rqm_exec(struct ast_channel *chan, const char *data)
        AST_STANDARD_APP_ARGS(args, parse);
 
        if (ast_strlen_zero(args.interface)) {
-               args.interface = ast_strdupa(chan->name);
+               args.interface = ast_strdupa(ast_channel_name(chan));
                temppos = strrchr(args.interface, '-');
                if (temppos)
                        *temppos = '\0';
@@ -5413,9 +5807,17 @@ static int rqm_exec(struct ast_channel *chan, const char *data)
 
        ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
 
+       if (log_membername_as_agent) {
+               mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
+       }
+
        switch (remove_from_queue(args.queuename, args.interface)) {
        case RES_OKAY:
-               ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
+               if (!mem || ast_strlen_zero(mem->membername)) {
+                       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
+               } else {
+                       ast_queue_log(args.queuename, chan->uniqueid, mem->membername, "REMOVEMEMBER", "%s", "");
+               }
                ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
                pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
                res = 0;
@@ -5437,6 +5839,10 @@ static int rqm_exec(struct ast_channel *chan, const char *data)
                break;
        }
 
+       if (mem) {
+               ao2_ref(mem, -1);
+       }
+
        return res;
 }
 
@@ -5465,7 +5871,7 @@ static int aqm_exec(struct ast_channel *chan, const char *data)
        AST_STANDARD_APP_ARGS(args, parse);
 
        if (ast_strlen_zero(args.interface)) {
-               args.interface = ast_strdupa(chan->name);
+               args.interface = ast_strdupa(ast_channel_name(chan));
                temppos = strrchr(args.interface, '-');
                if (temppos)
                        *temppos = '\0';
@@ -5480,7 +5886,11 @@ static int aqm_exec(struct ast_channel *chan, const char *data)
 
        switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
        case RES_OKAY:
-               ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
+               if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
+                       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
+               } else {
+                       ast_queue_log(args.queuename, chan->uniqueid, args.membername, "ADDMEMBER", "%s", "");
+               }
                ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
                pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
                res = 0;
@@ -5496,7 +5906,7 @@ static int aqm_exec(struct ast_channel *chan, const char *data)
                res = 0;
                break;
        case RES_OUTOFMEMORY:
-               ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
+               ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
                break;
        }
 
@@ -5553,7 +5963,6 @@ static void copy_rules(struct queue_ent *qe, const char *rulename)
                        struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
                        if (!new_pr) {
                                ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
-                               AST_LIST_UNLOCK(&rule_lists);
                                break;
                        }
                        new_pr->time = pr_iter->time;
@@ -5633,10 +6042,10 @@ static int queue_exec(struct ast_channel *chan, const char *data)
        user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
        if (user_priority) {
                if (sscanf(user_priority, "%30d", &prio) == 1) {
-                       ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
+                       ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
                } else {
                        ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
-                               user_priority, chan->name);
+                               user_priority, ast_channel_name(chan));
                        prio = 0;
                }
        } else {
@@ -5648,10 +6057,10 @@ static int queue_exec(struct ast_channel *chan, const char *data)
 
        if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
                if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
-                       ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
+                       ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
                } else {
                        ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
-                               max_penalty_str, chan->name);
+                               max_penalty_str, ast_channel_name(chan));
                        max_penalty = 0;
                }
        } else {
@@ -5660,10 +6069,10 @@ static int queue_exec(struct ast_channel *chan, const char *data)
 
        if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
                if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
-                       ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
+                       ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
                } else {
                        ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
-                               min_penalty_str, chan->name);
+                               min_penalty_str, ast_channel_name(chan));
                        min_penalty = 0;
                }
        } else {
@@ -5706,8 +6115,10 @@ static int queue_exec(struct ast_channel *chan, const char *data)
                set_queue_result(chan, reason);
                return 0;
        }
-       ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", S_OR(args.url, ""),
-               S_OR(chan->cid.cid_num, ""), qe.opos);
+       ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d",
+               S_OR(args.url, ""),
+               S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
+               qe.opos);
        copy_rules(&qe, args.rule);
        qe.pr = AST_LIST_FIRST(&qe.qe_rules);
 check_turns:
@@ -5786,7 +6197,7 @@ check_turns:
                }
 
                /* exit after 'timeout' cycle if 'n' option enabled */
-               if (noption && tries >= qe.parent->membercount) {
+               if (noption && tries >= ao2_container_count(qe.parent->members)) {
                        ast_verb(3, "Exiting on time-out cycle\n");
                        ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
                        record_abandoned(&qe);
@@ -5817,7 +6228,7 @@ check_turns:
                 * of the queue, go and check for our turn again.
                 */
                if (!is_our_turn(&qe)) {
-                       ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
+                       ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
                        goto check_turns;
                }
        }
@@ -5877,7 +6288,7 @@ static int queue_function_var(struct ast_channel *chan, const char *cmd, char *d
 {
        int res = -1;
        struct call_queue *q, tmpq = {
-               .name = data,   
+               .name = data,
        };
 
        char interfacevar[256] = "";
@@ -5916,31 +6327,65 @@ static int queue_function_var(struct ast_channel *chan, const char *cmd, char *d
        return 0;
 }
 
-/*! 
+/*!
+ * \brief Check if a given queue exists
+ *
+ */
+static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+       struct call_queue *q;
+
+       buf[0] = '\0';
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
+               return -1;
+       }
+       q = find_load_queue_rt_friendly(data);
+       snprintf(buf, len, "%d", q != NULL? 1 : 0);
+       if (q) {
+               queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
+       }
+
+       return 0;
+}
+
+/*!
  * \brief Get number either busy / free / ready or total members of a specific queue
- * \retval number of members (busy / free / ready / total)
+ * \brief Get or set member properties penalty / paused / ignorebusy
+ * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy)
  * \retval -1 on error
 */
-static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
        int count = 0;
        struct member *m;
        struct ao2_iterator mem_iter;
        struct call_queue *q;
-       char *option;
+
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(queuename);
+               AST_APP_ARG(option);
+               AST_APP_ARG(interface);
+       );
+       /* Make sure the returned value on error is zero length string. */
+       buf[0] = '\0';
 
        if (ast_strlen_zero(data)) {
-               ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
+               ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd);
                return -1;
        }
 
-       if ((option = strchr(data, ',')))
-               *option++ = '\0';
-       else
-               option = "logged";
-       if ((q = load_realtime_queue(data))) {
+       AST_STANDARD_APP_ARGS(args, data);
+
+       if (args.argc < 2) {
+               ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd);
+               return -1;
+       }
+
+       if ((q = find_load_queue_rt_friendly(args.queuename))) {
                ao2_lock(q);
-               if (!strcasecmp(option, "logged")) {
+               if (!strcasecmp(args.option, "logged")) {
                        mem_iter = ao2_iterator_init(q->members, 0);
                        while ((m = ao2_iterator_next(&mem_iter))) {
                                /* Count the agents who are logged in and presently answering calls */
@@ -5950,7 +6395,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
                                ao2_ref(m, -1);
                        }
                        ao2_iterator_destroy(&mem_iter);
-               } else if (!strcasecmp(option, "free")) {
+               } else if (!strcasecmp(args.option, "free")) {
                        mem_iter = ao2_iterator_init(q->members, 0);
                        while ((m = ao2_iterator_next(&mem_iter))) {
                                /* Count the agents who are logged in and presently answering calls */
@@ -5960,7 +6405,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
                                ao2_ref(m, -1);
                        }
                        ao2_iterator_destroy(&mem_iter);
-               } else if (!strcasecmp(option, "ready")) {
+               } else if (!strcasecmp(args.option, "ready")) {
                        time_t now;
                        time(&now);
                        mem_iter = ao2_iterator_init(q->members, 0);
@@ -5973,22 +6418,117 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
                                ao2_ref(m, -1);
                        }
                        ao2_iterator_destroy(&mem_iter);
-               } else /* must be "count" */
-                       count = q->membercount;
+               } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) {
+                       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") && !ast_strlen_zero(args.interface) &&
+                          ((m = interface_exists(q, args.interface)))) {
+                       count = m->ignorebusy;
+                       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);
+               }
                ao2_unlock(q);
                queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
-       } else
-               ast_log(LOG_WARNING, "queue %s was not found\n", data);
+       } else {
+               ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
+       }
 
        snprintf(buf, len, "%d", count);
 
        return 0;
 }
 
-/*! 
+/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy. */
+static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+       int memvalue;
+       struct call_queue *q;
+       struct member *m;
+       char rtvalue[80];
+
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(queuename);
+               AST_APP_ARG(option);
+               AST_APP_ARG(interface);
+       );
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n");
+               return -1;
+       }
+
+       AST_STANDARD_APP_ARGS(args, data);
+
+       if (args.argc < 3) {
+               ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
+               return -1;
+       }
+
+       if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) {
+               ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n");
+               return -1;
+       }
+
+       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)) {
+                       ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
+                       return -1;
+               }
+       } else if ((q = find_load_queue_rt_friendly(args.queuename))) {
+               ao2_lock(q);
+               if ((m = interface_exists(q, args.interface))) {
+                       sprintf(rtvalue, "%s",(memvalue <= 0) ? "0" : "1");
+                       if (!strcasecmp(args.option, "paused")) {
+                               if (m->realtime) {
+                                       update_realtime_member_field(m, q->name, args.option, rtvalue);
+                               } else {
+                                       m->paused = (memvalue <= 0) ? 0 : 1;
+                               }
+                       } else if (!strcasecmp(args.option, "ignorebusy")) {
+                               if (m->realtime) {
+                                       update_realtime_member_field(m, q->name, args.option, rtvalue);
+                               } else {
+                                       m->ignorebusy = (memvalue <= 0) ? 0 : 1;
+                               }
+                       } else {
+                               ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ignorebusy are valid\n");
+                               ao2_ref(m, -1);
+                               ao2_unlock(q);
+                               ao2_ref(q, -1);
+                               return -1;
+                       }
+                       ao2_ref(m, -1);
+               } else {
+                       ao2_unlock(q);
+                       ao2_ref(q, -1);
+                       ast_log(LOG_ERROR, "Invalid interface for queue\n");
+                       return -1;
+               }
+               ao2_unlock(q);
+               ao2_ref(q, -1);
+        } else {
+               ast_log(LOG_ERROR, "Invalid queue\n");
+               return -1;
+       }
+       return 0;
+}
+
+/*!
  * \brief Get the total number of members in a specific queue (Deprecated)
- * \retval number of members 
- * \retval -1 on error 
+ * \retval number of members
+ * \retval -1 on error
 */
 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
@@ -6008,7 +6548,7 @@ static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, cha
                return -1;
        }
        
-       if ((q = load_realtime_queue(data))) {
+       if ((q = find_load_queue_rt_friendly(data))) {
                ao2_lock(q);
                mem_iter = ao2_iterator_init(q->members, 0);
                while ((m = ao2_iterator_next(&mem_iter))) {
@@ -6021,8 +6561,9 @@ static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, cha
                ao2_iterator_destroy(&mem_iter);
                ao2_unlock(q);
                queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
-       } else
+       } else {
                ast_log(LOG_WARNING, "queue %s was not found\n", data);
+       }
 
        snprintf(buf, len, "%d", count);
 
@@ -6034,12 +6575,12 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char
 {
        int count = 0;
        struct call_queue *q, tmpq = {
-               .name = data,   
+               .name = data,
        };
        struct ast_variable *var = NULL;
 
        buf[0] = '\0';
-       
+
        if (ast_strlen_zero(data)) {
                ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
                return -1;
@@ -6052,7 +6593,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char
                queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
        } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
                /* if the queue is realtime but was not found in memory, this
-                * means that the queue had been deleted from memory since it was 
+                * means that the queue had been deleted from memory since it was
                 * "dead." This means it has a 0 waiting count
                 */
                count = 0;
@@ -6069,7 +6610,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char
 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
        struct call_queue *q, tmpq = {
-               .name = data,   
+               .name = data,
        };
        struct member *m;
 
@@ -6182,6 +6723,11 @@ static int queue_function_memberpenalty_write(struct ast_channel *chan, const ch
        return 0;
 }
 
+static struct ast_custom_function queueexists_function = {
+       .name = "QUEUE_EXISTS",
+       .read = queue_function_exists,
+};
+
 static struct ast_custom_function queuevar_function = {
        .name = "QUEUE_VARIABLES",
        .read = queue_function_var,
@@ -6189,7 +6735,8 @@ static struct ast_custom_function queuevar_function = {
 
 static struct ast_custom_function queuemembercount_function = {
        .name = "QUEUE_MEMBER",
-       .read = queue_function_qac,
+       .read = queue_function_mem_read,
+       .write = queue_function_mem_write,
 };
 
 static struct ast_custom_function queuemembercount_dep = {
@@ -6248,6 +6795,7 @@ static int reload_queue_rules(int reload)
        while ((rulecat = ast_category_browse(cfg, rulecat))) {
                if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
                        AST_LIST_UNLOCK(&rule_lists);
+                       ast_config_destroy(cfg);
                        return AST_MODULE_LOAD_FAILURE;
                } else {
                        ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
@@ -6271,22 +6819,38 @@ static void queue_set_global_params(struct ast_config *cfg)
 {
        const char *general_val = NULL;
        queue_persistent_members = 0;
-       if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
+       if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
                queue_persistent_members = ast_true(general_val);
+       }
        autofill_default = 0;
-       if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
+       if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
                autofill_default = ast_true(general_val);
+       }
        montype_default = 0;
        if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
                if (!strcasecmp(general_val, "mixmonitor"))
                        montype_default = 1;
        }
        update_cdr = 0;
-       if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
+       if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) {
                update_cdr = ast_true(general_val);
+       }
        shared_lastcall = 0;
-       if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
+       if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
                shared_lastcall = ast_true(general_val);
+       }
+       negative_penalty_invalid = 0;
+       if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
+               negative_penalty_invalid = ast_true(general_val);
+       }
+       log_membername_as_agent = 0;
+       if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
+               log_membername_as_agent = ast_true(general_val);
+       }
+       check_state_unknown = 0;
+       if ((general_val = ast_variable_retrieve(cfg, "general", "check_state_unknown"))) {
+               check_state_unknown = ast_true(general_val);
+       }
 }
 
 /*! \brief reload information pertaining to a single member
@@ -6358,8 +6922,6 @@ static void reload_single_member(const char *memberdata, struct call_queue *q)
 
        if (cur) {
                ao2_ref(cur, -1);
-       } else {
-               q->membercount++;
        }
 }
 
@@ -6375,19 +6937,11 @@ static int mark_member_dead(void *obj, void *arg, int flags)
 static int kill_dead_members(void *obj, void *arg, int flags)
 {
        struct member *member = obj;
-       struct call_queue *q = arg;
 
        if (!member->delme) {
-               if (member->dynamic) {
-                       /* dynamic members were not counted toward the member count
-                        * when reloading members from queues.conf, so we do that here
-                        */
-                       q->membercount++;
-               }
                member->status = get_queue_member_status(member);
                return 0;
        } else {
-               q->membercount--;
                return CMP_MATCH;
        }
 }
@@ -6466,7 +7020,6 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask,
                init_queue(q);
        }
        if (member_reload) {
-               q->membercount = 0;
                ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
        }
        for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
@@ -6552,12 +7105,12 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena
 
        /* We've made it here, so it looks like we're doing operations on all queues. */
        ao2_lock(queues);
-       
+
        /* Mark all queues as dead for the moment if we're reloading queues.
         * For clarity, we could just be reloading members, in which case we don't want to mess
         * with the other queue parameters at all*/
        if (queue_reload) {
-               ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
+               ao2_callback(queues, OBJ_NODATA | OBJ_NOLOCK, mark_dead_and_unfound, (char *) queuename);
        }
 
        /* Chug through config file */
@@ -6574,17 +7127,17 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena
        ast_config_destroy(cfg);
        /* Unref all the dead queues if we were reloading queues */
        if (queue_reload) {
-               ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
+               ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_dead_queues, (char *) queuename);
        }
        ao2_unlock(queues);
        return 0;
 }
-  
+
 /*! \brief Facilitates resetting statistics for a queue
  *
  * This function actually does not reset any statistics, but
  * rather finds a call_queue struct which corresponds to the
- * passed-in queue name and passes that structure to the 
+ * passed-in queue name and passes that structure to the
  * clear_queue function. If no queuename is passed in, then
  * all queues will have their statistics reset.
  *
@@ -6661,11 +7214,12 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
        struct ao2_iterator queue_iter;
        struct ao2_iterator mem_iter;
 
-       if (argc != 2 && argc != 3)
+       if (argc != 2 && argc != 3) {
                return CLI_SHOWUSAGE;
+       }
 
        if (argc == 3)  { /* specific queue */
-               if ((q = load_realtime_queue(argv[2]))) {
+               if ((q = find_load_queue_rt_friendly(argv[2]))) {
                        queue_t_unref(q, "Done with temporary pointer");
                }
        } else if (ast_check_realtime("queues")) {
@@ -6676,7 +7230,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
                char *queuename;
                if (cfg) {
                        for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
-                               if ((q = load_realtime_queue(queuename))) {
+                               if ((q = find_load_queue_rt_friendly(queuename))) {
                                        queue_t_unref(q, "Done with temporary pointer");
                                }
                        }
@@ -6695,13 +7249,16 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
                 * queues which have been deleted from realtime but which have not yet
                 * been deleted from the in-core container
                 */
-               if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) {
-                       ao2_unlock(q);
-                       queue_t_unref(q, "Done with iterator");
-                       continue;
-               } else if (q->realtime) {
+               if (q->realtime) {
+                       realtime_queue = find_load_queue_rt_friendly(q->name);
+                       if (!realtime_queue) {
+                               ao2_unlock(q);
+                               queue_t_unref(q, "Done with iterator");
+                               continue;
+                       }
                        queue_t_unref(realtime_queue, "Queue is already in memory");
                }
+
                if (argc == 3 && strcasecmp(q->name, argv[2])) {
                        ao2_unlock(q);
                        queue_t_unref(q, "Done with iterator");
@@ -6721,9 +7278,9 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
                        int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
                        q->callscompleted, q->callsabandoned,sl,q->servicelevel);
                do_print(s, fd, ast_str_buffer(out));
-               if (!ao2_container_count(q->members))
+               if (!ao2_container_count(q->members)) {
                        do_print(s, fd, "   No Members");
-               else {
+               } else {
                        struct member *mem;
 
                        do_print(s, fd, "   Members: ");
@@ -6731,35 +7288,41 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
                        while ((mem = ao2_iterator_next(&mem_iter))) {
                                ast_str_set(&out, 0, "      %s", mem->membername);
                                if (strcasecmp(mem->membername, mem->interface)) {
-                                       ast_str_append(&out, 0, " (%s)", mem->interface);
+                                       ast_str_append(&out, 0, " (%s", mem->interface);
+                                       if (mem->state_interface) {
+                                               ast_str_append(&out, 0, " from %s", mem->state_interface);
+                                       }
+                                       ast_str_append(&out, 0, ")");
                                }
-                               if (mem->penalty)
+                               if (mem->penalty) {
                                        ast_str_append(&out, 0, " with penalty %d", mem->penalty);
+                               }
                                ast_str_append(&out, 0, "%s%s%s (%s)",
                                        mem->dynamic ? " (dynamic)" : "",
                                        mem->realtime ? " (realtime)" : "",
                                        mem->paused ? " (paused)" : "",
                                        ast_devstate2str(mem->status));
-                               if (mem->calls)
+                               if (mem->calls) {
                                        ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
                                                mem->calls, (long) (time(NULL) - mem->lastcall));
-                               else
+                               } else {
                                        ast_str_append(&out, 0, " has taken no calls yet");
+                               }
                                do_print(s, fd, ast_str_buffer(out));
                                ao2_ref(mem, -1);
                        }
                        ao2_iterator_destroy(&mem_iter);
                }
-               if (!q->head)
+               if (!q->head) {
                        do_print(s, fd, "   No Callers");
-               else {
+               } else {
                        struct queue_ent *qe;
                        int pos = 1;
 
                        do_print(s, fd, "   Callers: ");
                        for (qe = q->head; qe; qe = qe->next) {
                                ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
-                                       pos++, qe->chan->name, (long) (now - qe->start) / 60,
+                                       pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
                                        (long) (now - qe->start) % 60, qe->prio);
                                do_print(s, fd, ast_str_buffer(out));
                        }
@@ -6771,10 +7334,11 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
        ao2_iterator_destroy(&queue_iter);
        ao2_unlock(queues);
        if (!found) {
-               if (argc == 3)
+               if (argc == 3) {
                        ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
-               else
+               } else {
                        ast_str_set(&out, 0, "No queues.");
+               }
                do_print(s, fd, ast_str_buffer(out));
        }
        return CLI_SUCCESS;
@@ -6841,9 +7405,15 @@ static int manager_queues_show(struct mansession *s, const struct message *m)
 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
 {
        const char *rule = astman_get_header(m, "Rule");
+       const char *id = astman_get_header(m, "ActionID");
        struct rule_list *rl_iter;
        struct penalty_rule *pr_iter;
 
+       astman_append(s, "Response: Success\r\n");
+       if (!ast_strlen_zero(id)) {
+               astman_append(s, "ActionID: %s\r\n", id);
+       }
+
        AST_LIST_LOCK(&rule_lists);
        AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
                if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
@@ -6857,6 +7427,10 @@ static int manager_queue_rule_show(struct mansession *s, const struct message *m
        }
        AST_LIST_UNLOCK(&rule_lists);
 
+       /*
+        * Two blank lines instead of one because the Response and
+        * ActionID headers used to not be present.
+        */
        astman_append(s, "\r\n\r\n");
 
        return RESULT_SUCCESS;
@@ -6989,6 +7563,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
                                                "Queue: %s\r\n"
                                                "Name: %s\r\n"
                                                "Location: %s\r\n"
+                                               "StateInterface: %s\r\n"
                                                "Membership: %s\r\n"
                                                "Penalty: %d\r\n"
                                                "CallsTaken: %d\r\n"
@@ -6997,7 +7572,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
                                                "Paused: %d\r\n"
                                                "%s"
                                                "\r\n",
-                                               q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
+                                               q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
                                                mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
                                }
                                ao2_ref(mem, -1);
@@ -7013,12 +7588,16 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
                                        "Uniqueid: %s\r\n"
                                        "CallerIDNum: %s\r\n"
                                        "CallerIDName: %s\r\n"
+                                       "ConnectedLineNum: %s\r\n"
+                                       "ConnectedLineName: %s\r\n"
                                        "Wait: %ld\r\n"
                                        "%s"
                                        "\r\n",
-                                       q->name, pos++, qe->chan->name, qe->chan->uniqueid,
-                                       S_OR(qe->chan->cid.cid_num, "unknown"),
-                                       S_OR(qe->chan->cid.cid_name, "unknown"),
+                                       q->name, pos++, ast_channel_name(qe->chan), qe->chan->uniqueid,
+                                       S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
+                                       S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
+                                       S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
+                                       S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
                                        (long) (now - qe->start), idText);
                        }
                }
@@ -7069,7 +7648,11 @@ static int manager_add_queue_member(struct mansession *s, const struct message *
 
        switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
        case RES_OKAY:
-               ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
+               if (ast_strlen_zero(membername) || !log_membername_as_agent) {
+                       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
+               } else {
+                       ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
+               }
                astman_send_ack(s, m, "Added interface to queue");
                break;
        case RES_EXISTS:
@@ -7089,6 +7672,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message *
 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
 {
        const char *queuename, *interface;
+       struct member *mem = NULL;
 
        queuename = astman_get_header(m, "Queue");
        interface = astman_get_header(m, "Interface");
@@ -7098,9 +7682,17 @@ static int manager_remove_queue_member(struct mansession *s, const struct messag
                return 0;
        }
 
+       if (log_membername_as_agent) {
+               mem = find_member_by_queuename_and_interface(queuename, interface);
+       }
+
        switch (remove_from_queue(queuename, interface)) {
        case RES_OKAY:
-               ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
+               if (!mem || ast_strlen_zero(mem->membername)) {
+                       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
+               } else {
+                       ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
+               }
                astman_send_ack(s, m, "Removed interface from queue");
                break;
        case RES_EXISTS:
@@ -7117,6 +7709,10 @@ static int manager_remove_queue_member(struct mansession *s, const struct messag
                break;
        }
 
+       if (mem) {
+               ao2_ref(mem, -1);
+       }
+
        return 0;
 }
 
@@ -7322,7 +7918,11 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as
 
        switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
        case RES_OKAY:
-               ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
+               if (ast_strlen_zero(membername) || !log_membername_as_agent) {
+                       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
+               } else {
+                       ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
+               }
                ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
                return CLI_SUCCESS;
        case RES_EXISTS:
@@ -7390,11 +7990,12 @@ static char *complete_queue_remove_member(const char *line, const char *word, in
 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        const char *queuename, *interface;
+       struct member *mem = NULL;
 
        switch (cmd) {
        case CLI_INIT:
                e->command = "queue remove member";
-               e->usage = 
+               e->usage =
                        "Usage: queue remove member <channel> from <queue>\n"
                        "       Remove a specific channel from a queue.\n";
                return NULL;
@@ -7413,8 +8014,18 @@ static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct
 
        switch (remove_from_queue(queuename, interface)) {
        case RES_OKAY:
-               ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
-               ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
+               if (log_membername_as_agent) {
+                       mem = find_member_by_queuename_and_interface(queuename, interface);
+               }
+               if (!mem || ast_strlen_zero(mem->membername)) {
+                       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
+               } else {
+                       ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
+               }
+               if (mem) {
+                       ao2_ref(mem, -1);
+               }
+               ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
                return CLI_SUCCESS;
        case RES_EXISTS:
                ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
@@ -7762,7 +8373,7 @@ static struct ast_cli_entry cli_queue[] = {
        MEMBER(call_queue, sound_reporthold, AST_DATA_STRING)           \
        MEMBER(call_queue, dead, AST_DATA_BOOLEAN)                      \
        MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN)           \
-       MEMBER(call_queue, ringinuse, AST_DATA_INTEGER)                 \
+       MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN)                 \
        MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN)           \
        MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN)               \
        MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN)          \
@@ -7770,20 +8381,18 @@ static struct ast_cli_entry cli_queue[] = {
        MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN)                   \
        MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN)            \
        MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER)          \
-       MEMBER(call_queue, announceposition, AST_DATA_INTEGER)          \
-       MEMBER(call_queue, strategy, AST_DATA_INTEGER)                  \
        MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN)          \
        MEMBER(call_queue, realtime, AST_DATA_BOOLEAN)                  \
        MEMBER(call_queue, found, AST_DATA_BOOLEAN)                     \
        MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER)     \
-       MEMBER(call_queue, announcefrequency, AST_DATA_INTEGER)         \
-       MEMBER(call_queue, minannouncefrequency, AST_DATA_INTEGER)      \
-       MEMBER(call_queue, periodicannouncefrequency, AST_DATA_INTEGER) \
+       MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS)         \
+       MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS)      \
+       MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS) \
        MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER)       \
        MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER)    \
-       MEMBER(call_queue, roundingseconds, AST_DATA_INTEGER)           \
-       MEMBER(call_queue, holdtime, AST_DATA_INTEGER)                  \
-       MEMBER(call_queue, talktime, AST_DATA_INTEGER)                  \
+       MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS)           \
+       MEMBER(call_queue, holdtime, AST_DATA_SECONDS)                  \
+       MEMBER(call_queue, talktime, AST_DATA_SECONDS)                  \
        MEMBER(call_queue, callscompleted, AST_DATA_INTEGER)            \
        MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER)            \
        MEMBER(call_queue, servicelevel, AST_DATA_INTEGER)              \
@@ -7792,17 +8401,16 @@ static struct ast_cli_entry cli_queue[] = {
        MEMBER(call_queue, montype, AST_DATA_INTEGER)                   \
        MEMBER(call_queue, count, AST_DATA_INTEGER)                     \
        MEMBER(call_queue, maxlen, AST_DATA_INTEGER)                    \
-       MEMBER(call_queue, wrapuptime, AST_DATA_INTEGER)                \
-       MEMBER(call_queue, retry, AST_DATA_INTEGER)                     \
-       MEMBER(call_queue, timeout, AST_DATA_INTEGER)                   \
+       MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS)                \
+       MEMBER(call_queue, retry, AST_DATA_SECONDS)                     \
+       MEMBER(call_queue, timeout, AST_DATA_SECONDS)                   \
        MEMBER(call_queue, weight, AST_DATA_INTEGER)                    \
        MEMBER(call_queue, autopause, AST_DATA_INTEGER)                 \
        MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER)           \
        MEMBER(call_queue, rrpos, AST_DATA_INTEGER)                     \
        MEMBER(call_queue, memberdelay, AST_DATA_INTEGER)               \
        MEMBER(call_queue, autofill, AST_DATA_INTEGER)                  \
-       MEMBER(call_queue, members, AST_DATA_CONTAINER)                 \
-       MEMBER(call_queue, membercount, AST_DATA_INTEGER)
+       MEMBER(call_queue, members, AST_DATA_CONTAINER)
 
 AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE);
 
@@ -7856,19 +8464,12 @@ AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT);
 static void queues_data_provider_get_helper(const struct ast_data_search *search,
        struct ast_data *data_root, struct call_queue *queue)
 {
-       int member_notmatch, caller_notmatch, caller_channel_notmatch;
        struct ao2_iterator im;
        struct member *member;
        struct queue_ent *qe;
-       struct ast_data *data_queue, *data_members = NULL;
+       struct ast_data *data_queue, *data_members = NULL, *enum_node;
        struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
 
-       /* compare the search pattern. */
-       if (ast_data_search_cmp_structure(search, call_queue, queue, "queue")) {
-               /* this doesn't match! continue! */
-               return;
-       }
-
        data_queue = ast_data_add_node(data_root, "queue");
        if (!data_queue) {
                return;
@@ -7876,16 +8477,36 @@ static void queues_data_provider_get_helper(const struct ast_data_search *search
 
        ast_data_add_structure(call_queue, data_queue, queue);
 
-       member_notmatch = ast_data_search_has_condition(search, "queue/members/member");
+       ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
+       ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
+
+       /* announce position */
+       enum_node = ast_data_add_node(data_queue, "announceposition");
+       if (!enum_node) {
+               return;
+       }
+       switch (queue->announceposition) {
+       case ANNOUNCEPOSITION_LIMIT:
+               ast_data_add_str(enum_node, "text", "limit");
+               break;
+       case ANNOUNCEPOSITION_MORE_THAN:
+               ast_data_add_str(enum_node, "text", "more");
+               break;
+       case ANNOUNCEPOSITION_YES:
+               ast_data_add_str(enum_node, "text", "yes");
+               break;
+       case ANNOUNCEPOSITION_NO:
+               ast_data_add_str(enum_node, "text", "no");
+               break;
+       default:
+               ast_data_add_str(enum_node, "text", "unknown");
+               break;
+       }
+       ast_data_add_int(enum_node, "value", queue->announceposition);
+
        /* add queue members */
        im = ao2_iterator_init(queue->members, 0);
        while ((member = ao2_iterator_next(&im))) {
-               /* compare the member structure. */
-               if (!ast_data_search_cmp_structure(search, member, member,
-                                       "queue/members/member")) {
-                       member_notmatch = 0;
-               }
-
                if (!data_members) {
                        data_members = ast_data_add_node(data_queue, "members");
                        if (!data_members) {
@@ -7905,28 +8526,9 @@ static void queues_data_provider_get_helper(const struct ast_data_search *search
                ao2_ref(member, -1);
        }
 
-       if (member_notmatch) {
-               ast_data_remove_node(data_root, data_queue);
-               return;
-       }
-
-       caller_notmatch = ast_data_search_has_condition(search, "queue/callers/caller");
-       caller_channel_notmatch = ast_data_search_has_condition(search,
-               "queue/callers/caller/channel");
        /* include the callers inside the result. */
        if (queue->head) {
                for (qe = queue->head; qe; qe = qe->next) {
-                       /* compare the member structure. */
-                       if (!ast_data_search_cmp_structure(search, queue_ent, qe,
-                                               "queue/callers/caller")) {
-                               caller_notmatch = 0;
-                       }
-
-                       if (!ast_channel_data_cmp_structure(search, qe->chan,
-                               "queue/callers/caller/channel")) {
-                               caller_channel_notmatch = 0;
-                       }
-
                        if (!data_callers) {
                                data_callers = ast_data_add_node(data_queue, "callers");
                                if (!data_callers) {
@@ -7947,12 +8549,12 @@ static void queues_data_provider_get_helper(const struct ast_data_search *search
                                continue;
                        }
 
-                       ast_channel_data_add_structure(data_caller_channel, qe->chan);
+                       ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
                }
        }
 
        /* if this queue doesn't match remove the added queue. */
-       if (caller_notmatch || caller_channel_notmatch) {
+       if (!ast_data_search_match(search, data_queue)) {
                ast_data_remove_node(data_root, data_queue);
        }
 }
@@ -7978,7 +8580,7 @@ static int queues_data_provider_get(const struct ast_data_search *search,
                for (queuename = ast_category_browse(cfg, NULL);
                                !ast_strlen_zero(queuename);
                                queuename = ast_category_browse(cfg, queuename)) {
-                       if ((queue = load_realtime_queue(queuename))) {
+                       if ((queue = find_load_queue_rt_friendly(queuename))) {
                                queue_unref(queue);
                        }
                }
@@ -7989,11 +8591,13 @@ static int queues_data_provider_get(const struct ast_data_search *search,
        i = ao2_iterator_init(queues, 0);
        while ((queue = ao2_iterator_next(&i))) {
                ao2_lock(queue);
-               if (queue->realtime && !(queue_realtime = load_realtime_queue(queue->name))) {
-                       ao2_unlock(queue);
-                       queue_unref(queue);
-                       continue;
-               } else if (queue->realtime) {
+               if (queue->realtime) {
+                       queue_realtime = find_load_queue_rt_friendly(queue->name);
+                       if (!queue_realtime) {
+                               ao2_unlock(queue);
+                               queue_unref(queue);
+                               continue;
+                       }
                        queue_unref(queue_realtime);
                }
 
@@ -8001,6 +8605,7 @@ static int queues_data_provider_get(const struct ast_data_search *search,
                ao2_unlock(queue);
                queue_unref(queue);
        }
+       ao2_iterator_destroy(&i);
 
        return 0;
 }
@@ -8011,7 +8616,7 @@ static const struct ast_data_handler queues_data_provider = {
 };
 
 static const struct ast_data_entry queue_data_providers[] = {
-       AST_DATA_ENTRY("asterisk/application/app_queue/queues", &queues_data_provider),
+       AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
 };
 
 static int unload_module(void)
@@ -8037,6 +8642,7 @@ static int unload_module(void)
        res |= ast_unregister_application(app_upqm);
        res |= ast_unregister_application(app_ql);
        res |= ast_unregister_application(app);
+       res |= ast_custom_function_unregister(&queueexists_function);
        res |= ast_custom_function_unregister(&queuevar_function);
        res |= ast_custom_function_unregister(&queuemembercount_function);
        res |= ast_custom_function_unregister(&queuemembercount_dep);
@@ -8111,6 +8717,7 @@ static int load_module(void)
        res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
        res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
        res |= ast_custom_function_register(&queuevar_function);
+       res |= ast_custom_function_register(&queueexists_function);
        res |= ast_custom_function_register(&queuemembercount_function);
        res |= ast_custom_function_register(&queuemembercount_dep);
        res |= ast_custom_function_register(&queuememberlist_function);
@@ -8135,15 +8742,34 @@ static int load_module(void)
 
 static int reload(void)
 {
-       struct ast_flags mask = {AST_FLAGS_ALL,};
+       struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
        ast_unload_realtime("queue_members");
        reload_handler(1, &mask, NULL);
        return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
+/* \brief Find a member by looking up queuename and interface.
+ * \return Returns a member or NULL if member not found.
+*/
+static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface)
+{
+       struct member *mem = NULL;
+       struct call_queue *q;
+
+       if ((q = find_load_queue_rt_friendly(queuename))) {
+               ao2_lock(q);
+               mem = ao2_find(q->members, interface, OBJ_KEY);
+               ao2_unlock(q);
+               queue_t_unref(q, "Expiring temporary reference.");
+       }
+       return mem;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
                .load = load_module,
                .unload = unload_module,
                .reload = reload,
+               .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
+               .nonoptreq = "res_monitor",
               );