Asterisk - The Open Source Telephony Project GIT-master-77d630f
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 == &__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
1397extern int ast_language_is_prefix;
1398
1399
1400
1401/* linkedlists.h */
1402
1403/*!
1404 \brief Write locks a list.
1405 \param head This is a pointer to the list head structure
1406
1407 This macro attempts to place an exclusive write lock in the
1408 list head structure pointed to by head.
1409 Returns non-zero on success, 0 on failure
1410*/
1411#define AST_RWLIST_WRLOCK(head) \
1412 ast_rwlock_wrlock(&(head)->lock)
1413
1414/*!
1415 \brief Read locks a list.
1416 \param head This is a pointer to the list head structure
1417
1418 This macro attempts to place a read lock in the
1419 list head structure pointed to by head.
1420 Returns non-zero on success, 0 on failure
1421*/
1422#define AST_RWLIST_RDLOCK(head) \
1423 ast_rwlock_rdlock(&(head)->lock)
1424
1425/*!
1426 \brief Attempts to unlock a read/write based list.
1427 \param head This is a pointer to the list head structure
1428
1429 This macro attempts to remove a read or write lock from the
1430 list head structure pointed to by head. If the list
1431 was not locked by this thread, this macro has no effect.
1432*/
1433#define AST_RWLIST_UNLOCK(head) \
1434 ast_rwlock_unlock(&(head)->lock)
1435
1436/*!
1437 \brief Defines a structure to be used to hold a list of specified type.
1438 \param name This will be the name of the defined structure.
1439 \param type This is the type of each list entry.
1440
1441 This macro creates a structure definition that can be used
1442 to hold a list of the entries of type \a type. It does not actually
1443 declare (allocate) a structure; to do that, either follow this
1444 macro with the desired name of the instance you wish to declare,
1445 or use the specified \a name to declare instances elsewhere.
1446
1447 Example usage:
1448 \code
1449 static AST_LIST_HEAD(entry_list, entry) entries;
1450 \endcode
1451
1452 This would define \c struct \c entry_list, and declare an instance of it named
1453 \a entries, all intended to hold a list of type \c struct \c entry.
1454*/
1455#define AST_LIST_HEAD(name, type) \
1456struct name { \
1457 struct type *first; \
1458 struct type *last; \
1459 ast_mutex_t lock; \
1460}
1461
1462/*!
1463 \brief Defines a structure to be used to hold a read/write list of specified type.
1464 \param name This will be the name of the defined structure.
1465 \param type This is the type of each list entry.
1466
1467 This macro creates a structure definition that can be used
1468 to hold a list of the entries of type \a type. It does not actually
1469 declare (allocate) a structure; to do that, either follow this
1470 macro with the desired name of the instance you wish to declare,
1471 or use the specified \a name to declare instances elsewhere.
1472
1473 Example usage:
1474 \code
1475 static AST_RWLIST_HEAD(entry_list, entry) entries;
1476 \endcode
1477
1478 This would define \c struct \c entry_list, and declare an instance of it named
1479 \a entries, all intended to hold a list of type \c struct \c entry.
1480*/
1481#define AST_RWLIST_HEAD(name, type) \
1482struct name { \
1483 struct type *first; \
1484 struct type *last; \
1485 ast_rwlock_t lock; \
1486}
1487
1488/*!
1489 \brief Defines a structure to be used to hold a list of specified type (with no lock).
1490 \param name This will be the name of the defined structure.
1491 \param type This is the type of each list entry.
1492
1493 This macro creates a structure definition that can be used
1494 to hold a list of the entries of type \a type. It does not actually
1495 declare (allocate) a structure; to do that, either follow this
1496 macro with the desired name of the instance you wish to declare,
1497 or use the specified \a name to declare instances elsewhere.
1498
1499 Example usage:
1500 \code
1501 static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
1502 \endcode
1503
1504 This would define \c struct \c entry_list, and declare an instance of it named
1505 \a entries, all intended to hold a list of type \c struct \c entry.
1506*/
1507#define AST_LIST_HEAD_NOLOCK(name, type) \
1508struct name { \
1509 struct type *first; \
1510 struct type *last; \
1511}
1512
1513/*!
1514 \brief Defines initial values for a declaration of AST_LIST_HEAD
1515*/
1516#define AST_LIST_HEAD_INIT_VALUE { \
1517 .first = NULL, \
1518 .last = NULL, \
1519 .lock = AST_MUTEX_INIT_VALUE, \
1520 }
1521
1522/*!
1523 \brief Defines initial values for a declaration of AST_RWLIST_HEAD
1524*/
1525#define AST_RWLIST_HEAD_INIT_VALUE { \
1526 .first = NULL, \
1527 .last = NULL, \
1528 .lock = AST_RWLOCK_INIT_VALUE, \
1529 }
1530
1531/*!
1532 \brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
1533*/
1534#define AST_LIST_HEAD_NOLOCK_INIT_VALUE { \
1535 .first = NULL, \
1536 .last = NULL, \
1537 }
1538
1539/*!
1540 \brief Defines a structure to be used to hold a list of specified type, statically initialized.
1541 \param name This will be the name of the defined structure.
1542 \param type This is the type of each list entry.
1543
1544 This macro creates a structure definition that can be used
1545 to hold a list of the entries of type \a type, and allocates an instance
1546 of it, initialized to be empty.
1547
1548 Example usage:
1549 \code
1550 static AST_LIST_HEAD_STATIC(entry_list, entry);
1551 \endcode
1552
1553 This would define \c struct \c entry_list, intended to hold a list of
1554 type \c struct \c entry.
1555*/
1556#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
1557#define AST_LIST_HEAD_STATIC(name, type) \
1558struct name { \
1559 struct type *first; \
1560 struct type *last; \
1561 ast_mutex_t lock; \
1562} name; \
1563static void __attribute__((constructor)) init_##name(void) \
1564{ \
1565 AST_LIST_HEAD_INIT(&name); \
1566} \
1567static void __attribute__((destructor)) fini_##name(void) \
1568{ \
1569 AST_LIST_HEAD_DESTROY(&name); \
1570} \
1571struct __dummy_##name
1572#else
1573#define AST_LIST_HEAD_STATIC(name, type) \
1574struct name { \
1575 struct type *first; \
1576 struct type *last; \
1577 ast_mutex_t lock; \
1578} name = AST_LIST_HEAD_INIT_VALUE
1579#endif
1580
1581/*!
1582 \brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
1583 \param name This will be the name of the defined structure.
1584 \param type This is the type of each list entry.
1585
1586 This macro creates a structure definition that can be used
1587 to hold a list of the entries of type \a type, and allocates an instance
1588 of it, initialized to be empty.
1589
1590 Example usage:
1591 \code
1592 static AST_RWLIST_HEAD_STATIC(entry_list, entry);
1593 \endcode
1594
1595 This would define \c struct \c entry_list, intended to hold a list of
1596 type \c struct \c entry.
1597*/
1598#ifndef AST_RWLOCK_INIT_VALUE
1599#define AST_RWLIST_HEAD_STATIC(name, type) \
1600struct name { \
1601 struct type *first; \
1602 struct type *last; \
1603 ast_rwlock_t lock; \
1604} name; \
1605static void __attribute__((constructor)) init_##name(void) \
1606{ \
1607 AST_RWLIST_HEAD_INIT(&name); \
1608} \
1609static void __attribute__((destructor)) fini_##name(void) \
1610{ \
1611 AST_RWLIST_HEAD_DESTROY(&name); \
1612} \
1613struct __dummy_##name
1614#else
1615#define AST_RWLIST_HEAD_STATIC(name, type) \
1616struct name { \
1617 struct type *first; \
1618 struct type *last; \
1619 ast_rwlock_t lock; \
1620} name = AST_RWLIST_HEAD_INIT_VALUE
1621#endif
1622
1623/*!
1624 \brief Defines a structure to be used to hold a list of specified type, statically initialized.
1625
1626 This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
1627*/
1628#define AST_LIST_HEAD_NOLOCK_STATIC(name, type) \
1629struct name { \
1630 struct type *first; \
1631 struct type *last; \
1632} name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
1633
1634/*!
1635 \brief Initializes a list head structure with a specified first entry.
1636 \param head This is a pointer to the list head structure
1637 \param entry pointer to the list entry that will become the head of the list
1638
1639 This macro initializes a list head structure by setting the head
1640 entry to the supplied value and recreating the embedded lock.
1641*/
1642#define AST_LIST_HEAD_SET(head, entry) do { \
1643 (head)->first = (entry); \
1644 (head)->last = (entry); \
1645 ast_mutex_init(&(head)->lock); \
1646} while (0)
1647
1648/*!
1649 \brief Initializes an rwlist head structure with a specified first entry.
1650 \param head This is a pointer to the list head structure
1651 \param entry pointer to the list entry that will become the head of the list
1652
1653 This macro initializes a list head structure by setting the head
1654 entry to the supplied value and recreating the embedded lock.
1655*/
1656#define AST_RWLIST_HEAD_SET(head, entry) do { \
1657 (head)->first = (entry); \
1658 (head)->last = (entry); \
1659 ast_rwlock_init(&(head)->lock); \
1660} while (0)
1661
1662/*!
1663 \brief Initializes a list head structure with a specified first entry.
1664 \param head This is a pointer to the list head structure
1665 \param entry pointer to the list entry that will become the head of the list
1666
1667 This macro initializes a list head structure by setting the head
1668 entry to the supplied value.
1669*/
1670#define AST_LIST_HEAD_SET_NOLOCK(head, entry) do { \
1671 (head)->first = (entry); \
1672 (head)->last = (entry); \
1673} while (0)
1674
1675/*!
1676 \brief Declare a forward link structure inside a list entry.
1677 \param type This is the type of each list entry.
1678
1679 This macro declares a structure to be used to link list entries together.
1680 It must be used inside the definition of the structure named in
1681 \a type, as follows:
1682
1683 \code
1684 struct list_entry {
1685 ...
1686 AST_LIST_ENTRY(list_entry) list;
1687 }
1688 \endcode
1689
1690 The field name \a list here is arbitrary, and can be anything you wish.
1691*/
1692#define AST_LIST_ENTRY(type) \
1693struct { \
1694 struct type *next; \
1695}
1696
1697#define AST_RWLIST_ENTRY AST_LIST_ENTRY
1698
1699/*!
1700 \brief Returns the first entry contained in a list.
1701 \param head This is a pointer to the list head structure
1702 */
1703#define AST_LIST_FIRST(head) ((head)->first)
1704
1705#define AST_RWLIST_FIRST AST_LIST_FIRST
1706
1707/*!
1708 \brief Returns the last entry contained in a list.
1709 \param head This is a pointer to the list head structure
1710 */
1711#define AST_LIST_LAST(head) ((head)->last)
1712
1713#define AST_RWLIST_LAST AST_LIST_LAST
1714
1715/*!
1716 \brief Returns the next entry in the list after the given entry.
1717 \param elm This is a pointer to the current entry.
1718 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1719 used to link entries of this list together.
1720*/
1721#define AST_LIST_NEXT(elm, field) ((elm)->field.next)
1722
1723#define AST_RWLIST_NEXT AST_LIST_NEXT
1724
1725/*!
1726 \brief Checks whether the specified list contains any entries.
1727 \param head This is a pointer to the list head structure
1728
1729 Returns non-zero if the list has entries, zero if not.
1730 */
1731#define AST_LIST_EMPTY(head) (AST_LIST_FIRST(head) == NULL)
1732
1733#define AST_RWLIST_EMPTY AST_LIST_EMPTY
1734
1735/*!
1736 \brief Loops over (traverses) the entries in a list.
1737 \param head This is a pointer to the list head structure
1738 \param var This is the name of the variable that will hold a pointer to the
1739 current list entry on each iteration. It must be declared before calling
1740 this macro.
1741 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1742 used to link entries of this list together.
1743
1744 This macro is use to loop over (traverse) the entries in a list. It uses a
1745 \a for loop, and supplies the enclosed code with a pointer to each list
1746 entry as it loops. It is typically used as follows:
1747 \code
1748 static AST_LIST_HEAD(entry_list, list_entry) entries;
1749 ...
1750 struct list_entry {
1751 ...
1752 AST_LIST_ENTRY(list_entry) list;
1753 }
1754 ...
1755 struct list_entry *current;
1756 ...
1757 AST_LIST_TRAVERSE(&entries, current, list) {
1758 (do something with current here)
1759 }
1760 \endcode
1761 \warning If you modify the forward-link pointer contained in the \a current entry while
1762 inside the loop, the behavior will be unpredictable. At a minimum, the following
1763 macros will modify the forward-link pointer, and should not be used inside
1764 AST_LIST_TRAVERSE() against the entry pointed to by the \a current pointer without
1765 careful consideration of their consequences:
1766 \li AST_LIST_NEXT() (when used as an lvalue)
1767 \li AST_LIST_INSERT_AFTER()
1768 \li AST_LIST_INSERT_HEAD()
1769 \li AST_LIST_INSERT_TAIL()
1770*/
1771#define AST_LIST_TRAVERSE(head,var,field) \
1772 for((var) = (head)->first; (var); (var) = (var)->field.next)
1773
1774#define AST_RWLIST_TRAVERSE AST_LIST_TRAVERSE
1775
1776/*!
1777 \brief Loops safely over (traverses) the entries in a list.
1778 \param head This is a pointer to the list head structure
1779 \param var This is the name of the variable that will hold a pointer to the
1780 current list entry on each iteration. It must be declared before calling
1781 this macro.
1782 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1783 used to link entries of this list together.
1784
1785 This macro is used to safely loop over (traverse) the entries in a list. It
1786 uses a \a for loop, and supplies the enclosed code with a pointer to each list
1787 entry as it loops. It is typically used as follows:
1788
1789 \code
1790 static AST_LIST_HEAD(entry_list, list_entry) entries;
1791 ...
1792 struct list_entry {
1793 ...
1794 AST_LIST_ENTRY(list_entry) list;
1795 }
1796 ...
1797 struct list_entry *current;
1798 ...
1799 AST_LIST_TRAVERSE_SAFE_BEGIN(&entries, current, list) {
1800 (do something with current here)
1801 }
1802 AST_LIST_TRAVERSE_SAFE_END;
1803 \endcode
1804
1805 It differs from AST_LIST_TRAVERSE() in that the code inside the loop can modify
1806 (or even free, after calling AST_LIST_REMOVE_CURRENT()) the entry pointed to by
1807 the \a current pointer without affecting the loop traversal.
1808*/
1809#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) { \
1810 typeof((head)->first) __list_next; \
1811 typeof((head)->first) __list_prev = NULL; \
1812 typeof((head)->first) __new_prev = NULL; \
1813 for ((var) = (head)->first, __new_prev = (var), \
1814 __list_next = (var) ? (var)->field.next : NULL; \
1815 (var); \
1816 __list_prev = __new_prev, (var) = __list_next, \
1817 __new_prev = (var), \
1818 __list_next = (var) ? (var)->field.next : NULL \
1819 )
1820
1821#define AST_RWLIST_TRAVERSE_SAFE_BEGIN AST_LIST_TRAVERSE_SAFE_BEGIN
1822
1823/*!
1824 \brief Removes the \a current entry from a list during a traversal.
1825 \param head This is a pointer to the list head structure
1826 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1827 used to link entries of this list together.
1828
1829 \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
1830 block; it is used to unlink the current entry from the list without affecting
1831 the list traversal (and without having to re-traverse the list to modify the
1832 previous entry, if any).
1833 */
1834#define AST_LIST_REMOVE_CURRENT(head, field) \
1835 __new_prev->field.next = NULL; \
1836 __new_prev = __list_prev; \
1837 if (__list_prev) \
1838 __list_prev->field.next = __list_next; \
1839 else \
1840 (head)->first = __list_next; \
1841 if (!__list_next) \
1842 (head)->last = __list_prev;
1843
1844#define AST_RWLIST_REMOVE_CURRENT AST_LIST_REMOVE_CURRENT
1845
1846/*!
1847 \brief Inserts a list entry before the current entry during a traversal.
1848 \param head This is a pointer to the list head structure
1849 \param elm This is a pointer to the entry to be inserted.
1850 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1851 used to link entries of this list together.
1852
1853 \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
1854 block.
1855 */
1856#define AST_LIST_INSERT_BEFORE_CURRENT(head, elm, field) do { \
1857 if (__list_prev) { \
1858 (elm)->field.next = __list_prev->field.next; \
1859 __list_prev->field.next = elm; \
1860 } else { \
1861 (elm)->field.next = (head)->first; \
1862 (head)->first = (elm); \
1863 } \
1864 __new_prev = (elm); \
1865} while (0)
1866
1867#define AST_RWLIST_INSERT_BEFORE_CURRENT AST_LIST_INSERT_BEFORE_CURRENT
1868
1869/*!
1870 \brief Closes a safe loop traversal block.
1871 */
1872#define AST_LIST_TRAVERSE_SAFE_END }
1873
1874#define AST_RWLIST_TRAVERSE_SAFE_END AST_LIST_TRAVERSE_SAFE_END
1875
1876/*!
1877 \brief Initializes a list head structure.
1878 \param head This is a pointer to the list head structure
1879
1880 This macro initializes a list head structure by setting the head
1881 entry to \a NULL (empty list) and recreating the embedded lock.
1882*/
1883#define AST_LIST_HEAD_INIT(head) { \
1884 (head)->first = NULL; \
1885 (head)->last = NULL; \
1886 ast_mutex_init(&(head)->lock); \
1887}
1888
1889/*!
1890 \brief Initializes an rwlist head structure.
1891 \param head This is a pointer to the list head structure
1892
1893 This macro initializes a list head structure by setting the head
1894 entry to \a NULL (empty list) and recreating the embedded lock.
1895*/
1896#define AST_RWLIST_HEAD_INIT(head) { \
1897 (head)->first = NULL; \
1898 (head)->last = NULL; \
1899 ast_rwlock_init(&(head)->lock); \
1900}
1901
1902/*!
1903 \brief Destroys an rwlist head structure.
1904 \param head This is a pointer to the list head structure
1905
1906 This macro destroys a list head structure by setting the head
1907 entry to \a NULL (empty list) and destroying the embedded lock.
1908 It does not free the structure from memory.
1909*/
1910#define AST_RWLIST_HEAD_DESTROY(head) { \
1911 (head)->first = NULL; \
1912 (head)->last = NULL; \
1913 ast_rwlock_destroy(&(head)->lock); \
1914}
1915
1916/*!
1917 \brief Initializes a list head structure.
1918 \param head This is a pointer to the list head structure
1919
1920 This macro initializes a list head structure by setting the head
1921 entry to \a NULL (empty list). There is no embedded lock handling
1922 with this macro.
1923*/
1924#define AST_LIST_HEAD_INIT_NOLOCK(head) { \
1925 (head)->first = NULL; \
1926 (head)->last = NULL; \
1927}
1928
1929/*!
1930 \brief Inserts a list entry after a given entry.
1931 \param head This is a pointer to the list head structure
1932 \param listelm This is a pointer to the entry after which the new entry should
1933 be inserted.
1934 \param elm This is a pointer to the entry to be inserted.
1935 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1936 used to link entries of this list together.
1937 */
1938#define AST_LIST_INSERT_AFTER(head, listelm, elm, field) do { \
1939 (elm)->field.next = (listelm)->field.next; \
1940 (listelm)->field.next = (elm); \
1941 if ((head)->last == (listelm)) \
1942 (head)->last = (elm); \
1943} while (0)
1944
1945#define AST_RWLIST_INSERT_AFTER AST_LIST_INSERT_AFTER
1946
1947/*!
1948 \brief Inserts a list entry at the head of a list.
1949 \param head This is a pointer to the list head structure
1950 \param elm This is a pointer to the entry to be inserted.
1951 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1952 used to link entries of this list together.
1953 */
1954#define AST_LIST_INSERT_HEAD(head, elm, field) do { \
1955 (elm)->field.next = (head)->first; \
1956 (head)->first = (elm); \
1957 if (!(head)->last) \
1958 (head)->last = (elm); \
1959} while (0)
1960
1961#define AST_RWLIST_INSERT_HEAD AST_LIST_INSERT_HEAD
1962
1963/*!
1964 \brief Appends a list entry to the tail of a list.
1965 \param head This is a pointer to the list head structure
1966 \param elm This is a pointer to the entry to be appended.
1967 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1968 used to link entries of this list together.
1969
1970 Note: The link field in the appended entry is \b not modified, so if it is
1971 actually the head of a list itself, the entire list will be appended
1972 temporarily (until the next AST_LIST_INSERT_TAIL is performed).
1973 */
1974#define AST_LIST_INSERT_TAIL(head, elm, field) do { \
1975 if (!(head)->first) { \
1976 (head)->first = (elm); \
1977 (head)->last = (elm); \
1978 } else { \
1979 (head)->last->field.next = (elm); \
1980 (head)->last = (elm); \
1981 } \
1982} while (0)
1983
1984#define AST_RWLIST_INSERT_TAIL AST_LIST_INSERT_TAIL
1985
1986/*!
1987 \brief Appends a whole list to the tail of a list.
1988 \param head This is a pointer to the list head structure
1989 \param list This is a pointer to the list to be appended.
1990 \param field This is the name of the field (declared using AST_LIST_ENTRY())
1991 used to link entries of this list together.
1992 */
1993#define AST_LIST_APPEND_LIST(head, list, field) do { \
1994 if (!(head)->first) { \
1995 (head)->first = (list)->first; \
1996 (head)->last = (list)->last; \
1997 } else { \
1998 (head)->last->field.next = (list)->first; \
1999 (head)->last = (list)->last; \
2000 } \
2001} while (0)
2002
2003#define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
2004
2005/*!
2006 \brief Removes and returns the head entry from a list.
2007 \param head This is a pointer to the list head structure
2008 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2009 used to link entries of this list together.
2010
2011 Removes the head entry from the list, and returns a pointer to it.
2012 This macro is safe to call on an empty list.
2013 */
2014#define AST_LIST_REMOVE_HEAD(head, field) ({ \
2015 typeof((head)->first) cur = (head)->first; \
2016 if (cur) { \
2017 (head)->first = cur->field.next; \
2018 cur->field.next = NULL; \
2019 if ((head)->last == cur) \
2020 (head)->last = NULL; \
2021 } \
2022 cur; \
2023 })
2024
2025#define AST_RWLIST_REMOVE_HEAD AST_LIST_REMOVE_HEAD
2026
2027/*!
2028 \brief Removes a specific entry from a list.
2029 \param head This is a pointer to the list head structure
2030 \param elm This is a pointer to the entry to be removed.
2031 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2032 used to link entries of this list together.
2033 \warning The removed entry is \b not freed nor modified in any way.
2034 */
2035#define AST_LIST_REMOVE(head, elm, field) do { \
2036 if ((head)->first == (elm)) { \
2037 (head)->first = (elm)->field.next; \
2038 if ((head)->last == (elm)) \
2039 (head)->last = NULL; \
2040 } else { \
2041 typeof(elm) curelm = (head)->first; \
2042 while (curelm && (curelm->field.next != (elm))) \
2043 curelm = curelm->field.next; \
2044 if (curelm) { \
2045 curelm->field.next = (elm)->field.next; \
2046 if ((head)->last == (elm)) \
2047 (head)->last = curelm; \
2048 } \
2049 } \
2050 (elm)->field.next = NULL; \
2051} while (0)
2052
2053#define AST_RWLIST_REMOVE AST_LIST_REMOVE
2054
2055/* chanvars.h */
2056
2057struct ast_var_t {
2059 char *value;
2060 char name[0];
2061};
2062
2064
2067
2068
2069/* IN CONFLICT: struct ast_var_t *ast_var_assign(const char *name, const char *value); */
2070
2071static struct ast_var_t *ast_var_assign(const char *name, const char *value);
2072
2073static void ast_var_delete(struct ast_var_t *var);
2074
2075/*from channel.h */
2076#define AST_MAX_EXTENSION 80 /*!< Max length of an extension */
2077
2078
2079/* from pbx.h */
2080#define PRIORITY_HINT -1 /*!< Special Priority for a hint */
2081
2083 AST_EXTENSION_REMOVED = -2, /*!< Extension removed */
2084 AST_EXTENSION_DEACTIVATED = -1, /*!< Extension hint removed */
2085 AST_EXTENSION_NOT_INUSE = 0, /*!< No device INUSE or BUSY */
2086 AST_EXTENSION_INUSE = 1 << 0, /*!< One or more devices INUSE */
2087 AST_EXTENSION_BUSY = 1 << 1, /*!< All devices BUSY */
2088 AST_EXTENSION_UNAVAILABLE = 1 << 2, /*!< All devices UNAVAILABLE/UNREGISTERED */
2089 AST_EXTENSION_RINGING = 1 << 3, /*!< All devices RINGING */
2090 AST_EXTENSION_ONHOLD = 1 << 4, /*!< All devices ONHOLD */
2091};
2092
2093struct ast_custom_function {
2094 const char *name; /*!< Name */
2095 const char *synopsis; /*!< Short description for "show functions" */
2096 const char *desc; /*!< Help text that explains it all */
2097 const char *syntax; /*!< Syntax description */
2098 int (*read)(struct ast_channel *, const char *, char *, char *, size_t); /*!< Read function, if read is supported */
2099 int (*write)(struct ast_channel *, const char *, char *, const char *); /*!< Write function, if write is supported */
2101};
2102
2103typedef int (ast_switch_f)(struct ast_channel *chan, const char *context,
2104 const char *exten, int priority, const char *callerid, const char *data);
2105
2106struct ast_switch {
2108 const char *name; /*!< Name of the switch */
2109 const char *description; /*!< Description of the switch */
2110
2115};
2116
2117
2118static char *config_filename = "extensions.conf";
2119static char *global_registrar = "conf2ael";
2120static char userscontext[AST_MAX_EXTENSION] = "default";
2121static int static_config = 0;
2125static void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
2126
2127
2128/* stolen from callerid.c */
2129
2130/*! \brief Clean up phone string
2131 * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
2132 * Basically, remove anything that could be invalid in a pattern.
2133 */
2134static void ast_shrink_phone_number(char *n)
2135{
2136 int x, y=0;
2137 int bracketed = 0;
2138
2139 for (x=0; n[x]; x++) {
2140 switch(n[x]) {
2141 case '[':
2142 bracketed++;
2143 n[y++] = n[x];
2144 break;
2145 case ']':
2146 bracketed--;
2147 n[y++] = n[x];
2148 break;
2149 case '-':
2150 if (bracketed)
2151 n[y++] = n[x];
2152 break;
2153 case '.':
2154 if (!n[x+1])
2155 n[y++] = n[x];
2156 break;
2157 default:
2158 if (!strchr("()", n[x]))
2159 n[y++] = n[x];
2160 }
2161 }
2162 n[y] = '\0';
2163}
2164
2165
2166/* stolen from chanvars.c */
2167
2168static const char *ast_var_name(const struct ast_var_t *var)
2169{
2170 const char *name;
2171
2172 if (var == NULL || (name = var->name) == NULL)
2173 return NULL;
2174 /* Return the name without the initial underscores */
2175 if (name[0] == '_') {
2176 name++;
2177 if (name[0] == '_')
2178 name++;
2179 }
2180 return name;
2181}
2182
2183/* experiment 1: see if it's easier just to use existing config code
2184 * to read in the extensions.conf file. In this scenario,
2185 I have to rip/copy code from other modules, because they
2186 are staticly declared as-is. A solution would be to move
2187 the ripped code to another location and make them available
2188 to other modules and standalones */
2189
2190/* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
2191
2192static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
2193{
2194 va_list vars;
2195 va_start(vars,fmt);
2196
2197 printf("LOG: lev:%d file:%s line:%d func: %s ",
2198 level, file, line, function);
2199 vprintf(fmt, vars);
2200 fflush(stdout);
2201 va_end(vars);
2202}
2203
2204void __attribute__((format(printf, 1, 2))) ast_verbose(const char *fmt, ...)
2205{
2206 va_list vars;
2207 va_start(vars,fmt);
2208
2209 printf("VERBOSE: ");
2210 vprintf(fmt, vars);
2211 fflush(stdout);
2212 va_end(vars);
2213}
2214
2215/* stolen from main/utils.c */
2216static char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
2217{
2218 char *dataPut = start;
2219 int inEscape = 0;
2220 int inQuotes = 0;
2221
2222 for (; *start; start++) {
2223 if (inEscape) {
2224 *dataPut++ = *start; /* Always goes verbatim */
2225 inEscape = 0;
2226 } else {
2227 if (*start == '\\') {
2228 inEscape = 1; /* Do not copy \ into the data */
2229 } else if (*start == '\'') {
2230 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
2231 } else {
2232 /* Replace , with |, unless in quotes */
2233 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
2234 }
2235 }
2236 }
2237 if (start != dataPut)
2238 *dataPut = 0;
2239 return dataPut;
2240}
2241
2242static int ast_true(const char *s)
2243{
2244 if (ast_strlen_zero(s))
2245 return 0;
2246
2247 /* Determine if this is a true value */
2248 if (!strcasecmp(s, "yes") ||
2249 !strcasecmp(s, "true") ||
2250 !strcasecmp(s, "y") ||
2251 !strcasecmp(s, "t") ||
2252 !strcasecmp(s, "1") ||
2253 !strcasecmp(s, "on"))
2254 return -1;
2255
2256 return 0;
2257}
2258
2259#define ONE_MILLION 1000000
2260/*
2261 * put timeval in a valid range. usec is 0..999999
2262 * negative values are not allowed and truncated.
2263 */
2264static struct timeval tvfix(struct timeval a)
2265{
2266 if (a.tv_usec >= ONE_MILLION) {
2267 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
2268 (long)a.tv_sec, (long int) a.tv_usec);
2269 a.tv_sec += a.tv_usec / ONE_MILLION;
2270 a.tv_usec %= ONE_MILLION;
2271 } else if (a.tv_usec < 0) {
2272 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
2273 (long)a.tv_sec, (long int) a.tv_usec);
2274 a.tv_usec = 0;
2275 }
2276 return a;
2277}
2278
2279struct timeval ast_tvadd(struct timeval a, struct timeval b);
2280struct timeval ast_tvadd(struct timeval a, struct timeval b)
2281{
2282 /* consistency checks to guarantee usec in 0..999999 */
2283 a = tvfix(a);
2284 b = tvfix(b);
2285 a.tv_sec += b.tv_sec;
2286 a.tv_usec += b.tv_usec;
2287 if (a.tv_usec >= ONE_MILLION) {
2288 a.tv_sec++;
2289 a.tv_usec -= ONE_MILLION;
2290 }
2291 return a;
2292}
2293
2294struct timeval ast_tvsub(struct timeval a, struct timeval b);
2295struct timeval ast_tvsub(struct timeval a, struct timeval b)
2296{
2297 /* consistency checks to guarantee usec in 0..999999 */
2298 a = tvfix(a);
2299 b = tvfix(b);
2300 a.tv_sec -= b.tv_sec;
2301 a.tv_usec -= b.tv_usec;
2302 if (a.tv_usec < 0) {
2303 a.tv_sec-- ;
2304 a.tv_usec += ONE_MILLION;
2305 }
2306 return a;
2307}
2308#undef ONE_MILLION
2309
2310void ast_mark_lock_failed(void *lock_addr);
2311void ast_mark_lock_failed(void *lock_addr)
2312{
2313 /* Pretend to do something. */
2314}
2315
2316/* stolen from pbx.c */
2317#define VAR_BUF_SIZE 4096
2318
2319#define VAR_NORMAL 1
2320#define VAR_SOFTTRAN 2
2321#define VAR_HARDTRAN 3
2322
2323#define BACKGROUND_SKIP (1 << 0)
2324#define BACKGROUND_NOANSWER (1 << 1)
2325#define BACKGROUND_MATCHEXTEN (1 << 2)
2326#define BACKGROUND_PLAYBACK (1 << 3)
2327
2328/*!
2329 \brief ast_exten: An extension
2330 The dialplan is saved as a linked list with each context
2331 having it's own linked list of extensions - one item per
2332 priority.
2333*/
2334struct ast_exten {
2335 char *exten; /*!< Extension name */
2336 int matchcid; /*!< Match caller id ? */
2337 const char *cidmatch; /*!< Caller id to match for this extension */
2338 int priority; /*!< Priority */
2339 const char *label; /*!< Label */
2340 struct ast_context *parent; /*!< The context this extension belongs to */
2341 const char *app; /*!< Application to execute */
2342 struct ast_app *cached_app; /*!< Cached location of application */
2343 void *data; /*!< Data to use (arguments) */
2344 void (*datad)(void *); /*!< Data destructor */
2345 struct ast_exten *peer; /*!< Next higher priority with our extension */
2346 const char *registrar; /*!< Registrar */
2347 struct ast_exten *next; /*!< Extension with a greater ID */
2348 char stuff[0];
2349};
2350/* from pbx.h */
2351typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
2352struct ast_timing {
2353 int hastime; /*!< If time construct exists */
2354 unsigned int monthmask; /*!< Mask for month */
2355 unsigned int daymask; /*!< Mask for date */
2356 unsigned int dowmask; /*!< Mask for day of week (mon-sun) */
2357 unsigned int minmask[48]; /*!< Mask for minute */
2358 char *timezone; /*!< NULL, or zoneinfo style timezone */
2359};
2360/* end of pbx.h */
2361/*! \brief ast_include: include= support in extensions.conf */
2362struct ast_include {
2363 const char *name;
2364 const char *rname; /*!< Context to include */
2365 const char *registrar; /*!< Registrar */
2366 int hastime; /*!< If time construct exists */
2367 struct ast_timing timing; /*!< time construct */
2368 struct ast_include *next; /*!< Link them together */
2369 char stuff[0];
2370};
2371
2372/*! \brief ast_sw: Switch statement in extensions.conf */
2373struct ast_sw {
2374 char *name;
2375 const char *registrar; /*!< Registrar */
2376 char *data; /*!< Data load */
2377 int eval;
2379 char *tmpdata;
2380 char stuff[0];
2381};
2382
2383/*! \brief ast_ignorepat: Ignore patterns in dial plan */
2384struct ast_ignorepat {
2385 const char *registrar;
2387 char pattern[0];
2388};
2389
2390/*! \brief ast_context: An extension context */
2391struct ast_context {
2392 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
2393 struct ast_exten *root; /*!< The root of the list of extensions */
2394 struct ast_context *next; /*!< Link them together */
2395 struct ast_include *includes; /*!< Include other contexts */
2396 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
2397 const char *registrar; /*!< Registrar */
2398 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
2399 char name[0]; /*!< Name of the context */
2400};
2401
2402
2403/*! \brief ast_app: A registered application */
2404struct ast_app {
2405 int (*execute)(struct ast_channel *chan, void *data);
2406 const char *synopsis; /*!< Synopsis text for 'show applications' */
2407 const char *description; /*!< Description (help text) for 'show application &lt;name&gt;' */
2408 AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
2409 void *module; /*!< Module this app belongs to */
2410 char name[0]; /*!< Name of the application */
2411};
2412
2413
2414/*! \brief ast_state_cb: An extension state notify register item */
2415struct ast_state_cb {
2416 int id;
2417 void *data;
2419 struct ast_state_cb *next;
2420};
2421
2422/*! \brief Structure for dial plan hints
2423
2424 \note Hints are pointers from an extension in the dialplan to one or
2425 more devices (tech/name)
2426 - See \ref AstExtState
2427*/
2428struct ast_hint {
2429 struct ast_exten *exten; /*!< Extension */
2430 int laststate; /*!< Last known state */
2431 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
2432 AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
2433};
2434
2435struct store_hint {
2436 char *context;
2437 char *exten;
2439 int laststate;
2441 char data[1];
2442};
2443
2445
2446#define STATUS_NO_CONTEXT 1
2447#define STATUS_NO_EXTENSION 2
2448#define STATUS_NO_PRIORITY 3
2449#define STATUS_NO_LABEL 4
2450#define STATUS_SUCCESS 5
2451
2452static struct ast_var_t *ast_var_assign(const char *name, const char *value)
2453{
2454 struct ast_var_t *var;
2455 int name_len = strlen(name) + 1;
2456 int value_len = strlen(value) + 1;
2457
2458 if (!(var = ast_calloc(sizeof(*var) + name_len + value_len, sizeof(char)))) {
2459 return NULL;
2460 }
2461
2462 ast_copy_string(var->name, name, name_len);
2463 var->value = var->name + name_len;
2464 ast_copy_string(var->value, value, value_len);
2465
2466 return var;
2467}
2468
2469static void ast_var_delete(struct ast_var_t *var)
2470{
2471 free(var);
2472}
2473
2474
2475/* chopped this one off at the knees! */
2476static int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
2477{
2478
2479 /* ast_log(LOG_ERROR, "Function %s not registered\n", function); we are not interested in the details here */
2480
2481 return -1;
2482}
2483
2484static unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
2485{
2486 int argc;
2487 char *scan;
2488 int paren = 0, quote = 0;
2489
2490 if (!buf || !array || !arraylen)
2491 return 0;
2492
2493 memset(array, 0, arraylen * sizeof(*array));
2494
2495 scan = buf;
2496
2497 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
2498 array[argc] = scan;
2499 for (; *scan; scan++) {
2500 if (*scan == '(')
2501 paren++;
2502 else if (*scan == ')') {
2503 if (paren)
2504 paren--;
2505 } else if (*scan == '"' && delim != '"') {
2506 quote = quote ? 0 : 1;
2507 /* Remove quote character from argument */
2508 memmove(scan, scan + 1, strlen(scan));
2509 scan--;
2510 } else if (*scan == '\\') {
2511 /* Literal character, don't parse */
2512 memmove(scan, scan + 1, strlen(scan));
2513 } else if ((*scan == delim) && !paren && !quote) {
2514 *scan++ = '\0';
2515 break;
2516 }
2517 }
2518 }
2519
2520 if (*scan)
2521 array[argc++] = scan;
2522
2523 return argc;
2524}
2525
2526static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
2527{
2528 struct ast_var_t *newvariable;
2529 struct varshead *headp;
2530 const char *nametail = name;
2531
2532 /* XXX may need locking on the channel ? */
2533 if (name[strlen(name)-1] == ')') {
2534 char *function = ast_strdupa(name);
2535
2536 ast_func_write(chan, function, value);
2537 return;
2538 }
2539
2540 headp = &globals;
2541
2542 /* For comparison purposes, we have to strip leading underscores */
2543 if (*nametail == '_') {
2544 nametail++;
2545 if (*nametail == '_')
2546 nametail++;
2547 }
2548
2549 AST_LIST_TRAVERSE (headp, newvariable, entries) {
2550 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
2551 /* there is already such a variable, delete it */
2552 AST_LIST_REMOVE(headp, newvariable, entries);
2553 ast_var_delete(newvariable);
2554 break;
2555 }
2556 }
2557
2558 if (value && (newvariable = ast_var_assign(name, value))) {
2559 if ((option_verbose > 1) && (headp == &globals))
2560 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
2561 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
2562 }
2563
2564}
2565
2566static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
2567{
2568 char *name, *value, *mydata;
2569 int argc;
2570 char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
2571 int global = 0;
2572 int x;
2573
2574 if (ast_strlen_zero(data)) {
2575 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
2576 return 0;
2577 }
2578
2579 mydata = ast_strdupa(data);
2580 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
2581
2582 /* check for a trailing flags argument */
2583 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
2584 argc--;
2585 if (strchr(argv[argc], 'g'))
2586 global = 1;
2587 }
2588
2589 for (x = 0; x < argc; x++) {
2590 name = argv[x];
2591 if ((value = strchr(name, '='))) {
2592 *value++ = '\0';
2594 } else
2595 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
2596 }
2597
2598 return(0);
2599}
2600
2601int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data);
2602
2603int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
2604{
2605 return pbx_builtin_setvar(chan, data);
2606}
2607
2608
2609/*! \brief Helper for get_range.
2610 * return the index of the matching entry, starting from 1.
2611 * If names is not supplied, try numeric values.
2612 */
2613static int lookup_name(const char *s, char *const names[], int max)
2614{
2615 int i;
2616
2617 if (names && *s > '9') {
2618 for (i = 0; names[i]; i++) {
2619 if (!strcasecmp(s, names[i])) {
2620 return i;
2621 }
2622 }
2623 }
2624
2625 /* Allow months and weekdays to be specified as numbers, as well */
2626 if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
2627 /* What the array offset would have been: "1" would be at offset 0 */
2628 return i - 1;
2629 }
2630 return -1; /* error return */
2631}
2632
2633/*! \brief helper function to return a range up to max (7, 12, 31 respectively).
2634 * names, if supplied, is an array of names that should be mapped to numbers.
2635 */
2636static unsigned get_range(char *src, int max, char *const names[], const char *msg)
2637{
2638 int start, end; /* start and ending position */
2639 unsigned int mask = 0;
2640 char *part;
2641
2642 /* Check for whole range */
2643 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
2644 return (1 << max) - 1;
2645 }
2646
2647 while ((part = strsep(&src, "&"))) {
2648 /* Get start and ending position */
2649 char *endpart = strchr(part, '-');
2650 if (endpart) {
2651 *endpart++ = '\0';
2652 }
2653 /* Find the start */
2654 if ((start = lookup_name(part, names, max)) < 0) {
2655 ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
2656 continue;
2657 }
2658 if (endpart) { /* find end of range */
2659 if ((end = lookup_name(endpart, names, max)) < 0) {
2660 ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
2661 continue;
2662 }
2663 } else {
2664 end = start;
2665 }
2666 /* Fill the mask. Remember that ranges are cyclic */
2667 mask |= (1 << end); /* initialize with last element */
2668 while (start != end) {
2669 if (start >= max) {
2670 start = 0;
2671 }
2672 mask |= (1 << start);
2673 start++;
2674 }
2675 }
2676 return mask;
2677}
2678
2679/*! \brief store a bitmask of valid times, one bit each 2 minute */
2680static void get_timerange(struct ast_timing *i, char *times)
2681{
2682 char *endpart, *part;
2683 int x;
2684 int st_h, st_m;
2685 int endh, endm;
2686 int minute_start, minute_end;
2687
2688 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
2689 memset(i->minmask, 0, sizeof(i->minmask));
2690
2691 /* 1-minute per bit */
2692 /* Star is all times */
2693 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
2694 /* 48, because each hour takes 2 integers; 30 bits each */
2695 for (x = 0; x < 48; x++) {
2696 i->minmask[x] = 0x3fffffff; /* 30 bits */
2697 }
2698 return;
2699 }
2700 /* Otherwise expect a range */
2701 while ((part = strsep(&times, "&"))) {
2702 if (!(endpart = strchr(part, '-'))) {
2703 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
2704 ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
2705 continue;
2706 }
2707 i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
2708 continue;
2709 }
2710 *endpart++ = '\0';
2711 /* why skip non digits? Mostly to skip spaces */
2712 while (*endpart && !isdigit(*endpart)) {
2713 endpart++;
2714 }
2715 if (!*endpart) {
2716 ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
2717 continue;
2718 }
2719 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
2720 ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
2721 continue;
2722 }
2723 if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
2724 ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
2725 continue;
2726 }
2727 minute_start = st_h * 60 + st_m;
2728 minute_end = endh * 60 + endm;
2729 /* Go through the time and enable each appropriate bit */
2730 for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
2731 i->minmask[x / 30] |= (1 << (x % 30));
2732 }
2733 /* Do the last one */
2734 i->minmask[x / 30] |= (1 << (x % 30));
2735 }
2736 /* All done */
2737 return;
2738}
2739
2740static void null_datad(void *foo)
2741{
2742}
2743
2744/*! \brief Find realtime engine for realtime family */
2745static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
2746{
2747 struct ast_config_engine *eng, *ret = NULL;
2748 struct ast_config_map *map;
2749
2750
2751 for (map = config_maps; map; map = map->next) {
2752 if (!strcasecmp(family, map->name)) {
2753 if (database)
2754 ast_copy_string(database, map->database, dbsiz);
2755 if (table)
2756 ast_copy_string(table, map->table ? map->table : family, tabsiz);
2757 break;
2758 }
2759 }
2760
2761 /* Check if the required driver (engine) exist */
2762 if (map) {
2763 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
2764 if (!strcasecmp(eng->name, map->driver))
2765 ret = eng;
2766 }
2767 }
2768
2769
2770 /* if we found a mapping, but the engine is not available, then issue a warning */
2771 if (map && !ret)
2772 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
2773
2774 return ret;
2775}
2776
2778
2780{
2781 return cfg->current;
2782}
2783
2784static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
2785
2786static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
2787{
2788 struct ast_category *category;
2789
2790 if ((category = ast_calloc(1, sizeof(*category))))
2791 ast_copy_string(category->name, name, sizeof(category->name));
2792 category->file = strdup(in_file);
2793 category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
2794 return category;
2795}
2796
2797struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name);
2798
2799struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name)
2800{
2801 return category_get(config, category_name, 0);
2802}
2803
2804static void move_variables(struct ast_category *old, struct ast_category *new)
2805{
2806 struct ast_variable *var = old->root;
2807 old->root = NULL;
2808#if 1
2809 /* we can just move the entire list in a single op */
2811#else
2812 while (var) {
2813 struct ast_variable *next = var->next;
2814 var->next = NULL;
2816 var = next;
2817 }
2818#endif
2819}
2820
2821static void inherit_category(struct ast_category *new, const struct ast_category *base)
2822{
2823 struct ast_variable *var;
2824
2825 for (var = base->root; var; var = var->next)
2827}
2828
2829static void ast_category_append(struct ast_config *config, struct ast_category *category);
2830
2831static void ast_category_append(struct ast_config *config, struct ast_category *category)
2832{
2833 if (config->last)
2834 config->last->next = category;
2835 else
2836 config->root = category;
2837 config->last = category;
2838 config->current = category;
2839}
2840
2841static void ast_category_destroy(struct ast_category *cat);
2842
2843static void ast_category_destroy(struct ast_category *cat)
2844{
2846 if (cat->file)
2847 free(cat->file);
2848
2849 free(cat);
2850}
2851
2853 .name = "text",
2854 .load_func = config_text_file_load,
2855};
2856
2857
2858static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file);
2859
2860static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file)
2861{
2862 char db[256] = "";
2863 char table[256] = "";
2864 struct ast_config_engine *loader = &text_file_engine;
2865 struct ast_config *result;
2866
2867 if (cfg->include_level == cfg->max_include_level) {
2868 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
2869 return NULL;
2870 }
2871
2872 cfg->include_level++;
2873 /* silence is golden!
2874 ast_log(LOG_WARNING, "internal loading file %s level=%d\n", filename, cfg->include_level);
2875 */
2876
2877 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
2878 struct ast_config_engine *eng;
2879
2880 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
2881
2882
2883 if (eng && eng->load_func) {
2884 loader = eng;
2885 } else {
2886 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
2887 if (eng && eng->load_func)
2888 loader = eng;
2889 }
2890 }
2891
2892 result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
2893 /* silence is golden
2894 ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
2895 */
2896
2897 if (result)
2898 result->include_level--;
2899
2900 return result;
2901}
2902
2903
2904static 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)
2905{
2906 char *c;
2907 char *cur = buf;
2908 struct ast_variable *v;
2909 char exec_file[512];
2910 int object, do_exec, do_include;
2911
2912 /* Actually parse the entry */
2913 if (cur[0] == '[') {
2914 struct ast_category *newcat = NULL;
2915 char *catname;
2916
2917 /* A category header */
2918 c = strchr(cur, ']');
2919 if (!c) {
2920 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
2921 return -1;
2922 }
2923 *c++ = '\0';
2924 cur++;
2925 if (*c++ != '(')
2926 c = NULL;
2927 catname = cur;
2928 if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
2929 return -1;
2930 }
2931 (*cat)->lineno = lineno;
2932
2933 /* add comments */
2934 if (withcomments && comment_buffer && comment_buffer[0] ) {
2936 }
2937 if (withcomments && lline_buffer && lline_buffer[0] ) {
2939 }
2940 if( withcomments )
2941 CB_RESET();
2942
2943 /* If there are options or categories to inherit from, process them now */
2944 if (c) {
2945 if (!(cur = strchr(c, ')'))) {
2946 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
2947 return -1;
2948 }
2949 *cur = '\0';
2950 while ((cur = strsep(&c, ","))) {
2951 if (!strcasecmp(cur, "!")) {
2952 (*cat)->ignored = 1;
2953 } else if (!strcasecmp(cur, "+")) {
2954 *cat = category_get(cfg, catname, 1);
2955 if (!*cat) {
2956 ast_config_destroy(cfg);
2957 if (newcat)
2958 ast_category_destroy(newcat);
2959 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
2960 return -1;
2961 }
2962 if (newcat) {
2963 move_variables(newcat, *cat);
2964 ast_category_destroy(newcat);
2965 newcat = NULL;
2966 }
2967 } else {
2968 struct ast_category *base;
2969
2970 base = category_get(cfg, cur, 1);
2971 if (!base) {
2972 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
2973 return -1;
2974 }
2975 inherit_category(*cat, base);
2976 }
2977 }
2978 }
2979 if (newcat)
2980 ast_category_append(cfg, *cat);
2981 } else if (cur[0] == '#') {
2982 /* A directive */
2983 cur++;
2984 c = cur;
2985 while(*c && (*c > 32)) c++;
2986 if (*c) {
2987 *c = '\0';
2988 /* Find real argument */
2989 c = ast_skip_blanks(c + 1);
2990 if (!*c)
2991 c = NULL;
2992 } else
2993 c = NULL;
2994 do_include = !strcasecmp(cur, "include");
2995 if(!do_include)
2996 do_exec = !strcasecmp(cur, "exec");
2997 else
2998 do_exec = 0;
2999 if (do_exec && !ast_opt_exec_includes) {
3000 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
3001 do_exec = 0;
3002 }
3003 if (do_include || do_exec) {
3004 if (c) {
3005 char *cur2;
3006 char real_inclusion_name[525];
3007
3008 /* Strip off leading and trailing "'s and <>'s */
3009 while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
3010 /* Get rid of leading mess */
3011 cur = c;
3012 cur2 = cur;
3013 while (!ast_strlen_zero(cur)) {
3014 c = cur + strlen(cur) - 1;
3015 if ((*c == '>') || (*c == '<') || (*c == '\"'))
3016 *c = '\0';
3017 else
3018 break;
3019 }
3020 /* #exec </path/to/executable>
3021 We create a tmp file, then we #include it, then we delete it. */
3022 if (do_exec) {
3023 char cmd[1024];
3024
3025 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
3026 if (snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file) >= sizeof(cmd)) {
3027 ast_log(LOG_ERROR, "Failed to construct command string to execute %s.\n", cur);
3028
3029 return -1;
3030 }
3031 ast_safe_system(cmd);
3032 cur = exec_file;
3033 } else
3034 exec_file[0] = '\0';
3035 /* A #include */
3036 /* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
3037
3038 /* record this inclusion */
3039 ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
3040
3041 do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
3042 if(!ast_strlen_zero(exec_file))
3043 unlink(exec_file);
3044 if(!do_include)
3045 return 0;
3046 /* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
3047
3048 } else {
3049 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
3050 do_exec ? "exec" : "include",
3051 do_exec ? "/path/to/executable" : "filename",
3052 lineno,
3053 configfile);
3054 }
3055 }
3056 else
3057 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
3058 } else {
3059 /* Just a line (variable = value) */
3060 if (!*cat) {
3062 "parse error: No category context for line %d of %s\n", lineno, configfile);
3063 return -1;
3064 }
3065 c = strchr(cur, '=');
3066 if (c) {
3067 *c = 0;
3068 c++;
3069 /* Ignore > in => */
3070 if (*c== '>') {
3071 object = 1;
3072 c++;
3073 } else
3074 object = 0;
3075 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), configfile))) {
3076 v->lineno = lineno;
3077 v->object = object;
3078 /* Put and reset comments */
3079 v->blanklines = 0;
3080 ast_variable_append(*cat, v);
3081 /* add comments */
3082 if (withcomments && comment_buffer && comment_buffer[0] ) {
3084 }
3085 if (withcomments && lline_buffer && lline_buffer[0] ) {
3087 }
3088 if( withcomments )
3089 CB_RESET();
3090
3091 } else {
3092 return -1;
3093 }
3094 } else {
3095 ast_log(LOG_WARNING, "EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno, configfile);
3096 }
3097 }
3098 return 0;
3099}
3100
3101static int use_local_dir = 1;
3102
3103void localized_use_local_dir(void);
3104void localized_use_conf_dir(void);
3105
3107{
3108 use_local_dir = 1;
3109}
3110
3112{
3113 use_local_dir = 0;
3114}
3115
3116
3117static 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)
3118{
3119 char fn[256];
3120 char buf[8192];
3121 char *new_buf, *comment_p, *process_buf;
3122 FILE *f;
3123 int lineno=0;
3124 int comment = 0, nest[MAX_NESTED_COMMENTS];
3125 struct ast_category *cat = NULL;
3126 int count = 0;
3127 struct stat statbuf;
3128
3130
3131 if (filename[0] == '/') {
3132 ast_copy_string(fn, filename, sizeof(fn));
3133 } else {
3134 if (use_local_dir)
3135 snprintf(fn, sizeof(fn), "./%s", filename);
3136 else
3137 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
3138 }
3139
3140 if (withcomments && cfg && cfg->include_level < 2 ) {
3141 CB_INIT();
3142 }
3143
3144 do {
3145 if (stat(fn, &statbuf))
3146 continue;
3147
3148 if (!S_ISREG(statbuf.st_mode)) {
3149 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
3150 continue;
3151 }
3152 if (option_verbose > 1) {
3153 ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
3154 fflush(stdout);
3155 }
3156 if (!(f = fopen(fn, "r"))) {
3157 if (option_debug)
3158 ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
3159 if (option_verbose > 1)
3160 ast_verbose( "Not found (%s)\n", strerror(errno));
3161 continue;
3162 }
3163 count++;
3164 if (option_debug)
3165 ast_log(LOG_DEBUG, "Parsing %s\n", fn);
3166 if (option_verbose > 1)
3167 ast_verbose("Found\n");
3168 while(!feof(f)) {
3169 lineno++;
3170 if (fgets(buf, sizeof(buf), f)) {
3171 if ( withcomments ) {
3172 CB_ADD(lline_buffer); /* add the current lline buffer to the comment buffer */
3173 lline_buffer[0] = 0; /* erase the lline buffer */
3174 }
3175
3176 new_buf = buf;
3177 if (comment)
3178 process_buf = NULL;
3179 else
3180 process_buf = buf;
3181
3182 while ((comment_p = strchr(new_buf, COMMENT_META))) {
3183 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
3184 /* Yuck, gotta memmove */
3185 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
3186 new_buf = comment_p;
3187 } else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
3188 /* Meta-Comment start detected ";--" */
3190 *comment_p = '\0';
3191 new_buf = comment_p + 3;
3192 comment++;
3193 nest[comment-1] = lineno;
3194 } else {
3195 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
3196 }
3197 } else if ((comment_p >= new_buf + 2) &&
3198 (*(comment_p - 1) == COMMENT_TAG) &&
3199 (*(comment_p - 2) == COMMENT_TAG)) {
3200 /* Meta-Comment end detected */
3201 comment--;
3202 new_buf = comment_p + 1;
3203 if (!comment) {
3204 /* Back to non-comment now */
3205 if (process_buf) {
3206 /* Actually have to move what's left over the top, then continue */
3207 char *oldptr;
3208 oldptr = process_buf + strlen(process_buf);
3209 if ( withcomments ) {
3210 CB_ADD(";");
3211 CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
3212 }
3213
3214 memmove(oldptr, new_buf, strlen(new_buf) + 1);
3215 new_buf = oldptr;
3216 } else
3217 process_buf = new_buf;
3218 }
3219 } else {
3220 if (!comment) {
3221 /* If ; is found, and we are not nested in a comment,
3222 we immediately stop all comment processing */
3223 if ( withcomments ) {
3224 LLB_ADD(comment_p);
3225 }
3226 *comment_p = '\0';
3227 new_buf = comment_p;
3228 } else
3229 new_buf = comment_p + 1;
3230 }
3231 }
3232 if( withcomments && comment && !process_buf )
3233 {
3234 CB_ADD(buf); /* the whole line is a comment, store it */
3235 }
3236
3237 if (process_buf) {
3238 char *stripped_process_buf = ast_strip(process_buf);
3239 if (!ast_strlen_zero(stripped_process_buf)) {
3240 if (process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
3241 cfg = NULL;
3242 break;
3243 }
3244 }
3245 }
3246 }
3247 }
3248 fclose(f);
3249 } while(0);
3250 if (comment) {
3251 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
3252 }
3253 if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
3254 if (comment_buffer) {
3258 lline_buffer=0;
3261 }
3262 }
3263 if (count == 0)
3264 return NULL;
3265
3266 return cfg;
3267}
3268
3269
3270static struct ast_config *ast_config_new(void) ;
3271
3272static struct ast_config *ast_config_new(void)
3273{
3274 struct ast_config *config;
3275
3276 if ((config = ast_calloc(1, sizeof(*config))))
3277 config->max_include_level = MAX_INCLUDE_LEVEL;
3278 return config;
3279}
3280
3281struct ast_config *localized_config_load(const char *filename);
3282
3283struct ast_config *localized_config_load(const char *filename)
3284{
3285 struct ast_config *cfg;
3286 struct ast_config *result;
3287
3288 cfg = ast_config_new();
3289 if (!cfg)
3290 return NULL;
3291
3292 result = ast_config_internal_load(filename, cfg, 0, "");
3293 if (!result)
3294 ast_config_destroy(cfg);
3295
3296 return result;
3297}
3298
3299struct ast_config *localized_config_load_with_comments(const char *filename);
3300
3302{
3303 struct ast_config *cfg;
3304 struct ast_config *result;
3305
3306 cfg = ast_config_new();
3307 if (!cfg)
3308 return NULL;
3309
3310 result = ast_config_internal_load(filename, cfg, 1, "");
3311 if (!result)
3312 ast_config_destroy(cfg);
3313
3314 return result;
3315}
3316
3318{
3319 for (; cat && cat->ignored; cat = cat->next);
3320
3321 return cat;
3322}
3323
3324static char *ast_category_browse(struct ast_config *config, const char *prev)
3325{
3326 struct ast_category *cat = NULL;
3327
3328 if (prev && config->last_browse && (config->last_browse->name == prev))
3329 cat = config->last_browse->next;
3330 else if (!prev && config->root)
3331 cat = config->root;
3332 else if (prev) {
3333 for (cat = config->root; cat; cat = cat->next) {
3334 if (cat->name == prev) {
3335 cat = cat->next;
3336 break;
3337 }
3338 }
3339 if (!cat) {
3340 for (cat = config->root; cat; cat = cat->next) {
3341 if (!strcasecmp(cat->name, prev)) {
3342 cat = cat->next;
3343 break;
3344 }
3345 }
3346 }
3347 }
3348
3349 if (cat)
3350 cat = next_available_category(cat);
3351
3352 config->last_browse = cat;
3353 return (cat) ? cat->name : NULL;
3354}
3355
3356
3357
3358void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
3359
3360void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
3361{
3362 /* cast below is just to silence compiler warning about dropping "const" */
3363 cfg->current = (struct ast_category *) cat;
3364}
3365
3366/* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
3367 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
3368 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
3369 be shocked and mystified as to why things are not showing up in the files!
3370
3371 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
3372 and line number are stored for each include, plus the name of the file included, so that these statements may be
3373 included in the output files on a file_save operation.
3374
3375 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
3376 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
3377 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
3378 and a header gets added.
3379
3380 vars and category heads are output in the order they are stored in the config file. So, if the software
3381 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
3382 file/lineno data probably won't get changed.
3383
3384*/
3385
3386static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
3387{
3388 char date[256]="";
3389 time_t t;
3390 time(&t);
3391 ast_copy_string(date, ctime(&t), sizeof(date));
3392
3393 fprintf(f1, ";!\n");
3394 fprintf(f1, ";! Automatically generated configuration file\n");
3395 if (strcmp(configfile, fn))
3396 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
3397 else
3398 fprintf(f1, ";! Filename: %s\n", configfile);
3399 fprintf(f1, ";! Generator: %s\n", generator);
3400 fprintf(f1, ";! Creation Date: %s", date);
3401 fprintf(f1, ";!\n");
3402}
3403
3404static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
3405{
3406 if (!file || file[0] == 0) {
3407 if (configfile[0] == '/')
3408 ast_copy_string(fn, configfile, fn_size);
3409 else
3410 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
3411 } else if (file[0] == '/')
3412 ast_copy_string(fn, file, fn_size);
3413 else
3414 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
3415}
3416
3417int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
3418
3419int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
3420{
3421 FILE *f;
3422 char fn[256];
3423 struct ast_variable *var;
3424 struct ast_category *cat;
3425 struct ast_comment *cmt;
3426 struct ast_config_include *incl;
3427 int blanklines = 0;
3428
3429 /* reset all the output flags, in case this isn't our first time saving this data */
3430
3431 for (incl=cfg->includes; incl; incl = incl->next)
3432 incl->output = 0;
3433
3434 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
3435 are all truncated to zero bytes and have that nice header*/
3436
3437 for (incl=cfg->includes; incl; incl = incl->next)
3438 {
3439 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*/
3440 FILE *f1;
3441
3442 set_fn(fn, sizeof(fn), incl->included_file, configfile); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
3443 f1 = fopen(fn,"w");
3444 if (f1) {
3445 gen_header(f1, configfile, fn, generator);
3446 fclose(f1); /* this should zero out the file */
3447 } else {
3448 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3449 }
3450 }
3451 }
3452
3453 set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
3454#ifdef __CYGWIN__
3455 if ((f = fopen(fn, "w+"))) {
3456#else
3457 if ((f = fopen(fn, "w"))) {
3458#endif
3459 if (option_verbose > 1)
3460 ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
3461
3462 gen_header(f, configfile, fn, generator);
3463 cat = cfg->root;
3464 fclose(f);
3465
3466 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
3467 /* since each var, cat, and associated comments can come from any file, we have to be
3468 mobile, and open each file, print, and close it on an entry-by-entry basis */
3469
3470 while(cat) {
3471 set_fn(fn, sizeof(fn), cat->file, configfile);
3472 f = fopen(fn, "a");
3473 if (!f)
3474 {
3475 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3476 return -1;
3477 }
3478
3479 /* dump any includes that happen before this category header */
3480 for (incl=cfg->includes; incl; incl = incl->next) {
3481 if (strcmp(incl->include_location_file, cat->file) == 0){
3482 if (cat->lineno > incl->include_location_lineno && !incl->output) {
3483 if (incl->exec)
3484 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
3485 else
3486 fprintf(f,"#include \"%s\"\n", incl->included_file);
3487 incl->output = 1;
3488 }
3489 }
3490 }
3491
3492 /* Dump section with any appropriate comment */
3493 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
3494 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
3495 fprintf(f,"%s", cmt->cmt);
3496 }
3497 if (!cat->precomments)
3498 fprintf(f,"\n");
3499 fprintf(f, "[%s]", cat->name);
3500 for(cmt = cat->sameline; cmt; cmt=cmt->next) {
3501 fprintf(f,"%s", cmt->cmt);
3502 }
3503 if (!cat->sameline)
3504 fprintf(f,"\n");
3505 fclose(f);
3506
3507 var = cat->root;
3508 while(var) {
3509 set_fn(fn, sizeof(fn), var->file, configfile);
3510 f = fopen(fn, "a");
3511 if (!f)
3512 {
3513 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3514 return -1;
3515 }
3516
3517 /* dump any includes that happen before this category header */
3518 for (incl=cfg->includes; incl; incl = incl->next) {
3519 if (strcmp(incl->include_location_file, var->file) == 0){
3520 if (var->lineno > incl->include_location_lineno && !incl->output) {
3521 if (incl->exec)
3522 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
3523 else
3524 fprintf(f,"#include \"%s\"\n", incl->included_file);
3525 incl->output = 1;
3526 }
3527 }
3528 }
3529
3530 for (cmt = var->precomments; cmt; cmt=cmt->next) {
3531 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
3532 fprintf(f,"%s", cmt->cmt);
3533 }
3534 if (var->sameline)
3535 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
3536 else
3537 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
3538 if (var->blanklines) {
3539 blanklines = var->blanklines;
3540 while (blanklines--)
3541 fprintf(f, "\n");
3542 }
3543
3544 fclose(f);
3545
3546
3547 var = var->next;
3548 }
3549 cat = cat->next;
3550 }
3551 if ((option_verbose > 1) && !option_debug)
3552 ast_verbose("Saved\n");
3553 } else {
3554 if (option_debug)
3555 ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
3556 if (option_verbose > 1)
3557 ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
3558 return -1;
3559 }
3560
3561 /* Now, for files with trailing #include/#exec statements,
3562 we have to make sure every entry is output */
3563
3564 for (incl=cfg->includes; incl; incl = incl->next) {
3565 if (!incl->output) {
3566 /* open the respective file */
3567 set_fn(fn, sizeof(fn), incl->include_location_file, configfile);
3568 f = fopen(fn, "a");
3569 if (!f)
3570 {
3571 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
3572 return -1;
3573 }
3574
3575 /* output the respective include */
3576 if (incl->exec)
3577 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
3578 else
3579 fprintf(f,"#include \"%s\"\n", incl->included_file);
3580 fclose(f);
3581 incl->output = 1;
3582 }
3583 }
3584
3585 return 0;
3586}
3587
3588/* ================ the Line ========================================
3589 above this line, you have what you need to load a config file,
3590 and below it, you have what you need to process the extensions.conf
3591 file into the context/exten/prio stuff. They are both in one file
3592 to make things simpler */
3593
3595static struct ast_context *contexts = NULL;
3596struct ast_context;
3597struct ast_app;
3598#ifdef LOW_MEMORY
3599#define EXT_DATA_SIZE 256
3600#else
3601#define EXT_DATA_SIZE 8192
3602#endif
3603
3604#ifdef NOT_ANYMORE
3606#endif
3607
3608#define SWITCH_DATA_LENGTH 256
3609
3610static const char *ast_get_extension_app(struct ast_exten *e)
3611{
3612 return e ? e->app : NULL;
3613}
3614
3615static const char *ast_get_extension_name(struct ast_exten *exten)
3616{
3617 return exten ? exten->exten : NULL;
3618}
3619
3621
3622/*! \brief ast_change_hint: Change hint for an extension */
3623static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
3624{
3625 struct ast_hint *hint;
3626 int res = -1;
3627
3628 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3629 if (hint->exten == oe) {
3630 hint->exten = ne;
3631 res = 0;
3632 break;
3633 }
3634 }
3635
3636 return res;
3637}
3638
3639/*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
3640static int ast_add_hint(struct ast_exten *e)
3641{
3642 struct ast_hint *hint;
3643
3644 if (!e)
3645 return -1;
3646
3647
3648 /* Search if hint exists, do nothing */
3649 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3650 if (hint->exten == e) {
3651 if (option_debug > 1)
3652 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3653 return -1;
3654 }
3655 }
3656
3657 if (option_debug > 1)
3658 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3659
3660 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
3661 return -1;
3662 }
3663 /* Initialize and insert new item at the top */
3664 hint->exten = e;
3665 AST_RWLIST_INSERT_HEAD(&hints, hint, list);
3666
3667 return 0;
3668}
3669
3670/*! \brief add the extension in the priority chain.
3671 * returns 0 on success, -1 on failure
3672 */
3673static int add_pri(struct ast_context *con, struct ast_exten *tmp,
3674 struct ast_exten *el, struct ast_exten *e, int replace)
3675{
3676 struct ast_exten *ep;
3677
3678 for (ep = NULL; e ; ep = e, e = e->peer) {
3679 if (e->priority >= tmp->priority)
3680 break;
3681 }
3682 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
3683 ep->peer = tmp;
3684 return 0; /* success */
3685 }
3686 if (e->priority == tmp->priority) {
3687 /* Can't have something exactly the same. Is this a
3688 replacement? If so, replace, otherwise, bonk. */
3689 if (!replace) {
3690 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
3691 tmp->datad(tmp->data);
3692 free(tmp);
3693 return -1;
3694 }
3695 /* we are replacing e, so copy the link fields and then update
3696 * whoever pointed to e to point to us
3697 */
3698 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
3699 tmp->peer = e->peer; /* always meaningful */
3700 if (ep) /* We're in the peer list, just insert ourselves */
3701 ep->peer = tmp;
3702 else if (el) /* We're the first extension. Take over e's functions */
3703 el->next = tmp;
3704 else /* We're the very first extension. */
3705 con->root = tmp;
3706 if (tmp->priority == PRIORITY_HINT)
3707 ast_change_hint(e,tmp);
3708 /* Destroy the old one */
3709 e->datad(e->data);
3710 free(e);
3711 } else { /* Slip ourselves in just before e */
3712 tmp->peer = e;
3713 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
3714 if (ep) /* Easy enough, we're just in the peer list */
3715 ep->peer = tmp;
3716 else { /* we are the first in some peer list, so link in the ext list */
3717 if (el)
3718 el->next = tmp; /* in the middle... */
3719 else
3720 con->root = tmp; /* ... or at the head */
3721 e->next = NULL; /* e is no more at the head, so e->next must be reset */
3722 }
3723 /* And immediately return success. */
3724 if (tmp->priority == PRIORITY_HINT)
3725 ast_add_hint(tmp);
3726 }
3727 return 0;
3728}
3729
3730/*! \brief ast_remove_hint: Remove hint from extension */
3731static int ast_remove_hint(struct ast_exten *e)
3732{
3733 /* Cleanup the Notifys if hint is removed */
3734 struct ast_hint *hint;
3735 struct ast_state_cb *cblist, *cbprev;
3736 int res = -1;
3737
3738 if (!e)
3739 return -1;
3740
3742 if (hint->exten == e) {
3743 cbprev = NULL;
3744 cblist = hint->callbacks;
3745 while (cblist) {
3746 /* Notify with -1 and remove all callbacks */
3747 cbprev = cblist;
3748 cblist = cblist->next;
3749 free(cbprev);
3750 }
3751 hint->callbacks = NULL;
3753 free(hint);
3754 res = 0;
3755 break;
3756 }
3757 }
3759
3760 return res;
3761}
3762
3763static void destroy_exten(struct ast_exten *e)
3764{
3765 if (e->priority == PRIORITY_HINT)
3766 ast_remove_hint(e);
3767
3768 if (e->datad)
3769 e->datad(e->data);
3770 free(e);
3771}
3772
3773char *days[] =
3774{
3775 "sun",
3776 "mon",
3777 "tue",
3778 "wed",
3779 "thu",
3780 "fri",
3781 "sat",
3782 NULL,
3783};
3784
3785char *months[] =
3786{
3787 "jan",
3788 "feb",
3789 "mar",
3790 "apr",
3791 "may",
3792 "jun",
3793 "jul",
3794 "aug",
3795 "sep",
3796 "oct",
3797 "nov",
3798 "dec",
3799 NULL,
3800};
3801
3802int ast_build_timing(struct ast_timing *i, const char *info_in);
3803
3804int ast_build_timing(struct ast_timing *i, const char *info_in)
3805{
3806 char *info;
3807 int j, num_fields, last_sep = -1;
3808
3809 i->timezone = NULL;
3810
3811 /* Check for empty just in case */
3812 if (ast_strlen_zero(info_in)) {
3813 return 0;
3814 }
3815
3816 /* make a copy just in case we were passed a static string */
3817 info = ast_strdupa(info_in);
3818
3819 /* count the number of fields in the timespec */
3820 for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
3821 if (info[j] == '|' || info[j] == ',') {
3822 last_sep = j;
3823 num_fields++;
3824 }
3825 }
3826
3827 /* save the timezone, if it is specified */
3828 if (num_fields == 5) {
3829 i->timezone = ast_strdup(info + last_sep + 1);
3830 }
3831
3832 /* Assume everything except time */
3833 i->monthmask = 0xfff; /* 12 bits */
3834 i->daymask = 0x7fffffffU; /* 31 bits */
3835 i->dowmask = 0x7f; /* 7 bits */
3836 /* on each call, use strsep() to move info to the next argument */
3837 get_timerange(i, strsep(&info, "|,"));
3838 if (info)
3839 i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
3840 if (info)
3841 i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
3842 if (info)
3843 i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
3844 return 1;
3845}
3846
3847/*!
3848 * \brief helper functions to sort extensions and patterns in the desired way,
3849 * so that more specific patterns appear first.
3850 *
3851 * ext_cmp1 compares individual characters (or sets of), returning
3852 * an int where bits 0-7 are the ASCII code of the first char in the set,
3853 * while bit 8-15 are the cardinality of the set minus 1.
3854 * This way more specific patterns (smaller cardinality) appear first.
3855 * Wildcards have a special value, so that we can directly compare them to
3856 * sets by subtracting the two values. In particular:
3857 * 0x000xx one character, xx
3858 * 0x0yyxx yy character set starting with xx
3859 * 0x10000 '.' (one or more of anything)
3860 * 0x20000 '!' (zero or more of anything)
3861 * 0x30000 NUL (end of string)
3862 * 0x40000 error in set.
3863 * The pointer to the string is advanced according to needs.
3864 * NOTES:
3865 * 1. the empty set is equivalent to NUL.
3866 * 2. given that a full set has always 0 as the first element,
3867 * we could encode the special cases as 0xffXX where XX
3868 * is 1, 2, 3, 4 as used above.
3869 */
3870static int ext_cmp1(const char **p)
3871{
3872 uint32_t chars[8];
3873 int c, cmin = 0xff, count = 0;
3874 const char *end;
3875
3876 /* load, sign extend and advance pointer until we find
3877 * a valid character.
3878 */
3879 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
3880 ; /* ignore some characters */
3881
3882 /* always return unless we have a set of chars */
3883 switch (c) {
3884 default: /* ordinary character */
3885 return 0x0000 | (c & 0xff);
3886
3887 case 'N': /* 2..9 */
3888 return 0x0700 | '2' ;
3889
3890 case 'X': /* 0..9 */
3891 return 0x0900 | '0';
3892
3893 case 'Z': /* 1..9 */
3894 return 0x0800 | '1';
3895
3896 case '.': /* wildcard */
3897 return 0x10000;
3898
3899 case '!': /* earlymatch */
3900 return 0x20000; /* less specific than NULL */
3901
3902 case '\0': /* empty string */
3903 *p = NULL;
3904 return 0x30000;
3905
3906 case '[': /* pattern */
3907 break;
3908 }
3909 /* locate end of set */
3910 end = strchr(*p, ']');
3911
3912 if (end == NULL) {
3913 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
3914 return 0x40000; /* XXX make this entry go last... */
3915 }
3916
3917 memset(chars, '\0', sizeof(chars)); /* clear all chars in the set */
3918 for (; *p < end ; (*p)++) {
3919 unsigned char c1, c2; /* first-last char in range */
3920 c1 = (unsigned char)((*p)[0]);
3921 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
3922 c2 = (unsigned char)((*p)[2]);
3923 *p += 2; /* skip a total of 3 chars */
3924 } else /* individual character */
3925 c2 = c1;
3926 if (c1 < cmin)
3927 cmin = c1;
3928 for (; c1 <= c2; c1++) {
3929 uint32_t mask = 1 << (c1 % 32);
3930 if ( (chars[ c1 / 32 ] & mask) == 0)
3931 count += 0x100;
3932 chars[ c1 / 32 ] |= mask;
3933 }
3934 }
3935 (*p)++;
3936 return count == 0 ? 0x30000 : (count | cmin);
3937}
3938
3939/*!
3940 * \brief the full routine to compare extensions in rules.
3941 */
3942static int ext_cmp(const char *a, const char *b)
3943{
3944 /* make sure non-patterns come first.
3945 * If a is not a pattern, it either comes first or
3946 * we use strcmp to compare the strings.
3947 */
3948 int ret = 0;
3949
3950 if (a[0] != '_')
3951 return (b[0] == '_') ? -1 : strcmp(a, b);
3952
3953 /* Now we know a is a pattern; if b is not, a comes first */
3954 if (b[0] != '_')
3955 return 1;
3956#if 0 /* old mode for ext matching */
3957 return strcmp(a, b);
3958#endif
3959 /* ok we need full pattern sorting routine */
3960 while (!ret && a && b)
3961 ret = ext_cmp1(&a) - ext_cmp1(&b);
3962 if (ret == 0)
3963 return 0;
3964 else
3965 return (ret > 0) ? 1 : -1;
3966}
3967
3968/*! \brief copy a string skipping whitespace */
3969static int ext_strncpy(char *dst, const char *src, int len)
3970{
3971 int count=0;
3972
3973 while (*src && (count < len - 1)) {
3974 switch(*src) {
3975 case ' ':
3976 /* otherwise exten => [a-b],1,... doesn't work */
3977 /* case '-': */
3978 /* Ignore */
3979 break;
3980 default:
3981 *dst = *src;
3982 dst++;
3983 }
3984 src++;
3985 count++;
3986 }
3987 *dst = '\0';
3988
3989 return count;
3990}
3991
3992/*
3993 * Wrapper around _extension_match_core() to do performance measurement
3994 * using the profiling code.
3995 */
3996int ast_check_timing(const struct ast_timing *i);
3997
3998int ast_check_timing(const struct ast_timing *i)
3999{
4000 /* sorry, but this feature will NOT be available
4001 in the standalone version */
4002 return 0;
4003}
4004
4005#ifdef NOT_ANYMORE
4006static struct ast_switch *pbx_findswitch(const char *sw)
4007{
4008 struct ast_switch *asw;
4009
4011 if (!strcasecmp(asw->name, sw))
4012 break;
4013 }
4014
4015 return asw;
4016}
4017#endif
4018
4019
4020static struct ast_context *ast_walk_contexts(struct ast_context *con);
4021
4022static struct ast_context *ast_walk_contexts(struct ast_context *con)
4023{
4024 return con ? con->next : contexts;
4025}
4026
4029{
4030 return ast_walk_contexts(con);
4031}
4032
4033
4034
4035static struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
4036 struct ast_exten *exten);
4037
4039 struct ast_exten *exten)
4040{
4041 if (!exten)
4042 return con ? con->root : NULL;
4043 else
4044 return exten->next;
4045}
4046
4048 struct ast_exten *exten);
4050 struct ast_exten *exten)
4051{
4053}
4054
4055
4057 struct ast_exten *priority);
4058
4060 struct ast_exten *priority)
4061{
4062 return priority ? priority->peer : exten;
4063}
4064
4066 struct ast_exten *priority);
4068 struct ast_exten *priority)
4069{
4071}
4072
4073
4074
4075static struct ast_include *ast_walk_context_includes(struct ast_context *con,
4076 struct ast_include *inc);
4077
4079 struct ast_include *inc)
4080{
4081 if (!inc)
4082 return con ? con->includes : NULL;
4083 else
4084 return inc->next;
4085}
4086
4089{
4090 int c = 0;
4091 struct ast_include *inc = NULL;
4092
4093 while ((inc = ast_walk_context_includes(con, inc))) {
4094 c++;
4095 }
4096
4097 return c;
4098}
4099
4101 struct ast_include *inc);
4103 struct ast_include *inc)
4104{
4105 return ast_walk_context_includes(con, inc);
4106}
4107
4108static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
4109 struct ast_ignorepat *ip);
4110
4112 struct ast_ignorepat *ip)
4113{
4114 if (!ip)
4115 return con ? con->ignorepats : NULL;
4116 else
4117 return ip->next;
4118}
4119
4122{
4123 int c = 0;
4124 struct ast_ignorepat *ip = NULL;
4125
4126 while ((ip = ast_walk_context_ignorepats(con, ip))) {
4127 c++;
4128 }
4129
4130 return c;
4131}
4132
4133
4134static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
4135 struct ast_sw *sw);
4136
4138 struct ast_sw *sw)
4139{
4140 if (!sw)
4141 return con ? AST_LIST_FIRST(&con->alts) : NULL;
4142 else
4143 return AST_LIST_NEXT(sw, list);
4144}
4145
4147 struct ast_sw *sw);
4149 struct ast_sw *sw)
4150{
4151 return ast_walk_context_switches(con, sw);
4152}
4153
4156{
4157 int c = 0;
4158 struct ast_sw *sw = NULL;
4159
4160 while ((sw = ast_walk_context_switches(con, sw))) {
4161 c++;
4162 }
4163
4164 return c;
4165}
4166
4167
4168static struct ast_context *ast_context_find(const char *name);
4169
4170static struct ast_context *ast_context_find(const char *name)
4171{
4172 struct ast_context *tmp = NULL;
4173 while ( (tmp = ast_walk_contexts(tmp)) ) {
4174 if (!name || !strcasecmp(name, tmp->name))
4175 break;
4176 }
4177 return tmp;
4178}
4179
4180/*
4181 * Internal function for ast_extension_{match|close}
4182 * return 0 on no-match, 1 on match, 2 on early match.
4183 * mode is as follows:
4184 * E_MATCH success only on exact match
4185 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
4186 * E_CANMATCH either of the above.
4187 */
4188
4189static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
4190{
4191 mode &= E_MATCH_MASK; /* only consider the relevant bits */
4192
4193 if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
4194 return 1;
4195
4196 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
4197 int ld = strlen(data), lp = strlen(pattern);
4198
4199 if (lp < ld) /* pattern too short, cannot match */
4200 return 0;
4201 /* depending on the mode, accept full or partial match or both */
4202 if (mode == E_MATCH)
4203 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
4204 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
4205 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
4206 else
4207 return 0;
4208 }
4209 pattern++; /* skip leading _ */
4210 /*
4211 * XXX below we stop at '/' which is a separator for the CID info. However we should
4212 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
4213 */
4214 while (*data && *pattern && *pattern != '/') {
4215 const char *end;
4216
4217 if (*data == '-') { /* skip '-' in data (just a separator) */
4218 data++;
4219 continue;
4220 }
4221 switch (toupper(*pattern)) {
4222 case '[': /* a range */
4223 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
4224 if (end == NULL) {
4225 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
4226 return 0; /* unconditional failure */
4227 }
4228 for (pattern++; pattern != end; pattern++) {
4229 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
4230 if (*data >= pattern[0] && *data <= pattern[2])
4231 break; /* match found */
4232 else {
4233 pattern += 2; /* skip a total of 3 chars */
4234 continue;
4235 }
4236 } else if (*data == pattern[0])
4237 break; /* match found */
4238 }
4239 if (pattern == end)
4240 return 0;
4241 pattern = end; /* skip and continue */
4242 break;
4243 case 'N':
4244 if (*data < '2' || *data > '9')
4245 return 0;
4246 break;
4247 case 'X':
4248 if (*data < '0' || *data > '9')
4249 return 0;
4250 break;
4251 case 'Z':
4252 if (*data < '1' || *data > '9')
4253 return 0;
4254 break;
4255 case '.': /* Must match, even with more digits */
4256 return 1;
4257 case '!': /* Early match */
4258 return 2;
4259 case ' ':
4260 case '-': /* Ignore these in patterns */
4261 data--; /* compensate the final data++ */
4262 break;
4263 default:
4264 if (*data != *pattern)
4265 return 0;
4266 }
4267 data++;
4268 pattern++;
4269 }
4270 if (*data) /* data longer than pattern, no match */
4271 return 0;
4272 /*
4273 * match so far, but ran off the end of the data.
4274 * Depending on what is next, determine match or not.
4275 */
4276 if (*pattern == '\0' || *pattern == '/') /* exact match */
4277 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
4278 else if (*pattern == '!') /* early match */
4279 return 2;
4280 else /* partial match */
4281 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
4282}
4283
4284static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
4285{
4286 int i;
4287 i = _extension_match_core(pattern, data, mode);
4288 return i;
4289}
4290
4291static int ast_extension_match(const char *pattern, const char *data);
4292
4293static int ast_extension_match(const char *pattern, const char *data)
4294{
4295 return extension_match_core(pattern, data, E_MATCH);
4296}
4297
4298static int matchcid(const char *cidpattern, const char *callerid)
4299{
4300 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
4301 failing to get a number should count as a match, otherwise not */
4302
4303 if (ast_strlen_zero(callerid))
4304 return ast_strlen_zero(cidpattern) ? 1 : 0;
4305
4306 return ast_extension_match(cidpattern, callerid);
4307}
4308
4309static inline int include_valid(struct ast_include *i)
4310{
4311 if (!i->hastime)
4312 return 1;
4313
4314 return ast_check_timing(&(i->timing));
4315}
4316
4317
4318
4319static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
4320 struct ast_context *bypass,
4321 struct pbx_find_info *q,
4322 const char *context,
4323 const char *exten,
4324 int priority,
4325 const char *label,
4326 const char *callerid,
4327 enum ext_match_t action);
4328
4329
4330static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
4331 struct ast_context *bypass,
4332 struct pbx_find_info *q,
4333 const char *context,
4334 const char *exten,
4335 int priority,
4336 const char *label,
4337 const char *callerid,
4338 enum ext_match_t action)
4339{
4340 int x;
4341 struct ast_context *tmp;
4342 struct ast_exten *e, *eroot;
4343 struct ast_include *i;
4344
4345 if (!context) {
4346 return NULL;
4347 }
4348
4349 /* Initialize status if appropriate */
4350 if (q->stacklen == 0) {
4352 q->swo = NULL;
4353 q->data = NULL;
4354 q->foundcontext = NULL;
4355 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
4356 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
4357 return NULL;
4358 }
4359 /* Check first to see if we've already been checked */
4360 for (x = 0; x < q->stacklen; x++) {
4361 if (!strcasecmp(q->incstack[x], context))
4362 return NULL;
4363 }
4364 if (bypass) /* bypass means we only look there */
4365 tmp = bypass;
4366 else { /* look in contexts */
4367 tmp = NULL;
4368 while ((tmp = ast_walk_contexts(tmp)) ) {
4369 if (!strcmp(tmp->name, context))
4370 break;
4371 }
4372 if (!tmp)
4373 return NULL;
4374 }
4375 if (q->status < STATUS_NO_EXTENSION)
4377
4378 /* scan the list trying to match extension and CID */
4379 eroot = NULL;
4380 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
4381 int match = extension_match_core(eroot->exten, exten, action);
4382 /* 0 on fail, 1 on match, 2 on earlymatch */
4383
4384 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
4385 continue; /* keep trying */
4386 if (match == 2 && action == E_MATCHMORE) {
4387 /* We match an extension ending in '!'.
4388 * The decision in this case is final and is NULL (no match).
4389 */
4390 return NULL;
4391 }
4392 /* found entry, now look for the right priority */
4393 if (q->status < STATUS_NO_PRIORITY)
4395 e = NULL;
4396 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
4397 /* Match label or priority */
4398 if (action == E_FINDLABEL) {
4399 if (q->status < STATUS_NO_LABEL)
4401 if (label && e->label && !strcmp(label, e->label))
4402 break; /* found it */
4403 } else if (e->priority == priority) {
4404 break; /* found it */
4405 } /* else keep searching */
4406 }
4407 if (e) { /* found a valid match */
4409 q->foundcontext = context;
4410 return e;
4411 }
4412 }
4413#ifdef NOT_RIGHT_NOW
4414 /* Check alternative switches??? */
4415 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
4416 struct ast_switch *asw = pbx_findswitch(sw->name);
4417 ast_switch_f *aswf = NULL;
4418 char *datap;
4419
4420 if (!asw) {
4421 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
4422 continue;
4423 }
4424 /* No need to Substitute variables now; we shouldn't be here if there's any */
4425
4426 /* equivalent of extension_match_core() at the switch level */
4427 if (action == E_CANMATCH)
4428 aswf = asw->canmatch;
4429 else if (action == E_MATCHMORE)
4430 aswf = asw->matchmore;
4431 else /* action == E_MATCH */
4432 aswf = asw->exists;
4433 datap = sw->eval ? sw->tmpdata : sw->data;
4434 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
4435 if (res) { /* Got a match */
4436 q->swo = asw;
4437 q->data = datap;
4438 q->foundcontext = context;
4439 /* XXX keep status = STATUS_NO_CONTEXT ? */
4440 return NULL;
4441 }
4442 }
4443#endif
4444 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
4445 /* Now try any includes we have in this context */
4446 for (i = tmp->includes; i; i = i->next) {
4447 if (include_valid(i)) {
4448 if ((e = pbx_find_extension(NULL, bypass, q, i->rname, exten, priority, label, callerid, action)))
4449 return e;
4450 if (q->swo)
4451 return NULL;
4452 }
4453 }
4454 return NULL;
4455}
4456
4457struct ast_exten *localized_find_extension(struct ast_context *bypass,
4458 struct pbx_find_info *q,
4459 const char *context,
4460 const char *exten,
4461 int priority,
4462 const char *label,
4463 const char *callerid,
4464 enum ext_match_t action);
4465
4467 struct pbx_find_info *q,
4468 const char *context,
4469 const char *exten,
4470 int priority,
4471 const char *label,
4472 const char *callerid,
4473 enum ext_match_t action)
4474{
4475 return pbx_find_extension(NULL, bypass, q, context, exten, priority, label, callerid, action);
4476}
4477
4478
4479static struct ast_context *contexts;
4480AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
4481
4482static const char *ast_get_context_name(struct ast_context *con);
4483
4484static const char *ast_get_context_name(struct ast_context *con)
4485{
4486 return con ? con->name : NULL;
4487}
4488
4489/*
4490 * errno values
4491 * ENOMEM - out of memory
4492 * EBUSY - can't lock
4493 * EEXIST - already included
4494 * EINVAL - there is no existence of context for inclusion
4495 */
4496static int ast_context_add_include2(struct ast_context *con, const char *value,
4497 const char *registrar);
4498
4499static int ast_context_add_include2(struct ast_context *con, const char *value,
4500 const char *registrar)
4501{
4502 struct ast_include *new_include;
4503 char *c;
4504 struct ast_include *i, *il = NULL; /* include, include_last */
4505 int length;
4506 char *p;
4507
4508 length = sizeof(struct ast_include);
4509 length += 2 * (strlen(value) + 1);
4510
4511 /* allocate new include structure ... */
4512 if (!(new_include = ast_calloc(1, length)))
4513 return -1;
4514 /* Fill in this structure. Use 'p' for assignments, as the fields
4515 * in the structure are 'const char *'
4516 */
4517 p = new_include->stuff;
4518 new_include->name = p;
4519 strcpy(p, value);
4520 p += strlen(value) + 1;
4521 new_include->rname = p;
4522 strcpy(p, value);
4523 /* Strip off timing info, and process if it is there */
4524 if ( (c = strchr(p, '|')) || (c = strchr(p, ',')) ) {
4525 *c++ = '\0';
4526 new_include->hastime = ast_build_timing(&(new_include->timing), c);
4527 }
4528 new_include->next = NULL;
4529 new_include->registrar = registrar;
4530
4531
4532 /* ... go to last include and check if context is already included too... */
4533 for (i = con->includes; i; i = i->next) {
4534 if (!strcasecmp(i->name, new_include->name)) {
4535 free(new_include);
4536 errno = EEXIST;
4537 return -1;
4538 }
4539 il = i;
4540 }
4541
4542 /* ... include new context into context list, unlock, return */
4543 if (il)
4544 il->next = new_include;
4545 else
4546 con->includes = new_include;
4547 if (option_verbose > 2)
4548 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
4549
4550 return 0;
4551}
4552
4553int localized_context_add_include2(struct ast_context *con, const char *value,
4554 const char *registrar);
4556 const char *registrar)
4557{
4559}
4560
4561
4562
4563static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
4564
4565static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
4566{
4567 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
4568 int length;
4569 length = sizeof(struct ast_ignorepat);
4570 length += strlen(value) + 1;
4571 if (!(ignorepat = ast_calloc(1, length)))
4572 return -1;
4573 /* The cast to char * is because we need to write the initial value.
4574 * The field is not supposed to be modified otherwise
4575 */
4576 strcpy((char *)ignorepat->pattern, value);
4577 ignorepat->next = NULL;
4578 ignorepat->registrar = registrar;
4579 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
4580 ignorepatl = ignorepatc;
4581 if (!strcasecmp(ignorepatc->pattern, value)) {
4582 /* Already there */
4583 errno = EEXIST;
4584 return -1;
4585 }
4586 }
4587 if (ignorepatl)
4588 ignorepatl->next = ignorepat;
4589 else
4590 con->ignorepats = ignorepat;
4591 return 0;
4592
4593}
4594
4595int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
4596
4597int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
4598{
4600}
4601
4602
4603/*
4604 * Lock context list functions ...
4605 */
4606
4607static int ast_wrlock_contexts(void)
4608{
4609 return ast_rwlock_wrlock(&conlock);
4610}
4611
4612static int ast_unlock_contexts(void)
4613{
4614 return ast_rwlock_unlock(&conlock);
4615}
4616
4617static int ast_wrlock_context(struct ast_context *con)
4618{
4619 return ast_rwlock_wrlock(&con->lock);
4620}
4621
4622static int ast_unlock_context(struct ast_context *con)
4623{
4624 return ast_rwlock_unlock(&con->lock);
4625}
4626
4627/*
4628 * errno values
4629 * ENOMEM - out of memory
4630 * EBUSY - can't lock
4631 * EEXIST - already included
4632 * EINVAL - there is no existence of context for inclusion
4633 */
4634static int ast_context_add_switch2(struct ast_context *con, const char *value,
4635 const char *data, int eval, const char *registrar);
4636
4637static int ast_context_add_switch2(struct ast_context *con, const char *value,
4638 const char *data, int eval, const char *registrar)
4639{
4640 struct ast_sw *new_sw;
4641 struct ast_sw *i;
4642 int length;
4643 char *p;
4644
4645 length = sizeof(struct ast_sw);
4646 length += strlen(value) + 1;
4647 if (data)
4648 length += strlen(data);
4649 length++;
4650 if (eval) {
4651 /* Create buffer for evaluation of variables */
4652 length += SWITCH_DATA_LENGTH;
4653 length++;
4654 }
4655
4656 /* allocate new sw structure ... */
4657 if (!(new_sw = ast_calloc(1, length)))
4658 return -1;
4659 /* ... fill in this structure ... */
4660 p = new_sw->stuff;
4661 new_sw->name = p;
4662 strcpy(new_sw->name, value);
4663 p += strlen(value) + 1;
4664 new_sw->data = p;
4665 if (data) {
4666 strcpy(new_sw->data, data);
4667 p += strlen(data) + 1;
4668 } else {
4669 strcpy(new_sw->data, "");
4670 p++;
4671 }
4672 if (eval)
4673 new_sw->tmpdata = p;
4674 new_sw->eval = eval;
4675 new_sw->registrar = registrar;
4676
4677 /* ... go to last sw and check if context is already swd too... */
4678 AST_LIST_TRAVERSE(&con->alts, i, list) {
4679 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
4680 free(new_sw);
4681 errno = EEXIST;
4682 return -1;
4683 }
4684 }
4685
4686 /* ... sw new context into context list, unlock, return */
4687 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
4688
4689 if (option_verbose > 2)
4690 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
4691
4692 return 0;
4693}
4694
4695int localized_context_add_switch2(struct ast_context *con, const char *value,
4696 const char *data, int eval, const char *registrar);
4697
4699 const char *data, int eval, const char *registrar)
4700{
4702}
4703
4704static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
4705{
4706 struct ast_context *tmp, **loc_contexts;
4707 int length = sizeof(struct ast_context) + strlen(name) + 1;
4708
4709 if (!extcontexts) {
4711 loc_contexts = &contexts;
4712 } else
4713 loc_contexts = extcontexts;
4714
4715 for (tmp = *loc_contexts; tmp; tmp = tmp->next) {
4716 if (!strcasecmp(tmp->name, name)) {
4717 if (!existsokay) {
4718 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
4719 tmp = NULL;
4720 }
4721 if (!extcontexts)
4723 return tmp;
4724 }
4725 }
4726 if ((tmp = ast_calloc(1, length))) {
4727 ast_rwlock_init(&tmp->lock);
4728 strcpy(tmp->name, name);
4729 tmp->root = NULL;
4730 tmp->registrar = registrar;
4731 tmp->next = *loc_contexts;
4732 tmp->includes = NULL;
4733 tmp->ignorepats = NULL;
4734 *loc_contexts = tmp;
4735 if (option_debug)
4736 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
4737 if (option_verbose > 2)
4738 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
4739 }
4740
4741 if (!extcontexts)
4743 return tmp;
4744}
4745
4746/*! \brief
4747 * Main interface to add extensions to the list for out context.
4748 *
4749 * We sort extensions in order of matching preference, so that we can
4750 * stop the search as soon as we find a suitable match.
4751 * This ordering also takes care of wildcards such as '.' (meaning
4752 * "one or more of any character") and '!' (which is 'earlymatch',
4753 * meaning "zero or more of any character" but also impacts the
4754 * return value from CANMATCH and EARLYMATCH.
4755 *
4756 * The extension match rules defined in the devmeeting 2006.05.05 are
4757 * quite simple: WE SELECT THE LONGEST MATCH.
4758 * In detail, "longest" means the number of matched characters in
4759 * the extension. In case of ties (e.g. _XXX and 333) in the length
4760 * of a pattern, we give priority to entries with the smallest cardinality
4761 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4762 * while the latter has 7, etc.
4763 * In case of same cardinality, the first element in the range counts.
4764 * If we still have a tie, any final '!' will make this as a possibly
4765 * less specific pattern.
4766 *
4767 * EBUSY - can't lock
4768 * EEXIST - extension with the same priority exist and no replace is set
4769 *
4770 */
4771static int ast_add_extension2(struct ast_context *con,
4772 int replace, const char *extension, int priority, const char *label, const char *callerid,
4773 const char *application, void *data, void (*datad)(void *),
4774 const char *registrar)
4775{
4776 /*
4777 * Sort extensions (or patterns) according to the rules indicated above.
4778 * These are implemented by the function ext_cmp()).
4779 * All priorities for the same ext/pattern/cid are kept in a list,
4780 * using the 'peer' field as a link field..
4781 */
4782 struct ast_exten *tmp, *e, *el = NULL;
4783 int res;
4784 int length;
4785 char *p;
4786
4787 /* if we are adding a hint, and there are global variables, and the hint
4788 contains variable references, then expand them --- NOT In this situation!!!
4789 */
4790
4791 length = sizeof(struct ast_exten);
4792 length += strlen(extension) + 1;
4793 length += strlen(application) + 1;
4794 if (label)
4795 length += strlen(label) + 1;
4796 if (callerid)
4797 length += strlen(callerid) + 1;
4798 else
4799 length ++; /* just the '\0' */
4800
4801 /* Be optimistic: Build the extension structure first */
4802 if (datad == NULL)
4803 datad = null_datad;
4804 if (!(tmp = ast_calloc(1, length)))
4805 return -1;
4806
4807 /* use p as dst in assignments, as the fields are const char * */
4808 p = tmp->stuff;
4809 if (label) {
4810 tmp->label = p;
4811 strcpy(p, label);
4812 p += strlen(label) + 1;
4813 }
4814 tmp->exten = p;
4815 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
4816 tmp->priority = priority;
4817 tmp->cidmatch = p; /* but use p for assignments below */
4818 if (callerid) {
4819 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
4820 tmp->matchcid = 1;
4821 } else {
4822 *p++ = '\0';
4823 tmp->matchcid = 0;
4824 }
4825 tmp->app = p;
4826 strcpy(p, application);
4827 tmp->parent = con;
4828 tmp->data = data;
4829 tmp->datad = datad;
4830 tmp->registrar = registrar;
4831
4832 res = 0; /* some compilers will think it is uninitialized otherwise */
4833 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
4834 res = ext_cmp(e->exten, extension);
4835 if (res == 0) { /* extension match, now look at cidmatch */
4836 if (!e->matchcid && !tmp->matchcid)
4837 res = 0;
4838 else if (tmp->matchcid && !e->matchcid)
4839 res = 1;
4840 else if (e->matchcid && !tmp->matchcid)
4841 res = -1;
4842 else
4843 res = strcasecmp(e->cidmatch, tmp->cidmatch);
4844 }
4845 if (res >= 0)
4846 break;
4847 }
4848 if (e && res == 0) { /* exact match, insert in the pri chain */
4849 res = add_pri(con, tmp, el, e, replace);
4850 if (res < 0) {
4851 errno = EEXIST; /* XXX do we care ? */
4852 return 0; /* XXX should we return -1 maybe ? */
4853 }
4854 } else {
4855 /*
4856 * not an exact match, this is the first entry with this pattern,
4857 * so insert in the main list right before 'e' (if any)
4858 */
4859 tmp->next = e;
4860 if (el)
4861 el->next = tmp;
4862 else
4863 con->root = tmp;
4864 if (tmp->priority == PRIORITY_HINT)
4865 ast_add_hint(tmp);
4866 }
4867 if (option_debug) {
4868 if (tmp->matchcid) {
4869 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4870 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4871 } else {
4872 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
4873 tmp->exten, tmp->priority, con->name);
4874 }
4875 }
4876 if (option_verbose > 2) {
4877 if (tmp->matchcid) {
4878 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
4879 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4880 } else {
4881 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
4882 tmp->exten, tmp->priority, con->name);
4883 }
4884 }
4885 return 0;
4886}
4887
4889 int replace, const char *extension, int priority, const char *label, const char *callerid,
4890 const char *application, void *data, void (*datad)(void *),
4891 const char *registrar);
4892
4894 int replace, const char *extension, int priority, const char *label, const char *callerid,
4895 const char *application, void *data, void (*datad)(void *),
4896 const char *registrar)
4897{
4898 return ast_add_extension2(con, replace, extension, priority, label, callerid, application, data, datad, registrar);
4899}
4900
4901
4902
4903/*! \brief The return value depends on the action:
4904 *
4905 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
4906 * and return 0 on failure, -1 on match;
4907 * E_FINDLABEL maps the label to a priority, and returns
4908 * the priority on success, ... XXX
4909 * E_SPAWN, spawn an application,
4910 * and return 0 on success, -1 on failure.
4911 */
4912static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
4913 const char *context, const char *exten, int priority,
4914 const char *label, const char *callerid, enum ext_match_t action)
4915{
4916 struct ast_exten *e;
4917 int res;
4918 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
4919
4920 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
4921
4922 e = pbx_find_extension(NULL, con, &q, context, exten, priority, label, callerid, action);
4923 if (e) {
4924 if (matching_action) {
4925 return -1; /* success, we found it */
4926 } else if (action == E_FINDLABEL) { /* map the label to a priority */
4927 res = e->priority;
4928 return res; /* the priority we were looking for */
4929 } else { /* spawn */
4930
4931 /* NOT!!!!! */
4932 return 0;
4933 }
4934 } else if (q.swo) { /* not found here, but in another switch */
4935 if (matching_action)
4936 return -1;
4937 else {
4938 if (!q.swo->exec) {
4939 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
4940 res = -1;
4941 }
4942 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
4943 }
4944 } else { /* not found anywhere, see what happened */
4945 switch (q.status) {
4946 case STATUS_NO_CONTEXT:
4947 if (!matching_action)
4948 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
4949 break;
4951 if (!matching_action)
4952 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
4953 break;
4954 case STATUS_NO_PRIORITY:
4955 if (!matching_action)
4956 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
4957 break;
4958 case STATUS_NO_LABEL:
4959 if (context)
4960 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
4961 break;
4962 default:
4963 if (option_debug)
4964 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
4965 }
4966
4967 return (matching_action) ? 0 : -1;
4968 }
4969}
4970
4971static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid);
4972
4973static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
4974{
4975 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
4976}
4977
4978static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
4979{
4980 return __ast_context_create(extcontexts, name, registrar, 1);
4981}
4982
4983struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar);
4984struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
4985{
4986 return __ast_context_create(extcontexts, name, registrar, 1);
4987}
4988
4989
4990/* chopped this one off at the knees */
4991static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
4992{
4993 ast_log(LOG_ERROR, "Function %s not registered\n", function);
4994 return -1;
4995}
4996
4997/*! \brief extract offset:length from variable name.
4998 * Returns 1 if there is a offset:length part, which is
4999 * trimmed off (values go into variables)
5000 */
5001static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
5002{
5003 int parens=0;
5004
5005 *offset = 0;
5006 *length = INT_MAX;
5007 *isfunc = 0;
5008 for (; *var; var++) {
5009 if (*var == '(') {
5010 (*isfunc)++;
5011 parens++;
5012 } else if (*var == ')') {
5013 parens--;
5014 } else if (*var == ':' && parens == 0) {
5015 *var++ = '\0';
5016 sscanf(var, "%30d:%30d", offset, length);
5017 return 1; /* offset:length valid */
5018 }
5019 }
5020 return 0;
5021}
5022
5023static const char *ast_var_value(const struct ast_var_t *var)
5024{
5025 return (var ? var->value : NULL);
5026}
5027
5028/*! \brief takes a substring. It is ok to call with value == workspace.
5029 *
5030 * offset < 0 means start from the end of the string and set the beginning
5031 * to be that many characters back.
5032 * length is the length of the substring. A value less than 0 means to leave
5033 * that many off the end.
5034 * Always return a copy in workspace.
5035 */
5036static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
5037{
5038 char *ret = workspace;
5039 int lr; /* length of the input string after the copy */
5040
5041 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
5042
5043 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
5044
5045 /* Quick check if no need to do anything */
5046 if (offset == 0 && length >= lr) /* take the whole string */
5047 return ret;
5048
5049 if (offset < 0) { /* translate negative offset into positive ones */
5050 offset = lr + offset;
5051 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
5052 offset = 0;
5053 }
5054
5055 /* too large offset result in empty string so we know what to return */
5056 if (offset >= lr)
5057 return ret + lr; /* the final '\0' */
5058
5059 ret += offset; /* move to the start position */
5060 if (length >= 0 && length < lr - offset) /* truncate if necessary */
5061 ret[length] = '\0';
5062 else if (length < 0) {
5063 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
5064 ret[lr + length - offset] = '\0';
5065 else
5066 ret[0] = '\0';
5067 }
5068
5069 return ret;
5070}
5071
5072/*! \brief Support for Asterisk built-in variables in the dialplan
5073\note See also
5074 - \ref AstVar Channel variables
5075 - \ref AstCauses The HANGUPCAUSE variable
5076 */
5077static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
5078{
5079 const char not_found = '\0';
5080 char *tmpvar;
5081 const char *s; /* the result */
5082 int offset, length;
5083 int i, need_substring;
5084 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
5085
5086 /*
5087 * Make a copy of var because parse_variable_name() modifies the string.
5088 * Then if called directly, we might need to run substring() on the result;
5089 * remember this for later in 'need_substring', 'offset' and 'length'
5090 */
5091 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
5092 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
5093
5094 /*
5095 * Look first into predefined variables, then into variable lists.
5096 * Variable 's' points to the result, according to the following rules:
5097 * s == &not_found (set at the beginning) means that we did not find a
5098 * matching variable and need to look into more places.
5099 * If s != &not_found, s is a valid result string as follows:
5100 * s = NULL if the variable does not have a value;
5101 * you typically do this when looking for an unset predefined variable.
5102 * s = workspace if the result has been assembled there;
5103 * typically done when the result is built e.g. with an snprintf(),
5104 * so we don't need to do an additional copy.
5105 * s != workspace in case we have a string, that needs to be copied
5106 * (the ast_copy_string is done once for all at the end).
5107 * Typically done when the result is already available in some string.
5108 */
5109 s = &not_found; /* default value */
5110 if (s == &not_found) { /* look for more */
5111 if (!strcmp(var, "EPOCH")) {
5112 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
5113 }
5114
5115 s = workspace;
5116 }
5117 /* if not found, look into chanvars or global vars */
5118 for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
5119 struct ast_var_t *variables;
5120 if (!places[i])
5121 continue;
5122 if (places[i] == &globals)
5124 AST_LIST_TRAVERSE(places[i], variables, entries) {
5125 if (strcasecmp(ast_var_name(variables), var)==0) {
5126 s = ast_var_value(variables);
5127 break;
5128 }
5129 }
5130 if (places[i] == &globals)
5132 }
5133 if (s == &not_found || s == NULL)
5134 *ret = NULL;
5135 else {
5136 if (s != workspace)
5137 ast_copy_string(workspace, s, workspacelen);
5138 *ret = workspace;
5139 if (need_substring)
5140 *ret = substring(*ret, offset, length, workspace, workspacelen);
5141 }
5142}
5143
5144static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
5145{
5146 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
5147 zero-filled */
5148 char *cp4;
5149 const char *tmp, *whereweare;
5150 int length, offset, offset2, isfunction;
5151 char *workspace = NULL;
5152 char *ltmp = NULL, *var = NULL;
5153 char *nextvar, *nextexp, *nextthing;
5154 char *vars, *vare;
5155 int pos, brackets, needsub, len;
5156
5157 *cp2 = 0; /* just in case there's nothing to do */
5158 whereweare=tmp=cp1;
5159 while (!ast_strlen_zero(whereweare) && count) {
5160 /* Assume we're copying the whole remaining string */
5161 pos = strlen(whereweare);
5162 nextvar = NULL;
5163 nextexp = NULL;
5164 nextthing = strchr(whereweare, '$');
5165 if (nextthing) {
5166 switch (nextthing[1]) {
5167 case '{':
5168 nextvar = nextthing;
5169 pos = nextvar - whereweare;
5170 break;
5171 case '[':
5172 nextexp = nextthing;
5173 pos = nextexp - whereweare;
5174 break;
5175 }
5176 }
5177
5178 if (pos) {
5179 /* Can't copy more than 'count' bytes */
5180 if (pos > count)
5181 pos = count;
5182
5183 /* Copy that many bytes */
5184 memcpy(cp2, whereweare, pos);
5185
5186 count -= pos;
5187 cp2 += pos;
5188 whereweare += pos;
5189 *cp2 = 0;
5190 }
5191
5192 if (nextvar) {
5193 /* We have a variable. Find the start and end, and determine
5194 if we are going to have to recursively call ourselves on the
5195 contents */
5196 vars = vare = nextvar + 2;
5197 brackets = 1;
5198 needsub = 0;
5199
5200 /* Find the end of it */
5201 while (brackets && *vare) {
5202 if ((vare[0] == '$') && (vare[1] == '{')) {
5203 needsub++;
5204 } else if (vare[0] == '{') {
5205 brackets++;
5206 } else if (vare[0] == '}') {
5207 brackets--;
5208 } else if ((vare[0] == '$') && (vare[1] == '['))
5209 needsub++;
5210 vare++;
5211 }
5212 if (brackets)
5213 ast_log(LOG_NOTICE, "Error in extension logic (missing '}' in '%s')\n", cp1);
5214 len = vare - vars - 1;
5215
5216 /* Skip totally over variable string */
5217 whereweare += (len + 3);
5218
5219 if (!var)
5220 var = alloca(VAR_BUF_SIZE);
5221
5222 /* Store variable name (and truncate) */
5223 ast_copy_string(var, vars, len + 1);
5224
5225 /* Substitute if necessary */
5226 if (needsub) {
5227 if (!ltmp)
5228 ltmp = alloca(VAR_BUF_SIZE);
5229
5230 memset(ltmp, 0, VAR_BUF_SIZE);
5232 vars = ltmp;
5233 } else {
5234 vars = var;
5235 }
5236
5237 if (!workspace)
5238 workspace = alloca(VAR_BUF_SIZE);
5239
5240 workspace[0] = '\0';
5241
5242 parse_variable_name(vars, &offset, &offset2, &isfunction);
5243 if (isfunction) {
5244 /* Evaluate function */
5245 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
5246 if (option_debug)
5247 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
5248 } else {
5249 /* Retrieve variable value */
5250 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
5251 }
5252 if (cp4) {
5253 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
5254
5255 length = strlen(cp4);
5256 if (length > count)
5257 length = count;
5258 memcpy(cp2, cp4, length);
5259 count -= length;
5260 cp2 += length;
5261 *cp2 = 0;
5262 }
5263 } else if (nextexp) {
5264 /* We have an expression. Find the start and end, and determine
5265 if we are going to have to recursively call ourselves on the
5266 contents */
5267 vars = vare = nextexp + 2;
5268 brackets = 1;
5269 needsub = 0;
5270
5271 /* Find the end of it */
5272 while (brackets && *vare) {
5273 if ((vare[0] == '$') && (vare[1] == '[')) {
5274 needsub++;
5275 brackets++;
5276 vare++;
5277 } else if (vare[0] == '[') {
5278 brackets++;
5279 } else if (vare[0] == ']') {
5280 brackets--;
5281 } else if ((vare[0] == '$') && (vare[1] == '{')) {
5282 needsub++;
5283 vare++;
5284 }
5285 vare++;
5286 }
5287 if (brackets)
5288 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
5289 len = vare - vars - 1;
5290
5291 /* Skip totally over expression */
5292 whereweare += (len + 3);
5293
5294 if (!var)
5295 var = alloca(VAR_BUF_SIZE);
5296
5297 /* Store variable name (and truncate) */
5298 ast_copy_string(var, vars, len + 1);
5299
5300 /* Substitute if necessary */
5301 if (needsub) {
5302 if (!ltmp)
5303 ltmp = alloca(VAR_BUF_SIZE);
5304
5305 memset(ltmp, 0, VAR_BUF_SIZE);
5307 vars = ltmp;
5308 } else {
5309 vars = var;
5310 }
5311
5312 length = ast_expr(vars, cp2, count, NULL);
5313
5314 if (length) {
5315 if (option_debug)
5316 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
5317 count -= length;
5318 cp2 += length;
5319 *cp2 = 0;
5320 }
5321 } else
5322 break;
5323 }
5324}
5325
5326static void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
5327{
5328 pbx_substitute_variables_helper_full(c, NULL, cp1, cp2, count);
5329}
5330
5331
5332static int pbx_load_config(const char *config_file);
5333
5334static int pbx_load_config(const char *config_file)
5335{
5336 struct ast_config *cfg;
5337 char *end;
5338 char *label;
5339 char realvalue[256];
5340 int lastpri = -2;
5341 struct ast_context *con;
5342 struct ast_variable *v;
5343 const char *cxt;
5344 const char *aft;
5345
5347 if (!cfg)
5348 return 0;
5349
5350 /* Use existing config to populate the PBX table */
5351 static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
5352 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
5353 if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
5355 clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
5356
5357 if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
5359 else
5360 ast_copy_string(userscontext, "default", sizeof(userscontext));
5361
5362 for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
5363 memset(realvalue, 0, sizeof(realvalue));
5364 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5365 pbx_builtin_setvar_helper(NULL, v->name, realvalue);
5366 }
5367 for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
5368 /* All categories but "general" or "globals" are considered contexts */
5369 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
5370 continue;
5372 if (con == NULL)
5373 continue;
5374
5375 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
5376 if (!strcasecmp(v->name, "exten")) {
5377 char *tc = ast_strdup(v->value);
5378 if (tc) {
5379 int ipri = -2;
5380 char realext[256]="";
5381 char *plus, *firstp, *firstc;
5382 char *pri, *appl, *data, *cidmatch;
5383 char *stringp = tc;
5384 char *ext = strsep(&stringp, ",");
5385 if (!ext)
5386 ext="";
5387 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
5388 cidmatch = strchr(realext, '/');
5389 if (cidmatch) {
5390 *cidmatch++ = '\0';
5391 ast_shrink_phone_number(cidmatch);
5392 }
5393 pri = strsep(&stringp, ",");
5394 if (!pri)
5395 pri="";
5396 label = strchr(pri, '(');
5397 if (label) {
5398 *label++ = '\0';
5399 end = strchr(label, ')');
5400 if (end)
5401 *end = '\0';
5402 else
5403 ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
5404 }
5405 plus = strchr(pri, '+');
5406 if (plus)
5407 *plus++ = '\0';
5408 if (!strcmp(pri,"hint"))
5409 ipri=PRIORITY_HINT;
5410 else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
5411 if (lastpri > -2)
5412 ipri = lastpri + 1;
5413 else
5414 ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
5415 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
5416 if (lastpri > -2)
5417 ipri = lastpri;
5418 else
5419 ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
5420 } else if (sscanf(pri, "%30d", &ipri) != 1 &&
5421 (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
5422 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
5423 ipri = 0;
5424 }
5425 appl = S_OR(stringp, "");
5426 /* Find the first occurrence of either '(' or ',' */
5427 firstc = strchr(appl, ',');
5428 firstp = strchr(appl, '(');
5429 if (firstc && (!firstp || firstc < firstp)) {
5430 /* comma found, no parenthesis */
5431 /* or both found, but comma found first */
5432 appl = strsep(&stringp, ",");
5433 data = stringp;
5434 } else if (!firstc && !firstp) {
5435 /* Neither found */
5436 data = "";
5437 } else {
5438 /* Final remaining case is parenthesis found first */
5439 appl = strsep(&stringp, "(");
5440 data = stringp;
5441 end = strrchr(data, ')');
5442 if ((end = strrchr(data, ')'))) {
5443 *end = '\0';
5444 } else {
5445 ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
5446 }
5447 ast_process_quotes_and_slashes(data, ',', '|');
5448 }
5449
5450 if (!data)
5451 data="";
5452 appl = ast_skip_blanks(appl);
5453 if (ipri) {
5454 if (plus)
5455 ipri += atoi(plus);
5456 lastpri = ipri;
5457 if (!ast_opt_dont_warn && !strcmp(realext, "_."))
5458 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);
5459 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, global_registrar)) {
5460 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
5461 }
5462 }
5463 free(tc);
5464 }
5465 } else if (!strcasecmp(v->name, "include")) {
5466 memset(realvalue, 0, sizeof(realvalue));
5467 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5468 if (ast_context_add_include2(con, realvalue, global_registrar))
5469 ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
5470 } else if (!strcasecmp(v->name, "ignorepat")) {
5471 memset(realvalue, 0, sizeof(realvalue));
5472 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5473 if (ast_context_add_ignorepat2(con, realvalue, global_registrar))
5474 ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
5475 } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
5476 char *stringp= realvalue;
5477 char *appl, *data;
5478
5479 memset(realvalue, 0, sizeof(realvalue));
5480 if (!strcasecmp(v->name, "switch"))
5481 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
5482 else
5483 ast_copy_string(realvalue, v->value, sizeof(realvalue));
5484 appl = strsep(&stringp, "/");
5485 data = strsep(&stringp, ""); /* XXX what for ? */
5486 if (!data)
5487 data = "";
5488 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), global_registrar))
5489 ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
5490 } else {
5491 ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
5492 }
5493 }
5494 }
5495 ast_config_destroy(cfg);
5496 return 1;
5497}
5498
5499static void __ast_context_destroy(struct ast_context *con, const char *registrar)
5500{
5501 struct ast_context *tmp, *tmpl=NULL;
5502 struct ast_include *tmpi;
5503 struct ast_sw *sw;
5504 struct ast_exten *e, *el, *en;
5505 struct ast_ignorepat *ipi;
5506
5507 for (tmp = contexts; tmp; ) {
5508 struct ast_context *next; /* next starting point */
5509 for (; tmp; tmpl = tmp, tmp = tmp->next) {
5510 if (option_debug)
5511 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
5512 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
5513 (!con || !strcasecmp(tmp->name, con->name)) )
5514 break; /* found it */
5515 }
5516 if (!tmp) /* not found, we are done */
5517 break;
5518 ast_wrlock_context(tmp);
5519 if (option_debug)
5520 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
5521 next = tmp->next;
5522 if (tmpl)
5523 tmpl->next = next;
5524 else
5525 contexts = next;
5526 /* Okay, now we're safe to let it go -- in a sense, we were
5527 ready to let it go as soon as we locked it. */
5528 ast_unlock_context(tmp);
5529 for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
5530 struct ast_include *tmpil = tmpi;
5531 tmpi = tmpi->next;
5532 free(tmpil);
5533 }
5534 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
5535 struct ast_ignorepat *ipl = ipi;
5536 ipi = ipi->next;
5537 free(ipl);
5538 }
5539 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
5540 free(sw);
5541 for (e = tmp->root; e;) {
5542 for (en = e->peer; en;) {
5543 el = en;
5544 en = en->peer;
5546 }
5547 el = e;
5548 e = e->next;
5550 }
5551 ast_rwlock_destroy(&tmp->lock);
5552 free(tmp);
5553 /* if we have a specific match, we are done, otherwise continue */
5554 tmp = con ? NULL : next;
5555 }
5556}
5557
5558void localized_context_destroy(struct ast_context *con, const char *registrar);
5559
5561{
5565}
5566
5567
5568static void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
5569{
5570 struct ast_context *tmp, *lasttmp = NULL;
5571
5572 /* it is very important that this function hold the hint list lock _and_ the conlock
5573 during its operation; not only do we need to ensure that the list of contexts
5574 and extensions does not change, but also that no hint callbacks (watchers) are
5575 added or removed during the merge/delete process
5576
5577 in addition, the locks _must_ be taken in this order, because there are already
5578 other code paths that use this order
5579 */
5581
5582 tmp = *extcontexts;
5583 if (registrar) {
5584 /* XXX remove previous contexts from same registrar */
5585 if (option_debug)
5586 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
5588 while (tmp) {
5589 lasttmp = tmp;
5590 tmp = tmp->next;
5591 }
5592 } else {
5593 /* XXX remove contexts with the same name */
5594 while (tmp) {
5595 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
5597 lasttmp = tmp;
5598 tmp = tmp->next;
5599 }
5600 }
5601 if (lasttmp) {
5602 lasttmp->next = contexts;
5603 contexts = *extcontexts;
5604 *extcontexts = NULL;
5605 } else
5606 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
5607
5609
5610 return;
5611}
5612
5613void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
5614{
5616}
5617
5619{
5620 struct ast_include *inc = NULL;
5621 int res = 0;
5622
5623 while ( (inc = ast_walk_context_includes(con, inc)) )
5624 if (!ast_context_find(inc->rname)) {
5625 res = -1;
5626 if (strcasecmp(inc->rname,"parkedcalls")!=0)
5627 ast_log(LOG_WARNING, "Context '%s' tries to include the nonexistent context '%s'\n",
5628 ast_get_context_name(con), inc->rname);
5629 }
5630 return res;
5631}
5632
5634
5636{
5637 return ast_context_verify_includes(con);
5638}
5639
5641
5643{
5644 struct ast_context *con;
5645
5647 return -1 /* AST_MODULE_LOAD_DECLINE*/;
5648
5649 /* pbx_load_users(); */ /* does this affect the dialplan? */
5650
5652
5653 for (con = NULL; (con = ast_walk_contexts(con));)
5655
5656 printf("=== Loading extensions.conf ===\n");
5657 con = 0;
5658 while ((con = ast_walk_contexts(con)) ) {
5659 printf("Context: %s\n", con->name);
5660 }
5661 printf("=========\n");
5662
5663 return 0;
5664}
5665
5666/* For platforms which don't have pthread_rwlock_timedrdlock() */
5667struct timeval ast_tvnow(void);
5668
5669struct timeval ast_tvnow(void)
5670{
5671 struct timeval t;
5672 gettimeofday(&t, NULL);
5673 return t;
5674}
#define paren
Definition: ael_lex.c:962
#define comment
Definition: ael_lex.c:965
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:1767
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.
Definition: ast_expr2f.c:2391
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:347
Asterisk main include file. File version handling, generic pbx functions.
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
#define strdup(a)
Definition: astmm.h:163
#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 HAVE_GCC_ATOMICS
Definition: autoconfig.h:310
#define SIZEOF_INT
Definition: autoconfig.h:1414
enum cc_state state
Definition: ccss.c:399
static int priority
static char * table
Definition: cdr_odbc.c:55
static const char config_file[]
Definition: cdr_odbc.c:54
static sqlite3 * db
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:2388
static const char config[]
Definition: chan_ooh323.c:111
#define ast_channel_lock(chan)
Definition: channel.h:2972
#define ast_channel_trylock(chan)
Definition: channel.h:2974
#define ast_channel_unlock(chan)
Definition: channel.h:2973
size_t current
#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:1844
static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
Definition: extconf.c:4991
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:3804
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:2613
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:2242
int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition: extconf.c:4597
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:4137
char * days[]
Definition: extconf.c:3773
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:2311
#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:1507
int localized_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Definition: extconf.c:4555
static int ext_cmp(const char *a, const char *b)
the full routine to compare extensions in rules.
Definition: extconf.c:3942
static int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
Definition: extconf.c:4637
static struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4022
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:3998
struct ast_sw * localized_walk_context_switches(struct ast_context *con, struct ast_sw *sw)
Definition: extconf.c:4148
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:2904
int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
Definition: extconf.c:2603
struct ast_context * localized_walk_contexts(struct ast_context *con)
Definition: extconf.c:4028
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: extconf.c:1821
static int ast_rwlock_unlock(ast_rwlock_t *prwlock)
Definition: extconf.c:534
int ast_language_is_prefix
The following variable controls the layout of localized sound files. If 0, use the historical layout ...
Definition: file.c:68
#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:5036
static int ast_wrlock_context(struct ast_context *con)
Definition: extconf.c:4617
#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:4102
struct ast_exten * localized_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
Definition: extconf.c:4049
pthread_mutex_t ast_mutex_t
Definition: extconf.c:465
static struct ast_context * ast_context_find(const char *name)
Definition: extconf.c:4170
static int autofallthrough_config
Definition: extconf.c:2123
#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:1771
static struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: extconf.c:1053
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:3117
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:1615
static struct ast_config * ast_config_new(void)
Definition: extconf.c:3272
static ast_rwlock_t globalslock
Definition: extconf.c:2065
struct ast_exten * localized_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4067
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:4771
static struct ast_ignorepat * ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip)
Definition: extconf.c:4111
static int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Definition: extconf.c:4499
static struct ast_context * __ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
Definition: extconf.c:4704
static void inherit_category(struct ast_category *new, const struct ast_category *base)
Definition: extconf.c:2821
static int ast_wrlock_contexts(void)
Definition: extconf.c:4607
int(* ast_state_cb_type)(char *context, char *id, enum ast_extension_states state, void *data)
Definition: extconf.c:2351
static const char * ast_get_extension_app(struct ast_exten *e)
Definition: extconf.c:3610
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: extconf.c:1974
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:2860
static void ast_category_append(struct ast_config *config, struct ast_category *category)
Definition: extconf.c:2831
#define STATUS_NO_LABEL
Definition: extconf.c:2449
#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:2447
static int ext_strncpy(char *dst, const char *src, int len)
copy a string skipping whitespace
Definition: extconf.c:3969
#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:4912
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: extconf.c:1534
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:3870
static struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
Definition: extconf.c:4038
static void __ast_context_destroy(struct ast_context *con, const char *registrar)
Definition: extconf.c:5499
static int ast_mutex_init(ast_mutex_t *pmutex)
Definition: extconf.c:469
static char * ast_process_quotes_and_slashes(char *start, char find, char replace_with)
Definition: extconf.c:2216
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:4698
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:3101
static struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Definition: extconf.c:2786
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: extconf.c:1692
int ast_context_switches_count(struct ast_context *con)
Definition: extconf.c:4155
#define ONE_MILLION
Definition: extconf.c:2259
static int include_valid(struct ast_include *i)
Definition: extconf.c:4309
static char * ast_category_browse(struct ast_config *config, const char *prev)
Definition: extconf.c:3324
static void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
Definition: extconf.c:5568
char debug_filename[AST_FILENAME_MAX]
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: extconf.c:1874
static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
Definition: extconf.c:2566
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_var_t * ast_var_assign(const char *name, const char *value)
Definition: extconf.c:2452
static struct ast_context * local_contexts
Definition: extconf.c:3594
static struct ast_category * next_available_category(struct ast_category *cat)
Definition: extconf.c:3317
static int ast_context_verify_includes(struct ast_context *con)
Definition: extconf.c:5618
static const char * ast_var_name(const struct ast_var_t *var)
Definition: extconf.c:2168
#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:2680
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:2636
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:3360
static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Definition: extconf.c:2526
static void CB_INIT(void)
Definition: extconf.c:716
@ AST_EXTENSION_REMOVED
Definition: extconf.c:2083
@ AST_EXTENSION_RINGING
Definition: extconf.c:2089
@ AST_EXTENSION_NOT_INUSE
Definition: extconf.c:2085
@ AST_EXTENSION_INUSE
Definition: extconf.c:2086
@ AST_EXTENSION_UNAVAILABLE
Definition: extconf.c:2088
@ AST_EXTENSION_ONHOLD
Definition: extconf.c:2090
@ AST_EXTENSION_BUSY
Definition: extconf.c:2087
@ AST_EXTENSION_DEACTIVATED
Definition: extconf.c:2084
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:4293
int localized_context_verify_includes(struct ast_context *con)
Definition: extconf.c:5635
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2204
struct ast_config * localized_config_load_with_comments(const char *filename)
Definition: extconf.c:3301
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Definition: extconf.c:2779
static void move_variables(struct ast_category *old, struct ast_category *new)
Definition: extconf.c:2804
static struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4059
static const char * ast_var_value(const struct ast_var_t *var)
Definition: extconf.c:5023
void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
Definition: extconf.c:5613
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:3386
static int clearglobalvars_config
Definition: extconf.c:2124
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:4484
void localized_context_destroy(struct ast_context *con, const char *registrar)
Definition: extconf.c:5560
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:3673
#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:3731
static char * comment_buffer
Definition: extconf.c:703
#define AST_RWLIST_TRAVERSE
Definition: extconf.c:1774
static void ast_category_destroy(struct ast_category *cat)
Definition: extconf.c:2843
static int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
Definition: extconf.c:544
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:5077
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2280
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:4893
char * months[]
Definition: extconf.c:3785
static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
Definition: extconf.c:5144
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:3615
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:4466
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:957
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:4978
static unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
Definition: extconf.c:2484
static ast_rwlock_t conlock
Definition: extconf.c:4480
int ast_context_ignorepats_count(struct ast_context *con)
Definition: extconf.c:4121
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2295
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:2103
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:2745
static int ast_rwlock_destroy(ast_rwlock_t *prwlock)
Definition: extconf.c:529
#define STATUS_NO_CONTEXT
Definition: extconf.c:2446
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: extconf.c:1954
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: extconf.c:2035
static int matchcid(const char *cidpattern, const char *callerid)
Definition: extconf.c:4298
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:3595
#define AST_MUTEX_KIND
Definition: extconf.c:194
static struct ast_config_map * config_maps
#define AST_RWLIST_INSERT_HEAD
Definition: extconf.c:1961
static int static_config
Definition: extconf.c:2121
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition: extconf.c:4189
static char userscontext[AST_MAX_EXTENSION]
Definition: extconf.c:2120
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: extconf.c:2014
int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
Definition: extconf.c:3419
void localized_use_conf_dir(void)
Definition: extconf.c:3111
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:4612
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:3404
int localized_pbx_load_module(void)
Definition: extconf.c:5642
int ast_context_includes_count(struct ast_context *con)
Definition: extconf.c:4088
#define STATUS_NO_PRIORITY
Definition: extconf.c:2448
static int pbx_load_config(const char *config_file)
Definition: extconf.c:5334
static int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition: extconf.c:4565
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:4622
struct ast_config * localized_config_load(const char *filename)
Definition: extconf.c:3283
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:5001
static char * global_registrar
Definition: extconf.c:2119
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:3106
#define AST_RWLIST_ENTRY
Definition: extconf.c:1697
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:2134
static struct ast_include * ast_walk_context_includes(struct ast_context *con, struct ast_include *inc)
Definition: extconf.c:4078
#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:4973
static void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Definition: extconf.c:2192
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:1455
#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:2080
static void null_datad(void *foo)
Definition: extconf.c:2740
struct timeval ast_tvnow(void)
Definition: extconf.c:5669
#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:2476
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: extconf.c:1703
#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:3623
static struct timeval tvfix(struct timeval a)
Definition: extconf.c:2264
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:4330
pid_t ast_mainpid
Definition: asterisk.c:322
#define VAR_BUF_SIZE
Definition: extconf.c:2317
static void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2469
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: extconf.c:1721
static void destroy_exten(struct ast_exten *e)
Definition: extconf.c:3763
static int ast_add_hint(struct ast_exten *e)
ast_add_hint: Add hint to hint list, check initial extension state
Definition: extconf.c:3640
struct ast_context * localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
Definition: extconf.c:4984
static char * config_filename
Definition: extconf.c:2118
struct ast_category * localized_category_get(const struct ast_config *config, const char *category_name)
Definition: extconf.c:2799
#define STATUS_SUCCESS
Definition: extconf.c:2450
static int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
Definition: extconf.c:539
static force_inline int ast_strlen_zero(const char *s)
Definition: extconf.c:950
static int ast_rwlock_init(ast_rwlock_t *prwlock)
Definition: extconf.c:516
static struct varshead globals
Definition: extconf.c:2066
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition: extconf.c:4284
#define AST_FILENAME_MAX
Definition: extconf.c:1357
#define AST_MAX_EXTENSION
Definition: extconf.c:2076
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:5326
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
Definition: logger.c:2480
pthread_rwlock_t ast_rwlock_t
Definition: extconf.c:514
static int write_protect_config
Definition: extconf.c:2122
#define ast_opt_exec_includes
Definition: extconf.c:1364
static struct ast_config_engine text_file_engine
Definition: extconf.c:2852
#define SWITCH_DATA_LENGTH
Definition: extconf.c:3608
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
#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)
Definition: func_strings.c:980
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
@ 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
void free()
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
const char * ext
Definition: http.c:150
Inlinable API function macro.
#define AST_INLINE_API(hdr, body)
Definition: inline_api.h:54
#define AST_MAX_REENTRANCY
Definition: lock.h:108
#define pthread_mutex_trylock
Definition: lock.h:634
#define pthread_mutex_lock
Definition: lock.h:632
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
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
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
def info(msg)
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
static char * registrar
Definition: pbx_ael.c:81
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
const char * description
Definition: extconf.c:2407
int(* execute)(struct ast_channel *chan, const char *data)
Definition: pbx_app.c:46
const char * synopsis
Definition: extconf.c:2406
struct ast_comment * precomments
Definition: main/config.c:237
char name[80]
Definition: main/config.c:227
struct ast_category * next
Definition: main/config.c:247
struct ast_variable * last
Definition: main/config.c:243
struct ast_variable * root
Definition: main/config.c:241
struct ast_comment * sameline
Definition: main/config.c:238
struct ast_category * prev
Definition: main/config.c:245
char * file
The file name from whence this declaration was read.
Definition: main/config.c:234
Main Channel structure associated with a channel.
char exten[AST_MAX_EXTENSION]
const char * data
char x
Definition: extconf.c:81
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
Definition: main/config.c:288
char * exec_file
if it's an exec, you'll have both the /var/tmp to read, and the original script
Definition: main/config.c:295
char * included_file
file name included
Definition: main/config.c:300
struct ast_config_include * next
Definition: main/config.c:308
const char * driver
Definition: main/config.c:206
char * driver
Definition: extconf.c:885
struct ast_config_map * next
Definition: main/config.c:201
const char * table
Definition: main/config.c:210
const char * database
Definition: main/config.c:208
char * name
Definition: extconf.c:884
char * database
Definition: extconf.c:886
const char * name
Definition: main/config.c:204
char * table
Definition: extconf.c:887
struct ast_category * current
Definition: main/config.c:255
int include_level
Definition: main/config.c:257
int max_include_level
Definition: main/config.c:258
struct ast_config_include * includes
Definition: extconf.c:916
struct ast_category * last
Definition: main/config.c:254
struct ast_category * root
Definition: main/config.c:252
struct ast_category * last_browse
Definition: main/config.c:256
ast_context: An extension context
Definition: pbx.c:299
struct ast_sws alts
Definition: pbx.c:310
struct ast_exten * root
Definition: pbx.c:304
struct ast_context::@517 alts
struct ast_ignorepats ignorepats
Definition: pbx.c:309
struct ast_includes includes
Definition: pbx.c:308
const char * registrar
Definition: pbx.c:301
char data[]
Definition: pbx.c:319
struct ast_context * next
Definition: pbx.c:307
struct ast_include * includes
Definition: extconf.c:2395
ast_rwlock_t lock
Definition: pbx.c:303
struct ast_ignorepat * ignorepats
Definition: extconf.c:2396
const char * name
Definition: pbx.c:300
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * syntax
Definition: extconf.c:2097
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:2096
const char * synopsis
Definition: extconf.c:2095
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:252
char * exten
Definition: pbx.c:253
char stuff[0]
Definition: pbx.c:272
const char * app
Definition: pbx.c:261
struct ast_app * cached_app
Definition: pbx.c:262
const char * registrar
Definition: pbx.c:268
const char * cidmatch
Definition: pbx.c:256
struct ast_context * parent
Definition: pbx.c:260
struct ast_exten * peer
Definition: pbx.c:265
void * data
Definition: pbx.c:263
struct ast_exten * next
Definition: pbx.c:271
int priority
Definition: pbx.c:258
void(* datad)(void *)
Definition: pbx.c:264
const char * label
Definition: pbx.c:259
int matchcid
Definition: pbx.c:255
Structure used to handle boolean flags.
Definition: utils.h:217
unsigned int flags
Definition: utils.h:218
Structure for dial plan hints.
Definition: pbx.c:346
int laststate
Definition: pbx.c:357
struct ao2_container * callbacks
Definition: pbx.c:354
struct ast_exten * exten
Hint extension.
Definition: pbx.c:353
struct ast_state_cb * callbacks
Definition: extconf.c:2431
ast_ignorepat: Ignore patterns in dial plan
Definition: pbx_ignorepat.c:37
const char pattern[0]
Definition: pbx_ignorepat.c:39
const char * registrar
Definition: pbx_ignorepat.c:38
struct ast_ignorepat * next
Definition: extconf.c:2386
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:2368
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: pbx.c:323
ast_state_cb_type callback
Definition: extconf.c:2418
struct ast_state_cb * next
Definition: pbx.c:335
int id
Definition: pbx.c:325
void * data
Definition: pbx.c:327
ast_sw: Switch statement in extensions.conf
Definition: pbx_sw.c:37
char stuff[0]
Definition: pbx_sw.c:45
int eval
Definition: pbx_sw.c:43
char * name
Definition: extconf.c:2374
char * tmpdata
Definition: extconf.c:2379
struct ast_sw::@386 list
const char * registrar
Definition: pbx_sw.c:40
const char * data
Definition: pbx_sw.c:42
const char * name
Definition: pbx_sw.c:38
struct ast_sw::@516 list
char * data
Definition: extconf.c:2376
struct ast_switch::@515 list
ast_switch_f * canmatch
Definition: pbx.h:167
const char * description
Definition: pbx.h:164
ast_switch_f * exists
Definition: pbx.h:166
ast_switch_f * exec
Definition: pbx.h:168
ast_switch_f * matchmore
Definition: pbx.h:169
struct ast_switch::@246 list
const char * name
Definition: pbx.h:163
unsigned int monthmask
Definition: pbx.h:174
unsigned int daymask
Definition: pbx.h:175
unsigned int minmask[48]
Definition: pbx.h:177
int hastime
Definition: pbx.h:173
char * timezone
Definition: pbx.h:178
unsigned int dowmask
Definition: pbx.h:176
char name[0]
Definition: chanvars.h:31
char * value
Definition: chanvars.h:30
struct ast_var_t::@216 entries
struct ast_var_t::@514 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.
Definition: astman.c:222
structure to hold extensions
int stacklen
Definition: extconf.h:237
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: pbx.c:6262
char * exten
Definition: pbx.c:6260
struct store_hint::@518 list
char * context
Definition: pbx.c:6259
char data[0]
Definition: pbx.c:6268
struct ast_state_cb * callbacks
Definition: extconf.c:2438
int value
Definition: syslog.c:37
static struct aco_type global
Definition: test_config.c:1445
static struct test_val b
static struct test_val a
static struct test_val c
Time-related functions and macros.