[svn-commits] murf: trunk r89547 - in /trunk: configs/ include/asterisk/ main/ pbx/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sat Nov 24 15:00:27 CST 2007


Author: murf
Date: Sat Nov 24 15:00:26 2007
New Revision: 89547

URL: http://svn.digium.com/view/asterisk?view=rev&rev=89547
Log:
closes issue #11363; where the pattern _20x. buried in an included context, didn't match 2012; There were a small set of problems to fix: 1. I needed NOT to score patterns unless you are at the end of the data string. 2. Capital N,X,Z and small n,x,z are OK in patterns. I canonicalize the patterns in the trie to caps. 3. When a pattern ends with dot or exclamation, CANMATCH/MATCHMORE should always report this pattern, no matter the length.  With this commit, I also supplied the wish of Luigi, where the user can select which pattern matching algorithm to use, the old (legacy) pattern matcher, or the new, trie based matcher. The OLD matcher is the default. A new [general] section variable, extenpatternmatchnew, is added to the extensions.conf, and the example config has it set to false. If true, the new matcher is used. In all other respects, the context/exten structs are the same; the tries and hashtabs are formed, but in the new mode the tries are not used.  A new CLI command
  'dialplan set extenpatternmatch true/false' is provided to allow switching at run time. I beg users that are forced to return to the old matcher to please report the reason in the bug tracker. Measured the speed benefit of the new matcher against an impossibly large context with 10,000 extensions: the new matcher is 374 times faster.

Modified:
    trunk/configs/extensions.conf.sample
    trunk/include/asterisk/pbx.h
    trunk/main/pbx.c
    trunk/pbx/pbx_config.c

Modified: trunk/configs/extensions.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/extensions.conf.sample?view=diff&rev=89547&r1=89546&r2=89547
==============================================================================
--- trunk/configs/extensions.conf.sample (original)
+++ trunk/configs/extensions.conf.sample Sat Nov 24 15:00:26 2007
@@ -35,6 +35,26 @@
 ; (this is the original behavior of Asterisk 1.0 and earlier).
 ;
 ;autofallthrough=no
+;
+; By default, the old pattern matcher is used. 
+
+; If extenpatternmatchnew is set (true, yes, etc), then a new algorithm that uses
+; a Trie to find the best matching pattern is used. In dialplans
+; with more than about 20-40 extensions in a single context, this
+; new algorithm can provide a noticeable speedup. 
+; With 1000 extensions, the speedup is ~25x
+; with 10,000 extensions, the speedup is 374x
+; Basically, the new algorithm provides a fairly flat response 
+; time, no matter the number of extensions.
+;
+; The new pattern matcher is for the brave, the bold, and 
+; the desperate. If you have large dialplans, and/or high 
+; call volume, you might consider setting this value to "yes" !!
+;
+; This value can be switched at runtime using the cli command "dialplan set extenpatternmatchnew true"
+; or "dialplan set extenpatternmatchnew false", so you can experiment to your hearts content.
+;
+;extenpatternmatchnew=no
 ;
 ; If clearglobalvars is set, global variables will be cleared 
 ; and reparsed on an extensions reload, or Asterisk reload.

Modified: trunk/include/asterisk/pbx.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/pbx.h?view=diff&rev=89547&r1=89546&r2=89547
==============================================================================
--- trunk/include/asterisk/pbx.h (original)
+++ trunk/include/asterisk/pbx.h Sat Nov 24 15:00:26 2007
@@ -841,6 +841,11 @@
   set to 1, sets to auto fall through.  If newval set to 0, sets to no auto
   fall through (reads extension instead).  Returns previous value. */
 int pbx_set_autofallthrough(int newval);
+
+/*! Set "extenpatternmatchnew" flag, if newval is <0, does not acutally set.  If
+  set to 1, sets to use the new Trie-based pattern matcher.  If newval set to 0, sets to use
+  the old linear-search algorithm.  Returns previous value. */
+int pbx_set_extenpatternmatchnew(int newval);
 int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority);
 /* I can find neither parsable nor parseable at dictionary.com, but google gives me 169000 hits for parseable and only 49,800 for parsable */
 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string);

Modified: trunk/main/pbx.c
URL: http://svn.digium.com/view/asterisk/trunk/main/pbx.c?view=diff&rev=89547&r1=89546&r2=89547
==============================================================================
--- trunk/main/pbx.c (original)
+++ trunk/main/pbx.c Sat Nov 24 15:00:26 2007
@@ -314,6 +314,7 @@
 static int pbx_builtin_saydigits(struct ast_channel *, void *);
 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
