Skip to content
Snippets Groups Projects
extconf.c 183 KiB
Newer Older
  • Learn to ignore specific revisions
  • Steve Murphy's avatar
    Steve Murphy committed
    	void *p;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!(p = calloc(num, len)))
    		MALLOC_FAILURE_MSG;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return p;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for calloc() for use in cache pools
     *
     * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
     * message in the case that the allocation fails. When memory debugging is in use,
     * the memory allocated by this function will be marked as 'cache' so it can be
     * distinguished from normal memory allocations.
     *
     * The arguments and return value are the same as calloc()
     */
    #define ast_calloc_cache(num, len) \
    	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for realloc()
     *
     * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as realloc()
     */
    #define ast_realloc(p, len) \
    	_ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
    {
    	void *newp;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!(newp = realloc(p, len)))
    		MALLOC_FAILURE_MSG;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return newp;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for strdup()
     *
     * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
     * argument is provided, ast_strdup will return NULL without generating any
     * kind of error log message.
     *
     * The argument and return value are the same as strdup()
     */
    #define ast_strdup(str) \
    	_ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
    {
    	char *newstr = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (str) {
    		if (!(newstr = strdup(str)))
    			MALLOC_FAILURE_MSG;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return newstr;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for strndup()
     *
     * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
     * string to duplicate. If a NULL argument is provided, ast_strdup will return  
     * NULL without generating any kind of error log message.
     *
     * The arguments and return value are the same as strndup()
     */
    #define ast_strndup(str, len) \
    	_ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
    {
    	char *newstr = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (str) {
    		if (!(newstr = strndup(str, len)))
    			MALLOC_FAILURE_MSG;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return newstr;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for asprintf()
     *
     * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as asprintf()
     */
    #define ast_asprintf(ret, fmt, ...) \
    	_ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    
    __attribute__((format(printf, 5, 6)))
    
    Steve Murphy's avatar
    Steve Murphy committed
    int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
    {
    	int res;
    	va_list ap;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	va_start(ap, fmt);
    	if ((res = vasprintf(ret, fmt, ap)) == -1)
    		MALLOC_FAILURE_MSG;
    	va_end(ap);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
     * \brief A wrapper for vasprintf()
     *
     * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
     * message in the case that the allocation fails.
     *
     * The arguments and return value are the same as vasprintf()
     */
    #define ast_vasprintf(ret, fmt, ap) \
    	_ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    
    __attribute__((format(printf, 5, 0)))
    
    Steve Murphy's avatar
    Steve Murphy committed
    int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
    {
    	int res;
    
    	if ((res = vasprintf(ret, fmt, ap)) == -1)
    		MALLOC_FAILURE_MSG;
    
    	return res;
    }
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if !defined(ast_strdupa) && defined(__GNUC__)
    /*!
      \brief duplicate a string in memory from the stack
      \param s The string to duplicate
    
      This macro will duplicate the given string.  It returns a pointer to the stack
      allocatted memory for the new string.
    */
    #define ast_strdupa(s)                                                    \
    	(__extension__                                                    \
    	({                                                                \
    		const char *__old = (s);                                  \
    		size_t __len = strlen(__old) + 1;                         \
    		char *__new = __builtin_alloca(__len);                    \
    		memcpy (__new, __old, __len);                             \
    		__new;                                                    \
    	}))
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from config.c */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define MAX_NESTED_COMMENTS 128
    #define COMMENT_START ";--"
    #define COMMENT_END "--;"
    #define COMMENT_META ';'
    #define COMMENT_TAG '-'
    
    Steve Murphy's avatar
    Steve Murphy committed
    static char *extconfig_conf = "extconfig.conf";
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! Growable string buffer */
    static char *comment_buffer;   /*!< this will be a comment collector.*/
    static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
    
    Steve Murphy's avatar
    Steve Murphy committed
    static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
    static int  lline_buffer_size;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define CB_INCR 250
    
    struct ast_comment {
    	struct ast_comment *next;
    	char cmt[0];
    };
    
    static void CB_INIT(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!comment_buffer) {
    		comment_buffer = ast_malloc(CB_INCR);
    		if (!comment_buffer)
    			return;
    		comment_buffer[0] = 0;
    		comment_buffer_size = CB_INCR;
    		lline_buffer = ast_malloc(CB_INCR);
    		if (!lline_buffer)
    			return;
    		lline_buffer[0] = 0;
    		lline_buffer_size = CB_INCR;
    	} else {
    		comment_buffer[0] = 0;
    		lline_buffer[0] = 0;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void  CB_ADD(char *str)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int rem = comment_buffer_size - strlen(comment_buffer) - 1;
    	int siz = strlen(str);
    	if (rem < siz+1) {
    		comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
    		if (!comment_buffer)
    			return;
    		comment_buffer_size += CB_INCR+siz+1;
    	}
    	strcat(comment_buffer,str);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void  CB_ADD_LEN(char *str, int len)
    {
    	int cbl = strlen(comment_buffer) + 1;
    	int rem = comment_buffer_size - cbl;
    	if (rem < len+1) {
    		comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
    		if (!comment_buffer)
    			return;
    		comment_buffer_size += CB_INCR+len+1;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	strncat(comment_buffer,str,len); /* safe */
    	comment_buffer[cbl+len-1] = 0;
    }
    
    static void  LLB_ADD(char *str)
    {
    	int rem = lline_buffer_size - strlen(lline_buffer) - 1;
    	int siz = strlen(str);
    	if (rem < siz+1) {
    		lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
    		if (!lline_buffer) 
    			return;
    		lline_buffer_size += CB_INCR + siz + 1;
    	}
    	strcat(lline_buffer,str);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void CB_RESET(void )  
    { 
    	comment_buffer[0] = 0; 
    	lline_buffer[0] = 0;
    }
    		
    /*! \brief Keep track of how many threads are currently trying to wait*() on
     *  a child process */
    static unsigned int safe_system_level = 0;
    
    static struct sigaction safe_system_prev_handler;
    
    Steve Murphy's avatar
    Steve Murphy committed
    
    /*! \brief NULL handler so we can collect the child exit status */
    
    static void _null_sig_handler(int sig)
    
    Steve Murphy's avatar
    Steve Murphy committed
    {
    
    static struct sigaction null_sig_handler = {
    	.sa_handler = _null_sig_handler,
    
    	.sa_flags = SA_RESTART,
    
    Steve Murphy's avatar
    Steve Murphy committed
    void ast_replace_sigchld(void);
    
    void ast_replace_sigchld(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	unsigned int level;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	level = safe_system_level++;
    
    	/* only replace the handler if it has not already been done */
    
    	if (level == 0) {
    		sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    void ast_unreplace_sigchld(void);
    
    Steve Murphy's avatar
    Steve Murphy committed
    void ast_unreplace_sigchld(void)
    {
    	unsigned int level;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	level = --safe_system_level;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* only restore the handler if we are the last one */
    
    	if (level == 0) {
    		sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    int ast_safe_system(const char *s);
    
    int ast_safe_system(const char *s)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pid_t pid;
    #ifdef HAVE_WORKING_FORK
    	int x;
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct rusage rusage;
    	int status;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
    	ast_replace_sigchld();
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef HAVE_WORKING_FORK
    	pid = fork();
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pid = vfork();
    #endif	
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (pid == 0) {
    #ifdef HAVE_WORKING_FORK
    		/* Close file descriptors and launch system command */
    		for (x = STDERR_FILENO + 1; x < 4096; x++)
    			close(x);
    #endif
    		execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
    		_exit(1);
    	} else if (pid > 0) {
    		for(;;) {
    			res = wait4(pid, &status, 0, &rusage);
    			if (res > -1) {
    				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
    				break;
    			} else if (errno != EINTR) 
    				break;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
    		res = -1;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	ast_unreplace_sigchld();
    #else
    	res = -1;
    #endif
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_comment *ALLOC_COMMENT(const char *buffer)
    { 
    	struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
    	strcpy(x->cmt, buffer);
    	return x;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_map {
    	struct ast_config_map *next;
    	char *name;
    	char *driver;
    	char *database;
    	char *table;
    	char stuff[0];
    } *config_maps = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_engine *config_engine_list;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define MAX_INCLUDE_LEVEL 10
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_category {
    	char name[80];
    	int ignored;			/*!< do not let user of the config see this category */
    	int include_level;	
        char *file;                /*!< the file name from whence this declaration was read */
        int lineno;
    	struct ast_comment *precomments;
    	struct ast_comment *sameline;
    	struct ast_variable *root;
    	struct ast_variable *last;
    	struct ast_category *next;
    };
    
    struct ast_config {
    	struct ast_category *root;
    	struct ast_category *last;
    	struct ast_category *current;
    	struct ast_category *last_browse;		/*!< used to cache the last category supplied via category_browse */
    	int include_level;
    	int max_include_level;
        struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_config_include {
    	char *include_location_file;     /*!< file name in which the include occurs */
    	int  include_location_lineno;    /*!< lineno where include occurred */
    	int  exec;                       /*!< set to non-zero if itsa #exec statement */
    	char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
    	char *included_file;             /*!< file name included */
    	int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
    									   we explode the instances and will include those-- so all entries will be unique */
    	int output;                      /*!< a flag to indicate if the inclusion has been output */
    	struct ast_config_include *next; /*!< ptr to next inclusion in the list */
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
    typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
    typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
    typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Configuration engine structure, used to define realtime drivers */
    struct ast_config_engine {
    	char *name;
    	config_load_func *load_func;
    	realtime_var_get *realtime_func;
    	realtime_multi_get *realtime_multi_func;
    	realtime_update *update_func;
    	struct ast_config_engine *next;
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_engine *config_engine_list;
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* taken from strings.h */
    
    Steve Murphy's avatar
    Steve Murphy committed
    static force_inline int ast_strlen_zero(const char *s)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return (!s || (*s == '\0'));
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define S_OR(a, b)	(!ast_strlen_zero(a) ? (a) : (b))
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    void ast_copy_string(char *dst, const char *src, size_t size),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (*src && size) {
    		*dst++ = *src++;
    		size--;
    	}
    	if (__builtin_expect(!size, 0))
    		dst--;
    	*dst = '\0';
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    char *ast_skip_blanks(const char *str),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (*str && *str < 33)
    		str++;
    	return (char *)str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
      \brief Trims trailing whitespace characters from a string.
      \param ast_trim_blanks function being used
      \param str the input string
      \return a pointer to the modified string
     */
    AST_INLINE_API(
    char *ast_trim_blanks(char *str),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	char *work = str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (work) {
    		work += strlen(work) - 1;
    		/* It's tempting to only want to erase after we exit this loop, 
    		   but since ast_trim_blanks *could* receive a constant string
    		   (which we presumably wouldn't have to touch), we shouldn't
    		   actually set anything unless we must, and it's easier just
    		   to set each position to \0 than to keep track of a variable
    		   for it */
    		while ((work >= str) && *work < 33)
    			*(work--) = '\0';
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
      \brief Strip leading/trailing whitespace from a string.
      \param s The string to be stripped (will be modified).
      \return The stripped string.
    
    Steve Murphy's avatar
    Steve Murphy committed
      This functions strips all leading and trailing whitespace
      characters from the input string, and returns a pointer to
      the resulting string. The string is modified in place.
    */
    AST_INLINE_API(
    char *ast_strip(char *s),
    {
    	s = ast_skip_blanks(s);
    	if (s)
    		ast_trim_blanks(s);
    	return s;
    } 
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from config.h */
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_variable {
    	char *name;
    	char *value;
    	char *file;
    	int lineno;
    	int object;		/*!< 0 for variable, 1 for object */
    	int blanklines; 	/*!< Number of blanklines following entry */
    	struct ast_comment *precomments;
    	struct ast_comment *sameline;
    	struct ast_variable *next;
    	char stuff[0];
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
    static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_config *localized_config_load_with_comments(const char *filename);
    static char *ast_category_browse(struct ast_config *config, const char *prev);
    static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
    static void ast_variables_destroy(struct ast_variable *v);
    static void ast_config_destroy(struct ast_config *cfg);
    static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
    static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
    void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *variable;
    	int name_len = strlen(name) + 1;	
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
    		variable->name = variable->stuff;
    		variable->value = variable->stuff + name_len;		
    		variable->file = variable->value + strlen(value) + 1;		
    		strcpy(variable->name,name);
    		strcpy(variable->value,value);
    		strcpy(variable->file,filename);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return variable;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* a file should be included ONCE. Otherwise, if one of the instances is changed,
           then all be changed. -- how do we know to include it? -- Handling modified 
           instances is possible, I'd have
           to create a new master for each instance. */
    	struct ast_config_include *inc;
        
    	inc = ast_include_find(conf, included_file);
    	if (inc)
    	{
    		inc->inclusion_count++;
    		snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
    		ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
    	} else
    		*real_included_file_name = 0;
    	
    	inc = ast_calloc(1,sizeof(struct ast_config_include));
    	inc->include_location_file = ast_strdup(from_file);
    	inc->include_location_lineno = from_lineno;
    	if (!ast_strlen_zero(real_included_file_name))
    		inc->included_file = ast_strdup(real_included_file_name);
    	else
    		inc->included_file = ast_strdup(included_file);
    	
    	inc->exec = is_exec;
    	if (is_exec)
    		inc->exec_file = ast_strdup(exec_file);
    	
    	/* attach this new struct to the conf struct */
    	inc->next = conf->includes;
    	conf->includes = inc;
        
    	return inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *incl;
    	struct ast_category *cat;
    	struct ast_variable *v;
        
    	int from_len = strlen(from_file);
    	int to_len = strlen(to_file);
        
    	if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
    		return;
    	
    	/* the manager code allows you to read in one config file, then
           write it back out under a different name. But, the new arrangement
    	   ties output lines to the file name. So, before you try to write
           the config file to disk, better riffle thru the data and make sure
           the file names are changed.
    	*/
    	/* file names are on categories, includes (of course), and on variables. So,
    	   traverse all this and swap names */
    	
    	for (incl = conf->includes; incl; incl=incl->next) {
    		if (strcmp(incl->include_location_file,from_file) == 0) {
    			if (from_len >= to_len)
    				strcpy(incl->include_location_file, to_file);
    			else {
    				free(incl->include_location_file);
    				incl->include_location_file = strdup(to_file);
    			}
    		}
    	}
    	for (cat = conf->root; cat; cat = cat->next) {
    		if (strcmp(cat->file,from_file) == 0) {
    			if (from_len >= to_len)
    				strcpy(cat->file, to_file);
    			else {
    				free(cat->file);
    				cat->file = strdup(to_file);
    			}
    		}
    		for (v = cat->root; v; v = v->next) {
    			if (strcmp(v->file,from_file) == 0) {
    				if (from_len >= to_len)
    					strcpy(v->file, to_file);
    				else {
    					free(v->file);
    					v->file = strdup(to_file);
    				}
    			}
    		}
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *x;
    	for (x=conf->includes;x;x=x->next)
    	{
    		if (strcmp(x->included_file,included_file) == 0)
    			return x;
    	}
    	return 0;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!variable)
    		return;
    	if (category->last)
    		category->last->next = variable;
    	else
    		category->root = variable;
    	category->last = variable;
    	while (category->last->next)
    		category->last = category->last->next;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* try exact match first, then case-insensitive match */
    	for (cat = config->root; cat; cat = cat->next) {
    		if (cat->name == category_name && (ignored || !cat->ignored))
    			return cat;
    	}
    
    	for (cat = config->root; cat; cat = cat->next) {
    		if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
    			return cat;
    	}
    
    	return NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return category_get(config, category_name, 0);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (category && config->last_browse && (config->last_browse->name == category))
    		cat = config->last_browse;
    	else
    		cat = ast_category_get(config, category);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return (cat) ? cat->root : NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *v;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (category) {
    		for (v = ast_variable_browse(config, category); v; v = v->next) {
    			if (!strcasecmp(variable, v->name))
    				return v->value;
    		}
    	} else {
    		struct ast_category *cat;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		for (cat = config->root; cat; cat = cat->next)
    			for (v = cat->root; v; v = v->next)
    				if (!strcasecmp(variable, v->name))
    					return v->value;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *variable_clone(const struct ast_variable *old)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
    
    	if (new) {
    		new->lineno = old->lineno;
    		new->object = old->object;
    		new->blanklines = old->blanklines;
    		/* TODO: clone comments? */
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return new;
    
    Steve Murphy's avatar
    Steve Murphy committed
     
    static void ast_variables_destroy(struct ast_variable *v)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *vn;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (v) {
    		vn = v;
    		v = v->next;
    		free(vn);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_includes_destroy(struct ast_config_include *incls)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *incl,*inclnext;
        
    	for (incl=incls; incl; incl = inclnext) {
    		inclnext = incl->next;
    		if (incl->include_location_file)
    			free(incl->include_location_file);
    		if (incl->exec_file)
    			free(incl->exec_file);
    		if (incl->included_file)
    			free(incl->included_file);
    		free(incl);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_config_destroy(struct ast_config *cfg)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat, *catn;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!cfg)
    		return;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	ast_includes_destroy(cfg->includes);
    	
    	cat = cfg->root;
    	while (cat) {
    		ast_variables_destroy(cat->root);
    		catn = cat;
    		cat = cat->next;
    		free(catn);
    	}
    	free(cfg);
    
    enum ast_option_flags {
    	/*! Allow \#exec in config files */
    	AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
    	/*! Do not fork() */
    	AST_OPT_FLAG_NO_FORK = (1 << 1),
    	/*! Keep quiet */
    	AST_OPT_FLAG_QUIET = (1 << 2),
    	/*! Console mode */
    	AST_OPT_FLAG_CONSOLE = (1 << 3),
    	/*! Run in realtime Linux priority */
    	AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
    	/*! Initialize keys for RSA authentication */
    	AST_OPT_FLAG_INIT_KEYS = (1 << 5),
    	/*! Remote console */
    	AST_OPT_FLAG_REMOTE = (1 << 6),
    	/*! Execute an asterisk CLI command upon startup */
    	AST_OPT_FLAG_EXEC = (1 << 7),
    	/*! Don't use termcap colors */
    	AST_OPT_FLAG_NO_COLOR = (1 << 8),
    	/*! Are we fully started yet? */
    	AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
    	/*! Trascode via signed linear */
    	AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
    	/*! Dump core on a seg fault */
    	AST_OPT_FLAG_DUMP_CORE = (1 << 12),
    	/*! Cache sound files */
    	AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
    	/*! Display timestamp in CLI verbose output */
    	AST_OPT_FLAG_TIMESTAMP = (1 << 14),
    	/*! Override config */
    	AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
    	/*! Reconnect */
    	AST_OPT_FLAG_RECONNECT = (1 << 16),
    	/*! Transmit Silence during Record() and DTMF Generation */
    	AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
    	/*! Suppress some warnings */
    	AST_OPT_FLAG_DONT_WARN = (1 << 18),
    	/*! End CDRs before the 'h' extension */
    	AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
    	/*! Use DAHDI Timing for generators if available */
    	AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
    	/*! Always fork, even if verbose or debug settings are non-zero */
    	AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
    	/*! Disable log/verbose output to remote consoles */
    	AST_OPT_FLAG_MUTE = (1 << 22),
    	/*! There is a per-file debug setting */
    	AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
    	/*! There is a per-file verbose setting */
    	AST_OPT_FLAG_VERBOSE_FILE = (1 << 24),
    	/*! Terminal colors should be adjusted for a light-colored background */
    	AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),
    	/*! Count Initiated seconds in CDR's */
    	AST_OPT_FLAG_INITIATED_SECONDS = (1 << 26),
    	/*! Force black background */
    	AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27),
    };
    
    /* options.h declares ast_options extern; I need it static? */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_CACHE_DIR_LEN 	512
    #define AST_FILENAME_MAX	80
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! These are the options that set by default when Asterisk starts */
    #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
    
    struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_opt_exec_includes		ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
    #define ast_opt_no_fork			ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
    #define ast_opt_quiet			ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
    #define ast_opt_console			ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
    #define ast_opt_high_priority		ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
    #define ast_opt_init_keys		ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
    #define ast_opt_remote			ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
    #define ast_opt_exec			ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
    #define ast_opt_no_color		ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
    #define ast_fully_booted		ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
    #define ast_opt_transcode_via_slin	ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
    #define ast_opt_priority_jumping	ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
    #define ast_opt_dump_core		ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
    #define ast_opt_cache_record_files	ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
    #define ast_opt_timestamp		ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
    #define ast_opt_override_config		ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
    #define ast_opt_reconnect		ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
    #define ast_opt_transmit_silence	ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
    #define ast_opt_dont_warn		ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
    #define ast_opt_end_cdr_before_h_exten	ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
    #define ast_opt_internal_timing		ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
    #define ast_opt_always_fork		ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
    #define ast_opt_mute			ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
    
    extern int option_verbose;
    extern int option_debug;		/*!< Debugging */
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern int option_maxcalls;		/*!< Maximum number of simultaneous channels */
    extern double option_maxload;
    extern char defaultlanguage[];
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern pid_t ast_mainpid;
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern char record_cache_dir[AST_CACHE_DIR_LEN];
    extern char debug_filename[AST_FILENAME_MAX];
    
    extern int ast_language_is_prefix;
    
    
    
    
    /* linkedlists.h */
    
    #define AST_LIST_LOCK(head)						\
    	ast_mutex_lock(&(head)->lock) 
    
    /*!
      \brief Write locks a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place an exclusive write lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_WRLOCK(head)                                         \
            ast_rwlock_wrlock(&(head)->lock)
    
    /*!
      \brief Read locks a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place a read lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_RDLOCK(head)                                         \
            ast_rwlock_rdlock(&(head)->lock)
    	
    /*!
      \brief Locks a list, without blocking if the list is locked.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place an exclusive lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_LIST_TRYLOCK(head)						\
    	ast_mutex_trylock(&(head)->lock) 
    
    /*!
      \brief Write locks a list, without blocking if the list is locked.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place an exclusive write lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_TRYWRLOCK(head)                                      \
            ast_rwlock_trywrlock(&(head)->lock)
    
    /*!
      \brief Read locks a list, without blocking if the list is locked.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place a read lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_TRYRDLOCK(head)                                      \
            ast_rwlock_tryrdlock(&(head)->lock)
    	
    /*!
      \brief Attempts to unlock a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to remove an exclusive lock from the
      list head structure pointed to by head. If the list
      was not locked by this thread, this macro has no effect.
    */
    #define AST_LIST_UNLOCK(head) 						\
    	ast_mutex_unlock(&(head)->lock)
    
    /*!
      \brief Attempts to unlock a read/write based list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to remove a read or write lock from the
      list head structure pointed to by head. If the list
      was not locked by this thread, this macro has no effect.
    */
    #define AST_RWLIST_UNLOCK(head)                                         \
            ast_rwlock_unlock(&(head)->lock)
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_LIST_HEAD(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_LIST_HEAD(name, type)					\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    }