diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f56f2fe8844fdb2180d964080827af1635581a00..31701114017109ecd0e1a58a0e68a5968d62de95 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -5733,20 +5733,24 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
 }
 
 /*--- cb_extensionstate: Part of thte SUBSCRIBE support subsystem ---*/
-static int cb_extensionstate(char *context, char* exten, int state, void *data)
+static int cb_extensionstate(char *context, char* exten, enum ast_extension_states state, void *data)
 {
 	struct sip_pvt *p = data;
-	if (state == -1) {
+
+	switch (state) {
+	case AST_EXTENSION_DEACTIVATED:
+	case AST_EXTENSION_REMOVED:
+		transmit_state_notify(p, state, 1);
 		sip_scheddestroy(p, 15000);
 		p->stateid = -1;
 		return 0;
+	default:
+		transmit_state_notify(p, state, 1);
+		
+		if (option_debug > 1)
+			ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username);
+		return 0;
 	}
- 
-	transmit_state_notify(p, state, 1);
-
-	if (option_debug > 1)
-		ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username);
-	return 0;
 }
 
 /*--- register_verify: Verify registration of user */
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index b0ca14cc0af1fb376b433a642273b335dc70823e..d54d3ef8ebb7e22bd5a6fa816aeac0f34d3f7af4 100755
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -34,14 +34,20 @@ extern "C" {
 #define PRIORITY_HINT	-1
 
 /*! Extension states */
-/*! No device INUSE or BUSY  */
-#define AST_EXTENSION_NOT_INUSE		0
-/*! One or more devices INUSE */
-#define AST_EXTENSION_INUSE		1
-/*! All devices BUSY */
-#define AST_EXTENSION_BUSY		2
-/*! All devices UNAVAILABLE/UNREGISTERED */
-#define AST_EXTENSION_UNAVAILABLE 	3
+enum ast_extension_states {
+	/*! Extension removed */
+	AST_EXTENSION_REMOVED = -2,
+	/*! Extension hint removed */
+	AST_EXTENSION_DEACTIVATED = -1,
+	/*! No device INUSE or BUSY  */
+	AST_EXTENSION_NOT_INUSE = 0,
+	/*! One or more devices INUSE */
+	AST_EXTENSION_INUSE = 1,
+	/*! All devices BUSY */
+	AST_EXTENSION_BUSY = 2,
+	/*! All devices UNAVAILABLE/UNREGISTERED */
+	AST_EXTENSION_UNAVAILABLE = 3,
+};
 
 struct ast_context;
 struct ast_exten;     
@@ -49,7 +55,7 @@ struct ast_include;
 struct ast_ignorepat;
 struct ast_sw;
 
-typedef int (*ast_state_cb_type)(char *context, char* id, int state, void *data);
+typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
 
 /*! Data structure associated with a custom function */
 struct ast_custom_function {
diff --git a/pbx.c b/pbx.c
index fbce712382bd2fa2b841f7b28ec3398a033381ee..75c94ab766f2e8926be251ad658adf2bbd16fc3b 100755
--- a/pbx.c
+++ b/pbx.c
@@ -2077,7 +2077,7 @@ static int ast_remove_hint(struct ast_exten *e)
 				/* Notify with -1 and remove all callbacks */
 				cbprev = cblist;	    
 				cblist = cblist->next;
-				cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
+				cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
 				free(cbprev);
 	    		}
 	    		list->callbacks = NULL;
@@ -3014,6 +3014,8 @@ static int handle_show_hints(int fd, int argc, char *argv[])
 {
 	struct ast_hint *hint;
 	int num = 0;
+	int watchers;
+	struct ast_state_cb *watcher;
 
 	if (!hints) {
 		ast_cli(fd, "There are no registered dialplan hints\n");
@@ -3027,7 +3029,12 @@ static int handle_show_hints(int fd, int argc, char *argv[])
 	}
 	hint = hints;
 	while (hint) {
-		ast_cli(fd, "   %-20.20s: %-20.20s  State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
+		watchers = 0;
+		for (watcher = hint->callbacks; watcher; watcher = watcher->next)
+			watchers++;
+		ast_cli(fd, "   %-20.20s: %-20.20s  State %2d Watchers %2d\n",
+			ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten),
+			hint->laststate, watchers);
 		num++;
 		hint = hint->next;
 	}
@@ -3542,8 +3549,50 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c
 
 void __ast_context_destroy(struct ast_context *con, const char *registrar);
 
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) {
+struct store_hint {
+	char *context;
+	char *exten;
+	struct ast_state_cb *callbacks;
+	int laststate;
+	AST_LIST_ENTRY(store_hint) list;
+	char data[1];
+};
+
+AST_LIST_HEAD(store_hints, store_hint);
+
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
+{
 	struct ast_context *tmp, *lasttmp = NULL;
+	struct store_hints store;
+	struct store_hint *this;
+	struct ast_hint *hint;
+	struct ast_exten *exten;
+	int length;
+	struct ast_state_cb *thiscb, *prevcb;
+
+	/* preserve all watchers for hints associated with this registrar */
+	AST_LIST_HEAD_INIT(&store);
+	ast_mutex_lock(&hintlock);
+	for (hint = hints; hint; hint = hint->next) {
+		if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
+			length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
+			this = calloc(1, length);
+			if (!this) {
+				ast_log(LOG_WARNING, "Could not allocate memory to preserve hint\n");
+				continue;
+			}
+			this->callbacks = hint->callbacks;
+			hint->callbacks = NULL;
+			this->laststate = hint->laststate;
+			this->context = this->data;
+			strcpy(this->data, hint->exten->parent->name);
+			this->exten = this->data + strlen(this->context) + 1;
+			strcpy(this->exten, hint->exten->exten);
+			AST_LIST_INSERT_HEAD(&store, this, list);
+		}
+	}
+	ast_mutex_unlock(&hintlock);
+
 	tmp = *extcontexts;
 	ast_mutex_lock(&conlock);
 	if (registrar) {
@@ -3566,6 +3615,40 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
 	} else 
 		ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
 	ast_mutex_unlock(&conlock);
+
+	/* restore the watchers for hints that can be found; notify those that
+	   cannot be restored
+	*/
+	while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
+		exten = ast_hint_extension(NULL, this->context, this->exten);
+		/* Find the hint in the list of hints */
+		ast_mutex_lock(&hintlock);
+		for (hint = hints; hint; hint = hint->next) {
+			if (hint->exten == exten)
+				break;
+		}
+		if (!exten || !hint) {
+			/* this hint has been removed, notify the watchers */
+			prevcb = NULL;
+			thiscb = this->callbacks;
+			while (thiscb) {
+				prevcb = thiscb;	    
+				thiscb = thiscb->next;
+				prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
+				free(prevcb);
+	    		}
+		} else {
+			thiscb = this->callbacks;
+			while (thiscb->next)
+				thiscb = thiscb->next;
+			thiscb->next = hint->callbacks;
+			hint->callbacks = this->callbacks;
+			hint->laststate = this->laststate;
+		}
+		ast_mutex_unlock(&hintlock);
+		free(this);
+	}
+
 	return;	
 }