[svn-commits] irroot: branch irroot/asterisk-trunk-quack-queue r345361 - /team/irroot/aster...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Nov 15 06:39:20 CST 2011


Author: irroot
Date: Tue Nov 15 06:39:14 2011
New Revision: 345361

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=345361
Log:
Cleanups / remove QUEUE_MEMBER_COUNT its been deprecated for a while now

Modified:
    team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c

Modified: team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c?view=diff&rev=345361&r1=345360&r2=345361
==============================================================================
--- team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c (original)
+++ team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c Tue Nov 15 06:39:14 2011
@@ -25,17 +25,18 @@
  * \arg Config in \ref Config_qu queues.conf
  *
  * \par Development notes
- * \note 2011-11-01: Made application more thread safe
+ * \note 2011-11-01: Reworked to seperate structures make more thread safe
  *		Distrotech PTY (LTD) (www.distrotech.co.za)
  *		Gregory Nietsky (irroot) <gregory at distrotech.co.za>
  *
  *		Split away from locking queues/queue to having locks per
- *		Queue/Member/Device.
+ *		Queue Data/Member/Device.
  *		Added device state struct to mange device states shared
  *		for multiple members sharing same device.
+ *		Added queue data struct to mange queue data.
  *
  *		Made all functions work with realtime/dynamic/static members.
- *		Added missing CLI/AMI functions for handling callinuse.
+ *		Added missing CLI/AMI functions for handling callinuse (ignorebusy).
  *
  * \note 2004-11-25: Persistent Dynamic Members added by:
  *             NetNation Communications (www.netnation.com)
@@ -117,25 +118,22 @@
  * \par Please read before modifying this file.
  * There are locks which are regularly used
  * throughout this file, the lock
- * for each individual queue, the individual member lock ,
+ * for each individual queue, queue data, the individual member lock ,
  * and the device state lock.
  * there are container locks for the queues list, the member
- * list on each queue and the devices container.
+ * list on each queue the devices container and rules container.
+ * in the queue data struct there is linked lists for the entries in queue.
  * Please be extra careful to always lock in the following order
  *
- * 1) queues container lock (ao2 functions that lock the container)
- * 2) queue lock
- * 3) queue member lock
- * 4) member lock
- * 5) devices container lock
- * 6) member device lock
+ * 1) container lock first
+ * 2) container element
+ *
+ * Never call a function on a container while a element is locked
+ *
  * This order has sort of "evolved" over the lifetime of this
  * application, but it is now in place this way, so please adhere
  * to this order!
  *
- * the only elements that do not require a read lock (ie will not change)
- * the queue name and members container, the member interface and
- * device state_interface as they are never altered after been linked.
  */
 
 /*** DOCUMENTATION
@@ -270,7 +268,6 @@
 			<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>
@@ -312,7 +309,6 @@
 			<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>
@@ -349,7 +345,6 @@
 			<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>
@@ -393,7 +388,6 @@
 			<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>
@@ -434,7 +428,6 @@
 			<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>
@@ -465,7 +458,6 @@
 			<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>
@@ -519,7 +511,6 @@
 			<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>
@@ -575,34 +566,6 @@
 			<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>
-			Count number of members answering a queue.
-		</synopsis>
-		<syntax>
-			<parameter name="queuename" required="true" />
-		</syntax>
-		<description>
-			<para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</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>
@@ -949,22 +912,20 @@
                                                      The default value of 15 provides backwards compatibility */
 #define MAX_QUEUE_BUCKETS 53
 
-#define	RES_OKAY	0		/*!< Action completed */
-#define	RES_EXISTS	(-1)		/*!< Entry already exists */
-#define	RES_OUTOFMEMORY	(-2)		/*!< Out of memory */
-#define	RES_NOSUCHQUEUE	(-3)		/*!< No such queue */
-#define RES_NOT_DYNAMIC (-4)		/*!< Member is not dynamic */
-#define RES_ERROR	(-5)		/*!< Member is mis configured */
+enum member_result {
+	RES_OKAY = 0,			/*!< Action completed */
+	RES_EXISTS = -1,		/*!< Entry already exists */
+	RES_OUTOFMEMORY	= -2,		/*!< Out of memory */
+	RES_NOSUCHQUEUE	= -3,		/*!< No such queue */
+	RES_NOT_DYNAMIC = -4,		/*!< Member is not dynamic */
+	RES_ERROR = -5,			/*!< Member is mis configured */
+};
+
 static char *app = "Queue";
-
 static char *app_aqm = "AddQueueMember" ;
-
 static char *app_rqm = "RemoveQueueMember" ;
-
 static char *app_pqm = "PauseQueueMember" ;
-
 static char *app_upqm = "UnpauseQueueMember" ;
