Index: apps/app_queue.c
===================================================================
--- apps/app_queue.c (revision 195443)
+++ apps/app_queue.c (working copy)
@@ -418,13 +418,13 @@
Returns 0 if queue is found and setqueuevar is defined, -1 otherwise.
-
+
Count number of members answering a queue.
-
+
Returns the number of logged-in members for the specified queue.
@@ -442,21 +442,6 @@
Returns the number of members currently associated with the specified queuename.
-
-
- Count number of members answering a queue.
-
-
-
-
-
- Returns the number of members currently associated with the specified queuename.
- This function has been deprecated in favor of the QUEUE_MEMBER() function
-
-
- [QUEUE_MEMBER_LIST]
-
-
Count number of calls currently waiting in a queue.
@@ -482,17 +467,51 @@
[QUEUE_MEMBER_COUNT]
-
+
- Gets or sets queue members penalty.
+ Gets or sets queue member fields.
-
-
+
+
+
+
+ Returns or sets the number of answered call counter for queue member
+
+
+ Returns or sets the last call timer for queue member
+
+
+ Returns or sets the penalty of queue member
+
+
+ Returns or sets the paused status for queue member
+
+
+ Returns or sets the wrapuptime on queue member
+
+
+ Returns or sets the wrapuptime on queue member for next call only.
+
+
+ Returns the count of logged-in members for the specified queue (deprecated, use QUEUE_MEMBER_COUNT instead)
+
+
+ Returns the count of logged-in members for the specified queue available to take a call (deprecated, use QUEUE_MEMBER_COUNT instead)
+
+
+ Returns the total amount of members for the specified queue (deprecated, use QUEUE_MEMBER_COUNT instead)
+
+
+
+
- Gets or sets queue members penalty.
+ Gets or sets queue member fields. If is not specified on write, member will be updated in all queues. Read also allows returning count of logged/free/total amount of agents for backward compatibility.
+
+ [QUEUE_MEMBER_COUNT]
+
***/
@@ -680,8 +699,8 @@
int realtime; /*!< Is this member realtime? */
int status; /*!< Status of queue member */
int paused; /*!< Are we paused (not accepting calls)? */
- int wrapuptime; /*!< Member wrapuptime. */
- int current_wrapuptime; /*!< This wrapuptime can be modified just for the next call. */
+ int wrapuptime; /*!< Member wrapuptime. */
+ int next_wrapuptime; /*!< This wrapuptime can be modified just for the next call. */
time_t lastcall; /*!< When last successful call was hungup */
struct call_queue *lastqueue; /*!< Last queue we received a call */
unsigned int dead:1; /*!< Used to detect members deleted in realtime */
@@ -689,6 +708,13 @@
char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
};
+#define QUEUE_MEMBER_FIELD_PENALTY "penalty"
+#define QUEUE_MEMBER_FIELD_CALLS "calls"
+#define QUEUE_MEMBER_FIELD_PAUSED "paused"
+#define QUEUE_MEMBER_FIELD_LASTCALL "lastcall"
+#define QUEUE_MEMBER_FIELD_WRAPUPTIME "wrapuptime"
+#define QUEUE_MEMBER_FIELD_NEXTWRAPUPTIME "nextwrapuptime"
+
enum empty_conditions {
QUEUE_EMPTY_PENALTY = (1 << 0),
QUEUE_EMPTY_PAUSED = (1 << 1),
@@ -832,7 +858,8 @@
static struct ao2_container *queues;
static void update_realtime_members(struct call_queue *q);
-static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
+static int set_member_field(struct call_queue *q, struct member *mem, const char *field, long value, int relative, const char *reason);
+static struct member *interface_exists(struct call_queue *q, const char *interface);
static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
/*! \brief sets the QUEUESTATUS channel variable */
@@ -1113,7 +1140,7 @@
cur->penalty = penalty;
cur->paused = paused;
cur->wrapuptime = wrapuptime;
- cur->current_wrapuptime = wrapuptime;
+ cur->next_wrapuptime = wrapuptime;
ast_copy_string(cur->interface, interface, sizeof(cur->interface));
if (!ast_strlen_zero(state_interface))
ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
@@ -1881,15 +1908,13 @@
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
{
- int ret = -1;
-
if (ast_strlen_zero(mem->rt_uniqueid))
- return ret;
+ return RESULT_FAILURE;
if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
- ret = 0;
+ return RESULT_SUCCESS;
- return ret;
+ return RESULT_FAILURE;
}
@@ -2499,10 +2524,10 @@
lastqueue = tmp->lastqueue;
/* check if the wrapuptime expired so we are able to call this member. */
- if (mem->current_wrapuptime >= 0) {
+ if (mem->next_wrapuptime >= 0) {
/* the queue member has a wrapuptime configured and didn't expired yet. */
- wrapup_notexpired = wrapuptime_notexpired(tmp->lastcall, mem->current_wrapuptime);
- } else if (mem->current_wrapuptime < 0) {
+ wrapup_notexpired = wrapuptime_notexpired(tmp->lastcall, mem->next_wrapuptime);
+ } else if (mem->next_wrapuptime < 0) {
/* the member doesn't have a specific wrapuptime configured. */
if (lastqueue && lastqueue->wrapuptime) {
/* if the queue member doesn't have a wrapuptime configured, check for the wrapuptime of the last queue
@@ -2883,10 +2908,15 @@
}
ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
if (qe->parent->autopause && pause) {
- 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", interface, qe->parent->name);
- } else {
- ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
+ struct member *mem;
+ //TODO: atis: update rna to pass member structure, not name
+ if ((mem = interface_exists(qe->parent, interface))) {
+ //TODO: atis: check all set_member_field for result
+ if (RESULT_SUCCESS==set_member_field(qe->parent, mem, QUEUE_MEMBER_FIELD_PAUSED, 1, 0, "Auto-Pause")) {
+ ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
+ } else {
+ ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
+ }
}
}
return;
@@ -3004,7 +3034,7 @@
}
}
peer = o;
- o->member->current_wrapuptime = o->member->wrapuptime;
+ o->member->next_wrapuptime = o->member->wrapuptime;
}
} else if (o->chan && (o->chan == winner)) {
@@ -3105,7 +3135,7 @@
}
}
peer = o;
- o->member->current_wrapuptime = o->member->wrapuptime;
+ o->member->next_wrapuptime = o->member->wrapuptime;
}
break;
case AST_CONTROL_BUSY:
@@ -3912,7 +3942,7 @@
tmp->oldstatus = cur->status;
tmp->lastcall = cur->lastcall;
tmp->lastqueue = cur->lastqueue;
- tmp->wrapuptime = cur->current_wrapuptime;
+ tmp->wrapuptime = cur->next_wrapuptime;
tmp->update_connectedline = 1;
ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
/* Special case: If we ring everyone, go ahead and ring them, otherwise
@@ -4501,10 +4531,11 @@
if ((mem = interface_exists(q, interface))) {
foundinterface++;
/* this wrapuptime will be used only for the next call to this agent. */
+ //TODO: eliel: Note to eliel - setting relative wrapuptime will probably mess up next_wrapuptime if they are not equal :)
if (absolute_value) {
- mem->current_wrapuptime = offset;
+ mem->next_wrapuptime = offset;
} else {
- mem->current_wrapuptime += offset;
+ mem->next_wrapuptime += offset;
}
/* modify static configuration. */
if (modify_defaults) {
@@ -4515,6 +4546,7 @@
}
if (mem->wrapuptime < 0) {
mem->wrapuptime = -1;
+ //TODO: eliel: clarify with eliel - what's the meaning of -1 value?
}
ast_queue_log(q->name, "NONE", interface, "WRAPUPTIME", "%d", mem->wrapuptime);
@@ -4524,12 +4556,12 @@
"Wrapuptime: %d\r\n",
q->name, mem->interface, mem->wrapuptime);
} else {
- ast_queue_log(q->name, "NONE", interface, "NEXTWRAPUPTIME", "%d", mem->current_wrapuptime);
+ ast_queue_log(q->name, "NONE", interface, "NEXTWRAPUPTIME", "%d", mem->next_wrapuptime);
manager_event(EVENT_FLAG_AGENT, "QueueMemberNextWrapuptime",
"Queue: %s\r\n"
"Interface: %s\r\n"
"Wrapuptime: %d\r\n",
- q->name, mem->interface, mem->current_wrapuptime);
+ q->name, mem->interface, mem->next_wrapuptime);
}
ao2_ref(mem, -1);
@@ -4570,6 +4602,7 @@
continue;
}
+ //TODO: eliel: add wrapuptime/next_wrapuptime/lastcall to PersistentMembers
res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
@@ -4702,63 +4735,187 @@
return res;
}
-static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
+/* \brief Updates field for identified member and identified queue.
+ * \return Returns RESULT_SUCCESS if update succeeded or RESULT_FAILURE on error.
+*/
+static int set_member_field(struct call_queue *q, struct member *mem, const char *field, long value, int relative, const char *reason)
{
- int found = 0;
+ char *log_event = "UPDATEMEMBER", *manager_event = "QueueMemberUpdate", *strbuf;
+
+ if (!strcasecmp(QUEUE_MEMBER_FIELD_CALLS, field)) {
+
+ if (relative) value = mem->calls+(relative*value);
+ if (value<0) {
+ ast_log(LOG_VERBOSE, "Can't set call count to %ld for queue member %s:%s\n", value, q->name, mem->interface);
+ return RESULT_FAILURE;
+ }
+
+ mem->calls = value;
+ manager_event = "QueueMemberCalls";
+ log_event = "UPDATECALLS";
+ ast_log(LOG_DEBUG, "Setting calls for queue member %s:%s to %ld\n", q->name, mem->interface, value);
+
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_LASTCALL, field)) {
+ /* TODO: atis: setting +x in lastcall actually shifts output data into negative. This is ok, but might create confusion
+ * TODO: atis: consider changing into inverse and allow updating "status changed" value. Disallow setting to 0 and other unlogical values.
+ *
+ */
+ //TODO: atis: reminder to myself - merge in another patch to set lastcall upon queue login - so that it always reflects correct status change
+ if (relative) value = mem->lastcall+(relative*value);
+ mem->lastcall = value;
+ manager_event = "QueueMemberLastcall";
+ log_event = "UPDATELASTCALL";
+ ast_log(LOG_DEBUG, "Setting lastcall for queue member %s:%s to %ld\n", q->name, mem->interface, value);
+
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_PENALTY, field)) {
+
+ if (relative) value = mem->penalty+(relative*value);
+ if (value<0) {
+ ast_log(LOG_VERBOSE, "Can't set penalty to %ld for queue member %s:%s\n", value, q->name, mem->interface);
+ return RESULT_FAILURE;
+ }
+
+ mem->penalty = value;
+ log_event = "PENALTY";
+ manager_event = "QueueMemberPenalty";
+ ast_log(LOG_DEBUG, "Setting penalty for queue member %s:%s to %ld\n", q->name, mem->interface, value);
+
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_WRAPUPTIME, field)) {
+ if (relative) value = mem->wrapuptime+(relative*value);
+ if (value<0) {
+ ast_log(LOG_VERBOSE, "Can't set wrapuptime to %ld for queue member %s:%s\n", value, q->name, mem->interface);
+ return RESULT_FAILURE;
+ }
+
+ mem->wrapuptime = value;
+ mem->next_wrapuptime = value;
+ log_event = "WRAPUPTIME";
+ manager_event = "QueueMemberWrapuptime";
+ ast_log(LOG_DEBUG, "Setting wrapuptime for queue member %s:%s to %ld\n", q->name, mem->interface, value);
+
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_NEXTWRAPUPTIME, field)) {
+
+ if (relative) value = mem->next_wrapuptime+(relative*value);
+ if (value<0) {
+ ast_log(LOG_VERBOSE, "Can't set nextwrapuptime to %ld for queue member %s:%s\n", value, q->name, mem->interface);
+ return RESULT_FAILURE;
+ }
+
+ mem->next_wrapuptime = value;
+ log_event = "NEXTWRAPUPTIME";
+ manager_event = "QueueMemberNextWrapuptime";
+ ast_log(LOG_DEBUG, "Setting nextwrapuptime for queue member %s:%s to %ld\n", q->name, mem->interface, value);
+
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_PAUSED, field)) {
+
+ // TODO: atis: use ast_true
+ if (relative) {
+ ast_log(LOG_VERBOSE, "Can't increment or decrement paused status for queue member %s:%s\n", q->name, mem->interface);
+ return RESULT_FAILURE;
+ } else if (value<0 || value>1) {
+ ast_log(LOG_VERBOSE, "Can't set paused other than 0 or 1 for queue member %s:%s\n", q->name, mem->interface);
+ return RESULT_FAILURE;
+ }
+
+ if (mem->paused == value) {
+ ast_log(LOG_NOTICE, "%spausing already-%spaused queue member %s:%s\n", (value ? "" : "un"), (value ? "" : "un"), q->name, mem->interface);
+ }
+
+ mem->paused = value;
+ manager_event = "QueueMemberPaused";
+ log_event = (value ? "PAUSE" : "UNPAUSE");
+ ast_log(LOG_DEBUG, "Setting paused for queue member %s:%s to %ld\n", q->name, mem->interface, value);
+
+ } else {
+ ast_log(LOG_VERBOSE, "Queue members don't have %s field.!\n", field);
+ return RESULT_FAILURE;
+ }
+
+ if (mem->realtime) {
+ snprintf(strbuf, sizeof(strbuf), "%ld", value);
+ ast_log(LOG_DEBUG, "Updating realtime member field %s to %s\n", field, strbuf);
+ if (!update_realtime_member_field(mem, q->name, field, strbuf)) {
+ //TODO: atis: keep previous value and reset back in memory upon failure
+ return RESULT_FAILURE;
+ }
+ }
+
+ if (queue_persistent_members) {
+ dump_queue_members(q);
+ }
+
+ // TODO: atis: think of something for consistency of reason field position within PAUSE/UNPAUSE
+ ast_queue_log(q->name, "NONE", mem->membername, log_event, "%ld|%s", value, S_OR(reason, ""));
+
+ if (!ast_strlen_zero(reason)) {
+ manager_event(EVENT_FLAG_AGENT, manager_event,
+ "Queue: %s\r\n"
+ "Location: %s\r\n"
+ "MemberName: %s\r\n"
+ "Paused: %d\r\n"
+ "Calls: %d\r\n"
+ "Penalty: %d\r\n"
+ "Lastcall: %ld\r\n"
+ "Reason: %s\r\n",
+ q->name, mem->interface, mem->membername, mem->paused, mem->calls, mem->penalty, (long)mem->lastcall, reason);
+ } else {
+ manager_event(EVENT_FLAG_AGENT, manager_event,
+ "Queue: %s\r\n"
+ "Location: %s\r\n"
+ "MemberName: %s\r\n"
+ "Paused: %d\r\n"
+ "Calls: %d\r\n"
+ "Penalty: %d\r\n"
+ "Lastcall: %ld\r\n",
+ q->name, mem->interface, mem->membername, mem->paused, mem->calls, mem->penalty, (long)mem->lastcall);
+ }
+
+ return RESULT_SUCCESS;
+}
+
+/* \brief Finds a queue and member in it, and updates specified field.
+ * \return Returns RESULT_SUCCESS if update succeeded or RESULT_FAILURE on error.
+*/
+static int update_member_field(const char *queuename, const char *interface, const char *field, const char *value_s, const char *reason)
+{
+ int relative = 0;
+ int res;
struct call_queue *q;
struct member *mem;
struct ao2_iterator queue_iter;
- int failed;
+ long value;
+ value = atol(value_s);
+
+ /* Check for increment/decrement */
+ if (!ast_strlen_zero(value_s)) {
+ if (value_s[0]=='+') {
+ relative = +1;
+ if (value==0) value = 1;
+ } else if (value_s[0]=='-') {
+ value = -value;
+ relative = -1;
+ if (value==0) value = 1;
+ }
+ }
+
/* Special event for when all queues are paused - individual events still generated */
/* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
- if (ast_strlen_zero(queuename))
- ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
+ if (!strcasecmp(QUEUE_MEMBER_FIELD_PAUSED, field) && ast_strlen_zero(queuename))
+ ast_queue_log("NONE", "NONE", interface, (value ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
queue_iter = ao2_iterator_init(queues, 0);
while ((q = ao2_iterator_next(&queue_iter))) {
ao2_lock(q);
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
if ((mem = interface_exists(q, interface))) {
- if (mem->paused == paused) {
- ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
- }
-
- failed = 0;
- if (mem->realtime) {
- failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
- }
-
- if (failed) {
- ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
+ res = set_member_field(q, mem, field, value, relative, reason);
+ if (res == RESULT_FAILURE) {
ao2_ref(mem, -1);
ao2_unlock(q);
continue;
- }
- found++;
- mem->paused = paused;
+ }
- if (queue_persistent_members)
- dump_queue_members(q);
-
- ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
-
- if (!ast_strlen_zero(reason)) {
- manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
- "Queue: %s\r\n"
- "Location: %s\r\n"
- "MemberName: %s\r\n"
- "Paused: %d\r\n"
- "Reason: %s\r\n",
- q->name, mem->interface, mem->membername, paused, 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, paused);
- }
ao2_ref(mem, -1);
}
}
@@ -4773,87 +4930,67 @@
queue_unref(q);
}
- return found ? RESULT_SUCCESS : RESULT_FAILURE;
+ return res;
}
-/* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
-static int set_member_penalty(char *queuename, char *interface, int penalty)
+/* \brief Gets members field
+ * \return Return the member field.
+*/
+static int get_member_field(const char *queuename, const char *interface, const char *field)
{
- int foundinterface = 0, foundqueue = 0;
struct call_queue *q;
struct member *mem;
struct ao2_iterator queue_iter;
+ int ret;
- if (penalty < 0) {
- ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
+ if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
+ ast_log(LOG_VERBOSE, "Queue name and interface must be specified\n");
return RESULT_FAILURE;
}
queue_iter = ao2_iterator_init(queues, 0);
while ((q = ao2_iterator_next(&queue_iter))) {
ao2_lock(q);
- if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
- foundqueue++;
- if ((mem = interface_exists(q, interface))) {
- foundinterface++;
- mem->penalty = penalty;
-
- ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
- manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
- "Queue: %s\r\n"
- "Location: %s\r\n"
- "Penalty: %d\r\n",
- q->name, mem->interface, penalty);
- ao2_ref(mem, -1);
+ if (!strcasecmp(q->name, queuename)) {
+ mem = interface_exists(q, interface);
+ if (!mem) {
+ ast_log(LOG_VERBOSE, "Member %s not found in queue %s!\n", interface, queuename);
+ ao2_unlock(q);
+ queue_unref(q);
+ return RESULT_FAILURE;
}
+
+ // Do cases for each field
+ if (!strcasecmp(QUEUE_MEMBER_FIELD_CALLS, field)) {
+ ret = mem->calls;
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_LASTCALL, field)) {
+ ret = mem->lastcall;
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_PENALTY, field)) {
+ ret = mem->penalty;
+ } else if (!strcasecmp(QUEUE_MEMBER_FIELD_PAUSED, field)) {
+ ret = mem->paused;
+ } else {
+ ast_log(LOG_VERBOSE, "Queue members don't have %s field.!\n", field);
+ }
+ ao2_ref(mem, -1);
+ ao2_unlock(q);
+ queue_unref(q);
+ return ret;
}
+
ao2_unlock(q);
queue_unref(q);
}
- if (foundinterface) {
- return RESULT_SUCCESS;
- } else if (!foundqueue) {
- ast_log (LOG_ERROR, "Invalid queuename\n");
- } else {
- ast_log (LOG_ERROR, "Invalid interface\n");
- }
-
return RESULT_FAILURE;
}
-/* \brief Gets members penalty.
+/* \brief Gets members penalty.
* \return Return the members penalty or RESULT_FAILURE on error.
*/
static int get_member_penalty(char *queuename, char *interface)
{
- int foundqueue = 0, penalty;
- struct call_queue *q, tmpq = {
- .name = queuename,
- };
- struct member *mem;
-
- if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
- foundqueue = 1;
- ao2_lock(q);
- if ((mem = interface_exists(q, interface))) {
- penalty = mem->penalty;
- ao2_ref(mem, -1);
- ao2_unlock(q);
- queue_unref(q);
- return penalty;
- }
- ao2_unlock(q);
- queue_unref(q);
- }
-
- /* some useful debuging */
- if (foundqueue)
- ast_log (LOG_ERROR, "Invalid queuename\n");
- else
- ast_log (LOG_ERROR, "Invalid interface\n");
-
- return RESULT_FAILURE;
+ return get_member_field(queuename, interface, QUEUE_MEMBER_FIELD_PENALTY);
}
/*! \brief Reload dynamic queue members persisted into the astdb */
@@ -4984,7 +5121,7 @@
return -1;
}
- if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
+ if (update_member_field(args.queuename, args.interface, QUEUE_MEMBER_FIELD_PAUSED, "1", args.reason)) {
ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
return 0;
@@ -5020,7 +5157,7 @@
return -1;
}
- if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
+ if (update_member_field(args.queuename, args.interface, QUEUE_MEMBER_FIELD_PAUSED, "0", args.reason)) {
ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
return 0;
@@ -5620,49 +5757,6 @@
return 0;
}
-/*!
- * \brief Get the total number of members in a specific queue (Deprecated)
- * \retval number of members
- * \retval -1 on error
-*/
-static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
- int count = 0;
- struct member *m;
- struct call_queue *q;
- struct ao2_iterator mem_iter;
- static int depflag = 1;
-
- if (depflag) {
- depflag = 0;
- ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
- }
-
- if (ast_strlen_zero(data)) {
- ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
- return -1;
- }
-
- if ((q = load_realtime_queue(data))) {
- ao2_lock(q);
- 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 */
- if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
- count++;
- }
- ao2_ref(m, -1);
- }
- ao2_unlock(q);
- queue_unref(q);
- } else
- ast_log(LOG_WARNING, "queue %s was not found\n", data);
-
- snprintf(buf, len, "%d", count);
-
- return 0;
-}
-
/*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
@@ -5748,9 +5842,16 @@
}
/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
-static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+static int queue_function_memberpenalty_read_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
int penalty;
+ static int deprecation_warning = 0;
+
+ if (deprecation_warning == 0) {
+ ast_log(LOG_VERBOSE, "The function QUEUE_MEMBER_PENALTY has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
+ deprecation_warning = 1;
+ }
+
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
@@ -5779,9 +5880,15 @@
}
/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
-static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+static int queue_function_memberpenalty_write_dep(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
- int penalty;
+ static int deprecation_warning = 0;
+
+ if (deprecation_warning == 0) {
+ ast_log(LOG_VERBOSE, "The function QUEUE_MEMBER_PENALTY has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
+ deprecation_warning = 1;
+ }
+
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
@@ -5799,15 +5906,13 @@
return -1;
}
- penalty = atoi(value);
-
if (ast_strlen_zero(args.interface)) {
ast_log (LOG_ERROR, " parameter can't be null\n");
return -1;
}
/* if queuename = NULL then penalty will be set for interface in all the queues. */
- if (set_member_penalty(args.queuename, args.interface, penalty)) {
+ if (update_member_field(args.queuename, args.interface, QUEUE_MEMBER_FIELD_PENALTY, value, NULL)) {
ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
return -1;
}
@@ -5815,19 +5920,90 @@
return 0;
}
+
+
+/*! \brief Dialplan function QUEUE_MEMBER() Gets the member parameters. */
+static int queue_function_member_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ int result;
+ static int deprecation_warning = 0;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(field);
+ AST_APP_ARG(interface);
+ );
+ /* Make sure the returned value on error is NULL. */
+ buf[0] = '\0';
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(,[,])\n");
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (args.argc < 1) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(,[,])\n");
+ return -1;
+ }
+
+ if (args.argc == 1 || !strcasecmp("count", args.field) || !strcasecmp("logged", args.field) || !strcasecmp("free", args.field)) {
+ if (deprecation_warning == 0) {
+ ast_log(LOG_VERBOSE, "Usage of QUEUE_MEMBER for 'count', 'logged' or 'free' is deprecated. Use QUEUE_MEMBER_COUNT instead.\n");
+ }
+ return queue_function_qac(chan, cmd, data, buf, len);
+ }
+
+ result = get_member_field(args.queuename, args.interface, args.field);
+
+ if (result >= 0) /* remember that buf is already '\0' */
+ snprintf (buf, len, "%d", result);
+
+ return 0;
+}
+
+/*! \brief Dialplan function QUEUE_MEMBER() Sets the member parameters. */
+static int queue_function_member_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(field);
+ AST_APP_ARG(interface);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER([],[,])\n");
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (args.argc < 2) {
+ ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER([],[,])\n");
+ return -1;
+ }
+
+ if (!update_member_field(args.queuename, args.interface, args.field, value, NULL)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
static struct ast_custom_function queuevar_function = {
.name = "QUEUE_VARIABLES",
.read = queue_function_var,
};
-
static struct ast_custom_function queuemembercount_function = {
- .name = "QUEUE_MEMBER",
+ .name = "QUEUE_MEMBER_COUNT",
.read = queue_function_qac,
};
-static struct ast_custom_function queuemembercount_dep = {
- .name = "QUEUE_MEMBER_COUNT",
- .read = queue_function_qac_dep,
+static struct ast_custom_function queuemember_function = {
+ .name = "QUEUE_MEMBER",
+ .read = queue_function_member_read,
+ .write = queue_function_member_write,
};
static struct ast_custom_function queuewaitingcount_function = {
@@ -5840,10 +6016,10 @@
.read = queue_function_queuememberlist,
};
-static struct ast_custom_function queuememberpenalty_function = {
+static struct ast_custom_function queuememberpenalty_dep = {
.name = "QUEUE_MEMBER_PENALTY",
- .read = queue_function_memberpenalty_read,
- .write = queue_function_memberpenalty_write,
+ .read = queue_function_memberpenalty_read_dep,
+ .write = queue_function_memberpenalty_write_dep,
};
/*! \brief Reload the rules defined in queuerules.conf
@@ -6377,7 +6553,7 @@
mem->paused ? " (paused)" : "",
ast_devstate2str(mem->status));
if (mem->wrapuptime >= 0) {
- ast_str_append(&out, 0, " (wrapuptime = %d/%d)", mem->wrapuptime, mem->current_wrapuptime);
+ ast_str_append(&out, 0, " (wrapuptime = %d/%d)", mem->wrapuptime, mem->next_wrapuptime);
}
if (mem->calls)
ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago) ",
@@ -6774,7 +6950,7 @@
paused = abs(ast_true(paused_s));
- if (set_member_paused(queuename, interface, reason, paused))
+ if (update_member_field(queuename, interface, QUEUE_MEMBER_FIELD_PAUSED, paused_s, reason))
astman_send_error(s, m, "Interface not found");
else
astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
@@ -6888,22 +7064,25 @@
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
{
- const char *queuename, *interface, *penalty_s;
- int penalty;
+ const char *queuename, *interface, *penalty;
+ static int deprecation_warning = 0;
+ if (deprecation_warning == 0) {
+ ast_log(LOG_VERBOSE, "Manager action QueuePenalty is deprecated in favor of QueueMember");
+ deprecation_warning = 1;
+ }
+
interface = astman_get_header(m, "Interface");
- penalty_s = astman_get_header(m, "Penalty");
+ penalty = astman_get_header(m, "Penalty");
/* Optional - if not supplied, set the penalty value for the given Interface in all queues */
queuename = astman_get_header(m, "Queue");
- if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
+ if (ast_strlen_zero(interface) || ast_strlen_zero(penalty)) {
astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
return 0;
}
- penalty = atoi(penalty_s);
-
- if (set_member_penalty((char *)queuename, (char *)interface, penalty))
+ if (update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_PENALTY, (char *)penalty, NULL))
astman_send_error(s, m, "Invalid interface, queuename or penalty");
else
astman_send_ack(s, m, "Interface penalty set successfully");
@@ -6911,6 +7090,63 @@
return 0;
}
+static int manager_queue_member(struct mansession *s, const struct message *m)
+{
+ const char *queuename, *interface, *val, *reason;
+ int res = -1;
+
+ /* Optional - if not supplied, set the value for the given Interface in all queues */
+ queuename = astman_get_header(m, "Queue");
+
+ interface = astman_get_header(m, "Interface");
+ reason = astman_get_header(m, "Reason");
+
+ if (ast_strlen_zero(interface)) {
+ astman_send_error(s, m, "Need to set 'Interface'");
+ return 0;
+ }
+
+ /* TODO: atis: use m->hdrcount and m->headers to iterate all arguments */
+ // TODO: atis: use string constants
+ if ((val = astman_get_header(m, "Penalty"))) {
+ res = res | update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_PENALTY, (char *)val, reason);
+ }
+
+ if ((val = astman_get_header(m, "Calls"))) {
+ res = res | update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_CALLS, (char *)val, reason);
+ }
+
+ if ((val = astman_get_header(m, "Paused"))) {
+ res = res | update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_PAUSED, (char *)val, reason);
+ }
+
+ if ((val = astman_get_header(m, "Lastcall"))) {
+ res = res | update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_PAUSED, (char *)val, reason);
+ }
+
+ if ((val = astman_get_header(m, "Wrapuptime"))) {
+ res = res | update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_WRAPUPTIME, (char *)val, reason);
+ }
+
+ if ((val = astman_get_header(m, "NextWrapuptime"))) {
+ res = res | update_member_field((char *)queuename, (char *)interface, QUEUE_MEMBER_FIELD_NEXTWRAPUPTIME, (char *)val, reason);
+ }
+
+ if (res==-1) {
+ astman_send_error(s, m, "Need to set either of 'Penalty', 'Calls', 'Paused', 'Lastcall', 'Wrapuptime' or 'NextWrapuptime'");
+ return 0;
+ }
+
+ if (res==RESULT_FAILURE)
+ astman_send_error(s, m, "Invalid interface, queuename or fields");
+ else
+ astman_send_ack(s, m, "Interface updated set successfully");
+
+ return 0;
+}
+
+
+
/*!
* \internal
* \brief Modify the queue member wrapuptime based on the manager request.
@@ -6967,6 +7203,7 @@
char *queuename, *interface, *membername = NULL, *state_interface = NULL;
int penalty, wrapuptime = -1;
+ // TODO: eliel: why add wrapuptime in middle? It shouldn't be more important than penalty.
switch ( cmd ) {
case CLI_INIT:
e->command = "queue add member";
@@ -7162,6 +7399,7 @@
{
char *queuename, *interface, *reason;
int paused;
+ char *paused_val;
switch (cmd) {
case CLI_INIT:
@@ -7189,8 +7427,9 @@
queuename = a->argc >= 6 ? a->argv[5] : NULL;
reason = a->argc == 8 ? a->argv[7] : NULL;
paused = !strcasecmp(a->argv[1], "pause");
+ paused_val = paused ? "1" : "0";
- if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
+ if (update_member_field(queuename, interface, QUEUE_MEMBER_FIELD_PAUSED, paused_val, reason) == RESULT_SUCCESS) {
ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
if (!ast_strlen_zero(queuename))
ast_cli(a->fd, " in queue '%s'", queuename);
@@ -7209,9 +7448,10 @@
}
}
-static char *complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
+static char *complete_queue_set_member(const char *line, const char *word, int pos, int state)
{
- /* 0 - queue; 1 - set; 2 - penalty; 3 - ; 4 - on; 5 - ; 6 - in; 7 - ;*/
+ //TODO: atis: complete all options
+ /* 0 - queue; 1 - set; 2 - penalty|calls|lastcall|paused; 3 - ; 4 - on; 5 - ; 6 - in|because; 7 - ; 8 - because; 9 - reason;*/
switch (pos) {
case 4:
if (state == 0) {
@@ -7227,45 +7467,78 @@
}
case 7:
return complete_queue(line, word, pos, state);
+ case 8:
+ if (state == 0) {
+ return ast_strdup("because");
+ } else {
+ return NULL;
+ }
default:
return NULL;
}
-}
-
-static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+}
+
+static char *handle_queue_set_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- char *queuename = NULL, *interface;
- int penalty = 0;
+ char *queuename = NULL, *reason = NULL, *interface = NULL, *value = NULL, *field = NULL;
switch (cmd) {
case CLI_INIT:
- e->command = "queue set penalty";
+ e->command = "queue set";
e->usage =
- "Usage: queue set penalty on [in ]\n"
- " Set a member's penalty in the queue specified. If no queue is specified\n"
- " then that interface's penalty is set in all queues to which that interface is a member\n";
+ "Usage: queue set (penalty|calls|paused|lastcall|wrapuptime|nextwrapuptime) [+|-] on [in ] [because ]\n"
+ " Set a member's field in the queue specified. If no queue is specified\n"
+ " then that interface's field is set in all queues to which that interface is a member\n";
return NULL;
case CLI_GENERATE:
- return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
+ return complete_queue_set_member(a->line, a->word, a->pos, a->n);
}
- if (a->argc != 6 && a->argc != 8) {
+ ast_log(LOG_WARNING, "handle_queue_set_member\n");
+
+ //TODO: atis: make reason multi-word
+ //TODO: probably it would be nice to allow specify membername instead of interface, and provide lookup for both
+ if (a->argc != 6 && a->argc != 8 && a->argc !=10) {
return CLI_SHOWUSAGE;
- } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
+ } else if (strcmp(a->argv[4], "on")) {
return CLI_SHOWUSAGE;
+ } else if (a->argc == 6 && (strcmp(a->argv[6], "in") || strcmp(a->argv[6], "because"))) {
+ return CLI_SHOWUSAGE;
+ } else if (a->argc == 7 && (strcmp(a->argv[6], "because"))) {
+ return CLI_SHOWUSAGE;
+ } else if (a->argc >= 8 && strcmp(a->argv[8], "because")) {
+ return CLI_SHOWUSAGE;
}
- if (a->argc == 8)
+ ast_log(LOG_WARNING, "handle_queue_set_member 2\n");
+
+ if (a->argc == 6 && !strcmp(a->argv[6], "in"))
queuename = a->argv[7];
+ if (a->argc == 6 && !strcmp(a->argv[6], "because"))
+ reason = a->argv[7];
+ if (a->argc == 8 && !strcmp(a->argv[8], "because"))
+ reason = a->argv[9];
+
+ ast_log(LOG_WARNING, "handle_queue_set_member 3\n");
+
+ field = a->argv[2];
+ value = a->argv[3];
interface = a->argv[5];
- penalty = atoi(a->argv[3]);
- switch (set_member_penalty(queuename, interface, penalty)) {
+ ast_log(LOG_WARNING, "handle_queue_set_member 4 (field: %s)\n", field);
+
+ if (strcmp(field, "penalty") && strcmp(field, "calls") && strcmp(field, "paused") &&
+ strcmp(field, "lastcall") && strcmp(field, "wrapuptime") && strcmp(field, "nextwrapuptime")) {
+ return CLI_SHOWUSAGE;
+ }
+ ast_log(LOG_WARNING, "handle_queue_set_member 5\n");
+
+ switch (update_member_field(queuename, interface, field, value, reason)) {
case RESULT_SUCCESS:
- ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
+ ast_cli(a->fd, "Set %s on interface '%s' in queue '%s'\n", field, interface, S_OR(queuename,""));
return CLI_SUCCESS;
case RESULT_FAILURE:
- ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
+ ast_cli(a->fd, "Failed to set %s on interface '%s' in queue '%s'\n", field, interface, S_OR(queuename,""));
return CLI_FAILURE;
default:
return CLI_FAILURE;
@@ -7508,16 +7781,12 @@
static const char qum_cmd_usage[] =
"Usage: queue unpause member in reason \n";
-static const char qsmp_cmd_usage[] =
-"Usage: queue set member penalty from \n";
-
static struct ast_cli_entry cli_queue[] = {
AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
- AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
- AST_CLI_DEFINE(handle_queue_set_member_wrapuptime, "Set wrapuptime for a member of a specified queue"),
+ AST_CLI_DEFINE(handle_queue_set_member, "Update queue member fields"),
AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
@@ -7540,6 +7809,8 @@
res |= ast_manager_unregister("QueuePause");
res |= ast_manager_unregister("QueueLog");
res |= ast_manager_unregister("QueuePenalty");
+ res |= ast_manager_unregister("QueueMember");
+ /* TODO: eliel: remove before merge */
res |= ast_manager_unregister("QueueMemberWrapuptime");
res |= ast_manager_unregister("QueueMemberNextWrapuptime");
res |= ast_unregister_application(app_aqm);
@@ -7550,10 +7821,10 @@
res |= ast_unregister_application(app);
res |= ast_custom_function_unregister(&queuevar_function);
res |= ast_custom_function_unregister(&queuemembercount_function);
- res |= ast_custom_function_unregister(&queuemembercount_dep);
res |= ast_custom_function_unregister(&queuememberlist_function);
res |= ast_custom_function_unregister(&queuewaitingcount_function);
- res |= ast_custom_function_unregister(&queuememberpenalty_function);
+ res |= ast_custom_function_unregister(&queuememberpenalty_dep);
+ res |= ast_custom_function_unregister(&queuemember_function);
if (device_state_sub)
ast_event_unsubscribe(device_state_sub);
@@ -7610,7 +7881,9 @@
res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log");
+ res |= ast_manager_register("QueueMember", EVENT_FLAG_AGENT, manager_queue_member, "Update the fields for a queue member");
res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member");
+ /* TODO: eliel: remove before merge */
res |= ast_manager_register("QueueMemberWrapuptime", EVENT_FLAG_AGENT, manager_queue_member_wrapuptime, "Set the wrapuptime for a queue member.");
res |= ast_manager_register("QueueMemberNextWrapuptime", EVENT_FLAG_AGENT, manager_queue_member_next_wrapuptime,
"Set the wrapuptime for a queue member, only for the next call.");
@@ -7619,10 +7892,10 @@
res |= ast_manager_register("QueueReset", 0, manager_queue_reset, "Reset queue statistics");
res |= ast_custom_function_register(&queuevar_function);
res |= ast_custom_function_register(&queuemembercount_function);
- res |= ast_custom_function_register(&queuemembercount_dep);
res |= ast_custom_function_register(&queuememberlist_function);
res |= ast_custom_function_register(&queuewaitingcount_function);
- res |= ast_custom_function_register(&queuememberpenalty_function);
+ res |= ast_custom_function_register(&queuememberpenalty_dep);
+ res |= ast_custom_function_register(&queuemember_function);
if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
@@ -7651,3 +7924,4 @@
.reload = reload,
);
+