+static int matchcid(const char *cidpattern, const char *callerid);
 int pbx_builtin_setvar(struct ast_channel *, void *);
 void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
 static int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
@@ -408,6 +409,7 @@
 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
 
 static int autofallthrough = 1;
+static int extenpatternmatchnew = 0;
 
 /*! \brief Subscription for device state change events */
 static struct ast_event_sub *device_state_sub;
@@ -909,6 +911,12 @@
 	struct match_char *m4;
 	struct ast_exten *e3;
 	
+	if (node && node->x[0] == '.' && !node->x[1]) /* dot and ! will ALWAYS be next match in a matchmore */
+		return node->exten;
+	
+	if (node && node->x[0] == '!' && !node->x[1])
+		return node->exten;
+	
 	if (!node || !node->next_char)
 		return NULL;
 	
@@ -931,9 +939,15 @@
 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid)
 {
 	struct match_char *p; /* note minimal stack storage requirements */
+#ifdef DEBUG_THIS
+	if (tree)
+		ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s\n", str, tree->x);
+	else
+		ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL\n", str);
+#endif
 	for (p=tree; p; p=p->alt_char) {
 		if (p->x[0] == 'N' && p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
-			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+			if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
 				update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);
 
 			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
@@ -948,7 +962,7 @@
 				return;
 			}
 		} else if (p->x[0] == 'Z' && p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
-			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+			if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
 				update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted,p);
 
 			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
@@ -963,7 +977,7 @@
 				return;
 			}
 		} else if (p->x[0] == 'X' && p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
-			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+			if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
 				update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted,p);
 
 			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
@@ -980,10 +994,11 @@
 		} else if (p->x[0] == '.' && p->x[1] == 0) {
 			/* how many chars will the . match against? */
 			int i = 0;
-			while (*str++) {
+			const char *str2 = str;
+			while (*str2++) {
 				i++;
 			}
-			if (p->exten)
+			if (p->exten && !(*(str+1)))
 				update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
 			if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
 				new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid);
@@ -992,10 +1007,11 @@
 		} else if (p->x[0] == '!' && p->x[1] == 0) {
 			/* how many chars will the . match against? */
 			int i = 0;
-			while (*str++) {
+			const char *str2 = str;
+			while (*str2++) {
 				i++;
 			}
-			if (p->exten)
+			if (p->exten && !(*(str+1)))
 				update_scoreboard(score, length+1, spec+(p->specificity*i), p->exten, '!', callerid, p->deleted, p);
 			if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
 				new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid);
@@ -1007,7 +1023,7 @@
 				new_find_extension(callerid, score, p->next_char, length+1, spec, callerid);
 			}
 		} else if (index(p->x, *str)) {
-			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+			if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
 				update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);
 
 
