diff --git a/apps/app_queue.c b/apps/app_queue.c
index 53f4225b9c..0f3fa4bdf3 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1059,6 +1059,9 @@
Priority value for change for caller on queue.
+
+ When set to yes will cause the priority change to be reflected immediately, causing the channel to change position within the queue.
+
@@ -2109,8 +2112,10 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st
/* every queue_ent must have a reference to it's parent call_queue, this
* reference does not go away until the end of the queue_ent's life, meaning
* that even when the queue_ent leaves the call_queue this ref must remain. */
- queue_ref(q);
- new->parent = q;
+ if (!new->parent) {
+ queue_ref(q);
+ new->parent = q;
+ }
new->pos = ++(*pos);
new->opos = *pos;
}
@@ -7711,10 +7716,10 @@ static int add_to_queue(const char *queuename, const char *interface, const char
* \retval RES_OKAY change priority
* \retval RES_NOT_CALLER queue exists but no caller
*/
-static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
+static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
{
struct call_queue *q;
- struct queue_ent *qe;
+ struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
int res = RES_NOSUCHQUEUE;
/*! \note Ensure the appropriate realtime queue is loaded. Note that this
@@ -7725,14 +7730,57 @@ static int change_priority_caller_on_queue(const char *queuename, const char *ca
ao2_lock(q);
res = RES_NOT_CALLER;
- for (qe = q->head; qe; qe = qe->next) {
- if (strcmp(ast_channel_name(qe->chan), caller) == 0) {
+ for (current = q->head; current; current = current->next) {
+ if (strcmp(ast_channel_name(current->chan), caller) == 0) {
ast_debug(1, "%s Caller new priority %d in queue %s\n",
caller, priority, queuename);
- qe->prio = priority;
+ current->prio = priority;
+ if (immediate) {
+ /* This caller is being immediately moved in the queue so remove them */
+ if (prev) {
+ prev->next = current->next;
+ } else {
+ q->head = current->next;
+ }
+ caller_qe = current;
+ /* The position for all callers is not recalculated in here as it will
+ * be updated when the moved caller is inserted back into the queue
+ */
+ }
res = RES_OKAY;
+ break;
+ } else if (immediate) {
+ prev = current;
}
}
+
+ if (caller_qe) {
+ int inserted = 0, pos = 0;
+
+ /* If a caller queue entry exists, we are applying their priority immediately
+ * and have to reinsert them at the correct position.
+ */
+ prev = NULL;
+ current = q->head;
+ while (current) {
+ if (!inserted && (caller_qe->prio > current->prio)) {
+ insert_entry(q, prev, caller_qe, &pos);
+ inserted = 1;
+ }
+
+ /* We always update the position as it may have changed */
+ current->pos = ++pos;
+
+ /* Move to the next caller in the queue */
+ prev = current;
+ current = current->next;
+ }
+
+ if (!inserted) {
+ insert_entry(q, prev, caller_qe, &pos);
+ }
+ }
+
ao2_unlock(q);
return res;
}
@@ -10909,12 +10957,13 @@ static int manager_queue_member_penalty(struct mansession *s, const struct messa
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
{
- const char *queuename, *caller, *priority_s;
- int priority = 0;
+ const char *queuename, *caller, *priority_s, *immediate_s;
+ int priority = 0, immediate = 0;
queuename = astman_get_header(m, "Queue");
caller = astman_get_header(m, "Caller");
priority_s = astman_get_header(m, "Priority");
+ immediate_s = astman_get_header(m, "Immediate");
if (ast_strlen_zero(queuename)) {
astman_send_error(s, m, "'Queue' not specified.");
@@ -10934,7 +10983,11 @@ static int manager_change_priority_caller_on_queue(struct mansession *s, const s
return 0;
}
- switch (change_priority_caller_on_queue(queuename, caller, priority)) {
+ if (!ast_strlen_zero(immediate_s)) {
+ immediate = ast_true(immediate_s);
+ }
+
+ switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
case RES_OKAY:
astman_send_ack(s, m, "Priority change for caller on queue");
break;
@@ -11178,21 +11231,21 @@ static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct
static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
const char *queuename, *caller;
- int priority;
+ int priority, immediate = 0;
char *res = CLI_FAILURE;
switch (cmd) {
case CLI_INIT:
e->command = "queue priority caller";
e->usage =
- "Usage: queue priority caller on to \n"
- " Change the priority of a channel on a queue.\n";
+ "Usage: queue priority caller on to [immediate]\n"
+ " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
- if (a->argc != 8) {
+ if (a->argc < 8) {
return CLI_SHOWUSAGE;
} else if (strcmp(a->argv[4], "on")) {
return CLI_SHOWUSAGE;
@@ -11201,12 +11254,17 @@ static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cm
} else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
ast_log (LOG_ERROR, " parameter must be an integer.\n");
return CLI_SHOWUSAGE;
+ } else if (a->argc == 9) {
+ if (strcmp(a->argv[8], "immediate")) {
+ return CLI_SHOWUSAGE;
+ }
+ immediate = 1;
}
caller = a->argv[3];
queuename = a->argv[5];
- switch (change_priority_caller_on_queue(queuename, caller, priority)) {
+ switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
case RES_OKAY:
res = CLI_SUCCESS;
break;