[svn-commits] murf: branch murf/bug6002 r104973 - in /team/murf/bug6002: apps/ channels/ in...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Feb 28 07:59:49 CST 2008


Author: murf
Date: Thu Feb 28 07:59:48 2008
New Revision: 104973

URL: http://svn.digium.com/view/asterisk?view=rev&rev=104973
Log:
an initial checkpoint; things compile, but I have still have some higher level cleanup to do

Modified:
    team/murf/bug6002/apps/app_dial.c
    team/murf/bug6002/apps/app_meetme.c
    team/murf/bug6002/apps/app_queue.c
    team/murf/bug6002/channels/chan_iax2.c
    team/murf/bug6002/channels/chan_sip.c
    team/murf/bug6002/channels/chan_skinny.c
    team/murf/bug6002/include/asterisk/pbx.h
    team/murf/bug6002/include/asterisk/pval.h
    team/murf/bug6002/main/features.c
    team/murf/bug6002/main/pbx.c
    team/murf/bug6002/pbx/pbx_ael.c
    team/murf/bug6002/pbx/pbx_config.c
    team/murf/bug6002/res/ael/ael.flex
    team/murf/bug6002/res/ael/ael.tab.c
    team/murf/bug6002/res/ael/ael.tab.h
    team/murf/bug6002/res/ael/ael.y
    team/murf/bug6002/res/ael/ael_lex.c
    team/murf/bug6002/res/ael/pval.c
    team/murf/bug6002/utils/Makefile
    team/murf/bug6002/utils/ael_main.c
    team/murf/bug6002/utils/conf2ael.c
    team/murf/bug6002/utils/extconf.c

Modified: team/murf/bug6002/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/apps/app_dial.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/apps/app_dial.c (original)
+++ team/murf/bug6002/apps/app_dial.c Thu Feb 28 07:59:48 2008
@@ -2024,9 +2024,7 @@
 	int res;
 	struct ast_context *con;
 
-	con = ast_context_find("app_dial_gosub_virtual_context");
-	if (!con)
-		con = ast_context_create(NULL, "app_dial_gosub_virtual_context", "app_dial");
+	con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
 	if (!con)
 		ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
 	else

