Index: apps/app_queue.c =================================================================== --- apps/app_queue.c (revision 196621) +++ apps/app_queue.c (working copy) @@ -512,6 +512,85 @@ return -1; } +static int check_device_in_hint(char *context, char *exten, char *device) +{ + char hint[AST_MAX_EXTENSION]; + char *cur, *rest; + struct ast_exten *e; + + e = ast_hint_extension(NULL, context, exten); + if (!e) + return 0; + + ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint)); + + rest = hint; /* One or more devices separated with a & character */ + while ( (cur = strsep(&rest, "&")) ) { + if (!strcasecmp(device, cur)) { + return 1; + } + } + return 0; +} + +static int extension_to_devicestate(const char *context, const char *exten) { + int res_exten; + int res_dev; + res_exten = ast_extension_state(NULL, context, exten); + + // We need to convert from the extension state to device state that the application is expecting + // + switch (res_exten) { + case AST_EXTENSION_NOT_INUSE: + res_dev = AST_DEVICE_NOT_INUSE; + break; + case AST_EXTENSION_INUSE: + res_dev = AST_DEVICE_INUSE; + break; + case AST_EXTENSION_BUSY: + res_dev = AST_DEVICE_BUSY; + break; + case AST_EXTENSION_RINGING: + res_dev = AST_DEVICE_RINGING; + break; + case AST_EXTENSION_ONHOLD: + res_dev = AST_DEVICE_ONHOLD; + break; + case AST_EXTENSION_UNAVAILABLE: + res_dev = AST_DEVICE_UNAVAILABLE; + break; + case AST_EXTENSION_REMOVED: + case AST_EXTENSION_DEACTIVATED: + default: + res_dev = AST_DEVICE_INVALID; + break; + } + return res_dev; +} + + +static int devexten_check(const char *dev) +{ + char hint[AST_MAX_EXTENSION]; + char *exten, *context; + + // If formatted as HINT:nnn@context then we treat that way. dev+5 strips us past the HINT: + // + if (!strncasecmp(dev,"HINT:",5)) { + ast_copy_string(hint, (dev+5), sizeof(hint)); + context = hint; + // TODO: if we parse this in the config file loader and AddQueueMember call we + // could avoid checking and fixing EVERY time here + // + exten = strsep(&context,"@"); + if (ast_strlen_zero(context)) + context = "default"; + return extension_to_devicestate(context, exten); + } else { + return ast_device_state(dev); + } +} + /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) { @@ -645,6 +724,7 @@ static void *handle_statechange(struct statechange *sc) { struct member_interface *curint; + int state_result = AST_DEVICE_INVALID; char *loc; char *technology; char interface[80]; @@ -653,20 +733,54 @@ loc = strchr(technology, '/'); if (loc) { *loc++ = '\0'; + /* } else { + // TODO: THIS IS A BUG, it means that state change for Custom:NNNN devstates are ignored, amongst others + // return NULL; + */ } AST_LIST_LOCK(&interfaces); AST_LIST_TRAVERSE(&interfaces, curint, list) { - char *slash_pos; + char *delim_pos; + char *context; + char *exten; ast_copy_string(interface, curint->interface, sizeof(interface)); - if ((slash_pos = strchr(interface, '/'))) - if ((slash_pos = strchr(slash_pos + 1, '/'))) - *slash_pos = '\0'; - if (!strcasecmp(interface, sc->dev)) - break; + // Check for standard tech/xxx[/n] formats + // + if ((delim_pos = strchr(interface, '/'))) { + if ((delim_pos = strchr(delim_pos + 1, '/'))) + *delim_pos = '\0'; + + if (!strcasecmp(interface, sc->dev)) { + state_result = sc->state; + break; + } + // Check for standard HINT:xxx[@context] formats + // + } else if (!strncasecmp(interface,"HINT:",5)) { + // TODO: if we parse this in the config file loader and AddQueueMember call we + // could avoid checking and fixing EVERY time here + // + context = interface + 5; // strip off HINT: (5 bytes) + exten = strsep(&context,"@"); + if (ast_strlen_zero(context)) + context = "default"; + + if (check_device_in_hint(context, exten, sc->dev)) { + state_result = extension_to_devicestate(context, exten); + break; + } + // All other Device types that: Custom:NNN, MeetMe:NNN, etc. + // + } else { + if (!strcasecmp(interface, sc->dev)) { + state_result = sc->state; + break; + } + } } AST_LIST_UNLOCK(&interfaces); @@ -679,7 +793,7 @@ if (option_debug) ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state)); - update_status(sc->dev, sc->state); + update_status(curint->interface, state_result); return NULL; } @@ -774,7 +888,7 @@ 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); + cur->status = devexten_check(cur->state_interface); } return cur; @@ -1922,7 +2036,7 @@ ast_cdr_busy(qe->chan->cdr); tmp->stillgoing = 0; - update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); + update_status(tmp->member->state_interface, devexten_check(tmp->member->state_interface)); ast_mutex_lock(&qe->parent->lock); qe->parent->rrpos++; @@ -1989,7 +2103,7 @@ ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); do_hang(tmp); (*busies)++; - update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); + update_status(tmp->member->state_interface, devexten_check(tmp->member->state_interface)); return 0; } else if (qe->parent->eventwhencalled) { char vars[2048]; @@ -2013,7 +2127,7 @@ ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); } - update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); + update_status(tmp->member->state_interface, devexten_check(tmp->member->state_interface)); return 1; } @@ -4538,7 +4652,7 @@ while ((cur = ao2_iterator_next(&mem_iter))) { if (cur->dynamic) q->membercount++; - cur->status = ast_device_state(cur->state_interface); + cur->status = devexten_check(cur->state_interface); ao2_ref(cur, -1); } ast_mutex_unlock(&q->lock); Index: include/asterisk/pbx.h =================================================================== --- include/asterisk/pbx.h (revision 196621) +++ include/asterisk/pbx.h (working copy) @@ -316,6 +316,17 @@ */ int ast_extension_state(struct ast_channel *c, const char *context, const char *exten); +/*! + * \brief ast_hint_extension: Find hint for given extension in context + * + * \param c this is not important + * \param context which context to look in + * \param exten which extension to get state + * + * \return extension structure as defined in struct ast_exten + */ +struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten); + /*! * \brief Return string representation of the state of an extension *