Merge "res_pjsip_mwi.c: Fix null pointer crash"
[asterisk/asterisk.git] / utils / extconf.c
index caed904..1be739c 100644 (file)
@@ -1,4 +1,4 @@
-/*  
+/*
  * Asterisk -- An open source telephony toolkit.
  *
  * Copyright (C) 2006, Digium, Inc.
  */
 
 
-/*
- *
+/*!
+ * \file
  * A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
  * for operations outside of asterisk. A huge, awful hack.
  *
  */
 
+/*!
+ * \li \ref extconf.c uses the configuration file \ref extconfig.conf and \ref extensions.conf and \ref asterisk.conf
+ * \addtogroup configuration_file Configuration Files
+ */
+
+/*!
+ * \page extconfig.conf extconfig.conf
+ * \verbinclude extconfig.conf.sample
+ */
+
+/*!
+ * \page extensions.conf extensions.conf
+ * \verbinclude extensions.conf.sample
+ */
+
+/*** MODULEINFO
+       <support_level>extended</support_level>
+ ***/
+
+#define ASTMM_LIBC ASTMM_REDIRECT
+#include "asterisk.h"
+
+#undef DEBUG_THREADS
+
 #include "asterisk/compat.h"
+#include "asterisk/paths.h"    /* we use AST_CONFIG_DIR */
 
 #include <errno.h>
 #include <time.h>
 #include <pthread.h>
 #include <netdb.h>
 #include <sys/param.h>
+#include <signal.h>
+
+static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
+void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
 #define ASINCLUDE_GLOB 1
 #ifdef AST_INCLUDE_GLOB
-#if defined(__Darwin__) || defined(__CYGWIN__)
+
+#if !defined(GLOB_ABORTED)
 #define GLOB_ABORTED GLOB_ABEND
 #endif
+
 # include <glob.h>
 #endif
 
-static char ast_config_AST_CONFIG_DIR[PATH_MAX] = {"/etc/asterisk"};
 #define AST_API_MODULE  1 /* gimme the inline defs! */
-struct ast_channel 
+struct ast_channel
 {
        char x; /* basically empty! */
 };
@@ -65,10 +96,10 @@ struct ast_channel
 #include "asterisk/inline_api.h"
 #include "asterisk/endian.h"
 #include "asterisk/ast_expr.h"
-#include "asterisk/ael_structs.h"
-#include "asterisk/pval.h"
+#include "asterisk/extconf.h"
 
 /* logger.h */
+
 #define EVENTLOG "event_log"
 #define        QUEUELOG        "queue_log"
 
@@ -81,28 +112,16 @@ struct ast_channel
 #define VERBOSE_PREFIX_3 "    -- "
 #define VERBOSE_PREFIX_4 "       > "
 
-/* IN CONFLICT: void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
-   __attribute__ ((format (printf, 5, 6))); */
-
-static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
-
-
-void ast_backtrace(void);
+void ast_log_backtrace(void);
 
 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
-       __attribute__ ((format (printf, 5, 6)));
+       __attribute__((format(printf, 5, 6)));
 
 /* IN CONFLICT: void ast_verbose(const char *fmt, ...)
-   __attribute__ ((format (printf, 1, 2))); */
-
-int ast_register_verbose(void (*verboser)(const char *string));
-int ast_unregister_verbose(void (*verboser)(const char *string));
+   __attribute__((format(printf, 1, 2))); */
 
 void ast_console_puts(const char *string);
 
-void ast_console_puts_mutable(const char *string);
-void ast_console_toggle_mute(int fd);
-
 #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
 
 #ifdef LOG_DEBUG
@@ -147,1714 +166,1477 @@ void ast_console_toggle_mute(int fd);
 #define __LOG_DTMF  6
 #define LOG_DTMF    __LOG_DTMF, _A_
 
-/* from utils.h */
+/* lock.h */
+#define _ASTERISK_LOCK_H /* A small indication that this is horribly wrong. */
 
-static unsigned int __unsigned_int_flags_dummy;
+#ifndef        HAVE_MTX_PROFILE
+#define        __MTX_PROF(a)   return pthread_mutex_lock((a))
+#else
+int mtx_prof = -1;
 
-struct ast_flags {  /* stolen from utils.h */
-       unsigned int flags;
-};
-#define ast_test_flag(p,flag)          ({ \
-                                       typeof ((p)->flags) __p = (p)->flags; \
-                                       typeof (__unsigned_int_flags_dummy) __x = 0; \
-                                       (void) (&__p == &__x); \
-                                       ((p)->flags & (flag)); \
-                                       })
+#define        __MTX_PROF(a)   do {                    \
+       int i;                                  \
+       /* profile only non-blocking events */  \
+       ast_mark(mtx_prof, 1);                  \
+       i = pthread_mutex_trylock((a));         \
+       ast_mark(mtx_prof, 0);                  \
+       if (!i)                                 \
+               return i;                       \
+       else                                    \
+               return pthread_mutex_lock((a)); \
+       } while (0)
+#endif /* HAVE_MTX_PROFILE */
 
-#define ast_set2_flag(p,value,flag)    do { \
-                                       typeof ((p)->flags) __p = (p)->flags; \
-                                       typeof (__unsigned_int_flags_dummy) __x = 0; \
-                                       (void) (&__p == &__x); \
-                                       if (value) \
-                                               (p)->flags |= (flag); \
-                                       else \
-                                               (p)->flags &= ~(flag); \
-                                       } while (0)
+#define AST_PTHREADT_NULL (pthread_t) -1
+#define AST_PTHREADT_STOP (pthread_t) -2
 
+#if defined(SOLARIS) || defined(BSD)
+#define AST_MUTEX_INIT_W_CONSTRUCTORS
+#endif /* SOLARIS || BSD */
 
-#ifdef __AST_DEBUG_MALLOC
-static void ast_free(void *ptr) attribute_unused;
-static void ast_free(void *ptr)
-{
-       free(ptr);
-}
+/* Asterisk REQUIRES recursive (not error checking) mutexes
+   and will not run without them. */
+#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
+#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE_NP
 #else
-#define ast_free free
-#endif
-
-#ifndef __AST_DEBUG_MALLOC
-
-#define MALLOC_FAILURE_MSG \
-       ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
-/*!
- * \brief A wrapper for malloc()
- *
- * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The argument and return value are the same as malloc()
- */
-#define ast_malloc(len) \
-       _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_MUTEX_INITIALIZER
+#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE
+#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
 
-AST_INLINE_API(
-void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
-{
-       void *p;
+#ifdef DEBUG_THREADS
 
-       if (!(p = malloc(len)))
-               MALLOC_FAILURE_MSG;
+#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
 
-       return p;
-}
-)
+#ifdef THREAD_CRASH
+#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
+#else
+#define DO_THREAD_CRASH do { } while (0)
+#endif
 
-/*!
- * \brief A wrapper for calloc()
- *
- * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as calloc()
- */
-#define ast_calloc(num, len) \
-       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
 
-AST_INLINE_API(
-void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
-{
-       void *p;
+#define AST_MAX_REENTRANCY 10
 
-       if (!(p = calloc(num, len)))
-               MALLOC_FAILURE_MSG;
+struct ast_mutex_info {
+       pthread_mutex_t mutex;
+       /*! Track which thread holds this lock */
+       unsigned int track:1;
+       const char *file[AST_MAX_REENTRANCY];
+       int lineno[AST_MAX_REENTRANCY];
+       int reentrancy;
+       const char *func[AST_MAX_REENTRANCY];
+       pthread_t thread[AST_MAX_REENTRANCY];
+};
 
-       return p;
-}
-)
+typedef struct ast_mutex_info ast_mutex_t;
 
-/*!
- * \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__)
+typedef pthread_cond_t ast_cond_t;
 
-/*!
- * \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__)
+static pthread_mutex_t empty_mutex;
 
-AST_INLINE_API(
-void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
+static void __attribute__((constructor)) init_empty_mutex(void)
 {
-       void *newp;
-
-       if (!(newp = realloc(p, len)))
-               MALLOC_FAILURE_MSG;
-
-       return newp;
+       memset(&empty_mutex, 0, sizeof(empty_mutex));
 }
-)
-
-/*!
- * \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__)
 
-AST_INLINE_API(
-char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
+static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
+                                               const char *mutex_name, ast_mutex_t *t,
+                                               pthread_mutexattr_t *attr)
 {
-       char *newstr = NULL;
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       int canlog = strcmp(filename, "logger.c");
 
-       if (str) {
-               if (!(newstr = strdup(str)))
-                       MALLOC_FAILURE_MSG;
+       if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               if ((t->mutex) != (empty_mutex)) {
+                       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
+                                          filename, lineno, func, mutex_name);
+                       __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
+                                          t->file[0], t->lineno[0], t->func[0], mutex_name);
+                       DO_THREAD_CRASH;
+                       return 0;
+               }
        }
+#endif
 
-       return newstr;
-}
-)
+       t->file[0] = filename;
+       t->lineno[0] = lineno;
+       t->func[0] = func;
+       t->thread[0]  = 0;
+       t->reentrancy = 0;
 
-/*!
- * \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__)
+       return pthread_mutex_init(&t->mutex, attr);
+}
 
-AST_INLINE_API(
-char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
+static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
+                                          const char *mutex_name, ast_mutex_t *t)
 {
-       char *newstr = NULL;
+       static pthread_mutexattr_t  attr;
 
-       if (str) {
-               if (!(newstr = strndup(str, len)))
-                       MALLOC_FAILURE_MSG;
-       }
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
 
-       return newstr;
+       return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
 }
-)
-
-/*!
- * \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__)
+#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
-AST_INLINE_API(
-int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
+static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
+                                               const char *mutex_name, ast_mutex_t *t)
 {
        int res;
-       va_list ap;
+       int canlog = strcmp(filename, "logger.c");
 
-       va_start(ap, fmt);
-       if ((res = vasprintf(ret, fmt, ap)) == -1)
-               MALLOC_FAILURE_MSG;
-       va_end(ap);
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+       }
+#endif
+
+       res = pthread_mutex_trylock(&t->mutex);
+       switch (res) {
+       case 0:
+               pthread_mutex_unlock(&t->mutex);
+               break;
+       case EINVAL:
+               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
+                                 filename, lineno, func, mutex_name);
+               break;
+       case EBUSY:
+               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
+                                  filename, lineno, func, mutex_name);
+               __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
+                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               break;
+       }
+
+       if ((res = pthread_mutex_destroy(&t->mutex)))
+               __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
+                                  filename, lineno, func, strerror(res));
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+       else
+               t->mutex = PTHREAD_MUTEX_INIT_VALUE;
+#endif
+       t->file[0] = filename;
+       t->lineno[0] = lineno;
+       t->func[0] = func;
 
        return res;
 }
-)
-
-/*!
- * \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))
 
-AST_INLINE_API(
-int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
+static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
+                                           const char* mutex_name, ast_mutex_t *t)
 {
        int res;
+       int canlog = strcmp(filename, "logger.c");
 
-       if ((res = vasprintf(ret, fmt, ap)) == -1)
-               MALLOC_FAILURE_MSG;
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                filename, lineno, func, mutex_name);
+               ast_mutex_init(t);
+       }
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+
+#ifdef DETECT_DEADLOCKS
+       {
+               time_t seconds = time(NULL);
+               time_t current;
+               do {
+#ifdef HAVE_MTX_PROFILE
+                       ast_mark(mtx_prof, 1);
+#endif
+                       res = pthread_mutex_trylock(&t->mutex);
+#ifdef HAVE_MTX_PROFILE
+                       ast_mark(mtx_prof, 0);
+#endif
+                       if (res == EBUSY) {
+                               current = time(NULL);
+                               if ((current - seconds) && (!((current - seconds) % 5))) {
+                                       __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
+                                                          filename, lineno, func, (int)(current - seconds), mutex_name);
+                                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                                          t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
+                                                          t->func[t->reentrancy-1], mutex_name);
+                               }
+                               usleep(200);
+                       }
+               } while (res == EBUSY);
+       }
+#else
+#ifdef HAVE_MTX_PROFILE
+       ast_mark(mtx_prof, 1);
+       res = pthread_mutex_trylock(&t->mutex);
+       ast_mark(mtx_prof, 0);
+       if (res)
+#endif
+       res = pthread_mutex_lock(&t->mutex);
+#endif /* DETECT_DEADLOCKS */
+
+       if (!res) {
+               if (t->reentrancy < AST_MAX_REENTRANCY) {
+                       t->file[t->reentrancy] = filename;
+                       t->lineno[t->reentrancy] = lineno;
+                       t->func[t->reentrancy] = func;
+                       t->thread[t->reentrancy] = pthread_self();
+                       t->reentrancy++;
+               } else {
+                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+                                                          filename, lineno, func, mutex_name);
+               }
+       } else {
+               __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
+                                  filename, lineno, func, strerror(errno));
+               DO_THREAD_CRASH;
+       }
 
        return res;
 }