Modified: team/murf/bug6002/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/apps/app_meetme.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/apps/app_meetme.c (original)
+++ team/murf/bug6002/apps/app_meetme.c Thu Feb 28 07:59:48 2008
@@ -5280,7 +5280,7 @@
 
 	if (!ast_strlen_zero(trunk->autocontext)) {
 		struct ast_context *context;
-		context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
+		context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
 		if (!context) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", trunk->autocontext);
@@ -5417,7 +5417,7 @@
 	if (!ast_strlen_zero(station->autocontext)) {
 		struct ast_context *context;
 		struct sla_trunk_ref *trunk_ref;
-		context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
+		context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
 		if (!context) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", station->autocontext);

Modified: team/murf/bug6002/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/apps/app_queue.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/apps/app_queue.c (original)
+++ team/murf/bug6002/apps/app_queue.c Thu Feb 28 07:59:48 2008
@@ -6144,9 +6144,7 @@
 	if (!reload_queues(0))
 		return AST_MODULE_LOAD_DECLINE;
 
-	con = ast_context_find("app_queue_gosub_virtual_context");
-	if (!con)
-		con = ast_context_create(NULL, "app_queue_gosub_virtual_context", "app_queue");
+	con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
 	if (!con)
 		ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
 	else

Modified: team/murf/bug6002/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/channels/chan_iax2.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/channels/chan_iax2.c (original)
+++ team/murf/bug6002/channels/chan_iax2.c Thu Feb 28 07:59:48 2008
@@ -10755,8 +10755,7 @@
 		} else if (!strcasecmp(v->name, "regcontext")) {
 			ast_copy_string(regcontext, v->value, sizeof(regcontext));
 			/* Create context if it doesn't exist already */
-			if (!ast_context_find(regcontext))
-				ast_context_create(NULL, regcontext, "IAX2");
+			ast_context_find_or_create(NULL, NULL, regcontext, "IAX2");
 		} else if (!strcasecmp(v->name, "tos")) {
 			if (ast_str2tos(v->value, &tos))
 				ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);

Modified: team/murf/bug6002/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/channels/chan_sip.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/channels/chan_sip.c (original)
+++ team/murf/bug6002/channels/chan_sip.c Thu Feb 28 07:59:48 2008
@@ -20280,8 +20280,7 @@
 			/* Create contexts if they don't exist already */
 			while ((context = strsep(&stringp, "&"))) {
 				ast_copy_string(used_context, context, sizeof(used_context));
-				if (!ast_context_find(context))
-					ast_context_create(NULL, context, "SIP");
+				ast_context_find_or_create(NULL, NULL, context, "SIP");
 			}
 			ast_copy_string(global_regcontext, v->value, sizeof(global_regcontext));
 		} else if (!strcasecmp(v->name, "regextenonqualify")) {

Modified: team/murf/bug6002/channels/chan_skinny.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/channels/chan_skinny.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/channels/chan_skinny.c (original)
+++ team/murf/bug6002/channels/chan_skinny.c Thu Feb 28 07:59:48 2008
@@ -5798,8 +5798,7 @@
 			/* Create contexts if they don't exist already */
 			while ((context = strsep(&stringp, "&"))) {
 				ast_copy_string(used_context, context, sizeof(used_context));
-				if (!ast_context_find(context))
-					ast_context_create(NULL, context, "Skinny");
+				ast_context_find_or_create(NULL, NULL, context, "Skinny");
 			}
 			ast_copy_string(regcontext, v->value, sizeof(regcontext));
 		} else if (!strcasecmp(v->name, "dateformat")) {

Modified: team/murf/bug6002/include/asterisk/pbx.h
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/include/asterisk/pbx.h?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/include/asterisk/pbx.h (original)
+++ team/murf/bug6002/include/asterisk/pbx.h Thu Feb 28 07:59:48 2008
@@ -25,6 +25,7 @@
 
 #include "asterisk/sched.h"
 #include "asterisk/chanvars.h"
+#include "asterisk/hashtab.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
@@ -167,11 +168,16 @@
 int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
 
 /*!
- * \brief Register a new context
+ * \brief Register a new context or find an existing one
  *
  * \param extcontexts pointer to the ast_context structure pointer
+ * \param exttable pointer to the hashtable that contains all the elements in extcontexts
  * \param name name of the new context
  * \param registrar registrar of the context
+ *
+ * This function allows you to play in two environments: the global contexts (active dialplan)
+ * or an external context set of your choosing. To act on the external set, make sure extcontexts
+ * and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.
  *
  * This will first search for a context with your name.  If it exists already, it will not
  * create a new one.  If it does not exist, it will create a new one with the given name
@@ -179,33 +185,19 @@
  *
  * \return NULL on failure, and an ast_context structure on success
  */
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
-
-/*!
- * \brief Register a new context or find an existing one
- *
- * \param extcontexts pointer to the ast_context structure pointer
- * \param name name of the new context
- * \param registrar registrar of the context
- *
- * This will first search for a context with your name.  If it exists already, it will not
- * create a new one.  If it does not exist, it will create a new one with the given name
- * and registrar.
- *
- * \return NULL on failure, and an ast_context structure on success
- */
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar);
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar);
 
 /*!
  * \brief Merge the temporary contexts into a global contexts list and delete from the 
  *        global list the ones that are being added
  *
- * \param extcontexts pointer to the ast_context structure pointer
+ * \param extcontexts pointer to the ast_context structure
+ * \param exttable pointer to the ast_hashtab structure that contains all the elements in extcontexts
  * \param registrar of the context; if it's set the routine will delete all contexts 
  *        that belong to that registrar; if NULL only the contexts that are specified 
  *        in extcontexts
  */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
 
 /*!
  * \brief Destroy a context (matches the specified context (or ANY context if NULL)
@@ -975,6 +967,9 @@
 									 const char *label, const char *callerid, enum ext_match_t action);
 	
 
+/* hashtable functions for contexts */
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

