[asterisk-commits] irroot: branch irroot/asterisk-trunk-quack-queue r344336 - in /team/irroot/as...
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list