Index: include/asterisk/devicestate.h
===================================================================
--- include/asterisk/devicestate.h	(revision 204194)
+++ include/asterisk/devicestate.h	(working copy)
@@ -45,6 +45,8 @@
 #define AST_DEVICE_RINGINUSE	7
 /*! Device is on hold */
 #define AST_DEVICE_ONHOLD	8
+/*! Total number of device states used during testing */
+#define AST_DEVICE_TOTAL	9
 
 /*! \brief Devicestate watcher call back */
 typedef int (*ast_devstate_cb_type)(const char *dev, int state, void *data);
Index: main/devicestate.c
===================================================================
--- main/devicestate.c	(revision 204194)
+++ main/devicestate.c	(working copy)
@@ -97,6 +97,10 @@
 /*! \brief Find devicestate as text message for output */
 const char *devstate2str(int devstate) 
 {
+	if (devstate >= ARRAY_LEN(devstatestring)) {
+		devstate = 0; /* 0 = unknown */
+	}
+
 	return devstatestring[devstate];
 }
 
Index: main/pbx.c
===================================================================
--- main/pbx.c	(revision 204194)
+++ main/pbx.c	(working copy)
@@ -201,6 +201,16 @@
 	AST_LIST_ENTRY(ast_hint) list;	/*!< Pointer to next hint in list */
 };
 
+struct exten_state_helper {
+	int allunavailable;
+	int allbusy;
+	int allfree;
+	int busy;
+	int inuse;
+	int ring;
+	int onhold;
+};
+
 static const struct cfextension_states {
 	int extension_state;
 	const char * const text;
@@ -1915,82 +1925,102 @@
 	return e;
 }
 
+static void exten_state_helper_init(struct exten_state_helper *s)
+{
+	s->allunavailable = 1;
+	s->allbusy = 1;
+	s->allfree = 1;
+	s->busy = 0;
+	s->inuse = 0;
+	s->ring = 0;
+	s->onhold = 0;
+}
+
+static void set_exten_state_helper(struct exten_state_helper *s, int res)
+{
+	switch (res) {
+	case AST_DEVICE_NOT_INUSE:
+		s->allunavailable = 0;
+		s->allbusy = 0;
+		break;
+	case AST_DEVICE_INUSE:
+		s->inuse = 1;
+		s->allunavailable = 0;
+		s->allfree = 0;
+		break;
+	case AST_DEVICE_RINGING:
+		s->ring = 1;
+		s->allunavailable = 0;
+		s->allfree = 0;
+		break;
+	case AST_DEVICE_RINGINUSE:
+		s->inuse = 1;
+		s->ring = 1;
+		s->allunavailable = 0;
+		s->allfree = 0;
+		break;
+	case AST_DEVICE_ONHOLD:
+		s->allunavailable = 0;
+		s->allfree = 0;
+		s->onhold = 1;
+		break;
+	case AST_DEVICE_BUSY:
+		s->allunavailable = 0;
+		s->allfree = 0;
+		s->busy = 1;
+		s->inuse = 1;
+		break;
+	case AST_DEVICE_UNAVAILABLE:
+	case AST_DEVICE_INVALID:
+		s->allbusy = 0;
+		s->allfree = 0;
+		break;
+	default:
+		s->allunavailable = 0;
+		s->allbusy = 0;
+		s->allfree = 0;
+	}
+}
+static enum ast_extension_states get_exten_state(struct exten_state_helper *s)
+{
+	if (s->allfree)
+		return AST_EXTENSION_NOT_INUSE;
+	if ((s->inuse || s->onhold) && s->ring)
+		return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
+	if (s->ring)
+		return AST_EXTENSION_RINGING;
+	if (s->busy)
+		return AST_EXTENSION_BUSY;
+	if (s->inuse)
+		return AST_EXTENSION_INUSE;
+	if (s->onhold)
+		return AST_EXTENSION_ONHOLD;
+	if (s->allbusy)
+		return AST_EXTENSION_BUSY;
+	if (s->allunavailable)
+		return AST_EXTENSION_UNAVAILABLE;
+
+	return AST_EXTENSION_NOT_INUSE;
+}
+
 /*! \brief  ast_extensions_state2: Check state of extension by using hints */
 static int ast_extension_state2(struct ast_exten *e)
 {
 	char hint[AST_MAX_EXTENSION];
 	char *cur, *rest;
-	int allunavailable = 1, allbusy = 1, allfree = 1;
-	int busy = 0, inuse = 0, ring = 0, onhold = 0;
-
+	struct exten_state_helper s;
 	if (!e)
 		return -1;
 
+	exten_state_helper_init(&s);
 	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, "&")) ) {
-		int res = ast_device_state(cur);
-		switch (res) {
-		case AST_DEVICE_NOT_INUSE:
-			allunavailable = 0;
-			allbusy = 0;
-			break;
-		case AST_DEVICE_INUSE:
-			inuse = 1;
-			allunavailable = 0;
-			allfree = 0;
-			break;
-		case AST_DEVICE_RINGING:
-			ring = 1;
-			allunavailable = 0;
-			allfree = 0;
-			break;
-		case AST_DEVICE_RINGINUSE:
-			inuse = 1;
-			ring = 1;
-			allunavailable = 0;
-			allfree = 0;
-			break;
-		case AST_DEVICE_ONHOLD:
-			allunavailable = 0;
-			allfree = 0;
-			onhold = 1;
-			break;
-		case AST_DEVICE_BUSY:
-			allunavailable = 0;
-			allfree = 0;
-			busy = 1;
-			inuse = 1;
-			break;
-		case AST_DEVICE_UNAVAILABLE:
-		case AST_DEVICE_INVALID:
-			allbusy = 0;
-			allfree = 0;
-			break;
-		default:
-			allunavailable = 0;
-			allbusy = 0;
-			allfree = 0;
-		}
+		set_exten_state_helper(&s, ast_device_state(cur));
 	}
 