Modified: team/murf/bug6002/include/asterisk/pval.h
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/include/asterisk/pval.h?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/include/asterisk/pval.h (original)
+++ team/murf/bug6002/include/asterisk/pval.h Thu Feb 28 07:59:48 2008
@@ -1,6 +1,7 @@
 #ifndef _ASTERISK_PVAL_H
 #define _ASTERISK_PVAL_H
 
+/* whatever includes this, better include asterisk/lock.h and asterisk/hashtab.h */
 
 typedef enum 
 {
@@ -143,7 +144,7 @@
    static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context ); */
 void set_priorities(struct ael_extension *exten);
 void add_extensions(struct ael_extension *exten);
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
 void destroy_pval(pval *item);
 void destroy_pval_item(pval *item);
 int is_float(char *arg );

Modified: team/murf/bug6002/main/features.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/main/features.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/main/features.c (original)
+++ team/murf/bug6002/main/features.c Thu Feb 28 07:59:48 2008
@@ -487,9 +487,7 @@
 		ast_adsi_unload_session(peer);
 	}
 
-	con = ast_context_find(parking_con);
-	if (!con) 
-		con = ast_context_create(NULL, parking_con, registrar);
+	con = ast_context_find_or_create(NULL, NULL, parking_con, registrar);
 	if (!con)	/* Still no context? Bad */
 		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
 	/* Tell the peer channel the number of the parking space */
@@ -2224,12 +2222,9 @@
 						if (peername_flat[i] == '/') 
 							peername_flat[i]= '0';
 					}
-					con = ast_context_find(parking_con_dial);
-					if (!con) {
-						con = ast_context_create(NULL, parking_con_dial, registrar);
-						if (!con)
-							ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
-					}
+					con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
+					if (!con)
+						ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
 					if (con) {
 						char returnexten[AST_MAX_EXTENSION];
 						snprintf(returnexten, sizeof(returnexten), "%s,,t", peername);
@@ -2804,7 +2799,7 @@
 		ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
 	}
 	
-	if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
+	if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) {
 		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
 		return -1;
 	}

Modified: team/murf/bug6002/main/pbx.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug6002/main/pbx.c?view=diff&rev=104973&r1=104972&r2=104973
==============================================================================
--- team/murf/bug6002/main/pbx.c (original)
+++ team/murf/bug6002/main/pbx.c Thu Feb 28 07:59:48 2008
@@ -140,8 +140,8 @@
 	void *data;			/*!< Data to use (arguments) */
 	void (*datad)(void *);		/*!< Data destructor */
 	struct ast_exten *peer;		/*!< Next higher priority with our extension */
-	struct ast_hashtab *peer_tree;    /*!< Priorities list in tree form -- only on the head of the peer list */
-	struct ast_hashtab *peer_label_tree; /*!< labeled priorities in the peer list -- only on the head of the peer list */
+	struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
+	struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peer list -- only on the head of the peer list */
 	const char *registrar;		/*!< Registrar */
 	struct ast_exten *next;		/*!< Extension with a greater ID */
 	char stuff[0];
