[svn-commits] irroot: branch irroot/asterisk-trunk-quack-queue r344336 - in /team/irroot/as...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Nov 10 11:06:50 CST 2011


Author: irroot
Date: Thu Nov 10 11:06:46 2011
New Revision: 344336

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=344336
Log:
Rename ignorebusy to callinuse
use the pickup macro from run macro on pickup project to detect pickup and not put the memberstate inuse/busy

Modified:
    team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c
    team/irroot/asterisk-trunk-quack-queue/include/asterisk/global_datastores.h
    team/irroot/asterisk-trunk-quack-queue/main/asterisk.exports.in
    team/irroot/asterisk-trunk-quack-queue/main/features.c
    team/irroot/asterisk-trunk-quack-queue/main/global_datastores.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=344336&r1=344335&r2=344336
==============================================================================
--- team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c (original)
+++ team/irroot/asterisk-trunk-quack-queue/apps/app_queue.c Thu Nov 10 11:06:46 2011
@@ -35,7 +35,7 @@
  *		for multiple members sharing same device.
  *
  *		Made all functions work with realtime/dynamic/static members.
- *		Added missing CLI/AMI functions for handling ignorebusy.
+ *		Added missing CLI/AMI functions for handling callinuse.
  *
  * \note 2004-11-25: Persistent Dynamic Members added by:
  *             NetNation Communications (www.netnation.com)
@@ -288,7 +288,7 @@
 			<parameter name="paused" />
 			<parameter name="membername" />
 			<parameter name="stateinterface" />
-			<parameter name="ignorebusy" />
+			<parameter name="callinuse" />
 		</syntax>
 		<description>
 			<para>Dynamically adds interface to an existing queue. If the interface is
@@ -552,8 +552,8 @@
 					<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 name="callinuse">
+						<para>Gets or sets queue member callinuse.</para>
 					</enum>
 				</enumlist>
 			</parameter>
@@ -868,14 +868,14 @@
 		<description>
 		</description>
 	</manager>
-	<manager name="QueueIgnoreBusy" language="en_US">
+	<manager name="QueueCallInuse" language="en_US">
 		<synopsis>
 			Set interface to allow multiple calls
 		</synopsis>
 		<syntax>
 			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
 			<parameter name="Interface" required="true" />
-			<parameter name="IgnoreBusy" required="true" />
+			<parameter name="CallInuse" required="true" />
 			<parameter name="Queue" required="true" />
 		</syntax>
 		<description>
@@ -906,6 +906,23 @@
 	QUEUE_RELOAD_RULES = (1 << 2),
 	QUEUE_RESET_STATS = (1 << 3),
 	QUEUE_RELOAD_REALTIME = (1 << 4),