-)
 
-#else
+static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
+                                              const char* mutex_name, ast_mutex_t *t)
+{
+       int res;
+       int canlog = strcmp(filename, "logger.c");
 
-/* If astmm is in use, let it handle these.  Otherwise, it will report that
-   all allocations are coming from this header file */
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+               ast_mutex_init(t);
+       }
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-#define ast_malloc(a)          malloc(a)
-#define ast_calloc(a,b)                calloc(a,b)
-#define ast_realloc(a,b)       realloc(a,b)
-#define ast_strdup(a)          strdup(a)
-#define ast_strndup(a,b)       strndup(a,b)
-#define ast_asprintf(a,b,c)    asprintf(a,b,c)
-#define ast_vasprintf(a,b,c)   vasprintf(a,b,c)
+       if (!(res = pthread_mutex_trylock(&t->mutex))) {
+               if (t->reentrancy < AST_MAX_REENTRANCY) {
+                       t->file[t->reentrancy] = filename;
+                       t->lineno[t->reentrancy] = lineno;
+                       t->func[t->reentrancy] = func;
+                       t->thread[t->reentrancy] = pthread_self();
+                       t->reentrancy++;
+               } else {
+                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+                                          filename, lineno, func, mutex_name);
+               }
+       } else {
+               __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
+                                   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+       }
 
-#endif /* AST_DEBUG_MALLOC */
+       return res;
+}
 
-#if !defined(ast_strdupa) && defined(__GNUC__)
-/*!
-  \brief duplicate a string in memory from the stack
-  \param s The string to duplicate
+static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
+                                            const char *mutex_name, ast_mutex_t *t)
+{
+       int res;
+       int canlog = strcmp(filename, "logger.c");
 
-  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;                                                    \
-       }))
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+       }
 #endif
 
+       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                  filename, lineno, func, mutex_name);
+               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               DO_THREAD_CRASH;
+       }
 
-/* from config.c */
+       if (--t->reentrancy < 0) {
+               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+                                  filename, lineno, func, mutex_name);
+               t->reentrancy = 0;
+       }
 
-#define MAX_NESTED_COMMENTS 128
-#define COMMENT_START ";--"
-#define COMMENT_END "--;"
-#define COMMENT_META ';'
-#define COMMENT_TAG '-'
+       if (t->reentrancy < AST_MAX_REENTRANCY) {
+               t->file[t->reentrancy] = NULL;
+               t->lineno[t->reentrancy] = 0;
+               t->func[t->reentrancy] = NULL;
+               t->thread[t->reentrancy] = 0;
+       }
 
-static char *extconfig_conf = "extconfig.conf";
+       if ((res = pthread_mutex_unlock(&t->mutex))) {
+               __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
+                                  filename, lineno, func, strerror(res));
+               DO_THREAD_CRASH;
+       }
 
-/*! 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 */
+       return res;
+}
 
-static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
-static int  lline_buffer_size;
+#else /* !DEBUG_THREADS */
 
-#define CB_INCR 250
 
-struct ast_comment {
-       struct ast_comment *next;
-       char cmt[0];
-};
+typedef pthread_mutex_t ast_mutex_t;
 
-static void CB_INIT(void)
-{
-       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;
-       }
-}
+#define AST_MUTEX_INIT_VALUE   ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
 
-static void  CB_ADD(char *str)
+static inline int ast_mutex_init(ast_mutex_t *pmutex)
 {
-       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);
+       pthread_mutexattr_t attr;
+
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+
+       return pthread_mutex_init(pmutex, &attr);
 }
 
-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;
-       }
-       strncat(comment_buffer,str,len);
-       comment_buffer[cbl+len-1] = 0;
-}
+#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
 
-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);
-}
+typedef pthread_cond_t ast_cond_t;
 
-static void CB_RESET(void )  
-{ 
-       comment_buffer[0] = 0; 
-       lline_buffer[0] = 0;
+#endif /* !DEBUG_THREADS */
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
+ constructors/destructors to create/destroy mutexes.  */
+#define __AST_MUTEX_DEFINE(scope, mutex) \
+       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
+static void  __attribute__((constructor)) init_##mutex(void) \
+{ \
+       ast_mutex_init(&mutex); \
 }
-               
-/*! \brief Keep track of how many threads are currently trying to wait*() on
- *  a child process */
-static unsigned int safe_system_level = 0;
-static void *safe_system_prev_handler;
+#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
+/* By default, use static initialization of mutexes. */
+#define __AST_MUTEX_DEFINE(scope, mutex) \
+       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-/*! \brief NULL handler so we can collect the child exit status */
-static void null_sig_handler(int signal)
-{
+#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
+#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
+#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
 
-}
+#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
 
-void ast_replace_sigchld(void);
+#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
 
-void ast_replace_sigchld(void)
+#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
+
+#ifndef __linux__
+#define pthread_create __use_ast_pthread_create_instead__
+#endif
+
+typedef pthread_rwlock_t ast_rwlock_t;
+
+static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
 {
-       unsigned int level;
+       pthread_rwlockattr_t attr;
 
-       level = safe_system_level++;
+       pthread_rwlockattr_init(&attr);
 
-       /* only replace the handler if it has not already been done */
-       if (level == 0)
-               safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
+#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
+       pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
+#endif
 
+       return pthread_rwlock_init(prwlock, &attr);
 }
 
-void ast_unreplace_sigchld(void);
+static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_destroy(prwlock);
+}
 
-void ast_unreplace_sigchld(void)
+static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
 {
-       unsigned int level;
+       return pthread_rwlock_unlock(prwlock);
+}
 
-       level = --safe_system_level;
+static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_rdlock(prwlock);
+}
 
-       /* only restore the handler if we are the last one */
-       if (level == 0)
-               signal(SIGCHLD, safe_system_prev_handler);
+static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_wrlock(prwlock);
+}
+
+/* Statically declared read/write locks */
 
+#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+        scope ast_rwlock_t rwlock; \
+static void  __attribute__((constructor)) init_##rwlock(void) \
+{ \
+        ast_rwlock_init(&rwlock); \
+} \
+static void  __attribute__((destructor)) fini_##rwlock(void) \
+{ \
+        ast_rwlock_destroy(&rwlock); \
 }
+#else
+#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+        scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
+#endif
 
-int ast_safe_system(const char *s);
+#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
 
-int ast_safe_system(const char *s)
-{
-       pid_t pid;
-#ifdef HAVE_WORKING_FORK
-       int x;
+/*
+ * Initial support for atomic instructions.
+ * For platforms that have it, use the native cpu instruction to
+ * implement them. For other platforms, resort to a 'slow' version
+ * (defined in utils.c) that protects the atomic instruction with
+ * a single lock.
+ * The slow versions is always available, for testing purposes,
+ * as ast_atomic_fetchadd_int_slow()
+ */
+
+#if defined(HAVE_OSX_ATOMICS)
+#include "libkern/OSAtomic.h"
 #endif
-       int res;
-       struct rusage rusage;
-       int status;
 
-#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
-       ast_replace_sigchld();
+/*! \brief Atomically add v to *p and return * the previous value of *p.
+ * This can be used to handle reference counts, and the return value
+ * can be used to generate unique identifiers.
+ */
 
-#ifdef HAVE_WORKING_FORK
-       pid = fork();
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return __sync_fetch_and_add(p, v);
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return OSAtomicAdd32(v, (int32_t *) p);
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return OSAtomicAdd64(v, (int64_t *) p);
+#elif defined (__i386__) || defined(__x86_64__)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       __asm __volatile (
+       "       lock   xaddl   %0, %1 ;        "
+       : "+r" (v),                     /* 0 (result) */
+         "=m" (*p)                     /* 1 */
+       : "m" (*p));                    /* 2 */
+       return (v);
+})
 #else
-       pid = vfork();
-#endif 
-
-       if (pid == 0) {
-#ifdef HAVE_WORKING_FORK
-               /* Close file descriptors and launch system command */
-               for (x = STDERR_FILENO + 1; x < 4096; x++)
-                       close(x);
+static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
+{
+       int ret;
+       ret = *p;
+       *p += v;
+       return ret;
+}
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return ast_atomic_fetchadd_int_slow(p, v);
+})
 #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;
-               }
-       } else {
-               ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
-               res = -1;
-       }
 
-       ast_unreplace_sigchld();
+/*! \brief decrement *p by 1 and return true if the variable has reached 0.
+ * Useful e.g. to check if a refcount has reached 0.
+ */
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       return __sync_sub_and_fetch(p, 1) == 0;
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       return OSAtomicAdd32( -1, (int32_t *) p) == 0;
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       return OSAtomicAdd64( -1, (int64_t *) p) == 0;
 #else
-       res = -1;
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       int a = ast_atomic_fetchadd_int(p, -1);
+       return a == 1; /* true if the value is 0 now (so it was 1 previously) */
+})
 #endif
 
-       return res;
-}
+#ifdef DEBUG_CHANNEL_LOCKS
+/*! \brief Lock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+int ast_channel_lock(struct ast_channel *chan);
 
-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;
-}
+/*! \brief Unlock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function
+*/
+int ast_channel_unlock(struct ast_channel *chan);
 
-static struct ast_config_map {
-       struct ast_config_map *next;
-       char *name;
-       char *driver;
-       char *database;
-       char *table;
-       char stuff[0];
-} *config_maps = NULL;
+/*! \brief Lock AST channel (and print debugging output)
+\note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
+int ast_channel_trylock(struct ast_channel *chan);
+#endif
 
-static struct ast_config_engine *config_engine_list;
 
-#define MAX_INCLUDE_LEVEL 10
+#include "asterisk/hashtab.h"
+#include "asterisk/ael_structs.h"
+#include "asterisk/pval.h"
 
+/* from utils.h */
 
-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;
-};
+#define ast_free free
+#define ast_free_ptr free
 
-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 */
-};
-
-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 */
+struct ast_flags {  /* stolen from utils.h */
+       unsigned int flags;
 };
+#define ast_test_flag(p,flag)          ({ \
+                                       typeof ((p)->flags) __p = (p)->flags; \
+                                       unsigned int __x = 0; \
+                                       (void) (&__p == &__x); \
+                                       ((p)->flags & (flag)); \
+                                       })
 
-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);
+#define ast_set2_flag(p,value,flag)    do { \
+                                       typeof ((p)->flags) __p = (p)->flags; \
+                                       unsigned int __x = 0; \
+                                       (void) (&__p == &__x); \
+                                       if (value) \
+                                               (p)->flags |= (flag); \
+                                       else \
+                                               (p)->flags &= ~(flag); \
+                                       } while (0)
 
-/*! \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;
-};
 
-static struct ast_config_engine *config_engine_list;
 
-/* taken from strings.h */
+#define MALLOC_FAILURE_MSG \
+       ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
 