@@ -203,12 +203,13 @@
 struct ast_context {
 	ast_rwlock_t lock; 			/*!< A lock to prevent multiple threads from clobbering the context */
 	struct ast_exten *root;			/*!< The root of the list of extensions */
-	struct ast_hashtab *root_tree;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
+	struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
  	struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
 	struct ast_context *next;		/*!< Link them together */
 	struct ast_include *includes;		/*!< Include other contexts */
 	struct ast_ignorepat *ignorepats;	/*!< Patterns for which to continue playing dialtone */
 	const char *registrar;			/*!< Registrar */
+	int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
 	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;	/*!< Alternative switches */
 	ast_mutex_t macrolock;			/*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
 	char name[0];				/*!< Name of the context */
@@ -327,17 +328,18 @@
 static void create_match_char_tree(struct ast_context *con);
 static struct ast_exten *get_canmatch_exten(struct match_char *node);
 static void destroy_pattern_tree(struct match_char *pattern_tree);
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
-static unsigned int hashtab_hash_contexts(const void *obj);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
 static unsigned int hashtab_hash_extens(const void *obj);
 static unsigned int hashtab_hash_priority(const void *obj);
 static unsigned int hashtab_hash_labels(const void *obj);
+static void __ast_internal_context_destroy( struct ast_context *con);
 
 /* labels, contexts are case sensitive  priority numbers are ints */
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
 {
 	const struct ast_context *ac = ah_a;
 	const struct ast_context *bc = ah_b;
@@ -376,7 +378,7 @@
 	return strcmp(ac->label, bc->label);
 }
 
-static unsigned int hashtab_hash_contexts(const void *obj)
+unsigned int ast_hashtab_hash_contexts(const void *obj)
 {
 	const struct ast_context *ac = obj;
 	return ast_hashtab_hash_string(ac->name);
@@ -684,7 +686,7 @@
 };
 
 static struct ast_context *contexts;
-static struct ast_hashtab *contexts_tree = NULL;
+static struct ast_hashtab *contexts_table = NULL;
 
 AST_RWLOCK_DEFINE_STATIC(conlock); 		/*!< Lock for the ast_context list */
 
@@ -1252,11 +1254,11 @@
 	int biggest_bucket, resizes, numobjs, numbucks;
 	
 	ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
-	ast_hashtab_get_stats(con->root_tree, &biggest_bucket, &resizes, &numobjs, &numbucks);
+	ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
 	ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
 			numobjs, numbucks, biggest_bucket, resizes);
 #endif