+};
+
+enum member_type {
+	QUEUE_ADD_MEMBER_STATIC = (1 << 0),
+	QUEUE_ADD_MEMBER_REALTIME = (1 << 1),
+	QUEUE_ADD_MEMBER_DYNAMIC = (1 << 2),
+};
+
+enum callattempt_flags {
+	/*! This attempt is busy dialing a user */
+	QUEUE_MEMBER_RESERVED = (1 << 0),
+	/*! This attempt is bridged */
+	QUEUE_MEMBER_ACTIVE = (1 << 1),
+	/*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
+	QUEUE_ATTEMPT_PENDING_CONNECTED = (1 << 2),
+	/*! TRUE if caller id is not available for connected line */
+	QUEUE_ATTEMPT_CALLERID_ABSENT = (1 << 3),
 };
 
 static const struct strategy {
@@ -949,11 +966,6 @@
 #define	RES_NOSUCHQUEUE	(-3)		/*!< No such queue */
 #define RES_NOT_DYNAMIC (-4)		/*!< Member is not dynamic */
 #define RES_ERROR	(-5)		/*!< Member is mis configured */
-
-#define MEMBER_STATIC		(1 << 0)
-#define MEMBER_REALTIME		(1 << 1)
-#define MEMBER_DYNAMIC		(1 << 2)
-
 static char *app = "Queue";
 
 static char *app_aqm = "AddQueueMember" ;
@@ -1041,11 +1053,8 @@
 	struct member *member;
 	/*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
 	struct ast_party_connected_line connected;
-	/*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
-	unsigned int pending_connected_update:1;
-	/*! TRUE if caller id is not available for connected line */
-	unsigned int dial_callerid_absent:1;
-	unsigned int reserved:1;
+	/*! Attempt flags */
+	unsigned int flags;
 	struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
@@ -1081,7 +1090,17 @@
 struct mem_state {
 	char state_interface[80];            /*!< Technology/Location from which to read devicestate changes */
 	int reserved;                        /*!< This interface is reserved for pending call */
+	int active;                          /*!< This interface is active on a call */
 	int status;                          /*!< Status of queue member */
+};
+
+
+enum member_flags {
+	QUEUE_MEMBER_REALTIME = ( 1 << 0),     /*!< Is this member realtime? */
+	QUEUE_MEMBER_DYNAMIC = ( 1 << 1),      /*!< Is this member dynamic? */
+	QUEUE_MEMBER_DEAD = (1 << 2),          /*!< Used to detect members deleted in realtime */
+	QUEUE_MEMBER_PAUSED = (1 << 3),        /*!< Are we paused (not accepting calls)? */
+	QUEUE_MEMBER_CALLINUSE = ( 1 << 4),    /*!< Are we dynamically added? */
 };
 
 struct member {
@@ -1094,11 +1113,7 @@
 	int calls;                             /*!< Number of calls serviced by this member */
 	struct timeval lastcall;               /*!< When last successful call was hungup */
 	int lastwrapup;                        /*!< Last wrapuptime */
-	unsigned int realtime:1;               /*!< Is this member realtime? */
-	unsigned int paused:1;                 /*!< Are we paused (not accepting calls)? */
-	unsigned int dead:1;                   /*!< Used to detect members deleted in realtime */
-	unsigned int dynamic:1;                /*!< Are we dynamically added? */
-	unsigned int ignorebusy:1;             /*!< Flag to ignore member if the status is not available */
+	unsigned int flags;                    /*!< Member Flags */
 	struct mem_state *device;              /*!< Device information */
 };
 
@@ -1402,7 +1417,9 @@
 	struct mem_state *s = m->device;
 
 	ao2_lock(s);
-	if (s->reserved && ((s->status == AST_DEVICE_NOT_INUSE) || (s->status == AST_DEVICE_UNKNOWN))) {
+	if (s->active && ((s->status == AST_DEVICE_NOT_INUSE) || (s->status == AST_DEVICE_UNKNOWN))) {
+		ret = (ast_test_flag(m, QUEUE_MEMBER_CALLINUSE)) ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
+	} else if (s->reserved && ((s->status == AST_DEVICE_NOT_INUSE) || (s->status == AST_DEVICE_UNKNOWN))) {
 		ret = AST_DEVICE_RINGING;
 	} else {
 		ret = s->status;
@@ -1478,7 +1495,7 @@
 			/* Fall-through */
 		default:
 		default_case:
-			if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
+			if (ast_test_flag(member, QUEUE_MEMBER_PAUSED) && (conditions & QUEUE_EMPTY_PAUSED)) {
 				ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
 				break;
 			} else if ((conditions & QUEUE_EMPTY_WRAPUP) && !ast_tvzero(member->lastcall) && member->lastwrapup && (ast_tvdiff_sec(ast_tvnow(), member->lastcall) <= member->lastwrapup)) {
@@ -1549,9 +1566,13 @@
 				"CallsTaken: %d\r\n"
 				"LastCall: %d\r\n"
 				"Status: %d\r\n"
-				"Paused: %d\r\n",
-				q->name, m->interface, m->membername, s->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
-				m->penalty, m->calls, (int)m->lastcall.tv_sec, s->status, m->paused
+				"Paused: %d\r\n"
+				"CallInuse: %d\r\n",
+				q->name, m->interface, m->membername, s->state_interface, 
+				(ast_test_flag(m, QUEUE_MEMBER_DYNAMIC)) ? "dynamic" : (ast_test_flag(m, QUEUE_MEMBER_REALTIME)) ? "realtime" : "static",
+				m->penalty, m->calls, (int)m->lastcall.tv_sec, s->status, 
+				ast_test_flag(m, QUEUE_MEMBER_PAUSED) ? 1 : 0,
+				ast_test_flag(m, QUEUE_MEMBER_CALLINUSE) ? 1 : 0
 			);
 			ao2_unlock(s);
 			ao2_unlock(m);
@@ -1706,7 +1727,7 @@
 }
 
 /*! \brief Set current state of member querying channel driver or hint state*/
-static void set_queue_member_status(struct member *m)
+static int set_queue_member_status(struct member *m)
 {
 	int status;
 	struct mem_state *s;
@@ -1732,6 +1753,8 @@
 	}
 	ao2_unlock(s);
 	ao2_unlock(m);
+
+	return status;
 }
 
 /*!
@@ -1767,7 +1790,8 @@
 	const struct member *mem2 = arg;
 	const char *uniqueid = (flags & OBJ_POINTER) ? mem2->rt_uniqueid : arg;
 
-	if (mem1->realtime && !mem1->dead && !strcasecmp(mem1->rt_uniqueid, uniqueid)) {
+	if (ast_test_flag(mem1, QUEUE_MEMBER_REALTIME) && !ast_test_flag(mem1, QUEUE_MEMBER_DEAD) &&
+	    !strcasecmp(mem1->rt_uniqueid, uniqueid)) {
 		return CMP_MATCH | CMP_STOP;
 	}
 
@@ -1781,8 +1805,10 @@
 {
 	struct member *member = obj;
 
-	if (member->realtime) {
-		member->dead = 1;
+	if (ast_test_flag(member, QUEUE_MEMBER_REALTIME)) {
+		ao2_lock(member);
+		ast_set_flag(member, QUEUE_MEMBER_DEAD);
+		ao2_unlock(member);
 		return CMP_MATCH;
 	}
 	return 0;
@@ -1796,7 +1822,7 @@
 	struct member *m = obj;
 	const struct call_queue *q = data;
 
-	if (m->dead && m->realtime) {
+	if (ast_test_flag(m, QUEUE_MEMBER_DEAD) && ast_test_flag(m, QUEUE_MEMBER_REALTIME)) {
 		ao2_lock(m);
 		if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
 			ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
@@ -2341,7 +2367,7 @@
  * \retval RES_OUTOFMEMORY queue exists but not enough memory to create member
 */
 static int handle_member_record(struct call_queue *q, const char *interface, struct ast_config *member_config,
-	int memtype, const char* source)
+	enum member_type memtype, const char* source)
 {
 	struct member *m, *rt_m;
 	struct mem_state *s;
@@ -2361,11 +2387,13 @@
 		}
 
 		m->device = NULL;
-		m->penalty = 0;
-		m->paused = 0;
-		m->ignorebusy = 1;
-		m->realtime = (memtype & MEMBER_REALTIME) ? 1 : 0;
-		m->dynamic = (memtype & MEMBER_DYNAMIC) ? 1 : 0;
+		m->flags = 0;
+		ast_set_flag(m, QUEUE_MEMBER_CALLINUSE);
+		if (memtype & QUEUE_ADD_MEMBER_REALTIME) {
+			ast_set_flag(m, QUEUE_MEMBER_REALTIME);
+		} else if (memtype & QUEUE_ADD_MEMBER_DYNAMIC) {
+			ast_set_flag(m, QUEUE_MEMBER_DYNAMIC);
+		}
 		m->calls = 0;
 		m->lastcall = ast_tv(0, 0);
 		m->lastwrapup = 0;
