summaryrefslogtreecommitdiff
path: root/apps/app_queue.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2009-11-03 21:16:14 +0000
committerJoshua Colp <jcolp@digium.com>2009-11-03 21:16:14 +0000
commit2263ced9dd27312c3c5c967833702c961f079dd7 (patch)
treebca2c7c40e6cbcfd9f54d87ba5d7deb5c2ced0ae /apps/app_queue.c
parent85e2c6d7fb671287dc61463617ccf43ee0d03f20 (diff)
Add support for using a hint when configuring a state interface using the format hint:<extension>@<context>.
(closes issue #15168) Reported by: p_lindheimer Patches: queue_extenstate5_1.4.svn.patch uploaded by GameGamer43 (license 894) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@227424 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'apps/app_queue.c')
-rw-r--r--apps/app_queue.c126
1 files changed, 107 insertions, 19 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 80ce8dd39..1c8dea31a 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -824,20 +824,22 @@ struct queue_ent {
};
struct member {
- 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 */
- int dynamic; /*!< Are we dynamically added? */
- int realtime; /*!< Is this member realtime? */
- int status; /*!< Status of queue member */
- int paused; /*!< Are we paused (not accepting calls)? */
- 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 */
- unsigned int delme:1; /*!< Flag to delete entry on reload */
- char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
+ char interface[80]; /*!< Technology/Location to dial to reach this member*/
+ char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
+ char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
+ 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 */
+ int dynamic; /*!< Are we dynamically added? */
+ int realtime; /*!< Is this member realtime? */
+ int status; /*!< Status of queue member */
+ int paused; /*!< Are we paused (not accepting calls)? */
+ 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 */
+ unsigned int delme:1; /*!< Flag to delete entry on reload */
+ char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
};
enum empty_conditions {
@@ -1258,6 +1260,81 @@ static void device_state_cb(const struct ast_event *event, void *unused)
}
}
+/*! \brief Helper function which converts from extension state to device state values */
+static int extensionstate2devicestate(int state)
+{
+ switch (state) {
+ case AST_EXTENSION_NOT_INUSE:
+ state = AST_DEVICE_NOT_INUSE;
+ break;
+ case AST_EXTENSION_INUSE:
+ state = AST_DEVICE_INUSE;
+ break;
+ case AST_EXTENSION_BUSY:
+ state = AST_DEVICE_BUSY;
+ break;
+ case AST_EXTENSION_RINGING:
+ state = AST_DEVICE_RINGING;
+ break;
+ case AST_EXTENSION_ONHOLD:
+ state = AST_DEVICE_ONHOLD;
+ break;
+ case AST_EXTENSION_UNAVAILABLE:
+ state = AST_DEVICE_UNAVAILABLE;
+ break;
+ case AST_EXTENSION_REMOVED:
+ case AST_EXTENSION_DEACTIVATED:
+ default:
+ state = AST_DEVICE_INVALID;
+ break;
+ }
+
+ return state;
+}
+
+static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
+{
+ struct ao2_iterator miter, qiter;
+ struct member *m;
+ struct call_queue *q;
+ int found = 0, device_state = extensionstate2devicestate(state);
+
+ qiter = ao2_iterator_init(queues, 0);
+ while ((q = ao2_iterator_next(&qiter))) {
+ ao2_lock(q);
+
+ miter = ao2_iterator_init(q->members, 0);
+ for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
+ if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
+ update_status(q, m, device_state);
+ ao2_ref(m, -1);
+ found = 1;
+ break;
+ }
+ }
+ ao2_iterator_destroy(&miter);
+
+ ao2_unlock(q);
+ ao2_ref(q, -1);
+ }
+ ao2_iterator_destroy(&qiter);
+
+ if (found) {
+ ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
+ } else {
+ ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
+ exten, context, device_state, ast_devstate2str(device_state));
+ }
+
+ return 0;
+}
+
+/*! \brief Return the current state of a member */
+static int get_queue_member_status(struct member *cur)
+{
+ return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
+}
+
/*! \brief allocate space for new queue member and set fields based on parameters passed */
static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
{
@@ -1277,7 +1354,14 @@ static struct member *create_queue_member(const char *interface, const char *mem
ast_copy_string(cur->membername, interface, sizeof(cur->membername));
if (!strchr(cur->interface, '/'))
ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
- cur->status = ast_device_state(cur->state_interface);
+ if (!strncmp(state_interface, "hint:", 5)) {
+ char *tmp = ast_strdupa(state_interface), *context = tmp;
+ char *exten = strsep(&context, "@") + 5;
+
+ ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
+ ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
+ }
+ cur->status = get_queue_member_status(cur);
}
return cur;
@@ -2677,7 +2761,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
tmp->stillgoing = 0;
ao2_lock(qe->parent);
- update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
+ update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
qe->parent->rrpos++;
qe->linpos++;
ao2_unlock(qe->parent);
@@ -2760,7 +2844,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
ast_channel_unlock(qe->chan);
do_hang(tmp);
(*busies)++;
- update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
+ update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
return 0;
} else if (qe->parent->eventwhencalled) {
char vars[2048];
@@ -2788,7 +2872,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
ast_channel_unlock(tmp->chan);
ast_channel_unlock(qe->chan);
- update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
+ update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
return 1;
}
@@ -6093,7 +6177,7 @@ static int kill_dead_members(void *obj, void *arg, int flags)
*/
q->membercount++;
}
- member->status = ast_device_state(member->state_interface);
+ member->status = get_queue_member_status(member);
return 0;
} else {
q->membercount--;
@@ -7480,6 +7564,8 @@ static int unload_module(void)
if (device_state_sub)
ast_event_unsubscribe(device_state_sub);
+ ast_extension_state_del(0, extension_state_cb);
+
if ((con = ast_context_find("app_queue_gosub_virtual_context"))) {
ast_context_remove_extension2(con, "s", 1, NULL, 0);
ast_context_destroy(con, "app_queue"); /* leave no trace */
@@ -7553,6 +7639,8 @@ static int load_module(void)
res = -1;
}
+ ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
+
ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
return res ? AST_MODULE_LOAD_DECLINE : 0;