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
certified/1.8.6
Joshua Colp 16 years ago
parent 85e2c6d7fb
commit 2263ced9dd

@ -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;

@ -474,6 +474,10 @@ shared_lastcall=no
; state notifications, even though the first interface specified is the one
; that is actually called.
;
; A hint can also be used in place of the state interface using the format
; hint:<extension>@<context>. If no context is specified then 'default' will
; be used.
;
; 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
; can be accomplished by explicitly listing them in modules.conf before

Loading…
Cancel
Save