diff --git a/main/pbx.c b/main/pbx.c
index 7bf4faab0dd7c0fc549515f0683945d1d9ba1ace..f6fd561376d64c0718ba99e353ce58e263e8696c 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -354,8 +354,10 @@ static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
 	const struct ast_exten *ac = ah_a;
 	const struct ast_exten *bc = ah_b;
 	int x = strcmp(ac->exten, bc->exten);
-	if (x) /* if exten names are diff, then return */
+	if (x) { /* if exten names are diff, then return */
 		return x;
+	}
+	
 	/* but if they are the same, do the cidmatch values match? */
 	if (ac->matchcid && bc->matchcid) {
 		return strcmp(ac->cidmatch,bc->cidmatch);
@@ -728,6 +730,185 @@ static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
 
 static AST_LIST_HEAD_NOLOCK_STATIC(statecbs, ast_state_cb);
 
+#ifdef CONTEXT_DEBUG
+
+/* these routines are provided for doing run-time checks
+   on the extension structures, in case you are having
+   problems, this routine might help you localize where
+   the problem is occurring. It's kinda like a debug memory
+   allocator's arena checker... It'll eat up your cpu cycles!
+   but you'll see, if you call it in the right places,
+   right where your problems began...
+*/
+
+/* you can break on the check_contexts_trouble()
+routine in your debugger to stop at the moment
+there's a problem */
+void check_contexts_trouble(void);
+
+void check_contexts_trouble(void)
+{
+	int x = 1;
+	x = 2;
+}
+
+static struct ast_context *find_context_locked(const char *context);
+int check_contexts(char *, int);
+
+int check_contexts(char *file, int line )
+{
+	struct ast_hashtab_iter *t1;
+	struct ast_context *c1, *c2;
+	int found = 0;
+	struct ast_exten *e1, *e2, *e3;
+	struct ast_exten ex;
+	
+	/* try to find inconsistencies */
+	/* is every context in the context table in the context list and vice-versa ? */
+	
+	if (!contexts_table) {
+		ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
+		usleep(500000);
+	}
+
+	t1 = ast_hashtab_start_traversal(contexts_table);
+	while( (c1 = ast_hashtab_next(t1))) {
+		for(c2=contexts;c2;c2=c2->next) {
+			if (!strcmp(c1->name, c2->name)) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
+			check_contexts_trouble();
+		}
+	}
+	ast_hashtab_end_traversal(t1);
+	for(c2=contexts;c2;c2=c2->next) {
+		c1 = find_context_locked(c2->name);
+		if (!c1) {
+			ast_log(LOG_NOTICE,"Could not find the %s context in the hashtab\n", c2->name);
+			check_contexts_trouble();
+		} else
+			ast_unlock_contexts();
+	}
+
+	/* loop thru all contexts, and verify the exten structure compares to the 
+	   hashtab structure */
+	for(c2=contexts;c2;c2=c2->next) {
+		c1 = find_context_locked(c2->name);
+		if (c1)
+		{
+
+			ast_unlock_contexts();
+
+			/* is every entry in the root list also in the root_table? */
+			for(e1 = c1->root; e1; e1=e1->next)
+			{
+				char dummy_name[1024];
+				ex.exten = dummy_name;
+				ex.matchcid = e1->matchcid;
+				ex.cidmatch = e1->cidmatch;
+				ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
+				e2 = ast_hashtab_lookup(c1->root_table, &ex);
+				if (!e2) {
+					if (e1->matchcid) {
+						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
+					} else {
+						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
+					}
+					check_contexts_trouble();
+				}
+			}
+			
+			/* is every entry in the root_table also in the root list? */ 
+			if (!c2->root_table) {
+				if (c2->root) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
+					usleep(500000);
+				}
+			} else {
+				t1 = ast_hashtab_start_traversal(c2->root_table);
+				while( (e2 = ast_hashtab_next(t1)) ) {
+					for(e1=c2->root;e1;e1=e1->next) {
+						if (!strcmp(e1->exten, e2->exten)) {
+							found = 1;
+							break;
+						}
+					}
+					if (!found) {
+						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
+						check_contexts_trouble();
+					}
+					
+				}
+				ast_hashtab_end_traversal(t1);
+			}
+		}
+		/* is every priority reflected in the peer_table at the head of the list? */
+		
+		/* is every entry in the root list also in the root_table? */
+		/* are the per-extension peer_tables in the right place? */
+
+		for(e1 = c2->root; e1; e1 = e1->next) {
+			
+			for(e2=e1;e2;e2=e2->peer) {
+				ex.priority = e2->priority;
+				if (e2 != e1 && e2->peer_table) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+				if (e2 != e1 && e2->peer_label_table) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+				if (e2 == e1 && !e2->peer_table){
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+				if (e2 == e1 && !e2->peer_label_table) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+
+				e3 = ast_hashtab_lookup(e1->peer_table, &ex);
+				if (!e3) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+			}
+			
+			if (!e1->peer_table){
+				ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
+				usleep(500000);
+			}
+			
+			/* is every entry in the peer_table also in the peer list? */ 
+			t1 = ast_hashtab_start_traversal(e1->peer_table);
+			while( (e2 = ast_hashtab_next(t1)) ) {
+				for(e3=e1;e3;e3=e3->peer) {
+					if (e3->priority == e2->priority) {
+						found = 1;
+						break;
+					}
+				}
+				if (!found) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+			}
+			ast_hashtab_end_traversal(t1);
+		}
+	}
+	return 0;
+}
+#endif
+
 /*
    \note This function is special. It saves the stack so that no matter
    how many times it is called, it returns to the same place */
@@ -4059,16 +4240,18 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 	 * peers, not just those matching the callerid. */
 #ifdef NEED_DEBUG
 	ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcid ? "/" : "", matchcid ? callerid : "", registrar);