@@ -2374,9 +2402,9 @@
 	} else {
 		ao2_lock(q->data->members);
 
-		if (memtype & MEMBER_DYNAMIC) {
+		if (memtype & QUEUE_ADD_MEMBER_DYNAMIC) {
 			/* dynamic members are the lowest priority and cannot overwrite settings from DB*/
-			if (m->dynamic) {
+			if (ast_test_flag(m, QUEUE_MEMBER_DYNAMIC)) {
 				res = RES_EXISTS;
 			} else {
 				res = RES_NOT_DYNAMIC;
@@ -2384,31 +2412,29 @@
 			ao2_unlock(q->data->members);
 			ao2_ref(m, -1);
 			return res;
-		} else if ((m->realtime || m->dynamic) && (memtype & MEMBER_STATIC)) {
+		} else if ((ast_test_flag(m, QUEUE_MEMBER_DYNAMIC) || ast_test_flag(m, QUEUE_MEMBER_REALTIME)) &&
+			   (memtype & QUEUE_ADD_MEMBER_STATIC)) {
 			/*static members take precedence over all others*/
 			ao2_lock(m);
-			m->dynamic = 0;
-			m->realtime = 0;
+			ast_clear_flag(m, QUEUE_MEMBER_DYNAMIC);
+			ast_clear_flag(m, QUEUE_MEMBER_REALTIME);
 			if (!ast_strlen_zero(m->rt_uniqueid)) {
 				ast_string_field_set(m, rt_uniqueid, NULL);
 			}
-			ao2_unlock(q->data->members);
-		} else if (memtype & MEMBER_REALTIME) {
+		} else if (memtype & QUEUE_ADD_MEMBER_REALTIME) {
 			/* realtime takes precedence over dynamic but not static*/
 			ao2_lock(m);
-			if (m->dynamic) {
-				m->dynamic = 0;
-				m->realtime = 1;
-			} else if (!m->realtime) {
+			if (ast_test_flag(m, QUEUE_MEMBER_DYNAMIC)) {
+				ast_clear_flag(m, QUEUE_MEMBER_DYNAMIC);
+				ast_set_flag(m, QUEUE_MEMBER_REALTIME);
+			} else if (!ast_test_flag(m, QUEUE_MEMBER_REALTIME)) {
 				ao2_unlock(q->data->members);
 				ao2_unlock(m);
 				ao2_ref(m, -1);
 				return RES_EXISTS;
 			}
-			m->dead = 0;
-			ao2_unlock(q->data->members);
+			ast_clear_flag(m, QUEUE_MEMBER_DEAD);
 		} else {
-			ao2_unlock(q->data->members);
 			ao2_lock(m);
 		}
 	}
@@ -2428,10 +2454,22 @@
 				dead = 1;
 			}
 		} else if (!strcasecmp(v->name, "paused")) {
-			m->paused = abs(ast_true(v->value));
-		} else if (!strcasecmp(v->name, "ignorebusy")) {
-			m->ignorebusy = abs(ast_true(v->value));
-		}
+			if (ast_true(v->value)) {
+				ast_set_flag(m, QUEUE_MEMBER_PAUSED);
+			} else {
+				ast_clear_flag(m, QUEUE_MEMBER_PAUSED);
+			}
+		} else if (!strcasecmp(v->name, "callinuse") || !strcasecmp(v->name, "ignorebusy")) {
+			if (ast_true(v->value)) {
+				ast_set_flag(m, QUEUE_MEMBER_CALLINUSE);
+			} else {
+				ast_clear_flag(m, QUEUE_MEMBER_CALLINUSE);
+			}
+		}
+	}
+
+	if (!link) {
+		ao2_unlock(q->data->members);
 	}
 
 	if (ast_strlen_zero(st_dev)) {
@@ -2456,7 +2494,7 @@
 	}
 
 	/*check the uniqueness of the RT uniqueid */
-	if (link && (memtype & MEMBER_REALTIME) && !dead) {
+	if (link && (memtype & QUEUE_ADD_MEMBER_REALTIME) && !dead) {
 		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;
@@ -2480,7 +2518,7 @@
 		} else {
 			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", "");
 		}
-		if (m->dynamic) {
+		if (ast_test_flag(m, QUEUE_MEMBER_DYNAMIC)) {
 			int status = get_device_status(m);
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
 				"Queue: %s\r\n"
@@ -2493,10 +2531,11 @@
 				"LastCall: %d\r\n"
 				"Status: %d\r\n"
 				"Paused: %d\r\n"
-				"IgnoreBusy: %d\r\n",
+				"CallInuse: %d\r\n",
 				q->name, m->interface, m->membername, m->device->state_interface,
 				"dynamic",m->penalty, m->calls, (int)m->lastcall.tv_sec,
-				status, m->paused, m->ignorebusy);
+				status, ast_test_flag(m, QUEUE_MEMBER_PAUSED) ? 1 : 0,
+				ast_test_flag(m, QUEUE_MEMBER_CALLINUSE) ? 1 : 0);
 		}
 		ao2_link(q->data->members, m);
 	} else if (dead) {
@@ -2539,7 +2578,7 @@
 	ao2_callback(q->data->members, OBJ_NODATA | OBJ_MULTIPLE, mark_realtime_member_dead, NULL);
 
 	while ((interface = ast_category_browse(member_config, interface))) {
-		handle_member_record(q, interface, member_config, MEMBER_REALTIME, "REALTIME");
+		handle_member_record(q, interface, member_config, QUEUE_ADD_MEMBER_REALTIME, "REALTIME");
 	}
 	ast_config_destroy(member_config);
 
@@ -2659,16 +2698,13 @@
 		return q;
 	}
 