@@ -1153,10 +1169,19 @@
 			*s2 = 0; /* null terminate the exploded range */
 			specif = strlen(buf);
 		} else {
+			
 			if (*s1 == '\\') {
 				s1++;
 				buf[0] = *s1;
 			} else {
+				if (pattern) {
+					if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
+						*s1 = 'N';
+					else if (*s1 == 'x')
+						*s1 = 'X';
+					else if (*s1 == 'z')
+						*s1 = 'Z';
+				}
 				buf[0] = *s1;
 			}
 			buf[1] = 0;
@@ -1566,6 +1591,17 @@
 #define STATUS_NO_LABEL		4
 #define STATUS_SUCCESS		5
 
+static int matchcid(const char *cidpattern, const char *callerid)
+{
+	/* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
+	   failing to get a number should count as a match, otherwise not */
+
+	if (ast_strlen_zero(callerid))
+		return ast_strlen_zero(cidpattern) ? 1 : 0;
+
+	return ast_extension_match(cidpattern, callerid);
+}
+
 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 	struct ast_context *bypass, struct pbx_find_info *q,
 	const char *context, const char *exten, int priority,
@@ -1639,96 +1675,117 @@
 #ifdef NEED_DEBUG
 	ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
 	log_match_char_tree(tmp->pattern_tree, "::  ");
-#endif	
-	new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid);
-	eroot = score.exten;
-
-	if (score.last_char == '!' && action == E_MATCHMORE) {
-		/* We match an extension ending in '!'.
-		 * The decision in this case is final and is NULL (no match).
-		 */
-		return NULL;
-	}
-
-	if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
-		q->status = STATUS_SUCCESS;
-		return score.canmatch_exten;
-	}
-
-	if (action == E_MATCHMORE && eroot) {
-		if (score.node) {
-			struct ast_exten *z = trie_find_next_match(score.node);
-			return z;
-		}
-		return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
-	}
-	
-
-	if (eroot) {
-		/* found entry, now look for the right priority */
-		if (q->status < STATUS_NO_PRIORITY)
-			q->status = STATUS_NO_PRIORITY;
-		e = NULL;
-		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);
-		} else {
-			e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
-		}
-		if (e) {	/* found a valid match */
-			q->status = STATUS_SUCCESS;
-			q->foundcontext = context;
-			return e;
-		}
-	}
-
-#ifdef NOTNOW2
-	/* scan the list trying to match extension and CID */
-	eroot = NULL;
-	while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
-		int match = extension_match_core(eroot->exten, exten, action);
-		/* 0 on fail, 1 on match, 2 on earlymatch */
-
-		if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
-			continue;	/* keep trying */
-		if (match == 2 && action == E_MATCHMORE) {
+#endif
+
+	if (extenpatternmatchnew) {
+		new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid);
+		eroot = score.exten;
+		
+		if (score.last_char == '!' && action == E_MATCHMORE) {
 			/* We match an extension ending in '!'.
 			 * The decision in this case is final and is NULL (no match).
 			 */
+#ifdef NEED_DEBUG
+			ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
+#endif
 			return NULL;
 		}
-		/* found entry, now look for the right priority */
-		if (q->status < STATUS_NO_PRIORITY)
-			q->status = STATUS_NO_PRIORITY;
-		e = NULL;
-		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);
-		} else {
-			e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
-		}
-#ifdef NOTNOW
-		while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
-			/* Match label or priority */
-			if (action == E_FINDLABEL) {
+		
+		if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
+			q->status = STATUS_SUCCESS;
+#ifdef NEED_DEBUG
+			ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
+#endif
+			return score.canmatch_exten;
+		}
+		
+		if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
+			if (score.node) {
+				struct ast_exten *z = trie_find_next_match(score.node);
+#ifdef NEED_DEBUG
+				if (z)
+					ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
+				else
+					ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
+#endif
+				return z;
+			}
+#ifdef NEED_DEBUG
+			ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
+#endif
+			return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
+		}
+		
+		if (eroot) {
+			/* found entry, now look for the right priority */
+			if (q->status < STATUS_NO_PRIORITY)
+				q->status = STATUS_NO_PRIORITY;
+			e = NULL;
+			if (action == E_FINDLABEL && label ) {
 				if (q->status < STATUS_NO_LABEL)
 					q->status = STATUS_NO_LABEL;
-				if (label && e->label && !strcmp(label, e->label))
+				e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+			} else {
+				e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+			}
+			if (e) {	/* found a valid match */
+				q->status = STATUS_SUCCESS;
+				q->foundcontext = context;
+#ifdef NEED_DEBUG
+				ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
+#endif
+				return e;
+			}
+		}
+	} else {
+		
+		/* scan the list trying to match extension and CID */
+		eroot = NULL;
+		while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
+			int match = extension_match_core(eroot->exten, exten, action);
+			/* 0 on fail, 1 on match, 2 on earlymatch */
+			
+			if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
+				continue;	/* keep trying */
+			if (match == 2 && action == E_MATCHMORE) {
+				/* We match an extension ending in '!'.
+				 * The decision in this case is final and is NULL (no match).
+				 */
+				return NULL;
+			}
+			/* found entry, now look for the right priority */
+			if (q->status < STATUS_NO_PRIORITY)
+				q->status = STATUS_NO_PRIORITY;
+			e = NULL;
+			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);
+			} else {
+				e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+			}
+#ifdef NOTNOW
+			while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
+				/* Match label or priority */
+				if (action == E_FINDLABEL) {
+					if (q->status < STATUS_NO_LABEL)
+						q->status = STATUS_NO_LABEL;
+					if (label && e->label && !strcmp(label, e->label))
+						break;	/* found it */
+				} else if (e->priority == priority) {
 					break;	/* found it */
-			} else if (e->priority == priority) {
-				break;	/* found it */
-			} /* else keep searching */
-		}
+				} /* else keep searching */
+			}
 #endif
