aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES9
-rw-r--r--UPGRADE.txt4
-rw-r--r--apps/app_queue.c360
-rw-r--r--configs/queues.conf.sample11
4 files changed, 290 insertions, 94 deletions
diff --git a/CHANGES b/CHANGES
index 1dfadcbf7..2dcc9b5e2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -439,6 +439,15 @@ Queue changes
supports sending the event arguments to 5 individual fields, although it
will fallback to the previous data definition, if the new table layout is
not found.
+ * Added general option negative_penalty_invalid default off. when set
+ members are seen as invalid/logged out when there penalty is negative.
+ for realtime members when set remove from queue will set penalty to -1.
+ * Added queue option autopausedelay when autopause is enabled it will be
+ delayed for this number of seconds since last successful call if there
+ was no prior call the agent will be autopaused immediately.
+ * Added member option ignorebusy this when set and ringinuse is not
+ will allow per member control of multiple calls as ringinuse does for
+ the Queue.
mISDN channel driver (chan_misdn) changes
----------------------------------------
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 3525621d3..dfa85684e 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -50,5 +50,9 @@ pbx_lua:
- the autoservice now defaults to being on by default
- autoservice_start() and autoservice_start() no longer return a value.
+Queue:
+ - Mark QUEUE_MEMBER_PENALTY Deprecated it never worked for realtime members
+ - QUEUE_MEMBER is now R/W supporting setting paused, ignorebusy and penalty.
+
===========================================================
===========================================================
diff --git a/apps/app_queue.c b/apps/app_queue.c
index be929c1dc..b9beafdd5 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -521,11 +521,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="count">
<para>Returns the total number of members for the specified queue.</para>
</enum>
+ <enum name="penalty">
+ <para>Gets or sets queue member penalty.</para>
+ </enum>
+ <enum name="paused">
+ <para>Gets or sets queue member paused status.</para>
+ </enum>
+ <enum name="ignorebusy">
+ <para>Gets or sets queue member ignorebusy.</para>
+ </enum>
</enumlist>
</parameter>
+ <parameter name="interface" required="false" />
</syntax>
<description>
- <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
+ <para>Allows access to queue counts [R] and member information [R/W].</para>
+ <para>
+ <replaceable>queuename</replaceable> is required for all operations
+ <replaceable>interface</replaceable> is required for all member operations.
+ </para>
</description>
<see-also>
<ref type="application">Queue</ref>
@@ -658,6 +672,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</syntax>
<description>
<para>Gets or sets queue members penalty.</para>
+ <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
</description>
<see-also>
<ref type="application">Queue</ref>
@@ -934,6 +949,9 @@ static struct ast_event_sub *device_state_sub;
/*! \brief queues.conf [general] option */
static int update_cdr = 0;
+/*! \brief queues.conf [general] option */
+static int negative_penalty_invalid = 0;
+
enum queue_result {
QUEUE_UNKNOWN = 0,
QUEUE_TIMEOUT = 1,
@@ -1043,6 +1061,7 @@ struct member {
unsigned int dead:1; /*!< Used to detect members deleted in realtime */
unsigned int delme:1; /*!< Flag to delete entry on reload */
char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
+ unsigned int ignorebusy:1; /*!< Flag to ignore member if the status is not available */
};
enum empty_conditions {
@@ -1160,6 +1179,7 @@ struct call_queue {
int timeout; /*!< How long to wait for an answer */
int weight; /*!< Respective weight */
int autopause; /*!< Auto pause queue members if they fail to answer */
+ int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
/* Queue strategy things */
@@ -1190,9 +1210,10 @@ static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
static struct ao2_container *queues;
static void update_realtime_members(struct call_queue *q);
+static struct member *interface_exists(struct call_queue *q, const char *interface);
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
-static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
/*! \brief sets the QUEUESTATUS channel variable */
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
{
@@ -1698,6 +1719,7 @@ static void init_queue(struct call_queue *q)
q->numperiodicannounce = 0;
q->autopause = QUEUE_AUTOPAUSE_OFF;
q->timeoutpriority = TIMEOUT_PRIORITY_APP;
+ q->autopausedelay = 0;
if (!q->members) {
if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED)
/* linear strategy depends on order, so we have to place all members in a single bucket */
@@ -2003,6 +2025,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
q->montype = 1;
} else if (!strcasecmp(param, "autopause")) {
q->autopause = autopause2int(val);
+ } else if (!strcasecmp(param, "autopausedelay")) {
+ q->autopausedelay = atoi(val);
} else if (!strcasecmp(param, "maxlen")) {
q->maxlen = atoi(val);
if (q->maxlen < 0)
@@ -2081,7 +2105,9 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc
int penalty = 0;
int paused = 0;
int found = 0;
+ int ignorebusy = 0;
+ const char *config_val;
const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
@@ -2095,8 +2121,11 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc
if (penalty_str) {
penalty = atoi(penalty_str);
- if (penalty < 0)
+ if ((penalty < 0) && negative_penalty_invalid) {
+ return;
+ } else if (penalty < 0) {
penalty = 0;
+ }
}
if (paused_str) {
@@ -2105,31 +2134,39 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc
paused = 0;
}
- /* Find member by realtime uniqueid and update */
- mem_iter = ao2_iterator_init(q->members, 0);
- while ((m = ao2_iterator_next(&mem_iter))) {
- if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
- m->dead = 0; /* Do not delete this one. */
- ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
- if (paused_str)
- m->paused = paused;
- if (strcasecmp(state_interface, m->state_interface)) {
- ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
- }
- m->penalty = penalty;
- found = 1;
- ao2_ref(m, -1);
- break;
- }
- ao2_ref(m, -1);
- }
+ if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy"))) {
+ ignorebusy = ast_true(config_val);
+ } else {
+ ignorebusy = 1;
+ }
+
+ /* Find member by realtime uniqueid and update */
+ mem_iter = ao2_iterator_init(q->members, 0);
+ while ((m = ao2_iterator_next(&mem_iter))) {
+ if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
+ m->dead = 0; /* Do not delete this one. */
+ ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
+ if (paused_str)
+ m->paused = paused;
+ if (strcasecmp(state_interface, m->state_interface)) {
+ ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+ }
+ m->penalty = penalty;
+ m->ignorebusy = ignorebusy;
+ found = 1;
+ ao2_ref(m, -1);
+ break;
+ }
+ ao2_ref(m, -1);
+ }
ao2_iterator_destroy(&mem_iter);
- /* Create a new member */
- if (!found) {
+ /* Create a new member */
+ if (!found) {
if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
m->dead = 0;
m->realtime = 1;
+ m->ignorebusy = ignorebusy;
ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
ao2_link(q->members, m);
@@ -2873,16 +2910,24 @@ static int num_available_members(struct call_queue *q)
mem_iter = ao2_iterator_init(q->members, 0);
while ((mem = ao2_iterator_next(&mem_iter))) {
switch (mem->status) {
- case AST_DEVICE_INUSE:
- if (!q->ringinuse)
+ case AST_DEVICE_INVALID:
+ case AST_DEVICE_UNAVAILABLE:
+ break;
+ case AST_DEVICE_INUSE:
+ case AST_DEVICE_BUSY:
+ case AST_DEVICE_RINGING:
+ case AST_DEVICE_RINGINUSE:
+ case AST_DEVICE_ONHOLD:
+ if ((!q->ringinuse) || (!mem->ignorebusy)) {
+ break;
+ }
+ /* else fall through */
+ case AST_DEVICE_NOT_INUSE:
+ case AST_DEVICE_UNKNOWN:
+ if (!mem->paused) {
+ avl++;
+ }
break;
- /* else fall through */
- case AST_DEVICE_NOT_INUSE:
- case AST_DEVICE_UNKNOWN:
- if (!mem->paused) {
- avl++;
- }
- break;
}
ao2_ref(mem, -1);
@@ -3010,38 +3055,54 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
char tech[256];
char *location;
const char *macrocontext, *macroexten;
+ enum ast_device_state newstate;
/* on entry here, we know that tmp->chan == NULL */
- if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
- (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
- ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
- (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
- if (qe->chan->cdr)
+ if (tmp->member->paused) {
+ ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
+ if (qe->chan->cdr) {
ast_cdr_busy(qe->chan->cdr);
+ }
tmp->stillgoing = 0;
- (*busies)++;
return 0;
}
- if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
- ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
- if (qe->chan->cdr)
+ if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
+ (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
+ ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
+ (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
+ if (qe->chan->cdr) {
ast_cdr_busy(qe->chan->cdr);
+ }
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
}
- if (tmp->member->paused) {
- ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
- if (qe->chan->cdr)
- ast_cdr_busy(qe->chan->cdr);
- tmp->stillgoing = 0;
- return 0;
+ if (!qe->parent->ringinuse || !tmp->member->ignorebusy) {
+ if ((tmp->member->status == AST_DEVICE_UNKNOWN) || (tmp->member->status == AST_DEVICE_NOT_INUSE)) {
+ newstate = ast_parse_device_state(tmp->member->interface);
+ if (newstate != tmp->member->status) {
+ ast_log(LOG_ERROR, "Found a channel matching iterface %s while status was %i changed to %i\n",
+ tmp->member->interface, tmp->member->status, newstate);
+ update_status(qe->parent, tmp->member, newstate);
+ }
+ }
+ if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
+ ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
+ if (qe->chan->cdr) {
+ ast_cdr_busy(qe->chan->cdr);
+ }
+ tmp->stillgoing = 0;
+ return 0;
+ }
}
+
if (use_weight && compare_weight(qe->parent,tmp->member)) {
ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
- if (qe->chan->cdr)
+ if (qe->chan->cdr) {
ast_cdr_busy(qe->chan->cdr);
+ }
tmp->stillgoing = 0;
(*busies)++;
return 0;
@@ -3056,8 +3117,9 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
/* Request the peer */
tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
if (!tmp->chan) { /* If we can't, just go on to the next call */
- if (qe->chan->cdr)
+ if (qe->chan->cdr) {
ast_cdr_busy(qe->chan->cdr);
+ }
tmp->stillgoing = 0;
ao2_lock(qe->parent);
@@ -3396,6 +3458,18 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
}
ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
+ if (qe->parent->autopausedelay > 0) {
+ struct member *mem;
+ ao2_lock(qe->parent);
+ if ((mem = interface_exists(qe->parent, interface))) {
+ time_t idletime = time(&idletime)-mem->lastcall;
+ if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
+ ao2_unlock(qe->parent);
+ return;
+ }
+ }
+ ao2_unlock(qe->parent);
+ }
if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
@@ -4707,8 +4781,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
else
ast_moh_stop(qe->chan);
/* If appropriate, log that we have a destination channel */
- if (qe->chan->cdr)
+ if (qe->chan->cdr) {
ast_cdr_setdestchan(qe->chan->cdr, peer->name);
+ }
/* Make sure channels are compatible */
res = ast_channel_make_compatible(qe->chan, peer);
if (res < 0) {
@@ -4788,10 +4863,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
if (mixmonapp) {
ast_debug(1, "Starting MixMonitor as requested.\n");
if (!monitorfilename) {
- if (qe->chan->cdr)
+ if (qe->chan->cdr) {
ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
- else
+ } else {
snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
+ }
} else {
const char *m = monitorfilename;
for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
@@ -4858,12 +4934,13 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
/* We purposely lock the CDR so that pbx_exec does not update the application data */
- if (qe->chan->cdr)
+ if (qe->chan->cdr) {
ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
+ }
pbx_exec(qe->chan, mixmonapp, mixmonargs);
- if (qe->chan->cdr)
+ if (qe->chan->cdr) {
ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
-
+ }
} else {
ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
}
@@ -5180,7 +5257,10 @@ static int remove_from_queue(const char *queuename, const char *interface)
ao2_lock(q);
if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
/* XXX future changes should beware of this assumption!! */
- if (!mem->dynamic) {
+ /*Change Penalty on realtime users*/
+ if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) {
+ update_realtime_member_field(mem, q->name, "penalty", "-1");
+ } else if (!mem->dynamic) {
ao2_ref(mem, -1);
ao2_unlock(q);
queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
@@ -5355,35 +5435,34 @@ static int set_member_penalty(const char *queuename, const char *interface, int
int foundinterface = 0, foundqueue = 0;
struct call_queue *q;
struct member *mem;
- struct ao2_iterator queue_iter;
+ char rtpenalty[80];
- if (penalty < 0) {
+ if (penalty < 0 && !negative_penalty_invalid) {
ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
return RESULT_FAILURE;
}
- queue_iter = ao2_iterator_init(queues, 0);
- while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
+ if ((q = load_realtime_queue(queuename))) {
+ foundqueue++;
ao2_lock(q);
- if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
- foundqueue++;
- if ((mem = interface_exists(q, interface))) {
- foundinterface++;
+ if ((mem = interface_exists(q, interface))) {
+ foundinterface++;
+ if (!mem->realtime) {
mem->penalty = penalty;
-
- ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
- manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
- "Queue: %s\r\n"
- "Location: %s\r\n"
- "Penalty: %d\r\n",
- q->name, mem->interface, penalty);
- ao2_ref(mem, -1);
+ } else {
+ sprintf(rtpenalty,"%i", penalty);
+ update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
}
+ ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
+ manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
+ "Queue: %s\r\n"
+ "Location: %s\r\n"
+ "Penalty: %d\r\n",
+ q->name, mem->interface, penalty);
+ ao2_ref(mem, -1);
}
ao2_unlock(q);
- queue_t_unref(q, "Done with iterator");
}
- ao2_iterator_destroy(&queue_iter);
if (foundinterface) {
return RESULT_SUCCESS;
@@ -6157,31 +6236,37 @@ static int queue_function_exists(struct ast_channel *chan, const char *cmd, char
return 0;
}
-/*!
+/*!
* \brief Get number either busy / free / ready or total members of a specific queue
- * \retval number of members (busy / free / ready / total)
+ * \brief Get or set member properties penalty / paused / ignorebusy
+ * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy)
* \retval -1 on error
*/
-static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
int count = 0;
struct member *m;
struct ao2_iterator mem_iter;
struct call_queue *q;
- char *option;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(option);
+ AST_APP_ARG(interface);
+ );
+ /* Make sure the returned value on error is zero length string. */
+ buf[0] = '\0';
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
return -1;
}
- if ((option = strchr(data, ',')))
- *option++ = '\0';
- else
- option = "logged";
- if ((q = load_realtime_queue(data))) {
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if ((q = load_realtime_queue(args.queuename))) {
ao2_lock(q);
- if (!strcasecmp(option, "logged")) {
+ if (!strcasecmp(args.option, "logged")) {
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
/* Count the agents who are logged in and presently answering calls */
@@ -6191,7 +6276,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
- } else if (!strcasecmp(option, "free")) {
+ } else if (!strcasecmp(args.option, "free")) {
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
/* Count the agents who are logged in and presently answering calls */
@@ -6201,7 +6286,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
- } else if (!strcasecmp(option, "ready")) {
+ } else if (!strcasecmp(args.option, "ready")) {
time_t now;
time(&now);
mem_iter = ao2_iterator_init(q->members, 0);
@@ -6214,22 +6299,104 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
- } else /* must be "count" */
+ } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) {
count = q->membercount;
+ } else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface) &&
+ ((m = interface_exists(q, args.interface)))) {
+ count = m->penalty;
+ } else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) &&
+ ((m = interface_exists(q, args.interface)))) {
+ count = m->paused;
+ } else if (!strcasecmp(args.option, "ignorebusy") && !ast_strlen_zero(args.interface) &&
+ ((m = interface_exists(q, args.interface)))) {
+ count = m->ignorebusy;
+ }
ao2_unlock(q);
queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
- } else
- ast_log(LOG_WARNING, "queue %s was not found\n", data);
+ } else {
+ ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
+ }
snprintf(buf, len, "%d", count);
return 0;
}
-/*!
+/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy. */
+static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ int memvalue;
+ struct call_queue *q;
+ struct member *m;
+ char rtvalue[80];
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(option);
+ AST_APP_ARG(interface);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n");
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (args.argc < 3) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
+ return -1;
+ }
+
+ if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) {
+ ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n");
+ return -1;
+ }
+
+ memvalue = atoi(value);
+
+ if (!strcasecmp(args.option, "penalty")) {
+ /* if queuename = NULL then penalty will be set for interface in all the queues.*/
+ if (set_member_penalty(args.queuename, args.interface, memvalue)) {
+ ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
+ return -1;
+ }
+ } else if ((q = load_realtime_queue(args.queuename))) {
+ ao2_lock(q);
+ if ((m = interface_exists(q, args.interface))) {
+ sprintf(rtvalue, "%s",(memvalue <= 0) ? "0" : "1");
+ if (!strcasecmp(args.option, "paused")) {
+ if (m->realtime) {
+ update_realtime_member_field(m, q->name, args.option, rtvalue);
+ } else {
+ m->paused = (memvalue <= 0) ? 0 : 1;
+ }
+ } else if (!strcasecmp(args.option, "ignorebusy")) {
+ if (m->realtime) {
+ update_realtime_member_field(m, q->name, args.option, rtvalue);
+ } else {
+ m->ignorebusy = (memvalue <= 0) ? 0 : 1;
+ }
+ } else {
+ ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ignorebusy are valid\n");
+ return -1;
+ }
+ } else {
+ ast_log(LOG_ERROR, "Invalid interface or queue\n");
+ return -1;
+ }
+ ao2_unlock(q);
+ } else {
+ ast_log(LOG_ERROR, "Invalid queue\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*!
* \brief Get the total number of members in a specific queue (Deprecated)
- * \retval number of members
- * \retval -1 on error
+ * \retval number of members
+ * \retval -1 on error
*/
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
@@ -6435,7 +6602,8 @@ static struct ast_custom_function queuevar_function = {
static struct ast_custom_function queuemembercount_function = {
.name = "QUEUE_MEMBER",
- .read = queue_function_qac,
+ .read = queue_function_mem_read,
+ .write = queue_function_mem_write,
};
static struct ast_custom_function queuemembercount_dep = {
@@ -6517,8 +6685,9 @@ static void queue_set_global_params(struct ast_config *cfg)
{
const char *general_val = NULL;
queue_persistent_members = 0;
- if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
+ if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
queue_persistent_members = ast_true(general_val);
+ }
autofill_default = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
autofill_default = ast_true(general_val);
@@ -6533,6 +6702,9 @@ static void queue_set_global_params(struct ast_config *cfg)
shared_lastcall = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
shared_lastcall = ast_true(general_val);
+ negative_penalty_invalid = 0;
+ if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid")))
+ negative_penalty_invalid = ast_true(general_val);
}
/*! \brief reload information pertaining to a single member
diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample
index c2045f90c..3f67d6df7 100644
--- a/configs/queues.conf.sample
+++ b/configs/queues.conf.sample
@@ -61,6 +61,10 @@ monitor-type = MixMonitor
;
;shared_lastcall=no
;
+; Negative_penalty_invalid will treat members with a negative penalty as logged off
+;
+;negative_penalty_invalid = no
+;
;[markq]
;
; A sample call queue
@@ -196,6 +200,10 @@ monitor-type = MixMonitor
; all: Memeber will be paused in all queues he/she is a member
;autopause=yes
;
+; Autopausedelay delay autopause for autopausedelay seconds from the
+; last call if a member has not taken a call the delay has no effect.
+;autopausedelay=60
+;
; Maximum number of people waiting in the queue (0 for unlimited)
;
;maxlen = 0
@@ -459,6 +467,9 @@ monitor-type = MixMonitor
; uncomment this option. (Note: only the SIP channel driver currently is able
; to report 'in use'.)
;
+; A member can have the ignorebusy flag set or unset when ringinuse is set to
+; allow a per member control.
+;
; ringinuse = no
;
; If you wish to have a delay before the member is connected to the caller (or