extconf.c

Go to the documentation of this file.
00001 /*  
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006, Digium, Inc.
00005  *
00006  * Steve Murphy <murf@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 
00020 /*!
00021  * \file extconf
00022  * A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
00023  * for operations outside of asterisk. A huge, awful hack.
00024  *
00025  */
00026 
00027 /*!
00028  * \li \ref extconf.c uses the configuration file \ref extconfig.conf and \ref extensions.conf and \ref asterisk.conf
00029  * \addtogroup configuration_file Configuration Files
00030  */
00031 
00032 /*!
00033  * \page extconfig.conf extconfig.conf
00034  * \verbinclude extconfig.conf.sample
00035  */
00036 
00037 /*!
00038  * \page extensions.conf extensions.conf
00039  * \verbinclude extensions.conf.sample
00040  */
00041 
00042 /*** MODULEINFO
00043    <support_level>extended</support_level>
00044  ***/
00045 
00046 #define WRAP_LIBC_MALLOC
00047 #include "asterisk.h"
00048 
00049 #undef DEBUG_THREADS
00050 
00051 #include "asterisk/compat.h"
00052 #include "asterisk/paths.h"   /* we use AST_CONFIG_DIR */
00053 
00054 #include <errno.h>
00055 #include <time.h>
00056 #include <sys/stat.h>
00057 #include <sys/types.h>
00058 #include <sys/time.h>
00059 #include <sys/resource.h>
00060 #include <sys/wait.h>
00061 #include <stdarg.h>
00062 #include <string.h>
00063 #include <locale.h>
00064 #include <ctype.h>
00065 #if !defined(SOLARIS) && !defined(__CYGWIN__)
00066 #include <err.h>
00067 #endif
00068 #include <regex.h>
00069 #include <limits.h>
00070 #include <pthread.h>
00071 #include <netdb.h>
00072 #include <sys/param.h>
00073 #include <signal.h>
00074 
00075 static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
00076 void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
00077 
00078 #define ASINCLUDE_GLOB 1
00079 #ifdef AST_INCLUDE_GLOB
00080 
00081 #if !defined(GLOB_ABORTED)
00082 #define GLOB_ABORTED GLOB_ABEND
00083 #endif
00084 
00085 # include <glob.h>
00086 #endif
00087 
00088 #define AST_API_MODULE  1 /* gimme the inline defs! */
00089 struct ast_channel 
00090 {
00091    char x; /* basically empty! */
00092 };
00093 
00094 
00095 
00096 #include "asterisk/inline_api.h"
00097 #include "asterisk/endian.h"
00098 #include "asterisk/ast_expr.h"
00099 #include "asterisk/extconf.h"
00100 
00101 /* logger.h */
00102 
00103 #define EVENTLOG "event_log"
00104 #define  QUEUELOG "queue_log"
00105 
00106 #define DEBUG_M(a) { \
00107    a; \
00108 }
00109 
00110 #define VERBOSE_PREFIX_1 " "
00111 #define VERBOSE_PREFIX_2 "  == "
00112 #define VERBOSE_PREFIX_3 "    -- "
00113 #define VERBOSE_PREFIX_4 "       > "
00114 
00115 void ast_log_backtrace(void);
00116 
00117 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00118    __attribute__((format(printf, 5, 6)));
00119 
00120 /* IN CONFLICT: void ast_verbose(const char *fmt, ...)
00121    __attribute__((format(printf, 1, 2))); */
00122 
00123 int ast_register_verbose(void (*verboser)(const char *string));
00124 int ast_unregister_verbose(void (*verboser)(const char *string));
00125 
00126 void ast_console_puts(const char *string);
00127 
00128 #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
00129 
00130 #ifdef LOG_DEBUG
00131 #undef LOG_DEBUG
00132 #endif
00133 #define __LOG_DEBUG    0
00134 #define LOG_DEBUG      __LOG_DEBUG, _A_
00135 
00136 #ifdef LOG_EVENT
00137 #undef LOG_EVENT
00138 #endif
00139 #define __LOG_EVENT    1
00140 #define LOG_EVENT      __LOG_EVENT, _A_
00141 
00142 #ifdef LOG_NOTICE
00143 #undef LOG_NOTICE
00144 #endif
00145 #define __LOG_NOTICE   2
00146 #define LOG_NOTICE     __LOG_NOTICE, _A_
00147 
00148 #ifdef LOG_WARNING
00149 #undef LOG_WARNING
00150 #endif
00151 #define __LOG_WARNING  3
00152 #define LOG_WARNING    __LOG_WARNING, _A_
00153 
00154 #ifdef LOG_ERROR
00155 #undef LOG_ERROR
00156 #endif
00157 #define __LOG_ERROR    4
00158 #define LOG_ERROR      __LOG_ERROR, _A_
00159 
00160 #ifdef LOG_VERBOSE
00161 #undef LOG_VERBOSE
00162 #endif
00163 #define __LOG_VERBOSE  5
00164 #define LOG_VERBOSE    __LOG_VERBOSE, _A_
00165 
00166 #ifdef LOG_DTMF
00167 #undef LOG_DTMF
00168 #endif
00169 #define __LOG_DTMF  6
00170 #define LOG_DTMF    __LOG_DTMF, _A_
00171 
00172 /* lock.h */
00173 #define _ASTERISK_LOCK_H /* A small indication that this is horribly wrong. */
00174 
00175 #ifndef  HAVE_MTX_PROFILE
00176 #define  __MTX_PROF(a)  return pthread_mutex_lock((a))
00177 #else
00178 int mtx_prof = -1;
00179 
00180 #define  __MTX_PROF(a)  do {        \
00181    int i;               \
00182    /* profile only non-blocking events */ \
00183    ast_mark(mtx_prof, 1);        \
00184    i = pthread_mutex_trylock((a));     \
00185    ast_mark(mtx_prof, 0);        \
00186    if (!i)              \
00187       return i;         \
00188    else              \
00189       return pthread_mutex_lock((a)); \
00190    } while (0)
00191 #endif   /* HAVE_MTX_PROFILE */
00192 
00193 #define AST_PTHREADT_NULL (pthread_t) -1
00194 #define AST_PTHREADT_STOP (pthread_t) -2
00195 
00196 #if defined(SOLARIS) || defined(BSD)
00197 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00198 #endif /* SOLARIS || BSD */
00199 
00200 /* Asterisk REQUIRES recursive (not error checking) mutexes
00201    and will not run without them. */
00202 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
00203 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00204 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE_NP
00205 #else
00206 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00207 #define AST_MUTEX_KIND        PTHREAD_MUTEX_RECURSIVE
00208 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
00209 
00210 #ifdef DEBUG_THREADS
00211 
00212 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
00213 
00214 #ifdef THREAD_CRASH
00215 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00216 #else
00217 #define DO_THREAD_CRASH do { } while (0)
00218 #endif
00219 
00220 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
00221 
00222 #define AST_MAX_REENTRANCY 10
00223 
00224 struct ast_mutex_info {
00225    pthread_mutex_t mutex;
00226    /*! Track which thread holds this lock */
00227    unsigned int track:1;
00228    const char *file[AST_MAX_REENTRANCY];
00229    int lineno[AST_MAX_REENTRANCY];
00230    int reentrancy;
00231    const char *func[AST_MAX_REENTRANCY];
00232    pthread_t thread[AST_MAX_REENTRANCY];
00233 };
00234 
00235 typedef struct ast_mutex_info ast_mutex_t;
00236 
00237 typedef pthread_cond_t ast_cond_t;
00238 
00239 static pthread_mutex_t empty_mutex;
00240 
00241 static void __attribute__((constructor)) init_empty_mutex(void)
00242 {
00243    memset(&empty_mutex, 0, sizeof(empty_mutex));
00244 }
00245 
00246 static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
00247                   const char *mutex_name, ast_mutex_t *t,
00248                   pthread_mutexattr_t *attr) 
00249 {
00250 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00251    int canlog = strcmp(filename, "logger.c");
00252 
00253    if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00254       if ((t->mutex) != (empty_mutex)) {
00255          __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
00256                   filename, lineno, func, mutex_name);
00257          __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
00258                   t->file[0], t->lineno[0], t->func[0], mutex_name);
00259          DO_THREAD_CRASH;
00260          return 0;
00261       }
00262    }
00263 #endif
00264 
00265    t->file[0] = filename;
00266    t->lineno[0] = lineno;
00267    t->func[0] = func;
00268    t->thread[0]  = 0;
00269    t->reentrancy = 0;
00270 
00271    return pthread_mutex_init(&t->mutex, attr);
00272 }
00273 
00274 static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
00275                   const char *mutex_name, ast_mutex_t *t)
00276 {
00277    static pthread_mutexattr_t  attr;
00278 
00279    pthread_mutexattr_init(&attr);
00280    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00281 
00282    return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
00283 }
00284 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00285 
00286 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00287                   const char *mutex_name, ast_mutex_t *t)
00288 {
00289    int res;
00290    int canlog = strcmp(filename, "logger.c");
00291 
00292 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00293    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00294       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00295                filename, lineno, func, mutex_name);
00296    }
00297 #endif
00298 
00299    res = pthread_mutex_trylock(&t->mutex);
00300    switch (res) {
00301    case 0:
00302       pthread_mutex_unlock(&t->mutex);
00303       break;
00304    case EINVAL:
00305       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00306               filename, lineno, func, mutex_name);
00307       break;
00308    case EBUSY:
00309       __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00310                filename, lineno, func, mutex_name);
00311       __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00312                t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00313       break;
00314    }
00315 
00316    if ((res = pthread_mutex_destroy(&t->mutex)))
00317       __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
00318                filename, lineno, func, strerror(res));
00319 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00320    else
00321       t->mutex = PTHREAD_MUTEX_INIT_VALUE;
00322 #endif
00323    t->file[0] = filename;
00324    t->lineno[0] = lineno;
00325    t->func[0] = func;
00326 
00327    return res;
00328 }
00329 
00330 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00331                                            const char* mutex_name, ast_mutex_t *t)
00332 {
00333    int res;
00334    int canlog = strcmp(filename, "logger.c");
00335 
00336 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00337    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00338       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00339              filename, lineno, func, mutex_name);
00340       ast_mutex_init(t);
00341    }
00342 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00343 
00344 #ifdef DETECT_DEADLOCKS
00345    {
00346       time_t seconds = time(NULL);
00347       time_t current;
00348       do {
00349 #ifdef   HAVE_MTX_PROFILE
00350          ast_mark(mtx_prof, 1);
00351 #endif
00352          res = pthread_mutex_trylock(&t->mutex);
00353 #ifdef   HAVE_MTX_PROFILE
00354          ast_mark(mtx_prof, 0);
00355 #endif
00356          if (res == EBUSY) {
00357             current = time(NULL);
00358             if ((current - seconds) && (!((current - seconds) % 5))) {
00359                __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00360                         filename, lineno, func, (int)(current - seconds), mutex_name);
00361                __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00362                         t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
00363                         t->func[t->reentrancy-1], mutex_name);
00364             }
00365             usleep(200);
00366          }
00367       } while (res == EBUSY);
00368    }
00369 #else
00370 #ifdef   HAVE_MTX_PROFILE
00371    ast_mark(mtx_prof, 1);
00372    res = pthread_mutex_trylock(&t->mutex);
00373    ast_mark(mtx_prof, 0);
00374    if (res)
00375 #endif
00376    res = pthread_mutex_lock(&t->mutex);
00377 #endif /* DETECT_DEADLOCKS */
00378 
00379    if (!res) {
00380       if (t->reentrancy < AST_MAX_REENTRANCY) {
00381          t->file[t->reentrancy] = filename;
00382          t->lineno[t->reentrancy] = lineno;
00383          t->func[t->reentrancy] = func;
00384          t->thread[t->reentrancy] = pthread_self();
00385          t->reentrancy++;
00386       } else {
00387          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00388                         filename, lineno, func, mutex_name);
00389       }
00390    } else {
00391       __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00392                filename, lineno, func, strerror(errno));
00393       DO_THREAD_CRASH;
00394    }
00395 
00396    return res;
00397 }
00398 
00399 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00400                                               const char* mutex_name, ast_mutex_t *t)
00401 {
00402    int res;
00403    int canlog = strcmp(filename, "logger.c");
00404 
00405 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00406    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00407       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00408                filename, lineno, func, mutex_name);
00409       ast_mutex_init(t);
00410    }
00411 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00412 
00413    if (!(res = pthread_mutex_trylock(&t->mutex))) {
00414       if (t->reentrancy < AST_MAX_REENTRANCY) {
00415          t->file[t->reentrancy] = filename;
00416          t->lineno[t->reentrancy] = lineno;
00417          t->func[t->reentrancy] = func;
00418          t->thread[t->reentrancy] = pthread_self();
00419          t->reentrancy++;
00420       } else {
00421          __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00422                   filename, lineno, func, mutex_name);
00423       }
00424    } else {
00425       __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
00426                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00427    }
00428 
00429    return res;
00430 }
00431 
00432 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00433                     const char *mutex_name, ast_mutex_t *t)
00434 {
00435    int res;
00436    int canlog = strcmp(filename, "logger.c");
00437 
00438 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00439    if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00440       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00441                filename, lineno, func, mutex_name);
00442    }
00443 #endif
00444 
00445    if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00446       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00447                filename, lineno, func, mutex_name);
00448       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00449                t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00450       DO_THREAD_CRASH;
00451    }
00452 
00453    if (--t->reentrancy < 0) {
00454       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00455                filename, lineno, func, mutex_name);
00456       t->reentrancy = 0;
00457    }
00458 
00459    if (t->reentrancy < AST_MAX_REENTRANCY) {
00460       t->file[t->reentrancy] = NULL;
00461       t->lineno[t->reentrancy] = 0;
00462       t->func[t->reentrancy] = NULL;
00463       t->thread[t->reentrancy] = 0;
00464    }
00465 
00466    if ((res = pthread_mutex_unlock(&t->mutex))) {
00467       __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
00468                filename, lineno, func, strerror(res));
00469       DO_THREAD_CRASH;
00470    }
00471 
00472    return res;
00473 }
00474 
00475 #else /* !DEBUG_THREADS */
00476 
00477 
00478 typedef pthread_mutex_t ast_mutex_t;
00479 
00480 #define AST_MUTEX_INIT_VALUE  ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00481 
00482 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00483 {
00484    pthread_mutexattr_t attr;
00485 
00486    pthread_mutexattr_init(&attr);
00487    pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00488 
00489    return pthread_mutex_init(pmutex, &attr);
00490 }
00491 
00492 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00493 
00494 typedef pthread_cond_t ast_cond_t;
00495 
00496 #endif /* !DEBUG_THREADS */
00497 
00498 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00499 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
00500  constructors/destructors to create/destroy mutexes.  */
00501 #define __AST_MUTEX_DEFINE(scope, mutex) \
00502    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
00503 static void  __attribute__((constructor)) init_##mutex(void) \
00504 { \
00505    ast_mutex_init(&mutex); \
00506 } \
00507 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
00508 /* By default, use static initialization of mutexes. */ 
00509 #define __AST_MUTEX_DEFINE(scope, mutex) \
00510    scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
00511 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
00512 
00513 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00514 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
00515 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
00516 
00517 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
00518 
00519 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00520 
00521 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00522 
00523 #ifndef __linux__
00524 #define pthread_create __use_ast_pthread_create_instead__
00525 #endif
00526 
00527 typedef pthread_rwlock_t ast_rwlock_t;
00528 
00529 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
00530 {
00531    pthread_rwlockattr_t attr;
00532 
00533    pthread_rwlockattr_init(&attr);
00534 
00535 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
00536    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
00537 #endif
00538 
00539    return pthread_rwlock_init(prwlock, &attr);
00540 }
00541 
00542 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
00543 {
00544    return pthread_rwlock_destroy(prwlock);
00545 }
00546 
00547 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
00548 {
00549    return pthread_rwlock_unlock(prwlock);
00550 }
00551 
00552 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
00553 {
00554    return pthread_rwlock_rdlock(prwlock);
00555 }
00556 
00557 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
00558 {
00559    return pthread_rwlock_wrlock(prwlock);
00560 }
00561 
00562 /* Statically declared read/write locks */
00563 
00564 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
00565 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
00566         scope ast_rwlock_t rwlock; \
00567 static void  __attribute__((constructor)) init_##rwlock(void) \
00568 { \
00569         ast_rwlock_init(&rwlock); \
00570 } \
00571 static void  __attribute__((destructor)) fini_##rwlock(void) \
00572 { \
00573         ast_rwlock_destroy(&rwlock); \
00574 }
00575 #else
00576 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
00577 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
00578         scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
00579 #endif
00580 
00581 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
00582 
00583 /*
00584  * Initial support for atomic instructions.
00585  * For platforms that have it, use the native cpu instruction to
00586  * implement them. For other platforms, resort to a 'slow' version
00587  * (defined in utils.c) that protects the atomic instruction with
00588  * a single lock.
00589  * The slow versions is always available, for testing purposes,
00590  * as ast_atomic_fetchadd_int_slow()
00591  */
00592 
00593 #if defined(HAVE_OSX_ATOMICS)
00594 #include "libkern/OSAtomic.h"
00595 #endif
00596 
00597 /*! \brief Atomically add v to *p and return * the previous value of *p.
00598  * This can be used to handle reference counts, and the return value
00599  * can be used to generate unique identifiers.
00600  */
00601 
00602 #if defined(HAVE_GCC_ATOMICS)
00603 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00604 {
00605    return __sync_fetch_and_add(p, v);
00606 })
00607 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
00608 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00609 {
00610    return OSAtomicAdd32(v, (int32_t *) p);
00611 })
00612 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
00613 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00614 {
00615    return OSAtomicAdd64(v, (int64_t *) p);
00616 #elif defined (__i386__) || defined(__x86_64__)
00617 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00618 {
00619    __asm __volatile (
00620    "       lock   xaddl   %0, %1 ;        "
00621    : "+r" (v),                     /* 0 (result) */   
00622      "=m" (*p)                     /* 1 */
00623    : "m" (*p));                    /* 2 */
00624    return (v);
00625 })
00626 #else
00627 static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
00628 {
00629    int ret;
00630    ret = *p;
00631    *p += v;
00632    return ret;
00633 }
00634 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
00635 {
00636    return ast_atomic_fetchadd_int_slow(p, v);
00637 })
00638 #endif
00639 
00640 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
00641  * Useful e.g. to check if a refcount has reached 0.
00642  */
00643 #if defined(HAVE_GCC_ATOMICS)
00644 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00645 {
00646    return __sync_sub_and_fetch(p, 1) == 0;
00647 })
00648 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
00649 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00650 {
00651    return OSAtomicAdd32( -1, (int32_t *) p) == 0;
00652 })
00653 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
00654 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00655 {
00656    return OSAtomicAdd64( -1, (int64_t *) p) == 0;
00657 #else
00658 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
00659 {
00660    int a = ast_atomic_fetchadd_int(p, -1);
00661    return a == 1; /* true if the value is 0 now (so it was 1 previously) */
00662 })
00663 #endif
00664 
00665 #ifdef DEBUG_CHANNEL_LOCKS
00666 /*! \brief Lock AST channel (and print debugging output)
00667 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
00668 int ast_channel_lock(struct ast_channel *chan);
00669 
00670 /*! \brief Unlock AST channel (and print debugging output)
00671 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
00672 */
00673 int ast_channel_unlock(struct ast_channel *chan);
00674 
00675 /*! \brief Lock AST channel (and print debugging output)
00676 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
00677 int ast_channel_trylock(struct ast_channel *chan);
00678 #endif
00679 
00680 
00681 #include "asterisk/hashtab.h"
00682 #include "asterisk/ael_structs.h"
00683 #include "asterisk/pval.h"
00684 
00685 /* from utils.h */
00686 
00687 #define ast_free free
00688 #define ast_free_ptr free
00689 
00690 #define MALLOC_FAILURE_MSG \
00691    ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
00692 
00693 /*!
00694  * \brief A wrapper for malloc()
00695  *
00696  * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
00697  * message in the case that the allocation fails.
00698  *
00699  * The argument and return value are the same as malloc()
00700  */
00701 #define ast_malloc(len) \
00702    _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00703 
00704 #define ast_calloc(num, len) \
00705    _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00706 
00707 #define ast_calloc_cache(num, len) \
00708    _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00709 
00710 #define ast_realloc(p, len) \
00711    _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00712 
00713 #define ast_strdup(str) \
00714    _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00715 
00716 #define ast_strndup(str, len) \
00717    _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00718 
00719 #define ast_asprintf(ret, fmt, ...) \
00720    _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
00721 
00722 #define ast_vasprintf(ret, fmt, ap) \
00723    _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
00724 
00725 struct ast_flags {  /* stolen from utils.h */
00726    unsigned int flags;
00727 };
00728 #define ast_test_flag(p,flag)       ({ \
00729                typeof ((p)->flags) __p = (p)->flags; \
00730                unsigned int __x = 0; \
00731                (void) (&__p == &__x); \
00732                ((p)->flags & (flag)); \
00733                })
00734 
00735 #define ast_set2_flag(p,value,flag) do { \
00736                typeof ((p)->flags) __p = (p)->flags; \
00737                unsigned int __x = 0; \
00738                (void) (&__p == &__x); \
00739                if (value) \
00740                   (p)->flags |= (flag); \
00741                else \
00742                   (p)->flags &= ~(flag); \
00743                } while (0)
00744 
00745 
00746 
00747 #define MALLOC_FAILURE_MSG \
00748    ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
00749 /*!
00750  * \brief A wrapper for malloc()
00751  *
00752  * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
00753  * message in the case that the allocation fails.
00754  *
00755  * The argument and return value are the same as malloc()
00756  */
00757 #define ast_malloc(len) \
00758    _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00759 
00760 AST_INLINE_API(
00761 void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
00762 {
00763    void *p;
00764 
00765    if (!(p = malloc(len)))
00766       MALLOC_FAILURE_MSG;
00767 
00768    return p;
00769 }
00770 )
00771 
00772 /*!
00773  * \brief A wrapper for calloc()
00774  *
00775  * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
00776  * message in the case that the allocation fails.
00777  *
00778  * The arguments and return value are the same as calloc()
00779  */
00780 #define ast_calloc(num, len) \
00781    _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00782 
00783 AST_INLINE_API(
00784 void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
00785 {
00786    void *p;
00787 
00788    if (!(p = calloc(num, len)))
00789       MALLOC_FAILURE_MSG;
00790 
00791    return p;
00792 }
00793 )
00794 
00795 /*!
00796  * \brief A wrapper for calloc() for use in cache pools
00797  *
00798  * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
00799  * message in the case that the allocation fails. When memory debugging is in use,
00800  * the memory allocated by this function will be marked as 'cache' so it can be
00801  * distinguished from normal memory allocations.
00802  *
00803  * The arguments and return value are the same as calloc()
00804  */
00805 #define ast_calloc_cache(num, len) \
00806    _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00807 
00808 /*!
00809  * \brief A wrapper for realloc()
00810  *
00811  * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
00812  * message in the case that the allocation fails.
00813  *
00814  * The arguments and return value are the same as realloc()
00815  */
00816 #define ast_realloc(p, len) \
00817    _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00818 
00819 AST_INLINE_API(
00820 void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
00821 {
00822    void *newp;
00823 
00824    if (!(newp = realloc(p, len)))
00825       MALLOC_FAILURE_MSG;
00826 
00827    return newp;
00828 }
00829 )
00830 
00831 /*!
00832  * \brief A wrapper for strdup()
00833  *
00834  * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
00835  * message in the case that the allocation fails.
00836  *
00837  * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
00838  * argument is provided, ast_strdup will return NULL without generating any
00839  * kind of error log message.
00840  *
00841  * The argument and return value are the same as strdup()
00842  */
00843 #define ast_strdup(str) \
00844    _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00845 
00846 AST_INLINE_API(
00847 char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
00848 {
00849    char *newstr = NULL;
00850 
00851    if (str) {
00852       if (!(newstr = strdup(str)))
00853          MALLOC_FAILURE_MSG;
00854    }
00855 
00856    return newstr;
00857 }
00858 )
00859 
00860 /*!
00861  * \brief A wrapper for strndup()
00862  *
00863  * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
00864  * message in the case that the allocation fails.
00865  *
00866  * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
00867  * string to duplicate. If a NULL argument is provided, ast_strdup will return  
00868  * NULL without generating any kind of error log message.
00869  *
00870  * The arguments and return value are the same as strndup()
00871  */
00872 #define ast_strndup(str, len) \
00873    _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
00874 
00875 AST_INLINE_API(
00876 char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
00877 {
00878    char *newstr = NULL;
00879 
00880    if (str) {
00881       if (!(newstr = strndup(str, len)))
00882          MALLOC_FAILURE_MSG;
00883    }
00884 
00885    return newstr;
00886 }
00887 )
00888 
00889 /*!
00890  * \brief A wrapper for asprintf()
00891  *
00892  * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
00893  * message in the case that the allocation fails.
00894  *
00895  * The arguments and return value are the same as asprintf()
00896  */
00897 #define ast_asprintf(ret, fmt, ...) \
00898    _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
00899 
00900 AST_INLINE_API(
00901 __attribute__((format(printf, 5, 6)))
00902 int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
00903 {
00904    int res;
00905    va_list ap;
00906 
00907    va_start(ap, fmt);
00908    if ((res = vasprintf(ret, fmt, ap)) == -1)
00909       MALLOC_FAILURE_MSG;
00910    va_end(ap);
00911 
00912    return res;
00913 }
00914 )
00915 
00916 /*!
00917  * \brief A wrapper for vasprintf()
00918  *
00919  * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
00920  * message in the case that the allocation fails.
00921  *
00922  * The arguments and return value are the same as vasprintf()
00923  */
00924 #define ast_vasprintf(ret, fmt, ap) \
00925    _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
00926 
00927 AST_INLINE_API(
00928 __attribute__((format(printf, 5, 0)))
00929 int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
00930 {
00931    int res;
00932 
00933    if ((res = vasprintf(ret, fmt, ap)) == -1)
00934       MALLOC_FAILURE_MSG;
00935 
00936    return res;
00937 }
00938 )
00939 
00940 #if !defined(ast_strdupa) && defined(__GNUC__)
00941 /*!
00942   \brief duplicate a string in memory from the stack
00943   \param s The string to duplicate
00944 
00945   This macro will duplicate the given string.  It returns a pointer to the stack
00946   allocatted memory for the new string.
00947 */
00948 #define ast_strdupa(s)                                                    \
00949    (__extension__                                                    \
00950    ({                                                                \
00951       const char *__old = (s);                                  \
00952       size_t __len = strlen(__old) + 1;                         \
00953       char *__new = __builtin_alloca(__len);                    \
00954       memcpy (__new, __old, __len);                             \
00955       __new;                                                    \
00956    }))
00957 #endif
00958 
00959 
00960 /* from config.c */
00961 
00962 #define MAX_NESTED_COMMENTS 128
00963 #define COMMENT_START ";--"
00964 #define COMMENT_END "--;"
00965 #define COMMENT_META ';'
00966 #define COMMENT_TAG '-'
00967 
00968 static char *extconfig_conf = "extconfig.conf";
00969 
00970 /*! Growable string buffer */
00971 static char *comment_buffer;   /*!< this will be a comment collector.*/
00972 static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
00973 
00974 static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
00975 static int  lline_buffer_size;
00976 
00977 #define CB_INCR 250
00978 
00979 struct ast_comment {
00980    struct ast_comment *next;
00981    char cmt[0];
00982 };
00983 
00984 static void CB_INIT(void)
00985 {
00986    if (!comment_buffer) {
00987       comment_buffer = ast_malloc(CB_INCR);
00988       if (!comment_buffer)
00989          return;
00990       comment_buffer[0] = 0;
00991       comment_buffer_size = CB_INCR;
00992       lline_buffer = ast_malloc(CB_INCR);
00993       if (!lline_buffer)
00994          return;
00995       lline_buffer[0] = 0;
00996       lline_buffer_size = CB_INCR;
00997    } else {
00998       comment_buffer[0] = 0;
00999       lline_buffer[0] = 0;
01000    }
01001 }
01002 
01003 static void  CB_ADD(char *str)
01004 {
01005    int rem = comment_buffer_size - strlen(comment_buffer) - 1;
01006    int siz = strlen(str);
01007    if (rem < siz+1) {
01008       comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
01009       if (!comment_buffer)
01010          return;
01011       comment_buffer_size += CB_INCR+siz+1;
01012    }
01013    strcat(comment_buffer,str);
01014 }
01015 
01016 static void  CB_ADD_LEN(char *str, int len)
01017 {
01018    int cbl = strlen(comment_buffer) + 1;
01019    int rem = comment_buffer_size - cbl;
01020    if (rem < len+1) {
01021       comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
01022       if (!comment_buffer)
01023          return;
01024       comment_buffer_size += CB_INCR+len+1;
01025    }
01026    strncat(comment_buffer,str,len); /* safe */
01027    comment_buffer[cbl+len-1] = 0;
01028 }
01029 
01030 static void  LLB_ADD(char *str)
01031 {
01032    int rem = lline_buffer_size - strlen(lline_buffer) - 1;
01033    int siz = strlen(str);
01034    if (rem < siz+1) {
01035       lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
01036       if (!lline_buffer) 
01037          return;
01038       lline_buffer_size += CB_INCR + siz + 1;
01039    }
01040    strcat(lline_buffer,str);
01041 }
01042 
01043 static void CB_RESET(void )  
01044 { 
01045    comment_buffer[0] = 0; 
01046    lline_buffer[0] = 0;
01047 }
01048       
01049 /*! \brief Keep track of how many threads are currently trying to wait*() on
01050  *  a child process */
01051 static unsigned int safe_system_level = 0;
01052 static struct sigaction safe_system_prev_handler;
01053 
01054 /*! \brief NULL handler so we can collect the child exit status */
01055 static void _null_sig_handler(int sig)
01056 {
01057 
01058 }
01059 
01060 static struct sigaction null_sig_handler = {
01061    .sa_handler = _null_sig_handler,
01062    .sa_flags = SA_RESTART,
01063 };
01064 
01065 void ast_replace_sigchld(void);
01066 
01067 void ast_replace_sigchld(void)
01068 {
01069    unsigned int level;
01070 
01071    level = safe_system_level++;
01072 
01073    /* only replace the handler if it has not already been done */
01074    if (level == 0) {
01075       sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
01076    }
01077 }
01078 
01079 void ast_unreplace_sigchld(void);
01080 
01081 void ast_unreplace_sigchld(void)
01082 {
01083    unsigned int level;
01084 
01085    level = --safe_system_level;
01086 
01087    /* only restore the handler if we are the last one */
01088    if (level == 0) {
01089       sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
01090    }
01091 }
01092 
01093 int ast_safe_system(const char *s);
01094 
01095 int ast_safe_system(const char *s)
01096 {
01097    pid_t pid;
01098 #ifdef HAVE_WORKING_FORK
01099    int x;
01100 #endif
01101    int res;
01102    int status;
01103 
01104 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
01105    ast_replace_sigchld();
01106 
01107 #ifdef HAVE_WORKING_FORK
01108    pid = fork();
01109 #else
01110    pid = vfork();
01111 #endif   
01112 
01113    if (pid == 0) {
01114 #ifdef HAVE_WORKING_FORK
01115       /* Close file descriptors and launch system command */
01116       for (x = STDERR_FILENO + 1; x < 4096; x++)
01117          close(x);
01118 #endif
01119       execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
01120       _exit(1);
01121    } else if (pid > 0) {
01122       for(;;) {
01123          res = waitpid(pid, &status, 0);
01124          if (res > -1) {
01125             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
01126             break;
01127          } else if (errno != EINTR) 
01128             break;
01129       }
01130    } else {
01131       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
01132       res = -1;
01133    }
01134 
01135    ast_unreplace_sigchld();
01136 #else
01137    res = -1;
01138 #endif
01139 
01140    return res;
01141 }
01142 
01143 static struct ast_comment *ALLOC_COMMENT(const char *buffer)
01144 { 
01145    struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
01146    strcpy(x->cmt, buffer);
01147    return x;
01148 }
01149 
01150 static struct ast_config_map {
01151    struct ast_config_map *next;
01152    char *name;
01153    char *driver;
01154    char *database;
01155    char *table;
01156    char stuff[0];
01157 } *config_maps = NULL;
01158 
01159 static struct ast_config_engine *config_engine_list;
01160 
01161 #define MAX_INCLUDE_LEVEL 10
01162 
01163 
01164 struct ast_category {
01165    char name[80];
01166    int ignored;         /*!< do not let user of the config see this category */
01167    int include_level;   
01168     char *file;                /*!< the file name from whence this declaration was read */
01169     int lineno;
01170    struct ast_comment *precomments;
01171    struct ast_comment *sameline;
01172    struct ast_variable *root;
01173    struct ast_variable *last;
01174    struct ast_category *next;
01175 };
01176 
01177 struct ast_config {
01178    struct ast_category *root;
01179    struct ast_category *last;
01180    struct ast_category *current;
01181    struct ast_category *last_browse;      /*!< used to cache the last category supplied via category_browse */
01182    int include_level;
01183    int max_include_level;
01184     struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
01185 };
01186 
01187 struct ast_config_include {
01188    char *include_location_file;     /*!< file name in which the include occurs */
01189    int  include_location_lineno;    /*!< lineno where include occurred */
01190    int  exec;                       /*!< set to non-zero if itsa #exec statement */
01191    char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
01192    char *included_file;             /*!< file name included */
01193    int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
01194                               we explode the instances and will include those-- so all entries will be unique */
01195    int output;                      /*!< a flag to indicate if the inclusion has been output */
01196    struct ast_config_include *next; /*!< ptr to next inclusion in the list */
01197 };
01198 
01199 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);
01200 typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
01201 typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
01202 typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
01203 
01204 /*! \brief Configuration engine structure, used to define realtime drivers */
01205 struct ast_config_engine {
01206    char *name;
01207    config_load_func *load_func;
01208    realtime_var_get *realtime_func;
01209    realtime_multi_get *realtime_multi_func;
01210    realtime_update *update_func;
01211    struct ast_config_engine *next;
01212 };
01213 
01214 static struct ast_config_engine *config_engine_list;
01215 
01216 /* taken from strings.h */
01217 
01218 static force_inline int ast_strlen_zero(const char *s)
01219 {
01220    return (!s || (*s == '\0'));
01221 }
01222 
01223 #define S_OR(a, b)   (!ast_strlen_zero(a) ? (a) : (b))
01224 
01225 AST_INLINE_API(
01226 void ast_copy_string(char *dst, const char *src, size_t size),
01227 {
01228    while (*src && size) {
01229       *dst++ = *src++;
01230       size--;
01231    }
01232    if (__builtin_expect(!size, 0))
01233       dst--;
01234    *dst = '\0';
01235 }
01236 )
01237 
01238 AST_INLINE_API(
01239 char *ast_skip_blanks(const char *str),
01240 {
01241    while (*str && *str < 33)
01242       str++;
01243    return (char *)str;
01244 }
01245 )
01246 
01247 /*!
01248   \brief Trims trailing whitespace characters from a string.
01249   \param ast_trim_blanks function being used
01250   \param str the input string
01251   \return a pointer to the modified string
01252  */
01253 AST_INLINE_API(
01254 char *ast_trim_blanks(char *str),
01255 {
01256    char *work = str;
01257 
01258    if (work) {
01259       work += strlen(work) - 1;
01260       /* It's tempting to only want to erase after we exit this loop, 
01261          but since ast_trim_blanks *could* receive a constant string
01262          (which we presumably wouldn't have to touch), we shouldn't
01263          actually set anything unless we must, and it's easier just
01264          to set each position to \0 than to keep track of a variable
01265          for it */
01266       while ((work >= str) && *work < 33)
01267          *(work--) = '\0';
01268    }
01269    return str;
01270 }
01271 )
01272 
01273 /*!
01274   \brief Strip leading/trailing whitespace from a string.
01275   \param s The string to be stripped (will be modified).
01276   \return The stripped string.
01277 
01278   This functions strips all leading and trailing whitespace
01279   characters from the input string, and returns a pointer to
01280   the resulting string. The string is modified in place.
01281 */
01282 AST_INLINE_API(
01283 char *ast_strip(char *s),
01284 {
01285    s = ast_skip_blanks(s);
01286    if (s)
01287       ast_trim_blanks(s);
01288    return s;
01289 } 
01290 )
01291 
01292 
01293 /* from config.h */
01294 
01295 struct ast_variable {
01296    char *name;
01297    char *value;
01298    char *file;
01299    int lineno;
01300    int object;    /*!< 0 for variable, 1 for object */
01301    int blanklines;   /*!< Number of blanklines following entry */
01302    struct ast_comment *precomments;
01303    struct ast_comment *sameline;
01304    struct ast_variable *next;
01305    char stuff[0];
01306 };
01307 
01308 static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
01309 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);
01310 
01311 struct ast_config *localized_config_load_with_comments(const char *filename);
01312 static char *ast_category_browse(struct ast_config *config, const char *prev);
01313 static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
01314 static void ast_variables_destroy(struct ast_variable *v);
01315 static void ast_config_destroy(struct ast_config *cfg);
01316 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);
01317 static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
01318 void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
01319 
01320 static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
01321 
01322 static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
01323 {
01324    struct ast_variable *variable;
01325    int name_len = strlen(name) + 1; 
01326 
01327    if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
01328       variable->name = variable->stuff;
01329       variable->value = variable->stuff + name_len;      
01330       variable->file = variable->value + strlen(value) + 1;    
01331       strcpy(variable->name,name);
01332       strcpy(variable->value,value);
01333       strcpy(variable->file,filename);
01334    }
01335 
01336    return variable;
01337 }
01338 
01339 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)
01340 {
01341    /* a file should be included ONCE. Otherwise, if one of the instances is changed,
01342        then all be changed. -- how do we know to include it? -- Handling modified 
01343        instances is possible, I'd have
01344        to create a new master for each instance. */
01345    struct ast_config_include *inc;
01346     
01347    inc = ast_include_find(conf, included_file);
01348    if (inc)
01349    {
01350       inc->inclusion_count++;
01351       snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
01352       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);
01353    } else
01354       *real_included_file_name = 0;
01355    
01356    inc = ast_calloc(1,sizeof(struct ast_config_include));
01357    inc->include_location_file = ast_strdup(from_file);
01358    inc->include_location_lineno = from_lineno;
01359    if (!ast_strlen_zero(real_included_file_name))
01360       inc->included_file = ast_strdup(real_included_file_name);
01361    else
01362       inc->included_file = ast_strdup(included_file);
01363    
01364    inc->exec = is_exec;
01365    if (is_exec)
01366       inc->exec_file = ast_strdup(exec_file);
01367    
01368    /* attach this new struct to the conf struct */
01369    inc->next = conf->includes;
01370    conf->includes = inc;
01371     
01372    return inc;
01373 }
01374 
01375 void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
01376 {
01377    struct ast_config_include *incl;
01378    struct ast_category *cat;
01379    struct ast_variable *v;
01380     
01381    int from_len = strlen(from_file);
01382    int to_len = strlen(to_file);
01383     
01384    if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
01385       return;
01386    
01387    /* the manager code allows you to read in one config file, then
01388        write it back out under a different name. But, the new arrangement
01389       ties output lines to the file name. So, before you try to write
01390        the config file to disk, better riffle thru the data and make sure
01391        the file names are changed.
01392    */
01393    /* file names are on categories, includes (of course), and on variables. So,
01394       traverse all this and swap names */
01395    
01396    for (incl = conf->includes; incl; incl=incl->next) {
01397       if (strcmp(incl->include_location_file,from_file) == 0) {
01398          if (from_len >= to_len)
01399             strcpy(incl->include_location_file, to_file);
01400          else {
01401             free(incl->include_location_file);
01402             incl->include_location_file = strdup(to_file);
01403          }
01404       }
01405    }
01406    for (cat = conf->root; cat; cat = cat->next) {
01407       if (strcmp(cat->file,from_file) == 0) {
01408          if (from_len >= to_len)
01409             strcpy(cat->file, to_file);
01410          else {
01411             free(cat->file);
01412             cat->file = strdup(to_file);
01413          }
01414       }
01415       for (v = cat->root; v; v = v->next) {
01416          if (strcmp(v->file,from_file) == 0) {
01417             if (from_len >= to_len)
01418                strcpy(v->file, to_file);
01419             else {
01420                free(v->file);
01421                v->file = strdup(to_file);
01422             }
01423          }
01424       }
01425    }
01426 }
01427 
01428 static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
01429 {
01430    struct ast_config_include *x;
01431    for (x=conf->includes;x;x=x->next)
01432    {
01433       if (strcmp(x->included_file,included_file) == 0)
01434          return x;
01435    }
01436    return 0;
01437 }
01438 
01439 
01440 static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
01441 
01442 static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
01443 {
01444    if (!variable)
01445       return;
01446    if (category->last)
01447       category->last->next = variable;
01448    else
01449       category->root = variable;
01450    category->last = variable;
01451    while (category->last->next)
01452       category->last = category->last->next;
01453 }
01454 
01455 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
01456 
01457 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
01458 {
01459    struct ast_category *cat;
01460 
01461    /* try exact match first, then case-insensitive match */
01462    for (cat = config->root; cat; cat = cat->next) {
01463       if (cat->name == category_name && (ignored || !cat->ignored))
01464          return cat;
01465    }
01466 
01467    for (cat = config->root; cat; cat = cat->next) {
01468       if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
01469          return cat;
01470    }
01471 
01472    return NULL;
01473 }
01474 
01475 static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
01476 {
01477    return category_get(config, category_name, 0);
01478 }
01479 
01480 static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
01481 {
01482    struct ast_category *cat = NULL;
01483 
01484    if (category && config->last_browse && (config->last_browse->name == category))
01485       cat = config->last_browse;
01486    else
01487       cat = ast_category_get(config, category);
01488 
01489    return (cat) ? cat->root : NULL;
01490 }
01491 
01492 static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
01493 {
01494    struct ast_variable *v;
01495 
01496    if (category) {
01497       for (v = ast_variable_browse(config, category); v; v = v->next) {
01498          if (!strcasecmp(variable, v->name))
01499             return v->value;
01500       }
01501    } else {
01502       struct ast_category *cat;
01503 
01504       for (cat = config->root; cat; cat = cat->next)
01505          for (v = cat->root; v; v = v->next)
01506             if (!strcasecmp(variable, v->name))
01507                return v->value;
01508    }
01509 
01510    return NULL;
01511 }
01512 
01513 static struct ast_variable *variable_clone(const struct ast_variable *old)
01514 {
01515    struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
01516 
01517    if (new) {
01518       new->lineno = old->lineno;
01519       new->object = old->object;
01520       new->blanklines = old->blanklines;
01521       /* TODO: clone comments? */
01522    }
01523 
01524    return new;
01525 }
01526  
01527 static void ast_variables_destroy(struct ast_variable *v)
01528 {
01529    struct ast_variable *vn;
01530 
01531    while (v) {
01532       vn = v;
01533       v = v->next;
01534       free(vn);
01535    }
01536 }
01537 
01538 static void ast_includes_destroy(struct ast_config_include *incls)
01539 {
01540    struct ast_config_include *incl,*inclnext;
01541     
01542    for (incl=incls; incl; incl = inclnext) {
01543       inclnext = incl->next;
01544       if (incl->include_location_file)
01545          free(incl->include_location_file);
01546       if (incl->exec_file)
01547          free(incl->exec_file);
01548       if (incl->included_file)
01549          free(incl->included_file);
01550       free(incl);
01551    }
01552 }
01553 
01554 static void ast_config_destroy(struct ast_config *cfg)
01555 {
01556    struct ast_category *cat, *catn;
01557 
01558    if (!cfg)
01559       return;
01560 
01561    ast_includes_destroy(cfg->includes);
01562    
01563    cat = cfg->root;
01564    while (cat) {
01565       ast_variables_destroy(cat->root);
01566       catn = cat;
01567       cat = cat->next;
01568       free(catn);
01569    }
01570    free(cfg);
01571 }
01572 
01573 enum ast_option_flags {
01574    /*! Allow \#exec in config files */
01575    AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
01576    /*! Do not fork() */
01577    AST_OPT_FLAG_NO_FORK = (1 << 1),
01578    /*! Keep quiet */
01579    AST_OPT_FLAG_QUIET = (1 << 2),
01580    /*! Console mode */
01581    AST_OPT_FLAG_CONSOLE = (1 << 3),
01582    /*! Run in realtime Linux priority */
01583    AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
01584    /*! Initialize keys for RSA authentication */
01585    AST_OPT_FLAG_INIT_KEYS = (1 << 5),
01586    /*! Remote console */
01587    AST_OPT_FLAG_REMOTE = (1 << 6),
01588    /*! Execute an asterisk CLI command upon startup */
01589    AST_OPT_FLAG_EXEC = (1 << 7),
01590    /*! Don't use termcap colors */
01591    AST_OPT_FLAG_NO_COLOR = (1 << 8),
01592    /*! Are we fully started yet? */
01593    AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
01594    /*! Trascode via signed linear */
01595    AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
01596    /*! Dump core on a seg fault */
01597    AST_OPT_FLAG_DUMP_CORE = (1 << 12),
01598    /*! Cache sound files */
01599    AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
01600    /*! Display timestamp in CLI verbose output */
01601    AST_OPT_FLAG_TIMESTAMP = (1 << 14),
01602    /*! Override config */
01603    AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
01604    /*! Reconnect */
01605    AST_OPT_FLAG_RECONNECT = (1 << 16),
01606    /*! Transmit Silence during Record() and DTMF Generation */
01607    AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
01608    /*! Suppress some warnings */
01609    AST_OPT_FLAG_DONT_WARN = (1 << 18),
01610    /*! End CDRs before the 'h' extension */
01611    AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
01612    /*! Always fork, even if verbose or debug settings are non-zero */
01613    AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
01614    /*! Disable log/verbose output to remote consoles */
01615    AST_OPT_FLAG_MUTE = (1 << 22),
01616    /*! There is a per-file debug setting */
01617    AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
01618    /*! There is a per-file verbose setting */
01619    AST_OPT_FLAG_VERBOSE_FILE = (1 << 24),
01620    /*! Terminal colors should be adjusted for a light-colored background */
01621    AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),
01622    /*! Count Initiated seconds in CDR's */
01623    AST_OPT_FLAG_INITIATED_SECONDS = (1 << 26),
01624    /*! Force black background */
01625    AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27),
01626 };
01627 
01628 /* options.h declares ast_options extern; I need it static? */
01629 #define AST_CACHE_DIR_LEN  512
01630 #define AST_FILENAME_MAX   80
01631 
01632 /*! These are the options that set by default when Asterisk starts */
01633 #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
01634 
01635 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
01636 
01637 #define ast_opt_exec_includes    ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
01638 #define ast_opt_no_fork       ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
01639 #define ast_opt_quiet         ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
01640 #define ast_opt_console       ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
01641 #define ast_opt_high_priority    ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
01642 #define ast_opt_init_keys     ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
01643 #define ast_opt_remote        ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
01644 #define ast_opt_exec       ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
01645 #define ast_opt_no_color      ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
01646 #define ast_fully_booted      ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
01647 #define ast_opt_transcode_via_slin  ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
01648 #define ast_opt_priority_jumping ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
01649 #define ast_opt_dump_core     ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
01650 #define ast_opt_cache_record_files  ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
01651 #define ast_opt_timestamp     ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
01652 #define ast_opt_override_config     ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
01653 #define ast_opt_reconnect     ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
01654 #define ast_opt_transmit_silence ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
01655 #define ast_opt_dont_warn     ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
01656 #define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
01657 #define ast_opt_always_fork      ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
01658 #define ast_opt_mute       ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
01659 
01660 extern int option_verbose;
01661 extern int option_debug;      /*!< Debugging */
01662 extern int ast_option_maxcalls;     /*!< Maximum number of simultaneous channels */
01663 extern double ast_option_maxload;
01664 extern char ast_defaultlanguage[];
01665 
01666 extern pid_t ast_mainpid;
01667 
01668 extern char record_cache_dir[AST_CACHE_DIR_LEN];
01669 extern char debug_filename[AST_FILENAME_MAX];
01670 
01671 extern int ast_language_is_prefix;
01672 
01673 
01674 
01675 /* linkedlists.h */
01676 
01677 /*!
01678   \brief Write locks a list.
01679   \param head This is a pointer to the list head structure
01680 
01681   This macro attempts to place an exclusive write lock in the
01682   list head structure pointed to by head.
01683   Returns non-zero on success, 0 on failure
01684 */
01685 #define AST_RWLIST_WRLOCK(head)                                         \
01686         ast_rwlock_wrlock(&(head)->lock)
01687 
01688 /*!
01689   \brief Read locks a list.
01690   \param head This is a pointer to the list head structure
01691 
01692   This macro attempts to place a read lock in the
01693   list head structure pointed to by head.
01694   Returns non-zero on success, 0 on failure
01695 */
01696 #define AST_RWLIST_RDLOCK(head)                                         \
01697         ast_rwlock_rdlock(&(head)->lock)
01698    
01699 /*!
01700   \brief Attempts to unlock a read/write based list.
01701   \param head This is a pointer to the list head structure
01702 
01703   This macro attempts to remove a read or write lock from the
01704   list head structure pointed to by head. If the list
01705   was not locked by this thread, this macro has no effect.
01706 */
01707 #define AST_RWLIST_UNLOCK(head)                                         \
01708         ast_rwlock_unlock(&(head)->lock)
01709 
01710 /*!
01711   \brief Defines a structure to be used to hold a list of specified type.
01712   \param name This will be the name of the defined structure.
01713   \param type This is the type of each list entry.
01714 
01715   This macro creates a structure definition that can be used
01716   to hold a list of the entries of type \a type. It does not actually
01717   declare (allocate) a structure; to do that, either follow this
01718   macro with the desired name of the instance you wish to declare,
01719   or use the specified \a name to declare instances elsewhere.
01720 
01721   Example usage:
01722   \code
01723   static AST_LIST_HEAD(entry_list, entry) entries;
01724   \endcode
01725 
01726   This would define \c struct \c entry_list, and declare an instance of it named
01727   \a entries, all intended to hold a list of type \c struct \c entry.
01728 */
01729 #define AST_LIST_HEAD(name, type)               \
01730 struct name {                       \
01731    struct type *first;                 \
01732    struct type *last;                  \
01733    ast_mutex_t lock;                \
01734 }
01735 
01736 /*!
01737   \brief Defines a structure to be used to hold a read/write list of specified type.
01738   \param name This will be the name of the defined structure.
01739   \param type This is the type of each list entry.
01740 
01741   This macro creates a structure definition that can be used
01742   to hold a list of the entries of type \a type. It does not actually
01743   declare (allocate) a structure; to do that, either follow this
01744   macro with the desired name of the instance you wish to declare,
01745   or use the specified \a name to declare instances elsewhere.
01746 
01747   Example usage:
01748   \code
01749   static AST_RWLIST_HEAD(entry_list, entry) entries;
01750   \endcode
01751 
01752   This would define \c struct \c entry_list, and declare an instance of it named
01753   \a entries, all intended to hold a list of type \c struct \c entry.
01754 */
01755 #define AST_RWLIST_HEAD(name, type)                                     \
01756 struct name {                                                           \
01757         struct type *first;                                             \
01758         struct type *last;                                              \
01759         ast_rwlock_t lock;                                              \
01760 }
01761 
01762 /*!
01763   \brief Defines a structure to be used to hold a list of specified type (with no lock).
01764   \param name This will be the name of the defined structure.
01765   \param type This is the type of each list entry.
01766 
01767   This macro creates a structure definition that can be used
01768   to hold a list of the entries of type \a type. It does not actually
01769   declare (allocate) a structure; to do that, either follow this
01770   macro with the desired name of the instance you wish to declare,
01771   or use the specified \a name to declare instances elsewhere.
01772 
01773   Example usage:
01774   \code
01775   static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
01776   \endcode
01777 
01778   This would define \c struct \c entry_list, and declare an instance of it named
01779   \a entries, all intended to hold a list of type \c struct \c entry.
01780 */
01781 #define AST_LIST_HEAD_NOLOCK(name, type)           \
01782 struct name {                       \
01783    struct type *first;                 \
01784    struct type *last;                  \
01785 }
01786 
01787 /*!
01788   \brief Defines initial values for a declaration of AST_LIST_HEAD
01789 */
01790 #define AST_LIST_HEAD_INIT_VALUE {     \
01791    .first = NULL,             \
01792    .last = NULL,              \
01793    .lock = AST_MUTEX_INIT_VALUE,       \
01794    }
01795 
01796 /*!
01797   \brief Defines initial values for a declaration of AST_RWLIST_HEAD
01798 */
01799 #define AST_RWLIST_HEAD_INIT_VALUE      {               \
01800         .first = NULL,                                  \
01801         .last = NULL,                                   \
01802         .lock = AST_RWLOCK_INIT_VALUE,                  \
01803         }
01804 
01805 /*!
01806   \brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
01807 */
01808 #define AST_LIST_HEAD_NOLOCK_INIT_VALUE   {  \
01809    .first = NULL,             \
01810    .last = NULL,              \
01811    }
01812 
01813 /*!
01814   \brief Defines a structure to be used to hold a list of specified type, statically initialized.
01815   \param name This will be the name of the defined structure.
01816   \param type This is the type of each list entry.
01817 
01818   This macro creates a structure definition that can be used
01819   to hold a list of the entries of type \a type, and allocates an instance
01820   of it, initialized to be empty.
01821 
01822   Example usage:
01823   \code
01824   static AST_LIST_HEAD_STATIC(entry_list, entry);
01825   \endcode
01826 
01827   This would define \c struct \c entry_list, intended to hold a list of
01828   type \c struct \c entry.
01829 */
01830 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
01831 #define AST_LIST_HEAD_STATIC(name, type)           \
01832 struct name {                       \
01833    struct type *first;                 \
01834    struct type *last;                  \
01835    ast_mutex_t lock;                \
01836 } name;                          \
01837 static void  __attribute__((constructor)) init_##name(void)    \
01838 {                          \
01839         AST_LIST_HEAD_INIT(&name);              \
01840 }                          \
01841 static void  __attribute__((destructor)) fini_##name(void)     \
01842 {                          \
01843         AST_LIST_HEAD_DESTROY(&name);              \
01844 }                          \
01845 struct __dummy_##name
01846 #else
01847 #define AST_LIST_HEAD_STATIC(name, type)           \
01848 struct name {                       \
01849    struct type *first;                 \
01850    struct type *last;                  \
01851    ast_mutex_t lock;                \
01852 } name = AST_LIST_HEAD_INIT_VALUE
01853 #endif
01854 
01855 /*!
01856   \brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
01857   \param name This will be the name of the defined structure.
01858   \param type This is the type of each list entry.
01859 
01860   This macro creates a structure definition that can be used
01861   to hold a list of the entries of type \a type, and allocates an instance
01862   of it, initialized to be empty.
01863 
01864   Example usage:
01865   \code
01866   static AST_RWLIST_HEAD_STATIC(entry_list, entry);
01867   \endcode
01868 
01869   This would define \c struct \c entry_list, intended to hold a list of
01870   type \c struct \c entry.
01871 */
01872 #ifndef AST_RWLOCK_INIT_VALUE
01873 #define AST_RWLIST_HEAD_STATIC(name, type)                              \
01874 struct name {                                                           \
01875         struct type *first;                                             \
01876         struct type *last;                                              \
01877         ast_rwlock_t lock;                                              \
01878 } name;                                                                 \
01879 static void  __attribute__((constructor)) init_##name(void)            \
01880 {                                                                       \
01881         AST_RWLIST_HEAD_INIT(&name);                                    \
01882 }                                                                       \
01883 static void  __attribute__((destructor)) fini_##name(void)             \
01884 {                                                                       \
01885         AST_RWLIST_HEAD_DESTROY(&name);                                 \
01886 }                                                                       \
01887 struct __dummy_##name
01888 #else
01889 #define AST_RWLIST_HEAD_STATIC(name, type)                              \
01890 struct name {                                                           \
01891         struct type *first;                                             \
01892         struct type *last;                                              \
01893         ast_rwlock_t lock;                                              \
01894 } name = AST_RWLIST_HEAD_INIT_VALUE
01895 #endif
01896 
01897 /*!
01898   \brief Defines a structure to be used to hold a list of specified type, statically initialized.
01899 
01900   This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
01901 */
01902 #define AST_LIST_HEAD_NOLOCK_STATIC(name, type)          \
01903 struct name {                       \
01904    struct type *first;                 \
01905    struct type *last;                  \
01906 } name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
01907 
01908 /*!
01909   \brief Initializes a list head structure with a specified first entry.
01910   \param head This is a pointer to the list head structure
01911   \param entry pointer to the list entry that will become the head of the list
01912 
01913   This macro initializes a list head structure by setting the head
01914   entry to the supplied value and recreating the embedded lock.
01915 */
01916 #define AST_LIST_HEAD_SET(head, entry) do {           \
01917    (head)->first = (entry);               \
01918    (head)->last = (entry);                \
01919    ast_mutex_init(&(head)->lock);               \
01920 } while (0)
01921 
01922 /*!
01923   \brief Initializes an rwlist head structure with a specified first entry.
01924   \param head This is a pointer to the list head structure
01925   \param entry pointer to the list entry that will become the head of the list
01926 
01927   This macro initializes a list head structure by setting the head
01928   entry to the supplied value and recreating the embedded lock.
01929 */
01930 #define AST_RWLIST_HEAD_SET(head, entry) do {                           \
01931         (head)->first = (entry);                                        \
01932         (head)->last = (entry);                                         \
01933         ast_rwlock_init(&(head)->lock);                                 \
01934 } while (0)
01935 
01936 /*!
01937   \brief Initializes a list head structure with a specified first entry.
01938   \param head This is a pointer to the list head structure
01939   \param entry pointer to the list entry that will become the head of the list
01940 
01941   This macro initializes a list head structure by setting the head
01942   entry to the supplied value.
01943 */
01944 #define AST_LIST_HEAD_SET_NOLOCK(head, entry) do {       \
01945    (head)->first = (entry);               \
01946    (head)->last = (entry);                \
01947 } while (0)
01948 
01949 /*!
01950   \brief Declare a forward link structure inside a list entry.
01951   \param type This is the type of each list entry.
01952 
01953   This macro declares a structure to be used to link list entries together.
01954   It must be used inside the definition of the structure named in
01955   \a type, as follows:
01956 
01957   \code
01958   struct list_entry {
01959    ...
01960    AST_LIST_ENTRY(list_entry) list;
01961   }
01962   \endcode
01963 
01964   The field name \a list here is arbitrary, and can be anything you wish.
01965 */
01966 #define AST_LIST_ENTRY(type)                 \
01967 struct {                      \
01968    struct type *next;                  \
01969 }
01970 
01971 #define AST_RWLIST_ENTRY AST_LIST_ENTRY
01972  
01973 /*!
01974   \brief Returns the first entry contained in a list.
01975   \param head This is a pointer to the list head structure
01976  */
01977 #define  AST_LIST_FIRST(head) ((head)->first)
01978 
01979 #define AST_RWLIST_FIRST AST_LIST_FIRST
01980 
01981 /*!
01982   \brief Returns the last entry contained in a list.
01983   \param head This is a pointer to the list head structure
01984  */
01985 #define  AST_LIST_LAST(head)  ((head)->last)
01986 
01987 #define AST_RWLIST_LAST AST_LIST_LAST
01988 
01989 /*!
01990   \brief Returns the next entry in the list after the given entry.
01991   \param elm This is a pointer to the current entry.
01992   \param field This is the name of the field (declared using AST_LIST_ENTRY())
01993   used to link entries of this list together.
01994 */
01995 #define AST_LIST_NEXT(elm, field)   ((elm)->field.next)
01996 
01997 #define AST_RWLIST_NEXT AST_LIST_NEXT
01998 
01999 /*!
02000   \brief Checks whether the specified list contains any entries.
02001   \param head This is a pointer to the list head structure
02002 
02003   Returns non-zero if the list has entries, zero if not.
02004  */
02005 #define  AST_LIST_EMPTY(head) (AST_LIST_FIRST(head) == NULL)
02006 
02007 #define AST_RWLIST_EMPTY AST_LIST_EMPTY
02008 
02009 /*!
02010   \brief Loops over (traverses) the entries in a list.
02011   \param head This is a pointer to the list head structure
02012   \param var This is the name of the variable that will hold a pointer to the
02013   current list entry on each iteration. It must be declared before calling
02014   this macro.
02015   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02016   used to link entries of this list together.
02017 
02018   This macro is use to loop over (traverse) the entries in a list. It uses a
02019   \a for loop, and supplies the enclosed code with a pointer to each list
02020   entry as it loops. It is typically used as follows:
02021   \code
02022   static AST_LIST_HEAD(entry_list, list_entry) entries;
02023   ...
02024   struct list_entry {
02025    ...
02026    AST_LIST_ENTRY(list_entry) list;
02027   }
02028   ...
02029   struct list_entry *current;
02030   ...
02031   AST_LIST_TRAVERSE(&entries, current, list) {
02032      (do something with current here)
02033   }
02034   \endcode
02035   \warning If you modify the forward-link pointer contained in the \a current entry while
02036   inside the loop, the behavior will be unpredictable. At a minimum, the following
02037   macros will modify the forward-link pointer, and should not be used inside
02038   AST_LIST_TRAVERSE() against the entry pointed to by the \a current pointer without
02039   careful consideration of their consequences:
02040   \li AST_LIST_NEXT() (when used as an lvalue)
02041   \li AST_LIST_INSERT_AFTER()
02042   \li AST_LIST_INSERT_HEAD()
02043   \li AST_LIST_INSERT_TAIL()
02044 */
02045 #define AST_LIST_TRAVERSE(head,var,field)             \
02046    for((var) = (head)->first; (var); (var) = (var)->field.next)
02047 
02048 #define AST_RWLIST_TRAVERSE AST_LIST_TRAVERSE
02049 
02050 /*!
02051   \brief Loops safely over (traverses) the entries in a list.
02052   \param head This is a pointer to the list head structure
02053   \param var This is the name of the variable that will hold a pointer to the
02054   current list entry on each iteration. It must be declared before calling
02055   this macro.
02056   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02057   used to link entries of this list together.
02058 
02059   This macro is used to safely loop over (traverse) the entries in a list. It
02060   uses a \a for loop, and supplies the enclosed code with a pointer to each list
02061   entry as it loops. It is typically used as follows:
02062 
02063   \code
02064   static AST_LIST_HEAD(entry_list, list_entry) entries;
02065   ...
02066   struct list_entry {
02067    ...
02068    AST_LIST_ENTRY(list_entry) list;
02069   }
02070   ...
02071   struct list_entry *current;
02072   ...
02073   AST_LIST_TRAVERSE_SAFE_BEGIN(&entries, current, list) {
02074      (do something with current here)
02075   }
02076   AST_LIST_TRAVERSE_SAFE_END;
02077   \endcode
02078 
02079   It differs from AST_LIST_TRAVERSE() in that the code inside the loop can modify
02080   (or even free, after calling AST_LIST_REMOVE_CURRENT()) the entry pointed to by
02081   the \a current pointer without affecting the loop traversal.
02082 */
02083 #define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) {          \
02084    typeof((head)->first) __list_next;                 \
02085    typeof((head)->first) __list_prev = NULL;             \
02086    typeof((head)->first) __new_prev = NULL;              \
02087    for ((var) = (head)->first, __new_prev = (var),             \
02088          __list_next = (var) ? (var)->field.next : NULL;          \
02089         (var);                         \
02090         __list_prev = __new_prev, (var) = __list_next,            \
02091         __new_prev = (var),                     \
02092         __list_next = (var) ? (var)->field.next : NULL            \
02093        )
02094 
02095 #define AST_RWLIST_TRAVERSE_SAFE_BEGIN AST_LIST_TRAVERSE_SAFE_BEGIN
02096 
02097 /*!
02098   \brief Removes the \a current entry from a list during a traversal.
02099   \param head This is a pointer to the list head structure
02100   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02101   used to link entries of this list together.
02102 
02103   \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
02104   block; it is used to unlink the current entry from the list without affecting
02105   the list traversal (and without having to re-traverse the list to modify the
02106   previous entry, if any).
02107  */
02108 #define AST_LIST_REMOVE_CURRENT(head, field)                \
02109    __new_prev->field.next = NULL;                     \
02110    __new_prev = __list_prev;                    \
02111    if (__list_prev)                       \
02112       __list_prev->field.next = __list_next;             \
02113    else                             \
02114       (head)->first = __list_next;                 \
02115    if (!__list_next)                      \
02116       (head)->last = __list_prev;
02117 
02118 #define AST_RWLIST_REMOVE_CURRENT AST_LIST_REMOVE_CURRENT
02119 
02120 /*!
02121   \brief Inserts a list entry before the current entry during a traversal.
02122   \param head This is a pointer to the list head structure
02123   \param elm This is a pointer to the entry to be inserted.
02124   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02125   used to link entries of this list together.
02126 
02127   \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
02128   block.
02129  */
02130 #define AST_LIST_INSERT_BEFORE_CURRENT(head, elm, field) do {     \
02131    if (__list_prev) {                  \
02132       (elm)->field.next = __list_prev->field.next;    \
02133       __list_prev->field.next = elm;            \
02134    } else {                   \
02135       (elm)->field.next = (head)->first;        \
02136       (head)->first = (elm);              \
02137    }                       \
02138    __new_prev = (elm);                 \
02139 } while (0)
02140 
02141 #define AST_RWLIST_INSERT_BEFORE_CURRENT AST_LIST_INSERT_BEFORE_CURRENT
02142 
02143 /*!
02144   \brief Closes a safe loop traversal block.
02145  */
02146 #define AST_LIST_TRAVERSE_SAFE_END  }
02147 
02148 #define AST_RWLIST_TRAVERSE_SAFE_END AST_LIST_TRAVERSE_SAFE_END
02149 
02150 /*!
02151   \brief Initializes a list head structure.
02152   \param head This is a pointer to the list head structure
02153 
02154   This macro initializes a list head structure by setting the head
02155   entry to \a NULL (empty list) and recreating the embedded lock.
02156 */
02157 #define AST_LIST_HEAD_INIT(head) {              \
02158    (head)->first = NULL;                  \
02159    (head)->last = NULL;                \
02160    ast_mutex_init(&(head)->lock);               \
02161 }
02162 
02163 /*!
02164   \brief Initializes an rwlist head structure.
02165   \param head This is a pointer to the list head structure
02166 
02167   This macro initializes a list head structure by setting the head
02168   entry to \a NULL (empty list) and recreating the embedded lock.
02169 */
02170 #define AST_RWLIST_HEAD_INIT(head) {                                    \
02171         (head)->first = NULL;                                           \
02172         (head)->last = NULL;                                            \
02173         ast_rwlock_init(&(head)->lock);                                 \
02174 }
02175 
02176 /*!
02177   \brief Destroys an rwlist head structure.
02178   \param head This is a pointer to the list head structure
02179 
02180   This macro destroys a list head structure by setting the head
02181   entry to \a NULL (empty list) and destroying the embedded lock.
02182   It does not free the structure from memory.
02183 */
02184 #define AST_RWLIST_HEAD_DESTROY(head) {                                 \
02185         (head)->first = NULL;                                           \
02186         (head)->last = NULL;                                            \
02187         ast_rwlock_destroy(&(head)->lock);                              \
02188 }
02189 
02190 /*!
02191   \brief Initializes a list head structure.
02192   \param head This is a pointer to the list head structure
02193 
02194   This macro initializes a list head structure by setting the head
02195   entry to \a NULL (empty list). There is no embedded lock handling
02196   with this macro.
02197 */
02198 #define AST_LIST_HEAD_INIT_NOLOCK(head) {          \
02199    (head)->first = NULL;                  \
02200    (head)->last = NULL;                \
02201 }
02202 
02203 /*!
02204   \brief Inserts a list entry after a given entry.
02205   \param head This is a pointer to the list head structure
02206   \param listelm This is a pointer to the entry after which the new entry should
02207   be inserted.
02208   \param elm This is a pointer to the entry to be inserted.
02209   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02210   used to link entries of this list together.
02211  */
02212 #define AST_LIST_INSERT_AFTER(head, listelm, elm, field) do {     \
02213    (elm)->field.next = (listelm)->field.next;         \
02214    (listelm)->field.next = (elm);               \
02215    if ((head)->last == (listelm))               \
02216       (head)->last = (elm);               \
02217 } while (0)
02218 
02219 #define AST_RWLIST_INSERT_AFTER AST_LIST_INSERT_AFTER
02220 
02221 /*!
02222   \brief Inserts a list entry at the head of a list.
02223   \param head This is a pointer to the list head structure
02224   \param elm This is a pointer to the entry to be inserted.
02225   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02226   used to link entries of this list together.
02227  */
02228 #define AST_LIST_INSERT_HEAD(head, elm, field) do {         \
02229       (elm)->field.next = (head)->first;        \
02230       (head)->first = (elm);              \
02231       if (!(head)->last)               \
02232          (head)->last = (elm);            \
02233 } while (0)
02234 
02235 #define AST_RWLIST_INSERT_HEAD AST_LIST_INSERT_HEAD
02236 
02237 /*!
02238   \brief Appends a list entry to the tail of a list.
02239   \param head This is a pointer to the list head structure
02240   \param elm This is a pointer to the entry to be appended.
02241   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02242   used to link entries of this list together.
02243 
02244   Note: The link field in the appended entry is \b not modified, so if it is
02245   actually the head of a list itself, the entire list will be appended
02246   temporarily (until the next AST_LIST_INSERT_TAIL is performed).
02247  */
02248 #define AST_LIST_INSERT_TAIL(head, elm, field) do {         \
02249       if (!(head)->first) {                  \
02250       (head)->first = (elm);              \
02251       (head)->last = (elm);               \
02252       } else {                      \
02253       (head)->last->field.next = (elm);         \
02254       (head)->last = (elm);               \
02255       }                          \
02256 } while (0)
02257 
02258 #define AST_RWLIST_INSERT_TAIL AST_LIST_INSERT_TAIL
02259 
02260 /*!
02261   \brief Appends a whole list to the tail of a list.
02262   \param head This is a pointer to the list head structure
02263   \param list This is a pointer to the list to be appended.
02264   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02265   used to link entries of this list together.
02266  */
02267 #define AST_LIST_APPEND_LIST(head, list, field) do {        \
02268       if (!(head)->first) {                  \
02269       (head)->first = (list)->first;            \
02270       (head)->last = (list)->last;           \
02271       } else {                      \
02272       (head)->last->field.next = (list)->first;    \
02273       (head)->last = (list)->last;           \
02274       }                          \
02275 } while (0)
02276 
02277 #define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
02278 
02279 /*!
02280   \brief Removes and returns the head entry from a list.
02281   \param head This is a pointer to the list head structure
02282   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02283   used to link entries of this list together.
02284 
02285   Removes the head entry from the list, and returns a pointer to it.
02286   This macro is safe to call on an empty list.
02287  */
02288 #define AST_LIST_REMOVE_HEAD(head, field) ({          \
02289       typeof((head)->first) cur = (head)->first;      \
02290       if (cur) {                 \
02291          (head)->first = cur->field.next;    \
02292          cur->field.next = NULL;          \
02293          if ((head)->last == cur)         \
02294             (head)->last = NULL;       \
02295       }                    \
02296       cur;                    \
02297    })
02298 
02299 #define AST_RWLIST_REMOVE_HEAD AST_LIST_REMOVE_HEAD
02300 
02301 /*!
02302   \brief Removes a specific entry from a list.
02303   \param head This is a pointer to the list head structure
02304   \param elm This is a pointer to the entry to be removed.
02305   \param field This is the name of the field (declared using AST_LIST_ENTRY())
02306   used to link entries of this list together.
02307   \warning The removed entry is \b not freed nor modified in any way.
02308  */
02309 #define AST_LIST_REMOVE(head, elm, field) do {                \
02310    if ((head)->first == (elm)) {             \
02311       (head)->first = (elm)->field.next;        \
02312       if ((head)->last == (elm))       \
02313          (head)->last = NULL;       \
02314    } else {                      \
02315       typeof(elm) curelm = (head)->first;       \
02316       while (curelm && (curelm->field.next != (elm)))       \
02317          curelm = curelm->field.next;        \
02318       if (curelm) { \
02319          curelm->field.next = (elm)->field.next;         \
02320          if ((head)->last == (elm))          \
02321             (head)->last = curelm;           \
02322       } \
02323    }                       \
02324         (elm)->field.next = NULL;                                       \
02325 } while (0)
02326 
02327 #define AST_RWLIST_REMOVE AST_LIST_REMOVE
02328 
02329 /* chanvars.h */
02330 
02331 struct ast_var_t {
02332    AST_LIST_ENTRY(ast_var_t) entries;
02333    char *value;
02334    char name[0];
02335 };
02336 
02337 AST_LIST_HEAD_NOLOCK(varshead, ast_var_t);
02338 
02339 AST_RWLOCK_DEFINE_STATIC(globalslock);
02340 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
02341 
02342 
02343 /* IN CONFLICT: struct ast_var_t *ast_var_assign(const char *name, const char *value); */
02344 
02345 static struct ast_var_t *ast_var_assign(const char *name, const char *value);
02346 
02347 static void ast_var_delete(struct ast_var_t *var);
02348 
02349 /*from channel.h */
02350 #define AST_MAX_EXTENSION  80      /*!< Max length of an extension */
02351 
02352 
02353 /* from pbx.h */
02354 #define PRIORITY_HINT   -1 /*!< Special Priority for a hint */
02355 
02356 enum ast_extension_states {
02357    AST_EXTENSION_REMOVED = -2,   /*!< Extension removed */
02358    AST_EXTENSION_DEACTIVATED = -1,  /*!< Extension hint removed */
02359    AST_EXTENSION_NOT_INUSE = 0,  /*!< No device INUSE or BUSY  */
02360    AST_EXTENSION_INUSE = 1 << 0, /*!< One or more devices INUSE */
02361    AST_EXTENSION_BUSY = 1 << 1,  /*!< All devices BUSY */
02362    AST_EXTENSION_UNAVAILABLE = 1 << 2, /*!< All devices UNAVAILABLE/UNREGISTERED */
02363    AST_EXTENSION_RINGING = 1 << 3,  /*!< All devices RINGING */
02364    AST_EXTENSION_ONHOLD = 1 << 4,   /*!< All devices ONHOLD */
02365 };
02366 
02367 struct ast_custom_function {
02368    const char *name;    /*!< Name */
02369    const char *synopsis;      /*!< Short description for "show functions" */
02370    const char *desc;    /*!< Help text that explains it all */
02371    const char *syntax;     /*!< Syntax description */
02372    int (*read)(struct ast_channel *, const char *, char *, char *, size_t);   /*!< Read function, if read is supported */
02373    int (*write)(struct ast_channel *, const char *, char *, const char *);    /*!< Write function, if write is supported */
02374    AST_RWLIST_ENTRY(ast_custom_function) acflist;
02375 };
02376 
02377 typedef int (ast_switch_f)(struct ast_channel *chan, const char *context,
02378    const char *exten, int priority, const char *callerid, const char *data);
02379 
02380 struct ast_switch {
02381    AST_LIST_ENTRY(ast_switch) list;
02382    const char *name;       /*!< Name of the switch */
02383    const char *description;      /*!< Description of the switch */
02384    
02385    ast_switch_f *exists;
02386    ast_switch_f *canmatch;
02387    ast_switch_f *exec;
02388    ast_switch_f *matchmore;
02389 };
02390 
02391 
02392 static char *config_filename = "extensions.conf";
02393 static char *global_registrar = "conf2ael";
02394 static char userscontext[AST_MAX_EXTENSION] = "default";
02395 static int static_config = 0;
02396 static int write_protect_config = 1;
02397 static int autofallthrough_config = 0;
02398 static int clearglobalvars_config = 0;
02399 static void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
02400 
02401 
02402 /* stolen from callerid.c */
02403 
02404 /*! \brief Clean up phone string
02405  * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
02406  * Basically, remove anything that could be invalid in a pattern.
02407  */
02408 static void ast_shrink_phone_number(char *n)
02409 {
02410    int x, y=0;
02411    int bracketed = 0;
02412 
02413    for (x=0; n[x]; x++) {
02414       switch(n[x]) {
02415       case '[':
02416          bracketed++;
02417          n[y++] = n[x];
02418          break;
02419       case ']':
02420          bracketed--;
02421          n[y++] = n[x];
02422          break;
02423       case '-':
02424          if (bracketed)
02425             n[y++] = n[x];
02426          break;
02427       case '.':
02428          if (!n[x+1])
02429             n[y++] = n[x];
02430          break;
02431       default:
02432          if (!strchr("()", n[x]))
02433             n[y++] = n[x];
02434       }
02435    }
02436    n[y] = '\0';
02437 }
02438 
02439 
02440 /* stolen from chanvars.c */
02441 
02442 static const char *ast_var_name(const struct ast_var_t *var)
02443 {
02444    const char *name;
02445 
02446    if (var == NULL || (name = var->name) == NULL)
02447       return NULL;
02448    /* Return the name without the initial underscores */
02449    if (name[0] == '_') {
02450       name++;
02451       if (name[0] == '_')
02452          name++;
02453    }
02454    return name;
02455 }
02456 
02457 /* experiment 1: see if it's easier just to use existing config code
02458  *               to read in the extensions.conf file. In this scenario, 
02459                  I have to rip/copy code from other modules, because they
02460                  are staticly declared as-is. A solution would be to move
02461                  the ripped code to another location and make them available
02462                  to other modules and standalones */
02463 
02464 /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
02465 
02466 static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
02467 {
02468    va_list vars;
02469    va_start(vars,fmt);
02470    
02471    printf("LOG: lev:%d file:%s  line:%d func: %s  ",
02472          level, file, line, function);
02473    vprintf(fmt, vars);
02474    fflush(stdout);
02475    va_end(vars);
02476 }
02477 
02478 void __attribute__((format(printf, 1, 2))) ast_verbose(const char *fmt, ...)
02479 {
02480    va_list vars;
02481    va_start(vars,fmt);
02482    
02483    printf("VERBOSE: ");
02484    vprintf(fmt, vars);
02485    fflush(stdout);
02486    va_end(vars);
02487 }
02488 
02489 /* stolen from main/utils.c */
02490 static char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
02491 {
02492    char *dataPut = start;
02493    int inEscape = 0;
02494    int inQuotes = 0;
02495 
02496    for (; *start; start++) {
02497       if (inEscape) {
02498          *dataPut++ = *start;       /* Always goes verbatim */
02499          inEscape = 0;
02500       } else {
02501          if (*start == '\\') {
02502             inEscape = 1;      /* Do not copy \ into the data */
02503          } else if (*start == '\'') {
02504             inQuotes = 1 - inQuotes;   /* Do not copy ' into the data */
02505          } else {
02506             /* Replace , with |, unless in quotes */
02507             *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
02508          }
02509       }
02510    }
02511    if (start != dataPut)
02512       *dataPut = 0;
02513    return dataPut;
02514 }
02515 
02516 static int ast_true(const char *s)
02517 {
02518    if (ast_strlen_zero(s))
02519       return 0;
02520 
02521    /* Determine if this is a true value */
02522    if (!strcasecmp(s, "yes") ||
02523        !strcasecmp(s, "true") ||
02524        !strcasecmp(s, "y") ||
02525        !strcasecmp(s, "t") ||
02526        !strcasecmp(s, "1") ||
02527        !strcasecmp(s, "on"))
02528       return -1;
02529 
02530    return 0;
02531 }
02532 
02533 #define ONE_MILLION  1000000
02534 /*
02535  * put timeval in a valid range. usec is 0..999999
02536  * negative values are not allowed and truncated.
02537  */
02538 static struct timeval tvfix(struct timeval a)
02539 {
02540    if (a.tv_usec >= ONE_MILLION) {
02541       ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
02542          (long)a.tv_sec, (long int) a.tv_usec);
02543       a.tv_sec += a.tv_usec / ONE_MILLION;
02544       a.tv_usec %= ONE_MILLION;
02545    } else if (a.tv_usec < 0) {
02546       ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
02547          (long)a.tv_sec, (long int) a.tv_usec);
02548       a.tv_usec = 0;
02549    }
02550    return a;
02551 }
02552 
02553 struct timeval ast_tvadd(struct timeval a, struct timeval b);
02554 struct timeval ast_tvadd(struct timeval a, struct timeval b)
02555 {
02556    /* consistency checks to guarantee usec in 0..999999 */
02557    a = tvfix(a);
02558    b = tvfix(b);
02559    a.tv_sec += b.tv_sec;
02560    a.tv_usec += b.tv_usec;
02561    if (a.tv_usec >= ONE_MILLION) {
02562       a.tv_sec++;
02563       a.tv_usec -= ONE_MILLION;
02564    }
02565    return a;
02566 }
02567 
02568 struct timeval ast_tvsub(struct timeval a, struct timeval b);
02569 struct timeval ast_tvsub(struct timeval a, struct timeval b)
02570 {
02571    /* consistency checks to guarantee usec in 0..999999 */
02572    a = tvfix(a);
02573    b = tvfix(b);
02574    a.tv_sec -= b.tv_sec;
02575    a.tv_usec -= b.tv_usec;
02576    if (a.tv_usec < 0) {
02577       a.tv_sec-- ;
02578       a.tv_usec += ONE_MILLION;
02579    }
02580    return a;
02581 }
02582 #undef ONE_MILLION
02583 
02584 void ast_mark_lock_failed(void *lock_addr);
02585 void ast_mark_lock_failed(void *lock_addr)
02586 {
02587    /* Pretend to do something. */
02588 }
02589 
02590 /* stolen from pbx.c */
02591 #define VAR_BUF_SIZE 4096
02592 
02593 #define  VAR_NORMAL     1
02594 #define  VAR_SOFTTRAN   2
02595 #define  VAR_HARDTRAN   3
02596 
02597 #define BACKGROUND_SKIP    (1 << 0)
02598 #define BACKGROUND_NOANSWER   (1 << 1)
02599 #define BACKGROUND_MATCHEXTEN (1 << 2)
02600 #define BACKGROUND_PLAYBACK   (1 << 3)
02601 
02602 /*!
02603    \brief ast_exten: An extension
02604    The dialplan is saved as a linked list with each context
02605    having it's own linked list of extensions - one item per
02606    priority.
02607 */
02608 struct ast_exten {
02609    char *exten;         /*!< Extension name */
02610    int matchcid;        /*!< Match caller id ? */
02611    const char *cidmatch;      /*!< Caller id to match for this extension */
02612    int priority;        /*!< Priority */
02613    const char *label;      /*!< Label */
02614    struct ast_context *parent;   /*!< The context this extension belongs to  */
02615    const char *app;     /*!< Application to execute */
02616    struct ast_app *cached_app;     /*!< Cached location of application */
02617    void *data;       /*!< Data to use (arguments) */
02618    void (*datad)(void *);     /*!< Data destructor */
02619    struct ast_exten *peer;    /*!< Next higher priority with our extension */
02620    const char *registrar;     /*!< Registrar */
02621    struct ast_exten *next;    /*!< Extension with a greater ID */
02622    char stuff[0];
02623 };
02624 /* from pbx.h */
02625 typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
02626 struct ast_timing {
02627    int hastime;            /*!< If time construct exists */
02628    unsigned int monthmask;       /*!< Mask for month */
02629    unsigned int daymask;         /*!< Mask for date */
02630    unsigned int dowmask;         /*!< Mask for day of week (mon-sun) */
02631    unsigned int minmask[48];     /*!< Mask for minute */
02632    char *timezone;                 /*!< NULL, or zoneinfo style timezone */
02633 };
02634 /* end of pbx.h */
02635 /*! \brief ast_include: include= support in extensions.conf */
02636 struct ast_include {
02637    const char *name;
02638    const char *rname;         /*!< Context to include */
02639    const char *registrar;        /*!< Registrar */
02640    int hastime;            /*!< If time construct exists */
02641    struct ast_timing timing;               /*!< time construct */
02642    struct ast_include *next;     /*!< Link them together */
02643    char stuff[0];
02644 };
02645 
02646 /*! \brief ast_sw: Switch statement in extensions.conf */
02647 struct ast_sw {
02648    char *name;
02649    const char *registrar;        /*!< Registrar */
02650    char *data;          /*!< Data load */
02651    int eval;
02652    AST_LIST_ENTRY(ast_sw) list;
02653    char *tmpdata;
02654    char stuff[0];
02655 };
02656 
02657 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
02658 struct ast_ignorepat {
02659    const char *registrar;
02660    struct ast_ignorepat *next;
02661    char pattern[0];
02662 };
02663 
02664 /*! \brief ast_context: An extension context */
02665 struct ast_context {
02666    ast_rwlock_t lock;         /*!< A lock to prevent multiple threads from clobbering the context */
02667    struct ast_exten *root;       /*!< The root of the list of extensions */
02668    struct ast_context *next;     /*!< Link them together */
02669    struct ast_include *includes;    /*!< Include other contexts */
02670    struct ast_ignorepat *ignorepats;   /*!< Patterns for which to continue playing dialtone */
02671    const char *registrar;        /*!< Registrar */
02672    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   /*!< Alternative switches */
02673    ast_mutex_t macrolock;        /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
02674    char name[0];           /*!< Name of the context */
02675 };
02676 
02677 
02678 /*! \brief ast_app: A registered application */
02679 struct ast_app {
02680    int (*execute)(struct ast_channel *chan, void *data);
02681    const char *synopsis;         /*!< Synopsis text for 'show applications' */
02682    const char *description;      /*!< Description (help text) for 'show application &lt;name&gt;' */
02683    AST_RWLIST_ENTRY(ast_app) list;     /*!< Next app in list */
02684    void *module;        /*!< Module this app belongs to */
02685    char name[0];           /*!< Name of the application */
02686 };
02687 
02688 
02689 /*! \brief ast_state_cb: An extension state notify register item */
02690 struct ast_state_cb {
02691    int id;
02692    void *data;
02693    ast_state_cb_type callback;
02694    struct ast_state_cb *next;
02695 };
02696 
02697 /*! \brief Structure for dial plan hints
02698 
02699   \note Hints are pointers from an extension in the dialplan to one or
02700   more devices (tech/name) 
02701    - See \ref AstExtState
02702 */
02703 struct ast_hint {
02704    struct ast_exten *exten;   /*!< Extension */
02705    int laststate;          /*!< Last known state */
02706    struct ast_state_cb *callbacks;  /*!< Callback list for this extension */
02707    AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
02708 };
02709 
02710 struct store_hint {
02711    char *context;
02712    char *exten;
02713    struct ast_state_cb *callbacks;
02714    int laststate;
02715    AST_LIST_ENTRY(store_hint) list;
02716    char data[1];
02717 };
02718 
02719 AST_LIST_HEAD(store_hints, store_hint);
02720 
02721 #define STATUS_NO_CONTEXT  1
02722 #define STATUS_NO_EXTENSION   2
02723 #define STATUS_NO_PRIORITY 3
02724 #define STATUS_NO_LABEL    4
02725 #define STATUS_SUCCESS     5
02726 
02727 static struct ast_var_t *ast_var_assign(const char *name, const char *value)
02728 {  
02729    struct ast_var_t *var;
02730    int name_len = strlen(name) + 1;
02731    int value_len = strlen(value) + 1;
02732 
02733    if (!(var = ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char)))) {
02734       return NULL;
02735    }
02736 
02737    ast_copy_string(var->name, name, name_len);
02738    var->value = var->name + name_len;
02739    ast_copy_string(var->value, value, value_len);
02740    
02741    return var;
02742 }  
02743    
02744 static void ast_var_delete(struct ast_var_t *var)
02745 {
02746    free(var);
02747 }
02748 
02749 
02750 /* chopped this one off at the knees! */
02751 static int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
02752 {
02753 
02754    /* ast_log(LOG_ERROR, "Function %s not registered\n", function); we are not interested in the details here */
02755 
02756    return -1;
02757 }
02758 
02759 static unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
02760 {
02761    int argc;
02762    char *scan;
02763    int paren = 0, quote = 0;
02764 
02765    if (!buf || !array || !arraylen)
02766       return 0;
02767 
02768    memset(array, 0, arraylen * sizeof(*array));
02769 
02770    scan = buf;
02771 
02772    for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
02773       array[argc] = scan;
02774       for (; *scan; scan++) {
02775          if (*scan == '(')
02776             paren++;
02777          else if (*scan == ')') {
02778             if (paren)
02779                paren--;
02780          } else if (*scan == '"' && delim != '"') {
02781             quote = quote ? 0 : 1;
02782             /* Remove quote character from argument */
02783             memmove(scan, scan + 1, strlen(scan));
02784             scan--;
02785          } else if (*scan == '\\') {
02786             /* Literal character, don't parse */
02787             memmove(scan, scan + 1, strlen(scan));
02788          } else if ((*scan == delim) && !paren && !quote) {
02789             *scan++ = '\0';
02790             break;
02791          }
02792       }
02793    }
02794 
02795    if (*scan)
02796       array[argc++] = scan;
02797 
02798    return argc;
02799 }
02800 
02801 static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
02802 {
02803    struct ast_var_t *newvariable;
02804    struct varshead *headp;
02805    const char *nametail = name;
02806 
02807    /* XXX may need locking on the channel ? */
02808    if (name[strlen(name)-1] == ')') {
02809       char *function = ast_strdupa(name);
02810 
02811       ast_func_write(chan, function, value);
02812       return;
02813    }
02814 
02815    headp = &globals;
02816 
02817    /* For comparison purposes, we have to strip leading underscores */
02818    if (*nametail == '_') {
02819       nametail++;
02820       if (*nametail == '_')
02821          nametail++;
02822    }
02823 
02824    AST_LIST_TRAVERSE (headp, newvariable, entries) {
02825       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
02826          /* there is already such a variable, delete it */
02827          AST_LIST_REMOVE(headp, newvariable, entries);
02828          ast_var_delete(newvariable);
02829          break;
02830       }
02831    }
02832 
02833    if (value && (newvariable = ast_var_assign(name, value))) {
02834       if ((option_verbose > 1) && (headp == &globals))
02835          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
02836       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
02837    }
02838 
02839 }
02840 
02841 static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
02842 {
02843    char *name, *value, *mydata;
02844    int argc;
02845    char *argv[24];      /* this will only support a maximum of 24 variables being set in a single operation */
02846    int global = 0;
02847    int x;
02848 
02849    if (ast_strlen_zero(data)) {
02850       ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
02851       return 0;
02852    }
02853 
02854    mydata = ast_strdupa(data);
02855    argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
02856 
02857    /* check for a trailing flags argument */
02858    if ((argc > 1) && !strchr(argv[argc-1], '=')) {
02859       argc--;
02860       if (strchr(argv[argc], 'g'))
02861          global = 1;
02862    }
02863 
02864    for (x = 0; x < argc; x++) {
02865       name = argv[x];
02866       if ((value = strchr(name, '='))) {
02867          *value++ = '\0';
02868          pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
02869       } else
02870          ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
02871    }
02872 
02873    return(0);
02874 }
02875 
02876 int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data);
02877 
02878 int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
02879 {
02880    return pbx_builtin_setvar(chan, data);
02881 }
02882 
02883 
02884 /*! \brief Helper for get_range.
02885  * return the index of the matching entry, starting from 1.
02886  * If names is not supplied, try numeric values.
02887  */
02888 static int lookup_name(const char *s, char *const names[], int max)
02889 {
02890    int i;
02891 
02892    if (names && *s > '9') {
02893       for (i = 0; names[i]; i++) {
02894          if (!strcasecmp(s, names[i])) {
02895             return i;
02896          }
02897       }
02898    }
02899 
02900    /* Allow months and weekdays to be specified as numbers, as well */
02901    if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
02902       /* What the array offset would have been: "1" would be at offset 0 */
02903       return i - 1;
02904    }
02905    return -1; /* error return */
02906 }
02907 
02908 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
02909  * names, if supplied, is an array of names that should be mapped to numbers.
02910  */
02911 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
02912 {
02913    int start, end; /* start and ending position */
02914    unsigned int mask = 0;
02915    char *part;
02916 
02917    /* Check for whole range */
02918    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
02919       return (1 << max) - 1;
02920    }
02921 
02922    while ((part = strsep(&src, "&"))) {
02923       /* Get start and ending position */
02924       char *endpart = strchr(part, '-');
02925       if (endpart) {
02926          *endpart++ = '\0';
02927       }
02928       /* Find the start */
02929       if ((start = lookup_name(part, names, max)) < 0) {
02930          ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
02931          continue;
02932       }
02933       if (endpart) { /* find end of range */
02934          if ((end = lookup_name(endpart, names, max)) < 0) {
02935             ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
02936             continue;
02937          }
02938       } else {
02939          end = start;
02940       }
02941       /* Fill the mask. Remember that ranges are cyclic */
02942       mask |= (1 << end);   /* initialize with last element */
02943       while (start != end) {
02944          if (start >= max) {
02945             start = 0;
02946          }
02947          mask |= (1 << start);
02948          start++;
02949       }
02950    }
02951    return mask;
02952 }
02953 
02954 /*! \brief store a bitmask of valid times, one bit each 2 minute */
02955 static void get_timerange(struct ast_timing *i, char *times)
02956 {
02957    char *endpart, *part;
02958    int x;
02959    int st_h, st_m;
02960    int endh, endm;
02961    int minute_start, minute_end;
02962 
02963    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
02964    memset(i->minmask, 0, sizeof(i->minmask));
02965 
02966    /* 1-minute per bit */
02967    /* Star is all times */
02968    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
02969       /* 48, because each hour takes 2 integers; 30 bits each */
02970       for (x = 0; x < 48; x++) {
02971          i->minmask[x] = 0x3fffffff; /* 30 bits */
02972       }
02973       return;
02974    }
02975    /* Otherwise expect a range */
02976    while ((part = strsep(&times, "&"))) {
02977       if (!(endpart = strchr(part, '-'))) {
02978          if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
02979             ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
02980             continue;
02981          }
02982          i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
02983          continue;
02984       }
02985       *endpart++ = '\0';
02986       /* why skip non digits? Mostly to skip spaces */
02987       while (*endpart && !isdigit(*endpart)) {
02988          endpart++;
02989       }
02990       if (!*endpart) {
02991          ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
02992          continue;
02993       }
02994       if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
02995          ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
02996          continue;
02997       }
02998       if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
02999          ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
03000          continue;
03001       }
03002       minute_start = st_h * 60 + st_m;
03003       minute_end = endh * 60 + endm;
03004       /* Go through the time and enable each appropriate bit */
03005       for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
03006          i->minmask[x / 30] |= (1 << (x % 30));
03007       }
03008       /* Do the last one */
03009       i->minmask[x / 30] |= (1 << (x % 30));
03010    }
03011    /* All done */
03012    return;
03013 }
03014 
03015 static void null_datad(void *foo)
03016 {
03017 }
03018 
03019 /*! \brief Find realtime engine for realtime family */
03020 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz) 
03021 {
03022    struct ast_config_engine *eng, *ret = NULL;
03023    struct ast_config_map *map;
03024 
03025 
03026    for (map = config_maps; map; map = map->next) {
03027       if (!strcasecmp(family, map->name)) {
03028          if (database)
03029             ast_copy_string(database, map->database, dbsiz);
03030          if (table)
03031             ast_copy_string(table, map->table ? map->table : family, tabsiz);
03032          break;
03033       }
03034    }
03035 
03036    /* Check if the required driver (engine) exist */
03037    if (map) {
03038       for (eng = config_engine_list; !ret && eng; eng = eng->next) {
03039          if (!strcasecmp(eng->name, map->driver))
03040             ret = eng;
03041       }
03042    }
03043    
03044    
03045    /* if we found a mapping, but the engine is not available, then issue a warning */
03046    if (map && !ret)
03047       ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
03048    
03049    return ret;
03050 }
03051 
03052 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg);
03053 
03054 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
03055 {
03056    return cfg->current;
03057 }
03058 
03059 static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
03060 
03061 static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
03062 {
03063    struct ast_category *category;
03064 
03065    if ((category = ast_calloc(1, sizeof(*category))))
03066       ast_copy_string(category->name, name, sizeof(category->name));
03067    category->file = strdup(in_file);
03068    category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
03069    return category;
03070 }
03071 
03072 struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name);
03073 
03074 struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name)
03075 {
03076    return category_get(config, category_name, 0);
03077 }
03078 
03079 static void move_variables(struct ast_category *old, struct ast_category *new)
03080 {
03081    struct ast_variable *var = old->root;
03082    old->root = NULL;
03083 #if 1
03084    /* we can just move the entire list in a single op */
03085    ast_variable_append(new, var);
03086 #else
03087    while (var) {
03088       struct ast_variable *next = var->next;
03089       var->next = NULL;
03090       ast_variable_append(new, var);
03091       var = next;
03092    }
03093 #endif
03094 }
03095 
03096 static void inherit_category(struct ast_category *new, const struct ast_category *base)
03097 {
03098    struct ast_variable *var;
03099 
03100    for (var = base->root; var; var = var->next)
03101       ast_variable_append(new, variable_clone(var));
03102 }
03103 
03104 static void ast_category_append(struct ast_config *config, struct ast_category *category);
03105 
03106 static void ast_category_append(struct ast_config *config, struct ast_category *category)
03107 {
03108    if (config->last)
03109       config->last->next = category;
03110    else
03111       config->root = category;
03112    config->last = category;
03113    config->current = category;
03114 }
03115 
03116 static void ast_category_destroy(struct ast_category *cat);
03117 
03118 static void ast_category_destroy(struct ast_category *cat)
03119 {
03120    ast_variables_destroy(cat->root);
03121    if (cat->file)
03122       free(cat->file);
03123    
03124    free(cat);
03125 }
03126 
03127 static struct ast_config_engine text_file_engine = {
03128    .name = "text",
03129    .load_func = config_text_file_load,
03130 };
03131 
03132 
03133 static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file);
03134 
03135 static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file)
03136 {
03137    char db[256];
03138    char table[256];
03139    struct ast_config_engine *loader = &text_file_engine;
03140    struct ast_config *result; 
03141 
03142    if (cfg->include_level == cfg->max_include_level) {
03143       ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
03144       return NULL;
03145    }
03146 
03147    cfg->include_level++;
03148    /*  silence is golden!
03149       ast_log(LOG_WARNING, "internal loading file %s level=%d\n", filename, cfg->include_level);
03150    */
03151 
03152    if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
03153       struct ast_config_engine *eng;
03154 
03155       eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
03156 
03157 
03158       if (eng && eng->load_func) {
03159          loader = eng;
03160       } else {
03161          eng = find_engine("global", db, sizeof(db), table, sizeof(table));
03162          if (eng && eng->load_func)
03163             loader = eng;
03164       }
03165    }
03166 
03167    result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
03168    /* silence is golden 
03169       ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
03170    */
03171 
03172    if (result)
03173       result->include_level--;
03174 
03175    return result;
03176 }
03177 
03178 
03179 static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments, const char *suggested_include_file)
03180 {
03181    char *c;
03182    char *cur = buf;
03183    struct ast_variable *v;
03184    char cmd[512], exec_file[512];
03185    int object, do_exec, do_include;
03186 
03187    /* Actually parse the entry */
03188    if (cur[0] == '[') {
03189       struct ast_category *newcat = NULL;
03190       char *catname;
03191 
03192       /* A category header */
03193       c = strchr(cur, ']');
03194       if (!c) {
03195          ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
03196          return -1;
03197       }
03198       *c++ = '\0';
03199       cur++;
03200       if (*c++ != '(')
03201          c = NULL;
03202       catname = cur;
03203       if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
03204          return -1;
03205       }
03206       (*cat)->lineno = lineno;
03207         
03208       /* add comments */
03209       if (withcomments && comment_buffer && comment_buffer[0] ) {
03210          newcat->precomments = ALLOC_COMMENT(comment_buffer);
03211       }
03212       if (withcomments && lline_buffer && lline_buffer[0] ) {
03213          newcat->sameline = ALLOC_COMMENT(lline_buffer);
03214       }
03215       if( withcomments )
03216          CB_RESET();
03217       
03218       /* If there are options or categories to inherit from, process them now */
03219       if (c) {
03220          if (!(cur = strchr(c, ')'))) {
03221             ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
03222             return -1;
03223          }
03224          *cur = '\0';
03225          while ((cur = strsep(&c, ","))) {
03226             if (!strcasecmp(cur, "!")) {
03227                (*cat)->ignored = 1;
03228             } else if (!strcasecmp(cur, "+")) {
03229                *cat = category_get(cfg, catname, 1);
03230                if (!*cat) {
03231                   ast_config_destroy(cfg);
03232                   if (newcat)
03233                      ast_category_destroy(newcat);
03234                   ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
03235                   return -1;
03236                }
03237                if (newcat) {
03238                   move_variables(newcat, *cat);
03239                   ast_category_destroy(newcat);
03240                   newcat = NULL;
03241                }
03242             } else {
03243                struct ast_category *base;
03244             
03245                base = category_get(cfg, cur, 1);
03246                if (!base) {
03247                   ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
03248                   return -1;
03249                }
03250                inherit_category(*cat, base);
03251             }
03252          }
03253       }
03254       if (newcat)
03255          ast_category_append(cfg, *cat);
03256    } else if (cur[0] == '#') {
03257       /* A directive */
03258       cur++;
03259       c = cur;
03260       while(*c && (*c > 32)) c++;
03261       if (*c) {
03262          *c = '\0';
03263          /* Find real argument */
03264          c = ast_skip_blanks(c + 1);
03265          if (!*c)
03266             c = NULL;
03267       } else 
03268          c = NULL;
03269       do_include = !strcasecmp(cur, "include");
03270       if(!do_include)
03271          do_exec = !strcasecmp(cur, "exec");
03272       else
03273          do_exec = 0;
03274       if (do_exec && !ast_opt_exec_includes) {
03275          ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
03276          do_exec = 0;
03277       }
03278       if (do_include || do_exec) {
03279          if (c) {
03280             char *cur2;
03281             char real_inclusion_name[256];
03282                 
03283             /* Strip off leading and trailing "'s and <>'s */
03284             while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
03285             /* Get rid of leading mess */
03286             cur = c;
03287             cur2 = cur;
03288             while (!ast_strlen_zero(cur)) {
03289                c = cur + strlen(cur) - 1;
03290                if ((*c == '>') || (*c == '<') || (*c == '\"'))
03291                   *c = '\0';
03292                else
03293                   break;
03294             }
03295             /* #exec </path/to/executable>
03296                We create a tmp file, then we #include it, then we delete it. */
03297             if (do_exec) { 
03298                snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
03299                snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
03300                ast_safe_system(cmd);
03301                cur = exec_file;
03302             } else
03303                exec_file[0] = '\0';
03304             /* A #include */
03305             /* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
03306             
03307             /* record this inclusion */
03308             ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
03309             
03310             do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
03311             if(!ast_strlen_zero(exec_file))
03312                unlink(exec_file);
03313             if(!do_include)
03314                return 0;
03315             /* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
03316             
03317          } else {
03318             ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n", 
03319                   do_exec ? "exec" : "include",
03320                   do_exec ? "/path/to/executable" : "filename",
03321                   lineno,
03322                   configfile);
03323          }
03324       }
03325       else 
03326          ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
03327    } else {
03328       /* Just a line (variable = value) */
03329       if (!*cat) {
03330          ast_log(LOG_WARNING,
03331             "parse error: No category context for line %d of %s\n", lineno, configfile);
03332          return -1;
03333       }
03334       c = strchr(cur, '=');
03335       if (c) {
03336          *c = 0;
03337          c++;
03338          /* Ignore > in => */
03339          if (*c== '>') {
03340             object = 1;
03341             c++;
03342          } else
03343             object = 0;
03344          if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), configfile))) {
03345             v->lineno = lineno;
03346             v->object = object;
03347             /* Put and reset comments */
03348             v->blanklines = 0;
03349             ast_variable_append(*cat, v);
03350             /* add comments */
03351             if (withcomments && comment_buffer && comment_buffer[0] ) {
03352                v->precomments = ALLOC_COMMENT(comment_buffer);
03353             }
03354             if (withcomments && lline_buffer && lline_buffer[0] ) {
03355                v->sameline = ALLOC_COMMENT(lline_buffer);
03356             }
03357             if( withcomments )
03358                CB_RESET();
03359             
03360          } else {
03361             return -1;
03362          }
03363       } else {
03364          ast_log(LOG_WARNING, "EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno, configfile);
03365       }
03366    }
03367    return 0;
03368 }
03369 
03370 static int use_local_dir = 1;
03371 
03372 void localized_use_local_dir(void);
03373 void localized_use_conf_dir(void);
03374 
03375 void localized_use_local_dir(void)
03376 {
03377    use_local_dir = 1;
03378 }
03379 
03380 void localized_use_conf_dir(void)
03381 {
03382    use_local_dir = 0;
03383 }
03384 
03385 
03386 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)
03387 {
03388    char fn[256];
03389    char buf[8192];
03390    char *new_buf, *comment_p, *process_buf;
03391    FILE *f;
03392    int lineno=0;
03393    int comment = 0, nest[MAX_NESTED_COMMENTS];
03394    struct ast_category *cat = NULL;
03395    int count = 0;
03396    struct stat statbuf;
03397    
03398    cat = ast_config_get_current_category(cfg);
03399 
03400    if (filename[0] == '/') {
03401       ast_copy_string(fn, filename, sizeof(fn));
03402    } else {
03403       if (use_local_dir)
03404          snprintf(fn, sizeof(fn), "./%s", filename);
03405       else
03406          snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
03407    }
03408 
03409    if (withcomments && cfg && cfg->include_level < 2 ) {
03410       CB_INIT();
03411    }
03412    
03413 #ifdef AST_INCLUDE_GLOB
03414    {
03415       int glob_ret;
03416       glob_t globbuf;
03417 
03418       globbuf.gl_offs = 0; /* initialize it to silence gcc */
03419 #ifdef SOLARIS
03420       glob_ret = glob(fn, GLOB_NOCHECK, NULL, &globbuf);
03421 #else
03422       glob_ret = glob(fn, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
03423 #endif
03424       if (glob_ret == GLOB_NOSPACE)
03425          ast_log(LOG_WARNING,
03426             "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
03427       else if (glob_ret  == GLOB_ABORTED)
03428          ast_log(LOG_WARNING,
03429             "Glob Expansion of pattern '%s' failed: Read error\n", fn);
03430       else  {
03431          /* loop over expanded files */
03432          int i;
03433          for (i=0; i<globbuf.gl_pathc; i++) {
03434             ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
03435 #endif
03436    do {
03437       if (stat(fn, &statbuf))
03438          continue;
03439 
03440       if (!S_ISREG(statbuf.st_mode)) {
03441          ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
03442          continue;
03443       }
03444       if (option_verbose > 1) {
03445          ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
03446          fflush(stdout);
03447       }
03448       if (!(f = fopen(fn, "r"))) {
03449          if (option_debug)
03450             ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
03451          if (option_verbose > 1)
03452             ast_verbose( "Not found (%s)\n", strerror(errno));
03453          continue;
03454       }
03455       count++;
03456       if (option_debug)
03457          ast_log(LOG_DEBUG, "Parsing %s\n", fn);
03458       if (option_verbose > 1)
03459          ast_verbose("Found\n");
03460       while(!feof(f)) {
03461          lineno++;
03462          if (fgets(buf, sizeof(buf), f)) {
03463             if ( withcomments ) {    
03464                CB_ADD(lline_buffer);       /* add the current lline buffer to the comment buffer */
03465                lline_buffer[0] = 0;        /* erase the lline buffer */
03466             }
03467             
03468             new_buf = buf;
03469             if (comment) 
03470                process_buf = NULL;
03471             else
03472                process_buf = buf;
03473             
03474             while ((comment_p = strchr(new_buf, COMMENT_META))) {
03475                if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
03476                   /* Yuck, gotta memmove */
03477                   memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
03478                   new_buf = comment_p;
03479                } else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
03480                   /* Meta-Comment start detected ";--" */
03481                   if (comment < MAX_NESTED_COMMENTS) {
03482                      *comment_p = '\0';
03483                      new_buf = comment_p + 3;
03484                      comment++;
03485                      nest[comment-1] = lineno;
03486                   } else {
03487                      ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
03488                   }
03489                } else if ((comment_p >= new_buf + 2) &&
03490                      (*(comment_p - 1) == COMMENT_TAG) &&
03491                      (*(comment_p - 2) == COMMENT_TAG)) {
03492                   /* Meta-Comment end detected */
03493                   comment--;
03494                   new_buf = comment_p + 1;
03495                   if (!comment) {
03496                      /* Back to non-comment now */
03497                      if (process_buf) {
03498                         /* Actually have to move what's left over the top, then continue */
03499                         char *oldptr;
03500                         oldptr = process_buf + strlen(process_buf);
03501                         if ( withcomments ) {
03502                            CB_ADD(";");
03503                            CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
03504                         }
03505                         
03506                         memmove(oldptr, new_buf, strlen(new_buf) + 1);
03507                         new_buf = oldptr;
03508                      } else
03509                         process_buf = new_buf;
03510                   }
03511                } else {
03512                   if (!comment) {
03513                      /* If ; is found, and we are not nested in a comment, 
03514                         we immediately stop all comment processing */
03515                      if ( withcomments ) {
03516                         LLB_ADD(comment_p);
03517                      }
03518                      *comment_p = '\0'; 
03519                      new_buf = comment_p;
03520                   } else
03521                      new_buf = comment_p + 1;
03522                }
03523             }
03524             if( withcomments && comment && !process_buf )
03525             {
03526                CB_ADD(buf);  /* the whole line is a comment, store it */
03527             }
03528             
03529             if (process_buf) {
03530                char *stripped_process_buf = ast_strip(process_buf);
03531                if (!ast_strlen_zero(stripped_process_buf)) {
03532                   if (process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
03533                      cfg = NULL;
03534                      break;
03535                   }
03536                }
03537             }
03538          }
03539       }
03540       fclose(f);     
03541    } while(0);
03542    if (comment) {
03543       ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
03544    }
03545 #ifdef AST_INCLUDE_GLOB
03546                if (!cfg)
03547                   break;
03548             }
03549             globfree(&globbuf);
03550          }
03551       }
03552 #endif
03553    if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
03554       if (comment_buffer) { 
03555          free(comment_buffer);
03556          free(lline_buffer);
03557          comment_buffer=0; 
03558          lline_buffer=0; 
03559          comment_buffer_size=0; 
03560          lline_buffer_size=0;
03561       }
03562    }
03563    if (count == 0)
03564       return NULL;
03565 
03566    return cfg;
03567 }
03568 
03569 
03570 static struct ast_config *ast_config_new(void) ;
03571 
03572 static struct ast_config *ast_config_new(void) 
03573 {
03574    struct ast_config *config;
03575 
03576    if ((config = ast_calloc(1, sizeof(*config))))
03577       config->max_include_level = MAX_INCLUDE_LEVEL;
03578    return config;
03579 }
03580 
03581 struct ast_config *localized_config_load(const char *filename);
03582 
03583 struct ast_config *localized_config_load(const char *filename)
03584 {
03585    struct ast_config *cfg;
03586    struct ast_config *result;
03587 
03588    cfg = ast_config_new();
03589    if (!cfg)
03590       return NULL;
03591 
03592    result = ast_config_internal_load(filename, cfg, 0, "");
03593    if (!result)
03594       ast_config_destroy(cfg);
03595 
03596    return result;
03597 }
03598 
03599 struct ast_config *localized_config_load_with_comments(const char *filename);
03600 
03601 struct ast_config *localized_config_load_with_comments(const char *filename)
03602 {
03603    struct ast_config *cfg;
03604    struct ast_config *result;
03605 
03606    cfg = ast_config_new();
03607    if (!cfg)
03608       return NULL;
03609 
03610    result = ast_config_internal_load(filename, cfg, 1, "");
03611    if (!result)
03612       ast_config_destroy(cfg);
03613 
03614    return result;
03615 }
03616 
03617 static struct ast_category *next_available_category(struct ast_category *cat)
03618 {
03619    for (; cat && cat->ignored; cat = cat->next);
03620 
03621    return cat;
03622 }
03623 
03624 static char *ast_category_browse(struct ast_config *config, const char *prev)
03625 {  
03626    struct ast_category *cat = NULL;
03627 
03628    if (prev && config->last_browse && (config->last_browse->name == prev))
03629       cat = config->last_browse->next;
03630    else if (!prev && config->root)
03631       cat = config->root;
03632    else if (prev) {
03633       for (cat = config->root; cat; cat = cat->next) {
03634          if (cat->name == prev) {
03635             cat = cat->next;
03636             break;
03637          }
03638       }
03639       if (!cat) {
03640          for (cat = config->root; cat; cat = cat->next) {
03641             if (!strcasecmp(cat->name, prev)) {
03642                cat = cat->next;
03643                break;
03644             }
03645          }
03646       }
03647    }
03648    
03649    if (cat)
03650       cat = next_available_category(cat);
03651 
03652    config->last_browse = cat;
03653    return (cat) ? cat->name : NULL;
03654 }
03655 
03656 
03657 
03658 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
03659 
03660 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
03661 {
03662    /* cast below is just to silence compiler warning about dropping "const" */
03663    cfg->current = (struct ast_category *) cat;
03664 }
03665 
03666 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
03667    which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
03668    recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
03669    be shocked and mystified as to why things are not showing up in the files! 
03670    
03671    Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
03672    and line number are stored for each include, plus the name of the file included, so that these statements may be
03673    included in the output files on a file_save operation. 
03674    
03675    The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
03676    are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
03677    the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
03678    and a header gets added.
03679    
03680    vars and category heads are output in the order they are stored in the config file. So, if the software
03681    shuffles these at all, then the placement of #include directives might get a little mixed up, because the
03682    file/lineno data probably won't get changed.
03683    
03684 */
03685 
03686 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
03687 {
03688    char date[256]="";
03689    time_t t;
03690    time(&t);
03691    ast_copy_string(date, ctime(&t), sizeof(date));
03692    
03693    fprintf(f1, ";!\n");
03694    fprintf(f1, ";! Automatically generated configuration file\n");
03695    if (strcmp(configfile, fn))
03696       fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
03697    else
03698       fprintf(f1, ";! Filename: %s\n", configfile);
03699    fprintf(f1, ";! Generator: %s\n", generator);
03700    fprintf(f1, ";! Creation Date: %s", date);
03701    fprintf(f1, ";!\n");
03702 }
03703 
03704 static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
03705 {
03706    if (!file || file[0] == 0) {
03707       if (configfile[0] == '/')
03708          ast_copy_string(fn, configfile, fn_size);
03709       else
03710          snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
03711    } else if (file[0] == '/') 
03712       ast_copy_string(fn, file, fn_size);
03713    else
03714       snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
03715 }
03716 
03717 int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
03718 
03719 int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
03720 {
03721    FILE *f;
03722    char fn[256];
03723    struct ast_variable *var;
03724    struct ast_category *cat;
03725    struct ast_comment *cmt;
03726    struct ast_config_include *incl;
03727    int blanklines = 0;
03728    
03729    /* reset all the output flags, in case this isn't our first time saving this data */
03730    
03731    for (incl=cfg->includes; incl; incl = incl->next)
03732       incl->output = 0;
03733    
03734    /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
03735       are all truncated to zero bytes and have that nice header*/
03736    
03737    for (incl=cfg->includes; incl; incl = incl->next)
03738    {
03739       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*/
03740          FILE *f1;
03741          
03742          set_fn(fn, sizeof(fn), incl->included_file, configfile); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
03743          f1 = fopen(fn,"w");
03744          if (f1) {
03745             gen_header(f1, configfile, fn, generator);
03746             fclose(f1); /* this should zero out the file */
03747          } else {
03748             ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
03749          }
03750       }
03751    }
03752    
03753    set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
03754 #ifdef __CYGWIN__ 
03755    if ((f = fopen(fn, "w+"))) {
03756 #else
03757    if ((f = fopen(fn, "w"))) {
03758 #endif       
03759       if (option_verbose > 1)
03760          ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
03761 
03762       gen_header(f, configfile, fn, generator);
03763       cat = cfg->root;
03764       fclose(f);
03765         
03766       /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
03767       /* since each var, cat, and associated comments can come from any file, we have to be 
03768          mobile, and open each file, print, and close it on an entry-by-entry basis */
03769       
03770       while(cat) {
03771          set_fn(fn, sizeof(fn), cat->file, configfile);
03772          f = fopen(fn, "a");
03773          if (!f)
03774          {
03775             ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
03776             return -1;
03777          }
03778          
03779          /* dump any includes that happen before this category header */
03780          for (incl=cfg->includes; incl; incl = incl->next) {
03781             if (strcmp(incl->include_location_file, cat->file) == 0){
03782                if (cat->lineno > incl->include_location_lineno && !incl->output) {
03783                   if (incl->exec)
03784                      fprintf(f,"#exec \"%s\"\n", incl->exec_file);
03785                   else
03786                      fprintf(f,"#include \"%s\"\n", incl->included_file);
03787                   incl->output = 1;
03788                }
03789             }
03790          }
03791             
03792          /* Dump section with any appropriate comment */
03793          for (cmt = cat->precomments; cmt; cmt=cmt->next) {
03794             if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
03795                fprintf(f,"%s", cmt->cmt);
03796          }
03797          if (!cat->precomments)
03798             fprintf(f,"\n");
03799          fprintf(f, "[%s]", cat->name);
03800          for(cmt = cat->sameline; cmt; cmt=cmt->next) {
03801             fprintf(f,"%s", cmt->cmt);
03802          }
03803          if (!cat->sameline)
03804             fprintf(f,"\n");
03805          fclose(f);
03806             
03807          var = cat->root;
03808          while(var) {
03809             set_fn(fn, sizeof(fn), var->file, configfile);
03810             f = fopen(fn, "a");
03811             if (!f)
03812             {
03813                ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
03814                return -1;
03815             }
03816                 
03817             /* dump any includes that happen before this category header */
03818             for (incl=cfg->includes; incl; incl = incl->next) {
03819                if (strcmp(incl->include_location_file, var->file) == 0){
03820                   if (var->lineno > incl->include_location_lineno && !incl->output) {
03821                      if (incl->exec)
03822                         fprintf(f,"#exec \"%s\"\n", incl->exec_file);
03823                      else
03824                         fprintf(f,"#include \"%s\"\n", incl->included_file);
03825                      incl->output = 1;
03826                   }
03827                }
03828             }
03829                 
03830             for (cmt = var->precomments; cmt; cmt=cmt->next) {
03831                if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
03832                   fprintf(f,"%s", cmt->cmt);
03833             }
03834             if (var->sameline) 
03835                fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
03836             else  
03837                fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
03838             if (var->blanklines) {
03839                blanklines = var->blanklines;
03840                while (blanklines--)
03841                   fprintf(f, "\n");
03842             }
03843             
03844             fclose(f);
03845                 
03846             
03847             var = var->next;
03848          }
03849          cat = cat->next;
03850       }
03851       if ((option_verbose > 1) && !option_debug)
03852          ast_verbose("Saved\n");
03853    } else {
03854       if (option_debug)
03855          ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
03856       if (option_verbose > 1)
03857          ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
03858       return -1;
03859    }
03860 
03861    /* Now, for files with trailing #include/#exec statements,
03862       we have to make sure every entry is output */
03863    
03864    for (incl=cfg->includes; incl; incl = incl->next) {
03865       if (!incl->output) {
03866          /* open the respective file */
03867          set_fn(fn, sizeof(fn), incl->include_location_file, configfile);
03868          f = fopen(fn, "a");
03869          if (!f)
03870          {
03871             ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
03872             return -1;
03873          }
03874             
03875          /* output the respective include */
03876          if (incl->exec)
03877             fprintf(f,"#exec \"%s\"\n", incl->exec_file);
03878          else
03879             fprintf(f,"#include \"%s\"\n", incl->included_file);
03880          fclose(f);
03881          incl->output = 1;
03882       }
03883    }
03884    
03885    return 0;
03886 }
03887 
03888 /* ================ the Line ========================================
03889    above this line, you have what you need to load a config file,
03890    and below it, you have what you need to process the extensions.conf
03891    file into the context/exten/prio stuff. They are both in one file
03892    to make things simpler */
03893 
03894 static struct ast_context *local_contexts = NULL;
03895 static struct ast_context *contexts = NULL;
03896 struct ast_context;
03897 struct ast_app;
03898 #ifdef LOW_MEMORY
03899 #define EXT_DATA_SIZE 256
03900 #else
03901 #define EXT_DATA_SIZE 8192
03902 #endif
03903 
03904 #ifdef NOT_ANYMORE
03905 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
03906 #endif
03907 
03908 #define SWITCH_DATA_LENGTH 256
03909 
03910 static const char *ast_get_extension_app(struct ast_exten *e)
03911 {
03912    return e ? e->app : NULL;
03913 }
03914 
03915 static const char *ast_get_extension_name(struct ast_exten *exten)
03916 {
03917    return exten ? exten->exten : NULL;
03918 }
03919 
03920 static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
03921 
03922 /*! \brief  ast_change_hint: Change hint for an extension */
03923 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
03924 {
03925    struct ast_hint *hint;
03926    int res = -1;
03927 
03928    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03929       if (hint->exten == oe) {
03930             hint->exten = ne;
03931          res = 0;
03932          break;
03933       }
03934    }
03935 
03936    return res;
03937 }
03938 
03939 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
03940 static int ast_add_hint(struct ast_exten *e)
03941 {
03942    struct ast_hint *hint;
03943 
03944    if (!e)
03945       return -1;
03946 
03947 
03948    /* Search if hint exists, do nothing */
03949    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03950       if (hint->exten == e) {
03951          if (option_debug > 1)
03952             ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03953          return -1;
03954       }
03955    }
03956 
03957    if (option_debug > 1)
03958       ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03959 
03960    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03961       return -1;
03962    }
03963    /* Initialize and insert new item at the top */
03964    hint->exten = e;
03965    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03966 
03967    return 0;
03968 }
03969 
03970 /*! \brief add the extension in the priority chain.
03971  * returns 0 on success, -1 on failure
03972  */
03973 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
03974    struct ast_exten *el, struct ast_exten *e, int replace)
03975 {
03976    struct ast_exten *ep;
03977 
03978    for (ep = NULL; e ; ep = e, e = e->peer) {
03979       if (e->priority >= tmp->priority)
03980          break;
03981    }
03982    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
03983       ep->peer = tmp;
03984       return 0;   /* success */
03985    }
03986    if (e->priority == tmp->priority) {
03987       /* Can't have something exactly the same.  Is this a
03988          replacement?  If so, replace, otherwise, bonk. */
03989       if (!replace) {
03990          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
03991          tmp->datad(tmp->data);
03992          free(tmp);
03993          return -1;
03994       }
03995       /* we are replacing e, so copy the link fields and then update
03996        * whoever pointed to e to point to us
03997        */
03998       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
03999       tmp->peer = e->peer; /* always meaningful */
04000       if (ep)        /* We're in the peer list, just insert ourselves */
04001          ep->peer = tmp;
04002       else if (el)      /* We're the first extension. Take over e's functions */
04003          el->next = tmp;
04004       else        /* We're the very first extension.  */
04005          con->root = tmp;
04006       if (tmp->priority == PRIORITY_HINT)
04007          ast_change_hint(e,tmp);
04008       /* Destroy the old one */
04009       e->datad(e->data);
04010       free(e);
04011    } else { /* Slip ourselves in just before e */
04012       tmp->peer = e;
04013       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
04014       if (ep)        /* Easy enough, we're just in the peer list */
04015          ep->peer = tmp;
04016       else {         /* we are the first in some peer list, so link in the ext list */
04017          if (el)
04018             el->next = tmp;   /* in the middle... */
04019          else
04020             con->root = tmp; /* ... or at the head */
04021          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
04022       }
04023       /* And immediately return success. */
04024       if (tmp->priority == PRIORITY_HINT)
04025           ast_add_hint(tmp);
04026    }
04027    return 0;
04028 }
04029 
04030 /*! \brief  ast_remove_hint: Remove hint from extension */
04031 static int ast_remove_hint(struct ast_exten *e)
04032 {
04033    /* Cleanup the Notifys if hint is removed */
04034    struct ast_hint *hint;
04035    struct ast_state_cb *cblist, *cbprev;
04036    int res = -1;
04037 
04038    if (!e)
04039       return -1;
04040 
04041    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
04042       if (hint->exten == e) {
04043          cbprev = NULL;
04044          cblist = hint->callbacks;
04045          while (cblist) {
04046             /* Notify with -1 and remove all callbacks */
04047             cbprev = cblist;
04048             cblist = cblist->next;
04049             free(cbprev);
04050          }
04051          hint->callbacks = NULL;
04052          AST_RWLIST_REMOVE_CURRENT(&hints, list);
04053          free(hint);
04054             res = 0;
04055          break;
04056       }
04057    }
04058    AST_RWLIST_TRAVERSE_SAFE_END
04059 
04060    return res;
04061 }
04062 
04063 static void destroy_exten(struct ast_exten *e)
04064 {
04065    if (e->priority == PRIORITY_HINT)
04066       ast_remove_hint(e);
04067 
04068    if (e->datad)
04069       e->datad(e->data);
04070    free(e);
04071 }
04072 
04073 char *days[] =
04074 {
04075    "sun",
04076    "mon",
04077    "tue",
04078    "wed",
04079    "thu",
04080    "fri",
04081    "sat",
04082    NULL,
04083 };
04084 
04085 char *months[] =
04086 {
04087    "jan",
04088    "feb",
04089    "mar",
04090    "apr",
04091    "may",
04092    "jun",
04093    "jul",
04094    "aug",
04095    "sep",
04096    "oct",
04097    "nov",
04098    "dec",
04099    NULL,
04100 };
04101 
04102 int ast_build_timing(struct ast_timing *i, const char *info_in);
04103 
04104 int ast_build_timing(struct ast_timing *i, const char *info_in)
04105 {
04106    char *info;
04107    int j, num_fields, last_sep = -1;
04108 
04109    i->timezone = NULL;
04110 
04111    /* Check for empty just in case */
04112    if (ast_strlen_zero(info_in)) {
04113       return 0;
04114    }
04115 
04116    /* make a copy just in case we were passed a static string */
04117    info = ast_strdupa(info_in);
04118 
04119    /* count the number of fields in the timespec */
04120    for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
04121       if (info[j] == ',') {
04122          last_sep = j;
04123          num_fields++;
04124       }
04125    }
04126 
04127    /* save the timezone, if it is specified */
04128    if (num_fields == 5) {
04129       i->timezone = ast_strdup(info + last_sep + 1);
04130    }
04131 
04132    /* Assume everything except time */
04133    i->monthmask = 0xfff;   /* 12 bits */
04134    i->daymask = 0x7fffffffU; /* 31 bits */
04135    i->dowmask = 0x7f; /* 7 bits */
04136    /* on each call, use strsep() to move info to the next argument */
04137    get_timerange(i, strsep(&info, "|,"));
04138    if (info)
04139       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
04140    if (info)
04141       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
04142    if (info)
04143       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
04144    return 1;
04145 }
04146 
04147 /*!
04148  * \brief helper functions to sort extensions and patterns in the desired way,
04149  * so that more specific patterns appear first.
04150  *
04151  * ext_cmp1 compares individual characters (or sets of), returning
04152  * an int where bits 0-7 are the ASCII code of the first char in the set,
04153  * while bit 8-15 are the cardinality of the set minus 1.
04154  * This way more specific patterns (smaller cardinality) appear first.
04155  * Wildcards have a special value, so that we can directly compare them to
04156  * sets by subtracting the two values. In particular:
04157  *    0x000xx     one character, xx
04158  *    0x0yyxx     yy character set starting with xx
04159  *    0x10000     '.' (one or more of anything)
04160  *    0x20000     '!' (zero or more of anything)
04161  *    0x30000     NUL (end of string)
04162  *    0x40000     error in set.
04163  * The pointer to the string is advanced according to needs.
04164  * NOTES:
04165  * 1. the empty set is equivalent to NUL.
04166  * 2. given that a full set has always 0 as the first element,
04167  *    we could encode the special cases as 0xffXX where XX
04168  *    is 1, 2, 3, 4 as used above.
04169  */
04170 static int ext_cmp1(const char **p)
04171 {
04172    uint32_t chars[8];
04173    int c, cmin = 0xff, count = 0;
04174    const char *end;
04175 
04176    /* load, sign extend and advance pointer until we find
04177     * a valid character.
04178     */
04179    while ( (c = *(*p)++) && (c == ' ' || c == '-') )
04180       ;  /* ignore some characters */
04181 
04182    /* always return unless we have a set of chars */
04183    switch (c) {
04184    default: /* ordinary character */
04185       return 0x0000 | (c & 0xff);
04186 
04187    case 'N':   /* 2..9 */
04188       return 0x0700 | '2' ;
04189 
04190    case 'X':   /* 0..9 */
04191       return 0x0900 | '0';
04192 
04193    case 'Z':   /* 1..9 */
04194       return 0x0800 | '1';
04195 
04196    case '.':   /* wildcard */
04197       return 0x10000;
04198 
04199    case '!':   /* earlymatch */
04200       return 0x20000;   /* less specific than NULL */
04201 
04202    case '\0':  /* empty string */
04203       *p = NULL;
04204       return 0x30000;
04205 
04206    case '[':   /* pattern */
04207       break;
04208    }
04209    /* locate end of set */
04210    end = strchr(*p, ']');  
04211 
04212    if (end == NULL) {
04213       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
04214       return 0x40000;   /* XXX make this entry go last... */
04215    }
04216 
04217    memset(chars, '\0', sizeof(chars)); /* clear all chars in the set */
04218    for (; *p < end  ; (*p)++) {
04219       unsigned char c1, c2;   /* first-last char in range */
04220       c1 = (unsigned char)((*p)[0]);
04221       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
04222          c2 = (unsigned char)((*p)[2]);
04223          *p += 2; /* skip a total of 3 chars */
04224       } else         /* individual character */
04225          c2 = c1;
04226       if (c1 < cmin)
04227          cmin = c1;
04228       for (; c1 <= c2; c1++) {
04229          uint32_t mask = 1 << (c1 % 32);
04230          if ( (chars[ c1 / 32 ] & mask) == 0)
04231             count += 0x100;
04232          chars[ c1 / 32 ] |= mask;
04233       }
04234    }
04235    (*p)++;
04236    return count == 0 ? 0x30000 : (count | cmin);
04237 }
04238 
04239 /*!
04240  * \brief the full routine to compare extensions in rules.
04241  */
04242 static int ext_cmp(const char *a, const char *b)
04243 {
04244    /* make sure non-patterns come first.
04245     * If a is not a pattern, it either comes first or
04246     * we use strcmp to compare the strings.
04247     */
04248    int ret = 0;
04249 
04250    if (a[0] != '_')
04251       return (b[0] == '_') ? -1 : strcmp(a, b);
04252 
04253    /* Now we know a is a pattern; if b is not, a comes first */
04254    if (b[0] != '_')
04255       return 1;
04256 #if 0 /* old mode for ext matching */
04257    return strcmp(a, b);
04258 #endif
04259    /* ok we need full pattern sorting routine */
04260    while (!ret && a && b)
04261       ret = ext_cmp1(&a) - ext_cmp1(&b);
04262    if (ret == 0)
04263       return 0;
04264    else
04265       return (ret > 0) ? 1 : -1;
04266 }
04267 
04268 /*! \brief copy a string skipping whitespace */
04269 static int ext_strncpy(char *dst, const char *src, int len)
04270 {
04271    int count=0;
04272 
04273    while (*src && (count < len - 1)) {
04274       switch(*src) {
04275       case ' ':
04276          /* otherwise exten => [a-b],1,... doesn't work */
04277          /*    case '-': */
04278          /* Ignore */
04279          break;
04280       default:
04281          *dst = *src;
04282          dst++;
04283       }
04284       src++;
04285       count++;
04286    }
04287    *dst = '\0';
04288 
04289    return count;
04290 }
04291 
04292 /*
04293  * Wrapper around _extension_match_core() to do performance measurement
04294  * using the profiling code.
04295  */
04296 int ast_check_timing(const struct ast_timing *i);
04297 
04298 int ast_check_timing(const struct ast_timing *i)
04299 {
04300    /* sorry, but this feature will NOT be available
04301       in the standalone version */
04302    return 0;
04303 }
04304 
04305 #ifdef NOT_ANYMORE
04306 static struct ast_switch *pbx_findswitch(const char *sw)
04307 {
04308    struct ast_switch *asw;
04309 
04310    AST_RWLIST_TRAVERSE(&switches, asw, list) {
04311       if (!strcasecmp(asw->name, sw))
04312          break;
04313    }
04314 
04315    return asw;
04316 }
04317 #endif
04318 
04319 
04320 static struct ast_context *ast_walk_contexts(struct ast_context *con);
04321 
04322 static struct ast_context *ast_walk_contexts(struct ast_context *con)
04323 {
04324    return con ? con->next : contexts;
04325 }
04326 
04327 struct ast_context *localized_walk_contexts(struct ast_context *con);
04328 struct ast_context *localized_walk_contexts(struct ast_context *con)
04329 {
04330    return ast_walk_contexts(con);
04331 }
04332 
04333 
04334 
04335 static struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
04336                                    struct ast_exten *exten);
04337 
04338 static struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
04339    struct ast_exten *exten)
04340 {
04341    if (!exten)
04342       return con ? con->root : NULL;
04343    else
04344       return exten->next;
04345 }
04346 
04347 struct ast_exten *localized_walk_context_extensions(struct ast_context *con,
04348                                        struct ast_exten *exten);
04349 struct ast_exten *localized_walk_context_extensions(struct ast_context *con,
04350                                        struct ast_exten *exten)
04351 {
04352    return ast_walk_context_extensions(con,exten);
04353 }
04354 
04355 
04356 static struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
04357                                     struct ast_exten *priority);
04358 
04359 static struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
04360    struct ast_exten *priority)
04361 {
04362    return priority ? priority->peer : exten;
04363 }
04364 
04365 struct ast_exten *localized_walk_extension_priorities(struct ast_exten *exten,
04366                                          struct ast_exten *priority);
04367 struct ast_exten *localized_walk_extension_priorities(struct ast_exten *exten,
04368                                          struct ast_exten *priority)
04369 {
04370    return ast_walk_extension_priorities(exten, priority);
04371 }
04372 
04373 
04374 
04375 static struct ast_include *ast_walk_context_includes(struct ast_context *con,
04376                                    struct ast_include *inc);
04377 
04378 static struct ast_include *ast_walk_context_includes(struct ast_context *con,
04379    struct ast_include *inc)
04380 {
04381    if (!inc)
04382       return con ? con->includes : NULL;
04383    else
04384       return inc->next;
04385 }
04386 
04387 struct ast_include *localized_walk_context_includes(struct ast_context *con,
04388                                        struct ast_include *inc);
04389 struct ast_include *localized_walk_context_includes(struct ast_context *con,
04390                                        struct ast_include *inc)
04391 {
04392    return ast_walk_context_includes(con, inc);
04393 }
04394 
04395 
04396 static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
04397                                         struct ast_sw *sw);
04398 
04399 static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
04400                                         struct ast_sw *sw)
04401 {
04402    if (!sw)
04403       return con ? AST_LIST_FIRST(&con->alts) : NULL;
04404    else
04405       return AST_LIST_NEXT(sw, list);
04406 }
04407 
04408 struct ast_sw *localized_walk_context_switches(struct ast_context *con,
04409                                        struct ast_sw *sw);
04410 struct ast_sw *localized_walk_context_switches(struct ast_context *con,
04411                                        struct ast_sw *sw)
04412 {
04413    return ast_walk_context_switches(con, sw);
04414 }
04415 
04416 
04417 static struct ast_context *ast_context_find(const char *name);
04418 
04419 static struct ast_context *ast_context_find(const char *name)
04420 {
04421    struct ast_context *tmp = NULL;
04422    while ( (tmp = ast_walk_contexts(tmp)) ) {
04423       if (!name || !strcasecmp(name, tmp->name))
04424          break;
04425    }
04426    return tmp;
04427 }
04428 
04429 /*
04430  * Internal function for ast_extension_{match|close}
04431  * return 0 on no-match, 1 on match, 2 on early match.
04432  * mode is as follows:
04433  * E_MATCH     success only on exact match
04434  * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
04435  * E_CANMATCH  either of the above.
04436  */
04437 
04438 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
04439 {
04440    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
04441 
04442    if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
04443       return 1;
04444 
04445    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
04446       int ld = strlen(data), lp = strlen(pattern);
04447 
04448       if (lp < ld)      /* pattern too short, cannot match */
04449          return 0;
04450       /* depending on the mode, accept full or partial match or both */
04451       if (mode == E_MATCH)
04452          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
04453       if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
04454          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
04455       else
04456          return 0;
04457    }
04458    pattern++; /* skip leading _ */
04459    /*
04460     * XXX below we stop at '/' which is a separator for the CID info. However we should
04461     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
04462     */
04463    while (*data && *pattern && *pattern != '/') {
04464       const char *end;
04465 
04466       if (*data == '-') { /* skip '-' in data (just a separator) */
04467          data++;
04468          continue;
04469       }
04470       switch (toupper(*pattern)) {
04471       case '[':   /* a range */
04472          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
04473          if (end == NULL) {
04474             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
04475             return 0;   /* unconditional failure */
04476          }
04477          for (pattern++; pattern != end; pattern++) {
04478             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
04479                if (*data >= pattern[0] && *data <= pattern[2])
04480                   break;   /* match found */
04481                else {
04482                   pattern += 2; /* skip a total of 3 chars */
04483                   continue;
04484                }
04485             } else if (*data == pattern[0])
04486                break;   /* match found */
04487          }
04488          if (pattern == end)
04489             return 0;
04490          pattern = end; /* skip and continue */
04491          break;
04492       case 'N':
04493          if (*data < '2' || *data > '9')
04494             return 0;
04495          break;
04496       case 'X':
04497          if (*data < '0' || *data > '9')
04498             return 0;
04499          break;
04500       case 'Z':
04501          if (*data < '1' || *data > '9')
04502             return 0;
04503          break;
04504       case '.':   /* Must match, even with more digits */
04505          return 1;
04506       case '!':   /* Early match */
04507          return 2;
04508       case ' ':
04509       case '-':   /* Ignore these in patterns */
04510          data--; /* compensate the final data++ */
04511          break;
04512       default:
04513          if (*data != *pattern)
04514             return 0;
04515       }
04516       data++;
04517       pattern++;
04518    }
04519    if (*data)        /* data longer than pattern, no match */
04520       return 0;
04521    /*
04522     * match so far, but ran off the end of the data.
04523     * Depending on what is next, determine match or not.
04524     */
04525    if (*pattern == '\0' || *pattern == '/')  /* exact match */
04526       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
04527    else if (*pattern == '!')        /* early match */
04528       return 2;
04529    else                 /* partial match */
04530       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
04531 }
04532 
04533 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
04534 {
04535    int i;
04536    i = _extension_match_core(pattern, data, mode);
04537    return i;
04538 }
04539 
04540 static int ast_extension_match(const char *pattern, const char *data);
04541 
04542 static int ast_extension_match(const char *pattern, const char *data)
04543 {
04544    return extension_match_core(pattern, data, E_MATCH);
04545 }
04546 
04547 static int matchcid(const char *cidpattern, const char *callerid)
04548 {
04549    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
04550       failing to get a number should count as a match, otherwise not */
04551 
04552    if (ast_strlen_zero(callerid))
04553       return ast_strlen_zero(cidpattern) ? 1 : 0;
04554 
04555    return ast_extension_match(cidpattern, callerid);
04556 }
04557 
04558 static inline int include_valid(struct ast_include *i)
04559 {
04560    if (!i->hastime)
04561       return 1;
04562 
04563    return ast_check_timing(&(i->timing));
04564 }
04565 
04566 
04567 
04568 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
04569                                  struct ast_context *bypass, 
04570                                  struct pbx_find_info *q,
04571                                  const char *context, 
04572                                  const char *exten, 
04573                                  int priority,
04574                                  const char *label, 
04575                                  const char *callerid, 
04576                                  enum ext_match_t action);
04577 
04578 
04579 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
04580                                  struct ast_context *bypass, 
04581                                  struct pbx_find_info *q,
04582                                  const char *context, 
04583                                  const char *exten, 
04584                                  int priority,
04585                                  const char *label, 
04586                                  const char *callerid, 
04587                                  enum ext_match_t action)
04588 {
04589    int x;
04590    struct ast_context *tmp;
04591    struct ast_exten *e, *eroot;
04592    struct ast_include *i;
04593 
04594    /* Initialize status if appropriate */
04595    if (q->stacklen == 0) {
04596       q->status = STATUS_NO_CONTEXT;
04597       q->swo = NULL;
04598       q->data = NULL;
04599       q->foundcontext = NULL;
04600    } else if (q->stacklen >= AST_PBX_MAX_STACK) {
04601       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
04602       return NULL;
04603    }
04604    /* Check first to see if we've already been checked */
04605    for (x = 0; x < q->stacklen; x++) {
04606       if (!strcasecmp(q->incstack[x], context))
04607          return NULL;
04608    }
04609    if (bypass) /* bypass means we only look there */
04610       tmp = bypass;
04611    else {   /* look in contexts */
04612       tmp = NULL;
04613       while ((tmp = ast_walk_contexts(tmp)) ) {
04614          if (!strcmp(tmp->name, context))
04615             break;
04616       }
04617       if (!tmp)
04618          return NULL;
04619    }
04620    if (q->status < STATUS_NO_EXTENSION)
04621       q->status = STATUS_NO_EXTENSION;
04622 
04623    /* scan the list trying to match extension and CID */
04624    eroot = NULL;
04625    while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
04626       int match = extension_match_core(eroot->exten, exten, action);
04627       /* 0 on fail, 1 on match, 2 on earlymatch */
04628 
04629       if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
04630          continue;   /* keep trying */
04631       if (match == 2 && action == E_MATCHMORE) {
04632          /* We match an extension ending in '!'.
04633           * The decision in this case is final and is NULL (no match).
04634           */
04635          return NULL;
04636       }
04637       /* found entry, now look for the right priority */
04638       if (q->status < STATUS_NO_PRIORITY)
04639          q->status = STATUS_NO_PRIORITY;
04640       e = NULL;
04641       while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
04642          /* Match label or priority */
04643          if (action == E_FINDLABEL) {
04644             if (q->status < STATUS_NO_LABEL)
04645                q->status = STATUS_NO_LABEL;
04646             if (label && e->label && !strcmp(label, e->label))
04647                break;   /* found it */
04648          } else if (e->priority == priority) {
04649             break;   /* found it */
04650          } /* else keep searching */
04651       }
04652       if (e) { /* found a valid match */
04653          q->status = STATUS_SUCCESS;
04654          q->foundcontext = context;
04655          return e;
04656       }
04657    }
04658 #ifdef NOT_RIGHT_NOW
04659    /* Check alternative switches???  */
04660    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
04661       struct ast_switch *asw = pbx_findswitch(sw->name);
04662       ast_switch_f *aswf = NULL;
04663       char *datap;
04664 
04665       if (!asw) {
04666          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
04667          continue;
04668       }
04669       /* No need to Substitute variables now; we shouldn't be here if there's any  */
04670       
04671       /* equivalent of extension_match_core() at the switch level */
04672       if (action == E_CANMATCH)
04673          aswf = asw->canmatch;
04674       else if (action == E_MATCHMORE)
04675          aswf = asw->matchmore;
04676       else /* action == E_MATCH */
04677          aswf = asw->exists;
04678       datap = sw->eval ? sw->tmpdata : sw->data;
04679       res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
04680       if (res) {  /* Got a match */
04681          q->swo = asw;
04682          q->data = datap;
04683          q->foundcontext = context;
04684          /* XXX keep status = STATUS_NO_CONTEXT ? */
04685          return NULL;
04686       }
04687    }
04688 #endif
04689    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
04690    /* Now try any includes we have in this context */
04691    for (i = tmp->includes; i; i = i->next) {
04692       if (include_valid(i)) {
04693          if ((e = pbx_find_extension(NULL, bypass, q, i->rname, exten, priority, label, callerid, action)))
04694             return e;
04695          if (q->swo)
04696             return NULL;
04697       }
04698    }
04699    return NULL;
04700 }
04701 
04702 struct ast_exten *localized_find_extension(struct ast_context *bypass,
04703                                 struct pbx_find_info *q,
04704                                 const char *context, 
04705                                 const char *exten, 
04706                                 int priority,
04707                                 const char *label, 
04708                                 const char *callerid, 
04709                                 enum ext_match_t action);
04710 
04711 struct ast_exten *localized_find_extension(struct ast_context *bypass,
04712                                 struct pbx_find_info *q,
04713                                 const char *context, 
04714                                 const char *exten, 
04715                                 int priority,
04716                                 const char *label, 
04717                                 const char *callerid, 
04718                                  enum ext_match_t action)
04719 {
04720    return pbx_find_extension(NULL, bypass, q, context, exten, priority, label, callerid, action);
04721 }
04722 
04723 
04724 static struct ast_context *contexts;
04725 AST_RWLOCK_DEFINE_STATIC(conlock);     /*!< Lock for the ast_context list */
04726 
04727 static const char *ast_get_context_name(struct ast_context *con);
04728 
04729 static const char *ast_get_context_name(struct ast_context *con)
04730 {
04731    return con ? con->name : NULL;
04732 }
04733 
04734 /*
04735  * errno values
04736  *  ENOMEM - out of memory
04737  *  EBUSY  - can't lock
04738  *  EEXIST - already included
04739  *  EINVAL - there is no existence of context for inclusion
04740  */
04741 static int ast_context_add_include2(struct ast_context *con, const char *value,
04742                       const char *registrar);
04743 
04744 static int ast_context_add_include2(struct ast_context *con, const char *value,
04745                            const char *registrar)
04746 {
04747    struct ast_include *new_include;
04748    char *c;
04749    struct ast_include *i, *il = NULL; /* include, include_last */
04750    int length;
04751    char *p;
04752 
04753    length = sizeof(struct ast_include);
04754    length += 2 * (strlen(value) + 1);
04755 
04756    /* allocate new include structure ... */
04757    if (!(new_include = ast_calloc(1, length)))
04758       return -1;
04759    /* Fill in this structure. Use 'p' for assignments, as the fields
04760     * in the structure are 'const char *'
04761     */
04762    p = new_include->stuff;
04763    new_include->name = p;
04764    strcpy(p, value);
04765    p += strlen(value) + 1;
04766    new_include->rname = p;
04767    strcpy(p, value);
04768    /* Strip off timing info, and process if it is there */
04769    if ( (c = strchr(p, '|')) ) {
04770       *c++ = '\0';
04771       new_include->hastime = ast_build_timing(&(new_include->timing), c);
04772    }
04773    new_include->next      = NULL;
04774    new_include->registrar = registrar;
04775 
04776 
04777    /* ... go to last include and check if context is already included too... */
04778    for (i = con->includes; i; i = i->next) {
04779       if (!strcasecmp(i->name, new_include->name)) {
04780          free(new_include);
04781          errno = EEXIST;
04782          return -1;
04783       }
04784       il = i;
04785    }
04786 
04787    /* ... include new context into context list, unlock, return */
04788    if (il)
04789       il->next = new_include;
04790    else
04791       con->includes = new_include;
04792    if (option_verbose > 2)
04793       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04794 
04795    return 0;
04796 }
04797 
04798 int localized_context_add_include2(struct ast_context *con, const char *value,
04799                       const char *registrar);
04800 int localized_context_add_include2(struct ast_context *con, const char *value,
04801                            const char *registrar)
04802 {
04803    return  ast_context_add_include2(con, value, registrar);
04804 }
04805 
04806 
04807 
04808 static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
04809 
04810 static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04811 {
04812    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04813    int length;
04814    length = sizeof(struct ast_ignorepat);
04815    length += strlen(value) + 1;
04816    if (!(ignorepat = ast_calloc(1, length)))
04817       return -1;
04818    /* The cast to char * is because we need to write the initial value.
04819     * The field is not supposed to be modified otherwise
04820     */
04821    strcpy((char *)ignorepat->pattern, value);
04822    ignorepat->next = NULL;
04823    ignorepat->registrar = registrar;
04824    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
04825       ignorepatl = ignorepatc;
04826       if (!strcasecmp(ignorepatc->pattern, value)) {
04827          /* Already there */
04828          errno = EEXIST;
04829          return -1;
04830       }
04831    }
04832    if (ignorepatl)
04833       ignorepatl->next = ignorepat;
04834    else
04835       con->ignorepats = ignorepat;
04836    return 0;
04837 
04838 }
04839 
04840 int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
04841 
04842 int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04843 {
04844    return ast_context_add_ignorepat2(con, value, registrar);
04845 }
04846 
04847 
04848 /*
04849  * Lock context list functions ...
04850  */
04851 
04852 static int ast_wrlock_contexts(void)
04853 {
04854    return ast_rwlock_wrlock(&conlock);
04855 }
04856 
04857 static int ast_unlock_contexts(void)
04858 {
04859    return ast_rwlock_unlock(&conlock);
04860 }
04861 
04862 static int ast_wrlock_context(struct ast_context *con)
04863 {
04864    return ast_rwlock_wrlock(&con->lock);
04865 }
04866 
04867 static int ast_unlock_context(struct ast_context *con)
04868 {
04869    return ast_rwlock_unlock(&con->lock);
04870 }
04871 
04872 /*
04873  * errno values
04874  *  ENOMEM - out of memory
04875  *  EBUSY  - can't lock
04876  *  EEXIST - already included
04877  *  EINVAL - there is no existence of context for inclusion
04878  */
04879 static int ast_context_add_switch2(struct ast_context *con, const char *value,
04880                      const char *data, int eval, const char *registrar);
04881 
04882 static int ast_context_add_switch2(struct ast_context *con, const char *value,
04883    const char *data, int eval, const char *registrar)
04884 {
04885    struct ast_sw *new_sw;
04886    struct ast_sw *i;
04887    int length;
04888    char *p;
04889 
04890    length = sizeof(struct ast_sw);
04891    length += strlen(value) + 1;
04892    if (data)
04893       length += strlen(data);
04894    length++;
04895    if (eval) {
04896       /* Create buffer for evaluation of variables */
04897       length += SWITCH_DATA_LENGTH;
04898       length++;
04899    }
04900 
04901    /* allocate new sw structure ... */
04902    if (!(new_sw = ast_calloc(1, length)))
04903       return -1;
04904    /* ... fill in this structure ... */
04905    p = new_sw->stuff;
04906    new_sw->name = p;
04907    strcpy(new_sw->name, value);
04908    p += strlen(value) + 1;
04909    new_sw->data = p;
04910    if (data) {
04911       strcpy(new_sw->data, data);
04912       p += strlen(data) + 1;
04913    } else {
04914       strcpy(new_sw->data, "");
04915       p++;
04916    }
04917    if (eval)
04918       new_sw->tmpdata = p;
04919    new_sw->eval     = eval;
04920    new_sw->registrar = registrar;
04921 
04922    /* ... go to last sw and check if context is already swd too... */
04923    AST_LIST_TRAVERSE(&con->alts, i, list) {
04924       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04925          free(new_sw);
04926          errno = EEXIST;
04927          return -1;
04928       }
04929    }
04930 
04931    /* ... sw new context into context list, unlock, return */
04932    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
04933 
04934    if (option_verbose > 2)
04935       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04936 
04937    return 0;
04938 }
04939 
04940 int localized_context_add_switch2(struct ast_context *con, const char *value,
04941                                const char *data, int eval, const char *registrar);
04942 
04943 int localized_context_add_switch2(struct ast_context *con, const char *value,
04944                                const char *data, int eval, const char *registrar)
04945 {
04946    return ast_context_add_switch2(con, value, data, eval, registrar);
04947 }
04948 
04949 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
04950 {
04951    struct ast_context *tmp, **loc_contexts;
04952    int length = sizeof(struct ast_context) + strlen(name) + 1;
04953 
04954    if (!extcontexts) {
04955       ast_wrlock_contexts();
04956       loc_contexts = &contexts;
04957    } else
04958       loc_contexts = extcontexts;
04959 
04960    for (tmp = *loc_contexts; tmp; tmp = tmp->next) {
04961       if (!strcasecmp(tmp->name, name)) {
04962          if (!existsokay) {
04963             ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
04964             tmp = NULL;
04965          }
04966          if (!extcontexts)
04967             ast_unlock_contexts();
04968          return tmp;
04969       }
04970    }
04971    if ((tmp = ast_calloc(1, length))) {
04972       ast_rwlock_init(&tmp->lock);
04973       ast_mutex_init(&tmp->macrolock);
04974       strcpy(tmp->name, name);
04975       tmp->root = NULL;
04976       tmp->registrar = registrar;
04977       tmp->next = *loc_contexts;
04978       tmp->includes = NULL;
04979       tmp->ignorepats = NULL;
04980       *loc_contexts = tmp;
04981       if (option_debug)
04982          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
04983       if (option_verbose > 2)
04984          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
04985    }
04986 
04987    if (!extcontexts)
04988       ast_unlock_contexts();
04989    return tmp;
04990 }
04991 
04992 /*! \brief
04993  * Main interface to add extensions to the list for out context.
04994  *
04995  * We sort extensions in order of matching preference, so that we can
04996  * stop the search as soon as we find a suitable match.
04997  * This ordering also takes care of wildcards such as '.' (meaning
04998  * "one or more of any character") and '!' (which is 'earlymatch',
04999  * meaning "zero or more of any character" but also impacts the
05000  * return value from CANMATCH and EARLYMATCH.
05001  *
05002  * The extension match rules defined in the devmeeting 2006.05.05 are
05003  * quite simple: WE SELECT THE LONGEST MATCH.
05004  * In detail, "longest" means the number of matched characters in
05005  * the extension. In case of ties (e.g. _XXX and 333) in the length
05006  * of a pattern, we give priority to entries with the smallest cardinality
05007  * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
05008  * while the latter has 7, etc.
05009  * In case of same cardinality, the first element in the range counts.
05010  * If we still have a tie, any final '!' will make this as a possibly
05011  * less specific pattern.
05012  *
05013  * EBUSY - can't lock
05014  * EEXIST - extension with the same priority exist and no replace is set
05015  *
05016  */
05017 static int ast_add_extension2(struct ast_context *con,
05018    int replace, const char *extension, int priority, const char *label, const char *callerid,
05019    const char *application, void *data, void (*datad)(void *),
05020    const char *registrar)
05021 {
05022    /*
05023     * Sort extensions (or patterns) according to the rules indicated above.
05024     * These are implemented by the function ext_cmp()).
05025     * All priorities for the same ext/pattern/cid are kept in a list,
05026     * using the 'peer' field  as a link field..
05027     */
05028    struct ast_exten *tmp, *e, *el = NULL;
05029    int res;
05030    int length;
05031    char *p;
05032 
05033    /* if we are adding a hint, and there are global variables, and the hint
05034       contains variable references, then expand them --- NOT In this situation!!!
05035    */
05036 
05037    length = sizeof(struct ast_exten);
05038    length += strlen(extension) + 1;
05039    length += strlen(application) + 1;
05040    if (label)
05041       length += strlen(label) + 1;
05042    if (callerid)
05043       length += strlen(callerid) + 1;
05044    else
05045       length ++;  /* just the '\0' */
05046 
05047    /* Be optimistic:  Build the extension structure first */
05048    if (datad == NULL)
05049       datad = null_datad;
05050    if (!(tmp = ast_calloc(1, length)))
05051       return -1;
05052 
05053    /* use p as dst in assignments, as the fields are const char * */
05054    p = tmp->stuff;
05055    if (label) {
05056       tmp->label = p;
05057       strcpy(p, label);
05058       p += strlen(label) + 1;
05059    }
05060    tmp->exten = p;
05061    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
05062    tmp->priority = priority;
05063    tmp->cidmatch = p;   /* but use p for assignments below */
05064    if (callerid) {
05065       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
05066       tmp->matchcid = 1;
05067    } else {
05068       *p++ = '\0';
05069       tmp->matchcid = 0;
05070    }
05071    tmp->app = p;
05072    strcpy(p, application);
05073    tmp->parent = con;
05074    tmp->data = data;
05075    tmp->datad = datad;
05076    tmp->registrar = registrar;
05077 
05078    res = 0; /* some compilers will think it is uninitialized otherwise */
05079    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
05080       res = ext_cmp(e->exten, extension);
05081       if (res == 0) { /* extension match, now look at cidmatch */
05082          if (!e->matchcid && !tmp->matchcid)
05083             res = 0;
05084          else if (tmp->matchcid && !e->matchcid)
05085             res = 1;
05086          else if (e->matchcid && !tmp->matchcid)
05087             res = -1;
05088          else
05089             res = strcasecmp(e->cidmatch, tmp->cidmatch);
05090       }
05091       if (res >= 0)
05092          break;
05093    }
05094    if (e && res == 0) { /* exact match, insert in the pri chain */
05095       res = add_pri(con, tmp, el, e, replace);
05096       if (res < 0) {
05097          errno = EEXIST;   /* XXX do we care ? */
05098          return 0; /* XXX should we return -1 maybe ? */
05099       }
05100    } else {
05101       /*
05102        * not an exact match, this is the first entry with this pattern,
05103        * so insert in the main list right before 'e' (if any)
05104        */
05105       tmp->next = e;
05106       if (el)
05107          el->next = tmp;
05108       else
05109          con->root = tmp;
05110       if (tmp->priority == PRIORITY_HINT)
05111          ast_add_hint(tmp);
05112    }
05113    if (option_debug) {
05114       if (tmp->matchcid) {
05115          ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
05116             tmp->exten, tmp->priority, tmp->cidmatch, con->name);
05117       } else {
05118          ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
05119             tmp->exten, tmp->priority, con->name);
05120       }
05121    }
05122    if (option_verbose > 2) {
05123       if (tmp->matchcid) {
05124          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
05125             tmp->exten, tmp->priority, tmp->cidmatch, con->name);
05126       } else {
05127          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
05128             tmp->exten, tmp->priority, con->name);
05129       }
05130    }
05131    return 0;
05132 }
05133 
05134 int localized_add_extension2(struct ast_context *con,
05135                       int replace, const char *extension, int priority, const char *label, const char *callerid,
05136                       const char *application, void *data, void (*datad)(void *),
05137                       const char *registrar);
05138 
05139 int localized_add_extension2(struct ast_context *con,
05140                       int replace, const char *extension, int priority, const char *label, const char *callerid,
05141                       const char *application, void *data, void (*datad)(void *),
05142                       const char *registrar)
05143 {
05144    return ast_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
05145 }
05146 
05147 
05148 
05149 /*! \brief The return value depends on the action:
05150  *
05151  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
05152  * and return 0 on failure, -1 on match;
05153  * E_FINDLABEL maps the label to a priority, and returns
05154  * the priority on success, ... XXX
05155  * E_SPAWN, spawn an application,
05156  * and return 0 on success, -1 on failure.
05157  */
05158 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
05159                         const char *context, const char *exten, int priority,
05160                         const char *label, const char *callerid, enum ext_match_t action)
05161 {
05162    struct ast_exten *e;
05163    int res;
05164    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
05165 
05166    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
05167 
05168    e = pbx_find_extension(NULL, con, &q, context, exten, priority, label, callerid, action);
05169    if (e) {
05170       if (matching_action) {
05171          return -1;  /* success, we found it */
05172       } else if (action == E_FINDLABEL) { /* map the label to a priority */
05173          res = e->priority;
05174          return res; /* the priority we were looking for */
05175       } else { /* spawn */
05176 
05177          /* NOT!!!!! */
05178          return 0;
05179       }
05180    } else if (q.swo) {  /* not found here, but in another switch */
05181       if (matching_action)
05182          return -1;
05183       else {
05184          if (!q.swo->exec) {
05185             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
05186             res = -1;
05187          }
05188          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
05189       }
05190    } else { /* not found anywhere, see what happened */
05191       switch (q.status) {
05192       case STATUS_NO_CONTEXT:
05193          if (!matching_action)
05194             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
05195          break;
05196       case STATUS_NO_EXTENSION:
05197          if (!matching_action)
05198             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
05199          break;
05200       case STATUS_NO_PRIORITY:
05201          if (!matching_action)
05202             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
05203          break;
05204       case STATUS_NO_LABEL:
05205          if (context)
05206             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
05207          break;
05208       default:
05209          if (option_debug)
05210             ast_log(LOG_DEBUG, "Shouldn't happen!\n");
05211       }
05212 
05213       return (matching_action) ? 0 : -1;
05214    }
05215 }
05216 
05217 static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid);
05218 
05219 static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
05220 {
05221    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
05222 }
05223 
05224 static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
05225 {
05226    return __ast_context_create(extcontexts, name, registrar, 1);
05227 }
05228 
05229 struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar);
05230 struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
05231 {
05232    return __ast_context_create(extcontexts, name, registrar, 1);
05233 }
05234 
05235 
05236 /* chopped this one off at the knees */
05237 static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
05238 {
05239    ast_log(LOG_ERROR, "Function %s not registered\n", function);
05240    return -1;
05241 }
05242 
05243 /*! \brief extract offset:length from variable name.
05244  * Returns 1 if there is a offset:length part, which is
05245  * trimmed off (values go into variables)
05246  */
05247 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
05248 {
05249    int parens=0;
05250 
05251    *offset = 0;
05252    *length = INT_MAX;
05253    *isfunc = 0;
05254    for (; *var; var++) {
05255       if (*var == '(') {
05256          (*isfunc)++;
05257          parens++;
05258       } else if (*var == ')') {
05259          parens--;
05260       } else if (*var == ':' && parens == 0) {
05261          *var++ = '\0';
05262          sscanf(var, "%30d:%30d", offset, length);
05263          return 1; /* offset:length valid */
05264       }
05265    }
05266    return 0;
05267 }
05268 
05269 static const char *ast_var_value(const struct ast_var_t *var)
05270 {
05271    return (var ? var->value : NULL);
05272 }
05273 
05274 /*! \brief takes a substring. It is ok to call with value == workspace.
05275  *
05276  * offset < 0 means start from the end of the string and set the beginning
05277  *   to be that many characters back.
05278  * length is the length of the substring.  A value less than 0 means to leave
05279  * that many off the end.
05280  * Always return a copy in workspace.
05281  */
05282 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
05283 {
05284    char *ret = workspace;
05285    int lr;  /* length of the input string after the copy */
05286 
05287    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
05288 
05289    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
05290 
05291    /* Quick check if no need to do anything */
05292    if (offset == 0 && length >= lr) /* take the whole string */
05293       return ret;
05294 
05295    if (offset < 0)   {  /* translate negative offset into positive ones */
05296       offset = lr + offset;
05297       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
05298          offset = 0;
05299    }
05300 
05301    /* too large offset result in empty string so we know what to return */
05302    if (offset >= lr)
05303       return ret + lr;  /* the final '\0' */
05304 
05305    ret += offset;    /* move to the start position */
05306    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
05307       ret[length] = '\0';
05308    else if (length < 0) {
05309       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
05310          ret[lr + length - offset] = '\0';
05311       else
05312          ret[0] = '\0';
05313    }
05314 
05315    return ret;
05316 }
05317 
05318 /*! \brief  Support for Asterisk built-in variables in the dialplan
05319 \note See also
05320    - \ref AstVar  Channel variables
05321    - \ref AstCauses The HANGUPCAUSE variable
05322  */
05323 static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
05324 {
05325    const char not_found = '\0';
05326    char *tmpvar;
05327    const char *s; /* the result */
05328    int offset, length;
05329    int i, need_substring;
05330    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
05331    
05332    /*
05333     * Make a copy of var because parse_variable_name() modifies the string.
05334     * Then if called directly, we might need to run substring() on the result;
05335     * remember this for later in 'need_substring', 'offset' and 'length'
05336     */
05337    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
05338    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
05339    
05340    /*
05341     * Look first into predefined variables, then into variable lists.
05342     * Variable 's' points to the result, according to the following rules:
05343     * s == &not_found (set at the beginning) means that we did not find a
05344     * matching variable and need to look into more places.
05345     * If s != &not_found, s is a valid result string as follows:
05346     * s = NULL if the variable does not have a value;
05347     * you typically do this when looking for an unset predefined variable.
05348     * s = workspace if the result has been assembled there;
05349     * typically done when the result is built e.g. with an snprintf(),
05350     * so we don't need to do an additional copy.
05351     * s != workspace in case we have a string, that needs to be copied
05352     * (the ast_copy_string is done once for all at the end).
05353     * Typically done when the result is already available in some string.
05354     */
05355    s = &not_found;   /* default value */
05356    if (s == &not_found) { /* look for more */
05357       if (!strcmp(var, "EPOCH")) {
05358          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
05359       }
05360       
05361       s = workspace;
05362    }
05363    /* if not found, look into chanvars or global vars */
05364    for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
05365       struct ast_var_t *variables;
05366       if (!places[i])
05367          continue;
05368       if (places[i] == &globals)
05369          ast_rwlock_rdlock(&globalslock);
05370       AST_LIST_TRAVERSE(places[i], variables, entries) {
05371          if (strcasecmp(ast_var_name(variables), var)==0) {
05372             s = ast_var_value(variables);
05373             break;
05374          }
05375       }
05376       if (places[i] == &globals)
05377          ast_rwlock_unlock(&globalslock);
05378    }
05379    if (s == &not_found || s == NULL)
05380       *ret = NULL;
05381    else {
05382       if (s != workspace)
05383          ast_copy_string(workspace, s, workspacelen);
05384       *ret = workspace;
05385       if (need_substring)
05386          *ret = substring(*ret, offset, length, workspace, workspacelen);
05387    }
05388 }
05389 
05390 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
05391 {
05392    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
05393       zero-filled */
05394    char *cp4;
05395    const char *tmp, *whereweare;
05396    int length, offset, offset2, isfunction;
05397    char *workspace = NULL;
05398    char *ltmp = NULL, *var = NULL;
05399    char *nextvar, *nextexp, *nextthing;
05400    char *vars, *vare;
05401    int pos, brackets, needsub, len;
05402 
05403    *cp2 = 0; /* just in case there's nothing to do */
05404    whereweare=tmp=cp1;
05405    while (!ast_strlen_zero(whereweare) && count) {
05406       /* Assume we're copying the whole remaining string */
05407       pos = strlen(whereweare);
05408       nextvar = NULL;
05409       nextexp = NULL;
05410       nextthing = strchr(whereweare, '$');
05411       if (nextthing) {
05412          switch (nextthing[1]) {
05413          case '{':
05414             nextvar = nextthing;
05415             pos = nextvar - whereweare;
05416             break;
05417          case '[':
05418             nextexp = nextthing;
05419             pos = nextexp - whereweare;
05420             break;
05421          }
05422       }
05423 
05424       if (pos) {
05425          /* Can't copy more than 'count' bytes */
05426          if (pos > count)
05427             pos = count;
05428 
05429          /* Copy that many bytes */
05430          memcpy(cp2, whereweare, pos);
05431 
05432          count -= pos;
05433          cp2 += pos;
05434          whereweare += pos;
05435          *cp2 = 0;
05436       }
05437 
05438       if (nextvar) {
05439          /* We have a variable.  Find the start and end, and determine
05440             if we are going to have to recursively call ourselves on the
05441             contents */
05442          vars = vare = nextvar + 2;
05443          brackets = 1;
05444          needsub = 0;
05445 
05446          /* Find the end of it */
05447          while (brackets && *vare) {
05448             if ((vare[0] == '$') && (vare[1] == '{')) {
05449                needsub++;
05450             } else if (vare[0] == '{') {
05451                brackets++;
05452             } else if (vare[0] == '}') {
05453                brackets--;
05454             } else if ((vare[0] == '$') && (vare[1] == '['))
05455                needsub++;
05456             vare++;
05457          }
05458          if (brackets)
05459             ast_log(LOG_NOTICE, "Error in extension logic (missing '}' in '%s')\n", cp1);
05460          len = vare - vars - 1;
05461 
05462          /* Skip totally over variable string */
05463          whereweare += (len + 3);
05464 
05465          if (!var)
05466             var = alloca(VAR_BUF_SIZE);
05467 
05468          /* Store variable name (and truncate) */
05469          ast_copy_string(var, vars, len + 1);
05470 
05471          /* Substitute if necessary */
05472          if (needsub) {
05473             if (!ltmp)
05474                ltmp = alloca(VAR_BUF_SIZE);
05475 
05476             memset(ltmp, 0, VAR_BUF_SIZE);
05477             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
05478             vars = ltmp;
05479          } else {
05480             vars = var;
05481          }
05482 
05483          if (!workspace)
05484             workspace = alloca(VAR_BUF_SIZE);
05485 
05486          workspace[0] = '\0';
05487 
05488          parse_variable_name(vars, &offset, &offset2, &isfunction);
05489          if (isfunction) {
05490             /* Evaluate function */
05491             cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
05492             if (option_debug)
05493                ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
05494          } else {
05495             /* Retrieve variable value */
05496             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
05497          }
05498          if (cp4) {
05499             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
05500 
05501             length = strlen(cp4);
05502             if (length > count)
05503                length = count;
05504             memcpy(cp2, cp4, length);
05505             count -= length;
05506             cp2 += length;
05507             *cp2 = 0;
05508          }
05509       } else if (nextexp) {
05510          /* We have an expression.  Find the start and end, and determine
05511             if we are going to have to recursively call ourselves on the
05512             contents */
05513          vars = vare = nextexp + 2;
05514          brackets = 1;
05515          needsub = 0;
05516 
05517          /* Find the end of it */
05518          while (brackets && *vare) {
05519             if ((vare[0] == '$') && (vare[1] == '[')) {
05520                needsub++;
05521                brackets++;
05522                vare++;
05523             } else if (vare[0] == '[') {
05524                brackets++;
05525             } else if (vare[0] == ']') {
05526                brackets--;
05527             } else if ((vare[0] == '$') && (vare[1] == '{')) {
05528                needsub++;
05529                vare++;
05530             }
05531             vare++;
05532          }
05533          if (brackets)
05534             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
05535          len = vare - vars - 1;
05536 
05537          /* Skip totally over expression */
05538          whereweare += (len + 3);
05539 
05540          if (!var)
05541             var = alloca(VAR_BUF_SIZE);
05542 
05543          /* Store variable name (and truncate) */
05544          ast_copy_string(var, vars, len + 1);
05545 
05546          /* Substitute if necessary */
05547          if (needsub) {
05548             if (!ltmp)
05549                ltmp = alloca(VAR_BUF_SIZE);
05550 
05551             memset(ltmp, 0, VAR_BUF_SIZE);
05552             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
05553             vars = ltmp;
05554          } else {
05555             vars = var;
05556          }
05557 
05558          length = ast_expr(vars, cp2, count, NULL);
05559 
05560          if (length) {
05561             if (option_debug)
05562                ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
05563             count -= length;
05564             cp2 += length;
05565             *cp2 = 0;
05566          }
05567       } else
05568          break;
05569    }
05570 }
05571 
05572 static void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
05573 {
05574    pbx_substitute_variables_helper_full(c, NULL, cp1, cp2, count);
05575 }
05576 
05577 
05578 static int pbx_load_config(const char *config_file);
05579 
05580 static int pbx_load_config(const char *config_file)
05581 {
05582    struct ast_config *cfg;
05583    char *end;
05584    char *label;
05585    char realvalue[256];
05586    int lastpri = -2;
05587    struct ast_context *con;
05588    struct ast_variable *v;
05589    const char *cxt;
05590    const char *aft;
05591 
05592    cfg = localized_config_load(config_file);
05593    if (!cfg)
05594       return 0;
05595 
05596    /* Use existing config to populate the PBX table */
05597    static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
05598    write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
05599    if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
05600       autofallthrough_config = ast_true(aft);
05601    clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
05602 
05603    if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext"))) 
05604       ast_copy_string(userscontext, cxt, sizeof(userscontext));
05605    else
05606       ast_copy_string(userscontext, "default", sizeof(userscontext));
05607                             
05608    for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
05609       memset(realvalue, 0, sizeof(realvalue));
05610       pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
05611       pbx_builtin_setvar_helper(NULL, v->name, realvalue);
05612    }
05613    for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
05614       /* All categories but "general" or "globals" are considered contexts */
05615       if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
05616          continue;
05617       con=ast_context_find_or_create(&local_contexts,NULL,cxt, global_registrar);
05618       if (con == NULL)
05619          continue;
05620 
05621       for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
05622          if (!strcasecmp(v->name, "exten")) {
05623             char *tc = ast_strdup(v->value);
05624             if (tc) {
05625                int ipri = -2;
05626                char realext[256]="";
05627                char *plus, *firstp, *firstc;
05628                char *pri, *appl, *data, *cidmatch;
05629                char *stringp = tc;
05630                char *ext = strsep(&stringp, ",");
05631                if (!ext)
05632                   ext="";
05633                pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
05634                cidmatch = strchr(realext, '/');
05635                if (cidmatch) {
05636                   *cidmatch++ = '\0';
05637                   ast_shrink_phone_number(cidmatch);
05638                }
05639                pri = strsep(&stringp, ",");
05640                if (!pri)
05641                   pri="";
05642                label = strchr(pri, '(');
05643                if (label) {
05644                   *label++ = '\0';
05645                   end = strchr(label, ')');
05646                   if (end)
05647                      *end = '\0';
05648                   else
05649                      ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
05650                }
05651                plus = strchr(pri, '+');
05652                if (plus)
05653                   *plus++ = '\0';
05654                if (!strcmp(pri,"hint"))
05655                   ipri=PRIORITY_HINT;
05656                else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
05657                   if (lastpri > -2)
05658                      ipri = lastpri + 1;
05659                   else
05660                      ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
05661                } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
05662                   if (lastpri > -2)
05663                      ipri = lastpri;
05664                   else
05665                      ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
05666                } else if (sscanf(pri, "%30d", &ipri) != 1 &&
05667                    (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
05668                   ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
05669                   ipri = 0;
05670                }
05671                appl = S_OR(stringp, "");
05672                /* Find the first occurrence of either '(' or ',' */
05673                firstc = strchr(appl, ',');
05674                firstp = strchr(appl, '(');
05675                if (firstc && (!firstp || firstc < firstp)) {
05676                   /* comma found, no parenthesis */
05677                   /* or both found, but comma found first */
05678                   appl = strsep(&stringp, ",");
05679                   data = stringp;
05680                } else if (!firstc && !firstp) {
05681                   /* Neither found */
05682                   data = "";
05683                } else {
05684                   /* Final remaining case is parenthesis found first */
05685                   appl = strsep(&stringp, "(");
05686                   data = stringp;
05687                   end = strrchr(data, ')');
05688                   if ((end = strrchr(data, ')'))) {
05689                      *end = '\0';
05690                   } else {
05691                      ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
05692                   }
05693                   ast_process_quotes_and_slashes(data, ',', '|');
05694                }
05695 
05696                if (!data)
05697                   data="";
05698                appl = ast_skip_blanks(appl);
05699                if (ipri) {
05700                   if (plus)
05701                      ipri += atoi(plus);
05702                   lastpri = ipri;
05703                   if (!ast_opt_dont_warn && !strcmp(realext, "_."))
05704                      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);
05705                   if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, global_registrar)) {
05706                      ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
05707                   }
05708                }
05709                free(tc);
05710             }
05711          } else if (!strcasecmp(v->name, "include")) {
05712             memset(realvalue, 0, sizeof(realvalue));
05713             pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
05714             if (ast_context_add_include2(con, realvalue, global_registrar))
05715                ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
05716          } else if (!strcasecmp(v->name, "ignorepat")) {
05717             memset(realvalue, 0, sizeof(realvalue));
05718             pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
05719             if (ast_context_add_ignorepat2(con, realvalue, global_registrar))
05720                ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
05721          } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
05722             char *stringp= realvalue;
05723             char *appl, *data;
05724 
05725             memset(realvalue, 0, sizeof(realvalue));
05726             if (!strcasecmp(v->name, "switch"))
05727                pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
05728             else
05729                ast_copy_string(realvalue, v->value, sizeof(realvalue));
05730             appl = strsep(&stringp, "/");
05731             data = strsep(&stringp, ""); /* XXX what for ? */
05732             if (!data)
05733                data = "";
05734             if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), global_registrar))
05735                ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
05736          } else {
05737             ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
05738          }
05739       }
05740    }
05741    ast_config_destroy(cfg);
05742    return 1;
05743 }
05744 
05745 static void __ast_context_destroy(struct ast_context *con, const char *registrar)
05746 {
05747    struct ast_context *tmp, *tmpl=NULL;
05748    struct ast_include *tmpi;
05749    struct ast_sw *sw;
05750    struct ast_exten *e, *el, *en;
05751    struct ast_ignorepat *ipi;
05752 
05753    for (tmp = contexts; tmp; ) {
05754       struct ast_context *next;  /* next starting point */
05755       for (; tmp; tmpl = tmp, tmp = tmp->next) {
05756          if (option_debug)
05757             ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
05758          if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
05759               (!con || !strcasecmp(tmp->name, con->name)) )
05760             break;   /* found it */
05761       }
05762       if (!tmp)   /* not found, we are done */
05763          break;
05764       ast_wrlock_context(tmp);
05765       if (option_debug)
05766          ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
05767       next = tmp->next;
05768       if (tmpl)
05769          tmpl->next = next;
05770       else
05771          contexts = next;
05772       /* Okay, now we're safe to let it go -- in a sense, we were
05773          ready to let it go as soon as we locked it. */
05774       ast_unlock_context(tmp);
05775       for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
05776          struct ast_include *tmpil = tmpi;
05777          tmpi = tmpi->next;
05778          free(tmpil);
05779       }
05780       for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
05781          struct ast_ignorepat *ipl = ipi;
05782          ipi = ipi->next;
05783          free(ipl);
05784       }
05785       while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
05786          free(sw);
05787       for (e = tmp->root; e;) {
05788          for (en = e->peer; en;) {
05789             el = en;
05790             en = en->peer;
05791             destroy_exten(el);
05792          }
05793          el = e;
05794          e = e->next;
05795          destroy_exten(el);
05796       }
05797       ast_rwlock_destroy(&tmp->lock);
05798       free(tmp);
05799       /* if we have a specific match, we are done, otherwise continue */
05800       tmp = con ? NULL : next;
05801    }
05802 }
05803 
05804 void localized_context_destroy(struct ast_context *con, const char *registrar);
05805 
05806 void localized_context_destroy(struct ast_context *con, const char *registrar)
05807 {
05808    ast_wrlock_contexts();
05809    __ast_context_destroy(con,registrar);
05810    ast_unlock_contexts();
05811 }
05812 
05813 
05814 static void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
05815 {
05816    struct ast_context *tmp, *lasttmp = NULL;
05817 
05818    /* it is very important that this function hold the hint list lock _and_ the conlock
05819       during its operation; not only do we need to ensure that the list of contexts
05820       and extensions does not change, but also that no hint callbacks (watchers) are
05821       added or removed during the merge/delete process
05822 
05823       in addition, the locks _must_ be taken in this order, because there are already
05824       other code paths that use this order
05825    */
05826    ast_wrlock_contexts();
05827 
05828    tmp = *extcontexts;
05829    if (registrar) {
05830       /* XXX remove previous contexts from same registrar */
05831       if (option_debug)
05832          ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
05833       __ast_context_destroy(NULL,registrar);
05834       while (tmp) {
05835          lasttmp = tmp;
05836          tmp = tmp->next;
05837       }
05838    } else {
05839       /* XXX remove contexts with the same name */
05840       while (tmp) {
05841          ast_log(LOG_WARNING, "must remove %s  reg %s\n", tmp->name, tmp->registrar);
05842          __ast_context_destroy(tmp,tmp->registrar);
05843          lasttmp = tmp;
05844          tmp = tmp->next;
05845       }
05846    }
05847    if (lasttmp) {
05848       lasttmp->next = contexts;
05849       contexts = *extcontexts;
05850       *extcontexts = NULL;
05851    } else
05852       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
05853 
05854    ast_unlock_contexts();
05855 
05856    return;
05857 }
05858 
05859 void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
05860 {
05861    ast_merge_contexts_and_delete(extcontexts, registrar);
05862 }
05863 
05864 static int ast_context_verify_includes(struct ast_context *con)
05865 {
05866    struct ast_include *inc = NULL;
05867    int res = 0;
05868 
05869    while ( (inc = ast_walk_context_includes(con, inc)) )
05870       if (!ast_context_find(inc->rname)) {
05871          res = -1;
05872          if (strcasecmp(inc->rname,"parkedcalls")!=0)
05873             ast_log(LOG_WARNING, "Context '%s' tries to include the nonexistent context '%s'\n",
05874                   ast_get_context_name(con), inc->rname);
05875       }
05876    return res;
05877 }
05878 
05879 int localized_context_verify_includes(struct ast_context *con);
05880 
05881 int localized_context_verify_includes(struct ast_context *con)
05882 {
05883    return ast_context_verify_includes(con);
05884 }
05885 
05886 int localized_pbx_load_module(void);
05887 
05888 int localized_pbx_load_module(void)
05889 {
05890    struct ast_context *con;
05891 
05892    if(!pbx_load_config(config_filename))
05893       return -1 /* AST_MODULE_LOAD_DECLINE*/;
05894 
05895    /* pbx_load_users(); */ /* does this affect the dialplan? */
05896 
05897    ast_merge_contexts_and_delete(&local_contexts, global_registrar);
05898 
05899    for (con = NULL; (con = ast_walk_contexts(con));)
05900       ast_context_verify_includes(con);
05901 
05902    printf("=== Loading extensions.conf ===\n");
05903    con = 0;
05904    while ((con = ast_walk_contexts(con)) ) {
05905       printf("Context: %s\n", con->name);
05906    }
05907    printf("=========\n");
05908    
05909    return 0;
05910 }
05911 
05912 /* For platforms which don't have pthread_rwlock_timedrdlock() */
05913 struct timeval ast_tvnow(void);
05914 
05915 struct timeval ast_tvnow(void)
05916 {
05917    struct timeval t;
05918    gettimeofday(&t, NULL);
05919    return t;
05920 }
05921 

Generated on Thu Apr 16 06:27:34 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6