-static force_inline int ast_strlen_zero(const char *s)
+/*!
+ * \brief A wrapper for malloc()
+ *
+ * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The argument and return value are the same as malloc()
+ */
+#define ast_malloc(len) \
+       __ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc __ast_malloc(size_t len, const char *file, int lineno, const char *func),
 {
-       return (!s || (*s == '\0'));
+       void *p;
+
+       if (!(p = malloc(len)))
+               MALLOC_FAILURE_MSG;
+
+       return p;
 }
+)
 
-#define S_OR(a, b)     (!ast_strlen_zero(a) ? (a) : (b))
+/*!
+ * \brief A wrapper for calloc()
+ *
+ * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as calloc()
+ */
+#define ast_calloc(num, len) \
+       __ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
 AST_INLINE_API(
-void ast_copy_string(char *dst, const char *src, size_t size),
+void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
 {
-       while (*src && size) {
-               *dst++ = *src++;
-               size--;
-       }
-       if (__builtin_expect(!size, 0))
-               dst--;
-       *dst = '\0';
+       void *p;
+
+       if (!(p = calloc(num, len)))
+               MALLOC_FAILURE_MSG;
+
+       return p;
 }
 )
 
+/*!
+ * \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__)
+
+/*!
+ * \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__)
+
 AST_INLINE_API(
-char *ast_skip_blanks(const char *str),
+void * attribute_malloc __ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
 {
-       while (*str && *str < 33)
-               str++;
-       return (char *)str;
+       void *newp;
+
+       if (!(newp = realloc(p, len)))
+               MALLOC_FAILURE_MSG;
+
+       return newp;
 }
 )
 
 /*!
-  \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
+ * \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__)
+
 AST_INLINE_API(
-char *ast_trim_blanks(char *str),
+char * attribute_malloc __ast_strdup(const char *str, const char *file, int lineno, const char *func),
 {
-       char *work = str;
+       char *newstr = NULL;
 
-       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';
+       if (str) {
+               if (!(newstr = strdup(str)))
+                       MALLOC_FAILURE_MSG;
        }
-       return str;
+
+       return newstr;
 }
 )
 
 /*!
-  \brief Strip leading/trailing whitespace from a string.
-  \param s The string to be stripped (will be modified).
-  \return The stripped string.
+ * \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__)
 
-  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),
+char * attribute_malloc __ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
 {
-       s = ast_skip_blanks(s);
-       if (s)
-               ast_trim_blanks(s);
-       return s;
-} 
-)
-
-
-/* from config.h */
-
-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];
-};
+       char *newstr = NULL;
 
-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);
+       if (str) {
+               if (!(newstr = strndup(str, len)))
+                       MALLOC_FAILURE_MSG;
+       }
 
-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);
+       return newstr;
+}
+)
 
-static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
+/*!
+ * \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(__FILE__, __LINE__, __PRETTY_FUNCTION__, (ret), (fmt), __VA_ARGS__)
 
-static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
+AST_INLINE_API(
+__attribute__((format(printf, 5, 6)))
+int __ast_asprintf(const char *file, int lineno, const char *func, char **ret, const char *fmt, ...),
 {
-       struct ast_variable *variable;
-       int name_len = strlen(name) + 1;        
+       int res;
+       va_list ap;
 
-       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);
-       }
+       va_start(ap, fmt);
+       if ((res = vasprintf(ret, fmt, ap)) == -1)
+               MALLOC_FAILURE_MSG;
+       va_end(ap);
 
-       return variable;
+       return res;
 }
+)
 
-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)
-{
-       /* 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;
-}
-
-void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
-{
-       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);
-                               }
-                       }
-               }
-       }
-}
-
-static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
-{
-       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;
-}
-
-
-static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
-
-static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
-{
-       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;
-}
-
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
-
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
-{
-       struct ast_category *cat;
-
-       /* 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;
-}
-
-static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
-{
-       return category_get(config, category_name, 0);
-}
-
-static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
-{
-       struct ast_category *cat = NULL;
-
-       if (category && config->last_browse && (config->last_browse->name == category))
-               cat = config->last_browse;
-       else
-               cat = ast_category_get(config, category);
-
-       return (cat) ? cat->root : NULL;
-}
-
-static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
-{
-       struct ast_variable *v;
-
-       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;
-
-               for (cat = config->root; cat; cat = cat->next)
-                       for (v = cat->root; v; v = v->next)
-                               if (!strcasecmp(variable, v->name))
-                                       return v->value;
-       }
-
-       return NULL;
-}
-
-static struct ast_variable *variable_clone(const struct ast_variable *old)
-{
-       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? */
-       }
-
-       return new;
-}
-static void ast_variables_destroy(struct ast_variable *v)
-{
-       struct ast_variable *vn;
-
-       while (v) {
-               vn = v;
-               v = v->next;
-               free(vn);
-       }
-}
-
-static void ast_includes_destroy(struct ast_config_include *incls)
-{
-       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);
-       }
-}
-
-static void ast_config_destroy(struct ast_config *cfg)
-{
-       struct ast_category *cat, *catn;
-
-       if (!cfg)
-               return;
-
-       ast_includes_destroy(cfg->includes);
-       
-       cat = cfg->root;
-       while (cat) {
-               ast_variables_destroy(cat->root);
-               catn = cat;
-               cat = cat->next;
-               free(catn);
-       }
-       free(cfg);
-}
-
-
-/* options.h declars ast_options extern; I need it static? */
-
-#define AST_CACHE_DIR_LEN      512
-#define AST_FILENAME_MAX       80
-
-/*! \ingroup main_options */
-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),
-       /*! Enable priority jumping in applications */
-       AST_OPT_FLAG_PRIORITY_JUMPING = (1 << 11),
-       /*! 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() */
-       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 Zaptel 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)
-};
-
-/*! These are the options that set by default when Asterisk starts */
-#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
-
-#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)
-
-/*  IN CONFLICT: extern int option_verbose; */
-/*  IN CONFLICT: extern int option_debug;      */      /*!< Debugging */
-extern int option_maxcalls;            /*!< Maximum number of simultaneous channels */
-extern double option_maxload;
-extern char defaultlanguage[];
-
-extern time_t ast_startuptime;
-extern time_t ast_lastreloadtime;
-extern pid_t ast_mainpid;
-
-extern char record_cache_dir[AST_CACHE_DIR_LEN];
-extern char debug_filename[AST_FILENAME_MAX];
-
-extern int ast_language_is_prefix;
-
-
-
-/* lock.h */
-
-#ifndef        HAVE_MTX_PROFILE
-#define        __MTX_PROF(a)   return pthread_mutex_lock((a))
-#else
-#define        __MTX_PROF(a)   do {                    \
-       int i;                                  \
-       /* profile only non-blocking events */  \
-       ast_mark(mtx_prof, 1);                  \
-       i = pthread_mutex_trylock((a));         \
-       ast_mark(mtx_prof, 0);                  \
-       if (!i)                                 \
-               return i;                       \
-       else                                    \
-               return pthread_mutex_lock((a)); \
-       } while (0)
-#endif /* HAVE_MTX_PROFILE */
-
-#define AST_PTHREADT_NULL (pthread_t) -1
-#define AST_PTHREADT_STOP (pthread_t) -2
-
-#if defined(SOLARIS) || defined(BSD)
-#define AST_MUTEX_INIT_W_CONSTRUCTORS
-#endif /* SOLARIS || BSD */
-
-/* Asterisk REQUIRES recursive (not error checking) mutexes
-   and will not run without them. */
-#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
-#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE_NP
-#else
-#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_MUTEX_INITIALIZER
-#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE
-#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
+/*!
+ * \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), (fmt), (ap), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-#ifdef DEBUG_THREADS
+AST_INLINE_API(
+__attribute__((format(printf, 2, 0)))
+int __ast_vasprintf(char **ret, const char *fmt, va_list ap, const char *file, int lineno, const char *func),
+{
+       int res;
 
-#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
+       if ((res = vasprintf(ret, fmt, ap)) == -1)
+               MALLOC_FAILURE_MSG;
 
-#ifdef THREAD_CRASH
-#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
-#else
-#define DO_THREAD_CRASH do { } while (0)
-#endif
+       return res;
+}
+)
 
-#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
+#if !defined(ast_strdupa) && defined(__GNUC__)
+/*!
+  \brief duplicate a string in memory from the stack
+  \param s The string to duplicate
 
-#define AST_MAX_REENTRANCY 10
+  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;                                                    \
+       }))
+#endif
 
-struct ast_mutex_info {
-       pthread_mutex_t mutex;
-       /*! Track which thread holds this lock */
-       unsigned int track:1;
-       const char *file[AST_MAX_REENTRANCY];
-       int lineno[AST_MAX_REENTRANCY];
-       int reentrancy;
-       const char *func[AST_MAX_REENTRANCY];
-       pthread_t thread[AST_MAX_REENTRANCY];
-};
 
-typedef struct ast_mutex_info ast_mutex_t;
+/* from config.c */
 
-typedef pthread_cond_t ast_cond_t;
+#define MAX_NESTED_COMMENTS 128
+#define COMMENT_START ";--"
+#define COMMENT_END "--;"
+#define COMMENT_META ';'
+#define COMMENT_TAG '-'
 
-static pthread_mutex_t empty_mutex;
+static char *extconfig_conf = "extconfig.conf";
 
-static void __attribute__((constructor)) init_empty_mutex(void)
-{
-       memset(&empty_mutex, 0, sizeof(empty_mutex));
-}
+/*! 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 */
 
-static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
-                                               const char *mutex_name, ast_mutex_t *t,
-                                               pthread_mutexattr_t *attr) 
-{
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       int canlog = strcmp(filename, "logger.c");
+static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
+static int  lline_buffer_size;
 
-       if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               if ((t->mutex) != (empty_mutex)) {
-                       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
-                                          filename, lineno, func, mutex_name);
-                       __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
-                                          t->file[0], t->lineno[0], t->func[0], mutex_name);
-                       DO_THREAD_CRASH;
-                       return 0;
-               }
-       }
-#endif
+#define CB_INCR 250
 
-       t->file[0] = filename;
-       t->lineno[0] = lineno;
-       t->func[0] = func;
-       t->thread[0]  = 0;
-       t->reentrancy = 0;
+struct ast_comment {
+       struct ast_comment *next;
+       char cmt[0];
+};
 
-       return pthread_mutex_init(&t->mutex, attr);
+static void CB_INIT(void)
+{
+       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;
+       }
 }
 
-static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
-                                          const char *mutex_name, ast_mutex_t *t)
+static void  CB_ADD(char *str)
 {
-       static pthread_mutexattr_t  attr;
-
-       pthread_mutexattr_init(&attr);
-       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
-
-       return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
+       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);
 }
-#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
-static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
-                                               const char *mutex_name, ast_mutex_t *t)
+static void  CB_ADD_LEN(char *str, int len)
 {
-       int res;
-       int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
+       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;
        }
-#endif
+       strncat(comment_buffer,str,len); /* safe */
+       comment_buffer[cbl+len-1] = 0;
+}
 
-       res = pthread_mutex_trylock(&t->mutex);
-       switch (res) {
-       case 0:
-               pthread_mutex_unlock(&t->mutex);
-               break;
-       case EINVAL:
-               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
-                                 filename, lineno, func, mutex_name);
-               break;
-       case EBUSY:
-               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               break;
+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);
+}
 
-       if ((res = pthread_mutex_destroy(&t->mutex)))
-               __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
-                                  filename, lineno, func, strerror(res));
-#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-       else
-               t->mutex = PTHREAD_MUTEX_INIT_VALUE;
-#endif
-       t->file[0] = filename;
-       t->lineno[0] = lineno;
-       t->func[0] = func;
-
-       return res;
+static void CB_RESET(void )
+{
+       comment_buffer[0] = 0;
+       lline_buffer[0] = 0;
 }
 