-	if (!reload_realtime && !ast_tvzero(q->reload) && ast_tvdiff_sec(ast_tvnow(), q->reload)) {
+	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 This will be two separate database transactions, so we might
-	   see queue parameters as they were before another process
-	   changed the queue and member list as it was after the change.
-	   Thus we might see an empty member list when a queue is
-	   deleted. In practise, this is unlikely to cause a problem. */
+	/*! \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. */
 	if (!(queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL))) {
@@ -2694,8 +2730,10 @@
 
 		oldq = q;
 		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");
 			ast_variables_destroy(queue_vars);
-			return NULL;
+			return oldq;
 		}
 	}
 
@@ -3172,13 +3210,20 @@
 static void callattempt_free(void *data)
 {
 	struct callattempt *doomed = data;
+	struct mem_state *s;
 
 	if (doomed->member) {
-		if (doomed->reserved) {
+		if (doomed->flags & (QUEUE_MEMBER_RESERVED | QUEUE_MEMBER_ACTIVE)) {
 			ao2_lock(doomed->member);
-			ao2_lock(doomed->member->device);
-			doomed->member->device->reserved--;
-			ao2_unlock(doomed->member->device);
+			s = doomed->member->device;
+			ao2_lock(s);
+			if (ast_test_flag(doomed, QUEUE_MEMBER_RESERVED)) {
+				s->reserved--;
+			}
+			if (ast_test_flag(doomed, QUEUE_MEMBER_ACTIVE)) {
+				s->active--;
+			}
+			ao2_unlock(s);
 			ao2_unlock(doomed->member);
 		}
 		ao2_ref(doomed->member, -1);
@@ -3187,19 +3232,23 @@
 }
 
 /*! \brief Hang up a list of outgoing calls */
-static void hangupcalls(struct queue_ent *qe, struct ast_channel *exception)
+static void hangupcalls(struct queue_ent *qe, struct callattempt *exception)
 {
 	struct callattempt *outgoing;
 	struct ao2_iterator aiter;
 
-	aiter = ao2_iterator_init(qe->attempts, AO2_ITERATOR_UNLINK);
+	aiter = ao2_iterator_init(qe->attempts, 0);
 	while ((outgoing = ao2_iterator_next(&aiter))) {
 		/* If someone else answered the call we should indicate this in the CANCEL */
 		/* Hangup any existing lines we have open */
-		if (outgoing->chan && (outgoing->chan != exception)) {
-			if (exception || qe->cancel_answered_elsewhere)
+		if (outgoing->chan && (outgoing != exception)) {
+			if (exception || qe->cancel_answered_elsewhere) {
 				ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
+			}
 			ast_hangup(outgoing->chan);
+			ao2_unlink(qe->attempts, outgoing);
+		} else {
+			ao2_unlink(qe->attempts, outgoing);
 		}
 		ast_aoc_destroy_decoded(outgoing->aoc_s_rate_list);
 		ao2_ref(outgoing, -1);
@@ -3227,19 +3276,19 @@
 		switch (get_device_status(mem)) {
 			case AST_DEVICE_INVALID:
 			case AST_DEVICE_UNAVAILABLE:
+			case AST_DEVICE_BUSY:
 				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)) {
+				if ((!q->ringinuse) || (!ast_test_flag(mem, QUEUE_MEMBER_CALLINUSE))) {
 					break;
 				}
 				/* else fall through */
 			case AST_DEVICE_NOT_INUSE:
 			case AST_DEVICE_UNKNOWN:
-				if (!mem->paused) {
+				if (!ast_test_flag(mem, QUEUE_MEMBER_PAUSED)) {
 					avl++;
 				}
 				break;
@@ -3379,48 +3428,63 @@
 	char *location;
 	const char *macrocontext, *macroexten;
 	struct mem_state *s;
-	int paused;
-	int ignorebusy;
 	int dstat;
-	int lastwrapup;
-	struct timeval lastcall;
 
 	ao2_lock(tmp->member);
-	paused = tmp->member->paused;
-	ignorebusy = tmp->member->ignorebusy;
 	s = tmp->member->device;
-	dstat = get_device_status(tmp->member);
-	lastcall = tmp->member->lastcall;
-	lastwrapup = tmp->member->lastwrapup;
+
+	/* on entry here, we know that tmp->chan == NULL */
+	if (ast_test_flag(tmp->member, QUEUE_MEMBER_PAUSED)) {
+		ao2_unlock(tmp->member);
+		ast_debug(1, "%s paused, can't receive call\n", tmp->member->interface);
+		if (qe->chan->cdr) {
+			ast_cdr_busy(qe->chan->cdr);
+		}
+		tmp->stillgoing = 0;
+		return 0;
+	}
+
+	if (tmp->member->lastwrapup && (ast_tvdiff_sec(ast_tvnow(), tmp->member->lastcall) <= tmp->member->lastwrapup)) {
+		ao2_unlock(tmp->member);
+		ast_debug(1, "Wrapuptime not yet expired for %s\n", tmp->member->interface);
+		if (qe->chan->cdr) {
+			ast_cdr_busy(qe->chan->cdr);
+		}
+		tmp->stillgoing = 0;
+		(*busies)++;
+		return 0;
+	}
+
+	if (!qe->parent->ringinuse || !ast_test_flag(tmp->member, QUEUE_MEMBER_CALLINUSE)) {
+		dstat = get_device_status(tmp->member);
+		if ((dstat == AST_DEVICE_NOT_INUSE) || (dstat == AST_DEVICE_UNKNOWN)) {
+			int newstate = set_queue_member_status(tmp->member);
+			if (newstate != dstat) {
+				ast_log(AST_LOG_WARNING, "Device (%s) state changed from %s to %s\n",
+					tmp->member->interface, ast_devstate2str(dstat), ast_devstate2str(newstate));
+				dstat = newstate;
+			}
+		}
+		if ((dstat != AST_DEVICE_NOT_INUSE) && (dstat != AST_DEVICE_UNKNOWN)) {
+			ao2_unlock(tmp->member);
+			ast_debug(1, "%s in use, can't receive call\n", tmp->member->interface);
+			if (qe->chan->cdr) {
+				ast_cdr_busy(qe->chan->cdr);
+			}
+			tmp->stillgoing = 0;
+			(*busies)++;
+			return 0;
+		}
+	}
 
 	/* mark device and call entry reserved */
-	if (!tmp->reserved) {
+	if (!ast_test_flag(tmp, QUEUE_MEMBER_RESERVED)) {
 		ao2_lock(s);
 		s->reserved++;
 		ao2_unlock(s);
-		tmp->reserved = 1;
+		ast_set_flag(tmp, QUEUE_MEMBER_RESERVED);
 	}
 	ao2_unlock(tmp->member);
-
-	/* on entry here, we know that tmp->chan == NULL */
-	if (paused) {
-		ast_debug(1, "%s paused, can't receive call\n", tmp->member->interface);
-		if (qe->chan->cdr) {
-			ast_cdr_busy(qe->chan->cdr);
-		}
-		tmp->stillgoing = 0;
-		return 0;
-	}
-
-	if (lastwrapup && (ast_tvdiff_sec(ast_tvnow(), lastcall) <= lastwrapup)) {
-		ast_debug(1, "Wrapuptime not yet expired for %s\n", tmp->member->interface);
-		if (qe->chan->cdr) {
-			ast_cdr_busy(qe->chan->cdr);
-		}
-		tmp->stillgoing = 0;
-		(*busies)++;
-		return 0;
-	}
 
 	if (use_weight && compare_weight(qe->parent,tmp->member->interface)) {
 		ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->member->interface);
@@ -3432,16 +3496,6 @@
 		return 0;
 	}
 
-	if ((!qe->parent->ringinuse || !ignorebusy) &&
-	    (dstat != AST_DEVICE_NOT_INUSE) && (dstat != AST_DEVICE_UNKNOWN)) {
-		ast_debug(1, "%s in use, can't receive call\n", tmp->member->interface);
-		if (qe->chan->cdr) {
-			ast_cdr_busy(qe->chan->cdr);
-		}
-		tmp->stillgoing = 0;
-		(*busies)++;
-		return 0;
-	}
 
 	ast_copy_string(tech, tmp->member->interface, sizeof(tech));
 	if ((location = strchr(tech, '/'))) {
@@ -3494,7 +3548,7 @@
 		} 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); 
 		}
-		tmp->dial_callerid_absent = 1;
+		ast_set_flag(tmp, QUEUE_ATTEMPT_CALLERID_ABSENT);
 	}
 
 	ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
@@ -3809,6 +3863,7 @@
 			}
 		}
 		if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
+			ao2_lock(qe->parent->data->members);
 			ao2_lock(call->member);
 			if (!(do_set_member_penalty_paused(qe->parent, call->member, 1, 1, "Auto-Pause"))) {
 				ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
@@ -3817,6 +3872,7 @@
 				ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", call->member->interface, qe->parent->name);
 			}
 			ao2_unlock(call->member);
+			ao2_unlock(qe->parent->data->members);
 		} else {
 			/* If queue autopause is mode all, just don't send any queue to stop.
 			* the function will stop in all queues */
@@ -3954,11 +4010,11 @@
 				if (!peer) {
 					ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
 					if (update_connectedline) {
-						if (o->pending_connected_update) {
+						if (ast_test_flag(o, QUEUE_ATTEMPT_PENDING_CONNECTED)) {
 							if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
 								ast_channel_update_connected_line(in, &o->connected, NULL);
 							}
-						} else if (!o->dial_callerid_absent) {
+						} else if (!ast_test_flag(o, QUEUE_ATTEMPT_CALLERID_ABSENT)) {
 							ast_channel_lock(o->chan);
 							ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
 							ast_channel_unlock(o->chan);
@@ -3975,7 +4031,13 @@
 							ast_aoc_destroy_encoded(encoded);
 						}
 					}
-					peer = o;
+					if (!peer || (peer && (peer != o))) {
+						if (peer) {
+							ao2_ref(peer, -1);
+						}
+						ao2_ref(o, 1);
+						peer = o;
+					}
 				}
 			} else if (o->chan && (o->chan == winner)) {
 				if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
@@ -4102,11 +4164,11 @@
 					if (!peer) {
 						ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
 						if (update_connectedline) {
-							if (o->pending_connected_update) {
+							if (ast_test_flag(o, QUEUE_ATTEMPT_PENDING_CONNECTED)) {
 								if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
 									ast_channel_update_connected_line(in, &o->connected, NULL);
 								}
-							} else if (!o->dial_callerid_absent) {
+							} else if (!ast_test_flag(o, QUEUE_ATTEMPT_CALLERID_ABSENT)) {
 								ast_channel_lock(o->chan);
 								ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
 								ast_channel_unlock(o->chan);
@@ -4123,7 +4185,13 @@
 								ast_aoc_destroy_encoded(encoded);
 							}
 						}
-						peer = o;
+						if (!peer || (peer && (peer != o))) {
+							if (peer) {
+								ao2_ref(peer, -1);
+							}
+							ao2_ref(o, 1);
+							peer = o;
+						}
 					}
 					break;
 				case AST_CONTROL_BUSY:
@@ -4185,7 +4253,7 @@
 						ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
 						ast_party_connected_line_set(&o->connected, &connected, NULL);
 						ast_party_connected_line_free(&connected);
-						o->pending_connected_update = 1;
+						ast_set_flag(o, QUEUE_ATTEMPT_PENDING_CONNECTED);
 					} else {
 						if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
 							ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
@@ -4219,6 +4287,7 @@
 				}
 				ast_frfree(f);
 			}
