Skip to content
Snippets Groups Projects
extconf.c 172 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		else			/* We're the very first extension.  */
    			con->root = tmp;
    		if (tmp->priority == PRIORITY_HINT)
    			ast_change_hint(e,tmp);
    		/* Destroy the old one */
    		e->datad(e->data);
    		free(e);
    	} else {	/* Slip ourselves in just before e */
    		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 */
    			ep->peer = tmp;
    		else {			/* we are the first in some peer list, so link in the ext list */
    			if (el)
    				el->next = tmp;	/* in the middle... */
    			else
    				con->root = tmp; /* ... or at the head */
    			e->next = NULL;	/* e is no more at the head, so e->next must be reset */
    		}
    		/* And immediately return success. */
    		if (tmp->priority == PRIORITY_HINT)
    			 ast_add_hint(tmp);
    	}
    	return 0;
    }
    
    /*! \brief  ast_remove_hint: Remove hint from extension */
    static int ast_remove_hint(struct ast_exten *e)
    {
    	/* Cleanup the Notifys if hint is removed */
    	struct ast_hint *hint;
    	struct ast_state_cb *cblist, *cbprev;
    	int res = -1;
    
    	if (!e)
    		return -1;
    
    	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
    		if (hint->exten == e) {
    			cbprev = NULL;
    			cblist = hint->callbacks;
    			while (cblist) {
    				/* Notify with -1 and remove all callbacks */
    				cbprev = cblist;
    				cblist = cblist->next;
    				free(cbprev);
    			}
    			hint->callbacks = NULL;
    			AST_RWLIST_REMOVE_CURRENT(&hints, list);
    			free(hint);
    	   		res = 0;
    			break;
    		}
    	}
    	AST_RWLIST_TRAVERSE_SAFE_END
    
    	return res;
    }
    
    static void destroy_exten(struct ast_exten *e)
    {
    	if (e->priority == PRIORITY_HINT)
    		ast_remove_hint(e);
    
    	if (e->datad)
    		e->datad(e->data);
    	free(e);
    }
    
    char *days[] =
    {
    	"sun",
    	"mon",
    	"tue",
    	"wed",
    	"thu",
    	"fri",
    	"sat",
    	NULL,
    };
    
    char *months[] =
    {
    	"jan",
    	"feb",
    	"mar",
    	"apr",
    	"may",
    	"jun",
    	"jul",
    	"aug",
    	"sep",
    	"oct",
    	"nov",
    	"dec",
    	NULL,
    };
    
    
    int ast_build_timing(struct ast_timing *i, const char *info_in);
    
    
    int ast_build_timing(struct ast_timing *i, const char *info_in)
    
    	int j, num_fields, last_sep = -1;
    
    	if (ast_strlen_zero(info_in)) {
    
    	/* make a copy just in case we were passed a static string */
    
    
    	/* count the number of fields in the timespec */
    	for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
    		if (info[j] == ',') {
    			last_sep = j;
    			num_fields++;
    		}
    	}
    
    	/* save the timezone, if it is specified */
    	if (num_fields == 5) {
    		i->timezone = ast_strdup(info + last_sep + 1);
    	}
    
    
    	/* Assume everything except time */
    	i->monthmask = 0xfff;	/* 12 bits */
    	i->daymask = 0x7fffffffU; /* 31 bits */
    	i->dowmask = 0x7f; /* 7 bits */
    	/* on each call, use strsep() to move info to the next argument */
    
    	get_timerange(i, strsep(&info, "|,"));
    
    		i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
    
    		i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
    
    		i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
    
    	return 1;
    }
    
    /*!
     * \brief helper functions to sort extensions and patterns in the desired way,
     * so that more specific patterns appear first.
     *
     * ext_cmp1 compares individual characters (or sets of), returning
     * an int where bits 0-7 are the ASCII code of the first char in the set,
     * while bit 8-15 are the cardinality of the set minus 1.
     * This way more specific patterns (smaller cardinality) appear first.
     * Wildcards have a special value, so that we can directly compare them to
     * sets by subtracting the two values. In particular:
     * 	0x000xx		one character, xx
     * 	0x0yyxx		yy character set starting with xx
     * 	0x10000		'.' (one or more of anything)
     * 	0x20000		'!' (zero or more of anything)
     * 	0x30000		NUL (end of string)
     * 	0x40000		error in set.
     * The pointer to the string is advanced according to needs.
     * NOTES:
     *	1. the empty set is equivalent to NUL.
     *	2. given that a full set has always 0 as the first element,
     *	   we could encode the special cases as 0xffXX where XX
     *	   is 1, 2, 3, 4 as used above.
     */
    static int ext_cmp1(const char **p)
    {
    	uint32_t chars[8];
    	int c, cmin = 0xff, count = 0;
    	const char *end;
    
    	/* load, sign extend and advance pointer until we find
    	 * a valid character.
    	 */
    	while ( (c = *(*p)++) && (c == ' ' || c == '-') )
    		;	/* ignore some characters */
    
    	/* always return unless we have a set of chars */
    	switch (c) {
    	default:	/* ordinary character */
    		return 0x0000 | (c & 0xff);
    
    	case 'N':	/* 2..9 */
    		return 0x0700 | '2' ;
    
    	case 'X':	/* 0..9 */
    		return 0x0900 | '0';
    
    	case 'Z':	/* 1..9 */
    		return 0x0800 | '1';
    
    	case '.':	/* wildcard */
    		return 0x10000;
    
    	case '!':	/* earlymatch */
    		return 0x20000;	/* less specific than NULL */
    
    	case '\0':	/* empty string */
    		*p = NULL;
    		return 0x30000;
    
    	case '[':	/* pattern */
    		break;
    	}
    	/* locate end of set */
    
    	end = strchr(*p, ']');
    
    
    	if (end == NULL) {
    		ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
    		return 0x40000;	/* XXX make this entry go last... */
    	}
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    	memset(chars, '\0', sizeof(chars));	/* clear all chars in the set */
    
    	for (; *p < end  ; (*p)++) {
    		unsigned char c1, c2;	/* first-last char in range */
    		c1 = (unsigned char)((*p)[0]);
    		if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
    			c2 = (unsigned char)((*p)[2]);
    			*p += 2;	/* skip a total of 3 chars */
    		} else			/* individual character */
    			c2 = c1;
    		if (c1 < cmin)
    			cmin = c1;
    		for (; c1 <= c2; c1++) {
    			uint32_t mask = 1 << (c1 % 32);
    			if ( (chars[ c1 / 32 ] & mask) == 0)
    				count += 0x100;
    			chars[ c1 / 32 ] |= mask;
    		}
    	}
    	(*p)++;
    	return count == 0 ? 0x30000 : (count | cmin);
    }
    
    /*!
     * \brief the full routine to compare extensions in rules.
     */
    static int ext_cmp(const char *a, const char *b)
    {
    	/* make sure non-patterns come first.
    	 * If a is not a pattern, it either comes first or
    	 * we use strcmp to compare the strings.
    	 */
    	int ret = 0;
    
    	if (a[0] != '_')
    		return (b[0] == '_') ? -1 : strcmp(a, b);
    
    	/* Now we know a is a pattern; if b is not, a comes first */
    	if (b[0] != '_')
    		return 1;
    #if 0	/* old mode for ext matching */
    	return strcmp(a, b);
    #endif
    	/* ok we need full pattern sorting routine */
    	while (!ret && a && b)
    		ret = ext_cmp1(&a) - ext_cmp1(&b);
    	if (ret == 0)
    		return 0;
    	else
    		return (ret > 0) ? 1 : -1;
    }
    
    /*! \brief copy a string skipping whitespace */
    static int ext_strncpy(char *dst, const char *src, int len)
    {
    	int count=0;
    
    	while (*src && (count < len - 1)) {
    		switch(*src) {
    		case ' ':
    			/*	otherwise exten => [a-b],1,... doesn't work */
    			/*		case '-': */
    			/* Ignore */
    			break;
    		default:
    			*dst = *src;
    			dst++;
    		}
    		src++;
    		count++;
    	}
    	*dst = '\0';
    
    	return count;
    }
    
    /*
     * Wrapper around _extension_match_core() to do performance measurement
     * using the profiling code.
     */
    
    int ast_check_timing(const struct ast_timing *i);
    
    
    int ast_check_timing(const struct ast_timing *i)
    
    	/* sorry, but this feature will NOT be available
    	   in the standalone version */
    	return 0;
    
    }
    
    #ifdef NOT_ANYMORE
    static struct ast_switch *pbx_findswitch(const char *sw)
    {
    	struct ast_switch *asw;
    
    	AST_RWLIST_TRAVERSE(&switches, asw, list) {
    		if (!strcasecmp(asw->name, sw))
    			break;
    	}
    
    	return asw;
    }
    #endif
    
    
    static struct ast_context *ast_walk_contexts(struct ast_context *con);
    
    static struct ast_context *ast_walk_contexts(struct ast_context *con)
    {
    	return con ? con->next : contexts;
    }
    
    struct ast_context *localized_walk_contexts(struct ast_context *con);
    struct ast_context *localized_walk_contexts(struct ast_context *con)
    {
    	return ast_walk_contexts(con);
    }
    
    
    
    static struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
    											  struct ast_exten *exten);
    
    static struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
    	struct ast_exten *exten)
    {
    	if (!exten)
    		return con ? con->root : NULL;
    	else
    		return exten->next;
    }
    
    struct ast_exten *localized_walk_context_extensions(struct ast_context *con,
    													struct ast_exten *exten);
    struct ast_exten *localized_walk_context_extensions(struct ast_context *con,
    													struct ast_exten *exten)
    {
    	return ast_walk_context_extensions(con,exten);
    }
    
    
    static struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
    												struct ast_exten *priority);
    
    static struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
    	struct ast_exten *priority)
    {
    	return priority ? priority->peer : exten;
    }
    
    struct ast_exten *localized_walk_extension_priorities(struct ast_exten *exten,
    													  struct ast_exten *priority);
    struct ast_exten *localized_walk_extension_priorities(struct ast_exten *exten,
    													  struct ast_exten *priority)
    {
    	return ast_walk_extension_priorities(exten, priority);
    }
    
    
    
    static struct ast_include *ast_walk_context_includes(struct ast_context *con,
    											  struct ast_include *inc);
    
    static struct ast_include *ast_walk_context_includes(struct ast_context *con,
    	struct ast_include *inc)
    {
    	if (!inc)
    		return con ? con->includes : NULL;
    	else
    		return inc->next;
    }
    
    
    int ast_context_includes_count(struct ast_context *con);
    int ast_context_includes_count(struct ast_context *con)
    {
    	int c = 0;
    	struct ast_include *inc = NULL;
    
    	while ((inc = ast_walk_context_includes(con, inc))) {
    		c++;
    	}
    
    	return c;
    }
    
    
    struct ast_include *localized_walk_context_includes(struct ast_context *con,
    													struct ast_include *inc);
    struct ast_include *localized_walk_context_includes(struct ast_context *con,
    													struct ast_include *inc)
    {
    	return ast_walk_context_includes(con, inc);
    }
    
    
    static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
    	struct ast_ignorepat *ip);
    
    static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
    	struct ast_ignorepat *ip)
    {
    	if (!ip)
    		return con ? con->ignorepats : NULL;
    	else
    		return ip->next;
    }
    
    int ast_context_ignorepats_count(struct ast_context *con);
    int ast_context_ignorepats_count(struct ast_context *con)
    {
    	int c = 0;
    	struct ast_ignorepat *ip = NULL;
    
    	while ((ip = ast_walk_context_ignorepats(con, ip))) {
    		c++;
    	}
    
    	return c;
    }
    
    
    
    static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
    													 struct ast_sw *sw);
    
    static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
    													 struct ast_sw *sw)
    {
    	if (!sw)
    		return con ? AST_LIST_FIRST(&con->alts) : NULL;
    	else
    		return AST_LIST_NEXT(sw, list);
    }
    
    struct ast_sw *localized_walk_context_switches(struct ast_context *con,
    													struct ast_sw *sw);
    struct ast_sw *localized_walk_context_switches(struct ast_context *con,
    													struct ast_sw *sw)
    {
    	return ast_walk_context_switches(con, sw);
    }
    
    
    int ast_context_switches_count(struct ast_context *con);
    int ast_context_switches_count(struct ast_context *con)
    {
    	int c = 0;
    	struct ast_sw *sw = NULL;
    
    	while ((sw = ast_walk_context_switches(con, sw))) {
    		c++;
    	}
    
    	return c;
    }
    
    
    
    static struct ast_context *ast_context_find(const char *name);
    
    static struct ast_context *ast_context_find(const char *name)
    {
    	struct ast_context *tmp = NULL;
    	while ( (tmp = ast_walk_contexts(tmp)) ) {
    		if (!name || !strcasecmp(name, tmp->name))
    			break;
    	}
    	return tmp;
    }
    
    /*
     * Internal function for ast_extension_{match|close}
     * return 0 on no-match, 1 on match, 2 on early match.
     * mode is as follows:
     *	E_MATCH		success only on exact match
     *	E_MATCHMORE	success only on partial match (i.e. leftover digits in pattern)
     *	E_CANMATCH	either of the above.
     */
    
    static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
    {
    	mode &= E_MATCH_MASK;	/* only consider the relevant bits */
    
    	if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
    		return 1;
    
    	if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
    		int ld = strlen(data), lp = strlen(pattern);
    
    		if (lp < ld)		/* pattern too short, cannot match */
    			return 0;
    		/* depending on the mode, accept full or partial match or both */
    		if (mode == E_MATCH)
    			return !strcmp(pattern, data); /* 1 on match, 0 on fail */
    		if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
    			return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
    		else
    			return 0;
    	}
    	pattern++; /* skip leading _ */
    	/*
    	 * XXX below we stop at '/' which is a separator for the CID info. However we should
    	 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
    	 */
    	while (*data && *pattern && *pattern != '/') {
    		const char *end;
    
    		if (*data == '-') { /* skip '-' in data (just a separator) */
    			data++;
    			continue;
    		}
    		switch (toupper(*pattern)) {
    		case '[':	/* a range */
    			end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
    			if (end == NULL) {
    				ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
    				return 0;	/* unconditional failure */
    			}
    			for (pattern++; pattern != end; pattern++) {
    				if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
    					if (*data >= pattern[0] && *data <= pattern[2])
    						break;	/* match found */
    					else {
    						pattern += 2; /* skip a total of 3 chars */
    						continue;
    					}
    				} else if (*data == pattern[0])
    					break;	/* match found */
    			}
    			if (pattern == end)
    				return 0;
    			pattern = end;	/* skip and continue */
    			break;
    		case 'N':
    			if (*data < '2' || *data > '9')
    				return 0;
    			break;
    		case 'X':
    			if (*data < '0' || *data > '9')
    				return 0;
    			break;
    		case 'Z':
    			if (*data < '1' || *data > '9')
    				return 0;
    			break;
    		case '.':	/* Must match, even with more digits */
    			return 1;
    		case '!':	/* Early match */
    			return 2;
    		case ' ':
    		case '-':	/* Ignore these in patterns */
    			data--; /* compensate the final data++ */
    			break;
    		default:
    			if (*data != *pattern)
    				return 0;
    		}
    		data++;
    		pattern++;
    	}
    	if (*data)			/* data longer than pattern, no match */
    		return 0;
    	/*
    	 * match so far, but ran off the end of the data.
    	 * Depending on what is next, determine match or not.
    	 */
    	if (*pattern == '\0' || *pattern == '/')	/* exact match */
    		return (mode == E_MATCHMORE) ? 0 : 1;	/* this is a failure for E_MATCHMORE */
    	else if (*pattern == '!')			/* early match */
    		return 2;
    	else						/* partial match */
    		return (mode == E_MATCH) ? 0 : 1;	/* this is a failure for E_MATCH */
    }
    
    static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
    {
    	int i;
    	i = _extension_match_core(pattern, data, mode);
    	return i;
    }
    
    static int ast_extension_match(const char *pattern, const char *data);
    
    static int ast_extension_match(const char *pattern, const char *data)
    {
    	return extension_match_core(pattern, data, E_MATCH);
    }
    
    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);
    }
    
    static inline int include_valid(struct ast_include *i)
    {
    	if (!i->hastime)
    		return 1;
    
    	return ast_check_timing(&(i->timing));
    }
    
    
    
    static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
    
    											struct ast_context *bypass,
    
    											const char *context,
    											const char *exten,
    
    											const char *label,
    											const char *callerid,
    
    											enum ext_match_t action);
    
    
    static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
    
    											struct ast_context *bypass,
    
    											const char *context,
    											const char *exten,
    
    											const char *label,
    											const char *callerid,
    
    											enum ext_match_t action)
    {
    	int x;
    	struct ast_context *tmp;
    	struct ast_exten *e, *eroot;
    	struct ast_include *i;
    
    	/* Initialize status if appropriate */
    	if (q->stacklen == 0) {
    		q->status = STATUS_NO_CONTEXT;
    		q->swo = NULL;
    		q->data = NULL;
    		q->foundcontext = NULL;
    	} else if (q->stacklen >= AST_PBX_MAX_STACK) {
    		ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
    		return NULL;
    	}
    	/* Check first to see if we've already been checked */
    	for (x = 0; x < q->stacklen; x++) {
    		if (!strcasecmp(q->incstack[x], context))
    			return NULL;
    	}
    	if (bypass)	/* bypass means we only look there */
    		tmp = bypass;
    	else {	/* look in contexts */
    		tmp = NULL;
    		while ((tmp = ast_walk_contexts(tmp)) ) {
    			if (!strcmp(tmp->name, context))
    				break;
    		}
    		if (!tmp)
    			return NULL;
    	}
    	if (q->status < STATUS_NO_EXTENSION)
    		q->status = STATUS_NO_EXTENSION;
    
    	/* 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;
    		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 keep searching */
    		}
    		if (e) {	/* found a valid match */
    			q->status = STATUS_SUCCESS;
    			q->foundcontext = context;
    			return e;
    		}
    	}
    #ifdef NOT_RIGHT_NOW
    	/* Check alternative switches???  */
    	AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
    		struct ast_switch *asw = pbx_findswitch(sw->name);
    		ast_switch_f *aswf = NULL;
    		char *datap;
    
    		if (!asw) {
    			ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
    			continue;
    		}
    		/* No need to Substitute variables now; we shouldn't be here if there's any  */
    
    		/* equivalent of extension_match_core() at the switch level */
    		if (action == E_CANMATCH)
    			aswf = asw->canmatch;
    		else if (action == E_MATCHMORE)
    			aswf = asw->matchmore;
    		else /* action == E_MATCH */
    			aswf = asw->exists;
    		datap = sw->eval ? sw->tmpdata : sw->data;
    		res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
    		if (res) {	/* Got a match */
    			q->swo = asw;
    			q->data = datap;
    			q->foundcontext = context;
    			/* XXX keep status = STATUS_NO_CONTEXT ? */
    			return NULL;
    		}
    	}
    #endif
    	q->incstack[q->stacklen++] = tmp->name;	/* Setup the stack */
    	/* 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(NULL, bypass, q, i->rname, exten, priority, label, callerid, action)))
    				return e;
    			if (q->swo)
    				return NULL;
    		}
    	}
    	return NULL;
    }
    
    struct ast_exten *localized_find_extension(struct ast_context *bypass,
    										  struct pbx_find_info *q,
    
    										  const char *context,
    										  const char *exten,
    
    										  const char *label,
    										  const char *callerid,
    
    										  enum ext_match_t action);
    
    struct ast_exten *localized_find_extension(struct ast_context *bypass,
    										  struct pbx_find_info *q,
    
    										  const char *context,
    										  const char *exten,
    
    										  const char *label,
    										  const char *callerid,
    
    										   enum ext_match_t action)
    {
    	return pbx_find_extension(NULL, bypass, q, context, exten, priority, label, callerid, action);
    }
    
    
    static struct ast_context *contexts;
    AST_RWLOCK_DEFINE_STATIC(conlock); 		/*!< Lock for the ast_context list */
    
    static const char *ast_get_context_name(struct ast_context *con);
    
    static const char *ast_get_context_name(struct ast_context *con)
    {
    	return con ? con->name : NULL;
    }
    
    /*
     * errno values
     *  ENOMEM - out of memory
     *  EBUSY  - can't lock
     *  EEXIST - already included
     *  EINVAL - there is no existence of context for inclusion
     */
    static int ast_context_add_include2(struct ast_context *con, const char *value,
    							 const char *registrar);
    
    static int ast_context_add_include2(struct ast_context *con, const char *value,
    									const char *registrar)
    {
    	struct ast_include *new_include;
    	char *c;
    	struct ast_include *i, *il = NULL; /* include, include_last */
    	int length;
    	char *p;
    
    	length = sizeof(struct ast_include);
    	length += 2 * (strlen(value) + 1);
    
    	/* allocate new include structure ... */
    	if (!(new_include = ast_calloc(1, length)))
    		return -1;
    	/* Fill in this structure. Use 'p' for assignments, as the fields
    	 * in the structure are 'const char *'
    	 */
    	p = new_include->stuff;
    	new_include->name = p;
    	strcpy(p, value);
    	p += strlen(value) + 1;
    	new_include->rname = p;
    	strcpy(p, value);
    	/* Strip off timing info, and process if it is there */
    	if ( (c = strchr(p, '|')) ) {
    		*c++ = '\0';
    
    		new_include->hastime = ast_build_timing(&(new_include->timing), c);
    
    	}
    	new_include->next      = NULL;
    	new_include->registrar = registrar;
    
    
    	/* ... go to last include and check if context is already included too... */
    	for (i = con->includes; i; i = i->next) {
    		if (!strcasecmp(i->name, new_include->name)) {
    			free(new_include);
    			errno = EEXIST;
    			return -1;
    		}
    		il = i;
    	}
    
    	/* ... include new context into context list, unlock, return */
    	if (il)
    		il->next = new_include;
    	else
    		con->includes = new_include;
    	if (option_verbose > 2)
    		ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
    
    	return 0;
    }
    
    int localized_context_add_include2(struct ast_context *con, const char *value,
    							 const char *registrar);
    int localized_context_add_include2(struct ast_context *con, const char *value,
    								   const char *registrar)
    {
    	return  ast_context_add_include2(con, value, registrar);
    }
    
    
    
    static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
    
    static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
    {
    	struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
    	int length;
    	length = sizeof(struct ast_ignorepat);
    	length += strlen(value) + 1;
    	if (!(ignorepat = ast_calloc(1, length)))
    		return -1;
    	/* The cast to char * is because we need to write the initial value.
    	 * The field is not supposed to be modified otherwise
    	 */
    	strcpy((char *)ignorepat->pattern, value);
    	ignorepat->next = NULL;
    	ignorepat->registrar = registrar;
    	for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
    		ignorepatl = ignorepatc;
    		if (!strcasecmp(ignorepatc->pattern, value)) {
    			/* Already there */
    			errno = EEXIST;
    			return -1;
    		}
    	}
    	if (ignorepatl)
    		ignorepatl->next = ignorepat;
    	else
    		con->ignorepats = ignorepat;
    	return 0;
    
    }
    
    int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
    
    int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
    {
    	return ast_context_add_ignorepat2(con, value, registrar);
    }
    
    
    /*
     * Lock context list functions ...
     */
    
    static int ast_wrlock_contexts(void)
    {
    	return ast_rwlock_wrlock(&conlock);
    }
    
    static int ast_unlock_contexts(void)
    {
    	return ast_rwlock_unlock(&conlock);
    }
    
    static int ast_wrlock_context(struct ast_context *con)
    {
    	return ast_rwlock_wrlock(&con->lock);
    }
    
    static int ast_unlock_context(struct ast_context *con)
    {
    	return ast_rwlock_unlock(&con->lock);
    }
    
    /*
     * errno values
     *  ENOMEM - out of memory
     *  EBUSY  - can't lock
     *  EEXIST - already included
     *  EINVAL - there is no existence of context for inclusion
     */
    static int ast_context_add_switch2(struct ast_context *con, const char *value,
    							const char *data, int eval, const char *registrar);
    
    static int ast_context_add_switch2(struct ast_context *con, const char *value,
    	const char *data, int eval, const char *registrar)
    {
    	struct ast_sw *new_sw;
    	struct ast_sw *i;
    	int length;
    	char *p;
    
    	length = sizeof(struct ast_sw);
    	length += strlen(value) + 1;
    	if (data)
    		length += strlen(data);
    	length++;
    	if (eval) {
    		/* Create buffer for evaluation of variables */
    		length += SWITCH_DATA_LENGTH;
    		length++;
    	}
    
    	/* allocate new sw structure ... */
    	if (!(new_sw = ast_calloc(1, length)))
    		return -1;
    	/* ... fill in this structure ... */
    	p = new_sw->stuff;
    	new_sw->name = p;
    	strcpy(new_sw->name, value);
    	p += strlen(value) + 1;
    	new_sw->data = p;
    	if (data) {
    		strcpy(new_sw->data, data);
    		p += strlen(data) + 1;
    	} else {
    		strcpy(new_sw->data, "");
    		p++;
    	}
    	if (eval)
    		new_sw->tmpdata = p;
    	new_sw->eval	  = eval;
    	new_sw->registrar = registrar;
    
    	/* ... go to last sw and check if context is already swd too... */
    	AST_LIST_TRAVERSE(&con->alts, i, list) {
    		if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
    			free(new_sw);
    			errno = EEXIST;
    			return -1;
    		}
    	}
    
    	/* ... sw new context into context list, unlock, return */
    	AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
    
    	if (option_verbose > 2)
    		ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
    
    	return 0;
    }
    
    int localized_context_add_switch2(struct ast_context *con, const char *value,
    										 const char *data, int eval, const char *registrar);
    
    int localized_context_add_switch2(struct ast_context *con, const char *value,
    										 const char *data, int eval, const char *registrar)
    {
    	return ast_context_add_switch2(con, value, data, eval, registrar);
    }
    
    static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
    {
    
    	struct ast_context *tmp, **loc_contexts;
    
    	int length = sizeof(struct ast_context) + strlen(name) + 1;