-
 static char *app_ql = "QueueLog" ;
 
 /*! \brief Persistent Members astdb family */
@@ -1037,14 +998,15 @@
 
 struct callattempt {
 	struct ast_channel *chan;                  /*! Channel called */
-	int stillgoing;                            /*! This attempt is valid and active */
 	int metric;                                /*! Metric calculated according to strategy */
 	struct member *member;                     /*! Member assosiated with this attempt */
 	struct ast_party_connected_line connected; /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
+	unsigned int stillgoing:1;                 /*! This attempt is valid and active */
 	unsigned int reserved:1;                   /*! Is this attempt been attempted*/
 	unsigned int active:1;                     /*! Is this attempt active in a call*/
 	unsigned int pending_connected_update:1;   /*! TRUE if caller id is not available for connected line*/
 	unsigned int dial_callerid_absent:1;       /*! TRUE if caller id is not available for connected line */
+	unsigned int watching:1;                   /*! TRUE if callattempt is been watched */
 	struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
@@ -1188,7 +1150,6 @@
 	int strategy:4;
 	unsigned int maskmemberstatus:1;
 	unsigned int realtime:1;
-	unsigned int found:1;
 	unsigned int relativeperiodicannounce:1;
 	unsigned int autopausebusy:1;
 	unsigned int autopauseunavail:1;
@@ -1416,7 +1377,6 @@
 			/* if im active and may not place calls when INUSE im actually BUSY */
 			if ((s->reserved || s->active) && !m->callinuse) {
 				ret = AST_DEVICE_BUSY;
-				break;
 			}
 			break;
 		case AST_DEVICE_NOT_INUSE:
@@ -1444,8 +1404,6 @@
 	struct member *member;
 	struct ao2_iterator mem_iter;
 	struct call_queue *q = qe->parent;
-	int max_penalty = qe->max_penalty;
-	int min_penalty = qe->min_penalty;
 	enum empty_conditions conditions;
 
 	conditions = (join) ? q->joinempty : q->leavewhenempty;
@@ -1457,9 +1415,9 @@
 	mem_iter = ao2_iterator_init(q->data->members, 0);
 	while((member = ao2_iterator_next(&mem_iter))) {
 		ao2_lock(member);
-		if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
+		if ((qe->max_penalty && (member->penalty > qe->max_penalty)) || (qe->min_penalty && (member->penalty < qe->min_penalty))) {
 			if (conditions & QUEUE_EMPTY_PENALTY) {
-				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
+				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, qe->min_penalty, qe->max_penalty);
 				ao2_unlock(member);
 				ao2_ref(member, -1);
 				continue;
@@ -1823,13 +1781,13 @@
 	const struct call_queue *q = data;
 
 	if (m->realtime && m->dead) {
-		ao2_lock(m);
-		if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
+		if (!log_membername_as_agent) {
 			ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
 		} else {
+			ao2_lock(m);
 			ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
-		}
-		ao2_unlock(m);
+			ao2_unlock(m);
+		}
 		return CMP_MATCH;
 	}
 	return 0;
@@ -1939,6 +1897,21 @@
 	return ast_str_case_hash(interface);
 }
 
+/*!
+ * \brief ao2 callback to find callattempt been watched
+ */
+static int callattempt_watched_cb(void *obj, void *arg, const int flags)
+{
+	const struct callattempt *c = obj;
+	const struct callattempt *c1 = arg;
+	const struct member *mem = c1->member;
+	const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
+
+	if (!arg || ast_strlen_zero(interface) || !strcasecmp(interface, c->member->interface)) {
+		return (c->watching) ? CMP_MATCH : 0;
+	}
+	return 0;
+}
 
 /*!
  * \brief ao2 callback to obtain the callattempt with best metric
@@ -2002,7 +1975,6 @@
 	q->autopause = QUEUE_AUTOPAUSE_OFF;
 	q->timeoutpriority = TIMEOUT_PRIORITY_APP;
 	q->autopausedelay = 0;
-	q->found = 1;
 
 	ast_string_field_set(q, sound_next, "queue-youarenext");
 	ast_string_field_set(q, sound_thereare, "queue-thereare");
@@ -2376,6 +2348,11 @@
 	char *rt_uniqueid = NULL, *st_dev = NULL;
 	int dead = 0;
 
+	if (ast_strlen_zero(interface)) {
+		ast_log(AST_LOG_ERROR, "Interface was not specified !!\n");
+		return RES_ERROR;
+	}
+
 	if (!(m = ao2_find(q->data->members, interface, OBJ_KEY))) {
 		if (!(m = ao2_alloc(sizeof(*m), remove_queue_member))) {
 			return RES_OUTOFMEMORY;
@@ -2473,7 +2450,7 @@
 		}
 	}
 
-	if (!dead && !m->device && (!(m->device = create_member_state(st_dev)))) {
+	if (!dead && !m->device && !(m->device = create_member_state(st_dev))) {
 		dead = 1;
 	}
 
@@ -2482,7 +2459,7 @@
 	}
 
 	/*check the uniqueness of the RT uniqueid */
-	if (link && (memtype & QUEUE_ADD_MEMBER_REALTIME) && !dead) {
+	if (!dead && link && (memtype & QUEUE_ADD_MEMBER_REALTIME)) {
 		if (ast_strlen_zero(rt_uniqueid)) {
 			ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(m->membername, interface));
 			dead = 1;
@@ -2503,7 +2480,7 @@
 		int status = get_device_status(m);
 
 		/* i have just been born */
-		if ((ast_strlen_zero(m->membername) || !log_membername_as_agent)) {
+		if (!log_membername_as_agent) {
 			ast_queue_log(q->name, source, m->interface, "ADDMEMBER", "%s", "");
 		} else {
 			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", "");
@@ -2533,7 +2510,7 @@
 		}
 		if (!link) {
 			/* thee was a config error remove this member from container now*/
-			if ((ast_strlen_zero(m->membername) || !log_membername_as_agent)) {
+			if (!log_membername_as_agent) {
 				ast_queue_log(q->name, source, m->interface, "REMOVEMEMBER", "%s", "");
 			} else {
 				ast_queue_log(q->name, source, m->membername, "REMOVEMEMBER", "%s", "");
@@ -2647,8 +2624,9 @@
 
 	ast_string_field_set(q, name, queuename);
 	q->realtime = rt;
-	q->weight = 0;
-	q->found = 0;
+
+	/* Ensure defaults for all parameters not set explicitly. */
+	init_queue(q);
 
 	return q;
 }
@@ -2670,51 +2648,52 @@
 	char tmpbuf[64];	/* Must be longer than the longest queue param name. */
 	int prev_weight = 0;
 	struct ast_variable *queue_vars;
-	struct call_queue *q, *oldq;
-	int found;
+	struct call_queue *oldq;
+	struct call_queue *q = NULL;
 	int reload_queue = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS) : 0;
 	int reload_members = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_MEMBER) : 0;
 	int reload_realtime = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_REALTIME) : 0;
 
-	if ((q = ao2_t_find(queues, queuename, OBJ_KEY, "Look for queue in memory first")) &&
-	    (!q->realtime || !reload_queue)) {
+	/* return if im not realtime or not reloading the queue possibly checking members */
+	if ((oldq = ao2_t_find(queues, queuename, OBJ_KEY, "Look for queue in memory first")) &&
+	    (!oldq->realtime || !(reload_queue || reload_realtime))) {
 		if (reload_members) {
-			rt_load_member_config(q);
-		}
-		return q;
-	}
-
-	if (!reload_realtime && q && !ast_tvzero(q->reload) && ast_tvdiff_sec(ast_tvnow(), q->reload)) {
-		ast_log(AST_LOG_WARNING, "Not reloading queue for next %ld Seconds\n", (long)ast_tvdiff_sec(q->reload, ast_tvnow()));
-		return q;
-	}
-
-	/*! \note The queue is recreated and the existing queue will not change and any
-		users holding a ref to the queue will have no changes applied. */
-
-	/* Check if queue is defined in realtime. */
+			rt_load_member_config(oldq);
+		}
+		return oldq;
+	} else if (!oldq && !(reload_queue || reload_realtime)) {
+		ast_debug(1, "Not loading queue %s at this time\n",queuename);
+		return NULL;
+	}
+
+	/* if im reloading realtime (CLI/AMI) i ignore cache timer */
+	if (!reload_realtime && oldq && !ast_tvzero(oldq->reload) && ast_tvdiff_sec(ast_tvnow(), oldq->reload)) {
+		ast_debug(1, "Not reloading queue %s for next %ld Seconds\n", oldq->name, (long)ast_tvdiff_sec(oldq->reload, ast_tvnow()));
+		return oldq;
+	}
+
+	/* Check if queue is defined in realtime if im reloading */
 	if (!(queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL))) {
-		/* Delete queue from in-core list if it has been deleted in realtime. */
-		if (q) {
-			/*! \note Hmm, can't seem to distinguish a DB failure from a not
-			   found condition... So we might delete an in-core queue
-			   in case of DB failure. */
+		/* Delete queue from in-core list if it has been deleted in realtime.
+		 * ! \note On DB failure the queue will be removed as i cant distinguish a DB failure 
+		 */
+		if (oldq) {
 			ast_debug(1, "Queue %s not found in realtime.\n", queuename);
-			ao2_t_unlink(queues, q, "Unused; removing from container");
-			ao2_t_ref(q, -1, "Queue is dead; can't return it");
+			ao2_t_unlink(queues, oldq, "Unused; removing from container");
+			ao2_t_ref(oldq, -1, "Queue is dead; can't return it");
 		}
 		return NULL;
 	}
 
 	/* Create a new queue if an in-core entry does not exist yet. */
-	if (!q && (!(q = alloc_queue(queuename, 1)))) {
+	if (!oldq && !(q = alloc_queue(queuename, 1))) {
 		ast_variables_destroy(queue_vars);
 		return NULL;
-	} else {
-		found = q->found;
-		prev_weight = q->weight ? 1 : 0;
-
-		oldq = q;
+	} else if (oldq) {
+		prev_weight = oldq->weight ? 1 : 0;
+		/*! \note The queue is recreated and the existing queue will not change and any
+		 *users holding a ref to the queue will have no changes applied.
+		 */
 		if (!(q = alloc_queue(queuename, 1))) {
 			/* i could not allocate new structure return the old one*/
 			ast_log(AST_LOG_WARNING, "Failed to assign new queue object returning unchanged object\n");
@@ -2722,8 +2701,6 @@
 			return oldq;
 		}
 	}
-
-	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
 
 	memset(tmpbuf, 0, sizeof(tmpbuf));
 	for (v = queue_vars; v; v = v->next) {
@@ -2753,7 +2730,6 @@
 	}
 
 	/* update the use_weight value if the queue's has gained or lost a weight */
-	/* Other cases will end up with the proper value for use_weight */
 	if (!q->weight && prev_weight) {
 		ast_atomic_fetchadd_int(&use_weight, -1);
 	} else if (q->weight && !prev_weight) {
@@ -2761,7 +2737,7 @@
 	}
 
 	/* add persistent members to new queue*/
-	if (!found && queue_persistent_members) {
+	if (!oldq && queue_persistent_members) {
 		pm_load_member_config(q);
 	}
 
@@ -2818,36 +2794,34 @@
 
 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
 {
-	struct call_queue *q;
 	struct queue_ent *cur;
 	int res = -1;
 	int pos = 0;
 	int inserted = 0;
 	struct ast_flags qflags = {QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER};
 
-	if (!(q = load_realtime_queue(queuename, &qflags))) {
+	/*obtain a ref for the queue reload realtime settings/members*/
+	if (!(qe->parent = load_realtime_queue(queuename, &qflags))) {
 		return res;
 	}
 
-	qe->parent = q;
-
 	/* This is our one */
-	if ((get_member_status(qe, 1))) {
+	if (get_member_status(qe, 1)) {
 		*reason = QUEUE_JOINEMPTY;
-		ao2_t_ref(q, -1, "Done with realtime queue");
+		ao2_t_ref(qe->parent, -1, "Done with realtime queue");
 		return res;
 	}
 
-	ao2_lock(q->data);
-	if ((*reason == QUEUE_UNKNOWN && q->maxlen && (q->data->count >= q->maxlen)) ||
+	ao2_lock(qe->parent->data);
+	if ((*reason == QUEUE_UNKNOWN && qe->parent->maxlen && (qe->parent->data->count >= qe->parent->maxlen)) ||
 	    (*reason != QUEUE_UNKNOWN)) {
-		ao2_unlock(q->data);
+		ao2_unlock(qe->parent->data);
 		*reason = QUEUE_FULL;
-		ao2_t_ref(q, -1, "Done with realtime queue");
+		ao2_t_ref(qe->parent, -1, "Done with realtime queue");
 
 		return res;
 	}
-	ao2_unlock(q->data);
+	ao2_unlock(qe->parent->data);
 
 
 	/* There's space for us, put us at the right position inside
@@ -2855,8 +2829,8 @@
 	 * Take into account the priority of the calling user */
 	inserted = 0;
 
-	AST_LIST_LOCK(q->data->head);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(q->data->head, cur, next) {
+	AST_LIST_LOCK(qe->parent->data->head);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(qe->parent->data->head, cur, next) {
 		/* We have higher priority than the current user, enter
 		 * before him, after all the other users with priority
 		 * higher or equal to our priority. */
@@ -2883,20 +2857,20 @@
 
 	/* No luck, join at the end of the queue */
 	if (!inserted && qe) {
-		AST_LIST_INSERT_TAIL(q->data->head, qe, next);
+		AST_LIST_INSERT_TAIL(qe->parent->data->head, qe, next);
 		insert_entry(qe, &pos);
 	}
-	AST_LIST_UNLOCK(q->data->head);
+	AST_LIST_UNLOCK(qe->parent->data->head);
 
 	/* pass a ref to the queue rules or this queue*/
 	qe->pr = NULL;
-	if ((qe->rules = ao2_find(rules, q->defaultrule, 0))) {
+	if ((qe->rules = ao2_find(rules, qe->parent->defaultrule, 0))) {
 		int time = 0;
 		ao2_callback_data(qe->rules->rules, OBJ_NODATA | OBJ_MULTIPLE, get_best_rule_cb, &time, &qe->pr);
 	}
 
 	res = 0;
-	ao2_lock(q->data);
+	ao2_lock(qe->parent->data);
 	ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
 		"Channel: %s\r\n"
 		"CallerIDNum: %s\r\n"
@@ -2912,9 +2886,9 @@
 		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->data->count, qe->chan->uniqueid );
-	ao2_unlock(q->data);
-	ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
+		qe->parent->name, qe->pos, qe->parent->data->count, qe->chan->uniqueid );
+	ao2_unlock(qe->parent->data);
+	ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", qe->parent->name, qe->chan->name, qe->pos );
 
 	return res;
 }
@@ -3307,43 +3281,35 @@
 {
 	struct call_queue *q;
 	struct member *mem;
-	int found = 0;
 	int count;
-	int rcount;
+	int res = 0;
 	struct ao2_iterator queue_iter;
-
-	ao2_lock(rq->data);
-	rcount = rq->data->count;
-	ao2_unlock(rq->data);
 
 	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 */
-			ao2_t_ref(q, -1, "Done with iterator");
+		/* don't check myself or queues with  lower weight*/
+		if ((q == rq) || (q->weight <= rq->weight)) {
+			ao2_ref(q, -1);
 			continue;
 		}
-
-		if (count && (mem = interface_exists(q, interface))) {
-			ao2_lock(q->data);
-			count = q->data->count;
-			ao2_unlock(q->data);
-
-			ao2_lock(mem);
-			ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
-			if (q->weight > rq->weight && count >= num_available_members(q)) {
-				ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, count, rq->name, rq->weight, rcount);
-				found = 1;
-			}
-			ao2_unlock(mem);
+		ao2_lock(q->data);
+		count = q->data->count;
+		ao2_unlock(q->data);
+		if (count && (mem = interface_exists(q, interface)) &&
+		    (count >= num_available_members(q))) {
 			ao2_ref(mem, -1);
+			ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d)\n",
+					q->name, q->weight, count, rq->name, rq->weight);
+			ao2_ref(q, -1);
+			res = 1;
+			break;
+		} else if (mem) {
+			ao2_ref(mem, -1);
 		}
 		ao2_ref(q, -1);
-		if (found) {
-			break;
-		}
 	}
 	ao2_iterator_destroy(&queue_iter);
-	return found;
+	return res;
 }
 
 /*! \brief common hangup actions */
@@ -3392,15 +3358,15 @@
 	return vars;
 }
 
-/*! 
+/*!
  * \brief Part 2 of ring_one
  *
  * Does error checking before attempting to request a channel and call a member.
  * This function is only called from ring_one().
  * Failure can occur if:
  * - Priority by another queue
+ * - Member is paused
  * - Wrapup time not expired
- * - Member is paused
  * - Member on call / or is not available for a call
  * - Channel cannot be created by driver
  * - Channel cannot be called by driver
@@ -3415,7 +3381,6 @@
 	char tech[256];
 	char *location;
 	const char *macrocontext, *macroexten;
-	struct mem_state *s;
 	int dstat;
 
 	/* we cannot take this call there is a more urgent call we qualify for */
@@ -3430,8 +3395,7 @@
 	}
 
 	ao2_lock(tmp->member);
-	s = tmp->member->device;
-
+	/* im paused i cannot take this call */
 	if (tmp->member->paused) {
 		ao2_unlock(tmp->member);
 		ast_debug(1, "%s paused, can't receive call\n", tmp->member->interface);
@@ -3473,6 +3437,7 @@
 
 	/* mark device and call entry reserved */
 	if (!tmp->reserved) {
+		struct mem_state *s = tmp->member->device;
 		ao2_lock(s);
 		s->reserved++;
 		ao2_unlock(s);
@@ -3488,17 +3453,16 @@
 	}
 
 	/* 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 (!(tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status))) {
 		if (qe->chan->cdr) {
 			ast_cdr_busy(qe->chan->cdr);
 		}
 		tmp->stillgoing = 0;
 
 		set_queue_member_status(tmp->member);
-		ao2_lock(qe->parent->data->members);
+		ao2_lock(qe->parent->data);
 		qe->parent->data->rrpos++;
-		ao2_unlock(qe->parent->data->members);
+		ao2_unlock(qe->parent->data);
 		qe->linpos++;
 
 		(*busies)++;
@@ -3898,8 +3862,7 @@
 	struct ast_channel *in = qe->chan;
 	long starttime = 0;
 	long endtime = 0;
-	struct ao2_iterator aiter;
-	struct ao2_container *calls;
+	struct ao2_iterator aiter, *calls;
 #ifdef HAVE_EPOLL
 	struct callattempt *epollo;
 #endif
@@ -3924,8 +3887,6 @@
 	ao2_iterator_destroy(&aiter);
 #endif
 
-	calls = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, NULL);
-
 	while (*to && !peer) {
 		int numlines, retry, pos = 1;
 		struct ast_channel *watchers[AST_MAX_WATCHERS];
@@ -3937,13 +3898,9 @@
 			while ((o = ao2_iterator_next(&aiter))) {
 				if (o->stillgoing) {	/* Keep track of important channels */
 					stillgoing = 1;
-					if (o->chan) {
-						if (pos < AST_MAX_WATCHERS) {
-							watchers[pos++] = o->chan;
-						}
-						if (!retry) {
-							ao2_link(calls, o);
-						}
+					if (o->chan && !o->watching && (pos < AST_MAX_WATCHERS)) {
+						watchers[pos++] = o->chan;
+						o->watching = 1;
 					}
 				}
 				numlines++;
@@ -3966,8 +3923,6 @@
 				ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
 			}
 			*to = 0;
-			ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-			ao2_ref(calls, -1);
 			return NULL;
 		}
 
@@ -3975,8 +3930,8 @@
 		winner = ast_waitfor_n(watchers, pos, to);
 
 		/* Service all of the outgoing channels */
-		aiter = ao2_iterator_init(calls, 0);
-		while ((o = ao2_iterator_next(&aiter))) {
+		calls = ao2_find(qe->attempts, NULL, OBJ_MULTIPLE);
+		while (calls && (o = ao2_iterator_next(calls))) {
 			/* We go with a static buffer here instead of using ast_strdupa. Using
 			 * ast_strdupa in a loop like this one can cause a stack overflow
 			 */
@@ -4059,7 +4014,6 @@
 						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);
 
@@ -4267,7 +4221,9 @@
 			}
 			ao2_ref(o, -1);
 		}
-		ao2_iterator_destroy(&aiter);
+		if (calls) {
+			ao2_iterator_destroy(calls);
+		}
 
 		/* If we received an event from the caller, deal with it. */
 		if (winner == in) {
@@ -4281,8 +4237,6 @@
 					}
 					ast_frfree(f);
 				}
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4292,8 +4246,6 @@
 				ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
 				*to = 0;
 				ast_frfree(f);
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4304,8 +4256,6 @@
 				*to = 0;
 				*digit = f->subclass.integer;
 				ast_frfree(f);
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4314,17 +4264,16 @@
 			ast_frfree(f);
 		}
 		if (!*to) {
-			aiter = ao2_iterator_init(calls, AO2_ITERATOR_UNLINK);
-			while ((o = ao2_iterator_next(&aiter))) {
+			calls = ao2_find(qe->attempts, NULL, OBJ_MULTIPLE);
+			while (calls && (o = ao2_iterator_next(calls))) {
 				rna(orig, qe, o, 1);
 				ao2_ref(o, -1);
 			}
-			ao2_iterator_destroy(&aiter);
-		}
-
-		ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-	}
-	ao2_ref(calls, -1);
+			if (calls) {
+				ao2_iterator_destroy(calls);
+			}
+		}
+	}
 
 #ifdef HAVE_EPOLL
 	aiter = ao2_iterator_init(qe->attempts, 0);