+			/* hold a ref for the answerd line */
 			ao2_ref(o, -1);
 		}
 		ao2_iterator_destroy(&aiter);
@@ -4237,6 +4306,9 @@
 				}
 				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
 				ao2_ref(calls, -1);
+				if (peer) {
+					ao2_ref(peer, -1);
+				}
 				return NULL;
 			}
 			if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
@@ -4245,6 +4317,9 @@
 				ast_frfree(f);
 				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
 				ao2_ref(calls, -1);
+				if (peer) {
+					ao2_ref(peer, -1);
+				}
 				return NULL;
 			}
 			if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
@@ -4254,6 +4329,9 @@
 				ast_frfree(f);
 				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
 				ao2_ref(calls, -1);
+				if (peer) {
+					ao2_ref(peer, -1);
+				}
 				return NULL;
 			}
 			ast_frfree(f);
@@ -4583,7 +4661,7 @@
 
 	tmp->stillgoing = -1;
 	tmp->member = mem;/* Place the reference for cur into callattempt. */
-	tmp->reserved = 0;
+	tmp->flags = 0;
 	tmp->metric = metric;
 
 	return tmp;
@@ -5071,6 +5149,9 @@
 			}
 			ao2_iterator_destroy(&aiter);
 		}
+		if (lpeer) {
+			ao2_ref(lpeer, -1);
+		}
 	} else { /* peer is valid */
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the
@@ -5085,10 +5166,9 @@
 		now = ast_tvnow();
 		recalc_holdtime(qe, ast_tvdiff_sec(now, qe->start));
 		callcompletedinsl = (ast_tvdiff_sec(now, qe->start) <= qe->parent->servicelevel);
+		/* lpeer holds the ref for member and we hold a ref for lpeer */
 		member = lpeer->member;
-		/* Increment the refcount for this member, since we're going to be using it for awhile in here. */
-		ao2_ref(member, 1);
-		hangupcalls(qe, peer);
+		hangupcalls(qe, lpeer);
 		outgoing = NULL;
 		if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
 			int res2;
@@ -5137,7 +5217,7 @@
 							qe->parent->name, qe->chan->uniqueid, peer->name, member->interface, member->membername,
 							qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
 				ao2_unlock(member);
-				ao2_ref(member, -1);
+				ao2_ref(lpeer, -1);
 				ast_hangup(peer);
 				goto out;
 			} else if (res2) {
@@ -5146,8 +5226,8 @@
 				ao2_lock(member);
 				ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)ast_tvdiff_sec(ast_tvnow(), qe->start));
 				ao2_unlock(member);