+#endif
+#ifdef CONTEXT_DEBUG
+	check_contexts(__FILE__, __LINE__);
 #endif
 	/* find this particular extension */
 	ex.exten = dummy_name;
-	ex.matchcid = matchcid;
+	ex.matchcid = matchcid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
 	ex.cidmatch = callerid;
 	ast_copy_string(dummy_name, extension, sizeof(dummy_name));
 	exten = ast_hashtab_lookup(con->root_table, &ex);
 	if (exten) {
-		if (priority == 0)
-		{
+		if (priority == 0) {
 			exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
 			if (!exten2)
 				ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
@@ -4135,7 +4318,8 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 	/* scan the extension list to find first matching extension-registrar */
 	for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
 		if (!strcmp(exten->exten, extension) &&
-			(!registrar || !strcmp(exten->registrar, registrar)))
+			(!registrar || !strcmp(exten->registrar, registrar)) &&
+			(!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
 			break;
 	}
 	if (!exten) {
@@ -4147,7 +4331,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 
 	/* scan the priority list to remove extension with exten->priority == priority */
 	for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
-			peer && !strcmp(peer->exten, extension);
+		 peer && !strcmp(peer->exten, extension) && (!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
 			peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
 		if ((priority == 0 || peer->priority == priority) &&
 				(!callerid || !matchcid || (matchcid && !strcmp(peer->cidmatch, callerid))) &&
@@ -4161,7 +4345,14 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 				 * The next node is either the next priority or the next extension
 				 */
 				struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
-
+				if (peer->peer) {
+					/* move the peer_table and peer_label_table down to the next peer, if
+					   it is there */
+					peer->peer->peer_table = peer->peer_table;
+					peer->peer->peer_label_table = peer->peer_label_table;
+					peer->peer_table = NULL;
+					peer->peer_label_table = NULL;
+				}
 				if (!prev_exten) {	/* change the root... */
 					con->root = next_node;
 				} else {
@@ -4180,6 +4371,9 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 			previous_peer = peer;
 		}
 	}
+#ifdef CONTEXT_DEBUG
+	check_contexts(__FILE__, __LINE__);
+#endif
 	if (!already_locked)
 		ast_unlock_context(con);
 	return found ? 0 : -1;
@@ -6361,8 +6555,10 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 	}
 	if (!e) {	/* go at the end, and ep is surely set because the list is not empty */
 		ast_hashtab_insert_safe(eh->peer_table, tmp);
-		if (tmp->label)
+		
+		if (tmp->label) {
 			ast_hashtab_insert_safe(eh->peer_label_table, tmp);
+		}
 		ep->peer = tmp;
 		return 0;	/* success */
 	}
@@ -6383,11 +6579,16 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 		tmp->peer = e->peer;	/* always meaningful */
 		if (ep)	{		/* We're in the peer list, just insert ourselves */
 			ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
-			if (e->label)
+
+			if (e->label) {
 				ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
+			}
+			
 			ast_hashtab_insert_safe(eh->peer_table,tmp);
-			if (tmp->label)
+			if (tmp->label) {
 				ast_hashtab_insert_safe(eh->peer_label_table,tmp);
+			}
+			
 			ep->peer = tmp;
 		} else if (el) {		/* We're the first extension. Take over e's functions */
 			struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
@@ -6395,10 +6596,13 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 			tmp->peer_label_table = e->peer_label_table;
 			ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
 			ast_hashtab_insert_safe(tmp->peer_table,tmp);
-			if (e->label)
+			if (e->label) {
 				ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
-			if (tmp->label)
+			}
+			if (tmp->label) {
 				ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+			}
+			
 			ast_hashtab_remove_object_via_lookup(con->root_table, e);
 			ast_hashtab_insert_safe(con->root_table, tmp);
 			el->next = tmp;
@@ -6419,10 +6623,13 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 			tmp->peer_label_table = e->peer_label_table;
 			ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
 			ast_hashtab_insert_safe(tmp->peer_table, tmp);
-			if (e->label)
+			if (e->label) {
 				ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
-			if (tmp->label)
-			ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+			}
+			if (tmp->label) {
+				ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+			}
+			
 			ast_hashtab_remove_object_via_lookup(con->root_table, e);
 			ast_hashtab_insert_safe(con->root_table, tmp);
  			con->root = tmp;
@@ -6446,8 +6653,9 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 		tmp->peer = e;
 		tmp->next = e->next;	/* extension chain, or NULL if e is not the first extension */
 		if (ep) {			/* Easy enough, we're just in the peer list */
-			if (tmp->label)
+			if (tmp->label) {
 				ast_hashtab_insert_safe(eh->peer_label_table, tmp);
+			}
 			ast_hashtab_insert_safe(eh->peer_table, tmp);
 			ep->peer = tmp;
 		} else {			/* we are the first in some peer list, so link in the ext list */
@@ -6636,10 +6844,10 @@ int ast_add_extension2(struct ast_context *con,
 								ast_hashtab_newsize_java,
 								hashtab_hash_labels,
 								0);
-			if (label)
+			if (label) {
 				ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+			}
 			ast_hashtab_insert_safe(tmp->peer_table, tmp);
-
 		} else {  /* this is the first exten in this context */
 			if (!con->root_table)
 				con->root_table = ast_hashtab_create(27,
@@ -6661,9 +6869,11 @@ int ast_add_extension2(struct ast_context *con,
 									ast_hashtab_newsize_java,
 									hashtab_hash_labels,
 									0);
-			if (label)
+			if (label) {
 				ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
+			}
 			ast_hashtab_insert_safe(con->root->peer_table, tmp);
+				
 		}
 		ast_hashtab_insert_safe(con->root_table, tmp);
 		ast_unlock_context(con);
@@ -7128,12 +7338,20 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
 
 	for (tmp = list; tmp; ) {
 		struct ast_context *next = NULL;	/* next starting point */
-		for (; tmp; tmpl = tmp, tmp = tmp->next) {
-			ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
-			if ( (registrar && !strcasecmp(tmp->registrar, registrar)) || (con && !strcasecmp(tmp->name, con->name)) ) {
-				break;	/* found it */
+			/* The following code used to skip forward to the next
+			   context with matching registrar, but this didn't
+			   make sense; individual priorities registrar'd to 
+			   the matching registrar could occur in any context! */
+		ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
+		if (con) {
+			for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
+				ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
+				if ( !strcasecmp(tmp->name, con->name) ) {
+					break;	/* found it */
+				}
 			}
 		}
+		
 		if (!tmp)	/* not found, we are done */
 			break;
 		ast_wrlock_context(tmp);
@@ -7142,19 +7360,66 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
 			/* then search thru and remove any extens that match registrar. */
 			struct ast_hashtab_iter *exten_iter;
 			struct ast_hashtab_iter *prio_iter;
+			struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
+			struct ast_include *i, *pi = NULL, *ni = NULL;
+			struct ast_sw *sw = NULL;
+
+			/* remove any ignorepats whose registrar matches */
+			for (ip = tmp->ignorepats; ip; ip = ipn) {
+				ipn = ip->next;
+				if (!strcmp(ip->registrar, registrar)) {
+					if (ipl) {
+						ipl->next = ip->next;
+						ast_free(ip);
+						continue; /* don't change ipl */
+					} else {
+						tmp->ignorepats = ip->next;
+						ast_free(ip);
+						continue; /* don't change ipl */
+					}
+				}
+				ipl = ip;
+			}
+			/* remove any includes whose registrar matches */
+			for (i = tmp->includes; i; i = ni) {
+				ni = i->next;
+				if (strcmp(i->registrar, registrar) == 0) {
+					/* remove from list */
+					if (pi) {
+						pi->next = i->next;
+						/* free include */
+						ast_free(i);
+						continue; /* don't change pi */
+					} else {
+						tmp->includes = i->next;
+						/* free include */
+						ast_free(i);
+						continue; /* don't change pi */
+					}
+				}
+				pi = i;
+			}
+			/* remove any switches whose registrar matches */
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
+				if (strcmp(sw->registrar,registrar) == 0) {
+					AST_LIST_REMOVE_CURRENT(list);
+					ast_free(sw);
+				}
+			}
+			AST_LIST_TRAVERSE_SAFE_END
 
 			if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
 				exten_iter = ast_hashtab_start_traversal(tmp->root_table);
 				while ((exten_item=ast_hashtab_next(exten_iter))) {
 					prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
 					while ((prio_item=ast_hashtab_next(prio_iter))) {
-						if (strcmp(prio_item->registrar, registrar) != 0) {
+						if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
 							continue;
 						}
 						ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
-								tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
-						
-						ast_context_remove_extension2(tmp, prio_item->exten, prio_item->priority, registrar, 1);
+								 tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
+						/* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
+						ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
 					}
 					ast_hashtab_end_traversal(prio_iter);
 				}
@@ -7162,7 +7427,9 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
 			}
 	
 			/* delete the context if it's registrar matches, is empty, has refcount of 1, */
-			if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root) {
+			/* it's not empty, if it has includes, ignorepats, or switches that are registered from
+			   another registrar. It's not empty if there are any extensions */
+			if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
 				ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
 				ast_hashtab_remove_this_object(contexttab, tmp);
 				
@@ -7176,7 +7443,11 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
 				ast_unlock_context(tmp);
 				__ast_internal_context_destroy(tmp);
 			} else {
+				ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
+						  tmp->refcount, tmp->root);
 				ast_unlock_context(tmp);
+				next = tmp->next;
+				tmpl = tmp;
 			}
 		} else if (con) {
 			ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);