Asterisk - The Open Source Telephony Project GIT-master-57e2743
Loading...
Searching...
No Matches
extconf.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2006, Digium, Inc.
5 *
6 * Steve Murphy <murf@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19
20/*!
21 * \file
22 * A condensation of the pbx_config stuff, to read into extensions.conf, and provide an interface to the data there,
23 * for operations outside of asterisk. A huge, awful hack.
24 *
25 */
26
27/*!
28 * \li \ref extconf.c uses the configuration file \ref extconfig.conf and \ref extensions.conf and \ref asterisk.conf
29 * \addtogroup configuration_file Configuration Files
30 */
31
32/*!
33 * \page extconfig.conf extconfig.conf
34 * \verbinclude extconfig.conf.sample
35 */
36
37/*!
38 * \page extensions.conf extensions.conf
39 * \verbinclude extensions.conf.sample
40 */
41
42/*** MODULEINFO
43 <support_level>extended</support_level>
44 ***/
45
46#define ASTMM_LIBC ASTMM_IGNORE
47#include "asterisk.h"
48
49#undef DEBUG_THREADS
50
51#include "asterisk/compat.h"
52#include "asterisk/paths.h" /* we use AST_CONFIG_DIR */
53
54#include <errno.h>
55#include <time.h>
56#include <sys/stat.h>
57#include <sys/types.h>
58#include <sys/time.h>
59#include <sys/resource.h>
60#include <sys/wait.h>
61#include <stdarg.h>
62#include <string.h>
63#include <locale.h>
64#include <ctype.h>
65#if !defined(SOLARIS) && !defined(__CYGWIN__)
66#include <err.h>
67#endif
68#include <regex.h>
69#include <limits.h>
70#include <pthread.h>
71#include <netdb.h>
72#include <sys/param.h>
73#include <signal.h>
74
75static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
76void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
77
78#define AST_API_MODULE 1 /* gimme the inline defs! */
79struct ast_channel
80{
81 char x; /* basically empty! */
82};
83
84
85
86#include "asterisk/inline_api.h"
87#include "asterisk/endian.h"
88#include "asterisk/ast_expr.h"
89#include "asterisk/extconf.h"
90
91/* logger.h */
92
93#define EVENTLOG "event_log"
94#define QUEUELOG "queue_log"
95
96#define DEBUG_M(a) { \
97 a; \
98}
99
100#define VERBOSE_PREFIX_1 " "
101#define VERBOSE_PREFIX_2 " == "
102#define VERBOSE_PREFIX_3 " -- "
103#define VERBOSE_PREFIX_4 " > "
104
105void ast_log_backtrace(void);
106
107void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
108 __attribute__((format(printf, 5, 6)));
109
110/* IN CONFLICT: void ast_verbose(const char *fmt, ...)
111 __attribute__((format(printf, 1, 2))); */
112
113void ast_console_puts(const char *string);
114
115#define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
116
117#ifdef LOG_DEBUG
118#undef LOG_DEBUG
119#endif
120#define __LOG_DEBUG 0
121#define LOG_DEBUG __LOG_DEBUG, _A_
122
123#ifdef LOG_EVENT
124#undef LOG_EVENT
125#endif
126#define __LOG_EVENT 1
127#define LOG_EVENT __LOG_EVENT, _A_
128
129#ifdef LOG_NOTICE
130#undef LOG_NOTICE
131#endif
132#define __LOG_NOTICE 2
133#define LOG_NOTICE __LOG_NOTICE, _A_
134
135#ifdef LOG_WARNING
136#undef LOG_WARNING
137#endif
138#define __LOG_WARNING 3
139#define LOG_WARNING __LOG_WARNING, _A_
140
141#ifdef LOG_ERROR
142#undef LOG_ERROR
143#endif
144#define __LOG_ERROR 4
145#define LOG_ERROR __LOG_ERROR, _A_
146
147#ifdef LOG_VERBOSE
148#undef LOG_VERBOSE
149#endif
150#define __LOG_VERBOSE 5
151#define LOG_VERBOSE __LOG_VERBOSE, _A_
152
153#ifdef LOG_DTMF
154#undef LOG_DTMF
155#endif
156#define __LOG_DTMF 6
157#define LOG_DTMF __LOG_DTMF, _A_
158
159/* lock.h */
160#define _ASTERISK_LOCK_H /* A small indication that this is horribly wrong. */
161
162#ifndef HAVE_MTX_PROFILE
163#define __MTX_PROF(a) return pthread_mutex_lock((a))
164#else
165int mtx_prof = -1;
166
167#define __MTX_PROF(a) do { \
168 int i; \
169 /* profile only non-blocking events */ \
170 ast_mark(mtx_prof, 1); \
171 i = pthread_mutex_trylock((a)); \
172 ast_mark(mtx_prof, 0); \
173 if (!i) \
174 return i; \
175 else \
176 return pthread_mutex_lock((a)); \
177 } while (0)
178#endif /* HAVE_MTX_PROFILE */
179
180#define AST_PTHREADT_NULL (pthread_t) -1
181#define AST_PTHREADT_STOP (pthread_t) -2
182
183#if defined(SOLARIS) || defined(BSD)
184#define AST_MUTEX_INIT_W_CONSTRUCTORS
185#endif /* SOLARIS || BSD */
186
187/* Asterisk REQUIRES recursive (not error checking) mutexes
188 and will not run without them. */
189#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
190#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
191#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
192#else
193#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
194#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
195#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
196
197#ifdef DEBUG_THREADS
198
199#define log_mutex_error(canlog, ...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
200
201#ifdef THREAD_CRASH
202#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
203#else
204#define DO_THREAD_CRASH do { } while (0)
205#endif
206
207#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
208
209#define AST_MAX_REENTRANCY 10
210
211struct ast_mutex_info {
213 /*! Track which thread holds this lock */
214 unsigned int track:1;
215 const char *file[AST_MAX_REENTRANCY];
216 int lineno[AST_MAX_REENTRANCY];
217 int reentrancy;
218 const char *func[AST_MAX_REENTRANCY];
219 pthread_t thread[AST_MAX_REENTRANCY];
220};
221
222typedef struct ast_mutex_info ast_mutex_t;
223
225
226static pthread_mutex_t empty_mutex;
227
228static void __attribute__((constructor)) init_empty_mutex(void)
229{
230 memset(&empty_mutex, 0, sizeof(empty_mutex));
231}
232
233static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
234 const char *mutex_name, ast_mutex_t *t,
235 pthread_mutexattr_t *attr)
236{
237#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
238 int canlog = strcmp(filename, "logger.c");
239
240 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
241 if ((t->mutex) != (empty_mutex)) {
242 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is already initialized.\n",
243 filename, lineno, func, mutex_name);
244 log_mutex_error(canlog, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
245 t->file[0], t->lineno[0], t->func[0], mutex_name);
246 DO_THREAD_CRASH;
247 return 0;
248 }
249 }
250#endif
251
252 t->file[0] = filename;
253 t->lineno[0] = lineno;
254 t->func[0] = func;
255 t->thread[0] = 0;
256 t->reentrancy = 0;
257
258 return pthread_mutex_init(&t->mutex, attr);
259}
260
261static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
262 const char *mutex_name, ast_mutex_t *t)
263{
264 static pthread_mutexattr_t attr;
265
266 pthread_mutexattr_init(&attr);
267 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
268
269 return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
270}
271#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
272
273static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
274 const char *mutex_name, ast_mutex_t *t)
275{
276 int res;
277 int canlog = strcmp(filename, "logger.c");
278
279#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
280 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
281 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
282 filename, lineno, func, mutex_name);
283 }
284#endif
285
286 res = pthread_mutex_trylock(&t->mutex);
287 switch (res) {
288 case 0:
290 break;
291 case EINVAL:
292 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
293 filename, lineno, func, mutex_name);
294 break;
295 case EBUSY:
296 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
297 filename, lineno, func, mutex_name);
298 log_mutex_error(canlog, "%s line %d (%s): Error: '%s' was locked here.\n",
299 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
300 break;
301 }
302
303 if ((res = pthread_mutex_destroy(&t->mutex)))
304 log_mutex_error(canlog, "%s line %d (%s): Error destroying mutex: %s\n",
305 filename, lineno, func, strerror(res));
306#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
307 else
309#endif
310 t->file[0] = filename;
311 t->lineno[0] = lineno;
312 t->func[0] = func;
313
314 return res;
315}
316
317static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
318 const char* mutex_name, ast_mutex_t *t)
319{
320 int res;
321 int canlog = strcmp(filename, "logger.c");
322
323#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
324 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
325 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
326 filename, lineno, func, mutex_name);
328 }
329#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
330
331#ifdef DETECT_DEADLOCKS
332 {
333 time_t seconds = time(NULL);
334 time_t current;
335 do {
336#ifdef HAVE_MTX_PROFILE
337 ast_mark(mtx_prof, 1);
338#endif
339 res = pthread_mutex_trylock(&t->mutex);
340#ifdef HAVE_MTX_PROFILE
341 ast_mark(mtx_prof, 0);
342#endif
343 if (res == EBUSY) {
344 current = time(NULL);
345 if ((current - seconds) && (!((current - seconds) % 5))) {
346 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
347 filename, lineno, func, (int)(current - seconds), mutex_name);
348 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
349 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
350 t->func[t->reentrancy-1], mutex_name);
351 }
352 usleep(200);
353 }
354 } while (res == EBUSY);
355 }
356#else
357#ifdef HAVE_MTX_PROFILE
358 ast_mark(mtx_prof, 1);
359 res = pthread_mutex_trylock(&t->mutex);
360 ast_mark(mtx_prof, 0);
361 if (res)
362#endif
363 res = pthread_mutex_lock(&t->mutex);
364#endif /* DETECT_DEADLOCKS */
365
366 if (!res) {
367 if (t->reentrancy < AST_MAX_REENTRANCY) {
368 t->file[t->reentrancy] = filename;
369 t->lineno[t->reentrancy] = lineno;
370 t->func[t->reentrancy] = func;
371 t->thread[t->reentrancy] = pthread_self();
372 t->reentrancy++;
373 } else {
374 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
375 filename, lineno, func, mutex_name);
376 }
377 } else {
378 log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
379 filename, lineno, func, strerror(errno));
380 DO_THREAD_CRASH;
381 }
382
383 return res;
384}
385
386static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
387 const char* mutex_name, ast_mutex_t *t)
388{
389 int res;
390 int canlog = strcmp(filename, "logger.c");
391
392#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
393 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
394 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
395 filename, lineno, func, mutex_name);
397 }
398#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
399
400 if (!(res = pthread_mutex_trylock(&t->mutex))) {
401 if (t->reentrancy < AST_MAX_REENTRANCY) {
402 t->file[t->reentrancy] = filename;
403 t->lineno[t->reentrancy] = lineno;
404 t->func[t->reentrancy] = func;
405 t->thread[t->reentrancy] = pthread_self();
406 t->reentrancy++;
407 } else {
408 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
409 filename, lineno, func, mutex_name);
410 }
411 } else {
412 log_mutex_error(canlog, "%s line %d (%s): Warning: '%s' was locked here.\n",
413 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
414 }
415
416 return res;
417}
418
419static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
420 const char *mutex_name, ast_mutex_t *t)
421{
422 int res;
423 int canlog = strcmp(filename, "logger.c");
424
425#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
426 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
427 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
428 filename, lineno, func, mutex_name);
429 }
430#endif
431
432 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
433 log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
434 filename, lineno, func, mutex_name);
435 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
436 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
437 DO_THREAD_CRASH;
438 }
439
440 if (--t->reentrancy < 0) {
441 log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
442 filename, lineno, func, mutex_name);
443 t->reentrancy = 0;
444 }
445
446 if (t->reentrancy < AST_MAX_REENTRANCY) {
447 t->file[t->reentrancy] = NULL;
448 t->lineno[t->reentrancy] = 0;
449 t->func[t->reentrancy] = NULL;
450 t->thread[t->reentrancy] = 0;
451 }
452
453 if ((res = pthread_mutex_unlock(&t->mutex))) {
454 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
455 filename, lineno, func, strerror(res));
456 DO_THREAD_CRASH;
457 }
458
459 return res;
460}
461
462#else /* !DEBUG_THREADS */
463
464
466
467#define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
468
469static inline int ast_mutex_init(ast_mutex_t *pmutex)
470{
471 pthread_mutexattr_t attr;
472
473 pthread_mutexattr_init(&attr);
474 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
475
476 return pthread_mutex_init(pmutex, &attr);
477}
478
479#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
480
482
483#endif /* !DEBUG_THREADS */
484
485#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
486/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
487 constructors/destructors to create/destroy mutexes. */
488#define __AST_MUTEX_DEFINE(scope, mutex) \
489 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
490static void __attribute__((constructor)) init_##mutex(void) \
491{ \
492 ast_mutex_init(&mutex); \
493}
494#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
495/* By default, use static initialization of mutexes. */
496#define __AST_MUTEX_DEFINE(scope, mutex) \
497 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
498#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
499
500#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
501#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
502#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
503
504#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
505
506#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
507
508#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
509
510#ifndef __linux__
511#define pthread_create __use_ast_pthread_create_instead__
512#endif
513
514typedef pthread_rwlock_t ast_rwlock_t;
515
516static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
517{
518 pthread_rwlockattr_t attr;
519
520 pthread_rwlockattr_init(&attr);
521
522#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
523 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
524#endif
525
526 return pthread_rwlock_init(prwlock, &attr);
527}
528
529static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
530{
531 return pthread_rwlock_destroy(prwlock);
532}
533
534static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
535{
536 return pthread_rwlock_unlock(prwlock);
537}
538
539static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
540{
541 return pthread_rwlock_rdlock(prwlock);
542}
543
544static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
545{
546 return pthread_rwlock_wrlock(prwlock);
547}
548
549/* Statically declared read/write locks */
550
551#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
552#define __AST_RWLOCK_DEFINE(scope, rwlock) \
553 scope ast_rwlock_t rwlock; \
554static void __attribute__((constructor)) init_##rwlock(void) \
555{ \
556 ast_rwlock_init(&rwlock); \
557} \
558static void __attribute__((destructor)) fini_##rwlock(void) \
559{ \
560 ast_rwlock_destroy(&rwlock); \
561}
562#else
563#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
564#define __AST_RWLOCK_DEFINE(scope, rwlock) \
565 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
566#endif
567
568#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
569
570/*
571 * Initial support for atomic instructions.
572 * For platforms that have it, use the native cpu instruction to
573 * implement them. For other platforms, resort to a 'slow' version
574 * (defined in utils.c) that protects the atomic instruction with
575 * a single lock.
576 * The slow versions is always available, for testing purposes,
577 * as ast_atomic_fetchadd_int_slow()
578 */
579
580#if defined(HAVE_OSX_ATOMICS)
581#include "libkern/OSAtomic.h"
582#endif
583
584/*! \brief Atomically add v to *p and return * the previous value of *p.
585 * This can be used to handle reference counts, and the return value
586 * can be used to generate unique identifiers.
587 */
588
589#if defined(HAVE_GCC_ATOMICS)
590AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
591{
592 return __sync_fetch_and_add(p, v);
594#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
595AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
596{
597 return OSAtomicAdd32(v, (int32_t *) p);
598})
599#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
600AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
601{
602 return OSAtomicAdd64(v, (int64_t *) p);
603#elif defined (__i386__) || defined(__x86_64__)
604AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
605{
606 __asm __volatile (
607 " lock xaddl %0, %1 ; "
608 : "+r" (v), /* 0 (result) */
609 "=m" (*p) /* 1 */
610 : "m" (*p)); /* 2 */
611 return (v);
612})
613#else
614static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
615{
616 int ret;
617 ret = *p;
618 *p += v;
619 return ret;
620}
621AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
622{
623 return ast_atomic_fetchadd_int_slow(p, v);
624})
625#endif
626
627/*! \brief decrement *p by 1 and return true if the variable has reached 0.
628 * Useful e.g. to check if a refcount has reached 0.
629 */
630#if defined(HAVE_GCC_ATOMICS)
631AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
632{
633 return __sync_sub_and_fetch(p, 1) == 0;
635#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
636AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
637{
638 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
639})
640#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
641AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
642{
643 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
644#else
645AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
646{
647 int a = ast_atomic_fetchadd_int(p, -1);
648 return a == 1; /* true if the value is 0 now (so it was 1 previously) */
649})
650#endif
651
652#ifdef DEBUG_CHANNEL_LOCKS
653/*! \brief Lock AST channel (and print debugging output)
654\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
655int ast_channel_lock(struct ast_channel *chan);
656
657/*! \brief Unlock AST channel (and print debugging output)
658\note You need to enable DEBUG_CHANNEL_LOCKS for this function
659*/
660int ast_channel_unlock(struct ast_channel *chan);
661
662/*! \brief Lock AST channel (and print debugging output)
663\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
664int ast_channel_trylock(struct ast_channel *chan);
665#endif
666
667
668#include "asterisk/hashtab.h"
669#include "asterisk/ael_structs.h"
670#include "asterisk/pval.h"
671
672/* from utils.h */
673
674struct ast_flags { /* stolen from utils.h */
675 unsigned int flags;
676};
677#if __BYTE_ORDER == __BIG_ENDIAN
678#define SWAP64_32(flags) (((uint64_t)(flags) << 32) | ((uint64_t)(flags) >> 32))
679#else
680#define SWAP64_32(flags) (flags)
681#endif
682
683extern uint64_t __unsigned_int_flags_dummy64;
684
685#define ast_test_flag64(p,flag) ({ \
686 typeof ((p)->flags) __p = (p)->flags; \
687 typeof (__unsigned_int_flags_dummy64) __x = 0; \
688 (void) (&__p == (typeof(__p)*)&__x); \
689 ((p)->flags & SWAP64_32(flag)); \
690 })
691
692/* from config.c */
693
694#define MAX_NESTED_COMMENTS 128
695#define COMMENT_START ";--"
696#define COMMENT_END "--;"
697#define COMMENT_META ';'
698#define COMMENT_TAG '-'
699
700static char *extconfig_conf = "extconfig.conf";
701
702/*! Growable string buffer */
703static char *comment_buffer; /*!< this will be a comment collector.*/
704static int comment_buffer_size; /*!< the amount of storage so far alloc'd for the comment_buffer */
705
706static char *lline_buffer; /*!< A buffer for stuff behind the ; */
708
709#define CB_INCR 250
710
711struct ast_comment {
712 struct ast_comment *next;
713 char cmt[0];
714};
715
716static void CB_INIT(void)
717{
718 if (!comment_buffer) {
720 if (!comment_buffer)
721 return;
722 comment_buffer[0] = 0;
725 if (!lline_buffer)
726 return;
727 lline_buffer[0] = 0;
729 } else {
730 comment_buffer[0] = 0;
731 lline_buffer[0] = 0;
732 }
733}
734
735static void CB_ADD(char *str)
736{
737 int rem = comment_buffer_size - strlen(comment_buffer) - 1;
738 int siz = strlen(str);
739 if (rem < siz+1) {
741 if (!comment_buffer)
742 return;
744 }
745 strcat(comment_buffer,str);
746}
747
748static void CB_ADD_LEN(char *str, int len)
749{
750 int cbl = strlen(comment_buffer) + 1;
751 int rem = comment_buffer_size - cbl;
752 if (rem < len+1) {
754 if (!comment_buffer)
755 return;
757 }
758 strncat(comment_buffer,str,len); /* safe */
759 comment_buffer[cbl+len-1] = 0;
760}
761
762static void LLB_ADD(char *str)
763{
764 int rem = lline_buffer_size - strlen(lline_buffer) - 1;
765 int siz = strlen(str);
766 if (rem < siz+1) {
768 if (!lline_buffer)
769 return;
770 lline_buffer_size += CB_INCR + siz + 1;
771 }
772 strcat(lline_buffer,str);
773}
774
775static void CB_RESET(void )
776{
777 comment_buffer[0] = 0;
778 lline_buffer[0] = 0;
779}
780
781/*! \brief Keep track of how many threads are currently trying to wait*() on
782 * a child process */
783static unsigned int safe_system_level = 0;
784static struct sigaction safe_system_prev_handler;
785
786/*! \brief NULL handler so we can collect the child exit status */
787static void _null_sig_handler(int sig)
788{
789
790}
791
792static struct sigaction null_sig_handler = {
793 .sa_handler = _null_sig_handler,
794 .sa_flags = SA_RESTART,
795};
796
797void ast_replace_sigchld(void);
798
800{
801 unsigned int level;
802
803 level = safe_system_level++;
804
805 /* only replace the handler if it has not already been done */
806 if (level == 0) {
807 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
808 }
809}
810
811void ast_unreplace_sigchld(void);
812
814{
815 unsigned int level;
816
817 level = --safe_system_level;
818
819 /* only restore the handler if we are the last one */
820 if (level == 0) {
821 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
822 }
823}
824
825int ast_safe_system(const char *s);
826
827int ast_safe_system(const char *s)
828{
829 pid_t pid;
830#ifdef HAVE_WORKING_FORK
831 int x;
832#endif
833 int res;
834 int status;
835
836#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
838
839#ifdef HAVE_WORKING_FORK
840 pid = fork();
841#else
842 pid = vfork();
843#endif
844
845 if (pid == 0) {
846#ifdef HAVE_WORKING_FORK
847 /* Close file descriptors and launch system command */
848 for (x = STDERR_FILENO + 1; x < 4096; x++)
849 close(x);
850#endif
851 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
852 _exit(1);
853 } else if (pid > 0) {
854 for(;;) {
855 res = waitpid(pid, &status, 0);
856 if (res > -1) {
857 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
858 break;
859 } else if (errno != EINTR)
860 break;
861 }
862 } else {
863 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
864 res = -1;
865 }
866
868#else
869 res = -1;
870#endif
871
872 return res;
873}
874
875static struct ast_comment *ALLOC_COMMENT(const char *buffer)
876{
877 struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
878 strcpy(x->cmt, buffer);
879 return x;
880}
881
882static struct ast_config_map {
883 struct ast_config_map *next;
884 char *name;
885 char *driver;
886 char *database;
887 char *table;
888 char stuff[0];
890
892
893#define MAX_INCLUDE_LEVEL 10
894
895
896struct ast_category {
897 char name[80];
898 int ignored; /*!< do not let user of the config see this category */
899 int include_level;
900 char *file; /*!< the file name from whence this declaration was read */
901 int lineno;
902 struct ast_comment *precomments;
903 struct ast_comment *sameline;
904 struct ast_variable *root;
905 struct ast_variable *last;
906 struct ast_category *next;
907};
908
909struct ast_config {
910 struct ast_category *root;
911 struct ast_category *last;
912 struct ast_category *current;
913 struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
914 int include_level;
916 struct ast_config_include *includes; /*!< a list of inclusions, which should describe the entire tree */
917};
918
919struct ast_config_include {
920 char *include_location_file; /*!< file name in which the include occurs */
921 int include_location_lineno; /*!< lineno where include occurred */
922 int exec; /*!< set to non-zero if itsa #exec statement */
923 char *exec_file; /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
924 char *included_file; /*!< file name included */
925 int inclusion_count; /*!< if the file is included more than once, a running count thereof -- but, worry not,
926 we explode the instances and will include those-- so all entries will be unique */
927 int output; /*!< a flag to indicate if the inclusion has been output */
928 struct ast_config_include *next; /*!< ptr to next inclusion in the list */
929};
930
931typedef 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);
932typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
933typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
934typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
935
936/*! \brief Configuration engine structure, used to define realtime drivers */
937struct ast_config_engine {
938 char *name;
943 struct ast_config_engine *next;
944};
945
947
948/* taken from strings.h */
949
950static force_inline int ast_strlen_zero(const char *s)
951{
952 return (!s || (*s == '\0'));
953}
954
955#define S_OR(a, b) (!ast_strlen_zero(a) ? (a) : (b))
956
958void ast_copy_string(char *dst, const char *src, size_t size),
959{
960 while (*src && size) {
961 *dst++ = *src++;
962 size--;
963 }
964 if (__builtin_expect(!size, 0))
965 dst--;
966 *dst = '\0';
967}
969
971char *ast_skip_blanks(const char *str),
972{
973 while (*str && *str < 33)
974 str++;
975 return (char *)str;
976}
978
979/*!
980 \brief Trims trailing whitespace characters from a string.
981 \param str the input string
982 \return a pointer to the modified string
983 */
985char *ast_trim_blanks(char *str),
986{
987 char *work = str;
988
989 if (work) {
990 work += strlen(work) - 1;
991 /* It's tempting to only want to erase after we exit this loop,
992 but since ast_trim_blanks *could* receive a constant string
993 (which we presumably wouldn't have to touch), we shouldn't
994 actually set anything unless we must, and it's easier just
995 to set each position to \0 than to keep track of a variable
996 for it */
997 while ((work >= str) && *work < 33)
998 *(work--) = '\0';
999 }
1000 return str;
1001}
1003
1004/*!
1005 \brief Strip leading/trailing whitespace from a string.
1006 \param s The string to be stripped (will be modified).
1007 \return The stripped string.
1008
1009 This functions strips all leading and trailing whitespace
1010 characters from the input string, and returns a pointer to
1011 the resulting string. The string is modified in place.
1012*/
1014char *ast_strip(char *s),
1015{
1016 s = ast_skip_blanks(s);
1017 if (s)
1018 ast_trim_blanks(s);
1019 return s;
1020}
1022
1023
1024/* from config.h */
1025
1026struct ast_variable {
1027 char *name;
1028 char *value;
1029 char *file;
1030 int lineno;
1031 int object; /*!< 0 for variable, 1 for object */
1032 int blanklines; /*!< Number of blanklines following entry */
1033 struct ast_comment *precomments;
1034 struct ast_comment *sameline;
1035 struct ast_variable *next;
1036 char stuff[0];
1037};
1038
1039static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
1040static 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);
1041
1042struct ast_config *localized_config_load_with_comments(const char *filename);
1043static char *ast_category_browse(struct ast_config *config, const char *prev);
1044static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
1045static void ast_variables_destroy(struct ast_variable *v);
1046static void ast_config_destroy(struct ast_config *cfg);
1047static 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);
1048static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
1049void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
1050
1051static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
1052
1053static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
1054{
1055 struct ast_variable *variable;
1056 int name_len = strlen(name) + 1;
1057 size_t value_len = strlen(value) + 1;
1058 size_t filename_len = strlen(filename) + 1;
1059
1060 if ((variable = ast_calloc(1, name_len + value_len + filename_len + sizeof(*variable)))) {
1061 variable->name = variable->stuff;
1062 variable->value = variable->stuff + name_len;
1063 variable->file = variable->value + value_len;
1064 strcpy(variable->name,name);
1065 ast_copy_string(variable->value, value, value_len);
1066 ast_copy_string(variable->file, filename, filename_len);
1067 }
1068
1069 return variable;
1070}
1071
1072static 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)
1073{
1074 /* a file should be included ONCE. Otherwise, if one of the instances is changed,
1075 then all be changed. -- how do we know to include it? -- Handling modified
1076 instances is possible, I'd have
1077 to create a new master for each instance. */
1078 struct ast_config_include *inc;
1079
1081 if (inc)
1082 {
1083 inc->inclusion_count++;
1084 snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
1085 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);
1086 } else
1087 *real_included_file_name = 0;
1088
1089 inc = ast_calloc(1,sizeof(struct ast_config_include));
1090 inc->include_location_file = ast_strdup(from_file);
1091 inc->include_location_lineno = from_lineno;
1092 if (!ast_strlen_zero(real_included_file_name))
1093 inc->included_file = ast_strdup(real_included_file_name);
1094 else
1096
1097 inc->exec = is_exec;
1098 if (is_exec)
1100
1101 /* attach this new struct to the conf struct */
1102 inc->next = conf->includes;
1103 conf->includes = inc;
1104
1105 return inc;
1106}
1107
1108void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
1109{
1110 struct ast_config_include *incl;
1111 struct ast_category *cat;
1112 struct ast_variable *v;
1113
1114 int from_len = strlen(from_file);
1115 int to_len = strlen(to_file);
1116
1117 if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
1118 return;
1119
1120 /* the manager code allows you to read in one config file, then
1121 write it back out under a different name. But, the new arrangement
1122 ties output lines to the file name. So, before you try to write
1123 the config file to disk, better riffle thru the data and make sure
1124 the file names are changed.
1125 */
1126 /* file names are on categories, includes (of course), and on variables. So,
1127 traverse all this and swap names */
1128
1129 for (incl = conf->includes; incl; incl=incl->next) {
1130 if (strcmp(incl->include_location_file,from_file) == 0) {
1131 if (from_len >= to_len)
1132 strcpy(incl->include_location_file, to_file);
1133 else {
1135 incl->include_location_file = strdup(to_file);
1136 }
1137 }
1138 }
1139 for (cat = conf->root; cat; cat = cat->next) {
1140 if (strcmp(cat->file,from_file) == 0) {
1141 if (from_len >= to_len)
1142 strcpy(cat->file, to_file);
1143 else {
1144 free(cat->file);
1145 cat->file = strdup(to_file);
1146 }
1147 }
1148 for (v = cat->root; v; v = v->next) {
1149 if (strcmp(v->file,from_file) == 0) {
1150 if (from_len >= to_len)
1151 strcpy(v->file, to_file);
1152 else {
1153 free(v->file);
1154 v->file = strdup(to_file);
1155 }
1156 }
1157 }
1158 }
1159}
1160
1162{
1163 struct ast_config_include *x;
1164 for (x=conf->includes;x;x=x->next)
1165 {
1166 if (strcmp(x->included_file,included_file) == 0)
1167 return x;
1168 }
1169 return 0;
1170}
1171
1172
1173static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
1174
1175static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
1176{
1177 if (!variable)
1178 return;
1179 if (category->last)
1180 category->last->next = variable;
1181 else
1182 category->root = variable;
1183 category->last = variable;
1184 while (category->last->next)
1185 category->last = category->last->next;
1186}
1187
1188static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
1189
1190static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
1191{
1192 struct ast_category *cat;
1193
1194 /* try exact match first, then case-insensitive match */
1195 for (cat = config->root; cat; cat = cat->next) {
1196 if (cat->name == category_name && (ignored || !cat->ignored))
1197 return cat;
1198 }
1199
1200 for (cat = config->root; cat; cat = cat->next) {
1201 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
1202 return cat;
1203 }
1204
1205 return NULL;
1206}
1207
1208static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
1209{
1210 return category_get(config, category_name, 0);
1211}
1212
1213static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
1214{
1215 struct ast_category *cat = NULL;
1216
1217 if (category && config->last_browse && (config->last_browse->name == category))
1218 cat = config->last_browse;
1219 else
1220 cat = ast_category_get(config, category);
1221
1222 return (cat) ? cat->root : NULL;
1223}
1224
1225static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
1226{
1227 struct ast_variable *v;
1228
1229 if (category) {
1230 for (v = ast_variable_browse(config, category); v; v = v->next) {
1231 if (!strcasecmp(variable, v->name))
1232 return v->value;
1233 }
1234 } else {
1235 struct ast_category *cat;
1236
1237 for (cat = config->root; cat; cat = cat->next)
1238 for (v = cat->root; v; v = v->next)
1239 if (!strcasecmp(variable, v->name))
1240 return v->value;
1241 }
1242
1243 return NULL;
1244}
1245
1246static struct ast_variable *variable_clone(const struct ast_variable *old)
1247{
1248 struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
1249
1250 if (new) {
1251 new->lineno = old->lineno;
1252 new->object = old->object;
1253 new->blanklines = old->blanklines;
1254 /* TODO: clone comments? */
1255 }
1256
1257 return new;
1258}
1259
1261{
1262 struct ast_variable *vn;
1263
1264 while (v) {
1265 vn = v;
1266 v = v->next;
1267 free(vn);
1268 }
1269}
1270
1272{
1273 struct ast_config_include *incl,*inclnext;
1274
1275 for (incl=incls; incl; incl = inclnext) {
1276 inclnext = incl->next;
1277 if (incl->include_location_file)
1279 if (incl->exec_file)
1280 free(incl->exec_file);
1281 if (incl->included_file)
1282 free(incl->included_file);
1283 free(incl);
1284 }
1285}
1286
1287static void ast_config_destroy(struct ast_config *cfg)
1288{
1289 struct ast_category *cat, *catn;
1290
1291 if (!cfg)
1292 return;
1293
1295
1296 cat = cfg->root;
1297 while (cat) {
1299 catn = cat;
1300 cat = cat->next;
1301 free(catn);
1302 }
1303 free(cfg);
1304}
1305
1307 /*! Allow \#exec in config files */
1309 /*! Do not fork() */
1311 /*! Keep quiet */
1313 /*! Console mode */
1315 /*! Run in realtime Linux priority */
1317 /*! Initialize keys for RSA authentication */
1319 /*! Remote console */
1321 /*! Execute an asterisk CLI command upon startup */
1323 /*! Don't use termcap colors */
1325 /*! Are we fully started yet? */
1327 /*! Trascode via signed linear */
1329 /*! Dump core on a seg fault */
1331 /*! Cache sound files */
1333 /*! Display timestamp in CLI verbose output */
1335 /*! Override config */
1337 /*! Reconnect */
1339 /*! Transmit Silence during Record() and DTMF Generation */
1341 /*! Suppress some warnings */
1343 /*! Always fork, even if verbose or debug settings are non-zero */
1345 /*! Disable log/verbose output to remote consoles */
1347 /*! There is a per-file debug setting */
1349 /*! Terminal colors should be adjusted for a light-colored background */
1351 /*! Force black background */
1353};
1354
1355/* options.h declares ast_options extern; I need it static? */
1356#define AST_CACHE_DIR_LEN 512
1357#define AST_FILENAME_MAX 80
1358
1359/*! These are the options that set by default when Asterisk starts */
1360#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
1361
1363
1364#define ast_opt_exec_includes ast_test_flag64(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
1365#define ast_opt_no_fork ast_test_flag64(&ast_options, AST_OPT_FLAG_NO_FORK)
1366#define ast_opt_quiet ast_test_flag64(&ast_options, AST_OPT_FLAG_QUIET)
1367#define ast_opt_console ast_test_flag64(&ast_options, AST_OPT_FLAG_CONSOLE)
1368#define ast_opt_high_priority ast_test_flag64(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
1369#define ast_opt_init_keys ast_test_flag64(&ast_options, AST_OPT_FLAG_INIT_KEYS)
1370#define ast_opt_remote ast_test_flag64(&ast_options, AST_OPT_FLAG_REMOTE)
1371#define ast_opt_exec ast_test_flag64(&ast_options, AST_OPT_FLAG_EXEC)
1372#define ast_opt_no_color ast_test_flag64(&ast_options, AST_OPT_FLAG_NO_COLOR)
1373#define ast_fully_booted ast_test_flag64(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
1374#define ast_opt_transcode_via_slin ast_test_flag64(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
1375#define ast_opt_priority_jumping ast_test_flag64(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
1376#define ast_opt_dump_core ast_test_flag64(&ast_options, AST_OPT_FLAG_DUMP_CORE)
1377#define ast_opt_cache_record_files ast_test_flag64(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
1378#define ast_opt_timestamp ast_test_flag64(&ast_options, AST_OPT_FLAG_TIMESTAMP)
1379#define ast_opt_override_config ast_test_flag64(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
1380#define ast_opt_reconnect ast_test_flag64(&ast_options, AST_OPT_FLAG_RECONNECT)
1381#define ast_opt_transmit_silence ast_test_flag64(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
1382#define ast_opt_dont_warn ast_test_flag64(&ast_options, AST_OPT_FLAG_DONT_WARN)
1383#define ast_opt_always_fork ast_test_flag64(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
1384#define ast_opt_mute ast_test_flag64(&ast_options, AST_OPT_FLAG_MUTE)
1385
1386extern int option_verbose;
1387extern int option_debug; /*!< Debugging */
1388extern int ast_option_maxcalls; /*!< Maximum number of simultaneous channels */
1389extern double ast_option_maxload;
1390extern char ast_defaultlanguage[];
1391
1392extern pid_t ast_mainpid;
1393
1395extern char debug_filename[AST_FILENAME_MAX];
1396
1397
1398
1399/* linkedlists.h */
1400
1401/*!
1402 \brief Write locks a list.
1403 \param head This is a pointer to the list head structure
1404
1405 This macro attempts to place an exclusive write lock in the
1406 list head structure pointed to by head.
1407 Returns non-zero on success, 0 on failure
1408*/
1409#define AST_RWLIST_WRLOCK(head) \
1410 ast_rwlock_wrlock(&(head)->lock)
1411
1412/*!
1413 \brief Read locks a list.
1414 \param head This is a pointer to the list head structure
1415
1416 This macro attempts to place a read lock in the
1417 list head structure pointed to by head.
1418 Returns non-zero on success, 0 on failure
1419*/
1420#define AST_RWLIST_RDLOCK(head) \
1421 ast_rwlock_rdlock(&(head)->lock)
1422
1423/*!
1424 \brief Attempts to unlock a read/write based list.
1425 \param head This is a pointer to the list head structure
1426
1427 This macro attempts to remove a read or write lock from the
1428 list head structure pointed to by head. If the list
1429 was not locked by this thread, this macro has no effect.
1430*/
1431#define AST_RWLIST_UNLOCK(head) \
1432 ast_rwlock_unlock(&(head)->lock)
1433
1434/*!
1435 \brief Defines a structure to be used to hold a list of specified type.
1436 \param name This will be the name of the defined structure.
1437 \param type This is the type of each list entry.
1438
1439 This macro creates a structure definition that can be used
1440 to hold a list of the entries of type \a type. It does not actually
1441 declare (allocate) a structure; to do that, either follow this
1442 macro with the desired name of the instance you wish to declare,
1443 or use the specified \a name to declare instances elsewhere.
1444
1445 Example usage:
1446 \code
1447 static AST_LIST_HEAD(entry_list, entry) entries;
1448 \endcode
1449
1450 This would define \c struct \c entry_list, and declare an instance of it named
1451 \a entries, all intended to hold a list of type \c struct \c entry.
1452*/
1453#define AST_LIST_HEAD(name, type) \
1454struct name { \
1455 struct type *first; \
1456 struct type *last; \
1457 ast_mutex_t lock; \
1458}
1459
1460/*!
1461 \brief Defines a structure to be used to hold a read/write list of specified type.
1462 \param name This will be the name of the defined structure.
1463 \param type This is the type of each list entry.
1464
1465 This macro creates a structure definition that can be used
1466 to hold a list of the entries of type \a type. It does not actually
1467 declare (allocate) a structure; to do that, either follow this
1468 macro with the desired name of the instance you wish to declare,
1469 or use the specified \a name to declare instances elsewhere.
1470
1471 Example usage:
1472 \code
1473 static AST_RWLIST_HEAD(entry_list, entry) entries;
1474 \endcode
1475
1476 This would define \c struct \c entry_list, and declare an instance of it named
1477 \a entries, all intended to hold a list of type \c struct \c entry.
1478*/
1479#define AST_RWLIST_HEAD(name, type) \
1480struct name { \
1481 struct type *first; \
1482 struct type *last; \
1483 ast_rwlock_t lock; \
1484}
1485
1486/*!
1487 \brief Defines a structure to be used to hold a list of specified type (with no lock).
1488 \param name This will be the name of the defined structure.
1489 \param type This is the type of each list entry.
1490
1491 This macro creates a structure definition that can be used
1492 to hold a list of the entries of type \a type. It does not actually
1493 declare (allocate) a structure; to do that, either follow this
1494 macro with the desired name of the instance you wish to declare,
1495 or use the specified \a name to declare instances elsewhere.
1496
1497 Example usage:
1498 \code
1499 static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
1500 \endcode
1501
1502 This would define \c struct \c entry_list, and declare an instance of it named
1503 \a entries, all intended to hold a list of type \c struct \c entry.
1504*/
1505#define AST_LIST_HEAD_NOLOCK(name, type) \
1506struct name { \
1507 struct type *first; \
1508 struct type *last; \
1509}
1510
1511/*!
1512 \brief Defines initial values for a declaration of AST_LIST_HEAD
1513*/
1514#define AST_LIST_HEAD_INIT_VALUE { \
1515 .first = NULL, \
1516 .last = NULL, \
1517 .lock = AST_MUTEX_INIT_VALUE, \
1518 }
1519
1520/*!
1521 \brief Defines initial values for a declaration of AST_RWLIST_HEAD
1522*/
1523#define AST_RWLIST_HEAD_INIT_VALUE { \
1524 .first = NULL, \
1525 .last = NULL, \
1526 .lock = AST_RWLOCK_INIT_VALUE, \
1527 }
1528
1529/*!
1530 \brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
1531*/
1532#define AST_LIST_HEAD_NOLOCK_INIT_VALUE { \
1533 .first = NULL, \
1534 .last = NULL, \
1535 }
1536
1537/*!
1538 \brief Defines a structure to be used to hold a list of specified type, statically initialized.
1539 \param name This will be the name of the defined structure.
1540 \param type This is the type of each list entry.
1541
1542 This macro creates a structure definition that can be used
1543 to hold a list of the entries of type \a type, and allocates an instance
1544 of it, initialized to be empty.
1545
1546 Example usage:
1547 \code
1548 static AST_LIST_HEAD_STATIC(entry_list, entry);
1549 \endcode
1550
1551 This would define \c struct \c entry_list, intended to hold a list of
1552 type \c struct \c entry.
1553*/
1554#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
1555#define AST_LIST_HEAD_STATIC(name, type) \
1556struct name { \
1557 struct type *first; \
1558 struct type *last; \
1559 ast_mutex_t lock; \
1560} name; \
1561static void __attribute__((constructor)) init_##name(void) \
1562{ \
1563 AST_LIST_HEAD_INIT(&name); \
1564} \
1565static void __attribute__((destructor)) fini_##name(void) \
1566{ \
1567 AST_LIST_HEAD_DESTROY(&name); \
1568} \
1569struct __dummy_##name
1570#else
1571#define AST_LIST_HEAD_STATIC(name, type) \
1572struct name { \
1573 struct type *first; \
1574 struct type *last; \
1575 ast_mutex_t lock; \
1576} name = AST_LIST_HEAD_INIT_VALUE
1577#endif
1578
1579/*!
1580 \brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
1581 \param name This will be the name of the defined structure.
1582 \param type This is the type of each list entry.
1583
1584 This macro creates a structure definition that can be used
1585 to hold a list of the entries of type \a type, and allocates an instance
1586 of it, initialized to be empty.
1587
1588 Example usage:
1589 \code
1590 static AST_RWLIST_HEAD_STATIC(entry_list, entry);
1591 \endcode
1592
1593 This would define \c struct \c entry_list, intended to hold a list of
1594 type \c struct \c entry.
1595*/
1596#ifndef AST_RWLOCK_INIT_VALUE
1597#define AST_RWLIST_HEAD_STATIC(name, type) \
1598struct name { \
1599 struct type *first; \
1600 struct type *last; \
1601 ast_rwlock_t lock; \
1602} name; \
1603static void __attribute__((constructor)) init_##name(void) \
1604{ \
1605 AST_RWLIST_HEAD_INIT(&name); \
1606} \
1607static void __attribute__((destructor)) fini_##name(void) \
1608{ \
1609 AST_RWLIST_HEAD_DESTROY(&name); \
1610} \
1611struct __dummy_##name
1612#else
1613#define AST_RWLIST_HEAD_STATIC(name, type) \
1614struct name { \
1615 struct type *first; \
1616 struct type *last; \
1617 ast_rwlock_t lock; \
1618} name = AST_RWLIST_HEAD_INIT_VALUE
1619#endif
1620
1621/*!
1622 \brief Defines a structure to be used to hold a list of specified type, statically initialized.
1623
1624 This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
1625*/
1626#define AST_LIST_HEAD_NOLOCK_STATIC(name, type) \
1627struct name { \
1628 struct type *first; \
1629 struct type *last; \
1630} name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
1631
1632/*!
1633 \brief Initializes a list head structure with a specified first entry.
1634 \param head This is a pointer to the list head structure
1635 \param entry pointer to the list entry that will become the head of the list
1636
1637 This macro initializes a list head structure by setting the head
1638 entry to the supplied value and recreating the embedded lock.
1639*/
1640#define AST_LIST_HEAD_SET(head, entry) do { \
1641 (head)->first = (entry); \
1642 (head)->last = (entry); \
1643 ast_mutex_init(&(head)->lock); \
1644} while (0)
1645
1646/*!
1647 \brief Initializes an rwlist head structure with a specified first entry.
1648 \param head This is a pointer to the list head structure
1649 \param entry pointer to the list entry that will become the head of the list
1650
1651 This macro initializes a list head structure by setting the head
1652 entry to the supplied value and recreating the embedded lock.
1653*/
1654#define AST_RWLIST_HEAD_SET(head, entry) do { \
1655 (head)->first = (entry); \
1656 (head)->last = (entry); \
1657 ast_rwlock_init(&(head)->lock); \
1658} while (0)
1659
1660/*!
1661 \brief Initializes a list head structure with a specified first entry.
1662 \param head This is a pointer to the list head structure
1663 \param entry pointer to the list entry that will become the head of the list
1664
1665 This macro initializes a list head structure by setting the head
1666 entry to the supplied value.
1667*/
1668#define AST_LIST_HEAD_SET_NOLOCK(head, entry) do { \
1669 (head)->first = (entry); \
1670 (head)->last = (entry); \
1671} while (0)
1672
1673/*!
1674 \brief Declare a forward link structure inside a list entry.
1675 \param type This is the type of each list entry.
1676
1677 This macro declares a structure to be used to link list entries together.
1678 It must be used inside the definition of the structure named in
1679 \a type, as follows:
1680
1681 \code
1682 struct list_entry {
1683 ...
1684 AST_LIST_ENTRY(list_entry) list;
1685 }
1686 \endcode
1687
1688 The field name \a list here is arbitrary, and can be anything you wish.
1689*/
1690#define AST_LIST_ENTRY(type) \
1691struct { \
1692 struct type *next; \
1693}
1694
1695#define AST_RWLIST_ENTRY AST_LIST_ENTRY
1696
1697/*!
1698 \brief Returns the first entry contained in a list.
1699 \param head This is a pointer to the list head structure
1700 */
1701#define AST_LIST_FIRST(head) ((head)->first)
1702
1703#define AST_RWLIST_FIRST AST_LIST_FIRST
1704
1705/*!
1706 \brief Returns the last entry contained in a list.
1707 \param head This is a pointer to the list head structure
1708 */
1709#define AST_LIST_LAST(head) ((head)->last)
1710
1711#define AST_RWLIST_LAST AST_LIST_LAST
1712
1713/*!
1714 \brief Returns the next entry in the list after the given entry.
1715 \param elm This is a pointer to the current entry.
1716 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1717 used to link entries of this list together.
1718*/
1719#define AST_LIST_NEXT(elm, field) ((elm)->field.next)
1720
1721#define AST_RWLIST_NEXT AST_LIST_NEXT
1722
1723/*!
1724 \brief Checks whether the specified list contains any entries.
1725 \param head This is a pointer to the list head structure
1726
1727 Returns non-zero if the list has entries, zero if not.
1728 */
1729#define AST_LIST_EMPTY(head) (AST_LIST_FIRST(head) == NULL)
1730
1731#define AST_RWLIST_EMPTY AST_LIST_EMPTY
1732
1733/*!
1734 \brief Loops over (traverses) the entries in a list.
1735 \param head This is a pointer to the list head structure
1736 \param var This is the name of the variable that will hold a pointer to the
1737 current list entry on each iteration. It must be declared before calling
1738 this macro.
1739 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1740 used to link entries of this list together.
1741
1742 This macro is use to loop over (traverse) the entries in a list. It uses a
1743 \a for loop, and supplies the enclosed code with a pointer to each list
1744 entry as it loops. It is typically used as follows:
1745 \code
1746 static AST_LIST_HEAD(entry_list, list_entry) entries;
1747 ...
1748 struct list_entry {
1749 ...
1750 AST_LIST_ENTRY(list_entry) list;
1751 }
1752 ...
1753 struct list_entry *current;
1754 ...
1755 AST_LIST_TRAVERSE(&entries, current, list) {
1756 (do something with current here)
1757 }
1758 \endcode
1759 \warning If you modify the forward-link pointer contained in the \a current entry while
1760 inside the loop, the behavior will be unpredictable. At a minimum, the following
1761 macros will modify the forward-link pointer, and should not be used inside
1762 AST_LIST_TRAVERSE() against the entry pointed to by the \a current pointer without
1763 careful consideration of their consequences:
1764 \li AST_LIST_NEXT() (when used as an lvalue)
1765 \li AST_LIST_INSERT_AFTER()
1766 \li AST_LIST_INSERT_HEAD()
1767 \li AST_LIST_INSERT_TAIL()
1768*/
1769#define AST_LIST_TRAVERSE(head,var,field) \
1770 for((var) = (head)->first; (var); (var) = (var)->field.next)
1771
1772#define AST_RWLIST_TRAVERSE AST_LIST_TRAVERSE
1773
1774/*!
1775 \brief Loops safely over (traverses) the entries in a list.
1776 \param head This is a pointer to the list head structure
1777 \param var This is the name of the variable that will hold a pointer to the
1778 current list entry on each iteration. It must be declared before calling
1779 this macro.
1780 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1781 used to link entries of this list together.
1782
1783 This macro is used to safely loop over (traverse) the entries in a list. It
1784 uses a \a for loop, and supplies the enclosed code with a pointer to each list
1785 entry as it loops. It is typically used as follows:
1786
1787 \code
1788 static AST_LIST_HEAD(entry_list, list_entry) entries;
1789 ...
1790 struct list_entry {
1791 ...
1792 AST_LIST_ENTRY(list_entry) list;
1793 }
1794 ...
1795 struct list_entry *current;
1796 ...
1797 AST_LIST_TRAVERSE_SAFE_BEGIN(&entries, current, list) {
1798 (do something with current here)
1799 }
1800 AST_LIST_TRAVERSE_SAFE_END;
1801 \endcode
1802
1803 It differs from AST_LIST_TRAVERSE() in that the code inside the loop can modify
1804 (or even free, after calling AST_LIST_REMOVE_CURRENT()) the entry pointed to by
1805 the \a current pointer without affecting the loop traversal.
1806*/
1807#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) { \
1808 typeof((head)->first) __list_next; \
1809 typeof((head)->first) __list_prev = NULL; \
1810 typeof((head)->first) __new_prev = NULL; \
1811 for ((var) = (head)->first, __new_prev = (var), \
1812 __list_next = (var) ? (var)->field.next : NULL; \
1813 (var); \
1814 __list_prev = __new_prev, (var) = __list_next, \
1815 __new_prev = (var), \
1816 __list_next = (var) ? (var)->field.next : NULL \
1817 )
1818
1819#define AST_RWLIST_TRAVERSE_SAFE_BEGIN AST_LIST_TRAVERSE_SAFE_BEGIN
1820
1821/*!
1822 \brief Removes the \a current entry from a list during a traversal.
1823 \param head This is a pointer to the list head structure
1824 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1825 used to link entries of this list together.
1826
1827 \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
1828 block; it is used to unlink the current entry from the list without affecting
1829 the list traversal (and without having to re-traverse the list to modify the
1830 previous entry, if any).
1831 */
1832#define AST_LIST_REMOVE_CURRENT(head, field) \
1833 __new_prev->field.next = NULL; \
1834 __new_prev = __list_prev; \
1835 if (__list_prev) \
1836 __list_prev->field.next = __list_next; \
1837 else \
1838 (head)->first = __list_next; \
1839 if (!__list_next) \
1840 (head)->last = __list_prev;
1841
1842#define AST_RWLIST_REMOVE_CURRENT AST_LIST_REMOVE_CURRENT
1843
1844/*!
1845 \brief Inserts a list entry before the current entry during a traversal.
1846 \param head This is a pointer to the list head structure
1847 \param elm This is a pointer to the entry to be inserted.
1848 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1849 used to link entries of this list together.
1850
1851 \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
1852 block.
1853 */
1854#define AST_LIST_INSERT_BEFORE_CURRENT(head, elm, field) do { \
1855 if (__list_prev) { \
1856 (elm)->field.next = __list_prev->field.next; \
1857 __list_prev->field.next = elm; \
1858 } else { \
1859 (elm)->field.next = (head)->first; \
1860 (head)->first = (elm); \
1861 } \
1862 __new_prev = (elm); \
1863} while (0)
1864
1865#define AST_RWLIST_INSERT_BEFORE_CURRENT AST_LIST_INSERT_BEFORE_CURRENT
1866
1867/*!
1868 \brief Closes a safe loop traversal block.
1869 */
1870#define AST_LIST_TRAVERSE_SAFE_END }
1871
1872#define AST_RWLIST_TRAVERSE_SAFE_END AST_LIST_TRAVERSE_SAFE_END
1873
1874/*!
1875 \brief Initializes a list head structure.
1876 \param head This is a pointer to the list head structure
1877
1878 This macro initializes a list head structure by setting the head
1879 entry to \a NULL (empty list) and recreating the embedded lock.
1880*/
1881#define AST_LIST_HEAD_INIT(head) { \
1882 (head)->first = NULL; \
1883 (head)->last = NULL; \
1884 ast_mutex_init(&(head)->lock); \
1885}
1886
1887/*!
1888 \brief Initializes an rwlist head structure.
1889 \param head This is a pointer to the list head structure
1890
1891 This macro initializes a list head structure by setting the head
1892 entry to \a NULL (empty list) and recreating the embedded lock.
1893*/
1894#define AST_RWLIST_HEAD_INIT(head) { \
1895 (head)->first = NULL; \
1896 (head)->last = NULL; \
1897 ast_rwlock_init(&(head)->lock); \
1898}
1899
1900/*!
1901 \brief Destroys an rwlist head structure.
1902 \param head This is a pointer to the list head structure
1903
1904 This macro destroys a list head structure by setting the head
1905 entry to \a NULL (empty list) and destroying the embedded lock.
1906 It does not free the structure from memory.
1907*/
1908#define AST_RWLIST_HEAD_DESTROY(head) { \
1909 (head)->first = NULL; \
1910 (head)->last = NULL; \
1911 ast_rwlock_destroy(&(head)->lock); \
1912}
1913
1914/*!
1915 \brief Initializes a list head structure.
1916 \param head This is a pointer to the list head structure
1917
1918 This macro initializes a list head structure by setting the head
1919 entry to \a NULL (empty list). There is no embedded lock handling
1920 with this macro.
1921*/
1922#define AST_LIST_HEAD_INIT_NOLOCK(head) { \
1923 (head)->first = NULL; \
1924 (head)->last = NULL; \
1925}
1926
1927/*!
1928 \brief Inserts a list entry after a given entry.
1929 \param head This is a pointer to the list head structure
1930 \param listelm This is a pointer to the entry after which the new entry should
1931 be inserted.
1932 \param elm This is a pointer to the entry to be inserted.
1933 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1934 used to link entries of this list together.
1935 */
1936#define AST_LIST_INSERT_AFTER(head, listelm, elm, field) do { \
1937 (elm)->field.next = (listelm)->field.next; \
1938 (listelm)->field.next = (elm); \
1939 if ((head)->last == (listelm)) \
1940 (head)->last = (elm); \
1941} while (0)
1942
1943#define AST_RWLIST_INSERT_AFTER AST_LIST_INSERT_AFTER
1944
1945/*!
1946 \brief Inserts a list entry at the head of a list.
1947 \param head This is a pointer to the list head structure
1948 \param elm This is a pointer to the entry to be inserted.
1949 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1950 used to link entries of this list together.
1951 */
1952#define AST_LIST_INSERT_HEAD(head, elm, field) do { \
1953 (elm)->field.next = (head)->first; \
1954 (head)->first = (elm); \
1955 if (!(head)->last) \
1956 (head)->last = (elm); \
1957} while (0)
1958
1959#define AST_RWLIST_INSERT_HEAD AST_LIST_INSERT_HEAD
1960
1961/*!
1962 \brief Appends a list entry to the tail of a list.
1963 \param head This is a pointer to the list head structure
1964 \param elm This is a pointer to the entry to be appended.
1965 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1966 used to link entries of this list together.
1967
1968 Note: The link field in the appended entry is \b not modified, so if it is
1969 actually the head of a list itself, the entire list will be appended
1970 temporarily (until the next AST_LIST_INSERT_TAIL is performed).
1971 */
1972#define AST_LIST_INSERT_TAIL(head, elm, field) do { \
1973 if (!(head)->first) { \
1974 (head)->first = (elm); \
1975 (head)->last = (elm); \
1976 } else { \
1977 (head)->last->field.next = (elm); \
1978 (head)->last = (elm); \
1979 } \
1980} while (0)
1981
1982#define AST_RWLIST_INSERT_TAIL AST_LIST_INSERT_TAIL
1983
1984/*!
1985 \brief Appends a whole list to the tail of a list.
1986 \param head This is a pointer to the list head structure
1987 \param list This is a pointer to the list to be appended.
1988 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1989 used to link entries of this list together.
1990 */
1991#define AST_LIST_APPEND_LIST(head, list, field) do { \
1992 if (!(head)->first) { \
1993 (head)->first = (list)->first; \
1994 (head)->last = (list)->last; \
1995 } else { \
1996 (head)->last->field.next = (list)->first; \
1997 (head)->last = (list)->last; \
1998 } \
1999} while (0)
2000
2001#define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
2002
2003/*!
2004 \brief Removes and returns the head entry from a list.
2005 \param head This is a pointer to the list head structure
2006 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2007 used to link entries of this list together.
2008
2009 Removes the head entry from the list, and returns a pointer to it.
2010 This macro is safe to call on an empty list.
2011 */
2012#define AST_LIST_REMOVE_HEAD(head, field) ({ \
2013 typeof((head)->first) cur = (head)->first; \
2014 if (cur) { \
2015 (head)->first = cur->field.next; \
2016 cur->field.next = NULL; \
2017 if ((head)->last == cur) \
2018 (head)->last = NULL; \
2019 } \
2020 cur; \
2021 })
2022
2023#define AST_RWLIST_REMOVE_HEAD AST_LIST_REMOVE_HEAD
2024
2025/*!
2026 \brief Removes a specific entry from a list.
2027 \param head This is a pointer to the list head structure
2028 \param elm This is a pointer to the entry to be removed.
2029 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2030 used to link entries of this list together.
2031 \warning The removed entry is \b not freed nor modified in any way.
2032 */
2033#define AST_LIST_REMOVE(head, elm, field) do { \
2034 if ((head)->first == (elm)) { \
2035 (head)->first = (elm)->field.next; \
2036 if ((head)->last == (elm)) \
2037 (head)->last = NULL; \
2038 } else { \
2039 typeof(elm) curelm = (head)->first; \
2040 while (curelm && (curelm->field.next != (elm))) \
2041 curelm = curelm->field.next; \
2042 if (curelm) { \
2043 curelm->field.next = (elm)->field.next; \
2044 if ((head)->last == (elm)) \
2045 (head)->last = curelm; \
2046 } \
2047 } \
2048 (elm)->field.next = NULL; \
2049} while (0)
2050
2051#define AST_RWLIST_REMOVE AST_LIST_REMOVE
2052
2053/* chanvars.h */
2054
2055struct ast_var_t {
2057 char *value;
2058 char name[0];
2059};
2060
2062
2065
2066
2067/* IN CONFLICT: struct ast_var_t *ast_var_assign(const char *name, const char *value); */
2068
2069static struct ast_var_t *ast_var_assign(const char *name, const char *value);
2070
2071static void ast_var_delete(struct ast_var_t *var);
2072
2073/*from channel.h */
2074#define AST_MAX_EXTENSION 80 /*!< Max length of an extension */
2075
2076
2077/* from pbx.h */
2078#define PRIORITY_HINT -1 /*!< Special Priority for a hint */
2079
2081 AST_EXTENSION_REMOVED = -2, /*!< Extension removed */
2082 AST_EXTENSION_DEACTIVATED = -1, /*!< Extension hint removed */
2083 AST_EXTENSION_NOT_INUSE = 0, /*!< No device INUSE or BUSY */
2084 AST_EXTENSION_INUSE = 1 << 0, /*!< One or more devices INUSE */
2085 AST_EXTENSION_BUSY = 1 << 1, /*!< All devices BUSY */
2086 AST_EXTENSION_UNAVAILABLE = 1 << 2, /*!< All devices UNAVAILABLE/UNREGISTERED */
2087 AST_EXTENSION_RINGING = 1 << 3, /*!< All devices RINGING */
2088 AST_EXTENSION_ONHOLD = 1 << 4, /*!< All devices ONHOLD */
2089};
2090
2091struct ast_custom_function {
2092 const char *name; /*!< Name */
2093 const char *synopsis; /*!< Short description for "show functions" */
2094 const char *desc; /*!< Help text that explains it all */
2095 const char *syntax; /*!< Syntax description */
2096 int (*read)(struct ast_channel *, const char *, char *, char *, size_t); /*!< Read function, if read is supported */
2097 int (*write)(struct ast_channel *, const char *, char *, const char *); /*!< Write function, if write is supported */
2099};
2100
2101typedef int (ast_switch_f)(struct ast_channel *chan, const char *context,
2102 const char *exten, int priority, const char *callerid, const char *data);
2103
2104struct ast_switch {
2106 const char *name; /*!< Name of the switch */
2107 const char *description; /*!< Description of the switch */
2108
2113};
2114
2115
2116static char *config_filename = "extensions.conf";
2117static char *global_registrar = "conf2ael";
2118static char userscontext[AST_MAX_EXTENSION] = "default";
2119static int static_config = 0;
2123static void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
2124
2125
2126/* stolen from callerid.c */
2127
2128/*! \brief Clean up phone string
2129 * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
2130 * Basically, remove anything that could be invalid in a pattern.
2131 */
2132static void ast_shrink_phone_number(char *n)
2133{
2134 int x, y=0;
2135 int bracketed = 0;
2136
2137 for (x=0; n[x]; x++) {
2138 switch(n[x]) {
2139 case '[':
2140 bracketed++;
2141 n[y++] = n[x];
2142 break;
2143 case ']':
2144 bracketed--;
2145 n[y++] = n[x];
2146 break;
2147 case '-':
2148 if (bracketed)
2149 n[y++] = n[x];
2150 break;
2151 case '.':
2152 if (!n[x+1])
2153 n[y++] = n[x];
2154 break;
2155 default:
2156 if (!strchr("()", n[x]))
2157 n[y++] = n[x];
2158 }
2159 }
2160 n[y] = '\0';
2161}
2162
2163
2164/* stolen from chanvars.c */
2165
2166static const char *ast_var_name(const struct ast_var_t *var)
2167{
2168 const char *name;
2169
2170 if (var == NULL || (name = var->name) == NULL)
2171 return NULL;
2172 /* Return the name without the initial underscores */
2173 if (name[0] == '_') {
2174 name++;
2175 if (name[0] == '_')
2176 name++;
2177 }
2178 return name;
2179}
2180
2181/* experiment 1: see if it's easier just to use existing config code
2182 * to read in the extensions.conf file. In this scenario,
2183 I have to rip/copy code from other modules, because they
2184 are staticly declared as-is. A solution would be to move
2185 the ripped code to another location and make them available
2186 to other modules and standalones */
2187
2188/* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
2189
2190static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
2191{
2192 va_list vars;
2193 va_start(vars,fmt);
2194
2195 printf("LOG: lev:%d file:%s line:%d func: %s ",
2196 level, file, line, function);
2197 vprintf(fmt, vars);
2198 fflush(stdout);
2199 va_end(vars);
2200}
2201
2202void __attribute__((format(printf, 1, 2))) ast_verbose(const char *fmt, ...)
2203{
2204 va_list vars;
2205 va_start(vars,fmt);
2206
2207 printf("VERBOSE: ");
2208 vprintf(fmt, vars);
2209 fflush(stdout);
2210 va_end(vars);
2211}
2212
2213/* stolen from main/utils.c */
2214static char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
2215{
2216 char *dataPut = start;
2217 int inEscape = 0;
2218 int inQuotes = 0;
2219
2220 for (; *start; start++) {
2221 if (inEscape) {
2222 *dataPut++ = *start; /* Always goes verbatim */
2223 inEscape = 0;
2224 } else {
2225 if (*start == '\\') {
2226 inEscape = 1; /* Do not copy \ into the data */
2227 } else if (*start == '\'') {
2228 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
2229 } else {
2230 /* Replace , with |, unless in quotes */
2231 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
2232 }
2233 }
2234 }
2235 if (start != dataPut)
2236 *dataPut = 0;
2237 return dataPut;
2238}
2239
2240static int ast_true(const char *s)
2241{
2242 if (ast_strlen_zero(s))
2243 return 0;
2244
2245 /* Determine if this is a true value */
2246 if (!strcasecmp(s, "yes") ||
2247 !strcasecmp(s, "true") ||
2248 !strcasecmp(s, "y") ||
2249 !strcasecmp(s, "t") ||
2250 !strcasecmp(s, "1") ||
2251 !strcasecmp(s, "on"))
2252 return -1;
2253
2254 return 0;
2255}
2256
2257#define ONE_MILLION 1000000
2258/*
2259 * put timeval in a valid range. usec is 0..999999
2260 * negative values are not allowed and truncated.
2261 */
2262static struct timeval tvfix(struct timeval a)
2263{
2264 if (a.tv_usec >= ONE_MILLION) {
2265 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
2266 (long)a.tv_sec, (long int) a.tv_usec);
2267 a.tv_sec += a.tv_usec / ONE_MILLION;
2268 a.tv_usec %= ONE_MILLION;
2269 } else if (a.tv_usec < 0) {
2270 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
2271 (long)a.tv_sec, (long int) a.tv_usec);
2272 a.tv_usec = 0;
2273 }
2274 return a;
2275}
2276
2277struct timeval ast_tvadd(struct timeval a, struct timeval b);
2278struct timeval ast_tvadd(struct timeval a, struct timeval b)
2279{
2280 /* consistency checks to guarantee usec in 0..999999 */
2281 a = tvfix(a);
2282 b = tvfix(b);
2283 a.tv_sec += b.tv_sec;
2284 a.tv_usec += b.tv_usec;
2285 if (a.tv_usec >= ONE_MILLION) {
2286 a.tv_sec++;
2287 a.tv_usec -= ONE_MILLION;
2288 }
2289 return a;
2290}
2291
2292struct timeval ast_tvsub(struct timeval a, struct timeval b);
2293struct timeval ast_tvsub(struct timeval a, struct timeval b)
2294{
2295 /* consistency checks to guarantee usec in 0..999999 */
2296 a = tvfix(a);
2297 b = tvfix(b);
2298 a.tv_sec -= b.tv_sec;
2299 a.tv_usec -= b.tv_usec;
2300 if (a.tv_usec < 0) {
2301 a.tv_sec-- ;
2302 a.tv_usec += ONE_MILLION;
2303 }
2304 return a;
2305}
2306#undef ONE_MILLION
2307
2308void ast_mark_lock_failed(void *lock_addr);
2309void ast_mark_lock_failed(void *lock_addr)
2310{
2311 /* Pretend to do something. */
2312}
2313
2314/* stolen from pbx.c */
2315#define VAR_BUF_SIZE 4096
2316
2317#define VAR_NORMAL 1
2318#define VAR_SOFTTRAN 2
2319#define VAR_HARDTRAN 3
2320
2321#define BACKGROUND_SKIP (1 << 0)
2322#define BACKGROUND_NOANSWER (1 << 1)
2323#define BACKGROUND_MATCHEXTEN (1 << 2)
2324#define BACKGROUND_PLAYBACK (1 << 3)
2325
2326/*!
2327 \brief ast_exten: An extension
2328 The dialplan is saved as a linked list with each context
2329 having it's own linked list of extensions - one item per
2330 priority.
2331*/
2332struct ast_exten {
2333 char *exten; /*!< Extension name */
2334 int matchcid; /*!< Match caller id ? */
2335 const char *cidmatch; /*!< Caller id to match for this extension */
2336 int priority; /*!< Priority */
2337 const char *label; /*!< Label */
2338 struct ast_context *parent; /*!< The context this extension belongs to */
2339 const char *app; /*!< Application to execute */
2340 struct ast_app *cached_app; /*!< Cached location of application */
2341 void *data; /*!< Data to use (arguments) */
2342 void (*datad)(void *); /*!< Data destructor */
2343 struct ast_exten *peer; /*!< Next higher priority with our extension */
2344 const char *registrar; /*!< Registrar */
2345 struct ast_exten *next; /*!< Extension with a greater ID */
2346 char stuff[0];
2347};
2348/* from pbx.h */
2349typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
2350struct ast_timing {
2351 int hastime; /*!< If time construct exists */
2352 unsigned int monthmask; /*!< Mask for month */
2353 unsigned int daymask; /*!< Mask for date */
2354 unsigned int dowmask; /*!< Mask for day of week (mon-sun) */
2355 unsigned int minmask[48]; /*!< Mask for minute */
2356 char *timezone; /*!< NULL, or zoneinfo style timezone */
2357};
2358/* end of pbx.h */
2359/*! \brief ast_include: include= support in extensions.conf */
2360struct ast_include {
2361 const char *name;
2362 const char *rname; /*!< Context to include */
2363 const char *registrar; /*!< Registrar */
2364 int hastime; /*!< If time construct exists */
2365 struct ast_timing timing; /*!< time construct */
2366 struct ast_include *next; /*!< Link them together */
2367 char stuff[0];
2368};
2369
2370/*! \brief ast_sw: Switch statement in extensions.conf */
2371struct ast_sw {
2372 char *name;
2373 const char *registrar; /*!< Registrar */
2374 char *data; /*!< Data load */
2375 int eval;
2377 char *tmpdata;
2378 char stuff[0];
2379};
2380
2381/*! \brief ast_ignorepat: Ignore patterns in dial plan */
2382struct ast_ignorepat {
2383 const char *registrar;
2385 char pattern[0];
2386};
2387
2388/*! \brief ast_context: An extension context */
2389struct ast_context {
2390 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
2391 struct ast_exten *root; /*!< The root of the list of extensions */
2392 struct ast_context *next; /*!< Link them together */
2393 struct ast_include *includes; /*!< Include other contexts */
2394 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
2395 const char *registrar; /*!< Registrar */
2396 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
2397 char name[0]; /*!< Name of the context */
2398};
2399
2400
2401/*! \brief ast_app: A registered application */
2402struct ast_app {
2403 int (*execute)(struct ast_channel *chan, void *data);
2404 const char *synopsis; /*!< Synopsis text for 'show applications' */
2405 const char *description; /*!< Description (help text) for 'show application &lt;name&gt;' */
2406 AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
2407 void *module; /*!< Module this app belongs to */
2408 char name[0]; /*!< Name of the application */
2409};
2410
2411
2412/*! \brief ast_state_cb: An extension state notify register item */
2419
2420/*! \brief Structure for dial plan hints
2421
2422 \note Hints are pointers from an extension in the dialplan to one or
2423 more devices (tech/name)
2424 - See \ref AstExtState
2425*/
2426struct ast_hint {
2427 struct ast_exten *exten; /*!< Extension */
2428 int laststate; /*!< Last known state */
2429 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
2430 AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
2431};
2432
2441
2443
2444#define STATUS_NO_CONTEXT 1
2445#define STATUS_NO_EXTENSION 2
2446#define STATUS_NO_PRIORITY 3
2447#define STATUS_NO_LABEL 4
2448#define STATUS_SUCCESS 5
2449
2450static struct ast_var_t *ast_var_assign(const char *name, const char *value)
2451{
2452 struct ast_var_t *var;
2453 int name_len = strlen(name) + 1;
2454 int value_len = strlen(value) + 1;
2455
2456 if (!(var = ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char)))) {
2457 return NULL;
2458 }
2459
2460 ast_copy_string(var->name, name, name_len);
2461 var->value = var->name + name_len;
2462 ast_copy_string(var->value, value, value_len);
2463
2464 return var;
2465}
2466
2467static void ast_var_delete(struct ast_var_t *var)
2468{
2469 free(var);
2470}
2471
2472
2473/* chopped this one off at the knees! */
2474static int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
2475{
2476
2477 /* ast_log(LOG_ERROR, "Function %s not registered\n", function); we are not interested in the details here */
2478
2479 return -1;
2480}
2481
2482static unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
2483{
2484 int argc;
2485 char *scan;
2486 int paren = 0, quote = 0;
2487
2488 if (!buf || !array || !arraylen)
2489 return 0;
2490
2491 memset(array, 0, arraylen * sizeof(*array));
2492
2493 scan = buf;
2494
2495 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
2496 array[argc] = scan;
2497 for (; *scan; scan++) {
2498 if (*scan == '(')
2499 paren++;
2500 else if (*scan == ')') {
2501 if (paren)
2502 paren--;
2503 } else if (*scan == '"' && delim != '"') {
2504 quote = quote ? 0 : 1;
2505 /* Remove quote character from argument */
2506 memmove(scan, scan + 1, strlen(scan));
2507 scan--;
2508 } else if (*scan == '\\') {
2509 /* Literal character, don't parse */
2510 memmove(scan, scan + 1, strlen(scan));
2511 } else if ((*scan == delim) && !paren && !quote) {
2512 *scan++ = '\0';
2513 break;
2514 }
2515 }
2516 }
2517
2518 if (*scan)
2519 array[argc++] = scan;
2520
2521 return argc;
2522}
2523
2524static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
2525{
2526 struct ast_var_t *newvariable;
2527 struct varshead *headp;
2528 const char *nametail = name;
2529
2530 /* XXX may need locking on the channel ? */
2531 if (name[strlen(name)-1] == ')') {
2532 char *function = ast_strdupa(name);
2533
2534 ast_func_write(chan, function, value);
2535 return;
2536 }
2537
2538 headp = &globals;
2539
2540 /* For comparison purposes, we have to strip leading underscores */
2541 if (*nametail == '_') {
2542 nametail++;
2543 if (*nametail == '_')
2544 nametail++;
2545 }
2546
2547 AST_LIST_TRAVERSE (headp, newvariable, entries) {
2548 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
2549 /* there is already such a variable, delete it */
2550 AST_LIST_REMOVE(headp, newvariable, entries);
2551 ast_var_delete(newvariable);
2552 break;
2553 }
2554 }
2555
2556 if (value && (newvariable = ast_var_assign(name, value))) {
2557 if ((option_verbose > 1) && (headp == &globals))
2558 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
2559 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
2560 }
2561
2562}
2563
2564static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
2565{
2566 char *name, *value, *mydata;
2567 int argc;
2568 char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
2569 int global = 0;
2570 int x;
2571
2572 if (ast_strlen_zero(data)) {
2573 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
2574 return 0;
2575 }
2576
2577 mydata = ast_strdupa(data);
2578 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
2579
2580 /* check for a trailing flags argument */
2581 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
2582 argc--;
2583 if (strchr(argv[argc], 'g'))
2584 global = 1;
2585 }
2586
2587 for (x = 0; x < argc; x++) {
2588 name = argv[x];
2589 if ((value = strchr(name, '='))) {
2590 *value++ = '\0';
2592 } else
2593 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
2594 }
2595
2596 return(0);
2597}
2598
2599int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data);
2600
2601int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
2602{
2603 return pbx_builtin_setvar(chan, data);
2604}
2605
2606
2607/*! \brief Helper for get_range.
2608 * return the index of the matching entry, starting from 1.
2609 * If names is not supplied, try numeric values.
2610 */
2611static int lookup_name(const char *s, char *const names[], int max)
2612{
2613 int i;
2614
2615 if (names && *s > '9') {
2616 for (i = 0; names[i]; i++) {
2617 if (!strcasecmp(s, names[i])) {
2618 return i;
2619 }
2620 }
2621 }
2622
2623 /* Allow months and weekdays to be specified as numbers, as well */
2624 if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
2625 /* What the array offset would have been: "1" would be at offset 0 */
2626 return i - 1;
2627 }
2628 return -1; /* error return */
2629}
2630
2631/*! \brief helper function to return a range up to max (7, 12, 31 respectively).
2632 * names, if supplied, is an array of names that should be mapped to numbers.
2633 */
2634static unsigned get_range(char *src, int max, char *const names[], const char *msg)
2635{
2636 int start, end; /* start and ending position */
2637 unsigned int mask = 0;
2638 char *part;
2639
2640 /* Check for whole range */
2641 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
2642 return (1 << max) - 1;
2643 }
2644
2645 while ((part = strsep(&src, "&"))) {
2646 /* Get start and ending position */
2647 char *endpart = strchr(part, '-');
2648 if (endpart) {
2649 *endpart++ = '\0';
2650 }
2651 /* Find the start */
2652 if ((start = lookup_name(part, names, max)) < 0) {
2653 ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
2654 continue;
2655 }
2656 if (endpart) { /* find end of range */
2657 if ((end = lookup_name(endpart, names, max)) < 0) {
2658 ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
2659 continue;
2660 }
2661 } else {
2662 end = start;
2663 }
2664 /* Fill the mask. Remember that ranges are cyclic */
2665 mask |= (1 << end); /* initialize with last element */
2666 while (start != end) {
2667 if (start >= max) {
2668 start = 0;
2669 }
2670 mask |= (1 << start);
2671 start++;
2672 }
2673 }
2674 return mask;
2675}
2676
2677/*! \brief store a bitmask of valid times, one bit each 2 minute */
2678static void get_timerange(struct ast_timing *i, char *times)
2679{
2680 char *endpart, *part;
2681 int x;
2682 int st_h, st_m;
2683 int endh, endm;
2684 int minute_start, minute_end;
2685
2686 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
2687 memset(i->minmask, 0, sizeof(i->minmask));
2688
2689 /* 1-minute per bit */
2690 /* Star is all times */
2691 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
2692 /* 48, because each hour takes 2 integers; 30 bits each */
2693 for (x = 0; x < 48; x++) {
2694 i->minmask[x] = 0x3fffffff; /* 30 bits */
2695 }
2696 return;
2697 }
2698 /* Otherwise expect a range */
2699 while ((part = strsep(&times, "&"))) {
2700 if (!(endpart = strchr(part, '-'))) {
2701 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
2702 ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
2703 continue;
2704 }
2705 i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
2706 continue;
2707 }
2708 *endpart++ = '\0';
2709 /* why skip non digits? Mostly to skip spaces */
2710 while (*endpart && !isdigit(*endpart)) {
2711 endpart++;
2712 }
2713 if (!*endpart) {
2714 ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
2715 continue;
2716 }
2717 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
2718 ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
2719 continue;
2720 }
2721 if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
2722 ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
2723 continue;
2724 }
2725 minute_start = st_h * 60 + st_m;
2726 minute_end = endh * 60 + endm;
2727 /* Go through the time and enable each appropriate bit */
2728 for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
2729 i->minmask[x / 30] |= (1 << (x % 30));
2730 }
2731 /* Do the last one */
2732 i->minmask[x / 30] |= (1 << (x % 30));
2733 }
2734 /* All done */
2735 return;
2736}
2737
2738static void null_datad(void *foo)
2739{
2740}
2741
2742/*! \brief Find realtime engine for realtime family */
2743static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
2744{
2745 struct ast_config_engine *eng, *ret = NULL;
2746 struct ast_config_map *map;
2747
2748
2749 for (map = config_maps; map; map = map->next) {
2750 if (!strcasecmp(family, map->name)) {
2751 if (database)
2752 ast_copy_string(database, map->database, dbsiz);
2753 if (table)
2754 ast_copy_string(table, map->table ? map->table : family, tabsiz);
2755 break;
2756 }
2757 }
2758
2759 /* Check if the required driver (engine) exist */
2760 if (map) {
2761 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
2762 if (!strcasecmp(eng->name, map->driver))
2763 ret = eng;
2764 }
2765 }
2766
2767
2768 /* if we found a mapping, but the engine is not available, then issue a warning */
2769 if (map && !ret)
2770 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
2771
2772 return ret;
2773}
2774
2776
2778{
2779 return cfg->current;
2780}
2781
2782static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
2783
2784static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
2785{
2786 struct ast_category *category;
2787
2788 if ((category = ast_calloc(1, sizeof(*category))))
2789 ast_copy_string(category->name, name, sizeof(category->name));
2790 category->file = strdup(in_file);
2791 category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
2792 return category;
2793}
2794
2795struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name);
2796
2797struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name)
2798{
2799 return category_get(config, category_name, 0);
2800}
2801
2802static void move_variables(struct ast_category *old, struct ast_category *new)
2803{
2804 struct ast_variable *var = old->root;
2805 old->root = NULL;
2806#if 1
2807 /* we can just move the entire list in a single op */
2809#else
2810 while (var) {
2811 struct ast_variable *next = var->next;
2812 var->next = NULL;
2814 var = next;
2815 }
2816#endif
2817}
2818
2819static void inherit_category(struct ast_category *new, const struct ast_category *base)
2820{
2821 struct ast_variable *var;
2822
2823 for (var = base->root; var; var = var->next)
2825}
2826
2827static void ast_category_append(struct ast_config *config, struct ast_category *category);
2828
2829static void ast_category_append(struct ast_config *config, struct ast_category *category)
2830{
2831 if (config->last)
2832 config->last->next = category;
2833 else
2834 config->root = category;
2835 config->last = category;
2836 config->current = category;
2837}
2838
2839static void ast_category_destroy(struct ast_category *cat);
2840
2841static void ast_category_destroy(struct ast_category *cat)
2842{
2844 if (cat->file)
2845 free(cat->file);
2846
2847 free(cat);
2848}
2849
2851 .name = "text",
2852 .load_func = config_text_file_load,
2853};
2854
2855
2856static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file);
2857
2858static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file)
2859{
2860 char db[256] = "";
2861 char table[256] = "";
2862 struct ast_config_engine *loader = &text_file_engine;
2863 struct ast_config *result;
2864
2865 if (cfg->include_level == cfg->max_include_level) {
2866 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
2867 return NULL;
2868 }
2869
2870 cfg->include_level++;
2871 /* silence is golden!
2872 ast_log(LOG_WARNING, "internal loading file %s level=%d\n", filename, cfg->include_level);
2873 */
2874
2875 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
2876 struct ast_config_engine *eng;
2877
2878 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
2879
2880
2881 if (eng && eng->load_func) {
2882 loader = eng;
2883 } else {
2884 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
2885 if (eng && eng->load_func)
2886 loader = eng;
2887 }
2888 }
2889
2890 result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
2891 /* silence is golden
2892 ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
2893 */
2894
2895 if (result)
2896 result->include_level--;
2897
2898 return result;
2899}
2900
2901
2902static 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)
2903{
2904 char *c;
2905 char *cur = buf;
2906 struct ast_variable *v;
2907 char exec_file[512];
2908 int object, do_exec, do_include;
2909
2910 /* Actually parse the entry */
2911 if (cur[0] == '[') {
2912 struct ast_category *newcat = NULL;
2913 char *catname;
2914
2915 /* A category header */
2916 c = strchr(cur, ']');
2917 if (!c) {
2918 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
2919 return -1;
2920 }
2921 *c++ = '\0';
2922 cur++;
2923 if (*c++ != '(')
2924 c = NULL;
2925 catname = cur;
2926 if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
2927 return -1;
2928 }
2929 (*cat)->lineno = lineno;
2930
2931 /* add comments */
2932 if (withcomments && comment_buffer && comment_buffer[0] ) {
2934 }
2935 if (withcomments && lline_buffer && lline_buffer[0] ) {
2937 }
2938 if( withcomments )
2939 CB_RESET();
2940
2941 /* If there are options or categories to inherit from, process them now */
2942 if (c) {
2943 if (!(cur = strchr(c, ')'))) {
2944 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
2945 return -1;
2946 }
2947 *cur = '\0';
2948 while ((cur = strsep(&c, ","))) {
2949 if (!strcasecmp(cur, "!")) {
2950 (*cat)->ignored = 1;
2951 } else if (!strcasecmp(cur, "+")) {
2952 *cat = category_get(cfg, catname, 1);
2953 if (!*cat) {
2954 ast_config_destroy(cfg);
2955 if (newcat)
2956 ast_category_destroy(newcat);
2957 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
2958 return -1;
2959 }
2960 if (newcat) {
2961 move_variables(newcat, *cat);
2962 ast_category_destroy(newcat);
2963 newcat = NULL;
2964 }
2965 } else {
2966 struct ast_category *base;
2967
2968 base = category_get(cfg, cur, 1);
2969 if (!base) {
2970 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
2971 return -1;
2972 }
2973 inherit_category(*cat, base);
2974 }
2975 }
2976 }
2977 if (newcat)
2978 ast_category_append(cfg, *cat);
2979 } else if (cur[0] == '#') {
2980 /* A directive */
2981 cur++;
2982 c = cur;
2983 while(*c && (*c > 32)) c++;
2984 if (*c) {
2985 *c = '\0';
2986 /* Find real argument */
2987 c = ast_skip_blanks(c + 1);
2988 if (!*c)
2989 c = NULL;
2990 } else
2991 c = NULL;
2992 do_include = !strcasecmp(cur, "include");
2993 if(!do_include)
2994 do_exec = !strcasecmp(cur, "exec");
2995 else
2996 do_exec = 0;
2997 if (do_exec && !ast_opt_exec_includes) {
2998 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
2999 do_exec = 0;
3000 }
3001 if (do_include || do_exec) {
3002 if (c) {
3003 char *cur2;
3004 char real_inclusion_name[525];
3005
3006 /* Strip off leading and trailing "'s and <>'s */
3007 while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
3008 /* Get rid of leading mess */
3009 cur = c;
3010 cur2 = cur;
3011 while (!ast_strlen_zero(cur)) {
3012 c = cur + strlen(cur) - 1;
3013 if ((*c == '>') || (*c == '<') || (*c == '\"'))
3014 *c = '\0';
3015 else
3016 break;
3017 }
3018 /* #exec </path/to/executable>
3019 We create a tmp file, then we #include it, then we delete it. */
3020 if (do_exec) {
3021 char cmd[1024];
3022
3023 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
3024 if (snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file) >= sizeof(cmd)) {
3025 ast_log(LOG_ERROR, "Failed to construct command string to execute %s.\n", cur);
3026
3027 return -1;
3028 }
3029 ast_safe_system(cmd);
3030 cur = exec_file;
3031 } else
3032 exec_file[0] = '\0';
3033 /* A #include */
3034 /* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
3035
3036 /* record this inclusion */
3037 ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
3038
3039 do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
3040 if(!ast_strlen_zero(exec_file))
3041 unlink(exec_file);
3042 if(!do_include)
3043 return 0;
3044 /* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
3045
3046 } else {
3047 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
3048 do_exec ? "exec" : "include",
3049 do_exec ? "/path/to/executable" : "filename",
3050 lineno,
3051 configfile);
3052 }
3053 }
3054 else
3055 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
3056 } else {
3057 /* Just a line (variable = value) */
3058 if (!*cat) {
3060 "parse error: No category context for line %d of %s\n", lineno, configfile);
3061 return -1;
3062 }
3063 c = strchr(cur, '=');
3064 if (c) {
3065 *c = 0;
3066 c++;
3067 /* Ignore > in => */
3068 if (*c== '>') {
3069 object = 1;
3070 c++;
3071 } else
3072 object = 0;
3073 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), configfile))) {
3074 v->lineno = lineno;
3075 v->object = object;
3076 /* Put and reset comments */
3077 v->blanklines = 0;
3078 ast_variable_append(*cat, v);
3079 /* add comments */
3080 if (withcomments && comment_buffer && comment_buffer[0] ) {
3082 }
3083 if (withcomments && lline_buffer && lline_buffer[0] ) {
3085 }
3086 if( withcomments )
3087 CB_RESET();
3088
3089 } else {
3090 return -1;
3091 }
3092 } else {
3093 ast_log(LOG_WARNING, "EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno, configfile);
3094 }
3095 }
3096 return 0;
3097}
3098
3099static int use_local_dir = 1;
3100
3101void localized_use_local_dir(void);
3102void localized_use_conf_dir(void);
3103
3105{
3106 use_local_dir = 1;
3107}
3108
3110{
3111 use_local_dir = 0;
3112}
3113
3114
3115static 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)
3116{
3117 char fn[256];
3118 char buf[8192];
3119 char *new_buf, *comment_p, *process_buf;
3120 FILE *f;
3121 int lineno=0;
3122 int comment = 0, nest[MAX_NESTED_COMMENTS];
3123 struct ast_category *cat = NULL;
3124 int count = 0;
3125 struct stat statbuf;
3126
3128
3129 if (filename[0] == '/') {
3130 ast_copy_string(fn, filename, sizeof(fn));
3131 } else {
3132 if (use_local_dir)
3133 snprintf(fn, sizeof(fn), "./%s", filename);
3134 else
3135 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
3136 }
3137
3138 if (withcomments && cfg && cfg->include_level < 2 ) {
3139 CB_INIT();
3140 }
3141
3142 do {
3143 if (stat(fn, &statbuf))
3144 continue;
3145
3146 if (!S_ISREG(statbuf.st_mode)) {
3147 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
3148 continue;
3149 }
3150 if (option_verbose > 1) {
3151 ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
3152 fflush(stdout);
3153 }
3154 if (!(f = fopen(fn, "r"))) {
3155 if (option_debug)
3156 ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
3157 if (option_verbose > 1)
3158 ast_verbose( "Not found (%s)\n", strerror(errno));
3159 continue;
3160 }
3161 count++;
3162 if (option_debug)
3163 ast_log(LOG_DEBUG, "Parsing %s\n", fn);
3164 if (option_verbose > 1)
3165 ast_verbose("Found\n");
3166 while(!feof(f)) {
3167 lineno++;
3168 if (fgets(buf, sizeof(buf), f)) {
3169 if ( withcomments ) {
3170 CB_ADD(lline_buffer); /* add the current lline buffer to the comment buffer */
3171 lline_buffer[0] = 0; /* erase the lline buffer */
3172 }
3173
3174 new_buf = buf;
3175 if (comment)
3176 process_buf = NULL;
3177 else
3178 process_buf = buf;
3179
3180 while ((comment_p = strchr(new_buf, COMMENT_META))) {
3181 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
3182 /* Yuck, gotta memmove */
3183 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
3184 new_buf = comment_p;
3185 } else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
3186 /* Meta-Comment start detected ";--" */
3188 *comment_p = '\0';
3189 new_buf = comment_p + 3;
3190 comment++;
3191 nest[comment-1] = lineno;
3192 } else {
3193 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
3194 }
3195 } else if ((comment_p >= new_buf + 2) &&
3196 (*(comment_p - 1) == COMMENT_TAG) &&
3197 (*(comment_p - 2) == COMMENT_TAG)) {
3198 /* Meta-Comment end detected */
3199 comment--;
3200 new_buf = comment_p + 1;
3201 if (!comment) {
3202 /* Back to non-comment now */
3203 if (process_buf) {
3204 /* Actually have to move what's left over the top, then continue */
3205 char *oldptr;
3206 oldptr = process_buf + strlen(process_buf);
3207 if ( withcomments ) {
3208 CB_ADD(";");
3209 CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
3210 }
3211
3212 memmove(oldptr, new_buf, strlen(new_buf) + 1);
3213 new_buf = oldptr;
3214 } else
3215 process_buf = new_buf;
3216 }
3217 } else {
3218 if (!comment) {
3219 /* If ; is found, and we are not nested in a comment,
3220 we immediately stop all comment processing */
3221 if ( withcomments ) {
3222 LLB_ADD(comment_p);
3223 }
3224 *comment_p = '\0';
3225 new_buf = comment_p;
3226 } else
3227 new_buf = comment_p + 1;
3228 }
3229 }
3230 if( withcomments && comment && !process_buf )
3231 {
3232 CB_ADD(buf); /* the whole line is a comment, store it */
3233 }
3234
3235 if (process_buf) {
3236 char *stripped_process_buf = ast_strip(process_buf);
3237 if (!ast_strlen_zero(stripped_process_buf)) {
3238 if (process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
3239 cfg = NULL;
3240 break;
3241 }
3242 }
3243 }
3244 }
3245 }
3246 fclose(f);
3247 } while(0);
3248 if (comment) {
3249 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
3250 }
3251 if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
3252 if (comment_buffer) {
3256 lline_buffer=0;
3259 }
3260 }
3261 if (count == 0)
3262 return NULL;
3263
3264 return cfg;
3265}
3266
3267
3268static struct ast_config *ast_config_new(void) ;
3269
3270static struct ast_config *ast_config_new(void)
3271{
3272 struct ast_config *config;
3273
3274 if ((config = ast_calloc(1, sizeof(*config))))
3276 return config;
3277}
3278
3279struct ast_config *localized_config_load(const char *filename);
3280
3281struct ast_config *localized_config_load(const char *filename)
3282{
3283 struct ast_config *cfg;
3284 struct ast_config *result;
3285
3286 cfg = ast_config_new();
3287 if (!cfg)
3288 return NULL;
3289
3290 result = ast_config_internal_load(filename, cfg, 0, "");
3291 if (!result)
3292 ast_config_destroy(cfg);
3293
3294 return result;
3295}
3296
3297struct ast_config *localized_config_load_with_comments(const char *filename);
3298
3300{
3301 struct ast_config *cfg;
3302 struct ast_config *result;
3303
3304 cfg = ast_config_new();
3305 if (!cfg)
3306 return NULL;
3307
3308 result = ast_config_internal_load(filename, cfg, 1, "");
3309 if (!result)
3310 ast_config_destroy(cfg);
3311
3312 return result;
3313}
3314
3316{
3317 for (; cat && cat->ignored; cat = cat->next);
3318
3319 return cat;
3320}
3321
3322static char *ast_category_browse(struct ast_config *config, const char *prev)
3323{
3324 struct ast_category *cat = NULL;
3325
3326 if (prev && config->last_browse && (config->last_browse->name == prev))
3327 cat = config->last_browse->next;
3328 else if (!prev && config->root)
3329 cat = config->root;
3330 else if (prev) {
3331 for (cat = config->root; cat; cat = cat->next) {
3332 if (cat->name == prev) {
3333 cat = cat->next;
3334 break;
3335 }
3336 }
3337 if (!cat) {
3338 for (cat = config->root; cat; cat = cat->next) {
3339 if (!strcasecmp(cat->name, prev)) {
3340 cat = cat->next;
3341 break;
3342 }
3343 }
3344 }
3345 }
3346
3347 if (cat)
3348 cat = next_available_category(cat);
3349
3350 config->last_browse = cat;
3351 return (cat) ? cat->name : NULL;
3352}
3353
3354
3355
3356void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
3357
3358void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
3359{
3360 /* cast below is just to silence compiler warning about dropping "const" */
3361 cfg->current = (struct ast_category *) cat;
3362}
3363
3364/* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
3365 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
3366 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
3367 be shocked and mystified as to why things are not showing up in the files!
3368
3369 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
3370 and line number are stored for each include, plus the name of the file included, so that these statements may be
3371 included in the output files on a file_save operation.
3372
3373 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
3374 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
3375 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
3376 and a header gets added.
3377
3378 vars and category heads are output in the order they are stored in the config file. So, if the software
3379 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
3380 file/lineno data probably won't get changed.
3381
3382*/
3383
3384static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
3385{
3386 char date[256]="";
3387 time_t t;
3388 time(&t);
3389 ast_copy_string(date, ctime(&t), sizeof(date));
3390
3391 fprintf(f1, ";!\n");
3392 fprintf(f1, ";! Automatically generated configuration file\n");
3393 if (strcmp(configfile, fn))
3394 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
3395 else
3396 fprintf(f1, ";! Filename: %s\n", configfile);
3397 fprintf(f1, ";! Generator: %s\n", generator);
3398 fprintf(f1, ";! Creation Date: %s", date);
3399 fprintf(f1, ";!\n");
3400}
3401
3402static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
3403{
3404 if (!file || file[0] == 0) {
3405 if (configfile[0] == '/')
3406 ast_copy_string(fn, configfile, fn_size);
3407 else
3408 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
3409 } else if (file[0] == '/')
3410 ast_copy_string(fn, file, fn_size);
3411 else
3412 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
3413}
3414
3415int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
3416
3417int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
3418{
3419 FILE *f;
3420 char fn[256];
3421 struct ast_variable *var;
3422 struct ast_category *cat;
3423 struct ast_comment *cmt;
3424 struct ast_config_include *incl;
3425 int blanklines = 0;
3426
3427 /* reset all the output flags, in case this isn't our first time saving this data */
3428
3429 for (incl=cfg->includes; incl; incl = incl->next)
3430 incl->output = 0;
3431
3432 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
3433 are all truncated to zero bytes and have that nice header*/
3434
3435 for (incl=cfg->includes; incl; incl = incl->next)
3436 {
3437 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*/
3438 FILE *f1;
3439
3440 set_fn(fn, sizeof(fn), incl->included_file, configfile); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
3441 f1 = fopen(fn,"w");
3442 if (f1) {
3443 gen_header(f1, configfile, fn, generator);
3444 fclose(f1); /* this should zero out the file */
3445 } else {
3446 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3447 }
3448 }
3449 }
3450
3451 set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
3452#ifdef __CYGWIN__
3453 if ((f = fopen(fn, "w+"))) {
3454#else
3455 if ((f = fopen(fn, "w"))) {
3456#endif
3457 if (option_verbose > 1)
3458 ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
3459
3460 gen_header(f, configfile, fn, generator);
3461 cat = cfg->root;
3462 fclose(f);
3463
3464 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
3465 /* since each var, cat, and associated comments can come from any file, we have to be
3466 mobile, and open each file, print, and close it on an entry-by-entry basis */
3467
3468 while(cat) {
3469 set_fn(fn, sizeof(fn), cat->file, configfile);
3470 f = fopen(fn, "a");
3471 if (!f)
3472 {
3473 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3474 return -1;
3475 }
3476
3477 /* dump any includes that happen before this category header */
3478 for (incl=cfg->includes; incl; incl = incl->next) {
3479 if (strcmp(incl->include_location_file, cat->file) == 0){
3480 if (cat->lineno > incl->include_location_lineno && !incl->output) {
3481 if (incl->exec)
3482 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
3483 else
3484 fprintf(f,"#include \"%s\"\n", incl->included_file);
3485 incl->output = 1;
3486 }
3487 }
3488 }
3489
3490 /* Dump section with any appropriate comment */
3491 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
3492 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
3493 fprintf(f,"%s", cmt->cmt);
3494 }
3495 if (!cat->precomments)
3496 fprintf(f,"\n");
3497 fprintf(f, "[%s]", cat->name);
3498 for(cmt = cat->sameline; cmt; cmt=cmt->next) {
3499 fprintf(f,"%s", cmt->cmt);
3500 }
3501 if (!cat->sameline)
3502 fprintf(f,"\n");
3503 fclose(f);
3504
3505 var = cat->root;
3506 while(var) {
3507 set_fn(fn, sizeof(fn), var->file, configfile);
3508 f = fopen(fn, "a");
3509 if (!f)
3510 {
3511 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3512 return -1;
3513 }
3514
3515 /* dump any includes that happen before this category header */
3516 for (incl=cfg->includes; incl; incl = incl->next) {
3517 if (strcmp(incl->include_location_file, var->file) == 0){
3518 if (var->lineno > incl->include_location_lineno && !incl->output) {
3519 if (incl->exec)
3520 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
3521 else
3522 fprintf(f,"#include \"%s\"\n", incl->included_file);
3523 incl->output = 1;
3524 }
3525 }
3526 }
3527
3528 for (cmt = var->precomments; cmt; cmt=cmt->next) {
3529 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
3530 fprintf(f,"%s", cmt->cmt);
3531 }
3532 if (var->sameline)
3533 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
3534 else
3535 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
3536 if (var->blanklines) {
3537 blanklines = var->blanklines;
3538 while (blanklines--)
3539 fprintf(f, "\n");
3540 }
3541
3542 fclose(f);
3543
3544
3545 var = var->next;
3546 }
3547 cat = cat->next;
3548 }
3549 if ((option_verbose > 1) && !option_debug)
3550 ast_verbose("Saved\n");
3551 } else {
3552 if (option_debug)
3553 ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
3554 if (option_verbose > 1)
3555 ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
3556 return -1;
3557 }
3558
3559 /* Now, for files with trailing #include/#exec statements,
3560 we have to make sure every entry is output */
3561
3562 for (incl=cfg->includes; incl; incl = incl->next) {
3563 if (!incl->output) {
3564 /* open the respective file */
3565 set_fn(fn, sizeof(fn), incl->include_location_file, configfile);
3566 f = fopen(fn, "a");
3567 if (!f)
3568 {
3569 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3570 return -1;
3571 }
3572
3573 /* output the respective include */
3574 if (incl->exec)
3575 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
3576 else
3577 fprintf(f,"#include \"%s\"\n", incl->included_file);
3578 fclose(f);
3579 incl->output = 1;
3580 }
3581 }
3582
3583 return 0;
3584}
3585
3586/* ================ the Line ========================================
3587 above this line, you have what you need to load a config file,
3588 and below it, you have what you need to process the extensions.conf
3589 file into the context/exten/prio stuff. They are both in one file
3590 to make things simpler */
3591
3593static struct ast_context *contexts = NULL;
3594struct ast_context;
3595struct ast_app;
3596#ifdef LOW_MEMORY
3597#define EXT_DATA_SIZE 256
3598#else
3599#define EXT_DATA_SIZE 8192
3600#endif
3601
3602#ifdef NOT_ANYMORE
3604#endif
3605
3606#define SWITCH_DATA_LENGTH 256
3607
3608static const char *ast_get_extension_app(struct ast_exten *e)
3609{
3610 return e ? e->app : NULL;
3611}
3612
3613static const char *ast_get_extension_name(struct ast_exten *exten)
3614{
3615 return exten ? exten->exten : NULL;
3616}
3617
3619
3620/*! \brief ast_change_hint: Change hint for an extension */
3621static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
3622{
3623 struct ast_hint *hint;
3624 int res = -1;
3625
3626 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3627 if (hint->exten == oe) {
3628 hint->exten = ne;
3629 res = 0;
3630 break;
3631 }
3632 }
3633
3634 return res;
3635}
3636
3637/*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
3638static int ast_add_hint(struct ast_exten *e)
3639{
3640 struct ast_hint *hint;
3641
3642 if (!e)
3643 return -1;
3644
3645
3646 /* Search if hint exists, do nothing */
3647 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3648 if (hint->exten == e) {
3649 if (option_debug > 1)
3650 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3651 return -1;
3652 }
3653 }
3654
3655 if (option_debug > 1)
3656 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3657
3658 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
3659 return -1;
3660 }
3661 /* Initialize and insert new item at the top */
3662 hint->exten = e;
3664
3665 return 0;
3666}
3667
3668/*! \brief add the extension in the priority chain.
3669 * returns 0 on success, -1 on failure
3670 */
3671static int add_pri(struct ast_context *con, struct ast_exten *tmp,
3672 struct ast_exten *el, struct ast_exten *e, int replace)
3673{
3674 struct ast_exten *ep;
3675
3676 for (ep = NULL; e ; ep = e, e = e->peer) {
3677 if (e->priority >= tmp->priority)
3678 break;
3679 }
3680 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
3681 ep->peer = tmp;
3682 return 0; /* success */
3683 }
3684 if (e->priority == tmp->priority) {
3685 /* Can't have something exactly the same. Is this a
3686 replacement? If so, replace, otherwise, bonk. */
3687 if (!replace) {
3688 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
3689 tmp->datad(tmp->data);
3690 free(tmp);
3691 return -1;
3692 }
3693 /* we are replacing e, so copy the link fields and then update
3694 * whoever pointed to e to point to us
3695 */
3696 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
3697 tmp->peer = e->peer; /* always meaningful */
3698 if (ep) /* We're in the peer list, just insert ourselves */
3699 ep->peer = tmp;
3700 else if (el) /* We're the first extension. Take over e's functions */
3701 el->next = tmp;
3702 else /* We're the very first extension. */
3703 con->root = tmp;
3704 if (tmp->priority == PRIORITY_HINT)
3705 ast_change_hint(e,tmp);
3706 /* Destroy the old one */
3707 e->datad(e->data);
3708 free(e);
3709 } else { /* Slip ourselves in just before e */
3710 tmp->peer = e;
3711 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
3712 if (ep) /* Easy enough, we're just in the peer list */
3713 ep->peer = tmp;
3714 else { /* we are the first in some peer list, so link in the ext list */
3715 if (el)
3716 el->next = tmp; /* in the middle... */
3717 else
3718 con->root = tmp; /* ... or at the head */
3719 e->next = NULL; /* e is no more at the head, so e->next must be reset */
3720 }
3721 /* And immediately return success. */
3722 if (tmp->priority == PRIORITY_HINT)
3723 ast_add_hint(tmp);
3724 }
3725 return 0;
3726}
3727
3728/*! \brief ast_remove_hint: Remove hint from extension */
3729static int ast_remove_hint(struct ast_exten *e)
3730{
3731 /* Cleanup the Notifys if hint is removed */
3732 struct ast_hint *hint;
3733 struct ast_state_cb *cblist, *cbprev;
3734 int res = -1;
3735
3736 if (!e)
3737 return -1;
3738
3740 if (hint->exten == e) {
3741 cbprev = NULL;
3742 cblist = hint->callbacks;
3743 while (cblist) {
3744 /* Notify with -1 and remove all callbacks */
3745 cbprev = cblist;
3746 cblist = cblist->next;
3747 free(cbprev);
3748 }
3749 hint->callbacks = NULL;
3751 free(hint);
3752 res = 0;
3753 break;
3754 }
3755 }
3757
3758 return res;
3759}
3760
3761static void destroy_exten(struct ast_exten *e)
3762{
3763 if (e->priority == PRIORITY_HINT)
3764 ast_remove_hint(e);
3765
3766 if (e->datad)
3767 e->datad(e->data);
3768 free(e);
3769}
3770
3771char *days[] =
3772{
3773 "sun",
3774 "mon",
3775 "tue",
3776 "wed",
3777 "thu",
3778 "fri",
3779 "sat",
3780 NULL,
3781};
3782
3783char *months[] =
3784{
3785 "jan",
3786 "feb",
3787 "mar",
3788 "apr",
3789 "may",
3790 "jun",
3791 "jul",
3792 "aug",
3793 "sep",
3794 "oct",
3795 "nov",
3796 "dec",
3797 NULL,
3798};
3799
3800int ast_build_timing(struct ast_timing *i, const char *info_in);
3801
3802int ast_build_timing(struct ast_timing *i, const char *info_in)
3803{
3804 char *info;
3805 int j, num_fields, last_sep = -1;
3806
3807 i->timezone = NULL;
3808
3809 /* Check for empty just in case */
3810 if (ast_strlen_zero(info_in)) {
3811 return 0;
3812 }
3813
3814 /* make a copy just in case we were passed a static string */
3815 info = ast_strdupa(info_in);
3816
3817 /* count the number of fields in the timespec */
3818 for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
3819 if (info[j] == '|' || info[j] == ',') {
3820 last_sep = j;
3821 num_fields++;
3822 }
3823 }
3824
3825 /* save the timezone, if it is specified */
3826 if (num_fields == 5) {
3827 i->timezone = ast_strdup(info + last_sep + 1);
3828 }
3829
3830 /* Assume everything except time */
3831 i->monthmask = 0xfff; /* 12 bits */
3832 i->daymask = 0x7fffffffU; /* 31 bits */
3833 i->dowmask = 0x7f; /* 7 bits */
3834 /* on each call, use strsep() to move info to the next argument */
3835 get_timerange(i, strsep(&info, "|,"));
3836 if (info)
3837 i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
3838 if (info)
3839 i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
3840 if (info)
3841 i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
3842 return 1;
3843}
3844
3845/*!
3846 * \brief helper functions to sort extensions and patterns in the desired way,
3847 * so that more specific patterns appear first.
3848 *
3849 * ext_cmp1 compares individual characters (or sets of), returning
3850 * an int where bits 0-7 are the ASCII code of the first char in the set,
3851 * while bit 8-15 are the cardinality of the set minus 1.
3852 * This way more specific patterns (smaller cardinality) appear first.
3853 * Wildcards have a special value, so that we can directly compare them to
3854 * sets by subtracting the two values. In particular:
3855 * 0x000xx one character, xx
3856 * 0x0yyxx yy character set starting with xx
3857 * 0x10000 '.' (one or more of anything)
3858 * 0x20000 '!' (zero or more of anything)
3859 * 0x30000 NUL (end of string)
3860 * 0x40000 error in set.
3861 * The pointer to the string is advanced according to needs.
3862 * NOTES:
3863 * 1. the empty set is equivalent to NUL.
3864 * 2. given that a full set has always 0 as the first element,
3865 * we could encode the special cases as 0xffXX where XX
3866 * is 1, 2, 3, 4 as used above.
3867 */
3868static int ext_cmp1(const char **p)
3869{
3870 uint32_t chars[8];
3871 int c, cmin = 0xff, count = 0;
3872 const char *end;
3873
3874 /* load, sign extend and advance pointer until we find
3875 * a valid character.
3876 */
3877 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
3878 ; /* ignore some characters */
3879
3880 /* always return unless we have a set of chars */
3881 switch (c) {
3882 default: /* ordinary character */
3883 return 0x0000 | (c & 0xff);
3884
3885 case 'N': /* 2..9 */
3886 return 0x0700 | '2' ;
3887
3888 case 'X': /* 0..9 */
3889 return 0x0900 | '0';
3890
3891 case 'Z': /* 1..9 */
3892 return 0x0800 | '1';
3893
3894 case '.': /* wildcard */
3895 return 0x10000;
3896
3897 case '!': /* earlymatch */
3898 return 0x20000; /* less specific than NULL */
3899
3900 case '\0': /* empty string */
3901 *p = NULL;
3902 return 0x30000;
3903
3904 case '[': /* pattern */
3905 break;
3906 }
3907 /* locate end of set */
3908 end = strchr(*p, ']');
3909
3910 if (end == NULL) {
3911 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
3912 return 0x40000; /* XXX make this entry go last... */
3913 }
3914
3915 memset(chars, '\0', sizeof(chars)); /* clear all chars in the set */
3916 for (; *p < end ; (*p)++) {
3917 unsigned char c1, c2; /* first-last char in range */
3918 c1 = (unsigned char)((*p)[0]);
3919 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
3920 c2 = (unsigned char)((*p)[2]);
3921 *p += 2; /* skip a total of 3 chars */
3922 } else /* individual character */
3923 c2 = c1;
3924 if (c1 < cmin)
3925 cmin = c1;
3926 for (; c1 <= c2; c1++) {
3927 uint32_t mask = 1 << (c1 % 32);
3928 if ( (chars[ c1 / 32 ] & mask) == 0)
3929 count += 0x100;
3930 chars[ c1 / 32 ] |= mask;
3931 }
3932 }
3933 (*p)++;
3934 return count == 0 ? 0x30000 : (count | cmin);
3935}
3936
3937/*!
3938 * \brief the full routine to compare extensions in rules.
3939 */
3940static int ext_cmp(const char *a, const char *b)
3941{
3942 /* make sure non-patterns come first.
3943 * If a is not a pattern, it either comes first or
3944 * we use strcmp to compare the strings.
3945 */
3946 int ret = 0;
3947
3948 if (a[0] != '_')
3949 return (b[0] == '_') ? -1 : strcmp(a, b);
3950
3951 /* Now we know a is a pattern; if b is not, a comes first */
3952 if (b[0] != '_')
3953 return 1;
3954#if 0 /* old mode for ext matching */
3955 return strcmp(a, b);
3956#endif
3957 /* ok we need full pattern sorting routine */
3958 while (!ret && a && b)
3959 ret = ext_cmp1(&a) - ext_cmp1(&b);
3960 if (ret == 0)
3961 return 0;
3962 else
3963 return (ret > 0) ? 1 : -1;
3964}
3965
3966/*! \brief copy a string skipping whitespace */
3967static int ext_strncpy(char *dst, const char *src, int len)
3968{
3969 int count=0;
3970
3971 while (*src && (count < len - 1)) {
3972 switch(*src) {
3973 case ' ':
3974 /* otherwise exten => [a-b],1,... doesn't work */
3975 /* case '-': */
3976 /* Ignore */
3977 break;
3978 default:
3979 *dst = *src;
3980 dst++;
3981 }
3982 src++;
3983 count++;
3984 }
3985 *dst = '\0';
3986
3987 return count;
3988}
3989
3990/*
3991 * Wrapper around _extension_match_core() to do performance measurement
3992 * using the profiling code.
3993 */
3994int ast_check_timing(const struct ast_timing *i);
3995
3996int ast_check_timing(const struct ast_timing *i)
3997{
3998 /* sorry, but this feature will NOT be available
3999 in the standalone version */
4000 return 0;
4001}
4002
4003#ifdef NOT_ANYMORE
4004static struct ast_switch *pbx_findswitch(const char *sw)
4005{
4006 struct ast_switch *asw;
4007
4009 if (!strcasecmp(asw->name, sw))
4010 break;
4011 }
4012
4013 return asw;
4014}
4015#endif
4016
4017
4018static struct ast_context *ast_walk_contexts(struct ast_context *con);
4019
4020static struct ast_context *ast_walk_contexts(struct ast_context *con)
4021{
4022 return con ? con->next : contexts;
4023}
4024
4027{
4028 return ast_walk_contexts(con);
4029}
4030
4031
4032
4033static struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
4034 struct ast_exten *exten);
4035
4037 struct ast_exten *exten)
4038{
4039 if (!exten)
4040 return con ? con->root : NULL;
4041 else
4042 return exten->next;
4043}
4044
4046 struct ast_exten *exten);
4048 struct ast_exten *exten)
4049{
4051}
4052
4053
4055 struct ast_exten *priority);
4056
4058 struct ast_exten *priority)
4059{
4060 return priority ? priority->peer : exten;
4061}
4062
4064 struct ast_exten *priority);
4070
4071
4072
4073static struct ast_include *ast_walk_context_includes(struct ast_context *con,
4074 struct ast_include *inc);
4075
4077 struct ast_include *inc)
4078{
4079 if (!inc)
4080 return con ? con->includes : NULL;
4081 else
4082 return inc->next;
4083}
4084
4087{
4088 int c = 0;
4089 struct ast_include *inc = NULL;
4090
4091 while ((inc = ast_walk_context_includes(con, inc))) {
4092 c++;
4093 }
4094
4095 return c;
4096}
4097
4099 struct ast_include *inc);
4101 struct ast_include *inc)
4102{
4103 return ast_walk_context_includes(con, inc);
4104}
4105
4106static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
4107 struct ast_ignorepat *ip);
4108
4110 struct ast_ignorepat *ip)
4111{
4112 if (!ip)
4113 return con ? con->ignorepats : NULL;
4114 else
4115 return ip->next;
4116}
4117
4120{
4121 int c = 0;
4122 struct ast_ignorepat *ip = NULL;
4123
4124 while ((ip = ast_walk_context_ignorepats(con, ip))) {
4125 c++;
4126 }
4127
4128 return c;
4129}
4130
4131
4132static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
4133 struct ast_sw *sw);
4134
4136 struct ast_sw *sw)
4137{
4138 if (!sw)
4139 return con ? AST_LIST_FIRST(&con->alts) : NULL;
4140 else
4141 return AST_LIST_NEXT(sw, list);
4142}
4143
4145 struct ast_sw *sw);
4147 struct ast_sw *sw)
4148{
4149 return ast_walk_context_switches(con, sw);
4150}
4151
4154{
4155 int c = 0;
4156 struct ast_sw *sw = NULL;
4157
4158 while ((sw = ast_walk_context_switches(con, sw))) {
4159 c++;
4160 }
4161
4162 return c;
4163}
4164
4165
4166static struct ast_context *ast_context_find(const char *name);
4167
4168static struct ast_context *ast_context_find(const char *name)
4169{
4170 struct ast_context *tmp = NULL;
4171 while ( (tmp = ast_walk_contexts(tmp)) ) {
4172 if (!name || !strcasecmp(name, tmp->name))
4173 break;
4174 }
4175 return tmp;
4176}
4177
4178/*
4179 * Internal function for ast_extension_{match|close}
4180 * return 0 on no-match, 1 on match, 2 on early match.
4181 * mode is as follows:
4182 * E_MATCH success only on exact match
4183 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
4184 * E_CANMATCH either of the above.
4185 */
4186
4187static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
4188{
4189 mode &= E_MATCH_MASK; /* only consider the relevant bits */
4190
4191 if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
4192 return 1;
4193
4194 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
4195 int ld = strlen(data), lp = strlen(pattern);
4196
4197 if (lp < ld) /* pattern too short, cannot match */
4198 return 0;
4199 /* depending on the mode, accept full or partial match or both */
4200 if (mode == E_MATCH)
4201 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
4202 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
4203 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
4204 else
4205 return 0;
4206 }
4207 pattern++; /* skip leading _ */
4208 /*
4209 * XXX below we stop at '/' which is a separator for the CID info. However we should
4210 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
4211 */
4212 while (*data && *pattern && *pattern != '/') {
4213 const char *end;
4214
4215 if (*data == '-') { /* skip '-' in data (just a separator) */
4216 data++;
4217 continue;
4218 }
4219 switch (toupper(*pattern)) {
4220 case '[': /* a range */
4221 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
4222 if (end == NULL) {
4223 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
4224 return 0; /* unconditional failure */
4225 }
4226 for (pattern++; pattern != end; pattern++) {
4227 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
4228 if (*data >= pattern[0] && *data <= pattern[2])
4229 break; /* match found */
4230 else {
4231 pattern += 2; /* skip a total of 3 chars */
4232 continue;
4233 }
4234 } else if (*data == pattern[0])
4235 break; /* match found */
4236 }
4237 if (pattern == end)
4238 return 0;
4239 pattern = end; /* skip and continue */
4240 break;
4241 case 'N':
4242 if (*data < '2' || *data > '9')
4243 return 0;
4244 break;
4245 case 'X':
4246 if (*data < '0' || *data > '9')
4247 return 0;
4248 break;
4249 case 'Z':
4250 if (*data < '1' || *data > '9')
4251 return 0;
4252 break;
4253 case '.': /* Must match, even with more digits */
4254 return 1;
4255 case '!': /* Early match */
4256 return 2;
4257 case ' ':
4258 case '-': /* Ignore these in patterns */
4259 data--; /* compensate the final data++ */
4260 break;
4261 default:
4262 if (*data != *pattern)
4263 return 0;
4264 }
4265 data++;
4266 pattern++;
4267 }
4268 if (*data) /* data longer than pattern, no match */
4269 return 0;
4270 /*
4271 * match so far, but ran off the end of the data.
4272 * Depending on what is next, determine match or not.
4273 */
4274 if (*pattern == '\0' || *pattern == '/') /* exact match */
4275 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
4276 else if (*pattern == '!') /* early match */
4277 return 2;
4278 else /* partial match */
4279 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
4280}
4281
4282static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
4283{
4284 int i;
4285 i = _extension_match_core(pattern, data, mode);
4286 return i;
4287}
4288
4289static int ast_extension_match(const char *pattern, const char *data);
4290
4291static int ast_extension_match(const char *pattern, const char *data)
4292{
4293 return extension_match_core(pattern, data, E_MATCH);
4294}
4295
4296static int matchcid(const char *cidpattern, const char *callerid)
4297{
4298 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
4299 failing to get a number should count as a match, otherwise not */
4300
4301 if (ast_strlen_zero(callerid))
4302 return ast_strlen_zero(cidpattern) ? 1 : 0;
4303
4304 return ast_extension_match(cidpattern, callerid);
4305}
4306
4307static inline int include_valid(struct ast_include *i)
4308{
4309 if (!i->hastime)
4310 return 1;
4311
4312 return ast_check_timing(&(i->timing));
4313}
4314
4315
4316
4317static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
4318 struct ast_context *bypass,
4319 struct pbx_find_info *q,
4320 const char *context,
4321 const char *exten,
4322 int priority,
4323 const char *label,
4324 const char *callerid,
4325 enum ext_match_t action);
4326
4327
4328static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
4329 struct ast_context *bypass,
4330 struct pbx_find_info *q,
4331 const char *context,
4332 const char *exten,
4333 int priority,
4334 const char *label,
4335 const char *callerid,
4336 enum ext_match_t action)
4337{
4338 int x;
4339 struct ast_context *tmp;
4340 struct ast_exten *e, *eroot;
4341 struct ast_include *i;
4342
4343 if (!context) {
4344 return NULL;
4345 }
4346
4347 /* Initialize status if appropriate */
4348 if (q->stacklen == 0) {
4350 q->swo = NULL;
4351 q->data = NULL;
4352 q->foundcontext = NULL;
4353 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
4354 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
4355 return NULL;
4356 }
4357 /* Check first to see if we've already been checked */
4358 for (x = 0; x < q->stacklen; x++) {
4359 if (!strcasecmp(q->incstack[x], context))
4360 return NULL;
4361 }
4362 if (bypass) /* bypass means we only look there */
4363 tmp = bypass;
4364 else { /* look in contexts */
4365 tmp = NULL;
4366 while ((tmp = ast_walk_contexts(tmp)) ) {
4367 if (!strcmp(tmp->name, context))
4368 break;
4369 }
4370 if (!tmp)
4371 return NULL;
4372 }
4373 if (q->status < STATUS_NO_EXTENSION)
4375
4376 /* scan the list trying to match extension and CID */
4377 eroot = NULL;
4378 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
4379 int match = extension_match_core(eroot->exten, exten, action);
4380 /* 0 on fail, 1 on match, 2 on earlymatch */
4381
4382 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
4383 continue; /* keep trying */
4384 if (match == 2 && action == E_MATCHMORE) {
4385 /* We match an extension ending in '!'.
4386 * The decision in this case is final and is NULL (no match).
4387 */
4388 return NULL;
4389 }
4390 /* found entry, now look for the right priority */
4391 if (q->status < STATUS_NO_PRIORITY)
4393 e = NULL;
4394 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
4395 /* Match label or priority */
4396 if (action == E_FINDLABEL) {
4397 if (q->status < STATUS_NO_LABEL)
4399 if (label && e->label && !strcmp(label, e->label))
4400 break; /* found it */
4401 } else if (e->priority == priority) {
4402 break; /* found it */
4403 } /* else keep searching */
4404 }
4405 if (e) { /* found a valid match */
4407 q->foundcontext = context;
4408 return e;
4409 }
4410 }
4411#ifdef NOT_RIGHT_NOW
4412 /* Check alternative switches??? */
4413 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
4414 struct ast_switch *asw = pbx_findswitch(sw->name);
4415 ast_switch_f *aswf = NULL;
4416 char *datap;
4417
4418 if (!asw) {
4419 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
4420 continue;
4421 }
4422 /* No need to Substitute variables now; we shouldn't be here if there's any */
4423
4424 /* equivalent of extension_match_core() at the switch level */
4425 if (action == E_CANMATCH)
4426 aswf = asw->canmatch;
4427 else if (action == E_MATCHMORE)
4428 aswf = asw->matchmore;
4429 else /* action == E_MATCH */
4430 aswf = asw->exists;
4431 datap = sw->eval ? sw->tmpdata : sw->data;
4432 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
4433 if (res) { /* Got a match */
4434 q->swo = asw;
4435 q->data = datap;
4436 q->foundcontext = context;
4437 /* XXX keep status = STATUS_NO_CONTEXT ? */
4438 return NULL;
4439 }
4440 }
4441#endif
4442 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
4443 /* Now try any includes we have in this context */
4444 for (i = tmp->includes; i; i = i->next) {
4445 if (include_valid(i)) {
4446 if ((e = pbx_find_extension(NULL, bypass, q, i->rname, exten, priority, label, callerid, action)))
4447 return e;
4448 if (q->swo)
4449 return NULL;
4450 }
4451 }
4452 return NULL;
4453}
4454
4455struct ast_exten *localized_find_extension(struct ast_context *bypass,
4456 struct pbx_find_info *q,
4457 const char *context,
4458 const char *exten,
4459 int priority,
4460 const char *label,
4461 const char *callerid,
4462 enum ext_match_t action);
4463
4465 struct pbx_find_info *q,
4466 const char *context,
4467 const char *exten,
4468 int priority,
4469 const char *label,
4470 const char *callerid,
4471 enum ext_match_t action)
4472{
4473 return pbx_find_extension(NULL, bypass, q, context, exten, priority, label, callerid, action);
4474}
4475
4476
4477static struct ast_context *contexts;
4478AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
4479
4480static const char *ast_get_context_name(struct ast_context *con);
4481
4482static const char *ast_get_context_name(struct ast_context *con)
4483{
4484 return con ? con->name : NULL;
4485}
4486
4487/*
4488 * errno values
4489 * ENOMEM - out of memory
4490 * EBUSY - can't lock
4491 * EEXIST - already included
4492 * EINVAL - there is no existence of context for inclusion
4493 */
4494static int ast_context_add_include2(struct ast_context *con, const char *value,
4495 const char *registrar);
4496
4497static int ast_context_add_include2(struct ast_context *con, const char *value,
4498 const char *registrar)
4499{
4500 struct ast_include *new_include;
4501 char *c;
4502 struct ast_include *i, *il = NULL; /* include, include_last */
4503 int length;
4504 char *p;
4505
4506 length = sizeof(struct ast_include);
4507 length += 2 * (strlen(value) + 1);
4508
4509 /* allocate new include structure ... */
4510 if (!(new_include = ast_calloc(1, length)))
4511 return -1;
4512 /* Fill in this structure. Use 'p' for assignments, as the fields
4513 * in the structure are 'const char *'
4514 */
4515 p = new_include->stuff;
4516 new_include->name = p;
4517 strcpy(p, value);
4518 p += strlen(value) + 1;
4519 new_include->rname = p;
4520 strcpy(p, value);
4521 /* Strip off timing info, and process if it is there */
4522 if ( (c = strchr(p, '|')) || (c = strchr(p, ',')) ) {
4523 *c++ = '\0';
4524 new_include->hastime = ast_build_timing(&(new_include->timing), c);
4525 }
4526 new_include->next = NULL;
4527 new_include->registrar = registrar;
4528
4529
4530 /* ... go to last include and check if context is already included too... */
4531 for (i = con->includes; i; i = i->next) {
4532 if (!strcasecmp(i->name, new_include->name)) {
4533 free(new_include);
4534 errno = EEXIST;
4535 return -1;
4536 }
4537 il = i;
4538 }
4539
4540 /* ... include new context into context list, unlock, return */
4541 if (il)
4542 il->next = new_include;
4543 else
4544 con->includes = new_include;
4545 if (option_verbose > 2)
4546 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
4547
4548 return 0;
4549}
4550
4551int localized_context_add_include2(struct ast_context *con, const char *value,
4552 const char *registrar);
4554 const char *registrar)
4555{
4557}
4558
4559
4560
4561static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
4562
4563static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
4564{
4565 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
4566 int length;
4567 length = sizeof(struct ast_ignorepat);
4568 length += strlen(value) + 1;
4569 if (!(ignorepat = ast_calloc(1, length)))
4570 return -1;
4571 /* The cast to char * is because we need to write the initial value.
4572 * The field is not supposed to be modified otherwise
4573 */
4574 strcpy((char *)ignorepat->pattern, value);
4575 ignorepat->next = NULL;
4576 ignorepat->registrar = registrar;
4577 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
4578 ignorepatl = ignorepatc;
4579 if (!strcasecmp(ignorepatc->pattern, value)) {
4580 /* Already there */
4581 errno = EEXIST;
4582 return -1;
4583 }
4584 }
4585 if (ignorepatl)
4586 ignorepatl->next = ignorepat;
4587 else
4588 con->ignorepats = ignorepat;
4589 return 0;
4590
4591}
4592
4593int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
4594
4595int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
4596{
4598}
4599
4600
4601/*
4602 * Lock context list functions ...
4603 */
4604
4605static int ast_wrlock_contexts(void)
4606{
4607 return ast_rwlock_wrlock(&conlock);
4608}
4609
4610static int ast_unlock_contexts(void)
4611{
4612 return ast_rwlock_unlock(&conlock);
4613}
4614
4615static int ast_wrlock_context(struct ast_context *con)
4616{
4617 return ast_rwlock_wrlock(&con->lock);
4618}
4619
4620static int ast_unlock_context(struct ast_context *con)
4621{
4622 return ast_rwlock_unlock(&con->lock);
4623}
4624
4625/*
4626 * errno values
4627 * ENOMEM - out of memory
4628 * EBUSY - can't lock
4629 * EEXIST - already included
4630 * EINVAL - there is no existence of context for inclusion
4631 */
4632static int ast_context_add_switch2(struct ast_context *con, const char *value,
4633 const char *data, int eval, const char *registrar);
4634
4635static int ast_context_add_switch2(struct ast_context *con, const char *value,
4636 const char *data, int eval, const char *registrar)
4637{
4638 struct ast_sw *new_sw;
4639 struct ast_sw *i;
4640 int length;
4641 char *p;
4642
4643 length = sizeof(struct ast_sw);
4644 length += strlen(value) + 1;
4645 if (data)
4646 length += strlen(data);
4647 length++;
4648 if (eval) {
4649 /* Create buffer for evaluation of variables */
4650 length += SWITCH_DATA_LENGTH;
4651 length++;
4652 }
4653
4654 /* allocate new sw structure ... */
4655 if (!(new_sw = ast_calloc(1, length)))
4656 return -1;
4657 /* ... fill in this structure ... */
4658 p = new_sw->stuff;
4659 new_sw->name = p;
4660 strcpy(new_sw->name, value);
4661 p += strlen(value) + 1;
4662 new_sw->data = p;
4663 if (data) {
4664 strcpy(new_sw->data, data);
4665 p += strlen(data) + 1;
4666 } else {
4667 strcpy(new_sw->data, "");
4668 p++;
4669 }
4670 if (eval)
4671 new_sw->tmpdata = p;
4672 new_sw->eval = eval;
4673 new_sw->registrar = registrar;
4674
4675 /* ... go to last sw and check if context is already swd too... */
4676 AST_LIST_TRAVERSE(&con->alts, i, list) {
4677 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
4678 free(new_sw);
4679 errno = EEXIST;
4680 return -1;
4681 }
4682 }
4683
4684 /* ... sw new context into context list, unlock, return */
4685 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
4686
4687 if (option_verbose > 2)
4688 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
4689
4690 return 0;
4691}
4692
4693int localized_context_add_switch2(struct ast_context *con, const char *value,
4694 const char *data, int eval, const char *registrar);
4695
4697 const char *data, int eval, const char *registrar)
4698{
4700}
4701
4702static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
4703{
4704 struct ast_context *tmp, **loc_contexts;
4705 int length = sizeof(struct ast_context) + strlen(name) + 1;
4706
4707 if (!extcontexts) {
4709 loc_contexts = &contexts;
4710 } else
4711 loc_contexts = extcontexts;
4712
4713 for (tmp = *loc_contexts; tmp; tmp = tmp->next) {
4714 if (!strcasecmp(tmp->name, name)) {
4715 if (!existsokay) {
4716 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
4717 tmp = NULL;
4718 }
4719 if (!extcontexts)
4721 return tmp;
4722 }
4723 }
4724 if ((tmp = ast_calloc(1, length))) {
4725 ast_rwlock_init(&tmp->lock);
4726 strcpy(tmp->name, name);
4727 tmp->root = NULL;
4728 tmp->registrar = registrar;
4729 tmp->next = *loc_contexts;
4730 tmp->includes = NULL;
4731 tmp->ignorepats = NULL;
4732 *loc_contexts = tmp;
4733 if (option_debug)
4734 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
4735 if (option_verbose > 2)
4736 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
4737 }
4738
4739 if (!extcontexts)
4741 return tmp;
4742}
4743
4744/*! \brief
4745 * Main interface to add extensions to the list for out context.
4746 *
4747 * We sort extensions in order of matching preference, so that we can
4748 * stop the search as soon as we find a suitable match.
4749 * This ordering also takes care of wildcards such as '.' (meaning
4750 * "one or more of any character") and '!' (which is 'earlymatch',
4751 * meaning "zero or more of any character" but also impacts the
4752 * return value from CANMATCH and EARLYMATCH.
4753 *
4754 * The extension match rules defined in the devmeeting 2006.05.05 are
4755 * quite simple: WE SELECT THE LONGEST MATCH.
4756 * In detail, "longest" means the number of matched characters in
4757 * the extension. In case of ties (e.g. _XXX and 333) in the length
4758 * of a pattern, we give priority to entries with the smallest cardinality
4759 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4760 * while the latter has 7, etc.
4761 * In case of same cardinality, the first element in the range counts.
4762 * If we still have a tie, any final '!' will make this as a possibly
4763 * less specific pattern.
4764 *
4765 * EBUSY - can't lock
4766 * EEXIST - extension with the same priority exist and no replace is set
4767 *
4768 */
4769static int ast_add_extension2(struct ast_context *con,
4770 int replace, const char *extension, int priority, const char *label, const char *callerid,
4771 const char *application, void *data, void (*datad)(void *),
4772 const char *registrar)
4773{
4774 /*
4775 * Sort extensions (or patterns) according to the rules indicated above.
4776 * These are implemented by the function ext_cmp()).
4777 * All priorities for the same ext/pattern/cid are kept in a list,
4778 * using the 'peer' field as a link field..
4779 */
4780 struct ast_exten *tmp, *e, *el = NULL;
4781 int res;
4782 int length;
4783 char *p;
4784
4785 /* if we are adding a hint, and there are global variables, and the hint
4786 contains variable references, then expand them --- NOT In this situation!!!
4787 */
4788
4789 length = sizeof(struct ast_exten);
4790 length += strlen(extension) + 1;
4791 length += strlen(application) + 1;
4792 if (label)
4793 length += strlen(label) + 1;
4794 if (callerid)
4795 length += strlen(callerid) + 1;
4796 else
4797 length ++; /* just the '\0' */
4798
4799 /* Be optimistic: Build the extension structure first */
4800 if (datad == NULL)
4801 datad = null_datad;
4802 if (!(tmp = ast_calloc(1, length)))
4803 return -1;
4804
4805 /* use p as dst in assignments, as the fields are const char * */
4806 p = tmp->stuff;
4807 if (label) {
4808 tmp->label = p;
4809 strcpy(p, label);
4810 p += strlen(label) + 1;
4811 }
4812 tmp->exten = p;
4813 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
4814 tmp->priority = priority;
4815 tmp->cidmatch = p; /* but use p for assignments below */
4816 if (callerid) {
4817 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
4818 tmp->matchcid = 1;
4819 } else {
4820 *p++ = '\0';
4821 tmp->matchcid = 0;
4822 }
4823 tmp->app = p;
4824 strcpy(p, application);
4825 tmp->parent = con;
4826 tmp->data = data;
4827 tmp->datad = datad;
4828 tmp->registrar = registrar;
4829
4830 res = 0; /* some compilers will think it is uninitialized otherwise */
4831 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
4832 res = ext_cmp(e->exten, extension);
4833 if (res == 0) { /* extension match, now look at cidmatch */
4834 if (!e->matchcid && !tmp->matchcid)
4835 res = 0;
4836 else if (tmp->matchcid && !e->matchcid)
4837 res = 1;
4838 else if (e->matchcid && !tmp->matchcid)
4839 res = -1;
4840 else
4841 res = strcasecmp(e->cidmatch, tmp->cidmatch);
4842 }
4843 if (res >= 0)
4844 break;
4845 }
4846 if (e && res == 0) { /* exact match, insert in the pri chain */
4847 res = add_pri(con, tmp, el, e, replace);
4848 if (res < 0) {
4849 errno = EEXIST; /* XXX do we care ? */
4850 return 0; /* XXX should we return -1 maybe ? */
4851 }
4852 } else {
4853 /*
4854 * not an exact match, this is the first entry with this pattern,
4855 * so insert in the main list right before 'e' (if any)
4856 */
4857 tmp->next = e;
4858 if (el)
4859 el->next = tmp;
4860 else
4861 con->root = tmp;
4862 if (tmp->priority == PRIORITY_HINT)
4863 ast_add_hint(tmp);
4864 }
4865 if (option_debug) {
4866 if (tmp->matchcid) {
4867 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4868 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4869 } else {
4870 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
4871 tmp->exten, tmp->priority, con->name);
4872 }
4873 }
4874 if (option_verbose > 2) {
4875 if (tmp->matchcid) {
4876 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
4877 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4878 } else {
4879 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
4880 tmp->exten, tmp->priority, con->name);
4881 }
4882 }
4883 return 0;
4884}
4885
4887 int replace, const char *extension, int priority, const char *label, const char *callerid,
4888 const char *application, void *data, void (*datad)(void *),
4889 const char *registrar);
4890
4892 int replace, const char *extension, int priority, const char *label, const char *callerid,
4893 const char *application, void *data, void (*datad)(void *),
4894 const char *registrar)
4895{
4896 return ast_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
4897}
4898
4899
4900
4901/*! \brief The return value depends on the action:
4902 *
4903 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
4904 * and return 0 on failure, -1 on match;
4905 * E_FINDLABEL maps the label to a priority, and returns
4906 * the priority on success, ... XXX
4907 * E_SPAWN, spawn an application,
4908 * and return 0 on success, -1 on failure.
4909 */
4910static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
4911 const char *context, const char *exten, int priority,
4912 const char *label, const char *callerid, enum ext_match_t action)
4913{
4914 struct ast_exten *e;
4915 int res;
4916 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
4917
4918 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
4919
4920 e = pbx_find_extension(NULL, con, &q, context, exten, priority, label, callerid, action);
4921 if (e) {
4922 if (matching_action) {
4923 return -1; /* success, we found it */
4924 } else if (action == E_FINDLABEL) { /* map the label to a priority */
4925 res = e->priority;
4926 return res; /* the priority we were looking for */
4927 } else { /* spawn */
4928
4929 /* NOT!!!!! */
4930 return 0;
4931 }
4932 } else if (q.swo) { /* not found here, but in another switch */
4933 if (matching_action)
4934 return -1;
4935 else {
4936 if (!q.swo->exec) {
4937 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
4938 res = -1;
4939 }
4940 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
4941 }
4942 } else { /* not found anywhere, see what happened */
4943 switch (q.status) {
4944 case STATUS_NO_CONTEXT:
4945 if (!matching_action)
4946 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
4947 break;
4949 if (!matching_action)
4950 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
4951 break;
4952 case STATUS_NO_PRIORITY:
4953 if (!matching_action)
4954 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
4955 break;
4956 case STATUS_NO_LABEL:
4957 if (context)
4958 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
4959 break;
4960 default:
4961 if (option_debug)
4962 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
4963 }
4964
4965 return (matching_action) ? 0 : -1;
4966 }
4967}
4968
4969static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid);
4970
4971static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
4972{
4973 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
4974}
4975
4976static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
4977{
4978 return __ast_context_create(extcontexts, name, registrar, 1);
4979}
4980
4981struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar);
4982struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
4983{
4984 return __ast_context_create(extcontexts, name, registrar, 1);
4985}
4986
4987
4988/* chopped this one off at the knees */
4989static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
4990{
4991 ast_log(LOG_ERROR, "Function %s not registered\n", function);
4992 return -1;
4993}
4994
4995/*! \brief extract offset:length from variable name.
4996 * Returns 1 if there is a offset:length part, which is
4997 * trimmed off (values go into variables)
4998 */
4999static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
5000{
5001 int parens=0;
5002
5003 *offset = 0;
5004 *length = INT_MAX;
5005 *isfunc = 0;
5006 for (; *var; var++) {
5007 if (*var == '(') {
5008 (*isfunc)++;
5009 parens++;
5010 } else if (*var == ')') {
5011 parens--;
5012 } else if (*var == ':' && parens == 0) {
5013 *var++ = '\0';
5014 sscanf(var, "%30d:%30d", offset, length);
5015 return 1; /* offset:length valid */
5016 }
5017 }
5018 return 0;
5019}
5020
5021static const char *ast_var_value(const struct ast_var_t *var)
5022{
5023 return (var ? var->value : NULL);
5024}
5025
5026/*! \brief takes a substring. It is ok to call with value == workspace.
5027 *
5028 * offset < 0 means start from the end of the string and set the beginning
5029 * to be that many characters back.
5030 * length is the length of the substring. A value less than 0 means to leave
5031 * that many off the end.
5032 * Always return a copy in workspace.
5033 */
5034static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
5035{
5036 char *ret = workspace;
5037 int lr; /* length of the input string after the copy */
5038
5039 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
5040
5041 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
5042
5043 /* Quick check if no need to do anything */
5044 if (offset == 0 && length >= lr) /* take the whole string */
5045 return ret;
5046
5047 if (offset < 0) { /* translate negative offset into positive ones */
5048 offset = lr + offset;
5049 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
5050 offset = 0;
5051 }
5052
5053 /* too large offset result in empty string so we know what to return */
5054 if (offset >= lr)
5055 return ret + lr; /* the final '\0' */
5056
5057 ret += offset; /* move to the start position */
5058 if (length >= 0 && length < lr - offset) /* truncate if necessary */
5059 ret[length] = '\0';
5060 else if (length < 0) {
5061 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
5062 ret[lr + length - offset] = '\0';
5063 else
5064 ret[0] = '\0';
5065 }
5066
5067 return ret;
5068}
5069
5070/*! \brief Support for Asterisk built-in variables in the dialplan
5071\note See also
5072 - \ref AstVar Channel variables
5073 - \ref AstCauses The HANGUPCAUSE variable
5074 */
5075static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
5076{
5077 const char not_found = '\0';
5078 char *tmpvar;
5079 const char *s; /* the result */
5080 int offset, length;
5081 int i, need_substring;
5082 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
5083
5084 /*
5085 * Make a copy of var because parse_variable_name() modifies the string.
5086 * Then if called directly, we might need to run substring() on the result;
5087 * remember this for later in 'need_substring', 'offset' and 'length'
5088 */
5089 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
5090 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
5091
5092 /*
5093 * Look first into predefined variables, then into variable lists.
5094 * Variable 's' points to the result, according to the following rules:
5095 * s == &not_found (set at the beginning) means that we did not find a
5096 * matching variable and need to look into more places.
5097 * If s != &not_found, s is a valid result string as follows:
5098 * s = NULL if the variable does not have a value;
5099 * you typically do this when looking for an unset predefined variable.
5100 * s = workspace if the result has been assembled there;
5101 * typically done when the result is built e.g. with an snprintf(),
5102 * so we don't need to do an additional copy.
5103 * s != workspace in case we have a string, that needs to be copied
5104 * (the ast_copy_string is done once for all at the end).
5105 * Typically done when the result is already available in some string.
5106 */
5107 s = &not_found; /* default value */
5108 if (s == &not_found) { /* look for more */
5109 if (!strcmp(var, "EPOCH")) {
5110 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
5111 }
5112
5113 s = workspace;
5114 }
5115 /* if not found, look into chanvars or global vars */
5116 for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
5117 struct ast_var_t *variables;
5118 if (!places[i])
5119 continue;
5120 if (places[i] == &globals)
5122 AST_LIST_TRAVERSE(places[i], variables, entries) {
5123 if (strcasecmp(ast_var_name(variables), var)==0) {
5124 s = ast_var_value(variables);
5125 break;
5126 }
5127 }
5128 if (places[i] == &globals)
5130 }
5131 if (s == &not_found || s == NULL)
5132 *ret = NULL;
5133 else {
5134 if (s != workspace)
5135 ast_copy_string(workspace, s, workspacelen);
5136 *ret = workspace;
5137 if (need_substring)
5138 *ret = substring(*ret, offset, length, workspace, workspacelen);
5139 }
5140}
5141
5142static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
5143{
5144 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
5145 zero-filled */
5146 char *cp4;
5147 const char *tmp, *whereweare;
5148 int length, offset, offset2, isfunction;
5149 char *workspace = NULL;
5150 char *ltmp = NULL, *var = NULL;
5151 char *nextvar, *nextexp, *nextthing;
5152 char *vars, *vare;
5153 int pos, brackets, needsub, len;
5154
5155 *cp2 = 0; /* just in case there's nothing to do */
5156 whereweare=tmp=cp1;
5157 while (!ast_strlen_zero(whereweare) && count) {
5158 /* Assume we're copying the whole remaining string */
5159 pos = strlen(whereweare);
5160 nextvar = NULL;
5161 nextexp = NULL;
5162 nextthing = (char *)strchr(whereweare, '$');
5163 if (nextthing) {
5164 switch (nextthing[1]) {
5165 case '{':
5166 nextvar = nextthing;
5167 pos = nextvar - whereweare;
5168 break;
5169 case '[':
5170 nextexp = nextthing;
5171 pos = nextexp - whereweare;
5172 break;
5173 }
5174 }
5175
5176 if (pos) {
5177 /* Can't copy more than 'count' bytes */
5178 if (pos > count)
5179 pos = count;
5180
5181 /* Copy that many bytes */
5182 memcpy(cp2, whereweare, pos);
5183
5184 count -= pos;
5185 cp2 += pos;
5186 whereweare += pos;
5187 *cp2 = 0;
5188 }
5189
5190 if (nextvar) {
5191 /* We have a variable. Find the start and end, and determine
5192 if we are going to have to recursively call ourselves on the
5193 contents */
5194 vars = vare = nextvar + 2;
5195 brackets = 1;
5196 needsub = 0;
5197
5198 /* Find the end of it */
5199 while (brackets && *vare) {
5200 if ((vare[0] == '$') && (vare[1] == '{')) {
5201 needsub++;
5202 } else if (vare[0] == '{') {
5203 brackets++;
5204 } else if (vare[0] == '}') {
5205 brackets--;
5206 } else if ((vare[0] == '$') && (vare[1] == '['))
5207 needsub++;
5208 vare++;
5209 }
5210 if (brackets)
5211 ast_log(LOG_NOTICE, "Error in extension logic (missing '}' in '%s')\n", cp1);
5212 len = vare - vars - 1;
5213
5214 /* Skip totally over variable string */
5215 whereweare += (len + 3);
5216
5217 if (!var)
5218 var = alloca(VAR_BUF_SIZE);
5219
5220 /* Store variable name (and truncate) */
5221 ast_copy_string(var, vars, len + 1);
5222
5223 /* Substitute if necessary */
5224 if (needsub) {
5225 if (!ltmp)
5226 ltmp = alloca(VAR_BUF_SIZE);
5227
5228 memset(ltmp, 0, VAR_BUF_SIZE);
5230 vars = ltmp;
5231 } else {
5232 vars = var;
5233 }
5234
5235 if (!workspace)
5236 workspace = alloca(VAR_BUF_SIZE);
5237
5238 workspace[0] = '\0';
5239
5240 parse_variable_name(vars, &offset, &offset2, &isfunction);
5241 if (isfunction) {
5242 /* Evaluate function */
5243 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
5244 if (option_debug)
5245 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
5246 } else {
5247 /* Retrieve variable value */
5248 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
5249 }
5250 if (cp4) {
5251 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
5252
5253 length = strlen(cp4);
5254 if (length > count)
5255 length = count;
5256 memcpy(cp2, cp4, length);
5257 count -= length;
5258 cp2 += length;
5259 *cp2 = 0;
5260 }
5261 } else if (nextexp) {
5262 /* We have an expression. Find the start and end, and determine
5263 if we are going to have to recursively call ourselves on the
5264 contents */
5265 vars = vare = nextexp + 2;
5266 brackets = 1;
5267 needsub = 0;
5268
5269 /* Find the end of it */
5270 while (brackets && *vare) {
5271 if ((vare[0] == '$') && (vare[1] == '[')) {
5272 needsub++;
5273 brackets++;
5274 vare++;
5275 } else if (vare[0] == '[') {
5276 brackets++;
5277 } else if (vare[0] == ']') {
5278 brackets--;
5279 } else if ((vare[0] == '$') && (vare[1] == '{')) {
5280 needsub++;
5281 vare++;
5282 }
5283 vare++;
5284 }
5285 if (brackets)
5286 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
5287 len = vare - vars - 1;
5288
5289 /* Skip totally over expression */
5290 whereweare += (len + 3);
5291
5292 if (!var)
5293 var = alloca(VAR_BUF_SIZE);
5294
5295 /* Store variable name (and truncate) */
5296 ast_copy_string(var, vars, len + 1);
5297
5298 /* Substitute if necessary */
5299 if (needsub) {
5300 if (!ltmp)
5301 ltmp = alloca(VAR_BUF_SIZE);
5302
5303 memset(ltmp, 0, VAR_BUF_SIZE);
5305 vars = ltmp;
5306 } else {
5307 vars = var;
5308 }
5309
5310 length = ast_expr(vars, cp2, count, NULL);
5311
5312 if (length) {
5313 if (option_debug)
5314 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
5315 count -= length;
5316 cp2 += length;
5317 *cp2 = 0;
5318 }
5319 } else
5320 break;
5321 }
5322}
5323
5324static void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
5325{
5326 pbx_substitute_variables_helper_full(c, NULL, cp1, cp2, count);
5327}
5328
5329
5330static int pbx_load_config(const char *config_file);
5331
5332static int pbx_load_config(const char *config_file)
5333{
5334 struct ast_config *cfg;
5335 char *end;
5336 char *label;
5337 char realvalue[256];
5338 int lastpri = -2;
5339 struct ast_context *con;
5340 struct ast_variable *v;
5341 const char *cxt;
5342 const char *aft;
5343
5345 if (!cfg)
5346 return 0;
5347
5348 /* Use existing config to populate the PBX table */
5349 static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
5350 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
5351 if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
5353 clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
5354
5355 if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
5357 else
5358 ast_copy_string(userscontext, "default", sizeof(userscontext));
5359
5360 for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
5361 memset(realvalue, 0, sizeof(realvalue));
5362 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5363 pbx_builtin_setvar_helper(NULL, v->name, realvalue);
5364 }
5365 for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
5366 /* All categories but "general" or "globals" are considered contexts */
5367 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
5368 continue;
5370 if (con == NULL)
5371 continue;
5372
5373 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
5374 if (!strcasecmp(v->name, "exten")) {
5375 char *tc = ast_strdup(v->value);
5376 if (tc) {
5377 int ipri = -2;
5378 char realext[256]="";
5379 char *plus, *firstp, *firstc;
5380 char *pri, *appl, *data, *cidmatch;
5381 char *stringp = tc;
5382 char *ext = strsep(&stringp, ",");
5383 if (!ext)
5384 ext="";
5385 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
5386 cidmatch = strchr(realext, '/');
5387 if (cidmatch) {
5388 *cidmatch++ = '\0';
5389 ast_shrink_phone_number(cidmatch);
5390 }
5391 pri = strsep(&stringp, ",");
5392 if (!pri)
5393 pri="";
5394 label = strchr(pri, '(');
5395 if (label) {
5396 *label++ = '\0';
5397 end = strchr(label, ')');
5398 if (end)
5399 *end = '\0';
5400 else
5401 ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
5402 }
5403 plus = strchr(pri, '+');
5404 if (plus)
5405 *plus++ = '\0';
5406 if (!strcmp(pri,"hint"))
5407 ipri=PRIORITY_HINT;
5408 else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
5409 if (lastpri > -2)
5410 ipri = lastpri + 1;
5411 else
5412 ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
5413 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
5414 if (lastpri > -2)
5415 ipri = lastpri;
5416 else
5417 ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
5418 } else if (sscanf(pri, "%30d", &ipri) != 1 &&
5419 (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
5420 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
5421 ipri = 0;
5422 }
5423 appl = S_OR(stringp, "");
5424 /* Find the first occurrence of either '(' or ',' */
5425 firstc = strchr(appl, ',');
5426 firstp = strchr(appl, '(');
5427 if (firstc && (!firstp || firstc < firstp)) {
5428 /* comma found, no parenthesis */
5429 /* or both found, but comma found first */
5430 appl = strsep(&stringp, ",");
5431 data = stringp;
5432 } else if (!firstc && !firstp) {
5433 /* Neither found */
5434 data = "";
5435 } else {
5436 /* Final remaining case is parenthesis found first */
5437 appl = strsep(&stringp, "(");
5438 data = stringp;
5439 end = strrchr(data, ')');
5440 if ((end = strrchr(data, ')'))) {
5441 *end = '\0';
5442 } else {
5443 ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
5444 }
5445 ast_process_quotes_and_slashes(data, ',', '|');
5446 }
5447
5448 if (!data)
5449 data="";
5450 appl = ast_skip_blanks(appl);
5451 if (ipri) {
5452 if (plus)
5453 ipri += atoi(plus);
5454 lastpri = ipri;
5455 if (!ast_opt_dont_warn && !strcmp(realext, "_."))
5456 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);
5457 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, global_registrar)) {
5458 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
5459 }
5460 }
5461 free(tc);
5462 }
5463 } else if (!strcasecmp(v->name, "include")) {
5464 memset(realvalue, 0, sizeof(realvalue));
5465 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5466 if (ast_context_add_include2(con, realvalue, global_registrar))
5467 ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
5468 } else if (!strcasecmp(v->name, "ignorepat")) {
5469 memset(realvalue, 0, sizeof(realvalue));
5470 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5471 if (ast_context_add_ignorepat2(con, realvalue, global_registrar))
5472 ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
5473 } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
5474 char *stringp= realvalue;
5475 char *appl, *data;
5476
5477 memset(realvalue, 0, sizeof(realvalue));
5478 if (!strcasecmp(v->name, "switch"))
5479 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5480 else
5481 ast_copy_string(realvalue, v->value, sizeof(realvalue));
5482 appl = strsep(&stringp, "/");
5483 data = strsep(&stringp, ""); /* XXX what for ? */
5484 if (!data)
5485 data = "";
5486 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), global_registrar))
5487 ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
5488 } else {
5489 ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
5490 }
5491 }
5492 }
5493 ast_config_destroy(cfg);
5494 return 1;
5495}
5496
5497static void __ast_context_destroy(struct ast_context *con, const char *registrar)
5498{
5499 struct ast_context *tmp, *tmpl=NULL;
5500 struct ast_include *tmpi;
5501 struct ast_sw *sw;
5502 struct ast_exten *e, *el, *en;
5503 struct ast_ignorepat *ipi;
5504
5505 for (tmp = contexts; tmp; ) {
5506 struct ast_context *next; /* next starting point */
5507 for (; tmp; tmpl = tmp, tmp = tmp->next) {
5508 if (option_debug)
5509 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
5510 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
5511 (!con || !strcasecmp(tmp->name, con->name)) )
5512 break; /* found it */
5513 }
5514 if (!tmp) /* not found, we are done */
5515 break;
5516 ast_wrlock_context(tmp);
5517 if (option_debug)
5518 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
5519 next = tmp->next;
5520 if (tmpl)
5521 tmpl->next = next;
5522 else
5523 contexts = next;
5524 /* Okay, now we're safe to let it go -- in a sense, we were
5525 ready to let it go as soon as we locked it. */
5526 ast_unlock_context(tmp);
5527 for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
5528 struct ast_include *tmpil = tmpi;
5529 tmpi = tmpi->next;
5530 free(tmpil);
5531 }
5532 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
5533 struct ast_ignorepat *ipl = ipi;
5534 ipi = ipi->next;
5535 free(ipl);
5536 }
5537 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
5538 free(sw);
5539 for (e = tmp->root; e;) {
5540 for (en = e->peer; en;) {
5541 el = en;
5542 en = en->peer;
5544 }
5545 el = e;
5546 e = e->next;
5548 }
5549 ast_rwlock_destroy(&tmp->lock);
5550 free(tmp);
5551 /* if we have a specific match, we are done, otherwise continue */
5552 tmp = con ? NULL : next;
5553 }
5554}
5555
5556void localized_context_destroy(struct ast_context *con, const char *registrar);
5557
5564
5565
5566static void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
5567{
5568 struct ast_context *tmp, *lasttmp = NULL;
5569
5570 /* it is very important that this function hold the hint list lock _and_ the conlock
5571 during its operation; not only do we need to ensure that the list of contexts
5572 and extensions does not change, but also that no hint callbacks (watchers) are
5573 added or removed during the merge/delete process
5574
5575 in addition, the locks _must_ be taken in this order, because there are already
5576 other code paths that use this order
5577 */
5579
5580 tmp = *extcontexts;
5581 if (registrar) {
5582 /* XXX remove previous contexts from same registrar */
5583 if (option_debug)
5584 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
5586 while (tmp) {
5587 lasttmp = tmp;
5588 tmp = tmp->next;
5589 }
5590 } else {
5591 /* XXX remove contexts with the same name */
5592 while (tmp) {
5593 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
5595 lasttmp = tmp;
5596 tmp = tmp->next;
5597 }
5598 }
5599 if (lasttmp) {
5600 lasttmp->next = contexts;
5601 contexts = *extcontexts;
5602 *extcontexts = NULL;
5603 } else
5604 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
5605
5607
5608 return;
5609}
5610
5611void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
5612{
5614}
5615
5617{
5618 struct ast_include *inc = NULL;
5619 int res = 0;
5620
5621 while ( (inc = ast_walk_context_includes(con, inc)) )
5622 if (!ast_context_find(inc->rname)) {
5623 res = -1;
5624 if (strcasecmp(inc->rname,"parkedcalls")!=0)
5625 ast_log(LOG_WARNING, "Context '%s' tries to include the nonexistent context '%s'\n",
5626 ast_get_context_name(con), inc->rname);
5627 }
5628 return res;
5629}
5630
5632
5637
5639
5641{
5642 struct ast_context *con;
5643
5645 return -1 /* AST_MODULE_LOAD_DECLINE*/;
5646
5647 /* pbx_load_users(); */ /* does this affect the dialplan? */
5648
5650
5651 for (con = NULL; (con = ast_walk_contexts(con));)
5653
5654 printf("=== Loading extensions.conf ===\n");
5655 con = 0;
5656 while ((con = ast_walk_contexts(con)) ) {
5657 printf("Context: %s\n", con->name);
5658 }
5659 printf("=========\n");
5660
5661 return 0;
5662}
5663
5664/* For platforms which don't have pthread_rwlock_timedrdlock() */
5665struct timeval ast_tvnow(void);
5666
5667struct timeval ast_tvnow(void)
5668{
5669 struct timeval t;
5670 gettimeofday(&t, NULL);
5671 return t;
5672}
#define paren
Definition ael_lex.c:962
#define comment
Definition ael_lex.c:965
void ast_context_verify_includes(void)
Definition ael_main.c:395
void ast_merge_contexts_and_delete(void)
Definition ael_main.c:389
struct ast_context * ast_walk_contexts(void)
Definition ael_main.c:401
Structures for AEL - the Asterisk extension language.
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
enum queue_result id
Definition app_queue.c:1790
pthread_t thread
Definition app_sla.c:335
#define var
Definition ast_expr2f.c:605
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
General Definitions for Asterisk top level program Included by asterisk.h to handle platform-specific...
char * strsep(char **str, const char *delims)
static EditLine * el
Definition asterisk.c:348
Asterisk main include file. File version handling, generic pbx functions.
int64_t ast_mark(int, int start1_stop0)
Definition astman.c:103
#define ast_realloc(p, len)
A wrapper for realloc()
Definition astmm.h:226
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define HAVE_GCC_ATOMICS
Definition autoconfig.h:313
#define SIZEOF_INT
static int priority
static const char config_file[]
Definition cdr_odbc.c:54
static PGresult * result
Definition cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition chan_iax2.c:2401
static const char config[]
#define ast_channel_lock(chan)
Definition channel.h:2983
#define ast_channel_trylock(chan)
Definition channel.h:2985
#define ast_channel_unlock(chan)
Definition channel.h:2984
size_t current
#define ast_var_assign(name, value)
Definition chanvars.h:40
#define force_inline
Definition compiler.h:29
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
Asterisk architecture endianess compatibility definitions.
#define AST_RWLIST_REMOVE_CURRENT
Definition extconf.c:1842
static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
Definition extconf.c:4989
int ast_build_timing(struct ast_timing *i, const char *info_in)
Construct a timing bitmap, for use in time-based conditionals.
Definition extconf.c:3802
static int lookup_name(const char *s, char *const names[], int max)
Helper for get_range. return the index of the matching entry, starting from 1. If names is not suppli...
Definition extconf.c:2611
struct ast_config * realtime_multi_get(const char *database, const char *table, va_list ap)
Definition extconf.c:933
static int ast_true(const char *s)
Definition extconf.c:2240
int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition extconf.c:4595
char record_cache_dir[AST_CACHE_DIR_LEN]
Definition options.c:97
static void CB_RESET(void)
Definition extconf.c:775
static char * lline_buffer
Definition extconf.c:706
static struct ast_sw * ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw)
Definition extconf.c:4135
char * days[]
Definition extconf.c:3771
int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap)
Definition extconf.c:934
void ast_mark_lock_failed(void *lock_addr)
Definition extconf.c:2309
#define MAX_NESTED_COMMENTS
Definition extconf.c:694
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition extconf.c:1505
int localized_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Definition extconf.c:4553
static int ext_cmp(const char *a, const char *b)
the full routine to compare extensions in rules.
Definition extconf.c:3940
static int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
Definition extconf.c:4635
static void ast_includes_destroy(struct ast_config_include *incls)
Definition extconf.c:1271
int ast_check_timing(const struct ast_timing *i)
Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified.
Definition extconf.c:3996
struct ast_sw * localized_walk_context_switches(struct ast_context *con, struct ast_sw *sw)
Definition extconf.c:4146
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)
Definition extconf.c:2902
int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
Definition extconf.c:2601
struct ast_context * localized_walk_contexts(struct ast_context *con)
Definition extconf.c:4026
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition extconf.c:1819
#define VERBOSE_PREFIX_3
Definition extconf.c:102
static char * substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
takes a substring. It is ok to call with value == workspace.
Definition extconf.c:5034
static int ast_wrlock_context(struct ast_context *con)
Definition extconf.c:4615
#define pthread_cond_t
Definition extconf.c:502
struct ast_include * localized_walk_context_includes(struct ast_context *con, struct ast_include *inc)
Definition extconf.c:4100
struct ast_exten * localized_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
Definition extconf.c:4047
pthread_mutex_t ast_mutex_t
Definition extconf.c:465
static struct ast_context * ast_context_find(const char *name)
Definition extconf.c:4168
static int autofallthrough_config
Definition extconf.c:2121
#define S_OR(a, b)
Definition extconf.c:955
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition extconf.c:1769
static unsigned int safe_system_level
Keep track of how many threads are currently trying to wait*() on a child process.
Definition extconf.c:783
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)
Definition extconf.c:3115
static const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Definition extconf.c:1225
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition extconf.c:1613
static struct ast_config * ast_config_new(void)
Definition extconf.c:3270
static ast_rwlock_t globalslock
Definition extconf.c:2063
struct ast_exten * localized_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition extconf.c:4065
static int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Main interface to add extensions to the list for out context.
Definition extconf.c:4769
static struct ast_ignorepat * ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip)
Definition extconf.c:4109
static int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Definition extconf.c:4497
static struct ast_context * __ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
Definition extconf.c:4702
static void inherit_category(struct ast_category *new, const struct ast_category *base)
Definition extconf.c:2819
static int ast_wrlock_contexts(void)
Definition extconf.c:4605
int(* ast_state_cb_type)(char *context, char *id, enum ast_extension_states state, void *data)
Definition extconf.c:2349
static const char * ast_get_extension_app(struct ast_exten *e)
Definition extconf.c:3608
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition extconf.c:1972
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)
Definition extconf.c:931
static struct ast_config * ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file)
Definition extconf.c:2858
static void ast_category_append(struct ast_config *config, struct ast_category *category)
Definition extconf.c:2829
#define STATUS_NO_LABEL
Definition extconf.c:2447
#define CB_INCR
Definition extconf.c:709
#define COMMENT_TAG
Definition extconf.c:698
#define ast_opt_dont_warn
Definition extconf.c:1382
#define STATUS_NO_EXTENSION
Definition extconf.c:2445
static int ext_strncpy(char *dst, const char *src, int len)
copy a string skipping whitespace
Definition extconf.c:3967
#define VERBOSE_PREFIX_2
Definition extconf.c:101
static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition extconf.c:1175
static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
The return value depends on the action:
Definition extconf.c:4910
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition extconf.c:1532
static struct sigaction safe_system_prev_handler
Definition extconf.c:784
static int ext_cmp1(const char **p)
helper functions to sort extensions and patterns in the desired way, so that more specific patterns a...
Definition extconf.c:3868
static struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
Definition extconf.c:4036
static void __ast_context_destroy(struct ast_context *con, const char *registrar)
Definition extconf.c:5497
static char * ast_process_quotes_and_slashes(char *start, char find, char replace_with)
Definition extconf.c:2214
static struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Definition extconf.c:1213
static struct ast_category * category_get(const struct ast_config *config, const char *category_name, int ignored)
Definition extconf.c:1190
int localized_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
Definition extconf.c:4696
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)
Definition extconf.c:1072
#define AST_CACHE_DIR_LEN
Definition extconf.c:1356
static int use_local_dir
Definition extconf.c:3099
static struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Definition extconf.c:2784
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition extconf.c:1690
int ast_context_switches_count(struct ast_context *con)
Definition extconf.c:4153
static int include_valid(struct ast_include *i)
Definition extconf.c:4307
static char * ast_category_browse(struct ast_config *config, const char *prev)
Definition extconf.c:3322
char debug_filename[AST_FILENAME_MAX]
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition extconf.c:1872
static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
Definition extconf.c:2564
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
Definition extconf.c:799
static struct ast_config_engine * config_engine_list
Definition extconf.c:891
#define LOG_DEBUG
Definition extconf.c:121
static struct ast_context * local_contexts
Definition extconf.c:3592
static struct ast_category * next_available_category(struct ast_category *cat)
Definition extconf.c:3315
static const char * ast_var_name(const struct ast_var_t *var)
Definition extconf.c:2166
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition extconf.c:568
static void get_timerange(struct ast_timing *i, char *times)
store a bitmask of valid times, one bit each 2 minute
Definition extconf.c:2678
static int lline_buffer_size
Definition extconf.c:707
uint64_t __unsigned_int_flags_dummy64
static void _null_sig_handler(int sig)
NULL handler so we can collect the child exit status.
Definition extconf.c:787
static unsigned get_range(char *src, int max, char *const names[], const char *msg)
helper function to return a range up to max (7, 12, 31 respectively). names, if supplied,...
Definition extconf.c:2634
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
Set the category within the configuration as being current.
Definition extconf.c:3358
static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Definition extconf.c:2524
static void CB_INIT(void)
Definition extconf.c:716
@ AST_EXTENSION_REMOVED
Definition extconf.c:2081
@ AST_EXTENSION_RINGING
Definition extconf.c:2087
@ AST_EXTENSION_NOT_INUSE
Definition extconf.c:2083
@ AST_EXTENSION_INUSE
Definition extconf.c:2084
@ AST_EXTENSION_UNAVAILABLE
Definition extconf.c:2086
@ AST_EXTENSION_ONHOLD
Definition extconf.c:2088
@ AST_EXTENSION_BUSY
Definition extconf.c:2085
@ AST_EXTENSION_DEACTIVATED
Definition extconf.c:2082
void ast_console_puts(const char *string)
write the string to the root console, and all attached network console clients
Definition asterisk.c:1368
static int ast_extension_match(const char *pattern, const char *data)
Definition extconf.c:4291
int localized_context_verify_includes(struct ast_context *con)
Definition extconf.c:5633
struct ast_config * localized_config_load_with_comments(const char *filename)
Definition extconf.c:3299
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Definition extconf.c:2777
static void move_variables(struct ast_category *old, struct ast_category *new)
Definition extconf.c:2802
static struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition extconf.c:4057
static const char * ast_var_value(const struct ast_var_t *var)
Definition extconf.c:5021
void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
Definition extconf.c:5611
static void CB_ADD(char *str)
Definition extconf.c:735
static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
Definition extconf.c:3384
static int clearglobalvars_config
Definition extconf.c:2122
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition extconf.c:593
static const char * ast_get_context_name(struct ast_context *con)
Definition extconf.c:4482
void localized_context_destroy(struct ast_context *con, const char *registrar)
Definition extconf.c:5558
static int add_pri(struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace)
add the extension in the priority chain. returns 0 on success, -1 on failure
Definition extconf.c:3671
#define pthread_mutex_t
Definition extconf.c:500
void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
Definition extconf.c:1108
static int ast_remove_hint(struct ast_exten *e)
ast_remove_hint: Remove hint from extension
Definition extconf.c:3729
static char * comment_buffer
Definition extconf.c:703
#define AST_RWLIST_TRAVERSE
Definition extconf.c:1772
static void ast_category_destroy(struct ast_category *cat)
Definition extconf.c:2841
static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Support for Asterisk built-in variables in the dialplan.
Definition extconf.c:5075
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition extconf.c:2278
int localized_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Definition extconf.c:4891
char * months[]
Definition extconf.c:3783
static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
Definition extconf.c:5142
static void ast_config_destroy(struct ast_config *cfg)
Definition extconf.c:1287
#define PTHREAD_MUTEX_INIT_VALUE
Definition extconf.c:193
static const char * ast_get_extension_name(struct ast_exten *exten)
Definition extconf.c:3613
struct ast_exten * localized_find_extension(struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition extconf.c:4464
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition logger.c:973
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
static struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
Definition extconf.c:4976
static ast_rwlock_t conlock
Definition extconf.c:4478
int ast_context_ignorepats_count(struct ast_context *con)
Definition extconf.c:4119
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition extconf.c:2293
static struct ast_comment * ALLOC_COMMENT(const char *buffer)
Definition extconf.c:875
int() ast_switch_f(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
Definition extconf.c:2101
static struct ast_config_engine * find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
Find realtime engine for realtime family.
Definition extconf.c:2743
#define STATUS_NO_CONTEXT
Definition extconf.c:2444
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition extconf.c:1952
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition extconf.c:2033
static int matchcid(const char *cidpattern, const char *callerid)
Definition extconf.c:4296
static struct ast_variable * variable_clone(const struct ast_variable *old)
Definition extconf.c:1246
static struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name)
Definition extconf.c:1208
static struct ast_context * contexts
Definition extconf.c:3593
#define AST_MUTEX_KIND
Definition extconf.c:194
static struct ast_config_map * config_maps
#define AST_RWLIST_INSERT_HEAD
Definition extconf.c:1959
static int static_config
Definition extconf.c:2119
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition extconf.c:4187
static char userscontext[AST_MAX_EXTENSION]
Definition extconf.c:2118
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition extconf.c:2012
int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
Definition extconf.c:3417
void localized_use_conf_dir(void)
Definition extconf.c:3109
static struct ast_config_include * ast_include_find(struct ast_config *conf, const char *included_file)
Definition extconf.c:1161
#define COMMENT_META
Definition extconf.c:697
#define MAX_INCLUDE_LEVEL
Definition extconf.c:893
static int ast_unlock_contexts(void)
Definition extconf.c:4610
pthread_cond_t ast_cond_t
Definition extconf.c:481
struct ast_variable * realtime_var_get(const char *database, const char *table, va_list ap)
Definition extconf.c:932
static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
Definition extconf.c:3402
int localized_pbx_load_module(void)
Definition extconf.c:5640
int ast_context_includes_count(struct ast_context *con)
Definition extconf.c:4086
#define STATUS_NO_PRIORITY
Definition extconf.c:2446
static int pbx_load_config(const char *config_file)
Definition extconf.c:5332
static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition extconf.c:4563
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition extconf.c:1002
static int ast_unlock_context(struct ast_context *con)
Definition extconf.c:4620
struct ast_config * localized_config_load(const char *filename)
Definition extconf.c:3281
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
extract offset:length from variable name. Returns 1 if there is a offset:length part,...
Definition extconf.c:4999
static char * global_registrar
Definition extconf.c:2117
void ast_copy_string(char *dst, const char *src, size_t size)
Definition extconf.c:968
void localized_use_local_dir(void)
Definition extconf.c:3104
#define AST_RWLIST_ENTRY
Definition extconf.c:1695
static int comment_buffer_size
Definition extconf.c:704
static void ast_variables_destroy(struct ast_variable *v)
Definition extconf.c:1260
static void ast_shrink_phone_number(char *n)
Clean up phone string remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets....
Definition extconf.c:2132
static struct ast_include * ast_walk_context_includes(struct ast_context *con, struct ast_include *inc)
Definition extconf.c:4076
#define AST_DEFAULT_OPTIONS
Definition extconf.c:1360
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition extconf.c:1021
static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
Definition extconf.c:4971
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0. Useful e.g. to check if a refcount h...
Definition extconf.c:634
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition extconf.c:1453
#define LOG_ERROR
Definition extconf.c:145
static void CB_ADD_LEN(char *str, int len)
Definition extconf.c:748
#define PRIORITY_HINT
Definition extconf.c:2078
static void null_datad(void *foo)
Definition extconf.c:2738
struct timeval ast_tvnow(void)
Definition extconf.c:5667
#define pthread_mutex_init
Definition extconf.c:501
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
Definition extconf.c:813
static char * extconfig_conf
Definition extconf.c:700
#define LOG_NOTICE
Definition extconf.c:133
static int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
Definition extconf.c:2474
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition extconf.c:1701
#define LOG_WARNING
Definition extconf.c:139
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
ast_change_hint: Change hint for an extension
Definition extconf.c:3621
static struct timeval tvfix(struct timeval a)
Definition extconf.c:2262
static struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition extconf.c:4328
pid_t ast_mainpid
Definition asterisk.c:323
#define VAR_BUF_SIZE
Definition extconf.c:2315
static void ast_var_delete(struct ast_var_t *var)
Definition extconf.c:2467
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition extconf.c:1719
static void destroy_exten(struct ast_exten *e)
Definition extconf.c:3761
static int ast_add_hint(struct ast_exten *e)
ast_add_hint: Add hint to hint list, check initial extension state
Definition extconf.c:3638
struct ast_context * localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
Definition extconf.c:4982
static char * config_filename
Definition extconf.c:2116
struct ast_category * localized_category_get(const struct ast_config *config, const char *category_name)
Definition extconf.c:2797
#define STATUS_SUCCESS
Definition extconf.c:2448
static force_inline int ast_strlen_zero(const char *s)
Definition extconf.c:950
static struct varshead globals
Definition extconf.c:2064
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition extconf.c:4282
@ AST_OPT_FLAG_HIGH_PRIORITY
Definition extconf.c:1316
@ AST_OPT_FLAG_TRANSCODE_VIA_SLIN
Definition extconf.c:1328
@ AST_OPT_FLAG_EXEC_INCLUDES
Definition extconf.c:1308
@ AST_OPT_FLAG_NO_COLOR
Definition extconf.c:1324
@ AST_OPT_FLAG_NO_FORK
Definition extconf.c:1310
@ AST_OPT_FLAG_DEBUG_FILE
Definition extconf.c:1348
@ AST_OPT_FLAG_TRANSMIT_SILENCE
Definition extconf.c:1340
@ AST_OPT_FLAG_ALWAYS_FORK
Definition extconf.c:1344
@ AST_OPT_FLAG_QUIET
Definition extconf.c:1312
@ AST_OPT_FLAG_MUTE
Definition extconf.c:1346
@ AST_OPT_FLAG_OVERRIDE_CONFIG
Definition extconf.c:1336
@ AST_OPT_FLAG_TIMESTAMP
Definition extconf.c:1334
@ AST_OPT_FLAG_EXEC
Definition extconf.c:1322
@ AST_OPT_FLAG_CACHE_RECORD_FILES
Definition extconf.c:1332
@ AST_OPT_FLAG_FULLY_BOOTED
Definition extconf.c:1326
@ AST_OPT_FLAG_INIT_KEYS
Definition extconf.c:1318
@ AST_OPT_FLAG_CONSOLE
Definition extconf.c:1314
@ AST_OPT_FLAG_DONT_WARN
Definition extconf.c:1342
@ AST_OPT_FLAG_FORCE_BLACK_BACKGROUND
Definition extconf.c:1352
@ AST_OPT_FLAG_LIGHT_BACKGROUND
Definition extconf.c:1350
@ AST_OPT_FLAG_REMOTE
Definition extconf.c:1320
@ AST_OPT_FLAG_DUMP_CORE
Definition extconf.c:1330
@ AST_OPT_FLAG_RECONNECT
Definition extconf.c:1338
#define AST_FILENAME_MAX
Definition extconf.c:1357
#define AST_MAX_EXTENSION
Definition extconf.c:2074
char * ast_skip_blanks(const char *str)
Definition extconf.c:977
static void LLB_ADD(char *str)
Definition extconf.c:762
static struct sigaction null_sig_handler
Definition extconf.c:792
static void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition extconf.c:5324
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
Definition logger.c:2577
pthread_rwlock_t ast_rwlock_t
Definition extconf.c:514
static int write_protect_config
Definition extconf.c:2120
#define ast_opt_exec_includes
Definition extconf.c:1364
static struct ast_config_engine text_file_engine
Definition extconf.c:2850
#define SWITCH_DATA_LENGTH
Definition extconf.c:3606
char ast_defaultlanguage[]
Definition options.c:99
External configuration handlers (realtime and static configuration)
#define AST_PBX_MAX_STACK
Definition extconf.h:225
ext_match_t
Definition extconf.h:214
@ E_MATCH_MASK
Definition extconf.h:218
@ E_MATCH
Definition extconf.h:217
@ E_CANMATCH
Definition extconf.h:216
@ E_FINDLABEL
Definition extconf.h:220
@ E_MATCHMORE
Definition extconf.h:215
static const char registrar[]
The static registrar for the added dialplan hints.
#define max(a, b)
Definition f2c.h:198
static const char name[]
Definition format_mp3.c:68
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
static int array(struct ast_channel *chan, const char *cmd, char *var, const char *value)
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int option_debug
Definition options.c:70
int ast_option_maxcalls
Definition options.c:80
struct ast_flags ast_options
Definition extconf.c:1362
double ast_option_maxload
Definition options.c:78
int option_verbose
Definition options.c:68
ast_option_flags
Definition options.h:39
void free()
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
const char * ext
Definition http.c:151
#define ast_app_separate_args(a, b, c, d)
#define ast_variable_new(name, value, filename)
#define LOG_WARNING
#define ast_verbose(...)
Inlinable API function macro.
#define AST_INLINE_API(hdr, body)
Definition inline_api.h:54
#define ast_rwlock_wrlock(a)
Definition lock.h:243
#define AST_MAX_REENTRANCY
Definition lock.h:108
#define pthread_mutex_trylock
Definition lock.h:634
#define pthread_mutex_lock
Definition lock.h:632
#define ast_rwlock_rdlock(a)
Definition lock.h:242
#define ast_mutex_init(pmutex)
Definition lock.h:193
#define pthread_mutex_t
Definition lock.h:629
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition lock.h:231
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:255
int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:145
#define ast_rwlock_destroy(rwlock)
Definition lock.h:240
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:398
#define pthread_mutex_unlock
Definition lock.h:633
#define pthread_mutex_destroy
Definition lock.h:636
#define ast_rwlock_unlock(a)
Definition lock.h:241
int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:177
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:453
#define WEXITSTATUS(status)
#define WIFEXITED(status)
int errno
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_CONFIG_DIR
Definition options.c:152
ast_extension_states
Extension states.
Definition pbx.h:61
struct ast_switch * pbx_findswitch(const char *sw)
Definition pbx_switch.c:40
#define NULL
Definition resample.c:96
ast_app: A registered application
Definition pbx_app.c:45
struct ast_module *char name[0]
Definition pbx_app.c:60
const char * description
Definition extconf.c:2405
struct ast_app::@554 list
int(* execute)(struct ast_channel *chan, const char *data)
Definition pbx_app.c:46
const char * synopsis
Definition extconf.c:2404
struct ast_comment * precomments
char name[80]
struct ast_category * next
struct ast_variable * last
struct ast_variable * root
struct ast_comment * sameline
struct ast_category * prev
char * file
The file name from whence this declaration was read.
Main Channel structure associated with a channel.
char exten[AST_MAX_EXTENSION]
const char * data
char context[AST_MAX_CONTEXT]
Structure to keep comments for rewriting configuration files.
Definition main/config.c:85
char cmt[0]
Definition main/config.c:88
struct ast_comment * next
Definition main/config.c:86
Configuration engine structure, used to define realtime drivers.
realtime_var_get * realtime_func
struct ast_config_engine * next
realtime_multi_get * realtime_multi_func
config_load_func * load_func
realtime_update * update_func
char * include_location_file
file name in which the include occurs
char * exec_file
if it's an exec, you'll have both the /var/tmp to read, and the original script
char * included_file
file name included
struct ast_config_include * next
const char * driver
char * driver
Definition extconf.c:885
struct ast_config_map * next
const char * table
const char * database
char * name
Definition extconf.c:884
char * database
Definition extconf.c:886
const char * name
char * table
Definition extconf.c:887
struct ast_category * current
int include_level
int max_include_level
struct ast_config_include * includes
Definition extconf.c:916
struct ast_category * last
struct ast_category * root
struct ast_category * last_browse
ast_context: An extension context
Definition pbx.c:254
struct ast_sws alts
Definition pbx.c:265
struct ast_exten * root
Definition pbx.c:259
struct ast_context::@553 alts
struct ast_ignorepats ignorepats
Definition pbx.c:264
struct ast_includes includes
Definition pbx.c:263
const char * registrar
Definition pbx.c:256
char data[]
Definition pbx.c:275
struct ast_context * next
Definition pbx.c:262
struct ast_include * includes
Definition extconf.c:2393
ast_rwlock_t lock
Definition pbx.c:258
struct ast_ignorepat * ignorepats
Definition extconf.c:2394
const char * name
Definition pbx.c:255
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * syntax
Definition extconf.c:2095
ast_acf_write_fn_t write
Definition pbx.h:141
ast_acf_read_fn_t read
Definition pbx.h:129
const char * desc
Definition extconf.c:2094
struct ast_custom_function::@550 acflist
const char * synopsis
Definition extconf.c:2093
const char * name
Definition pbx.h:119
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition pbx.c:207
char * exten
Definition pbx.c:208
char stuff[0]
Definition pbx.c:227
const char * app
Definition pbx.c:216
struct ast_app * cached_app
Definition pbx.c:217
const char * registrar
Definition pbx.c:223
const char * cidmatch
Definition pbx.c:211
struct ast_context * parent
Definition pbx.c:215
struct ast_exten * peer
Definition pbx.c:220
void * data
Definition pbx.c:218
struct ast_exten * next
Definition pbx.c:226
int priority
Definition pbx.c:213
void(* datad)(void *)
Definition pbx.c:219
const char * label
Definition pbx.c:214
int matchcid
Definition pbx.c:210
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
Structure for dial plan hints.
Definition extconf.c:2426
int laststate
Definition extconf.c:2428
struct ast_hint::@555 list
struct ast_state_cb * callbacks
Definition extconf.c:2429
struct ast_exten * exten
Definition extconf.c:2427
ast_ignorepat: Ignore patterns in dial plan
const char pattern[0]
const char * registrar
struct ast_ignorepat * next
Definition extconf.c:2384
ast_include: include= support in extensions.conf
Definition pbx_include.c:37
struct ast_timing timing
Definition pbx_include.c:46
const char * rname
Definition pbx_include.c:40
char stuff[0]
Definition pbx_include.c:47
const char * registrar
Definition pbx_include.c:42
struct ast_include * next
Definition extconf.c:2366
const char * name
Definition pbx_include.c:38
Structure for mutex and tracking information.
Definition lock.h:142
pthread_mutex_t mutex
Definition lock.h:143
Structure for rwlock and tracking information.
Definition lock.h:164
ast_state_cb: An extension state notify register item
Definition extconf.c:2413
ast_state_cb_type callback
Definition extconf.c:2416
void * data
Definition extconf.c:2415
struct ast_state_cb * next
Definition extconf.c:2417
ast_sw: Switch statement in extensions.conf
Definition pbx_sw.c:37
struct ast_sw::@408 list
char stuff[0]
Definition pbx_sw.c:45
int eval
Definition pbx_sw.c:43
char * name
Definition extconf.c:2372
char * tmpdata
Definition extconf.c:2377
const char * registrar
Definition pbx_sw.c:40
const char * data
Definition pbx_sw.c:42
const char * name
Definition pbx_sw.c:38
char * data
Definition extconf.c:2374
struct ast_sw::@552 list
struct ast_switch::@255 list
ast_switch_f * canmatch
Definition pbx.h:168
const char * description
Definition pbx.h:165
ast_switch_f * exists
Definition pbx.h:167
ast_switch_f * exec
Definition pbx.h:169
struct ast_switch::@551 list
ast_switch_f * matchmore
Definition pbx.h:170
const char * name
Definition pbx.h:164
unsigned int monthmask
Definition pbx.h:175
unsigned int daymask
Definition pbx.h:176
unsigned int minmask[48]
Definition pbx.h:178
int hastime
Definition pbx.h:174
char * timezone
Definition pbx.h:179
unsigned int dowmask
Definition pbx.h:177
char name[0]
Definition chanvars.h:31
char * value
Definition chanvars.h:30
struct ast_var_t::@549 entries
struct ast_var_t::@221 entries
Structure for variables, used for configurations and for channel variables.
char stuff[0]
Contents of file, name, and value in that order stuffed here.
struct ast_comment * precomments
char * value
Definition extconf.c:1028
char * name
Definition extconf.c:1027
struct ast_comment * sameline
char * file
Definition extconf.c:1029
struct ast_variable * next
All configuration options for http media cache.
structure to hold extensions
struct ast_switch * swo
Definition extconf.h:239
char * incstack[AST_PBX_MAX_STACK]
Definition extconf.h:236
const char * foundcontext
Definition extconf.h:241
const char * data
Definition extconf.h:240
int laststate
Definition extconf.c:2437
char * context
Definition extconf.c:2434
char data[1]
Definition extconf.c:2439
struct store_hint::@556 list
char * exten
Definition extconf.c:2435
struct ast_state_cb * callbacks
Definition extconf.c:2436
int value
Definition syslog.c:37
static struct aco_type global
static struct test_val b
static struct test_val a
static struct test_val c
Time-related functions and macros.
#define ONE_MILLION
Definition utils.c:2267
static struct timeval tvfix(struct timeval a)
Definition utils.c:2272