-static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
-                                           const char* mutex_name, ast_mutex_t *t)
+/*! \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;
+
+/*! \brief NULL handler so we can collect the child exit status */
+static void _null_sig_handler(int sig)
 {
-       int res;
-       int canlog = strcmp(filename, "logger.c");
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                filename, lineno, func, mutex_name);
-               ast_mutex_init(t);
-       }
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+}
 
-#ifdef DETECT_DEADLOCKS
-       {
-               time_t seconds = time(NULL);
-               time_t current;
-               do {
-#ifdef HAVE_MTX_PROFILE
-                       ast_mark(mtx_prof, 1);
-#endif
-                       res = pthread_mutex_trylock(&t->mutex);
-#ifdef HAVE_MTX_PROFILE
-                       ast_mark(mtx_prof, 0);
-#endif
-                       if (res == EBUSY) {
-                               current = time(NULL);
-                               if ((current - seconds) && (!((current - seconds) % 5))) {
-                                       __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
-                                                          filename, lineno, func, (int)(current - seconds), mutex_name);
-                                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                                          t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
-                                                          t->func[t->reentrancy-1], mutex_name);
-                               }
-                               usleep(200);
-                       }
-               } while (res == EBUSY);
-       }
-#else
-#ifdef HAVE_MTX_PROFILE
-       ast_mark(mtx_prof, 1);
-       res = pthread_mutex_trylock(&t->mutex);
-       ast_mark(mtx_prof, 0);
-       if (res)
-#endif
-       res = pthread_mutex_lock(&t->mutex);
-#endif /* DETECT_DEADLOCKS */
+static struct sigaction null_sig_handler = {
+       .sa_handler = _null_sig_handler,
+       .sa_flags = SA_RESTART,
+};
 
-       if (!res) {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
-       } else {
-               __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
-                                  filename, lineno, func, strerror(errno));
-               DO_THREAD_CRASH;
+void ast_replace_sigchld(void);
+
+void ast_replace_sigchld(void)
+{
+       unsigned int level;
+
+       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);
        }
+}
 
-       return res;
+void ast_unreplace_sigchld(void);
+
+void ast_unreplace_sigchld(void)
+{
+       unsigned int level;
+
+       level = --safe_system_level;
+
+       /* only restore the handler if we are the last one */
+       if (level == 0) {
+               sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
+       }
 }
 
-static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
-                                              const char* mutex_name, ast_mutex_t *t)
+int ast_safe_system(const char *s);
+
+int ast_safe_system(const char *s)
 {
+       pid_t pid;
+#ifdef HAVE_WORKING_FORK
+       int x;
+#endif
        int res;
-       int canlog = strcmp(filename, "logger.c");
+       int status;
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-               ast_mutex_init(t);
-       }
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
+       ast_replace_sigchld();
 
-       if (!(res = pthread_mutex_trylock(&t->mutex))) {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                          filename, lineno, func, mutex_name);
+#ifdef HAVE_WORKING_FORK
+       pid = fork();
+#else
+       pid = vfork();
+#endif
+
+       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 = waitpid(pid, &status, 0);
+                       if (res > -1) {
+                               res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+                               break;
+                       } else if (errno != EINTR)
+                               break;
                }
        } else {
-               __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
-                                   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
+               res = -1;
        }
 
+       ast_unreplace_sigchld();
+#else
+       res = -1;
+#endif
+
        return res;
 }
 
-static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
-                                            const char *mutex_name, ast_mutex_t *t)
+static struct ast_comment *ALLOC_COMMENT(const char *buffer)
 {
-       int res;
-       int canlog = strcmp(filename, "logger.c");
+       struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
+       strcpy(x->cmt, buffer);
+       return x;
+}
 
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
+static struct ast_config_map {
+       struct ast_config_map *next;
+       char *name;
+       char *driver;
+       char *database;
+       char *table;
+       char stuff[0];
+} *config_maps = NULL;
 
-       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               DO_THREAD_CRASH;
-       }
+static struct ast_config_engine *config_engine_list;
 
-       if (--t->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               t->reentrancy = 0;
-       }
+#define MAX_INCLUDE_LEVEL 10
 
-       if (t->reentrancy < AST_MAX_REENTRANCY) {
-               t->file[t->reentrancy] = NULL;
-               t->lineno[t->reentrancy] = 0;
-               t->func[t->reentrancy] = NULL;
-               t->thread[t->reentrancy] = 0;
-       }
 
-       if ((res = pthread_mutex_unlock(&t->mutex))) {
-               __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
-                                  filename, lineno, func, strerror(res));
-               DO_THREAD_CRASH;
-       }
+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;
+};
 
-       return res;
-}
+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 */
+};
 
-static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
-                                 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
-       return pthread_cond_init(cond, cond_attr);
-}
+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 */
+};
+
+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);
+
+/*! \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;
+};
 
-static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
-                                   const char *cond_name, ast_cond_t *cond)
+static struct ast_config_engine *config_engine_list;
+
+/* taken from strings.h */
+
+static force_inline int ast_strlen_zero(const char *s)
 {
-       return pthread_cond_signal(cond);
+       return (!s || (*s == '\0'));
 }
 
-static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
-                                      const char *cond_name, ast_cond_t *cond)
+#define S_OR(a, b)     (!ast_strlen_zero(a) ? (a) : (b))
+
+AST_INLINE_API(
+void ast_copy_string(char *dst, const char *src, size_t size),
 {
-       return pthread_cond_broadcast(cond);
+       while (*src && size) {
+               *dst++ = *src++;
+               size--;
+       }
+       if (__builtin_expect(!size, 0))
+               dst--;
+       *dst = '\0';
 }
+)
 
-static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
-                                    const char *cond_name, ast_cond_t *cond)
+AST_INLINE_API(
+char *ast_skip_blanks(const char *str),
 {
-       return pthread_cond_destroy(cond);
+       while (*str && *str < 33)
+               str++;
+       return (char *)str;
 }
+)
 
-static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
-                                 const char *cond_name, const char *mutex_name,
-                                 ast_cond_t *cond, ast_mutex_t *t)
+/*!
+  \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),
 {
-       int res;
-       int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
-
-       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               DO_THREAD_CRASH;
-       }
-
-       if (--t->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               t->reentrancy = 0;
-       }
-
-       if (t->reentrancy < AST_MAX_REENTRANCY) {
-               t->file[t->reentrancy] = NULL;
-               t->lineno[t->reentrancy] = 0;
-               t->func[t->reentrancy] = NULL;
-               t->thread[t->reentrancy] = 0;
-       }
+       char *work = str;
 
-       if ((res = pthread_cond_wait(cond, &t->mutex))) {
-               __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
-                                  filename, lineno, func, strerror(res));
-               DO_THREAD_CRASH;
-       } else {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
+       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';
        }
-
-       return res;
+       return str;
 }
+)
 
-static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
-                                      const char *cond_name, const char *mutex_name, ast_cond_t *cond,
-                                      ast_mutex_t *t, const struct timespec *abstime)
-{
-       int res;
-       int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
+/*!
+  \brief Strip leading/trailing whitespace from a string.
+  \param s The string to be stripped (will be modified).
+  \return The stripped string.
 
-       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               DO_THREAD_CRASH;
-       }
+  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;
+}
+)
 
-       if (--t->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               t->reentrancy = 0;
-       }
 
-       if (t->reentrancy < AST_MAX_REENTRANCY) {
-               t->file[t->reentrancy] = NULL;
-               t->lineno[t->reentrancy] = 0;
-               t->func[t->reentrancy] = NULL;
-               t->thread[t->reentrancy] = 0;
-       }
+/* from config.h */
 
-       if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
-               __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
-                                  filename, lineno, func, strerror(res));
-               DO_THREAD_CRASH;
-       } else {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
-       }
+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];
+};
 
-       return res;
-}
+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);
 
-#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
-#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
-#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
+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);
 
-#else /* !DEBUG_THREADS */
+static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
 
+static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
+{
+       struct ast_variable *variable;
+       int name_len = strlen(name) + 1;
 
-typedef pthread_mutex_t ast_mutex_t;
+       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);
+       }
 
-#define AST_MUTEX_INIT_VALUE   ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
+       return variable;
+}
 
-static inline int ast_mutex_init(ast_mutex_t *pmutex)
+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)
 {
-       pthread_mutexattr_t attr;
+       /* 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;
 
-       pthread_mutexattr_init(&attr);
-       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+       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;
 
-       return pthread_mutex_init(pmutex, &attr);
-}
+       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);
 
-#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
+       inc->exec = is_exec;
+       if (is_exec)
+               inc->exec_file = ast_strdup(exec_file);
 
-static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
-{
-       return pthread_mutex_unlock(pmutex);
-}
+       /* attach this new struct to the conf struct */
+       inc->next = conf->includes;
+       conf->includes = inc;
 
-static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
-{
-       return pthread_mutex_destroy(pmutex);
+       return inc;
 }
 
-static inline int ast_mutex_lock(ast_mutex_t *pmutex)
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
 {
-       __MTX_PROF(pmutex);
-}
+       struct ast_config_include *incl;
+       struct ast_category *cat;
+       struct ast_variable *v;
 
-static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
-{
-       return pthread_mutex_trylock(pmutex);
-}
+       int from_len = strlen(from_file);
+       int to_len = strlen(to_file);
 
-typedef pthread_cond_t ast_cond_t;
+       if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
+               return;
 
-static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
-       return pthread_cond_init(cond, cond_attr);
-}
+       /* 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 */
 
-static inline int ast_cond_signal(ast_cond_t *cond)
-{
-       return pthread_cond_signal(cond);
+       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);
+                               }
+                       }
+               }
+       }
 }
 
-static inline int ast_cond_broadcast(ast_cond_t *cond)
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
 {
-       return pthread_cond_broadcast(cond);
+       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;
 }
 
-static inline int ast_cond_destroy(ast_cond_t *cond)
-{
-       return pthread_cond_destroy(cond);
-}
 
-static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
-{
-       return pthread_cond_wait(cond, t);
-}
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
 
-static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
 {
-       return pthread_cond_timedwait(cond, t, abstime);
+       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;
 }
 
-#endif /* !DEBUG_THREADS */
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
- constructors/destructors to create/destroy mutexes.  */
-#define __AST_MUTEX_DEFINE(scope, mutex) \
-       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
-static void  __attribute__ ((constructor)) init_##mutex(void) \
-{ \
-       ast_mutex_init(&mutex); \
-} \
-static void  __attribute__ ((destructor)) fini_##mutex(void) \
-{ \
-       ast_mutex_destroy(&mutex); \
-}
-#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
-/* By default, use static initialization of mutexes. */ 
-#define __AST_MUTEX_DEFINE(scope, mutex) \
-       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
+{
+       struct ast_category *cat;
 
-#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
-#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
-#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
-#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
-#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
-#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
-#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
-#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
-#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
-#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
-#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
-#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
-#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
+       /* 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;
+       }
 
-#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
+       for (cat = config->root; cat; cat = cat->next) {
+               if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
+                       return cat;
+       }
+
+       return NULL;
+}
 
-#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
+static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+{
+       return category_get(config, category_name, 0);
+}
 
-#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
+static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
+{
+       struct ast_category *cat = NULL;
 
-#ifndef __linux__
-#define pthread_create __use_ast_pthread_create_instead__
-#endif
+       if (category && config->last_browse && (config->last_browse->name == category))
+               cat = config->last_browse;
+       else
+               cat = ast_category_get(config, category);
 
-typedef pthread_rwlock_t ast_rwlock_t;
+       return (cat) ? cat->root : NULL;
+}
 
-static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
 {
-       pthread_rwlockattr_t attr;
+       struct ast_variable *v;
 
-       pthread_rwlockattr_init(&attr);
+       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;
 
-#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
-       pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
-#endif
+               for (cat = config->root; cat; cat = cat->next)
+                       for (v = cat->root; v; v = v->next)
+                               if (!strcasecmp(variable, v->name))
+                                       return v->value;
+       }
 
-       return pthread_rwlock_init(prwlock, &attr);
+       return NULL;
 }
 
-static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
+static struct ast_variable *variable_clone(const struct ast_variable *old)
 {
-       return pthread_rwlock_destroy(prwlock);
-}
+       struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
 
-static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
-{
-       return pthread_rwlock_unlock(prwlock);
-}
+       if (new) {
+               new->lineno = old->lineno;
+               new->object = old->object;
+               new->blanklines = old->blanklines;
+               /* TODO: clone comments? */
+       }
 