-		if (e) {	/* found a valid match */
-			q->status = STATUS_SUCCESS;
-			q->foundcontext = context;
-			return e;
-		}
-	}
-#endif
+			if (e) {	/* found a valid match */
+				q->status = STATUS_SUCCESS;
+				q->foundcontext = context;
+				return e;
+			}
+		}
+	}
+	
+	
 	/* Check alternative switches */
 	AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
 		struct ast_switch *asw = pbx_findswitch(sw->name);
@@ -1765,9 +1822,12 @@
 	/* Now try any includes we have in this context */
 	for (i = tmp->includes; i; i = i->next) {
 		if (include_valid(i)) {
-			if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
+			if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
+#ifdef NEED_DEBUG
+				ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
+#endif
 				return e;
-			
+			}
 			if (q->swo)
 				return NULL;
 		}
@@ -3497,6 +3557,13 @@
 	return oldval;
 }
 
+int pbx_set_extenpatternmatchnew(int newval)
+{
+	int oldval = extenpatternmatchnew;
+	extenpatternmatchnew = newval;
+	return oldval;
+}
+
 /*!
  * \brief lookup for a context with a given name,
  * \retval with conlock held if found.
@@ -4777,6 +4844,62 @@
 	return CLI_SUCCESS;
 }
 
+static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int oldval = 0;
+	
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "dialplan set extenpaternmatchnew true";
+		e->usage = 
+			"Usage: dialplan set extenpatternmatchnew true|false\n"
+			"       Use the NEW extension pattern matching algorithm, true or false.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;	
+	}
+
+	if (a->argc != 4)
+		return CLI_SHOWUSAGE;
+
+	oldval =  pbx_set_extenpatternmatchnew(1);
+	
+	if (oldval)
+		ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
+	else
+		ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int oldval = 0;
+	
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "dialplan set extenpaternmatchnew false";
+		e->usage = 
+			"Usage: dialplan set extenpatternmatchnew true|false\n"
+			"       Use the NEW extension pattern matching algorithm, true or false.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;	
+	}
+
+	if (a->argc != 4)
+		return CLI_SHOWUSAGE;
+
+	oldval =  pbx_set_extenpatternmatchnew(0);
+	
+	if (!oldval)
+		ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
+	else
+		ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
+
+	return CLI_SUCCESS;
+}
+
 /*
  * CLI entries for upper commands ...
  */
@@ -4790,6 +4913,8 @@
 	AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
 	AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
 	AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
+	AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
+	AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
 };
 
 static void unreference_cached_app(struct ast_app *app)

Modified: trunk/pbx/pbx_config.c
URL: http://svn.digium.com/view/asterisk/trunk/pbx/pbx_config.c?view=diff&rev=89547&r1=89546&r2=89547
==============================================================================
--- trunk/pbx/pbx_config.c (original)
+++ trunk/pbx/pbx_config.c Sat Nov 24 15:00:26 2007
@@ -46,6 +46,7 @@
 static int write_protect_config = 1;
 static int autofallthrough_config = 1;
 static int clearglobalvars_config = 0;
+static int extenpatternmatchnew_config = 0;
 
 AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
 
@@ -780,11 +781,12 @@
 	}
 
 	/* fireout general info */
-	fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\n\n",
+	fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\nextenpatternmatchnew=%s\n\n",
 		static_config ? "yes" : "no",
 		write_protect_config ? "yes" : "no",
                 autofallthrough_config ? "yes" : "no",
-                clearglobalvars_config ? "yes" : "no");
+				clearglobalvars_config ? "yes" : "no",
+				extenpatternmatchnew_config ? "yes" : "no");
 
 	if ((v = ast_variable_browse(cfg, "globals"))) {
 		fprintf(output, "[globals]\n");
@@ -1367,6 +1369,7 @@
 	struct ast_variable *v;
 	const char *cxt;
 	const char *aft;
+	const char *newpm;
 	struct ast_flags config_flags = { 0 };
 
 	cfg = ast_config_load(config_file, config_flags);
@@ -1378,7 +1381,10 @@
 	write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
 	if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
 		autofallthrough_config = ast_true(aft);
+	if ((newpm = ast_variable_retrieve(cfg, "general", "extenpatternmatchnew")))
+		extenpatternmatchnew_config = ast_true(newpm);
 	clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
+	
 
 	if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext"))) 
 		ast_copy_string(userscontext, cxt, sizeof(userscontext));
@@ -1631,6 +1637,7 @@
 		ast_context_verify_includes(con);
 
 	pbx_set_autofallthrough(autofallthrough_config);
+	pbx_set_extenpatternmatchnew(extenpatternmatchnew_config);
 
 	return 0;
 }




More information about the svn-commits mailing list