-	if (allfree)
-		return AST_EXTENSION_NOT_INUSE;
-	if ((inuse || onhold) && ring)
-		return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
-	if (allbusy)
-		return AST_EXTENSION_BUSY;
-	if (inuse)
-		return AST_EXTENSION_INUSE;
-	if (ring)
-		return AST_EXTENSION_RINGING;
-	if (onhold)
-		return AST_EXTENSION_ONHOLD;
-	if (allunavailable)
-		return AST_EXTENSION_UNAVAILABLE;
-
-	return AST_EXTENSION_NOT_INUSE;
+	return get_exten_state(&s);
 }
 
 /*! \brief  ast_extension_state2str: Return extension_state as string */
@@ -3068,6 +3098,12 @@
 "Usage: core show application <application> [<application> [<application> [...]]]\n"
 "       Describes a particular application.\n";
 
+#ifdef AST_DEVMODE
+static char show_device2extenstate_help[] =
+"Usage: core show device2extenstate\n"
+"       Lists device state to extension state combinations.\n";
+#endif
+
 static char show_function_help[] =
 "Usage: core show function <function>\n"
 "       Describe a particular dialplan function.\n";
@@ -3733,6 +3769,44 @@
 	return RESULT_SUCCESS;
 }
 
+#ifdef AST_DEVMODE
+static int handle_show_device2extenstate_deprecated(int fd, int argc, char *argv[])
+{
+	struct exten_state_helper s;
+	int i, j;
+	const int max = AST_DEVICE_TOTAL;
+
+	for (i = 0; i < max; i++) {
+		for (j = 0; j < max; j++) {
+			exten_state_helper_init(&s);
+			set_exten_state_helper(&s, i);
+			set_exten_state_helper(&s, j);
+			ast_cli(fd, "\n Exten:%14s Dev1:%12s\tDev2:%12s", ast_extension_state2str(get_exten_state(&s)), devstate2str(j), devstate2str(i));
+		}
+	}
+	ast_cli(fd, "\n");
+	return RESULT_SUCCESS;
+}
+
+static int handle_show_device2extenstate(int fd, int argc, char *argv[])
+{
+	struct exten_state_helper s;
+	int i, j;
+	const int max = AST_DEVICE_TOTAL;
+
+	for (i = 0; i < max; i++) {
+		for (j = 0; j < max; j++) {
+			exten_state_helper_init(&s);
+			set_exten_state_helper(&s, i);
+			set_exten_state_helper(&s, j);
+			ast_cli(fd, "\n Exten:%14s Dev1:%12s\tDev2:%12s", ast_extension_state2str(get_exten_state(&s)), devstate2str(j), devstate2str(i));
+		}
+	}
+	ast_cli(fd, "\n");
+	return RESULT_SUCCESS;
+}
+#endif
+
 /*! \brief  CLI support for setting global variables */
 static int handle_set_global_deprecated(int fd, int argc, char *argv[])
 {
@@ -3807,6 +3881,13 @@
 	handle_set_global_deprecated, NULL,
         NULL };
 
+#ifdef AST_DEVMODE
+static struct ast_cli_entry cli_show_device2extenstate_deprecated = {
+	{ "show", "device2extenstate", NULL },
+	handle_show_device2extenstate_deprecated, NULL,
+        NULL };
+#endif
+
 static struct ast_cli_entry pbx_cli[] = {
 	{ { "core", "show", "applications", NULL },
 	handle_show_applications, "Shows registered dialplan applications",
@@ -3835,7 +3916,11 @@
 	{ { "core", "show", "application", NULL },
 	handle_show_application, "Describe a specific dialplan application",
 	show_application_help, complete_show_application, &cli_show_application_deprecated },
-
+#ifdef AST_DEVMODE
+	{ { "core", "show", "device2extenstate", NULL },
+	handle_show_device2extenstate, "Show expected exten state from multiple device states",
+	show_device2extenstate_help, NULL, &cli_show_device2extenstate_deprecated },
+#endif
 	{ { "core", "set", "global", NULL },
 	handle_set_global, "Set global dialplan variable",
 	set_global_help, NULL, &cli_set_global_deprecated },