-static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
-{
-       return pthread_rwlock_rdlock(prwlock);
+       return new;
 }
 
-static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
+static void ast_variables_destroy(struct ast_variable *v)
 {
-       return pthread_rwlock_tryrdlock(prwlock);
+       struct ast_variable *vn;
+
+       while (v) {
+               vn = v;
+               v = v->next;
+               free(vn);
+       }
 }
 
-static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
+static void ast_includes_destroy(struct ast_config_include *incls)
 {
-       return pthread_rwlock_wrlock(prwlock);
+       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);
+       }
 }
 
-static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
+static void ast_config_destroy(struct ast_config *cfg)
 {
-       return pthread_rwlock_trywrlock(prwlock);
-}
+       struct ast_category *cat, *catn;
 
-/* Statically declared read/write locks */
+       if (!cfg)
+               return;
 
-#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
-        scope ast_rwlock_t rwlock; \
-static void  __attribute__ ((constructor)) init_##rwlock(void) \
-{ \
-        ast_rwlock_init(&rwlock); \
-} \
-static void  __attribute__ ((destructor)) fini_##rwlock(void) \
-{ \
-        ast_rwlock_destroy(&rwlock); \
-}
-#else
-#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
-        scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
-#endif
+       ast_includes_destroy(cfg->includes);
 
-#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
+       cat = cfg->root;
+       while (cat) {
+               ast_variables_destroy(cat->root);
+               catn = cat;
+               cat = cat->next;
+               free(catn);
+       }
+       free(cfg);
+}
 
-/*
- * Initial support for atomic instructions.
- * For platforms that have it, use the native cpu instruction to
- * implement them. For other platforms, resort to a 'slow' version
- * (defined in utils.c) that protects the atomic instruction with
- * a single lock.
- * The slow versions is always available, for testing purposes,
- * as ast_atomic_fetchadd_int_slow()
- */
+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),
+       /*! 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),
+};
 
-int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
+/* options.h declares ast_options extern; I need it static? */
+#define AST_CACHE_DIR_LEN      512
+#define AST_FILENAME_MAX       80
 
-#if defined(HAVE_OSX_ATOMICS)
-#include "libkern/OSAtomic.h"
-#endif
+/*! These are the options that set by default when Asterisk starts */
+#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
 
-/*! \brief Atomically add v to *p and return * the previous value of *p.
- * This can be used to handle reference counts, and the return value
- * can be used to generate unique identifiers.
- */
+struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
 
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return __sync_fetch_and_add(p, v);
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return OSAtomicAdd32(v, (int32_t *) p);
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return OSAtomicAdd64(v, (int64_t *) p);
-#elif defined (__i386__) || defined(__x86_64__)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       __asm __volatile (
-       "       lock   xaddl   %0, %1 ;        "
-       : "+r" (v),                     /* 0 (result) */   
-         "=m" (*p)                     /* 1 */
-       : "m" (*p));                    /* 2 */
-       return (v);
-})
-#else   /* low performance version in utils.c */
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return ast_atomic_fetchadd_int_slow(p, v);
-})
-#endif
+#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_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)
 
-/*! \brief decrement *p by 1 and return true if the variable has reached 0.
- * Useful e.g. to check if a refcount has reached 0.
- */
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       return __sync_sub_and_fetch(p, 1) == 0;
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       return OSAtomicAdd32( -1, (int32_t *) p) == 0;
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       return OSAtomicAdd64( -1, (int64_t *) p) == 0;
-#else
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       int a = ast_atomic_fetchadd_int(p, -1);
-       return a == 1; /* true if the value is 0 now (so it was 1 previously) */
-})
-#endif
+extern int option_verbose;
+extern int option_debug;               /*!< Debugging */
+extern int ast_option_maxcalls;                /*!< Maximum number of simultaneous channels */
+extern double ast_option_maxload;
+extern char ast_defaultlanguage[];
 
-#ifndef DEBUG_CHANNEL_LOCKS
-/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
-       in the Makefile, print relevant output for debugging */
-#define ast_channel_lock(x)            ast_mutex_lock(&x->lock)
-/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
-       in the Makefile, print relevant output for debugging */
-#define ast_channel_unlock(x)          ast_mutex_unlock(&x->lock)
-/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
-       in the Makefile, print relevant output for debugging */
-#define ast_channel_trylock(x)         ast_mutex_trylock(&x->lock)
-#else
+extern pid_t ast_mainpid;
 
-/*! \brief Lock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
-int ast_channel_lock(struct ast_channel *chan);
+extern char record_cache_dir[AST_CACHE_DIR_LEN];
+extern char debug_filename[AST_FILENAME_MAX];
 
-/*! \brief Unlock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function
-*/
-int ast_channel_unlock(struct ast_channel *chan);
+extern int ast_language_is_prefix;
 
-/*! \brief Lock AST channel (and print debugging output)
-\note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
-int ast_channel_trylock(struct ast_channel *chan);
-#endif
 
 
 /* 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
@@ -1876,50 +1658,6 @@ int ast_channel_trylock(struct ast_channel *chan);
 */
 #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.
@@ -2059,11 +1797,11 @@ struct name {                                                           \
        struct type *last;                                              \
        ast_mutex_t lock;                                               \
 } name;                                                                        \
-static void  __attribute__ ((constructor)) init_##name(void)           \
+static void  __attribute__((constructor)) init_##name(void)            \
 {                                                                      \
         AST_LIST_HEAD_INIT(&name);                                     \
 }                                                                      \
-static void  __attribute__ ((destructor)) fini_##name(void)            \
+static void  __attribute__((destructor)) fini_##name(void)             \
 {                                                                      \
         AST_LIST_HEAD_DESTROY(&name);                                  \
 }                                                                      \
@@ -2101,11 +1839,11 @@ struct name {                                                           \
         struct type *last;                                              \
         ast_rwlock_t lock;                                              \
 } name;                                                                 \
-static void  __attribute__ ((constructor)) init_##name(void)            \
+static void  __attribute__((constructor)) init_##name(void)            \
 {                                                                       \
         AST_RWLIST_HEAD_INIT(&name);                                    \
 }                                                                       \
-static void  __attribute__ ((destructor)) fini_##name(void)             \
+static void  __attribute__((destructor)) fini_##name(void)             \
 {                                                                       \
         AST_RWLIST_HEAD_DESTROY(&name);                                 \
 }                                                                       \
@@ -2194,7 +1932,7 @@ struct {                                                          \
 }
 
 #define AST_RWLIST_ENTRY AST_LIST_ENTRY
+
 /*!
   \brief Returns the first entry contained in a list.
   \param head This is a pointer to the list head structure
@@ -2399,20 +2137,6 @@ struct {                                                         \
 }
 
 /*!
-  \brief Destroys a list head structure.
-  \param head This is a pointer to the list head structure
-
-  This macro destroys a list head structure by setting the head
-  entry to \a NULL (empty list) and destroying the embedded lock.
-  It does not free the structure from memory.
-*/
-#define AST_LIST_HEAD_DESTROY(head) {                                  \
-       (head)->first = NULL;                                           \
-       (head)->last = NULL;                                            \
-       ast_mutex_destroy(&(head)->lock);                               \
-}
-
-/*!
   \brief Destroys an rwlist head structure.
   \param head This is a pointer to the list head structure
 
@@ -2620,7 +2344,7 @@ struct ast_switch {
        AST_LIST_ENTRY(ast_switch) list;
        const char *name;                       /*!< Name of the switch */
        const char *description;                /*!< Description of the switch */
-       
+
        ast_switch_f *exists;
        ast_switch_f *canmatch;
        ast_switch_f *exec;
@@ -2628,15 +2352,13 @@ struct ast_switch {
 };
 
 
-static char *config = "extensions.conf";
-static char *registrar = "conf2ael";
+static char *config_filename = "extensions.conf";
+static char *global_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;
-/*! Go no deeper than this through includes (not counting loops) */
-#define AST_PBX_MAX_STACK      128
 static void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
 
 
@@ -2695,16 +2417,8 @@ static const char *ast_var_name(const struct ast_var_t *var)
        return name;
 }
 
-
-/* stolen from asterisk.c */
-
-static struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
-static int option_verbose = 0;                         /*!< Verbosity level */
-static int option_debug = 0;                           /*!< Debug level */
-
-
 /* experiment 1: see if it's easier just to use existing config code
- *               to read in the extensions.conf file. In this scenario, 
+ *               to read in the extensions.conf file. In this scenario,
                  I have to rip/copy code from other modules, because they
                  are staticly declared as-is. A solution would be to move
                  the ripped code to another location and make them available
@@ -2716,7 +2430,7 @@ static void ast_log(int level, const char *file, int line, const char *function,
 {
        va_list vars;
        va_start(vars,fmt);
-       
+
        printf("LOG: lev:%d file:%s  line:%d func: %s  ",
                   level, file, line, function);
        vprintf(fmt, vars);
@@ -2724,11 +2438,11 @@ static void ast_log(int level, const char *file, int line, const char *function,
        va_end(vars);
 }
 
-static void ast_verbose(const char *fmt, ...)
+void __attribute__((format(printf, 1, 2))) ast_verbose(const char *fmt, ...)
 {
        va_list vars;
        va_start(vars,fmt);
-       
+
        printf("VERBOSE: ");
        vprintf(fmt, vars);
        fflush(stdout);
@@ -2779,6 +2493,63 @@ static int ast_true(const char *s)
        return 0;
 }
 
+#define ONE_MILLION    1000000
+/*
+ * put timeval in a valid range. usec is 0..999999
+ * negative values are not allowed and truncated.
+ */
+static struct timeval tvfix(struct timeval a)
+{
+       if (a.tv_usec >= ONE_MILLION) {
+               ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
+                       (long)a.tv_sec, (long int) a.tv_usec);
+               a.tv_sec += a.tv_usec / ONE_MILLION;
+               a.tv_usec %= ONE_MILLION;
+       } else if (a.tv_usec < 0) {
+               ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
+                       (long)a.tv_sec, (long int) a.tv_usec);
+               a.tv_usec = 0;
+       }
+       return a;
+}
+
+struct timeval ast_tvadd(struct timeval a, struct timeval b);
+struct timeval ast_tvadd(struct timeval a, struct timeval b)
+{
+       /* consistency checks to guarantee usec in 0..999999 */
+       a = tvfix(a);
+       b = tvfix(b);
+       a.tv_sec += b.tv_sec;
+       a.tv_usec += b.tv_usec;
+       if (a.tv_usec >= ONE_MILLION) {
+               a.tv_sec++;
+               a.tv_usec -= ONE_MILLION;
+       }
+       return a;
+}
+
+struct timeval ast_tvsub(struct timeval a, struct timeval b);
+struct timeval ast_tvsub(struct timeval a, struct timeval b)
+{
+       /* consistency checks to guarantee usec in 0..999999 */
+       a = tvfix(a);
+       b = tvfix(b);
+       a.tv_sec -= b.tv_sec;
+       a.tv_usec -= b.tv_usec;
+       if (a.tv_usec < 0) {
+               a.tv_sec-- ;
+               a.tv_usec += ONE_MILLION;
+       }
+       return a;
+}
+#undef ONE_MILLION
+
+void ast_mark_lock_failed(void *lock_addr);
+void ast_mark_lock_failed(void *lock_addr)
+{
+       /* Pretend to do something. */
+}
+
 /* stolen from pbx.c */
 #define VAR_BUF_SIZE 4096
 