-				ao2_ref(member, -1);
 				record_abandoned(qe);
+				ao2_ref(lpeer, -1);
 				ast_hangup(peer);
 				return -1;
 			}
@@ -5170,8 +5250,8 @@
 			ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
 			record_abandoned(qe);
 			ast_cdr_failed(qe->chan->cdr);
+			ao2_ref(lpeer, -1);
 			ast_hangup(peer);
-			ao2_ref(member, -1);
 			return -1;
 		}
 
@@ -5186,7 +5266,9 @@
 		if (qe->parent->setinterfacevar) {
 			ao2_lock(member);
 			snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
-				member->interface, member->membername, member->calls, (long)member->lastcall.tv_sec, member->penalty, member->dynamic, member->realtime);
+				member->interface, member->membername, member->calls, (long)member->lastcall.tv_sec, member->penalty,
+				ast_test_flag(member, QUEUE_MEMBER_DYNAMIC),
+				ast_test_flag(member, QUEUE_MEMBER_REALTIME));
 			pbx_builtin_setvar_multiple(qe->chan, interfacevar);
 			pbx_builtin_setvar_multiple(peer, interfacevar);
 			ao2_unlock(member);
@@ -5492,7 +5574,7 @@
 		callstart = ast_tvnow();
 
 		ao2_lock(member);
-		if (qe->parent->eventwhencalled)
+		if (qe->parent->eventwhencalled) {
 			manager_event(EVENT_FLAG_AGENT, "AgentConnect",
 					"Queue: %s\r\n"
 					"Uniqueid: %s\r\n"
@@ -5506,6 +5588,7 @@
 					qe->parent->name, qe->chan->uniqueid, peer->name, member->interface, member->membername,
 					(long)ast_tvdiff_sec(callstart, qe->start), peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
 					qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+		}
 		ao2_unlock(member);
 
 		ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
@@ -5522,6 +5605,27 @@
 			 * are done with it. We remove this reference in end_bridge_callback.
 			 */
 			ao2_t_ref(qe->parent, 1, "For bridge_config reference");
+		}
+
+		ast_channel_lock(peer);
+		if (ast_channel_datastore_find(peer, &pickup_target_info, NULL)) {
+			ast_channel_unlock(peer);
+			ao2_unlink(qe->attempts, lpeer);
+			ao2_ref(member, 1);
+			ao2_ref(lpeer, -1);
+			lpeer = NULL;
+		} else {
+			ast_channel_unlock(peer);
+			ao2_lock(member);
+			ao2_lock(member->device);
+			member->device->active++;
+			ast_set_flag(lpeer, QUEUE_MEMBER_ACTIVE);
+			if (ast_test_flag(lpeer, QUEUE_MEMBER_RESERVED)) {
+				ast_clear_flag(lpeer, QUEUE_MEMBER_RESERVED);
+				member->device->reserved--;
+			}
+			ao2_unlock(member->device);
+			ao2_unlock(member);
 		}
 
 		transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
@@ -5569,9 +5673,14 @@
 		if (transfer_ds) {
 			ast_datastore_free(transfer_ds);
 		}