@@ -4446,7 +4395,7 @@
 			break;
 		}
 
-		if ((get_member_status(qe, 0))) {
+		if (get_member_status(qe, 0)) {
 			*reason = QUEUE_LEAVEEMPTY;
 			ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)ast_tvdiff_sec(ast_tvnow(), qe->start));
 			leave_queue(qe);
@@ -4509,7 +4458,7 @@
 	int oldtalktime;
 
 	struct member *mem;
-	struct call_queue *qtmp;
+	struct queue_data *qtmp;
 	struct ao2_iterator queue_iter;
 
 	ao2_lock(q->data);
@@ -4523,9 +4472,9 @@
 	ao2_unlock(q->data);
 
 	if (shared_lastcall) {
-		queue_iter = ao2_iterator_init(queues, 0);
+		queue_iter = ao2_iterator_init(qdata, 0);
 		while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
-			if ((mem = ao2_find(qtmp->data->members, member, OBJ_POINTER))) {
+			if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
 				ao2_lock(mem);
 				mem->lastcall = ast_tvnow();
 				mem->calls++;
@@ -4636,8 +4585,9 @@
 		return NULL;
 	}
 
-	tmp->stillgoing = -1;
-	tmp->member = mem;/* Place the reference for cur into callattempt. */
+	tmp->stillgoing = 1;
+	tmp->watching = 0;
+	tmp->member = mem;/* Place the reference for mem into callattempt. */
 	tmp->dial_callerid_absent = 0;
 	tmp->pending_connected_update =0;
 	tmp->metric = metric;
@@ -4819,7 +4769,6 @@
  *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
  *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
  *    during each iteration, we calculate a metric to determine which members should be rung when.
- *
  * 3. Call ring_one to place a call to the appropriate member(s)
  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
@@ -5783,6 +5732,7 @@
 	} else if (!mem->dynamic) {
 		ao2_unlock(mem);
 		ao2_ref(mem, -1);
+		ao2_ref(q, -1);
 		return RES_NOT_DYNAMIC;
 	} else if (mem->dynamic) {
 		reload = 1;
@@ -5793,7 +5743,7 @@
 		"MemberName: %s\r\n",
 		q->name, mem->interface, mem->membername);
 