@@ -2820,7 +2591,8 @@ struct ast_timing {
        unsigned int monthmask;                 /*!< Mask for month */
        unsigned int daymask;                   /*!< Mask for date */
        unsigned int dowmask;                   /*!< Mask for day of week (mon-sun) */
-       unsigned int minmask[24];               /*!< Mask for minute */
+       unsigned int minmask[48];               /*!< Mask for minute */
+       char *timezone;                 /*!< NULL, or zoneinfo style timezone */
 };
 /* end of pbx.h */
 /*! \brief ast_include: include= support in extensions.conf */
@@ -2849,7 +2621,7 @@ struct ast_sw {
 struct ast_ignorepat {
        const char *registrar;
        struct ast_ignorepat *next;
-       const char pattern[0];
+       char pattern[0];
 };
 
 /*! \brief ast_context: An extension context */
@@ -2888,7 +2660,7 @@ struct ast_state_cb {
 /*! \brief Structure for dial plan hints
 
   \note Hints are pointers from an extension in the dialplan to one or
-  more devices (tech/name) 
+  more devices (tech/name)
        - See \ref AstExtState
 */
 struct ast_hint {
@@ -2909,50 +2681,14 @@ struct store_hint {
 
 AST_LIST_HEAD(store_hints, store_hint);
 
-static const struct cfextension_states {
-       int extension_state;
-       const char * const text;
-} extension_states[] = {
-       { AST_EXTENSION_NOT_INUSE,                     "Idle" },
-       { AST_EXTENSION_INUSE,                         "InUse" },
-       { AST_EXTENSION_BUSY,                          "Busy" },
-       { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
-       { AST_EXTENSION_RINGING,                       "Ringing" },
-       { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
-       { AST_EXTENSION_ONHOLD,                        "Hold" },
-       { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
-};
 #define STATUS_NO_CONTEXT      1
 #define STATUS_NO_EXTENSION    2
 #define STATUS_NO_PRIORITY     3
 #define STATUS_NO_LABEL                4
 #define STATUS_SUCCESS         5
 
-
-#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
-
-
 static 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;
@@ -2964,14 +2700,13 @@ static struct ast_var_t *ast_var_assign(const char *name, const char *value)
        ast_copy_string(var->name, name, name_len);
        var->value = var->name + name_len;
        ast_copy_string(var->value, value, value_len);
-       
+
        return var;
-}      
-       
+}
+
 static void ast_var_delete(struct ast_var_t *var)
 {
-       if (var)
-               free(var);
+       free(var);
 }
 
 
@@ -3058,16 +2793,15 @@ static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name
                }
        }
 
-       if (value) {
+       if (value && (newvariable = ast_var_assign(name, 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);
                AST_LIST_INSERT_HEAD(headp, newvariable, entries);
        }
 
 }
 
-static int pbx_builtin_setvar(struct ast_channel *chan, void *data)
+static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
 {
        char *name, *value, *mydata;
        int argc;
@@ -3102,9 +2836,9 @@ static int pbx_builtin_setvar(struct ast_channel *chan, void *data)
        return(0);
 }
 
-int localized_pbx_builtin_setvar(struct ast_channel *chan, void *data);
+int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data);
 
-int localized_pbx_builtin_setvar(struct ast_channel *chan, void *data)
+int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
 {
        return pbx_builtin_setvar(chan, data);
 }
@@ -3114,20 +2848,24 @@ int localized_pbx_builtin_setvar(struct ast_channel *chan, void *data)
  * return the index of the matching entry, starting from 1.
  * If names is not supplied, try numeric values.
  */
-
 static int lookup_name(const char *s, char *const names[], int max)
 {
        int i;
 
-       if (names) {
+       if (names && *s > '9') {
                for (i = 0; names[i]; i++) {
-                       if (!strcasecmp(s, names[i]))
-                               return i+1;
+                       if (!strcasecmp(s, names[i])) {
+                               return i;
+                       }
                }
-       } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
-               return i;
        }
-       return 0; /* error return */
+
+       /* Allow months and weekdays to be specified as numbers, as well */
+       if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
+               /* What the array offset would have been: "1" would be at offset 0 */
+               return i - 1;
+       }
+       return -1; /* error return */
 }
 
 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
@@ -3135,44 +2873,42 @@ static int lookup_name(const char *s, char *const names[], int max)
  */
 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
 {
-       int s, e; /* start and ending position */
+       int start, end; /* start and ending position */
        unsigned int mask = 0;
+       char *part;
 
        /* Check for whole range */
        if (ast_strlen_zero(src) || !strcmp(src, "*")) {
-               s = 0;
-               e = max - 1;
-       } else {
+               return (1 << max) - 1;
+       }
+
+       while ((part = strsep(&src, "&"))) {
                /* Get start and ending position */
-               char *c = strchr(src, '-');
-               if (c)
-                       *c++ = '\0';
+               char *endpart = strchr(part, '-');
+               if (endpart) {
+                       *endpart++ = '\0';
+               }
                /* Find the start */
-               s = lookup_name(src, names, max);
-               if (!s) {
-                       ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
-                       return 0;
+               if ((start = lookup_name(part, names, max)) < 0) {
+                       ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
+                       continue;
                }
-               s--;
-               if (c) { /* find end of range */
-                       e = lookup_name(c, names, max);
-                       if (!e) {
-                               ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
-                               return 0;
+               if (endpart) { /* find end of range */
+                       if ((end = lookup_name(endpart, names, max)) < 0) {
+                               ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
+                               continue;
                        }
-                       e--;
-               } else
-                       e = s;
-       }
-       /* Fill the mask. Remember that ranges are cyclic */
-       mask = 1 << e;  /* initialize with last element */
-       while (s != e) {
-               if (s >= max) {
-                       s = 0;
-                       mask |= (1 << s);
                } else {
-                       mask |= (1 << s);
-                       s++;
+                       end = start;
+               }
+               /* Fill the mask. Remember that ranges are cyclic */
+               mask |= (1 << end);   /* initialize with last element */
+               while (start != end) {
+                       if (start >= max) {
+                               start = 0;
+                       }
+                       mask |= (1 << start);
+                       start++;
                }
        }
        return mask;
@@ -3181,85 +2917,60 @@ static unsigned get_range(char *src, int max, char *const names[], const char *m
 /*! \brief store a bitmask of valid times, one bit each 2 minute */
 static void get_timerange(struct ast_timing *i, char *times)
 {
-       char *e;
+       char *endpart, *part;
        int x;
-       int s1, s2;
-       int e1, e2;
-       /*      int cth, ctm; */
+       int st_h, st_m;
+       int endh, endm;
+       int minute_start, minute_end;
 
        /* start disabling all times, fill the fields with 0's, as they may contain garbage */
        memset(i->minmask, 0, sizeof(i->minmask));
 
-       /* 2-minutes per bit, since the mask has only 32 bits :( */
+       /* 1-minute per bit */
        /* Star is all times */
        if (ast_strlen_zero(times) || !strcmp(times, "*")) {
-               for (x=0; x<24; x++)
+               /* 48, because each hour takes 2 integers; 30 bits each */
+               for (x = 0; x < 48; x++) {
                        i->minmask[x] = 0x3fffffff; /* 30 bits */
+               }
                return;
        }
        /* Otherwise expect a range */
-       e = strchr(times, '-');
-       if (!e) {
-               ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
-               return;
-       }
-       *e++ = '\0';
-       /* XXX why skip non digits ? */
-       while (*e && !isdigit(*e))
-               e++;
-       if (!*e) {
-               ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
-               return;
-       }
-       if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
-               ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
-               return;
-       }
-       if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
-               ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
-               return;
-       }
-       /* XXX this needs to be optimized */
-#if 1
-       s1 = s1 * 30 + s2/2;
-       if ((s1 < 0) || (s1 >= 24*30)) {
-               ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
-               return;
-       }
-       e1 = e1 * 30 + e2/2;
-       if ((e1 < 0) || (e1 >= 24*30)) {
-               ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
-               return;
-       }
-       /* Go through the time and enable each appropriate bit */
-       for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
-               i->minmask[x/30] |= (1 << (x % 30));
-       }
-       /* Do the last one */
-       i->minmask[x/30] |= (1 << (x % 30));
-#else
-       for (cth=0; cth<24; cth++) {
-               /* Initialize masks to blank */
-               i->minmask[cth] = 0;
-               for (ctm=0; ctm<30; ctm++) {
-                       if (
-                       /* First hour with more than one hour */
-                             (((cth == s1) && (ctm >= s2)) &&
-                              ((cth < e1)))
-                       /* Only one hour */
-                       ||    (((cth == s1) && (ctm >= s2)) &&
-                              ((cth == e1) && (ctm <= e2)))
-                       /* In between first and last hours (more than 2 hours) */
-                       ||    ((cth > s1) &&
-                              (cth < e1))
-                       /* Last hour with more than one hour */
-                       ||    ((cth > s1) &&
-                              ((cth == e1) && (ctm <= e2)))
-                       )
-                               i->minmask[cth] |= (1 << (ctm / 2));
+       while ((part = strsep(&times, "&"))) {
+               if (!(endpart = strchr(part, '-'))) {
+                       if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
+                               ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
+                               continue;
+                       }
+                       i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
+                       continue;
+               }
+               *endpart++ = '\0';
+               /* why skip non digits? Mostly to skip spaces */
+               while (*endpart && !isdigit(*endpart)) {
+                       endpart++;
+               }
+               if (!*endpart) {
+                       ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
+                       continue;
+               }
+               if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
+                       ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
+                       continue;
                }
+               if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
+                       ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
+                       continue;
+               }
+               minute_start = st_h * 60 + st_m;
+               minute_end = endh * 60 + endm;
+               /* Go through the time and enable each appropriate bit */
+               for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
+                       i->minmask[x / 30] |= (1 << (x % 30));
+               }
+               /* Do the last one */
+               i->minmask[x / 30] |= (1 << (x % 30));
        }
-#endif
        /* All done */
        return;
 }
@@ -3269,7 +2980,7 @@ static void null_datad(void *foo)
 }
 
 /*! \brief Find realtime engine for realtime family */
-static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz) 
+static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
 {
        struct ast_config_engine *eng, *ret = NULL;
        struct ast_config_map *map;
@@ -3292,12 +3003,12 @@ static struct ast_config_engine *find_engine(const char *family, char *database,
                                ret = eng;
                }
        }
-       
-       
+
+
        /* if we found a mapping, but the engine is not available, then issue a warning */
        if (map && !ret)
                ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
-       
+
        return ret;
 }
 
@@ -3372,7 +3083,7 @@ static void ast_category_destroy(struct ast_category *cat)
        ast_variables_destroy(cat->root);
        if (cat->file)
                free(cat->file);
-       
+
        free(cat);
 }
 
