diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | apps/app_queue.c | 128 | ||||
-rw-r--r-- | configs/queues.conf.sample | 6 |
3 files changed, 85 insertions, 52 deletions
@@ -265,6 +265,9 @@ Queue changes * Added new channel variable QUEUE_MIN_PENALTY * QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY may be adjusted in mid-call by defining rules in queuerules.conf. See configs/queuerules.conf.sample for details + * Added a new parameter for member definition, called state_interface. This may be + used so that a member may be called via one interface but have a different interface's + device state reported. MeetMe Changes -------------- diff --git a/apps/app_queue.c b/apps/app_queue.c index 1185b361c..8e35d7da7 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -352,7 +352,8 @@ struct queue_ent { }; struct member { - char interface[80]; /*!< Technology/Location */ + char interface[80]; /*!< Technology/Location to dial to reach this member*/ + char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */ char membername[80]; /*!< Member name to use in queue logs */ int penalty; /*!< Are we a last resort? */ int calls; /*!< Number of calls serviced by this member */ @@ -690,7 +691,7 @@ static void *handle_statechange(struct statechange *sc) while ((cur = ao2_iterator_next(&mem_iter))) { char *interface; char *slash_pos; - interface = ast_strdupa(cur->interface); + interface = ast_strdupa(cur->state_interface); if ((slash_pos = strchr(interface, '/'))) if ((slash_pos = strchr(slash_pos + 1, '/'))) *slash_pos = '\0'; @@ -815,7 +816,7 @@ static void device_state_cb(const struct ast_event *event, void *unused) statechange_queue(device, state); } -static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused) +static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface) { struct member *cur; @@ -823,6 +824,10 @@ static struct member *create_queue_member(const char *interface, const char *mem cur->penalty = penalty; cur->paused = paused; 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)); + else + ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); if (!ast_strlen_zero(membername)) ast_copy_string(cur->membername, membername, sizeof(cur->membername)); else @@ -958,20 +963,20 @@ static int interface_exists_global(const char *interface) { struct call_queue *q; struct member *mem, tmpmem; - struct ao2_iterator queue_iter; + struct ao2_iterator queue_iter, mem_iter; int ret = 0; ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); queue_iter = ao2_iterator_init(queues, 0); while ((q = ao2_iterator_next(&queue_iter))) { - ao2_lock(q); - if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { - ao2_ref(mem, -1); - ao2_unlock(q); - queue_unref(q); - ret = 1; - break; + mem_iter = ao2_iterator_init(q->members, 0); + while ((mem = ao2_iterator_next(&mem_iter))) { + if (!strcasecmp(mem->state_interface, interface)) { + ao2_ref(mem, -1); + ret = 1; + break; + } } ao2_unlock(q); queue_unref(q); @@ -991,7 +996,7 @@ static int remove_from_interfaces(const char *interface) ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); AST_LIST_REMOVE_CURRENT(list); ast_free(curint); - } + } break; } } @@ -1256,7 +1261,7 @@ static void queue_set_param(struct call_queue *q, const char *param, const char } } -static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str) +static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface) { struct member *m, tmpmem; int penalty = 0; @@ -1280,10 +1285,10 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const /* Create a new one if not found, else update penalty */ if (!m) { - if ((m = create_queue_member(interface, membername, penalty, paused))) { + if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { m->dead = 0; m->realtime = 1; - add_to_interfaces(interface); + add_to_interfaces(state_interface); ao2_link(q->members, m); ao2_ref(m, -1); m = NULL; @@ -1293,6 +1298,11 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const m->dead = 0; /* Do not delete this one. */ if (paused_str) m->paused = paused; + if (strcasecmp(state_interface, m->state_interface)) { + remove_from_interfaces(m->state_interface); + ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); + add_to_interfaces(m->state_interface); + } m->penalty = penalty; ao2_ref(m, -1); } @@ -1307,7 +1317,7 @@ static void free_members(struct call_queue *q, int all) while ((cur = ao2_iterator_next(&mem_iter))) { if (all || !cur->dynamic) { ao2_unlink(q->members, cur); - remove_from_interfaces(cur->interface); + remove_from_interfaces(cur->state_interface); q->membercount--; } ao2_ref(cur, -1); @@ -1436,7 +1446,8 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "membername"), ast_variable_retrieve(member_config, interface, "penalty"), - ast_variable_retrieve(member_config, interface, "paused")); + ast_variable_retrieve(member_config, interface, "paused"), + ast_variable_retrieve(member_config, interface, "state_interface")); } /* Delete all realtime members that have been deleted in DB. */ @@ -1444,9 +1455,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as while ((m = ao2_iterator_next(&mem_iter))) { if (m->dead) { ao2_unlink(q->members, m); - ao2_unlock(q); - remove_from_interfaces(m->interface); - ao2_lock(q); + remove_from_interfaces(m->state_interface); q->membercount--; } ao2_ref(m, -1); @@ -1549,7 +1558,8 @@ static void update_realtime_members(struct call_queue *q) rt_handle_member_record(q, interface, S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), ast_variable_retrieve(member_config, interface, "penalty"), - ast_variable_retrieve(member_config, interface, "paused")); + ast_variable_retrieve(member_config, interface, "paused"), + ast_variable_retrieve(member_config, interface, "state_interface")); } /* Delete all realtime members that have been deleted in DB. */ @@ -1557,9 +1567,7 @@ static void update_realtime_members(struct call_queue *q) while ((m = ao2_iterator_next(&mem_iter))) { if (m->dead) { ao2_unlink(q->members, m); - ao2_unlock(q); - remove_from_interfaces(m->interface); - ao2_lock(q); + remove_from_interfaces(m->state_interface); q->membercount--; } ao2_ref(m, -1); @@ -3578,6 +3586,7 @@ static int remove_from_queue(const char *queuename, const char *interface) "MemberName: %s\r\n", q->name, mem->interface, mem->membername); ao2_unlink(q->members, mem); + remove_from_interfaces(mem->state_interface); ao2_ref(mem, -1); if (queue_persistent_members) @@ -3591,14 +3600,11 @@ static int remove_from_queue(const char *queuename, const char *interface) queue_unref(q); } - if (res == RES_OKAY) - remove_from_interfaces(interface); - return res; } -static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump) +static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface) { struct call_queue *q; struct member *new_member, *old_member; @@ -3613,8 +3619,8 @@ static int add_to_queue(const char *queuename, const char *interface, const char ao2_lock(q); if ((old_member = interface_exists(q, interface)) == NULL) { - add_to_interfaces(interface); - if ((new_member = create_queue_member(interface, membername, penalty, paused))) { + if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { + add_to_interfaces(state_interface); new_member->dynamic = 1; ao2_link(q->members, new_member); q->membercount++; @@ -3797,6 +3803,7 @@ static void reload_queue_members(void) char *member; char *interface; char *membername = NULL; + char *state_interface; char *penalty_tok; int penalty = 0; char *paused_tok; @@ -3846,6 +3853,7 @@ static void reload_queue_members(void) penalty_tok = strsep(&member, ";"); paused_tok = strsep(&member, ";"); membername = strsep(&member, ";"); + state_interface = strsep(&member, ";"); if (!penalty_tok) { ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); @@ -3866,12 +3874,10 @@ static void reload_queue_members(void) ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); break; } - if (ast_strlen_zero(membername)) - membername = interface; ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); - if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) { + if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); break; } @@ -4020,6 +4026,7 @@ static int aqm_exec(struct ast_channel *chan, void *data) AST_APP_ARG(penalty); AST_APP_ARG(options); AST_APP_ARG(membername); + AST_APP_ARG(state_interface); ); int penalty = 0; @@ -4046,7 +4053,7 @@ static int aqm_exec(struct ast_channel *chan, void *data) } } - switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) { + switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { case RES_OKAY: ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); @@ -4803,7 +4810,7 @@ static int reload_queues(int reload) int new; const char *general_val = NULL; char parse[80]; - char *interface; + char *interface, *state_interface; char *membername = NULL; int penalty; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; @@ -4812,6 +4819,7 @@ static int reload_queues(int reload) AST_APP_ARG(interface); AST_APP_ARG(penalty); AST_APP_ARG(membername); + AST_APP_ARG(state_interface); ); /*First things first. Let's load queuerules.conf*/ @@ -4880,8 +4888,10 @@ static int reload_queues(int reload) /* Check if a queue with this name already exists */ if (q->found) { ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); - if (!new) + if (!new) { ao2_unlock(q); + queue_unref(q); + } continue; } /* Due to the fact that the "linear" strategy will have a different allocation @@ -4933,11 +4943,22 @@ static int reload_queues(int reload) while (*membername && *membername < 33) membername++; } + if (!ast_strlen_zero(args.state_interface)) { + state_interface = args.state_interface; + while (*state_interface && *state_interface < 33) state_interface++; + } else + state_interface = interface; + /* Find the old position in the list */ ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); - - newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0); + /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ + if (cur && strcasecmp(cur->state_interface, state_interface)) { + remove_from_interfaces(cur->state_interface); + } + newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); + if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) + add_to_interfaces(state_interface); ao2_link(q->members, newm); ao2_ref(newm, -1); newm = NULL; @@ -4945,8 +4966,6 @@ static int reload_queues(int reload) if (cur) ao2_ref(cur, -1); else { - /* Add them to the master int list if necessary */ - add_to_interfaces(interface); q->membercount++; } } else { @@ -4961,16 +4980,16 @@ static int reload_queues(int reload) ao2_ref(cur, -1); continue; } - - remove_from_interfaces(cur->interface); + ast_log(LOG_DEBUG, "%s in queue marked as delme, we should be deleting...\n", cur->interface); q->membercount--; ao2_unlink(q->members, cur); + remove_from_interfaces(cur->interface); ao2_ref(cur, -1); } if (new) { ao2_link(queues, q); - } else + } else ao2_unlock(q); queue_unref(q); } @@ -5352,7 +5371,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m) static int manager_add_queue_member(struct mansession *s, const struct message *m) { - const char *queuename, *interface, *penalty_s, *paused_s, *membername; + const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; int paused, penalty = 0; queuename = astman_get_header(m, "Queue"); @@ -5360,6 +5379,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message * penalty_s = astman_get_header(m, "Penalty"); paused_s = astman_get_header(m, "Paused"); membername = astman_get_header(m, "MemberName"); + state_interface = astman_get_header(m, "StateInterface"); if (ast_strlen_zero(queuename)) { astman_send_error(s, m, "'Queue' not specified."); @@ -5381,7 +5401,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message * else paused = abs(ast_true(paused_s)); - switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) { + switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { case RES_OKAY: ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); astman_send_ack(s, m, "Added interface to queue"); @@ -5537,26 +5557,28 @@ static int manager_queue_member_penalty(struct mansession *s, const struct messa static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char *queuename, *interface, *membername = NULL; + char *queuename, *interface, *membername = NULL, *state_interface; int penalty; switch ( cmd ) { case CLI_INIT: e->command = "queue add member"; e->usage = - "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n"; + "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"; return NULL; case CLI_GENERATE: return complete_queue_add_member(a->line, a->word, a->pos, a->n); } - if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10)) { + if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { return CLI_SHOWUSAGE; } else if (strcmp(a->argv[4], "to")) { return CLI_SHOWUSAGE; - } else if ((a->argc == 8) && strcmp(a->argv[6], "penalty")) { + } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { + return CLI_SHOWUSAGE; + } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { return CLI_SHOWUSAGE; - } else if ((a->argc == 10) && strcmp(a->argv[8], "as")) { + } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { return CLI_SHOWUSAGE; } @@ -5580,7 +5602,11 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as membername = a->argv[9]; } - switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) { + if (a->argc >= 12) { + state_interface = a->argv[11]; + } + + switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { case RES_OKAY: ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index 7fe148639..92c323773 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -375,7 +375,10 @@ shared_lastcall=no ; entries with higher penalties are considered last. An optional member ; name may also be specified after a second comma, which is used in log ; messages as a "friendly name". Multiple interfaces may share a single -; member name. +; member name. An optional state interface may be specified after a third +; comma. This interface will be the one for which app_queue receives device +; state notifications, even though the first interface specified is the one +; that is actually called. ; ; It is important to ensure that channel drivers used for members are loaded ; before app_queue.so itself or they may be marked invalid until reload. This @@ -386,6 +389,7 @@ shared_lastcall=no ;member => Zap/3,10,Bob Johnson ;member => Agent/1001 ;member => Agent/1002 +;member => Local/1000@default,0,John Smith,SIP/1000 ; ; Note that using agent groups is probably not what you want. Strategies do |