[asterisk-commits] murf: branch murf/bug_7638 r57752 -
/team/murf/bug_7638/utils/
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Sat Mar 3 11:06:31 MST 2007
Author: murf
Date: Sat Mar 3 12:06:30 2007
New Revision: 57752
URL: http://svn.digium.com/view/asterisk?view=rev&rev=57752
Log:
refactored most of the extensions.conf parser into extconf.c
Added:
team/murf/bug_7638/utils/extconf.c (with props)
Modified:
team/murf/bug_7638/utils/Makefile
team/murf/bug_7638/utils/conf2ael.c
Modified: team/murf/bug_7638/utils/Makefile
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/Makefile?view=diff&rev=57752&r1=57751&r2=57752
==============================================================================
--- team/murf/bug_7638/utils/Makefile (original)
+++ team/murf/bug_7638/utils/Makefile Sat Mar 3 12:06:30 2007
@@ -112,7 +112,9 @@
config_external.o : config_external.c
-conf2ael: conf2ael.o config_external.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o
+extconf.o : extconf.c
+
+conf2ael: conf2ael.o config_external.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o
testexpr2s: ../main/ast_expr2f.c ../main/ast_expr2.c ../main/ast_expr2.h
Modified: team/murf/bug_7638/utils/conf2ael.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/conf2ael.c?view=diff&rev=57752&r1=57751&r2=57752
==============================================================================
--- team/murf/bug_7638/utils/conf2ael.c (original)
+++ team/murf/bug_7638/utils/conf2ael.c Sat Mar 3 12:06:30 2007
@@ -55,20 +55,28 @@
#include "asterisk/ael_structs.h"
#include "asterisk/pval.h"
-
-static char *config = "extensions.conf";
+int pbx_load_config(const char *config_file);
+void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);
+int all_bits_set(unsigned int *word, int bitsperword, int totalbits);
+
+extern char *days[];
+extern char *months[];
+extern char *config;
+char ast_config_AST_CONFIG_DIR[PATH_MAX];
+
+/* static char *config = "extensions.conf";
static char *registrar = "conf2ael";
static char userscontext[AST_MAX_EXTENSION] = "default";
static int static_config = 0;
static int write_protect_config = 1;
static int autofallthrough_config = 0;
static int clearglobalvars_config = 0;
-char ast_config_AST_SYSTEM_NAME[20] = "";
+char ast_config_AST_SYSTEM_NAME[20] = ""; */
+
/*! Go no deeper than this through includes (not counting loops) */
#define AST_PBX_MAX_STACK 128
-static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
-char ast_config_AST_CONFIG_DIR[PATH_MAX];
-extern char *my_file;
+/* static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function); */
+extern char ast_config_AST_CONFIG_DIR[PATH_MAX];
/* modulation */
void ast_register_file_version(void);
@@ -89,71 +97,6 @@
}
-/* stolen from callerid.c */
-
-/*! \brief Clean up phone string
- * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
- * Basically, remove anything that could be invalid in a pattern.
- */
-void ast_shrink_phone_number(char *n)
-{
- int x, y=0;
- int bracketed = 0;
-
- for (x=0; n[x]; x++) {
- switch(n[x]) {
- case '[':
- bracketed++;
- n[y++] = n[x];
- break;
- case ']':
- bracketed--;
- n[y++] = n[x];
- break;
- case '-':
- if (bracketed)
- n[y++] = n[x];
- break;
- case '.':
- if (!n[x+1])
- n[y++] = n[x];
- break;
- default:
- if (!strchr("()", n[x]))
- n[y++] = n[x];
- }
- }
- n[y] = '\0';
-}
-
-
-/* stolen from chanvars.c */
-
-const char *ast_var_name(const struct ast_var_t *var)
-{
- const char *name;
-
- if (var == NULL || (name = var->name) == NULL)
- return NULL;
- /* Return the name without the initial underscores */
- if (name[0] == '_') {
- name++;
- if (name[0] == '_')
- name++;
- }
- return name;
-}
-
-const char *ast_var_value(const struct ast_var_t *var)
-{
- return (var ? var->value : NULL);
-}
-
-
-/* stolen from asterisk.c */
-struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
-int option_verbose = 0; /*!< Verbosity level */
-int option_debug = 0; /*!< Debug level */
/* experiment 1: see if it's easier just to use existing config code
@@ -165,90 +108,6 @@
/* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
-
-void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
-{
- va_list vars;
- va_start(vars,fmt);
-
- printf("LOG: lev:%d file:%s line:%d func: %s ",
- level, file, line, function);
- vprintf(fmt, vars);
- fflush(stdout);
- va_end(vars);
-}
-
-void ast_verbose(const char *fmt, ...)
-{
- va_list vars;
- va_start(vars,fmt);
-
- printf("VERBOSE: ");
- vprintf(fmt, vars);
- fflush(stdout);
- va_end(vars);
-}
-
-/* stolen from main/utils.c */
-char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
-{
- char *dataPut = start;
- int inEscape = 0;
- int inQuotes = 0;
-
- for (; *start; start++) {
- if (inEscape) {
- *dataPut++ = *start; /* Always goes verbatim */
- inEscape = 0;
- } else {
- if (*start == '\\') {
- inEscape = 1; /* Do not copy \ into the data */
- } else if (*start == '\'') {
- inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
- } else {
- /* Replace , with |, unless in quotes */
- *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
- }
- }
- }
- if (start != dataPut)
- *dataPut = 0;
- return dataPut;
-}
-
-int ast_true(const char *s)
-{
- if (ast_strlen_zero(s))
- return 0;
-
- /* Determine if this is a true value */
- if (!strcasecmp(s, "yes") ||
- !strcasecmp(s, "true") ||
- !strcasecmp(s, "y") ||
- !strcasecmp(s, "t") ||
- !strcasecmp(s, "1") ||
- !strcasecmp(s, "on"))
- return -1;
-
- return 0;
-}
-
-int ast_false(const char *s)
-{
- if (ast_strlen_zero(s))
- return 0;
-
- /* Determine if this is a false value */
- if (!strcasecmp(s, "no") ||
- !strcasecmp(s, "false") ||
- !strcasecmp(s, "n") ||
- !strcasecmp(s, "f") ||
- !strcasecmp(s, "0") ||
- !strcasecmp(s, "off"))
- return -1;
-
- return 0;
-}
/* stolen from pbx.c */
struct ast_context;
@@ -273,7 +132,6 @@
E_FINDLABEL = 0x22 /* returns the priority for a given label. Requires exact match */
};
-static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
#define SWITCH_DATA_LENGTH 256
@@ -415,12 +273,10 @@
#define STATUS_NO_PRIORITY 3
#define STATUS_NO_LABEL 4
#define STATUS_SUCCESS 5
-static struct ast_context *local_contexts = NULL;
-static struct ast_context *contexts = NULL;
-static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
-
-static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
-struct ast_state_cb *statecbs = NULL;
+
+extern struct ast_context *local_contexts;
+extern struct ast_context *contexts;
+
/* request and result for pbx_find_extension */
struct pbx_find_info {
@@ -438,156 +294,7 @@
const char *foundcontext; /* set on return */
};
-/*
- * 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 */
-}
-
-/*
- * Wrapper around _extension_match_core() to do performance measurement
- * using the profiling code.
- */
-int ast_check_timing(const struct ast_timing *i)
-{
- struct tm tm;
- time_t t = time(NULL);
-
- localtime_r(&t,&tm);
-
- /* If it's not the right month, return */
- if (!(i->monthmask & (1 << tm.tm_mon)))
- return 0;
-
- /* If it's not that time of the month.... */
- /* Warning, tm_mday has range 1..31! */
- if (!(i->daymask & (1 << (tm.tm_mday-1))))
- return 0;
-
- /* If it's not the right day of the week */
- if (!(i->dowmask & (1 << tm.tm_wday)))
- return 0;
-
- /* Sanity check the hour just to be safe */
- if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
- ast_log(LOG_WARNING, "Insane time...\n");
- return 0;
- }
-
- /* Now the tough part, we calculate if it fits
- in the right time based on min/hour */
- if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
- return 0;
-
- /* If we got this far, then we're good */
- return 1;
-}
-
-static inline int include_valid(struct ast_include *i)
-{
- if (!i->hastime)
- return 1;
-
- return ast_check_timing(&(i->timing));
-}
+
struct profile_entry {
const char *name;
@@ -603,2243 +310,6 @@
struct profile_entry e[0];
};
-static struct profile_data *prof_data;
-
-/*! \brief allocates a counter with a given name and scale.
- * \return Returns the identifier of the counter.
- */
-int ast_add_profile(const char *name, uint64_t scale);
-
-int ast_add_profile(const char *name, uint64_t scale)
-{
- int l = sizeof(struct profile_data);
- int n = 10; /* default entries */
-
- if (prof_data == NULL) {
- prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
- if (prof_data == NULL)
- return -1;
- prof_data->entries = 0;
- prof_data->max_size = n;
- }
- if (prof_data->entries >= prof_data->max_size) {
- void *p;
- n = prof_data->max_size + 20;
- p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
- if (p == NULL)
- return -1;
- prof_data = p;
- prof_data->max_size = n;
- }
- n = prof_data->entries++;
- prof_data->e[n].name = ast_strdup(name);
- prof_data->e[n].value = 0;
- prof_data->e[n].events = 0;
- prof_data->e[n].mark = 0;
- prof_data->e[n].scale = scale;
- return n;
-}
-
-int64_t ast_profile(int i, int64_t delta);
-
-int64_t ast_profile(int i, int64_t delta)
-{
- if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
- return 0;
- if (prof_data->e[i].scale > 1)
- delta /= prof_data->e[i].scale;
- prof_data->e[i].value += delta;
- prof_data->e[i].events++;
- return prof_data->e[i].value;
-}
-
-#if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
-#if defined(__FreeBSD__)
-#include <machine/cpufunc.h>
-#elif defined(linux)
-static __inline uint64_t
-rdtsc(void)
-{
- uint64_t rv;
-
- __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
- return (rv);
-}
-#endif
-#else /* supply a dummy function on other platforms */
-static __inline uint64_t
-rdtsc(void)
-{
- return 0;
-}
-#endif
-
-int64_t ast_mark(int i, int startstop);
-
-int64_t ast_mark(int i, int startstop)
-{
- if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
- return 0;
- if (startstop == 1)
- prof_data->e[i].mark = rdtsc();
- else {
- prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
- if (prof_data->e[i].scale > 1)
- prof_data->e[i].mark /= prof_data->e[i].scale;
- prof_data->e[i].value += prof_data->e[i].mark;
- prof_data->e[i].events++;
- }
- return prof_data->e[i].mark;
-}
-static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
-{
- int i;
- static int prof_id = -2; /* marker for 'unallocated' id */
- if (prof_id == -2)
- prof_id = ast_add_profile("ext_match", 0);
- ast_mark(prof_id, 1);
- i = _extension_match_core(pattern, data, mode);
- ast_mark(prof_id, 0);
- return i;
-}
-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 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;
-}
-struct ast_context *ast_walk_contexts(struct ast_context *con)
-{
- return con ? con->next : contexts;
-}
-
-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 *ast_walk_extension_priorities(struct ast_exten *exten,
- struct ast_exten *priority)
-{
- return priority ? priority->peer : exten;
-}
-
-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;
-}
-
-
-
-static 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,
- const char *label, const char *callerid, enum ext_match_t action)
-{
- int x, res;
- struct ast_context *tmp;
- struct ast_exten *e, *eroot;
- struct ast_include *i;
- struct ast_sw *sw;
-
- /* Initialize status if appropriate */
- if (q->stacklen == 0) {
- q->status = STATUS_NO_CONTEXT;
- q->swo = NULL;
- q->data = NULL;
- q->foundcontext = NULL;
- }
- /* Check for stack overflow */
- 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;
- }
- }
- /* 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;
- }
- /* Substitute variables now */
- if (sw->eval)
- pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
-
- /* 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;
- }
- }
- 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(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
- return e;
- if (q->swo)
- return NULL;
- }
- }
- return NULL;
-}
-
-/*! \brief ast_hint_extension: Find hint for given extension in context */
-static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
-{
- struct ast_exten *e;
- struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
-
- e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
-
- return e;
-}
-
-const char *ast_get_extension_app(struct ast_exten *e)
-{
- return e ? e->app : NULL;
-}
-
-void *ast_get_extension_app_data(struct ast_exten *e)
-{
- return e ? e->data : NULL;
-}
-
-const char *ast_get_extension_name(struct ast_exten *exten)
-{
- return exten ? exten->exten : NULL;
-}
-
-
-/*! \brief ast_get_hint: Get hint for channel */
-int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
-{
- struct ast_exten *e = ast_hint_extension(c, context, exten);
-
- if (e) {
- if (hint)
- ast_copy_string(hint, ast_get_extension_app(e), hintsize);
- if (name) {
- const char *tmp = ast_get_extension_app_data(e);
- if (tmp)
- ast_copy_string(name, tmp, namesize);
- }
- return -1;
- }
- return 0;
-}
-
-/*! \brief extract offset:length from variable name.
- * Returns 1 if there is a offset:length part, which is
- * trimmed off (values go into variables)
- */
-static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
-{
- int parens=0;
-
- *offset = 0;
- *length = INT_MAX;
- *isfunc = 0;
- for (; *var; var++) {
- if (*var == '(') {
- (*isfunc)++;
- parens++;
- } else if (*var == ')') {
- parens--;
- } else if (*var == ':' && parens == 0) {
- *var++ = '\0';
- sscanf(var, "%d:%d", offset, length);
- return 1; /* offset:length valid */
- }
- }
- return 0;
-}
-
-/*! \brief takes a substring. It is ok to call with value == workspace.
- *
- * offset < 0 means start from the end of the string and set the beginning
- * to be that many characters back.
- * length is the length of the substring. A value less than 0 means to leave
- * that many off the end.
- * Always return a copy in workspace.
- */
-static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
-{
- char *ret = workspace;
- int lr; /* length of the input string after the copy */
-
- ast_copy_string(workspace, value, workspace_len); /* always make a copy */
-
- lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
-
- /* Quick check if no need to do anything */
- if (offset == 0 && length >= lr) /* take the whole string */
- return ret;
-
- if (offset < 0) { /* translate negative offset into positive ones */
- offset = lr + offset;
- if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
- offset = 0;
- }
-
- /* too large offset result in empty string so we know what to return */
- if (offset >= lr)
- return ret + lr; /* the final '\0' */
-
- ret += offset; /* move to the start position */
- if (length >= 0 && length < lr - offset) /* truncate if necessary */
- ret[length] = '\0';
- else if (length < 0) {
- if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
- ret[lr + length - offset] = '\0';
- else
- ret[0] = '\0';
- }
-
- return ret;
-}
-
-/*! \brief Support for Asterisk built-in variables and functions in the dialplan
-
-\note See also
- - \ref AstVar Channel variables
- - \ref AstCauses The HANGUPCAUSE variable
- */
-void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
-{
- const char not_found = '\0';
- char *tmpvar;
- const char *s; /* the result */
- int offset, length;
- int i, need_substring;
- struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
-
- if (c) {
- places[0] = &c->varshead;
- }
- /*
- * Make a copy of var because parse_variable_name() modifies the string.
- * Then if called directly, we might need to run substring() on the result;
- * remember this for later in 'need_substring', 'offset' and 'length'
- */
- tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
- need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
-
- /*
- * Look first into predefined variables, then into variable lists.
- * Variable 's' points to the result, according to the following rules:
- * s == ¬_found (set at the beginning) means that we did not find a
- * matching variable and need to look into more places.
- * If s != ¬_found, s is a valid result string as follows:
- * s = NULL if the variable does not have a value;
- * you typically do this when looking for an unset predefined variable.
- * s = workspace if the result has been assembled there;
- * typically done when the result is built e.g. with an snprintf(),
- * so we don't need to do an additional copy.
- * s != workspace in case we have a string, that needs to be copied
- * (the ast_copy_string is done once for all at the end).
- * Typically done when the result is already available in some string.
- */
- s = ¬_found; /* default value */
- if (c) { /* This group requires a valid channel */
- /* Names with common parts are looked up a piece at a time using strncmp. */
- if (!strncmp(var, "CALL", 4)) {
- if (!strncmp(var + 4, "ING", 3)) {
- if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
- s = workspace;
- } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
- s = workspace;
- } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
- s = workspace;
- } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
- s = workspace;
- }
- }
- } else if (!strcmp(var, "HINT")) {
- s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
- } else if (!strcmp(var, "HINTNAME")) {
- s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
- } else if (!strcmp(var, "EXTEN")) {
- s = c->exten;
- } else if (!strcmp(var, "CONTEXT")) {
- s = c->context;
- } else if (!strcmp(var, "PRIORITY")) {
- snprintf(workspace, workspacelen, "%d", c->priority);
- s = workspace;
- } else if (!strcmp(var, "CHANNEL")) {
- s = c->name;
- } else if (!strcmp(var, "UNIQUEID")) {
- s = c->uniqueid;
- } else if (!strcmp(var, "HANGUPCAUSE")) {
- snprintf(workspace, workspacelen, "%d", c->hangupcause);
- s = workspace;
- }
- }
- if (s == ¬_found) { /* look for more */
- if (!strcmp(var, "EPOCH")) {
- snprintf(workspace, workspacelen, "%u",(int)time(NULL));
- s = workspace;
- } else if (!strcmp(var, "SYSTEMNAME")) {
- s = ast_config_AST_SYSTEM_NAME;
- }
- }
- /* if not found, look into chanvars or global vars */
- for (i = 0; s == ¬_found && i < (sizeof(places) / sizeof(places[0])); i++) {
- struct ast_var_t *variables;
- if (!places[i])
- continue;
- AST_LIST_TRAVERSE(places[i], variables, entries) {
- if (strcasecmp(ast_var_name(variables), var)==0) {
- s = ast_var_value(variables);
- break;
- }
- }
- }
- if (s == ¬_found || s == NULL)
- *ret = NULL;
- else {
- if (s != workspace)
- ast_copy_string(workspace, s, workspacelen);
- *ret = workspace;
- if (need_substring)
- *ret = substring(*ret, offset, length, workspace, workspacelen);
- }
-}
-struct ast_custom_function *ast_custom_function_find(const char *name)
-{
- struct ast_custom_function *acf = NULL;
-
- AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
- if (!strcmp(name, acf->name))
- break;
- }
-
- return acf;
-}
-
-
-/*! \brief return a pointer to the arguments of the function,
- * and terminates the function name with '\\0'
- */
-static char *func_args(const char *function)
-{
- char *args = strchr(function, '(');
-
- if (!args)
- ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
- else {
- char *p;
- *args++ = '\0';
- if ((p = strrchr(args, ')')) )
- *p = '\0';
- else
- ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
- }
- return args;
-}
-
-int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
-{
- char *args = func_args(function);
- struct ast_custom_function *acfptr = ast_custom_function_find(function);
-
- if (acfptr == NULL)
- ast_log(LOG_ERROR, "Function %s not registered\n", function);
- else if (!acfptr->read)
- ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
- else
- return acfptr->read(chan, function, args, workspace, len);
- return -1;
-}
-
-static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
-{
- /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
- zero-filled */
- char *cp4;
- const char *tmp, *whereweare;
- int length, offset, offset2, isfunction;
- char *workspace = NULL;
- char *ltmp = NULL, *var = NULL;
- char *nextvar, *nextexp, *nextthing;
- char *vars, *vare;
- int pos, brackets, needsub, len;
-
- whereweare=tmp=cp1;
- while (!ast_strlen_zero(whereweare) && count) {
- /* Assume we're copying the whole remaining string */
- pos = strlen(whereweare);
- nextvar = NULL;
- nextexp = NULL;
- nextthing = strchr(whereweare, '$');
- if (nextthing) {
- switch(nextthing[1]) {
- case '{':
- nextvar = nextthing;
- pos = nextvar - whereweare;
- break;
- case '[':
- nextexp = nextthing;
- pos = nextexp - whereweare;
- break;
- }
- }
-
- if (pos) {
- /* Can't copy more than 'count' bytes */
- if (pos > count)
- pos = count;
-
- /* Copy that many bytes */
- memcpy(cp2, whereweare, pos);
-
- count -= pos;
- cp2 += pos;
- whereweare += pos;
- }
-
- if (nextvar) {
- /* We have a variable. Find the start and end, and determine
- if we are going to have to recursively call ourselves on the
- contents */
- vars = vare = nextvar + 2;
- brackets = 1;
- needsub = 0;
-
- /* Find the end of it */
- while (brackets && *vare) {
- if ((vare[0] == '$') && (vare[1] == '{')) {
- needsub++;
- } else if (vare[0] == '{') {
- brackets++;
- } else if (vare[0] == '}') {
- brackets--;
- } else if ((vare[0] == '$') && (vare[1] == '['))
- needsub++;
- vare++;
- }
- if (brackets)
- ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
- len = vare - vars - 1;
-
- /* Skip totally over variable string */
- whereweare += (len + 3);
-
- if (!var)
- var = alloca(VAR_BUF_SIZE);
-
- /* Store variable name (and truncate) */
- ast_copy_string(var, vars, len + 1);
-
- /* Substitute if necessary */
- if (needsub) {
- if (!ltmp)
- ltmp = alloca(VAR_BUF_SIZE);
-
- memset(ltmp, 0, VAR_BUF_SIZE);
- pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
- vars = ltmp;
- } else {
- vars = var;
- }
-
- if (!workspace)
- workspace = alloca(VAR_BUF_SIZE);
-
- workspace[0] = '\0';
-
- parse_variable_name(vars, &offset, &offset2, &isfunction);
- if (isfunction) {
- /* Evaluate function */
- cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
- if (option_debug)
- ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
- } else {
- /* Retrieve variable value */
- pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
- }
- if (cp4) {
- cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
-
- length = strlen(cp4);
- if (length > count)
- length = count;
- memcpy(cp2, cp4, length);
- count -= length;
- cp2 += length;
- }
- } else if (nextexp) {
- /* We have an expression. Find the start and end, and determine
- if we are going to have to recursively call ourselves on the
- contents */
- vars = vare = nextexp + 2;
- brackets = 1;
- needsub = 0;
-
- /* Find the end of it */
- while(brackets && *vare) {
- if ((vare[0] == '$') && (vare[1] == '[')) {
- needsub++;
- brackets++;
- vare++;
- } else if (vare[0] == '[') {
- brackets++;
- } else if (vare[0] == ']') {
- brackets--;
- } else if ((vare[0] == '$') && (vare[1] == '{')) {
- needsub++;
- vare++;
- }
- vare++;
- }
- if (brackets)
- ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
- len = vare - vars - 1;
-
- /* Skip totally over expression */
- whereweare += (len + 3);
-
- if (!var)
- var = alloca(VAR_BUF_SIZE);
-
- /* Store variable name (and truncate) */
- ast_copy_string(var, vars, len + 1);
-
- /* Substitute if necessary */
- if (needsub) {
- if (!ltmp)
- ltmp = alloca(VAR_BUF_SIZE);
-
- memset(ltmp, 0, VAR_BUF_SIZE);
- pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
- vars = ltmp;
- } else {
- vars = var;
- }
-
- length = ast_expr(vars, cp2, count);
-
- if (length) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
- count -= length;
- cp2 += length;
- }
- } else
- break;
- }
-}
-
-void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
-{
- pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
-}
-
-void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
-{
- pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
-}
-
-/*! \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);
-}
-
-void ast_context_destroy(struct ast_context *con, const char *registrar)
-{
- struct ast_context *tmp, *tmpl=NULL;
- struct ast_exten *e, *el, *en;
- struct ast_include *tmpi;
- struct ast_sw *sw;
- struct ast_ignorepat *ipi;
-
- for (tmp = contexts; tmp; ) {
- struct ast_context *next; /* next starting point */
- for (; tmp; tmpl = tmp, tmp = tmp->next) {
- if (option_debug)
- ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
- if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
- (!con || !strcasecmp(tmp->name, con->name)) )
- break; /* found it */
- }
- if (!tmp) /* not found, we are done */
- break;
- if (option_debug)
- ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
- next = tmp->next;
- if (tmpl)
- tmpl->next = next;
- else
- contexts = next;
- /* Okay, now we're safe to let it go -- in a sense, we were
- ready to let it go as soon as we locked it. */
- for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
- struct ast_include *tmpil = tmpi;
- tmpi = tmpi->next;
- free(tmpil);
- }
- for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
- struct ast_ignorepat *ipl = ipi;
- ipi = ipi->next;
- free(ipl);
- }
- while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
- free(sw);
- for (e = tmp->root; e;) {
- for (en = e->peer; en;) {
- el = en;
- en = en->peer;
- destroy_exten(el);
- }
- el = e;
- e = e->next;
- destroy_exten(el);
- }
- free(tmp);
- /* if we have a specific match, we are done, otherwise continue */
- tmp = con ? NULL : next;
- }
-}
-
-static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
-{
- struct ast_context *tmp, **local_contexts;
- int length = sizeof(struct ast_context) + strlen(name) + 1;
-
- if (!extcontexts) {
- local_contexts = &contexts;
- } else
- 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;
- }
- }
- if ((tmp = ast_calloc(1, length))) {
- strcpy(tmp->name, name);
- tmp->root = NULL;
- tmp->registrar = registrar;
- tmp->next = *local_contexts;
- tmp->includes = NULL;
- tmp->ignorepats = NULL;
- *local_contexts = tmp;
- if (option_debug)
- ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
- }
-
- 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);
-}
-
-struct ast_var_t *ast_var_assign(const char *name, const char *value)
-{
- struct ast_var_t *var;
- int name_len = strlen(name) + 1;
- int value_len = strlen(value) + 1;
-
- if (!(var = ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char)))) {
- return NULL;
- }
-
- ast_copy_string(var->name, name, name_len);
- var->value = var->name + name_len;
- ast_copy_string(var->value, value, value_len);
-
- return var;
-}
-
-void ast_var_delete(struct ast_var_t *var)
-{
- if (var)
- free(var);
-}
-
-
-int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
-{
- char *args = func_args(function);
- struct ast_custom_function *acfptr = ast_custom_function_find(function);
-
- if (acfptr == NULL)
- ast_log(LOG_ERROR, "Function %s not registered\n", function);
- else if (!acfptr->write)
- ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
- else
- return acfptr->write(chan, function, args, value);
-
- return -1;
-}
-
-unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
-{
- int argc;
- char *scan;
- int paren = 0, quote = 0;
-
- if (!buf || !array || !arraylen)
- return 0;
-
- memset(array, 0, arraylen * sizeof(*array));
-
- scan = buf;
-
- for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
- array[argc] = scan;
- for (; *scan; scan++) {
- if (*scan == '(')
- paren++;
- else if (*scan == ')') {
- if (paren)
- paren--;
- } else if (*scan == '"' && delim != '"') {
- quote = quote ? 0 : 1;
- /* Remove quote character from argument */
- memmove(scan, scan + 1, strlen(scan));
- scan--;
- } else if (*scan == '\\') {
- /* Literal character, don't parse */
- memmove(scan, scan + 1, strlen(scan));
- } else if ((*scan == delim) && !paren && !quote) {
- *scan++ = '\0';
- break;
- }
- }
- }
-
- if (*scan)
- array[argc++] = scan;
-
- return argc;
-}
-
-void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
-{
- struct ast_var_t *newvariable;
- struct varshead *headp;
- const char *nametail = name;
-
- /* XXX may need locking on the channel ? */
- if (name[strlen(name)-1] == ')') {
- char *function = ast_strdupa(name);
-
- ast_func_write(chan, function, value);
- return;
- }
-
- headp = (chan) ? &chan->varshead : &globals;
-
- /* For comparison purposes, we have to strip leading underscores */
- if (*nametail == '_') {
- nametail++;
- if (*nametail == '_')
- nametail++;
- }
-
- AST_LIST_TRAVERSE (headp, newvariable, entries) {
- if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
- /* there is already such a variable, delete it */
- AST_LIST_REMOVE(headp, newvariable, entries);
- ast_var_delete(newvariable);
- break;
- }
- }
-
- if (value) {
- if ((option_verbose > 1) && (headp == &globals))
- ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
- newvariable = ast_var_assign(name, value);
[... 4094 lines stripped ...]
More information about the asterisk-commits
mailing list