@@ -3389,7 +3100,7 @@ static struct ast_config *ast_config_internal_load(const char *filename, struct
        char db[256];
        char table[256];
        struct ast_config_engine *loader = &text_file_engine;
-       struct ast_config *result; 
+       struct ast_config *result;
 
        if (cfg->include_level == cfg->max_include_level) {
                ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
@@ -3417,7 +3128,7 @@ static struct ast_config *ast_config_internal_load(const char *filename, struct
        }
 
        result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
-       /* silence is golden 
+       /* silence is golden
           ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
        */
 
@@ -3456,7 +3167,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                        return -1;
                }
                (*cat)->lineno = lineno;
-        
+
                /* add comments */
                if (withcomments && comment_buffer && comment_buffer[0] ) {
                        newcat->precomments = ALLOC_COMMENT(comment_buffer);
@@ -3466,7 +3177,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                }
                if( withcomments )
                        CB_RESET();
-               
+
                /* If there are options or categories to inherit from, process them now */
                if (c) {
                        if (!(cur = strchr(c, ')'))) {
@@ -3493,7 +3204,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                        }
                                } else {
                                        struct ast_category *base;
-                               
+
                                        base = category_get(cfg, cur, 1);
                                        if (!base) {
                                                ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
@@ -3516,7 +3227,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                        c = ast_skip_blanks(c + 1);
                        if (!*c)
                                c = NULL;
-               } else 
+               } else
                        c = NULL;
                do_include = !strcasecmp(cur, "include");
                if(!do_include)
@@ -3531,8 +3242,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                        if (c) {
                                char *cur2;
                                char real_inclusion_name[256];
-                               struct ast_config_include *inclu;
-                
+
                                /* Strip off leading and trailing "'s and <>'s */
                                while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
                                /* Get rid of leading mess */
@@ -3547,7 +3257,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                }
                                /* #exec </path/to/executable>
                                   We create a tmp file, then we #include it, then we delete it. */
-                               if (do_exec) { 
+                               if (do_exec) {
                                        snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
                                        snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
                                        ast_safe_system(cmd);
@@ -3556,26 +3266,26 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                        exec_file[0] = '\0';
                                /* A #include */
                                /* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
-                               
+
                                /* record this inclusion */
-                               inclu = ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
-                               
+                               ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
+
                                do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
                                if(!ast_strlen_zero(exec_file))
                                        unlink(exec_file);
                                if(!do_include)
                                        return 0;
                                /* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
-                               
+
                        } else {
-                               ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n", 
+                               ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
                                                do_exec ? "exec" : "include",
                                                do_exec ? "/path/to/executable" : "filename",
                                                lineno,
                                                configfile);
                        }
                }
-               else 
+               else
                        ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
        } else {
                /* Just a line (variable = value) */
@@ -3609,7 +3319,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                }
                                if( withcomments )
                                        CB_RESET();
-                               
+
                        } else {
                                return -1;
                        }
@@ -3647,7 +3357,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
        struct ast_category *cat = NULL;
        int count = 0;
        struct stat statbuf;
-       
+
        cat = ast_config_get_current_category(cfg);
 
        if (filename[0] == '/') {
@@ -3656,13 +3366,13 @@ static struct ast_config *config_text_file_load(const char *database, const char
                if (use_local_dir)
                        snprintf(fn, sizeof(fn), "./%s", filename);
                else
-                       snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, filename);
+                       snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
        }
 
        if (withcomments && cfg && cfg->include_level < 2 ) {
                CB_INIT();
        }
-       
+
 #ifdef AST_INCLUDE_GLOB
        {
                int glob_ret;
@@ -3713,17 +3423,17 @@ static struct ast_config *config_text_file_load(const char *database, const char
                while(!feof(f)) {
                        lineno++;
                        if (fgets(buf, sizeof(buf), f)) {
-                               if ( withcomments ) {    
+                               if ( withcomments ) {
                                        CB_ADD(lline_buffer);       /* add the current lline buffer to the comment buffer */
                                        lline_buffer[0] = 0;        /* erase the lline buffer */
                                }
-                               
+
                                new_buf = buf;
-                               if (comment) 
+                               if (comment)
                                        process_buf = NULL;
                                else
                                        process_buf = buf;
-                               
+
                                while ((comment_p = strchr(new_buf, COMMENT_META))) {
                                        if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
                                                /* Yuck, gotta memmove */
@@ -3755,7 +3465,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                                                        CB_ADD(";");
                                                                        CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
                                                                }
-                                                               
+
                                                                memmove(oldptr, new_buf, strlen(new_buf) + 1);
                                                                new_buf = oldptr;
                                                        } else
@@ -3763,12 +3473,12 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                                }
                                        } else {
                                                if (!comment) {
-                                                       /* If ; is found, and we are not nested in a comment, 
+                                                       /* If ; is found, and we are not nested in a comment,
                                                           we immediately stop all comment processing */
                                                        if ( withcomments ) {
                                                                LLB_ADD(comment_p);
                                                        }
-                                                       *comment_p = '\0'; 
+                                                       *comment_p = '\0';
                                                        new_buf = comment_p;
                                                } else
                                                        new_buf = comment_p + 1;
@@ -3778,11 +3488,11 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                {
                                        CB_ADD(buf);  /* the whole line is a comment, store it */
                                }
-                               
+
                                if (process_buf) {
-                                       char *buf = ast_strip(process_buf);
-                                       if (!ast_strlen_zero(buf)) {
-                                               if (process_text_line(cfg, &cat, buf, lineno, filename, withcomments, suggested_include_file)) {
+                                       char *stripped_process_buf = ast_strip(process_buf);
+                                       if (!ast_strlen_zero(stripped_process_buf)) {
+                                               if (process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
                                                        cfg = NULL;
                                                        break;
                                                }
@@ -3790,7 +3500,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                }
                        }
                }
-               fclose(f);              
+               fclose(f);
        } while(0);
        if (comment) {
                ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
@@ -3804,12 +3514,12 @@ static struct ast_config *config_text_file_load(const char *database, const char
                }
 #endif
        if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
-               if (comment_buffer) { 
+               if (comment_buffer) {
                        free(comment_buffer);
                        free(lline_buffer);
-                       comment_buffer=0; 
-                       lline_buffer=0; 
-                       comment_buffer_size=0; 
+                       comment_buffer=0;
+                       lline_buffer=0;
+                       comment_buffer_size=0;
                        lline_buffer_size=0;
                }
        }
@@ -3822,7 +3532,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
 
 static struct ast_config *ast_config_new(void) ;
 
-static struct ast_config *ast_config_new(void) 
+static struct ast_config *ast_config_new(void)
 {
        struct ast_config *config;
 
@@ -3875,7 +3585,7 @@ static struct ast_category *next_available_category(struct ast_category *cat)
 }
 
 static char *ast_category_browse(struct ast_config *config, const char *prev)
-{      
+{
        struct ast_category *cat = NULL;
 
        if (prev && config->last_browse && (config->last_browse->name == prev))
@@ -3898,7 +3608,7 @@ static char *ast_category_browse(struct ast_config *config, const char *prev)
                        }
                }
        }
-       
+
        if (cat)
                cat = next_available_category(cat);
 
@@ -3919,21 +3629,21 @@ void ast_config_set_current_category(struct ast_config *cfg, const struct ast_ca
 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
    which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
    recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
-   be shocked and mystified as to why things are not showing up in the files! 
-   
+   be shocked and mystified as to why things are not showing up in the files!
+
    Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
    and line number are stored for each include, plus the name of the file included, so that these statements may be
-   included in the output files on a file_save operation. 
-   
+   included in the output files on a file_save operation.
+
    The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
    are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
    the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
    and a header gets added.
-   
+
    vars and category heads are output in the order they are stored in the config file. So, if the software
    shuffles these at all, then the placement of #include directives might get a little mixed up, because the
    file/lineno data probably won't get changed.
-   
+
 */
 
 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
@@ -3942,7 +3652,7 @@ static void gen_header(FILE *f1, const char *configfile, const char *fn, const c
        time_t t;
        time(&t);
        ast_copy_string(date, ctime(&t), sizeof(date));
-       
+
        fprintf(f1, ";!\n");
        fprintf(f1, ";! Automatically generated configuration file\n");
        if (strcmp(configfile, fn))
@@ -3961,7 +3671,7 @@ static void set_fn(char *fn, int fn_size, const char *file, const char *configfi
                        ast_copy_string(fn, configfile, fn_size);
                else
                        snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
-       } else if (file[0] == '/') 
+       } else if (file[0] == '/')
                ast_copy_string(fn, file, fn_size);
        else
                snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
@@ -3978,20 +3688,20 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
        struct ast_comment *cmt;
        struct ast_config_include *incl;
        int blanklines = 0;
-       
+
        /* reset all the output flags, in case this isn't our first time saving this data */
-       
+
        for (incl=cfg->includes; incl; incl = incl->next)
                incl->output = 0;
-       
+
        /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
           are all truncated to zero bytes and have that nice header*/
-       
+
        for (incl=cfg->includes; incl; incl = incl->next)
        {
                if (!incl->exec) { /* leave the execs alone -- we'll write out the #exec directives, but won't zero out the include files or exec files*/
                        FILE *f1;
-                       
+
                        set_fn(fn, sizeof(fn), incl->included_file, configfile); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
                        f1 = fopen(fn,"w");
                        if (f1) {
@@ -4002,24 +3712,24 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                        }
                }
        }
-       
+
        set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
-#ifdef __CYGWIN__      
+#ifdef __CYGWIN__
        if ((f = fopen(fn, "w+"))) {
 #else
        if ((f = fopen(fn, "w"))) {
-#endif     
+#endif
                if (option_verbose > 1)
                        ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
 
                gen_header(f, configfile, fn, generator);
                cat = cfg->root;
                fclose(f);
-        
+
                /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
-               /* since each var, cat, and associated comments can come from any file, we have to be 
+               /* since each var, cat, and associated comments can come from any file, we have to be
                   mobile, and open each file, print, and close it on an entry-by-entry basis */
-               
+
                while(cat) {
                        set_fn(fn, sizeof(fn), cat->file, configfile);
                        f = fopen(fn, "a");
@@ -4028,7 +3738,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                                ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
                                return -1;
                        }
-                       
+
                        /* dump any includes that happen before this category header */
                        for (incl=cfg->includes; incl; incl = incl->next) {
                                if (strcmp(incl->include_location_file, cat->file) == 0){
@@ -4041,7 +3751,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                                        }
                                }
                        }
-            
+
                        /* Dump section with any appropriate comment */
                        for (cmt = cat->precomments; cmt; cmt=cmt->next) {
                                if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
@@ -4056,7 +3766,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                        if (!cat->sameline)
                                fprintf(f,"\n");
                        fclose(f);
-            
+
                        var = cat->root;
                        while(var) {
                                set_fn(fn, sizeof(fn), var->file, configfile);
@@ -4066,7 +3776,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                                        ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
                                        return -1;
                                }
-                
+
                                /* dump any includes that happen before this category header */
                                for (incl=cfg->includes; incl; incl = incl->next) {
                                        if (strcmp(incl->include_location_file, var->file) == 0){
@@ -4079,24 +3789,24 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                                                }
                                        }
                                }
-                
+
                                for (cmt = var->precomments; cmt; cmt=cmt->next) {
                                        if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
                                                fprintf(f,"%s", cmt->cmt);
                                }
-                               if (var->sameline) 
+                               if (var->sameline)
                                        fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
-                               else    
+                               else
                                        fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
                                if (var->blanklines) {
                                        blanklines = var->blanklines;
                                        while (blanklines--)
                                                fprintf(f, "\n");
                                }
-                               
+
                                fclose(f);
-                
-                               
+
+
                                var = var->next;
                        }
                        cat = cat->next;
@@ -4113,7 +3823,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
 
        /* Now, for files with trailing #include/#exec statements,
           we have to make sure every entry is output */
-       
+
        for (incl=cfg->includes; incl; incl = incl->next) {
                if (!incl->output) {
                        /* open the respective file */
@@ -4124,7 +3834,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                                ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
                                return -1;
                        }
-            
+
                        /* output the respective include */
                        if (incl->exec)
                                fprintf(f,"#exec \"%s\"\n", incl->exec_file);
@@ -4134,7 +3844,7 @@ int localized_config_text_file_save(const char *configfile, const struct ast_con
                        incl->output = 1;
                }
        }
-       
+
        return 0;
 }
 
@@ -4153,20 +3863,6 @@ struct ast_app;
 #else
 #define EXT_DATA_SIZE 8192
 #endif
-/*!
- * When looking up extensions, we can have different requests
- * identified by the 'action' argument, as follows.
- * Note that the coding is such that the low 4 bits are the
- * third argument to extension_match_core.
- */
-enum ext_match_t {
-       E_MATCHMORE =   0x00,   /* extension can match but only with more 'digits' */
-       E_CANMATCH =    0x01,   /* extension can match with or without more 'digits' */
-       E_MATCH =       0x02,   /* extension is an exact match */
-       E_MATCH_MASK =  0x03,   /* mask for the argument to extension_match_core() */
-       E_SPAWN =       0x12,   /* want to spawn an extension. Requires exact match */
-       E_FINDLABEL =   0x22    /* returns the priority for a given label. Requires exact match */
-};
 
 #ifdef NOT_ANYMORE
 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
@@ -4366,29 +4062,48 @@ char *months[] =
        NULL,
 };
 
-static 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 ast_build_timing(struct ast_timing *i, const char *info_in)
 {
-       char info_save[256];
        char *info;
+       int j, num_fields, last_sep = -1;
+
+       i->timezone = NULL;
 
        /* Check for empty just in case */
-       if (ast_strlen_zero(info_in))
+       if (ast_strlen_zero(info_in)) {
                return 0;
+       }
+
        /* make a copy just in case we were passed a static string */
-       ast_copy_string(info_save, info_in, sizeof(info_save));
-       info = info_save;
+       info = ast_strdupa(info_in);
+
+       /* 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, "|"));
+       get_timerange(i, strsep(&info, "|,"));
        if (info)
-               i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
+               i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
        if (info)
-               i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
+               i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
        if (info)
-               i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
+               i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
        return 1;
 }
 
@@ -4455,14 +4170,14 @@ static int ext_cmp1(const char **p)
                break;
        }
        /* locate end of set */
-       end = strchr(*p, ']');  
+       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... */
        }
 
-       bzero(chars, sizeof(chars));    /* clear all chars in the set */
+       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]);
@@ -4541,39 +4256,13 @@ static int ext_strncpy(char *dst, const char *src, int len)
  * Wrapper around _extension_match_core() to do performance measurement
  * using the profiling code.
  */
-static 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;
+int ast_check_timing(const struct ast_timing *i);
 
-       /* If we got this far, then we're good */
-       return 1;
+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
@@ -4658,6 +4347,19 @@ static struct ast_include *ast_walk_context_includes(struct ast_context *con,
                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,
@@ -4666,6 +4368,31 @@ struct ast_include *localized_walk_context_includes(struct ast_context *con,
        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);
@@ -4687,6 +4414,19 @@ struct ast_sw *localized_walk_context_switches(struct ast_context *con,
        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);
 
@@ -4700,22 +4440,6 @@ static struct ast_context *ast_context_find(const char *name)
        return tmp;
 }
 
-/* request and result for pbx_find_extension */
-struct pbx_find_info {
-#if 0
-       const char *context;
-       const char *exten;
-       int priority;
-#endif
-
-       char *incstack[AST_PBX_MAX_STACK];      /* filled during the search */
-       int stacklen;                   /* modified during the search */
-       int status;                     /* set on return */
-       struct ast_switch *swo;         /* set on return */
-       const char *data;               /* set on return */
-       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.
@@ -4856,24 +4580,24 @@ static inline int include_valid(struct ast_include *i)
 
 
 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
-                                                                                       struct ast_context *bypass, 
+                                                                                       struct ast_context *bypass,
                                                                                        struct pbx_find_info *q,
-                                                                                       const char *context, 
-                                                                                       const char *exten, 
+                                                                                       const char *context,
+                                                                                       const char *exten,
                                                                                        int priority,
-                                                                                       const char *label, 
-                                                                                       const char *callerid, 
+                                                                                       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, 
+                                                                                       struct ast_context *bypass,
                                                                                        struct pbx_find_info *q,
-                                                                                       const char *context, 
-                                                                                       const char *exten, 
+                                                                                       const char *context,
+                                                                                       const char *exten,
                                                                                        int priority,
-                                                                                       const char *label, 
-                                                                                       const char *callerid, 
+                                                                                       const char *label,
+                                                                                       const char *callerid,
                                                                                        enum ext_match_t action)
 {
        int x;
@@ -4881,6 +4605,10 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        struct ast_exten *e, *eroot;
        struct ast_include *i;
 
+       if (!context) {
+               return NULL;
+       }
+
        /* Initialize status if appropriate */
        if (q->stacklen == 0) {
                q->status = STATUS_NO_CONTEXT;
@@ -4957,7 +4685,7 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                        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;
@@ -4991,20 +4719,20 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 
 struct ast_exten *localized_find_extension(struct ast_context *bypass,
                                                                                  struct pbx_find_info *q,
-                                                                                 const char *context, 
-                                                                                 const char *exten, 
+                                                                                 const char *context,
+                                                                                 const char *exten,
                                                                                  int priority,
-                                                                                 const char *label, 
-                                                                                 const char *callerid, 
+                                                                                 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 *context,
+                                                                                 const char *exten,
                                                                                  int priority,
-                                                                                 const char *label, 
-                                                                                 const char *callerid, 
+                                                                                 const char *label,
+                                                                                 const char *callerid,
                                                                                   enum ext_match_t action)
 {
        return pbx_find_extension(NULL, bypass, q, context, exten, priority, label, callerid, action);
@@ -5058,7 +4786,7 @@ static int ast_context_add_include2(struct ast_context *con, const char *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->hastime = ast_build_timing(&(new_include->timing), c);
        }
        new_include->next      = NULL;
        new_include->registrar = registrar;
@@ -5238,16 +4966,16 @@ int localized_context_add_switch2(struct ast_context *con, const char *value,
 
 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;
+       struct ast_context *tmp, **loc_contexts;
        int length = sizeof(struct ast_context) + strlen(name) + 1;
 
        if (!extcontexts) {
                ast_wrlock_contexts();
-               local_contexts = &contexts;
+               loc_contexts = &contexts;
        } else
-               local_contexts = extcontexts;
+               loc_contexts = extcontexts;
 
-       for (tmp = *local_contexts; tmp; tmp = tmp->next) {
+       for (tmp = *loc_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);
@@ -5264,10 +4992,10 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
                strcpy(tmp->name, name);
                tmp->root = NULL;
                tmp->registrar = registrar;
-               tmp->next = *local_contexts;
+               tmp->next = *loc_contexts;
                tmp->includes = NULL;
                tmp->ignorepats = NULL;
-               *local_contexts = tmp;
+               *loc_contexts = tmp;
                if (option_debug)
                        ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
                if (option_verbose > 2)
@@ -5511,20 +5239,18 @@ static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *c
        return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
 }
 
-static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
 {
        return __ast_context_create(extcontexts, name, registrar, 1);
 }
 
-struct ast_context *localized_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
-
-struct ast_context *localized_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar);
+struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
 {
-       return __ast_context_create(extcontexts, name, registrar, 0);
+       return __ast_context_create(extcontexts, name, registrar, 1);
 }
 
 
-
 /* chopped this one off at the knees */
 static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
 {
@@ -5551,7 +5277,7 @@ static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
                        parens--;
                } else if (*var == ':' && parens == 0) {
                        *var++ = '\0';
-                       sscanf(var, "%d:%d", offset, length);
+                       sscanf(var, "%30d:%30d", offset, length);
                        return 1; /* offset:length valid */
                }
        }
@@ -5620,7 +5346,7 @@ static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char *
        int offset, length;
        int i, need_substring;
        struct varshead *places[2] = { headp, &globals };       /* list of places where we may look */
-       
+
        /*
         * 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;
@@ -5628,7 +5354,7 @@ static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char *
         */
        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:
@@ -5649,7 +5375,7 @@ static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char *
                if (!strcmp(var, "EPOCH")) {
                        snprintf(workspace, workspacelen, "%u",(int)time(NULL));
                }
-               
+
                s = workspace;
        }
        /* if not found, look into chanvars or global vars */
@@ -5891,13 +5617,12 @@ static int pbx_load_config(const char *config_file)
        if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
                autofallthrough_config = ast_true(aft);
        clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
-       ast_set2_flag(&ast_options, ast_true(ast_variable_retrieve(cfg, "general", "priorityjumping")), AST_OPT_FLAG_PRIORITY_JUMPING);
 
-       if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext"))) 
+       if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
                ast_copy_string(userscontext, cxt, sizeof(userscontext));
        else
                ast_copy_string(userscontext, "default", sizeof(userscontext));
-                                                                   
+
        for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
                memset(realvalue, 0, sizeof(realvalue));
                pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
@@ -5907,7 +5632,7 @@ static int pbx_load_config(const char *config_file)
                /* All categories but "general" or "globals" are considered contexts */
                if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
                        continue;
-               con=ast_context_find_or_create(&local_contexts,cxt, registrar);
+               con=ast_context_find_or_create(&local_contexts,NULL,cxt, global_registrar);
                if (con == NULL)
                        continue;
 
@@ -5956,7 +5681,7 @@ static int pbx_load_config(const char *config_file)
                                                        ipri = lastpri;
                                                else
                                                        ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
-                                       } else if (sscanf(pri, "%d", &ipri) != 1 &&
+                                       } else if (sscanf(pri, "%30d", &ipri) != 1 &&
                                            (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
                                                ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
                                                ipri = 0;
@@ -5995,7 +5720,7 @@ static int pbx_load_config(const char *config_file)
                                                lastpri = ipri;
                                                if (!ast_opt_dont_warn && !strcmp(realext, "_."))
                                                        ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior.  Please use '_X.' instead at line %d\n", v->lineno);
-                                               if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free, registrar)) {
+                                               if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, global_registrar)) {
                                                        ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
                                                }
                                        }