-	if (log_membername_as_agent && !ast_strlen_zero(mem->membername)) {
+	if (log_membername_as_agent) {
 		ast_queue_log(q->name, source, mem->membername, "REMOVEMEMBER", "%s", "");
 	} else {
 		ast_queue_log(q->name, source, mem->interface, "REMOVEMEMBER", "%s", "");
@@ -6404,7 +6354,7 @@
 	qe.last_periodic_announce_sound = 0;
 	qe.valid_digits = 0;
 
-	qe.attempts = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, NULL);
+	qe.attempts = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, callattempt_watched_cb);
 
 	if (join_queue(args.queuename, &qe, &reason, position)) {
 		ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
@@ -6483,7 +6433,7 @@
 			goto stop;
 		}
 
-		if ((get_member_status(&qe, 0))) {
+		if (get_member_status(&qe, 0)) {
 			record_abandoned(&qe);
 			reason = QUEUE_LEAVEEMPTY;
 			ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)ast_tvdiff_sec(ast_tvnow(), qe.start));
@@ -6686,7 +6636,7 @@
 		if (!strcasecmp(args.option, "logged")) {
 			mem_iter = ao2_iterator_init(q->data->members, 0);
 			while ((m = ao2_iterator_next(&mem_iter))) {
-				/* Count the agents who are logged in and presently answering calls */
+				/* Count the agents who are logged in and reachable */
 				ao2_lock(m);
 				status = get_device_status(m);
 				if ((status != AST_DEVICE_UNAVAILABLE) && (status != AST_DEVICE_INVALID)) {
@@ -6700,7 +6650,7 @@
 			mem_iter = ao2_iterator_init(q->data->members, 0);
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				ao2_lock(m);
-				/* Count the agents who are logged in and presently answering calls */
+				/* Count the agents who are logged in and not presently on calls */
 				status = get_device_status(m);
 				if ((status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
 					count++;
@@ -6713,7 +6663,7 @@
 			mem_iter = ao2_iterator_init(q->data->members, 0);
 			while ((m = ao2_iterator_next(&mem_iter))) {
 				ao2_lock(m);
-				/* Count the agents who are logged in, not paused and not wrapping up */
+				/* Count the agents who are logged in, not on a call, not paused and not wrapping up */
 				status = get_device_status(m);
 				if ((status == AST_DEVICE_NOT_INUSE) && !m->paused &&
 				    !(!ast_tvzero(m->lastcall) && m->lastwrapup &&
@@ -6762,7 +6712,6 @@
 	struct call_queue *q;
 	struct member *m;
 	int ret = 0;
-	int reload = 0;
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(queuename);
@@ -6777,8 +6726,8 @@
 
 	AST_STANDARD_APP_ARGS(args, data);
 
-	if (args.argc < 3) {
-		ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
+	if (args.argc < 2) {
+		ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>[,<interface>])\n");
 		return -1;
 	}
 
@@ -6814,77 +6763,30 @@
 			ast_log(LOG_ERROR, "Invalid member %s queue %s\n", args.interface, args.queuename);
 			return -1;
 		}
+		ao2_lock(m);
 		if (!strcasecmp(args.option, "callinuse")) {
-			ao2_lock(m);
 			m->callinuse = (memvalue) ? 1 : 0;
-			if (m->realtime) {
-				update_realtime_member_field(m, q->name, args.option, value);
-			} else if (m->dynamic) {
-				reload = 1;
-			}
-			ao2_unlock(m);
 		} else {
 			ast_log(LOG_ERROR, "Invalid option, only penalty , paused or callinuse are valid\n");
 			ret = -1;
 		}
+
+		/* update the DB data */
+		if (!ret && m->realtime) {
+			update_realtime_member_field(m, q->name, args.option, value);
+			ao2_unlock(m);
+		} else if (!ret && m->dynamic && queue_persistent_members) {
+			ao2_unlock(m);
+			dump_queue_members(q);
+		}
+
 		ao2_ref(m, -1);
-
-		if (reload && queue_persistent_members) {
-			dump_queue_members(q);
-		}
 		ao2_ref(q, -1);
         } else {
 		ast_log(LOG_ERROR, "Invalid queue\n");
 		return -1;
 	}
 	return ret;
-}
-
-/*!
- * \brief Get the total number of members in a specific queue (Deprecated)
- * \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)
-{
-	int count = 0;
-	int status;
-	struct member *m;
-	struct call_queue *q;
-	struct ao2_iterator mem_iter;
-	static int depflag = 1;
-
-	if (depflag) {
-		depflag = 0;
-		ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
-	}
-
-	if (ast_strlen_zero(data)) {
-		ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
-		return -1;
-	}
-
-	if ((q = load_realtime_queue(data, NULL))) {
-		mem_iter = ao2_iterator_init(q->data->members, 0);
-		while ((m = ao2_iterator_next(&mem_iter))) {
-			ao2_lock(m);
-			/* Count the agents who are logged in and presently answering calls */
-			status = get_device_status(m);
-			if ((status != AST_DEVICE_UNAVAILABLE) && (status != AST_DEVICE_INVALID)) {
-				count++;
-			}
-			ao2_unlock(m);
-			ao2_ref(m, -1);
-		}
-		ao2_iterator_destroy(&mem_iter);
-		ao2_t_ref(q, -1, "Done with temporary reference in QUEUE_MEMBER_COUNT");
-	} else {
-		ast_log(LOG_WARNING, "queue %s was not found\n", data);
-	}
-
-	snprintf(buf, len, "%d", count);
-
-	return 0;
 }
 
 /*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
@@ -6980,6 +6882,8 @@
 	/* Make sure the returned value on error is NULL. */
 	buf[0] = '\0';
 
+	ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_PENALTY has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
+
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
 		return -1;
@@ -7063,11 +6967,6 @@
 	.name = "QUEUE_MEMBER",
 	.read = queue_function_mem_read,
 	.write = queue_function_mem_write,
-};
-
-static struct ast_custom_function queuemembercount_dep = {
-	.name = "QUEUE_MEMBER_COUNT",
-	.read = queue_function_qac_dep,
 };
 
 static struct ast_custom_function queuewaitingcount_function = {
@@ -7290,19 +7189,18 @@
 			 * or we could not alloc a new queue
 			 */
 			return;
-	} else if (queue_reload) {
-		prev_weight = q->weight ? 1 : 0;
+	} else if (q && queue_reload) {
 		oldq = q;
+		prev_weight = oldq->weight ? 1 : 0;
 		if (!(q = alloc_queue(queuename, 1))) {
 			ast_log(AST_LOG_ERROR, "Failed to configure new queue object: reload aborted\n");
 			ao2_ref(oldq, -1);
 			return;
 		}
-	}
-
-	if (queue_reload) {
-		init_queue(q);
 	} else if (!member_reload) {
+		if (q) {
+			ao2_ref(oldq, -1);
+		}
 		ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
 		return;
 	}
@@ -7413,13 +7311,13 @@
 	struct member *m = obj;
 	const struct call_queue *q = data;
 
-	ao2_lock(m);
-	if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
+	if (!log_membername_as_agent) {
 		ast_queue_log(q->name, "SHUTDOWN", m->interface, "REMOVEMEMBER", "%s", "");
 	} else {
+		ao2_lock(m);
 		ast_queue_log(q->name, "SHUTDOWN", m->membername, "REMOVEMEMBER", "%s", "");
-	}
-	ao2_unlock(m);
+		ao2_unlock(m);
+	}
 	return CMP_MATCH;
 }
 
@@ -8128,6 +8026,7 @@
 	}
 	if (!(mem = interface_exists(q, interface))) {
 		astman_send_error(s, m, "Invalid 'Interface'");
+		ao2_ref(q, -1);
 		return 0;
 	}
 
@@ -8899,7 +8798,6 @@
 	MEMBER(call_queue, announceholdtime, 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_SECONDS)		\
 	MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS)	\
@@ -9143,7 +9041,6 @@
 	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);
 	res |= ast_custom_function_unregister(&queuememberlist_function);
 	res |= ast_custom_function_unregister(&queuewaitingcount_function);
 	res |= ast_custom_function_unregister(&queuememberpenalty_function);
@@ -9224,7 +9121,6 @@
 	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);
 	res |= ast_custom_function_register(&queuewaitingcount_function);
 	res |= ast_custom_function_register(&queuememberpenalty_function);




More information about the svn-commits mailing list