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