@@ -6004,12 +5729,12 @@ static int pbx_load_config(const char *config_file)
                        } else if (!strcasecmp(v->name, "include")) {
                                memset(realvalue, 0, sizeof(realvalue));
                                pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
-                               if (ast_context_add_include2(con, realvalue, registrar))
+                               if (ast_context_add_include2(con, realvalue, global_registrar))
                                        ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
                        } else if (!strcasecmp(v->name, "ignorepat")) {
                                memset(realvalue, 0, sizeof(realvalue));
                                pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
-                               if (ast_context_add_ignorepat2(con, realvalue, registrar))
+                               if (ast_context_add_ignorepat2(con, realvalue, global_registrar))
                                        ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
                        } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
                                char *stringp= realvalue;
@@ -6024,7 +5749,7 @@ static int pbx_load_config(const char *config_file)
                                data = strsep(&stringp, ""); /* XXX what for ? */
                                if (!data)
                                        data = "";
-                               if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
+                               if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), global_registrar))
                                        ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
                        } else {
                                ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
@@ -6149,9 +5874,7 @@ static void ast_merge_contexts_and_delete(struct ast_context **extcontexts, cons
        return;
 }
 
-void localized_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
-
-void localized_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
+void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
 {
        ast_merge_contexts_and_delete(extcontexts, registrar);
 }
@@ -6184,12 +5907,12 @@ int localized_pbx_load_module(void)
 {
        struct ast_context *con;
 
-       if(!pbx_load_config(config))
+       if(!pbx_load_config(config_filename))
                return -1 /* AST_MODULE_LOAD_DECLINE*/;
 
        /* pbx_load_users(); */ /* does this affect the dialplan? */
 
-       ast_merge_contexts_and_delete(&local_contexts, registrar);
+       ast_merge_contexts_and_delete(&local_contexts, global_registrar);
 
        for (con = NULL; (con = ast_walk_contexts(con));)
                ast_context_verify_includes(con);
@@ -6200,7 +5923,16 @@ int localized_pbx_load_module(void)
                printf("Context: %s\n", con->name);
        }
        printf("=========\n");
-       
+
        return 0;
 }
 
+/* For platforms which don't have pthread_rwlock_timedrdlock() */
+struct timeval ast_tvnow(void);
+
+struct timeval ast_tvnow(void)
+{
+       struct timeval t;
+       gettimeofday(&t, NULL);
+       return t;
+}