+		if (lpeer) {
+			ao2_unlink(qe->attempts, lpeer);
+			ao2_ref(lpeer, -1);
+		} else {
+			ao2_ref(member, -1);
+		}
 		ast_hangup(peer);
 		res = bridge ? bridge : 1;
-		ao2_ref(member, -1);
 	}
 out:
 	hangupcalls(qe, NULL);
@@ -5605,7 +5714,7 @@
 			return NULL;
 		}
 		while ((newm = ast_category_browse(mcfg, newm))) {
-			handle_member_record(q, newm, mcfg, MEMBER_REALTIME, "REALTIME");
+			handle_member_record(q, newm, mcfg, QUEUE_ADD_MEMBER_REALTIME, "REALTIME");
 			found ++;
 		}
 		ast_config_destroy(mcfg);
@@ -5618,7 +5727,7 @@
 
 /*! \brief Dump all members in a specific queue to the database
  *
- * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>;<ignorebusy>[|...]
+ * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>;<callinuse>[|...]
  */
 static void dump_queue_members(struct call_queue *pm_queue)
 {
@@ -5636,15 +5745,18 @@
 	mem_iter = ao2_iterator_init(pm_queue->data->members, 0);
 	while ((cur_member = ao2_iterator_next(&mem_iter))) {
 		ao2_lock(cur_member);
-		if (!cur_member->dynamic || cur_member->dead) {
+		if (!ast_test_flag(cur_member, QUEUE_MEMBER_DYNAMIC) ||
+		    ast_test_flag(cur_member, QUEUE_MEMBER_DEAD)) {
 			ao2_unlock(cur_member);
 			ao2_ref(cur_member, -1);
 			continue;
 		}
 
 		res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s;%d",
-			value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused,
-					cur_member->membername, cur_member->device->state_interface, cur_member->ignorebusy);
+			value_len ? "|" : "", cur_member->interface, cur_member->penalty,
+					ast_test_flag(cur_member, QUEUE_MEMBER_PAUSED) ? 1 : 0,
+					cur_member->membername, cur_member->device->state_interface,
+					ast_test_flag(cur_member, QUEUE_MEMBER_CALLINUSE) ? 1 : 0);
 
 		ao2_unlock(cur_member);
 		ao2_ref(cur_member, -1);
@@ -5687,13 +5799,13 @@
 	ao2_lock(mem);
 	/* XXX future changes should beware of this assumption!! */
 	/*Change Penalty on realtime users*/
-	if (mem->realtime && negative_penalty_invalid) {
+	if (ast_test_flag(mem, QUEUE_MEMBER_REALTIME) && negative_penalty_invalid) {
 		update_realtime_member_field(mem, q->name, "penalty", "-1");
-	} else if (!mem->dynamic) {
+	} else if (!ast_test_flag(mem, QUEUE_MEMBER_DYNAMIC)) {
 		ao2_unlock(mem);
 		ao2_ref(mem, -1);
 		return RES_NOT_DYNAMIC;
-	} else if (mem->dynamic) {
+	} else if (ast_test_flag(mem, QUEUE_MEMBER_DYNAMIC)) {
 		reload = 1;
 	}
 	manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
@@ -5721,20 +5833,19 @@
 static int do_set_member_penalty_paused(struct call_queue *q, struct member *mem, int pause, int value, const char *reason)
 {
 	if (pause) {
-		if (mem->paused == value) {
-			ast_debug(1, "%spausing already-%spaused member %s queue %s\n", (mem->paused) ? "" : "un",
-					(mem->paused) ? "" : "un", mem->membername, q->name);
-			return 0;
-		}
-
-		mem->paused = (value) ? 1 : 0;
-		if ((mem->realtime) && (update_realtime_member_field(mem, q->name, "paused", (mem->paused) ? "1" : "0"))) {
+		if (value) {
+			ast_set_flag(mem, QUEUE_MEMBER_PAUSED);
+		} else {
+			ast_clear_flag(mem, QUEUE_MEMBER_PAUSED);
+		}
+		if (ast_test_flag(mem, QUEUE_MEMBER_REALTIME) &&
+		    update_realtime_member_field(mem, q->name, "paused", (value) ? "1" : "0")) {
 			ast_log(LOG_WARNING, "Failed %spausing realtime member %s queue %s\n",
-					(mem->paused) ? "" : "un", mem->membername, q->name);
+					(value) ? "" : "un", mem->membername, q->name);
 			return -1;
 		}
 
-		ast_queue_log(q->name, "NONE", mem->membername, (mem->paused) ? "PAUSE" : "UNPAUSE", "%s", S_OR(reason, ""));
+		ast_queue_log(q->name, "NONE", mem->membername, (value) ? "PAUSE" : "UNPAUSE", "%s", S_OR(reason, ""));
 
 		if (!ast_strlen_zero(reason)) {
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
@@ -5743,18 +5854,18 @@
 				"MemberName: %s\r\n"
 				"Paused: %d\r\n"
 				"Reason: %s\r\n",
-					q->name, mem->interface, mem->membername, mem->paused, reason);
+					q->name, mem->interface, mem->membername, (value) ? 1 : 0, reason);
 		} else {
 			manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
 				"Queue: %s\r\n"
 				"Location: %s\r\n"
 				"MemberName: %s\r\n"
 				"Paused: %d\r\n",
-					q->name, mem->interface, mem->membername, mem->paused);
+					q->name, mem->interface, mem->membername, (value) ? 1 : 0);
 		}
 	} else {
 		mem->penalty = value;
-		if (mem->realtime) {
+		if (ast_test_flag(mem, QUEUE_MEMBER_REALTIME)) {
 			char *rtpenalty;
 			if (!asprintf(&rtpenalty,"%i", mem->penalty) ||
 			    update_realtime_member_field(mem, q->name, "penalty", rtpenalty)) {
@@ -5772,7 +5883,7 @@
 			q->name, mem->interface, mem->penalty);
 	}
 
-	if (mem->dynamic && queue_persistent_members) {
+	if (ast_test_flag(mem, QUEUE_MEMBER_DYNAMIC) && queue_persistent_members) {
 		dump_queue_members(q);
 	}
 
@@ -5795,10 +5906,11 @@
 			ao2_ref(q, -1);
 			return RESULT_FAILURE;
 		}
-
+		ao2_lock(q->data->members);
 		ao2_lock(mem);
 		found = !do_set_member_penalty_paused(q, mem, 1, paused, reason);
 		ao2_unlock(mem);
+		ao2_unlock(q->data->members);
 		ao2_ref(mem, -1);
 		ao2_ref(q, -1);
 		return (!found) ? RESULT_FAILURE : RESULT_SUCCESS;
@@ -5813,11 +5925,13 @@
 	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
 		if ((mem = interface_exists(q, interface))) {
+			ao2_lock(q->data->members);
 			ao2_lock(mem);
 			if (!do_set_member_penalty_paused(q, mem, 1, paused, reason)) {
 				found ++;
 			}
 			ao2_unlock(mem);
+			ao2_unlock(q->data->members);
 			ao2_ref(mem, -1);
 		}
 		ao2_t_ref(q, -1, "Done with iterator");
@@ -5920,11 +6034,11 @@
 		add_var_to_cat(mcat, "paused", strsep(&member, ";"));
 		add_var_to_cat(mcat, "membername", strsep(&member, ";"));
 		add_var_to_cat(mcat, "state_interface", strsep(&member, ";"));
-		add_var_to_cat(mcat, "ignorebusy", strsep(&member, ";"));
+		add_var_to_cat(mcat, "callinuse", strsep(&member, ";"));
 	}
 
 	while ((interface = ast_category_browse(mcfg, interface))) {
-		handle_member_record(q, interface, mcfg, MEMBER_DYNAMIC, "ASTDB");
+		handle_member_record(q, interface, mcfg, QUEUE_ADD_MEMBER_DYNAMIC, "ASTDB");
 	}
 	ast_config_destroy(mcfg);
 }