-	t1 = ast_hashtab_start_traversal(con->root_tree);
+	t1 = ast_hashtab_start_traversal(con->root_table);
 	while( (e1 = ast_hashtab_next(t1)) ) {
 		if (e1->exten)
 			add_exten_to_pattern_tree(con, e1, 0);
@@ -1582,7 +1584,7 @@
 {
 	ast_rwlock_t lock; 			
 	struct ast_exten *root;		
-	struct ast_hashtab *root_tree;            
+	struct ast_hashtab *root_table;            
 	struct match_char *pattern_tree;       
 	struct ast_context *next;	
 	struct ast_include *includes;		
@@ -1599,8 +1601,8 @@
 	struct fake_context item;
 	strncpy(item.name,name,256);
 	ast_rdlock_contexts();
-	if( contexts_tree ) {
-		tmp = ast_hashtab_lookup(contexts_tree,&item);
+	if( contexts_table ) {
+		tmp = ast_hashtab_lookup(contexts_table,&item);
 	} else {
 		while ( (tmp = ast_walk_contexts(tmp)) ) {
 			if (!name || !strcasecmp(name, tmp->name))
@@ -1668,7 +1670,7 @@
 	else {	/* look in contexts */
 		struct fake_context item;
 		strncpy(item.name,context,256);
-		tmp = ast_hashtab_lookup(contexts_tree,&item);
+		tmp = ast_hashtab_lookup(contexts_table,&item);
 #ifdef NOTNOW
 		tmp = NULL;
 		while ((tmp = ast_walk_contexts(tmp)) ) {
@@ -1690,7 +1692,7 @@
 	score.total_specificity = 0;
 	score.exten = 0;
 	score.total_length = 0;
-	if (!tmp->pattern_tree && tmp->root_tree)
+	if (!tmp->pattern_tree && tmp->root_table)
 	{
 		create_match_char_tree(tmp);
 #ifdef NEED_DEBUG
@@ -1750,9 +1752,9 @@
 			if (action == E_FINDLABEL && label ) {
 				if (q->status < STATUS_NO_LABEL)
 					q->status = STATUS_NO_LABEL;
-				e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
 			} else {
-				e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
 			}
 			if (e) {	/* found a valid match */
 				q->status = STATUS_SUCCESS;
@@ -1786,9 +1788,9 @@
 			if (action == E_FINDLABEL && label ) {
 				if (q->status < STATUS_NO_LABEL)
 					q->status = STATUS_NO_LABEL;
-				e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
 			} else {
-				e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
 			}
 #ifdef NOTNOW
 			while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
@@ -3527,10 +3529,10 @@
 	if (e->priority == PRIORITY_HINT)
 		ast_remove_hint(e);
 
-	if (e->peer_tree)
-		ast_hashtab_destroy(e->peer_tree,0);
-	if (e->peer_label_tree)
-		ast_hashtab_destroy(e->peer_label_tree, 0);
+	if (e->peer_table)
+		ast_hashtab_destroy(e->peer_table,0);
+	if (e->peer_label_table)
+		ast_hashtab_destroy(e->peer_label_table, 0);
 	if (e->datad)
 		e->datad(e->data);
 	ast_free(e);
@@ -3625,7 +3627,7 @@
 	struct fake_context item;
 	strncpy(item.name, context, 256);
 	ast_rdlock_contexts();
-	c = ast_hashtab_lookup(contexts_tree,&item);
+	c = ast_hashtab_lookup(contexts_table,&item);
 
 #ifdef NOTNOW
 
@@ -3792,13 +3794,13 @@
 	ex.exten = dummy_name;
 	ex.matchcid = 0;
 	ast_copy_string(dummy_name,extension, sizeof(dummy_name));
-	exten = ast_hashtab_lookup(con->root_tree, &ex);
+	exten = ast_hashtab_lookup(con->root_table, &ex);
 	if (exten) {
 		if (priority == 0)
 		{
-			exten2 = ast_hashtab_remove_this_object(con->root_tree, exten);
+			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_tree\n", extension, con->name);
+				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);
 			if (con->pattern_tree) {
 				
 				struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
@@ -3812,24 +3814,24 @@
 			}
 		} else {
 			ex.priority = priority;
-			exten2 = ast_hashtab_lookup(exten->peer_tree, &ex);
+			exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
 			if (exten2) {
 				
 				if (exten2->label) { /* if this exten has a label, remove that, too */
-					exten3 = ast_hashtab_remove_this_object(exten->peer_label_tree,exten2);
+					exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
 					if (!exten3)
-						ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_tree of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
+						ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
 				}
 				
-				exten3 = ast_hashtab_remove_this_object(exten->peer_tree, exten2);
+				exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
 				if (!exten3)
-					ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_tree of context %s, extension %s!\n", priority, con->name, exten2->exten);
-				if (ast_hashtab_size(exten->peer_tree) == 0) {
+					ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
+				if (ast_hashtab_size(exten->peer_table) == 0) {
 					/* well, if the last priority of an exten is to be removed,
 					   then, the extension is removed, too! */
-					exten3 = ast_hashtab_remove_this_object(con->root_tree, exten);
+					exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
 					if (!exten3)
-						ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_tree (%s) (priority %d)\n", exten->exten, con->name, priority);
+						ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
 					if (con->pattern_tree) {
 						struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
 						if (x->exten) { /* this test for safety purposes */
@@ -3845,7 +3847,7 @@
 		}
 	} else {
 		/* hmmm? this exten is not in this pattern tree? */
-		ast_log(LOG_WARNING,"Cannot find extension %s in root_tree in context %s\n",
+		ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
 				extension, con->name);
 	}
 #ifdef NEED_DEBUG
@@ -3902,10 +3904,10 @@
 			 */
 			struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
 			if (next_node && next_node == peer->peer) {
-				next_node->peer_tree = exten->peer_tree; /* move the priority hash tabs over */
-				exten->peer_tree = 0;
-				next_node->peer_label_tree = exten->peer_label_tree;
-				exten->peer_label_tree = 0;
+				next_node->peer_table = exten->peer_table; /* move the priority hash tabs over */
+				exten->peer_table = 0;
+				next_node->peer_label_table = exten->peer_label_table;
+				exten->peer_label_table = 0;
 			}
 			if (!prev_exten) {	/* change the root... */
 				con->root = next_node;
@@ -3943,7 +3945,7 @@
 	ast_rdlock_contexts();
 
 	strncpy(item.name,context,256);
-	c = ast_hashtab_lookup(contexts_tree,&item);
+	c = ast_hashtab_lookup(contexts_table,&item);
 	if (c)
 		ret = 0;
 
@@ -3981,7 +3983,7 @@
 	ast_rdlock_contexts();
 
 	strncpy(item.name, context, 256);
-	c = ast_hashtab_lookup(contexts_tree,&item);
+	c = ast_hashtab_lookup(contexts_table,&item);
 	if (c)
 		ret = 0;
 #ifdef NOTNOW
@@ -5124,42 +5126,37 @@
 	return tmp ? 0 : -1;
 }
 
-static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
 {
 	struct ast_context *tmp, **local_contexts;
 	struct fake_context search;
 	int length = sizeof(struct ast_context) + strlen(name) + 1;
 
-	if (!contexts_tree) {
-		contexts_tree = ast_hashtab_create(17,
-										   hashtab_compare_contexts, 
+	if (!contexts_table) {
+		contexts_table = ast_hashtab_create(17,
+										   ast_hashtab_compare_contexts, 
 										   ast_hashtab_resize_java,
 										   ast_hashtab_newsize_java,
-										   hashtab_hash_contexts,
+										   ast_hashtab_hash_contexts,
 										   0);
 	}
 	
+	strncpy(search.name,name,sizeof(search.name));
 	if (!extcontexts) {
 		ast_rdlock_contexts();
 		local_contexts = &contexts;
-		strncpy(search.name,name,sizeof(search.name));
-		tmp = ast_hashtab_lookup(contexts_tree, &search);
-		if (!existsokay && tmp) {
-			ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
-		}
+		tmp = ast_hashtab_lookup(contexts_table, &search);
 		ast_unlock_contexts();
-		if (tmp)
+		if (tmp) {
+			tmp->refcount++;
 			return tmp;
+		}
 	} else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
 		local_contexts = extcontexts;
-		for (tmp = *local_contexts; tmp; tmp = tmp->next) {
-			if (!strcasecmp(tmp->name, name)) {
-				if (!existsokay) {
-					ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
-					tmp = NULL;
-				}
-				return tmp;
-			}
+		tmp = ast_hashtab_lookup(exttable, &search);
+		if (tmp) {
+			tmp->refcount++;
+			return tmp;
 		}
 	}
 	
@@ -5168,19 +5165,26 @@
 		ast_mutex_init(&tmp->macrolock);
 		strcpy(tmp->name, name);
 		tmp->root = NULL;
-		tmp->root_tree = NULL;
+		tmp->root_table = NULL;
 		tmp->registrar = registrar;
 		tmp->includes = NULL;
 		tmp->ignorepats = NULL;
-	}
+		tmp->refcount = 1;
+	} else {
+		ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
+		return NULL;
+	}
+	
 	if (!extcontexts) {
 		ast_wrlock_contexts();
 		tmp->next = *local_contexts;
 		*local_contexts = tmp;
-		ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
+		ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
 		ast_unlock_contexts();
 	} else {
 		tmp->next = *local_contexts;
+		if (exttable)
+			ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
 		*local_contexts = tmp;
 	}
 	ast_debug(1, "Registered context '%s'\n", tmp->name);
@@ -5188,15 +5192,6 @@
 	return tmp;
 }
 
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-	return __ast_context_create(extcontexts, name, registrar, 0);
-}
-
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-	return __ast_context_create(extcontexts, name, registrar, 1);
-}
 void __ast_context_destroy(struct ast_context *con, const char *registrar);
 
 struct store_hint {
@@ -5210,17 +5205,87 @@
 
 AST_LIST_HEAD(store_hints, store_hint);
 
+/* the purpose of this routine is to duplicate a context, with all its substructure,
+   except for any extens that have a matching registrar */
+static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
+{
+	struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
+	struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
+	struct ast_hashtab_iter *exten_iter;
+	struct ast_hashtab_iter *prio_iter;
+	int insert_count = 0;
+	
+	/* We'll traverse all the extensions/prios, and see which are not registrar'd with
+	   the current registrar, and copy them to the new context. If the new context does not
+	   exist, we'll create it "on demand". If no items are in this context to copy, then we'll
+	   only create the empty matching context if the old one meets the criteria */
+
+	exten_iter = ast_hashtab_start_traversal(context->root_table);
+	while ((exten_item=ast_hashtab_next(exten_iter))) {
+		if (new) {
+			new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
+		} else {
+			new_exten_item = NULL;
+		}
+		prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
+		while ((prio_item=ast_hashtab_next(prio_iter))) {
+			int res1;
+			
+			if (new_exten_item) {
+				new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
+			} else {
+				new_prio_item = NULL;
+			}
+			if (strcmp(prio_item->registrar,registrar) == 0) {
+				continue;
+			}
+			/* make sure the new context exists, so we have somewhere to stick this exten/prio */
+			if (!new) {
+				new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
+			}
+			if (!new) {
+				ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
+				return; /* no sense continuing. */
+			}
+			/* we will not replace existing entries in the new context with stuff from the old context.
+			   but, if this is because of some sort of registrar conflict, we ought to say something... */
+			res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
+									  prio_item->cidmatch, prio_item->app, prio_item->data, prio_item->datad, prio_item->registrar);
+			
+			if (!res1 && new_exten_item && new_prio_item){
+				ast_log(LOG_NOTICE,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
+						context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
+			} else {
+				insert_count++;
+			}
+		}
+		ast_hashtab_end_traversal(prio_iter);
+	}
+	ast_hashtab_end_traversal(exten_iter);
+	
+	if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
+		  (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
+		
+		/* we could have given it the registrar of the other module who incremented the refcount,
+		   but that's not available, so we give it the registrar we know about */
+		new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
+	}
+}
+
+
 /* XXX this does not check that multiple contexts are merged */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
-{
-	struct ast_context *tmp, *lasttmp = NULL;
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
+{
+	struct ast_context *tmp, *oldcontextslist;
+	struct ast_hashtab *oldtable;
 	struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
 	struct store_hint *this;
 	struct ast_hint *hint;
 	struct ast_exten *exten;
 	int length;
 	struct ast_state_cb *thiscb, *prevcb;
-
+	struct ast_hashtab_iter *iter;
+	
 	/* it is very important that this function hold the hint list lock _and_ the conlock
 	   during its operation; not only do we need to ensure that the list of contexts
 	   and extensions does not change, but also that no hint callbacks (watchers) are
@@ -5229,6 +5294,14 @@
 	   in addition, the locks _must_ be taken in this order, because there are already
 	   other code paths that use this order
 	*/
+
+	ast_rdlock_contexts();
+	iter = ast_hashtab_start_traversal(contexts_table);
+	while ((tmp=ast_hashtab_next(iter))) {
+		context_merge(extcontexts, exttable, tmp, registrar);
+	}
+	ast_hashtab_end_traversal(iter);
+	
 	ast_wrlock_contexts();
 	AST_RWLIST_WRLOCK(&hints);
 
@@ -5249,36 +5322,14 @@
 		}
 	}
 
-	tmp = *extcontexts;
-	if (registrar) {
-		/* XXX remove previous contexts from same registrar */
-		ast_debug(1, "must remove any reg %s\n", registrar);
-		__ast_context_destroy(NULL,registrar);
-		while (tmp) {
-			lasttmp = tmp;
-			tmp = tmp->next;
-		}
-	} else {
-		/* XXX remove contexts with the same name */
-		while (tmp) {
-			ast_log(LOG_WARNING, "must remove %s  reg %s\n", tmp->name, tmp->registrar);
-			__ast_context_destroy(tmp,tmp->registrar);
-			lasttmp = tmp;
-			tmp = tmp->next;
-		}
-	}
-	tmp = *extcontexts;
-	while (tmp) {
-		ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
-		tmp = tmp->next;
-	}
-	if (lasttmp) {
-		lasttmp->next = contexts;
-		contexts = *extcontexts;
-		*extcontexts = NULL;
-	} else
-		ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
-
+	/* save the old table and list */
+	oldtable = contexts_table;
+	oldcontextslist = contexts;
+
+	/* move in the new table and list */
+	contexts_table = exttable;
+	contexts = *extcontexts;
+	
 	/* restore the watchers for hints that can be found; notify those that
 	   cannot be restored
 	*/
@@ -5313,7 +5364,18 @@
 
 	AST_RWLIST_UNLOCK(&hints);
 	ast_unlock_contexts();
-
+	
+	/* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
+	   is now freely using the new stuff instead */
+	
+	ast_hashtab_destroy(oldtable, NULL);
+
+	for (tmp = oldcontextslist; tmp; ) {
+		struct ast_context *next;	/* next starting point */
+		next = tmp->next;
+		__ast_internal_context_destroy(tmp);
+		tmp = next;
+	}
 	return;
 }
 
@@ -5977,9 +6039,9 @@
 			break;
 	}
 	if (!e) {	/* go at the end, and ep is surely set because the list is not empty */
-		ast_hashtab_insert_safe(eh->peer_tree, tmp);
+		ast_hashtab_insert_safe(eh->peer_table, tmp);
 		if (tmp->label)
-			ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
+			ast_hashtab_insert_safe(eh->peer_label_table, tmp);
 		ep->peer = tmp;
 		return 0;	/* success */
 	}
@@ -5999,25 +6061,25 @@
 		tmp->next = e->next;	/* not meaningful if we are not first in the peer list */
 		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_tree,e);
+			ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
 			if (e->label)
-				ast_hashtab_remove_object_via_lookup(eh->peer_label_tree,e);
-			ast_hashtab_insert_safe(eh->peer_tree,tmp);
+				ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
+			ast_hashtab_insert_safe(eh->peer_table,tmp);
 			if (tmp->label)
-				ast_hashtab_insert_safe(eh->peer_label_tree,tmp);
+				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);
-			tmp->peer_tree = e->peer_tree;
-			tmp->peer_label_tree = e->peer_label_tree;
-			ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
-			ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+			tmp->peer_table = e->peer_table;
+			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)
-				ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
+				ast_hashtab_remove_object_via_lookup(tmp->peer_label_table,e);
 			if (tmp->label)
-				ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
-			ast_hashtab_remove_object_via_lookup(con->root_tree, e);
-			ast_hashtab_insert_safe(con->root_tree, tmp);
+				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;
 			/* The pattern trie points to this exten; replace the pointer,
 			   and all will be well */
@@ -6029,18 +6091,18 @@
 			}
 		} else {			/* We're the very first extension.  */
 			struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
-			ast_hashtab_remove_object_via_lookup(con->root_tree,e);
-			ast_hashtab_insert_safe(con->root_tree,tmp);
-			tmp->peer_tree = e->peer_tree;
-			tmp->peer_label_tree = e->peer_label_tree;
-			ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
-			ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+			ast_hashtab_remove_object_via_lookup(con->root_table,e);
+			ast_hashtab_insert_safe(con->root_table,tmp);
+			tmp->peer_table = e->peer_table;
+			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)
-				ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
+				ast_hashtab_remove_object_via_lookup(tmp->peer_label_table,e);
 			if (tmp->label)
-			ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
-			ast_hashtab_remove_object_via_lookup(con->root_tree, e);
-			ast_hashtab_insert_safe(con->root_tree, tmp);
+			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;
 			/* The pattern trie points to this exten; replace the pointer,
 			   and all will be well */
@@ -6061,20 +6123,20 @@
 		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)
-				ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
-			ast_hashtab_insert_safe(eh->peer_tree, tmp);
+				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 */
-			tmp->peer_tree = e->peer_tree;
-			tmp->peer_label_tree = e ->peer_label_tree;
-			e->peer_tree = 0;
-			e->peer_label_tree = 0;
-			ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+			tmp->peer_table = e->peer_table;
+			tmp->peer_label_table = e ->peer_label_table;
+			e->peer_table = 0;
+			e->peer_label_table = 0;
+			ast_hashtab_insert_safe(tmp->peer_table,tmp);
 			if (tmp->label) {
-				ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
-			}
-			ast_hashtab_remove_object_via_lookup(con->root_tree,e);
-			ast_hashtab_insert_safe(con->root_tree,tmp);
+				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);
 			if (el)
 				el->next = tmp;	/* in the middle... */
 			else
@@ -6189,11 +6251,11 @@
 		dummy_exten.exten = dummy_name;
 		dummy_exten.matchcid = 0;
 		dummy_exten.cidmatch = 0;

[... 3995 lines stripped ...]



More information about the svn-commits mailing list