@@ -6073,11 +6187,11 @@
 		AST_APP_ARG(paused);
 		AST_APP_ARG(membername);
 		AST_APP_ARG(state_interface);
-		AST_APP_ARG(ignorebusy);
+		AST_APP_ARG(callinuse);
 	);
 
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,paused[,membername[,stateinterface[,ignorebusy]]]]])\n");
+		ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,paused[,membername[,stateinterface[,callinuse]]]]])\n");
 		return -1;
 	}
 
@@ -6113,9 +6227,9 @@
 	add_var_to_cat(mcat, "paused", args.paused);
 	add_var_to_cat(mcat, "membername", args.membername);
 	add_var_to_cat(mcat, "state_interface", args.state_interface);
-	add_var_to_cat(mcat, "ignorebusy", args.ignorebusy);
-
-	switch (handle_member_record(q, args.interface, mcfg, MEMBER_DYNAMIC, chan->uniqueid)) {
+	add_var_to_cat(mcat, "callinuse", args.callinuse);
+
+	switch (handle_member_record(q, args.interface, mcfg, QUEUE_ADD_MEMBER_DYNAMIC, chan->uniqueid)) {
 	case RES_OKAY:
 		ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
 		pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
@@ -6229,6 +6343,11 @@
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
+	if (ast_strlen_zero(args.queuename)) {
+		ast_log(AST_LOG_ERROR, "Queuename not specified\n");
+		return -1;
+	}
+
 	/* Setup our queue entry */
 	qe.start = ast_tvnow();
 
@@ -6565,8 +6684,8 @@
 
 /*!
  * \brief Get number either busy / free / ready or total members of a specific queue
- * \brief Get or set member properties penalty / paused / ignorebusy
- * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy)
+ * \brief Get or set member properties penalty / paused / callinuse
+ * \retval number of members (busy / free / ready / total) or member info (penalty / paused / callinuse)
  * \retval -1 on error
 */
 static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
@@ -6612,7 +6731,7 @@
 				ao2_lock(m);
 				/* Count the agents who are logged in and presently answering calls */
 				status = get_device_status(m);
-				if ((status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
+				if ((status == AST_DEVICE_NOT_INUSE) && (!ast_test_flag(m, QUEUE_MEMBER_PAUSED))) {
 					count++;
 				}
 				ao2_unlock(m);
@@ -6625,7 +6744,7 @@
 				ao2_lock(m);
 				/* Count the agents who are logged in, not paused and not wrapping up */
 				status = get_device_status(m);
-				if ((status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
+				if ((status == AST_DEVICE_NOT_INUSE) && (!ast_test_flag(m, QUEUE_MEMBER_PAUSED)) &&
 				    !(!ast_tvzero(m->lastcall) && m->lastwrapup &&
 				      (ast_tvdiff_sec(ast_tvnow(), m->lastcall) <= m->lastwrapup))) {
 					count++;
@@ -6645,13 +6764,13 @@
 		} else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) &&
 			   ((m = interface_exists(q, args.interface)))) {
 			ao2_lock(m);
-			count = m->paused;
+			count = ast_test_flag(m, QUEUE_MEMBER_PAUSED) ? 1 : 0;
 			ao2_unlock(m);
 			ao2_ref(m, -1);
-		} else if (!strcasecmp(args.option, "ignorebusy") && !ast_strlen_zero(args.interface) &&
+		} else if (!strcasecmp(args.option, "callinuse") && !ast_strlen_zero(args.interface) &&
 			   ((m = interface_exists(q, args.interface)))) {
 			ao2_lock(m);
-			count = m->ignorebusy;
+			count = ast_test_flag(m, QUEUE_MEMBER_CALLINUSE) ? 1 : 0;

[... 486 lines stripped ...]



More information about the svn-commits mailing list