2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2006, Digium, Inc.
6 * Steve Murphy <murf@digium.com>
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.
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.
22 * A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
23 * for operations outside of asterisk. A huge, awful hack.
28 #include "asterisk/compat.h"
29 #include "asterisk/paths.h" /* we use AST_CONFIG_DIR */
34 #include <sys/types.h>
36 #include <sys/resource.h>
42 #if !defined(SOLARIS) && !defined(__CYGWIN__)
49 #include <sys/param.h>
50 #define ASINCLUDE_GLOB 1
51 #ifdef AST_INCLUDE_GLOB
52 #if defined(__Darwin__) || defined(__CYGWIN__)
53 #define GLOB_ABORTED GLOB_ABEND
58 #define AST_API_MODULE 1 /* gimme the inline defs! */
61 char x
; /* basically empty! */
66 #include "asterisk/inline_api.h"
67 #include "asterisk/endian.h"
68 #include "asterisk/ast_expr.h"
72 #define EVENTLOG "event_log"
73 #define QUEUELOG "queue_log"
75 #define DEBUG_M(a) { \
79 #define VERBOSE_PREFIX_1 " "
80 #define VERBOSE_PREFIX_2 " == "
81 #define VERBOSE_PREFIX_3 " -- "
82 #define VERBOSE_PREFIX_4 " > "
84 /* IN CONFLICT: void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
85 __attribute__ ((format (printf, 5, 6))); */
87 static void ast_log(int level
, const char *file
, int line
, const char *function
, const char *fmt
, ...) __attribute__ ((format (printf
,5,6)));
90 void ast_backtrace(void);
92 void ast_queue_log(const char *queuename
, const char *callid
, const char *agent
, const char *event
, const char *fmt
, ...)
93 __attribute__ ((format (printf
, 5, 6)));
95 /* IN CONFLICT: void ast_verbose(const char *fmt, ...)
96 __attribute__ ((format (printf, 1, 2))); */
98 int ast_register_verbose(void (*verboser
)(const char *string
));
99 int ast_unregister_verbose(void (*verboser
)(const char *string
));
101 void ast_console_puts(const char *string
);
103 void ast_console_puts_mutable(const char *string
);
104 void ast_console_toggle_mute(int fd
);
106 #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
111 #define __LOG_DEBUG 0
112 #define LOG_DEBUG __LOG_DEBUG, _A_
117 #define __LOG_EVENT 1
118 #define LOG_EVENT __LOG_EVENT, _A_
123 #define __LOG_NOTICE 2
124 #define LOG_NOTICE __LOG_NOTICE, _A_
129 #define __LOG_WARNING 3
130 #define LOG_WARNING __LOG_WARNING, _A_
135 #define __LOG_ERROR 4
136 #define LOG_ERROR __LOG_ERROR, _A_
141 #define __LOG_VERBOSE 5
142 #define LOG_VERBOSE __LOG_VERBOSE, _A_
148 #define LOG_DTMF __LOG_DTMF, _A_
152 #ifndef HAVE_MTX_PROFILE
153 #define __MTX_PROF(a) return pthread_mutex_lock((a))
155 #define __MTX_PROF(a) do { \
157 /* profile only non-blocking events */ \
158 ast_mark(mtx_prof, 1); \
159 i = pthread_mutex_trylock((a)); \
160 ast_mark(mtx_prof, 0); \
164 return pthread_mutex_lock((a)); \
166 #endif /* HAVE_MTX_PROFILE */
168 #define AST_PTHREADT_NULL (pthread_t) -1
169 #define AST_PTHREADT_STOP (pthread_t) -2
171 #if defined(SOLARIS) || defined(BSD)
172 #define AST_MUTEX_INIT_W_CONSTRUCTORS
173 #endif /* SOLARIS || BSD */
175 /* Asterisk REQUIRES recursive (not error checking) mutexes
176 and will not run without them. */
177 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
178 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
179 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
181 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
182 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
183 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
187 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
190 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
192 #define DO_THREAD_CRASH do { } while (0)
195 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
197 #define AST_MAX_REENTRANCY 10
199 struct ast_mutex_info
{
200 pthread_mutex_t mutex
;
201 /*! Track which thread holds this lock */
202 unsigned int track
:1;
203 const char *file
[AST_MAX_REENTRANCY
];
204 int lineno
[AST_MAX_REENTRANCY
];
206 const char *func
[AST_MAX_REENTRANCY
];
207 pthread_t thread
[AST_MAX_REENTRANCY
];
210 typedef struct ast_mutex_info ast_mutex_t
;
212 typedef pthread_cond_t ast_cond_t
;
214 static pthread_mutex_t empty_mutex
;
216 static void __attribute__((constructor
)) init_empty_mutex(void)
218 memset(&empty_mutex
, 0, sizeof(empty_mutex
));
221 static inline int __ast_pthread_mutex_init_attr(const char *filename
, int lineno
, const char *func
,
222 const char *mutex_name
, ast_mutex_t
*t
,
223 pthread_mutexattr_t
*attr
)
225 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
226 int canlog
= strcmp(filename
, "logger.c");
228 if ((t
->mutex
) != ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
229 if ((t
->mutex
) != (empty_mutex
)) {
230 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
231 filename
, lineno
, func
, mutex_name
);
232 __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
233 t
->file
[0], t
->lineno
[0], t
->func
[0], mutex_name
);
240 t
->file
[0] = filename
;
241 t
->lineno
[0] = lineno
;
246 return pthread_mutex_init(&t
->mutex
, attr
);
249 static inline int __ast_pthread_mutex_init(const char *filename
, int lineno
, const char *func
,
250 const char *mutex_name
, ast_mutex_t
*t
)
252 static pthread_mutexattr_t attr
;
254 pthread_mutexattr_init(&attr
);
255 pthread_mutexattr_settype(&attr
, AST_MUTEX_KIND
);
257 return __ast_pthread_mutex_init_attr(filename
, lineno
, func
, mutex_name
, t
, &attr
);
259 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
261 static inline int __ast_pthread_mutex_destroy(const char *filename
, int lineno
, const char *func
,
262 const char *mutex_name
, ast_mutex_t
*t
)
265 int canlog
= strcmp(filename
, "logger.c");
267 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
268 if ((t
->mutex
) == ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
269 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
270 filename
, lineno
, func
, mutex_name
);
274 res
= pthread_mutex_trylock(&t
->mutex
);
277 pthread_mutex_unlock(&t
->mutex
);
280 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
281 filename
, lineno
, func
, mutex_name
);
284 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
285 filename
, lineno
, func
, mutex_name
);
286 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
287 t
->file
[t
->reentrancy
-1], t
->lineno
[t
->reentrancy
-1], t
->func
[t
->reentrancy
-1], mutex_name
);
291 if ((res
= pthread_mutex_destroy(&t
->mutex
)))
292 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
293 filename
, lineno
, func
, strerror(res
));
294 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
296 t
->mutex
= PTHREAD_MUTEX_INIT_VALUE
;
298 t
->file
[0] = filename
;
299 t
->lineno
[0] = lineno
;
305 static inline int __ast_pthread_mutex_lock(const char *filename
, int lineno
, const char *func
,
306 const char* mutex_name
, ast_mutex_t
*t
)
309 int canlog
= strcmp(filename
, "logger.c");
311 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
312 if ((t
->mutex
) == ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
313 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
314 filename
, lineno
, func
, mutex_name
);
317 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
319 #ifdef DETECT_DEADLOCKS
321 time_t seconds
= time(NULL
);
324 #ifdef HAVE_MTX_PROFILE
325 ast_mark(mtx_prof
, 1);
327 res
= pthread_mutex_trylock(&t
->mutex
);
328 #ifdef HAVE_MTX_PROFILE
329 ast_mark(mtx_prof
, 0);
332 current
= time(NULL
);
333 if ((current
- seconds
) && (!((current
- seconds
) % 5))) {
334 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
335 filename
, lineno
, func
, (int)(current
- seconds
), mutex_name
);
336 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
337 t
->file
[t
->reentrancy
-1], t
->lineno
[t
->reentrancy
-1],
338 t
->func
[t
->reentrancy
-1], mutex_name
);
342 } while (res
== EBUSY
);
345 #ifdef HAVE_MTX_PROFILE
346 ast_mark(mtx_prof
, 1);
347 res
= pthread_mutex_trylock(&t
->mutex
);
348 ast_mark(mtx_prof
, 0);
351 res
= pthread_mutex_lock(&t
->mutex
);
352 #endif /* DETECT_DEADLOCKS */
355 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
356 t
->file
[t
->reentrancy
] = filename
;
357 t
->lineno
[t
->reentrancy
] = lineno
;
358 t
->func
[t
->reentrancy
] = func
;
359 t
->thread
[t
->reentrancy
] = pthread_self();
362 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
363 filename
, lineno
, func
, mutex_name
);
366 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
367 filename
, lineno
, func
, strerror(errno
));
374 static inline int __ast_pthread_mutex_trylock(const char *filename
, int lineno
, const char *func
,
375 const char* mutex_name
, ast_mutex_t
*t
)
378 int canlog
= strcmp(filename
, "logger.c");
380 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
381 if ((t
->mutex
) == ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
382 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
383 filename
, lineno
, func
, mutex_name
);
386 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
388 if (!(res
= pthread_mutex_trylock(&t
->mutex
))) {
389 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
390 t
->file
[t
->reentrancy
] = filename
;
391 t
->lineno
[t
->reentrancy
] = lineno
;
392 t
->func
[t
->reentrancy
] = func
;
393 t
->thread
[t
->reentrancy
] = pthread_self();
396 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
397 filename
, lineno
, func
, mutex_name
);
400 __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
401 t
->file
[t
->reentrancy
-1], t
->lineno
[t
->reentrancy
-1], t
->func
[t
->reentrancy
-1], mutex_name
);
407 static inline int __ast_pthread_mutex_unlock(const char *filename
, int lineno
, const char *func
,
408 const char *mutex_name
, ast_mutex_t
*t
)
411 int canlog
= strcmp(filename
, "logger.c");
413 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
414 if ((t
->mutex
) == ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
415 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
416 filename
, lineno
, func
, mutex_name
);
420 if (t
->reentrancy
&& (t
->thread
[t
->reentrancy
-1] != pthread_self())) {
421 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
422 filename
, lineno
, func
, mutex_name
);
423 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
424 t
->file
[t
->reentrancy
-1], t
->lineno
[t
->reentrancy
-1], t
->func
[t
->reentrancy
-1], mutex_name
);
428 if (--t
->reentrancy
< 0) {
429 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
430 filename
, lineno
, func
, mutex_name
);
434 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
435 t
->file
[t
->reentrancy
] = NULL
;
436 t
->lineno
[t
->reentrancy
] = 0;
437 t
->func
[t
->reentrancy
] = NULL
;
438 t
->thread
[t
->reentrancy
] = 0;
441 if ((res
= pthread_mutex_unlock(&t
->mutex
))) {
442 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
443 filename
, lineno
, func
, strerror(res
));
450 static inline int __ast_cond_init(const char *filename
, int lineno
, const char *func
,
451 const char *cond_name
, ast_cond_t
*cond
, pthread_condattr_t
*cond_attr
)
453 return pthread_cond_init(cond
, cond_attr
);
456 static inline int __ast_cond_signal(const char *filename
, int lineno
, const char *func
,
457 const char *cond_name
, ast_cond_t
*cond
)
459 return pthread_cond_signal(cond
);
462 static inline int __ast_cond_broadcast(const char *filename
, int lineno
, const char *func
,
463 const char *cond_name
, ast_cond_t
*cond
)
465 return pthread_cond_broadcast(cond
);
468 static inline int __ast_cond_destroy(const char *filename
, int lineno
, const char *func
,
469 const char *cond_name
, ast_cond_t
*cond
)
471 return pthread_cond_destroy(cond
);
474 static inline int __ast_cond_wait(const char *filename
, int lineno
, const char *func
,
475 const char *cond_name
, const char *mutex_name
,
476 ast_cond_t
*cond
, ast_mutex_t
*t
)
479 int canlog
= strcmp(filename
, "logger.c");
481 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
482 if ((t
->mutex
) == ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
483 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
484 filename
, lineno
, func
, mutex_name
);
488 if (t
->reentrancy
&& (t
->thread
[t
->reentrancy
-1] != pthread_self())) {
489 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
490 filename
, lineno
, func
, mutex_name
);
491 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
492 t
->file
[t
->reentrancy
-1], t
->lineno
[t
->reentrancy
-1], t
->func
[t
->reentrancy
-1], mutex_name
);
496 if (--t
->reentrancy
< 0) {
497 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
498 filename
, lineno
, func
, mutex_name
);
502 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
503 t
->file
[t
->reentrancy
] = NULL
;
504 t
->lineno
[t
->reentrancy
] = 0;
505 t
->func
[t
->reentrancy
] = NULL
;
506 t
->thread
[t
->reentrancy
] = 0;
509 if ((res
= pthread_cond_wait(cond
, &t
->mutex
))) {
510 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
511 filename
, lineno
, func
, strerror(res
));
514 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
515 t
->file
[t
->reentrancy
] = filename
;
516 t
->lineno
[t
->reentrancy
] = lineno
;
517 t
->func
[t
->reentrancy
] = func
;
518 t
->thread
[t
->reentrancy
] = pthread_self();
521 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
522 filename
, lineno
, func
, mutex_name
);
529 static inline int __ast_cond_timedwait(const char *filename
, int lineno
, const char *func
,
530 const char *cond_name
, const char *mutex_name
, ast_cond_t
*cond
,
531 ast_mutex_t
*t
, const struct timespec
*abstime
)
534 int canlog
= strcmp(filename
, "logger.c");
536 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
537 if ((t
->mutex
) == ((pthread_mutex_t
) PTHREAD_MUTEX_INITIALIZER
)) {
538 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
539 filename
, lineno
, func
, mutex_name
);
543 if (t
->reentrancy
&& (t
->thread
[t
->reentrancy
-1] != pthread_self())) {
544 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
545 filename
, lineno
, func
, mutex_name
);
546 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
547 t
->file
[t
->reentrancy
-1], t
->lineno
[t
->reentrancy
-1], t
->func
[t
->reentrancy
-1], mutex_name
);
551 if (--t
->reentrancy
< 0) {
552 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
553 filename
, lineno
, func
, mutex_name
);
557 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
558 t
->file
[t
->reentrancy
] = NULL
;
559 t
->lineno
[t
->reentrancy
] = 0;
560 t
->func
[t
->reentrancy
] = NULL
;
561 t
->thread
[t
->reentrancy
] = 0;
564 if ((res
= pthread_cond_timedwait(cond
, &t
->mutex
, abstime
)) && (res
!= ETIMEDOUT
)) {
565 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
566 filename
, lineno
, func
, strerror(res
));
569 if (t
->reentrancy
< AST_MAX_REENTRANCY
) {
570 t
->file
[t
->reentrancy
] = filename
;
571 t
->lineno
[t
->reentrancy
] = lineno
;
572 t
->func
[t
->reentrancy
] = func
;
573 t
->thread
[t
->reentrancy
] = pthread_self();
576 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
577 filename
, lineno
, func
, mutex_name
);
584 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
585 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
586 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
587 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
588 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
589 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
590 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
591 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
592 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
593 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
595 #else /* !DEBUG_THREADS */
598 typedef pthread_mutex_t ast_mutex_t
;
600 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
602 static inline int ast_mutex_init(ast_mutex_t
*pmutex
)
604 pthread_mutexattr_t attr
;
606 pthread_mutexattr_init(&attr
);
607 pthread_mutexattr_settype(&attr
, AST_MUTEX_KIND
);
609 return pthread_mutex_init(pmutex
, &attr
);
612 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
614 static inline int ast_mutex_unlock(ast_mutex_t
*pmutex
)
616 return pthread_mutex_unlock(pmutex
);
619 static inline int ast_mutex_destroy(ast_mutex_t
*pmutex
)
621 return pthread_mutex_destroy(pmutex
);
624 static inline int ast_mutex_lock(ast_mutex_t
*pmutex
)
629 static inline int ast_mutex_trylock(ast_mutex_t
*pmutex
)
631 return pthread_mutex_trylock(pmutex
);
634 typedef pthread_cond_t ast_cond_t
;
636 static inline int ast_cond_init(ast_cond_t
*cond
, pthread_condattr_t
*cond_attr
)
638 return pthread_cond_init(cond
, cond_attr
);
641 static inline int ast_cond_signal(ast_cond_t
*cond
)
643 return pthread_cond_signal(cond
);
646 static inline int ast_cond_broadcast(ast_cond_t
*cond
)
648 return pthread_cond_broadcast(cond
);
651 static inline int ast_cond_destroy(ast_cond_t
*cond
)
653 return pthread_cond_destroy(cond
);
656 static inline int ast_cond_wait(ast_cond_t
*cond
, ast_mutex_t
*t
)
658 return pthread_cond_wait(cond
, t
);
661 static inline int ast_cond_timedwait(ast_cond_t
*cond
, ast_mutex_t
*t
, const struct timespec
*abstime
)
663 return pthread_cond_timedwait(cond
, t
, abstime
);
666 #endif /* !DEBUG_THREADS */
668 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
669 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
670 constructors/destructors to create/destroy mutexes. */
671 #define __AST_MUTEX_DEFINE(scope, mutex) \
672 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
673 static void __attribute__ ((constructor)) init_##mutex(void) \
675 ast_mutex_init(&mutex); \
677 static void __attribute__ ((destructor)) fini_##mutex(void) \
679 ast_mutex_destroy(&mutex); \
681 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
682 /* By default, use static initialization of mutexes. */
683 #define __AST_MUTEX_DEFINE(scope, mutex) \
684 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
685 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
687 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
688 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
689 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
690 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
691 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
692 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
693 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
694 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
695 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
696 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
697 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
698 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
699 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
701 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
703 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
705 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
708 #define pthread_create __use_ast_pthread_create_instead__
711 typedef pthread_rwlock_t ast_rwlock_t
;
713 static inline int ast_rwlock_init(ast_rwlock_t
*prwlock
)
715 pthread_rwlockattr_t attr
;
717 pthread_rwlockattr_init(&attr
);
719 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
720 pthread_rwlockattr_setkind_np(&attr
, PTHREAD_RWLOCK_PREFER_WRITER_NP
);
723 return pthread_rwlock_init(prwlock
, &attr
);
726 static inline int ast_rwlock_destroy(ast_rwlock_t
*prwlock
)
728 return pthread_rwlock_destroy(prwlock
);
731 static inline int ast_rwlock_unlock(ast_rwlock_t
*prwlock
)
733 return pthread_rwlock_unlock(prwlock
);
736 static inline int ast_rwlock_rdlock(ast_rwlock_t
*prwlock
)
738 return pthread_rwlock_rdlock(prwlock
);
741 static inline int ast_rwlock_tryrdlock(ast_rwlock_t
*prwlock
)
743 return pthread_rwlock_tryrdlock(prwlock
);
746 static inline int ast_rwlock_wrlock(ast_rwlock_t
*prwlock
)
748 return pthread_rwlock_wrlock(prwlock
);
751 static inline int ast_rwlock_trywrlock(ast_rwlock_t
*prwlock
)
753 return pthread_rwlock_trywrlock(prwlock
);
756 /* Statically declared read/write locks */
758 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
759 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
760 scope ast_rwlock_t rwlock; \
761 static void __attribute__ ((constructor)) init_##rwlock(void) \
763 ast_rwlock_init(&rwlock); \
765 static void __attribute__ ((destructor)) fini_##rwlock(void) \
767 ast_rwlock_destroy(&rwlock); \
770 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
771 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
772 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
775 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
778 * Initial support for atomic instructions.
779 * For platforms that have it, use the native cpu instruction to
780 * implement them. For other platforms, resort to a 'slow' version
781 * (defined in utils.c) that protects the atomic instruction with
783 * The slow versions is always available, for testing purposes,
784 * as ast_atomic_fetchadd_int_slow()
787 #if defined(HAVE_OSX_ATOMICS)
788 #include "libkern/OSAtomic.h"
791 /*! \brief Atomically add v to *p and return * the previous value of *p.
792 * This can be used to handle reference counts, and the return value
793 * can be used to generate unique identifiers.
796 #if defined(HAVE_GCC_ATOMICS)
797 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p
, int v
),
799 return __sync_fetch_and_add(p
, v
);
801 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
802 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p
, int v
),
804 return OSAtomicAdd32(v
, (int32_t *) p
);
806 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
807 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p
, int v
),
809 return OSAtomicAdd64(v
, (int64_t *) p
);
810 #elif defined (__i386__) || defined(__x86_64__)
811 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p
, int v
),
814 " lock xaddl %0, %1 ; "
815 : "+r" (v
), /* 0 (result) */
821 static int ast_atomic_fetchadd_int_slow(volatile int *p
, int v
)
828 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p
, int v
),
830 return ast_atomic_fetchadd_int_slow(p
, v
);
834 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
835 * Useful e.g. to check if a refcount has reached 0.
837 #if defined(HAVE_GCC_ATOMICS)
838 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p
),
840 return __sync_sub_and_fetch(p
, 1) == 0;
842 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
843 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p
),
845 return OSAtomicAdd32( -1, (int32_t *) p
) == 0;
847 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
848 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p
),
850 return OSAtomicAdd64( -1, (int64_t *) p
) == 0;
852 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p
),
854 int a
= ast_atomic_fetchadd_int(p
, -1);
855 return a
== 1; /* true if the value is 0 now (so it was 1 previously) */
859 #ifndef DEBUG_CHANNEL_LOCKS
860 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
861 in the Makefile, print relevant output for debugging */
862 #define ast_channel_lock(x) ast_mutex_lock(&x->lock)
863 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
864 in the Makefile, print relevant output for debugging */
865 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
866 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
867 in the Makefile, print relevant output for debugging */
868 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
871 /*! \brief Lock AST channel (and print debugging output)
872 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
873 int ast_channel_lock(struct ast_channel
*chan
);
875 /*! \brief Unlock AST channel (and print debugging output)
876 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
878 int ast_channel_unlock(struct ast_channel
*chan
);
880 /*! \brief Lock AST channel (and print debugging output)
881 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
882 int ast_channel_trylock(struct ast_channel
*chan
);
886 #include "asterisk/hashtab.h"
887 #include "asterisk/ael_structs.h"
888 #include "asterisk/pval.h"
892 static unsigned int __unsigned_int_flags_dummy
;
894 struct ast_flags
{ /* stolen from utils.h */
897 #define ast_test_flag(p,flag) ({ \
898 typeof ((p)->flags) __p = (p)->flags; \
899 typeof (__unsigned_int_flags_dummy) __x = 0; \
900 (void) (&__p == &__x); \
901 ((p)->flags & (flag)); \
904 #define ast_set2_flag(p,value,flag) do { \
905 typeof ((p)->flags) __p = (p)->flags; \
906 typeof (__unsigned_int_flags_dummy) __x = 0; \
907 (void) (&__p == &__x); \
909 (p)->flags |= (flag); \
911 (p)->flags &= ~(flag); \
915 #ifdef __AST_DEBUG_MALLOC
916 static void ast_free(void *ptr
) attribute_unused
;
917 static void ast_free(void *ptr
)
922 #define ast_free free
925 #ifndef __AST_DEBUG_MALLOC
927 #define MALLOC_FAILURE_MSG \
928 ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
930 * \brief A wrapper for malloc()
932 * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
933 * message in the case that the allocation fails.
935 * The argument and return value are the same as malloc()
937 #define ast_malloc(len) \
938 _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
941 void * attribute_malloc
_ast_malloc(size_t len
, const char *file
, int lineno
, const char *func
),
945 if (!(p
= malloc(len
)))
953 * \brief A wrapper for calloc()
955 * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
956 * message in the case that the allocation fails.
958 * The arguments and return value are the same as calloc()
960 #define ast_calloc(num, len) \
961 _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
964 void * attribute_malloc
_ast_calloc(size_t num
, size_t len
, const char *file
, int lineno
, const char *func
),
968 if (!(p
= calloc(num
, len
)))
976 * \brief A wrapper for calloc() for use in cache pools
978 * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
979 * message in the case that the allocation fails. When memory debugging is in use,
980 * the memory allocated by this function will be marked as 'cache' so it can be
981 * distinguished from normal memory allocations.
983 * The arguments and return value are the same as calloc()
985 #define ast_calloc_cache(num, len) \
986 _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
989 * \brief A wrapper for realloc()
991 * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
992 * message in the case that the allocation fails.
994 * The arguments and return value are the same as realloc()
996 #define ast_realloc(p, len) \
997 _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
1000 void * attribute_malloc
_ast_realloc(void *p
, size_t len
, const char *file
, int lineno
, const char *func
),
1004 if (!(newp
= realloc(p
, len
)))
1012 * \brief A wrapper for strdup()
1014 * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
1015 * message in the case that the allocation fails.
1017 * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
1018 * argument is provided, ast_strdup will return NULL without generating any
1019 * kind of error log message.
1021 * The argument and return value are the same as strdup()
1023 #define ast_strdup(str) \
1024 _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
1027 char * attribute_malloc
_ast_strdup(const char *str
, const char *file
, int lineno
, const char *func
),
1029 char *newstr
= NULL
;
1032 if (!(newstr
= strdup(str
)))
1041 * \brief A wrapper for strndup()
1043 * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
1044 * message in the case that the allocation fails.
1046 * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
1047 * string to duplicate. If a NULL argument is provided, ast_strdup will return
1048 * NULL without generating any kind of error log message.
1050 * The arguments and return value are the same as strndup()
1052 #define ast_strndup(str, len) \
1053 _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
1056 char * attribute_malloc
_ast_strndup(const char *str
, size_t len
, const char *file
, int lineno
, const char *func
),
1058 char *newstr
= NULL
;
1061 if (!(newstr
= strndup(str
, len
)))
1070 * \brief A wrapper for asprintf()
1072 * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
1073 * message in the case that the allocation fails.
1075 * The arguments and return value are the same as asprintf()
1077 #define ast_asprintf(ret, fmt, ...) \
1078 _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
1081 __attribute__((format (printf
, 5, 6)))
1082 int _ast_asprintf(char **ret
, const char *file
, int lineno
, const char *func
, const char *fmt
, ...),
1088 if ((res
= vasprintf(ret
, fmt
, ap
)) == -1)
1097 * \brief A wrapper for vasprintf()
1099 * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
1100 * message in the case that the allocation fails.
1102 * The arguments and return value are the same as vasprintf()
1104 #define ast_vasprintf(ret, fmt, ap) \
1105 _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
1108 __attribute__((format (printf
, 5, 0)))
1109 int _ast_vasprintf(char **ret
, const char *file
, int lineno
, const char *func
, const char *fmt
, va_list ap
),
1113 if ((res
= vasprintf(ret
, fmt
, ap
)) == -1)
1122 /* If astmm is in use, let it handle these. Otherwise, it will report that
1123 all allocations are coming from this header file */
1125 #define ast_malloc(a) malloc(a)
1126 #define ast_calloc(a,b) calloc(a,b)
1127 #define ast_realloc(a,b) realloc(a,b)
1128 #define ast_strdup(a) strdup(a)
1129 #define ast_strndup(a,b) strndup(a,b)
1130 #define ast_asprintf(a,b,c) asprintf(a,b,c)
1131 #define ast_vasprintf(a,b,c) vasprintf(a,b,c)
1133 #endif /* AST_DEBUG_MALLOC */
1135 #if !defined(ast_strdupa) && defined(__GNUC__)
1137 \brief duplicate a string in memory from the stack
1138 \param s The string to duplicate
1140 This macro will duplicate the given string. It returns a pointer to the stack
1141 allocatted memory for the new string.
1143 #define ast_strdupa(s) \
1146 const char *__old = (s); \
1147 size_t __len = strlen(__old) + 1; \
1148 char *__new = __builtin_alloca(__len); \
1149 memcpy (__new, __old, __len); \
1157 #define MAX_NESTED_COMMENTS 128
1158 #define COMMENT_START ";--"
1159 #define COMMENT_END "--;"
1160 #define COMMENT_META ';'
1161 #define COMMENT_TAG '-'
1163 static char *extconfig_conf
= "extconfig.conf";
1165 /*! Growable string buffer */
1166 static char *comment_buffer
; /*!< this will be a comment collector.*/
1167 static int comment_buffer_size
; /*!< the amount of storage so far alloc'd for the comment_buffer */
1169 static char *lline_buffer
; /*!< A buffer for stuff behind the ; */
1170 static int lline_buffer_size
;
1174 struct ast_comment
{
1175 struct ast_comment
*next
;
1179 static void CB_INIT(void)
1181 if (!comment_buffer
) {
1182 comment_buffer
= ast_malloc(CB_INCR
);
1183 if (!comment_buffer
)
1185 comment_buffer
[0] = 0;
1186 comment_buffer_size
= CB_INCR
;
1187 lline_buffer
= ast_malloc(CB_INCR
);
1190 lline_buffer
[0] = 0;
1191 lline_buffer_size
= CB_INCR
;
1193 comment_buffer
[0] = 0;
1194 lline_buffer
[0] = 0;
1198 static void CB_ADD(char *str
)
1200 int rem
= comment_buffer_size
- strlen(comment_buffer
) - 1;
1201 int siz
= strlen(str
);
1203 comment_buffer
= ast_realloc(comment_buffer
, comment_buffer_size
+ CB_INCR
+ siz
+ 1);
1204 if (!comment_buffer
)
1206 comment_buffer_size
+= CB_INCR
+siz
+1;
1208 strcat(comment_buffer
,str
);
1211 static void CB_ADD_LEN(char *str
, int len
)
1213 int cbl
= strlen(comment_buffer
) + 1;
1214 int rem
= comment_buffer_size
- cbl
;
1216 comment_buffer
= ast_realloc(comment_buffer
, comment_buffer_size
+ CB_INCR
+ len
+ 1);
1217 if (!comment_buffer
)
1219 comment_buffer_size
+= CB_INCR
+len
+1;
1221 strncat(comment_buffer
,str
,len
); /* safe */
1222 comment_buffer
[cbl
+len
-1] = 0;
1225 static void LLB_ADD(char *str
)
1227 int rem
= lline_buffer_size
- strlen(lline_buffer
) - 1;
1228 int siz
= strlen(str
);
1230 lline_buffer
= ast_realloc(lline_buffer
, lline_buffer_size
+ CB_INCR
+ siz
+ 1);
1233 lline_buffer_size
+= CB_INCR
+ siz
+ 1;
1235 strcat(lline_buffer
,str
);
1238 static void CB_RESET(void )
1240 comment_buffer
[0] = 0;
1241 lline_buffer
[0] = 0;
1244 /*! \brief Keep track of how many threads are currently trying to wait*() on
1245 * a child process */
1246 static unsigned int safe_system_level
= 0;
1247 static void *safe_system_prev_handler
;
1249 /*! \brief NULL handler so we can collect the child exit status */
1250 static void null_sig_handler(int signal
)
1255 void ast_replace_sigchld(void);
1257 void ast_replace_sigchld(void)
1261 level
= safe_system_level
++;
1263 /* only replace the handler if it has not already been done */
1265 safe_system_prev_handler
= signal(SIGCHLD
, null_sig_handler
);
1269 void ast_unreplace_sigchld(void);
1271 void ast_unreplace_sigchld(void)
1275 level
= --safe_system_level
;
1277 /* only restore the handler if we are the last one */
1279 signal(SIGCHLD
, safe_system_prev_handler
);
1283 int ast_safe_system(const char *s
);
1285 int ast_safe_system(const char *s
)
1288 #ifdef HAVE_WORKING_FORK
1292 struct rusage rusage
;
1295 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1296 ast_replace_sigchld();
1298 #ifdef HAVE_WORKING_FORK
1305 #ifdef HAVE_WORKING_FORK
1306 /* Close file descriptors and launch system command */
1307 for (x
= STDERR_FILENO
+ 1; x
< 4096; x
++)
1310 execl("/bin/sh", "/bin/sh", "-c", s
, (char *) NULL
);
1312 } else if (pid
> 0) {
1314 res
= wait4(pid
, &status
, 0, &rusage
);
1316 res
= WIFEXITED(status
) ? WEXITSTATUS(status
) : -1;
1318 } else if (errno
!= EINTR
)
1322 ast_log(LOG_WARNING
, "Fork failed: %s\n", strerror(errno
));
1326 ast_unreplace_sigchld();
1334 static struct ast_comment
*ALLOC_COMMENT(const char *buffer
)
1336 struct ast_comment
*x
= ast_calloc(1,sizeof(struct ast_comment
)+strlen(buffer
)+1);
1337 strcpy(x
->cmt
, buffer
);
1341 static struct ast_config_map
{
1342 struct ast_config_map
*next
;
1348 } *config_maps
= NULL
;
1350 static struct ast_config_engine
*config_engine_list
;
1352 #define MAX_INCLUDE_LEVEL 10
1355 struct ast_category
{
1357 int ignored
; /*!< do not let user of the config see this category */
1359 char *file
; /*!< the file name from whence this declaration was read */
1361 struct ast_comment
*precomments
;
1362 struct ast_comment
*sameline
;
1363 struct ast_variable
*root
;
1364 struct ast_variable
*last
;
1365 struct ast_category
*next
;
1369 struct ast_category
*root
;
1370 struct ast_category
*last
;
1371 struct ast_category
*current
;
1372 struct ast_category
*last_browse
; /*!< used to cache the last category supplied via category_browse */
1374 int max_include_level
;
1375 struct ast_config_include
*includes
; /*!< a list of inclusions, which should describe the entire tree */
1378 struct ast_config_include
{
1379 char *include_location_file
; /*!< file name in which the include occurs */
1380 int include_location_lineno
; /*!< lineno where include occurred */
1381 int exec
; /*!< set to non-zero if itsa #exec statement */
1382 char *exec_file
; /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
1383 char *included_file
; /*!< file name included */
1384 int inclusion_count
; /*!< if the file is included more than once, a running count thereof -- but, worry not,
1385 we explode the instances and will include those-- so all entries will be unique */
1386 int output
; /*!< a flag to indicate if the inclusion has been output */
1387 struct ast_config_include
*next
; /*!< ptr to next inclusion in the list */
1390 typedef struct ast_config
*config_load_func(const char *database
, const char *table
, const char *configfile
, struct ast_config
*config
, int withcomments
, const char *suggested_include_file
);
1391 typedef struct ast_variable
*realtime_var_get(const char *database
, const char *table
, va_list ap
);
1392 typedef struct ast_config
*realtime_multi_get(const char *database
, const char *table
, va_list ap
);
1393 typedef int realtime_update(const char *database
, const char *table
, const char *keyfield
, const char *entity
, va_list ap
);
1395 /*! \brief Configuration engine structure, used to define realtime drivers */
1396 struct ast_config_engine
{
1398 config_load_func
*load_func
;
1399 realtime_var_get
*realtime_func
;
1400 realtime_multi_get
*realtime_multi_func
;
1401 realtime_update
*update_func
;
1402 struct ast_config_engine
*next
;
1405 static struct ast_config_engine
*config_engine_list
;
1407 /* taken from strings.h */
1409 static force_inline
int ast_strlen_zero(const char *s
)
1411 return (!s
|| (*s
== '\0'));
1414 #define S_OR(a, b) (!ast_strlen_zero(a) ? (a) : (b))
1417 void ast_copy_string(char *dst
, const char *src
, size_t size
),
1419 while (*src
&& size
) {
1423 if (__builtin_expect(!size
, 0))
1430 char *ast_skip_blanks(const char *str
),
1432 while (*str
&& *str
< 33)
1439 \brief Trims trailing whitespace characters from a string.
1440 \param ast_trim_blanks function being used
1441 \param str the input string
1442 \return a pointer to the modified string
1445 char *ast_trim_blanks(char *str
),
1450 work
+= strlen(work
) - 1;
1451 /* It's tempting to only want to erase after we exit this loop,
1452 but since ast_trim_blanks *could* receive a constant string
1453 (which we presumably wouldn't have to touch), we shouldn't
1454 actually set anything unless we must, and it's easier just
1455 to set each position to \0 than to keep track of a variable
1457 while ((work
>= str
) && *work
< 33)
1465 \brief Strip leading/trailing whitespace from a string.
1466 \param s The string to be stripped (will be modified).
1467 \return The stripped string.
1469 This functions strips all leading and trailing whitespace
1470 characters from the input string, and returns a pointer to
1471 the resulting string. The string is modified in place.
1474 char *ast_strip(char *s
),
1476 s
= ast_skip_blanks(s
);
1486 struct ast_variable
{
1491 int object
; /*!< 0 for variable, 1 for object */
1492 int blanklines
; /*!< Number of blanklines following entry */
1493 struct ast_comment
*precomments
;
1494 struct ast_comment
*sameline
;
1495 struct ast_variable
*next
;
1499 static const char *ast_variable_retrieve(const struct ast_config
*config
, const char *category
, const char *variable
);
1500 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
);
1502 struct ast_config
*localized_config_load_with_comments(const char *filename
);
1503 static char *ast_category_browse(struct ast_config
*config
, const char *prev
);
1504 static struct ast_variable
*ast_variable_browse(const struct ast_config
*config
, const char *category
);
1505 static void ast_variables_destroy(struct ast_variable
*v
);
1506 static void ast_config_destroy(struct ast_config
*cfg
);
1507 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
);
1508 static struct ast_config_include
*ast_include_find(struct ast_config
*conf
, const char *included_file
);
1509 void localized_ast_include_rename(struct ast_config
*conf
, const char *from_file
, const char *to_file
);
1511 static struct ast_variable
*ast_variable_new(const char *name
, const char *value
, const char *filename
);
1513 static struct ast_variable
*ast_variable_new(const char *name
, const char *value
, const char *filename
)
1515 struct ast_variable
*variable
;
1516 int name_len
= strlen(name
) + 1;
1518 if ((variable
= ast_calloc(1, name_len
+ strlen(value
) + 1 + strlen(filename
) + 1 + sizeof(*variable
)))) {
1519 variable
->name
= variable
->stuff
;
1520 variable
->value
= variable
->stuff
+ name_len
;
1521 variable
->file
= variable
->value
+ strlen(value
) + 1;
1522 strcpy(variable
->name
,name
);
1523 strcpy(variable
->value
,value
);
1524 strcpy(variable
->file
,filename
);
1530 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
)
1532 /* a file should be included ONCE. Otherwise, if one of the instances is changed,
1533 then all be changed. -- how do we know to include it? -- Handling modified
1534 instances is possible, I'd have
1535 to create a new master for each instance. */
1536 struct ast_config_include
*inc
;
1538 inc
= ast_include_find(conf
, included_file
);
1541 inc
->inclusion_count
++;
1542 snprintf(real_included_file_name
, real_included_file_name_size
, "%s~~%d", included_file
, inc
->inclusion_count
);
1543 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
);
1545 *real_included_file_name
= 0;
1547 inc
= ast_calloc(1,sizeof(struct ast_config_include
));
1548 inc
->include_location_file
= ast_strdup(from_file
);
1549 inc
->include_location_lineno
= from_lineno
;
1550 if (!ast_strlen_zero(real_included_file_name
))
1551 inc
->included_file
= ast_strdup(real_included_file_name
);
1553 inc
->included_file
= ast_strdup(included_file
);
1555 inc
->exec
= is_exec
;
1557 inc
->exec_file
= ast_strdup(exec_file
);
1559 /* attach this new struct to the conf struct */
1560 inc
->next
= conf
->includes
;
1561 conf
->includes
= inc
;
1566 void localized_ast_include_rename(struct ast_config
*conf
, const char *from_file
, const char *to_file
)
1568 struct ast_config_include
*incl
;
1569 struct ast_category
*cat
;
1570 struct ast_variable
*v
;
1572 int from_len
= strlen(from_file
);
1573 int to_len
= strlen(to_file
);
1575 if (strcmp(from_file
, to_file
) == 0) /* no use wasting time if the name is the same */
1578 /* the manager code allows you to read in one config file, then
1579 write it back out under a different name. But, the new arrangement
1580 ties output lines to the file name. So, before you try to write
1581 the config file to disk, better riffle thru the data and make sure
1582 the file names are changed.
1584 /* file names are on categories, includes (of course), and on variables. So,
1585 traverse all this and swap names */
1587 for (incl
= conf
->includes
; incl
; incl
=incl
->next
) {
1588 if (strcmp(incl
->include_location_file
,from_file
) == 0) {
1589 if (from_len
>= to_len
)
1590 strcpy(incl
->include_location_file
, to_file
);
1592 free(incl
->include_location_file
);
1593 incl
->include_location_file
= strdup(to_file
);
1597 for (cat
= conf
->root
; cat
; cat
= cat
->next
) {
1598 if (strcmp(cat
->file
,from_file
) == 0) {
1599 if (from_len
>= to_len
)
1600 strcpy(cat
->file
, to_file
);
1603 cat
->file
= strdup(to_file
);
1606 for (v
= cat
->root
; v
; v
= v
->next
) {
1607 if (strcmp(v
->file
,from_file
) == 0) {
1608 if (from_len
>= to_len
)
1609 strcpy(v
->file
, to_file
);
1612 v
->file
= strdup(to_file
);
1619 static struct ast_config_include
*ast_include_find(struct ast_config
*conf
, const char *included_file
)
1621 struct ast_config_include
*x
;
1622 for (x
=conf
->includes
;x
;x
=x
->next
)
1624 if (strcmp(x
->included_file
,included_file
) == 0)
1631 static void ast_variable_append(struct ast_category
*category
, struct ast_variable
*variable
);
1633 static void ast_variable_append(struct ast_category
*category
, struct ast_variable
*variable
)
1638 category
->last
->next
= variable
;
1640 category
->root
= variable
;
1641 category
->last
= variable
;
1642 while (category
->last
->next
)
1643 category
->last
= category
->last
->next
;
1646 static struct ast_category
*category_get(const struct ast_config
*config
, const char *category_name
, int ignored
);
1648 static struct ast_category
*category_get(const struct ast_config
*config
, const char *category_name
, int ignored
)
1650 struct ast_category
*cat
;
1652 /* try exact match first, then case-insensitive match */
1653 for (cat
= config
->root
; cat
; cat
= cat
->next
) {
1654 if (cat
->name
== category_name
&& (ignored
|| !cat
->ignored
))
1658 for (cat
= config
->root
; cat
; cat
= cat
->next
) {
1659 if (!strcasecmp(cat
->name
, category_name
) && (ignored
|| !cat
->ignored
))
1666 static struct ast_category
*ast_category_get(const struct ast_config
*config
, const char *category_name
)
1668 return category_get(config
, category_name
, 0);
1671 static struct ast_variable
*ast_variable_browse(const struct ast_config
*config
, const char *category
)
1673 struct ast_category
*cat
= NULL
;
1675 if (category
&& config
->last_browse
&& (config
->last_browse
->name
== category
))
1676 cat
= config
->last_browse
;
1678 cat
= ast_category_get(config
, category
);
1680 return (cat
) ? cat
->root
: NULL
;
1683 static const char *ast_variable_retrieve(const struct ast_config
*config
, const char *category
, const char *variable
)
1685 struct ast_variable
*v
;
1688 for (v
= ast_variable_browse(config
, category
); v
; v
= v
->next
) {
1689 if (!strcasecmp(variable
, v
->name
))
1693 struct ast_category
*cat
;
1695 for (cat
= config
->root
; cat
; cat
= cat
->next
)
1696 for (v
= cat
->root
; v
; v
= v
->next
)
1697 if (!strcasecmp(variable
, v
->name
))
1704 static struct ast_variable
*variable_clone(const struct ast_variable
*old
)
1706 struct ast_variable
*new = ast_variable_new(old
->name
, old
->value
, old
->file
);
1709 new->lineno
= old
->lineno
;
1710 new->object
= old
->object
;
1711 new->blanklines
= old
->blanklines
;
1712 /* TODO: clone comments? */
1718 static void ast_variables_destroy(struct ast_variable
*v
)
1720 struct ast_variable
*vn
;
1729 static void ast_includes_destroy(struct ast_config_include
*incls
)
1731 struct ast_config_include
*incl
,*inclnext
;
1733 for (incl
=incls
; incl
; incl
= inclnext
) {
1734 inclnext
= incl
->next
;
1735 if (incl
->include_location_file
)
1736 free(incl
->include_location_file
);
1737 if (incl
->exec_file
)
1738 free(incl
->exec_file
);
1739 if (incl
->included_file
)
1740 free(incl
->included_file
);
1745 static void ast_config_destroy(struct ast_config
*cfg
)
1747 struct ast_category
*cat
, *catn
;
1752 ast_includes_destroy(cfg
->includes
);
1756 ast_variables_destroy(cat
->root
);
1765 /* options.h declars ast_options extern; I need it static? */
1767 #define AST_CACHE_DIR_LEN 512
1768 #define AST_FILENAME_MAX 80
1770 /*! \ingroup main_options */
1771 enum ast_option_flags
{
1772 /*! Allow \#exec in config files */
1773 AST_OPT_FLAG_EXEC_INCLUDES
= (1 << 0),
1774 /*! Do not fork() */
1775 AST_OPT_FLAG_NO_FORK
= (1 << 1),
1777 AST_OPT_FLAG_QUIET
= (1 << 2),
1779 AST_OPT_FLAG_CONSOLE
= (1 << 3),
1780 /*! Run in realtime Linux priority */
1781 AST_OPT_FLAG_HIGH_PRIORITY
= (1 << 4),
1782 /*! Initialize keys for RSA authentication */
1783 AST_OPT_FLAG_INIT_KEYS
= (1 << 5),
1784 /*! Remote console */
1785 AST_OPT_FLAG_REMOTE
= (1 << 6),
1786 /*! Execute an asterisk CLI command upon startup */
1787 AST_OPT_FLAG_EXEC
= (1 << 7),
1788 /*! Don't use termcap colors */
1789 AST_OPT_FLAG_NO_COLOR
= (1 << 8),
1790 /*! Are we fully started yet? */
1791 AST_OPT_FLAG_FULLY_BOOTED
= (1 << 9),
1792 /*! Trascode via signed linear */
1793 AST_OPT_FLAG_TRANSCODE_VIA_SLIN
= (1 << 10),
1794 /*! Enable priority jumping in applications */
1795 AST_OPT_FLAG_PRIORITY_JUMPING
= (1 << 11),
1796 /*! Dump core on a seg fault */
1797 AST_OPT_FLAG_DUMP_CORE
= (1 << 12),
1798 /*! Cache sound files */
1799 AST_OPT_FLAG_CACHE_RECORD_FILES
= (1 << 13),
1800 /*! Display timestamp in CLI verbose output */
1801 AST_OPT_FLAG_TIMESTAMP
= (1 << 14),
1802 /*! Override config */
1803 AST_OPT_FLAG_OVERRIDE_CONFIG
= (1 << 15),
1805 AST_OPT_FLAG_RECONNECT
= (1 << 16),
1806 /*! Transmit Silence during Record() */
1807 AST_OPT_FLAG_TRANSMIT_SILENCE
= (1 << 17),
1808 /*! Suppress some warnings */
1809 AST_OPT_FLAG_DONT_WARN
= (1 << 18),
1810 /*! End CDRs before the 'h' extension */
1811 AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN
= (1 << 19),
1812 /*! Use DAHDI Timing for generators if available */
1813 AST_OPT_FLAG_INTERNAL_TIMING
= (1 << 20),
1814 /*! Always fork, even if verbose or debug settings are non-zero */
1815 AST_OPT_FLAG_ALWAYS_FORK
= (1 << 21),
1816 /*! Disable log/verbose output to remote consoles */
1817 AST_OPT_FLAG_MUTE
= (1 << 22)
1820 /*! These are the options that set by default when Asterisk starts */
1821 #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
1823 #define ast_opt_exec_includes ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
1824 #define ast_opt_no_fork ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
1825 #define ast_opt_quiet ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
1826 #define ast_opt_console ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
1827 #define ast_opt_high_priority ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
1828 #define ast_opt_init_keys ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
1829 #define ast_opt_remote ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
1830 #define ast_opt_exec ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
1831 #define ast_opt_no_color ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
1832 #define ast_fully_booted ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
1833 #define ast_opt_transcode_via_slin ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
1834 #define ast_opt_priority_jumping ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
1835 #define ast_opt_dump_core ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
1836 #define ast_opt_cache_record_files ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
1837 #define ast_opt_timestamp ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
1838 #define ast_opt_override_config ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
1839 #define ast_opt_reconnect ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
1840 #define ast_opt_transmit_silence ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
1841 #define ast_opt_dont_warn ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
1842 #define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
1843 #define ast_opt_internal_timing ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
1844 #define ast_opt_always_fork ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
1845 #define ast_opt_mute ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
1847 /* IN CONFLICT: extern int option_verbose; */
1848 /* IN CONFLICT: extern int option_debug; */ /*!< Debugging */
1849 extern int option_maxcalls
; /*!< Maximum number of simultaneous channels */
1850 extern double option_maxload
;
1851 extern char defaultlanguage
[];
1853 extern time_t ast_startuptime
;
1854 extern time_t ast_lastreloadtime
;
1855 extern pid_t ast_mainpid
;
1857 extern char record_cache_dir
[AST_CACHE_DIR_LEN
];
1858 extern char debug_filename
[AST_FILENAME_MAX
];
1860 extern int ast_language_is_prefix
;
1866 #define AST_LIST_LOCK(head) \
1867 ast_mutex_lock(&(head)->lock)
1870 \brief Write locks a list.
1871 \param head This is a pointer to the list head structure
1873 This macro attempts to place an exclusive write lock in the
1874 list head structure pointed to by head.
1875 Returns non-zero on success, 0 on failure
1877 #define AST_RWLIST_WRLOCK(head) \
1878 ast_rwlock_wrlock(&(head)->lock)
1881 \brief Read locks a list.
1882 \param head This is a pointer to the list head structure
1884 This macro attempts to place a read lock in the
1885 list head structure pointed to by head.
1886 Returns non-zero on success, 0 on failure
1888 #define AST_RWLIST_RDLOCK(head) \
1889 ast_rwlock_rdlock(&(head)->lock)
1892 \brief Locks a list, without blocking if the list is locked.
1893 \param head This is a pointer to the list head structure
1895 This macro attempts to place an exclusive lock in the
1896 list head structure pointed to by head.
1897 Returns non-zero on success, 0 on failure
1899 #define AST_LIST_TRYLOCK(head) \
1900 ast_mutex_trylock(&(head)->lock)
1903 \brief Write locks a list, without blocking if the list is locked.
1904 \param head This is a pointer to the list head structure
1906 This macro attempts to place an exclusive write lock in the
1907 list head structure pointed to by head.
1908 Returns non-zero on success, 0 on failure
1910 #define AST_RWLIST_TRYWRLOCK(head) \
1911 ast_rwlock_trywrlock(&(head)->lock)
1914 \brief Read locks a list, without blocking if the list is locked.
1915 \param head This is a pointer to the list head structure
1917 This macro attempts to place a read lock in the
1918 list head structure pointed to by head.
1919 Returns non-zero on success, 0 on failure
1921 #define AST_RWLIST_TRYRDLOCK(head) \
1922 ast_rwlock_tryrdlock(&(head)->lock)
1925 \brief Attempts to unlock a list.
1926 \param head This is a pointer to the list head structure
1928 This macro attempts to remove an exclusive lock from the
1929 list head structure pointed to by head. If the list
1930 was not locked by this thread, this macro has no effect.
1932 #define AST_LIST_UNLOCK(head) \
1933 ast_mutex_unlock(&(head)->lock)
1936 \brief Attempts to unlock a read/write based list.
1937 \param head This is a pointer to the list head structure
1939 This macro attempts to remove a read or write lock from the
1940 list head structure pointed to by head. If the list
1941 was not locked by this thread, this macro has no effect.
1943 #define AST_RWLIST_UNLOCK(head) \
1944 ast_rwlock_unlock(&(head)->lock)
1947 \brief Defines a structure to be used to hold a list of specified type.
1948 \param name This will be the name of the defined structure.
1949 \param type This is the type of each list entry.
1951 This macro creates a structure definition that can be used
1952 to hold a list of the entries of type \a type. It does not actually
1953 declare (allocate) a structure; to do that, either follow this
1954 macro with the desired name of the instance you wish to declare,
1955 or use the specified \a name to declare instances elsewhere.
1959 static AST_LIST_HEAD(entry_list, entry) entries;
1962 This would define \c struct \c entry_list, and declare an instance of it named
1963 \a entries, all intended to hold a list of type \c struct \c entry.
1965 #define AST_LIST_HEAD(name, type) \
1967 struct type *first; \
1968 struct type *last; \
1973 \brief Defines a structure to be used to hold a read/write list of specified type.
1974 \param name This will be the name of the defined structure.
1975 \param type This is the type of each list entry.
1977 This macro creates a structure definition that can be used
1978 to hold a list of the entries of type \a type. It does not actually
1979 declare (allocate) a structure; to do that, either follow this
1980 macro with the desired name of the instance you wish to declare,
1981 or use the specified \a name to declare instances elsewhere.
1985 static AST_RWLIST_HEAD(entry_list, entry) entries;
1988 This would define \c struct \c entry_list, and declare an instance of it named
1989 \a entries, all intended to hold a list of type \c struct \c entry.
1991 #define AST_RWLIST_HEAD(name, type) \
1993 struct type *first; \
1994 struct type *last; \
1995 ast_rwlock_t lock; \
1999 \brief Defines a structure to be used to hold a list of specified type (with no lock).
2000 \param name This will be the name of the defined structure.
2001 \param type This is the type of each list entry.
2003 This macro creates a structure definition that can be used
2004 to hold a list of the entries of type \a type. It does not actually
2005 declare (allocate) a structure; to do that, either follow this
2006 macro with the desired name of the instance you wish to declare,
2007 or use the specified \a name to declare instances elsewhere.
2011 static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
2014 This would define \c struct \c entry_list, and declare an instance of it named
2015 \a entries, all intended to hold a list of type \c struct \c entry.
2017 #define AST_LIST_HEAD_NOLOCK(name, type) \
2019 struct type *first; \
2020 struct type *last; \
2024 \brief Defines initial values for a declaration of AST_LIST_HEAD
2026 #define AST_LIST_HEAD_INIT_VALUE { \
2029 .lock = AST_MUTEX_INIT_VALUE, \
2033 \brief Defines initial values for a declaration of AST_RWLIST_HEAD
2035 #define AST_RWLIST_HEAD_INIT_VALUE { \
2038 .lock = AST_RWLOCK_INIT_VALUE, \
2042 \brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
2044 #define AST_LIST_HEAD_NOLOCK_INIT_VALUE { \
2050 \brief Defines a structure to be used to hold a list of specified type, statically initialized.
2051 \param name This will be the name of the defined structure.
2052 \param type This is the type of each list entry.
2054 This macro creates a structure definition that can be used
2055 to hold a list of the entries of type \a type, and allocates an instance
2056 of it, initialized to be empty.
2060 static AST_LIST_HEAD_STATIC(entry_list, entry);
2063 This would define \c struct \c entry_list, intended to hold a list of
2064 type \c struct \c entry.
2066 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
2067 #define AST_LIST_HEAD_STATIC(name, type) \
2069 struct type *first; \
2070 struct type *last; \
2073 static void __attribute__ ((constructor)) init_##name(void) \
2075 AST_LIST_HEAD_INIT(&name); \
2077 static void __attribute__ ((destructor)) fini_##name(void) \
2079 AST_LIST_HEAD_DESTROY(&name); \
2081 struct __dummy_##name
2083 #define AST_LIST_HEAD_STATIC(name, type) \
2085 struct type *first; \
2086 struct type *last; \
2088 } name = AST_LIST_HEAD_INIT_VALUE
2092 \brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
2093 \param name This will be the name of the defined structure.
2094 \param type This is the type of each list entry.
2096 This macro creates a structure definition that can be used
2097 to hold a list of the entries of type \a type, and allocates an instance
2098 of it, initialized to be empty.
2102 static AST_RWLIST_HEAD_STATIC(entry_list, entry);
2105 This would define \c struct \c entry_list, intended to hold a list of
2106 type \c struct \c entry.
2108 #ifndef AST_RWLOCK_INIT_VALUE
2109 #define AST_RWLIST_HEAD_STATIC(name, type) \
2111 struct type *first; \
2112 struct type *last; \
2113 ast_rwlock_t lock; \
2115 static void __attribute__ ((constructor)) init_##name(void) \
2117 AST_RWLIST_HEAD_INIT(&name); \
2119 static void __attribute__ ((destructor)) fini_##name(void) \
2121 AST_RWLIST_HEAD_DESTROY(&name); \
2123 struct __dummy_##name
2125 #define AST_RWLIST_HEAD_STATIC(name, type) \
2127 struct type *first; \
2128 struct type *last; \
2129 ast_rwlock_t lock; \
2130 } name = AST_RWLIST_HEAD_INIT_VALUE
2134 \brief Defines a structure to be used to hold a list of specified type, statically initialized.
2136 This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
2138 #define AST_LIST_HEAD_NOLOCK_STATIC(name, type) \
2140 struct type *first; \
2141 struct type *last; \
2142 } name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
2145 \brief Initializes a list head structure with a specified first entry.
2146 \param head This is a pointer to the list head structure
2147 \param entry pointer to the list entry that will become the head of the list
2149 This macro initializes a list head structure by setting the head
2150 entry to the supplied value and recreating the embedded lock.
2152 #define AST_LIST_HEAD_SET(head, entry) do { \
2153 (head)->first = (entry); \
2154 (head)->last = (entry); \
2155 ast_mutex_init(&(head)->lock); \
2159 \brief Initializes an rwlist head structure with a specified first entry.
2160 \param head This is a pointer to the list head structure
2161 \param entry pointer to the list entry that will become the head of the list
2163 This macro initializes a list head structure by setting the head
2164 entry to the supplied value and recreating the embedded lock.
2166 #define AST_RWLIST_HEAD_SET(head, entry) do { \
2167 (head)->first = (entry); \
2168 (head)->last = (entry); \
2169 ast_rwlock_init(&(head)->lock); \
2173 \brief Initializes a list head structure with a specified first entry.
2174 \param head This is a pointer to the list head structure
2175 \param entry pointer to the list entry that will become the head of the list
2177 This macro initializes a list head structure by setting the head
2178 entry to the supplied value.
2180 #define AST_LIST_HEAD_SET_NOLOCK(head, entry) do { \
2181 (head)->first = (entry); \
2182 (head)->last = (entry); \
2186 \brief Declare a forward link structure inside a list entry.
2187 \param type This is the type of each list entry.
2189 This macro declares a structure to be used to link list entries together.
2190 It must be used inside the definition of the structure named in
2191 \a type, as follows:
2196 AST_LIST_ENTRY(list_entry) list;
2200 The field name \a list here is arbitrary, and can be anything you wish.
2202 #define AST_LIST_ENTRY(type) \
2204 struct type *next; \
2207 #define AST_RWLIST_ENTRY AST_LIST_ENTRY
2210 \brief Returns the first entry contained in a list.
2211 \param head This is a pointer to the list head structure
2213 #define AST_LIST_FIRST(head) ((head)->first)
2215 #define AST_RWLIST_FIRST AST_LIST_FIRST
2218 \brief Returns the last entry contained in a list.
2219 \param head This is a pointer to the list head structure
2221 #define AST_LIST_LAST(head) ((head)->last)
2223 #define AST_RWLIST_LAST AST_LIST_LAST
2226 \brief Returns the next entry in the list after the given entry.
2227 \param elm This is a pointer to the current entry.
2228 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2229 used to link entries of this list together.
2231 #define AST_LIST_NEXT(elm, field) ((elm)->field.next)
2233 #define AST_RWLIST_NEXT AST_LIST_NEXT
2236 \brief Checks whether the specified list contains any entries.
2237 \param head This is a pointer to the list head structure
2239 Returns non-zero if the list has entries, zero if not.
2241 #define AST_LIST_EMPTY(head) (AST_LIST_FIRST(head) == NULL)
2243 #define AST_RWLIST_EMPTY AST_LIST_EMPTY
2246 \brief Loops over (traverses) the entries in a list.
2247 \param head This is a pointer to the list head structure
2248 \param var This is the name of the variable that will hold a pointer to the
2249 current list entry on each iteration. It must be declared before calling
2251 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2252 used to link entries of this list together.
2254 This macro is use to loop over (traverse) the entries in a list. It uses a
2255 \a for loop, and supplies the enclosed code with a pointer to each list
2256 entry as it loops. It is typically used as follows:
2258 static AST_LIST_HEAD(entry_list, list_entry) entries;
2262 AST_LIST_ENTRY(list_entry) list;
2265 struct list_entry *current;
2267 AST_LIST_TRAVERSE(&entries, current, list) {
2268 (do something with current here)
2271 \warning If you modify the forward-link pointer contained in the \a current entry while
2272 inside the loop, the behavior will be unpredictable. At a minimum, the following
2273 macros will modify the forward-link pointer, and should not be used inside
2274 AST_LIST_TRAVERSE() against the entry pointed to by the \a current pointer without
2275 careful consideration of their consequences:
2276 \li AST_LIST_NEXT() (when used as an lvalue)
2277 \li AST_LIST_INSERT_AFTER()
2278 \li AST_LIST_INSERT_HEAD()
2279 \li AST_LIST_INSERT_TAIL()
2281 #define AST_LIST_TRAVERSE(head,var,field) \
2282 for((var) = (head)->first; (var); (var) = (var)->field.next)
2284 #define AST_RWLIST_TRAVERSE AST_LIST_TRAVERSE
2287 \brief Loops safely over (traverses) the entries in a list.
2288 \param head This is a pointer to the list head structure
2289 \param var This is the name of the variable that will hold a pointer to the
2290 current list entry on each iteration. It must be declared before calling
2292 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2293 used to link entries of this list together.
2295 This macro is used to safely loop over (traverse) the entries in a list. It
2296 uses a \a for loop, and supplies the enclosed code with a pointer to each list
2297 entry as it loops. It is typically used as follows:
2300 static AST_LIST_HEAD(entry_list, list_entry) entries;
2304 AST_LIST_ENTRY(list_entry) list;
2307 struct list_entry *current;
2309 AST_LIST_TRAVERSE_SAFE_BEGIN(&entries, current, list) {
2310 (do something with current here)
2312 AST_LIST_TRAVERSE_SAFE_END;
2315 It differs from AST_LIST_TRAVERSE() in that the code inside the loop can modify
2316 (or even free, after calling AST_LIST_REMOVE_CURRENT()) the entry pointed to by
2317 the \a current pointer without affecting the loop traversal.
2319 #define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) { \
2320 typeof((head)->first) __list_next; \
2321 typeof((head)->first) __list_prev = NULL; \
2322 typeof((head)->first) __new_prev = NULL; \
2323 for ((var) = (head)->first, __new_prev = (var), \
2324 __list_next = (var) ? (var)->field.next : NULL; \
2326 __list_prev = __new_prev, (var) = __list_next, \
2327 __new_prev = (var), \
2328 __list_next = (var) ? (var)->field.next : NULL \
2331 #define AST_RWLIST_TRAVERSE_SAFE_BEGIN AST_LIST_TRAVERSE_SAFE_BEGIN
2334 \brief Removes the \a current entry from a list during a traversal.
2335 \param head This is a pointer to the list head structure
2336 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2337 used to link entries of this list together.
2339 \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
2340 block; it is used to unlink the current entry from the list without affecting
2341 the list traversal (and without having to re-traverse the list to modify the
2342 previous entry, if any).
2344 #define AST_LIST_REMOVE_CURRENT(head, field) \
2345 __new_prev->field.next = NULL; \
2346 __new_prev = __list_prev; \
2348 __list_prev->field.next = __list_next; \
2350 (head)->first = __list_next; \
2352 (head)->last = __list_prev;
2354 #define AST_RWLIST_REMOVE_CURRENT AST_LIST_REMOVE_CURRENT
2357 \brief Inserts a list entry before the current entry during a traversal.
2358 \param head This is a pointer to the list head structure
2359 \param elm This is a pointer to the entry to be inserted.
2360 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2361 used to link entries of this list together.
2363 \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
2366 #define AST_LIST_INSERT_BEFORE_CURRENT(head, elm, field) do { \
2367 if (__list_prev) { \
2368 (elm)->field.next = __list_prev->field.next; \
2369 __list_prev->field.next = elm; \
2371 (elm)->field.next = (head)->first; \
2372 (head)->first = (elm); \
2374 __new_prev = (elm); \
2377 #define AST_RWLIST_INSERT_BEFORE_CURRENT AST_LIST_INSERT_BEFORE_CURRENT
2380 \brief Closes a safe loop traversal block.
2382 #define AST_LIST_TRAVERSE_SAFE_END }
2384 #define AST_RWLIST_TRAVERSE_SAFE_END AST_LIST_TRAVERSE_SAFE_END
2387 \brief Initializes a list head structure.
2388 \param head This is a pointer to the list head structure
2390 This macro initializes a list head structure by setting the head
2391 entry to \a NULL (empty list) and recreating the embedded lock.
2393 #define AST_LIST_HEAD_INIT(head) { \
2394 (head)->first = NULL; \
2395 (head)->last = NULL; \
2396 ast_mutex_init(&(head)->lock); \
2400 \brief Initializes an rwlist head structure.
2401 \param head This is a pointer to the list head structure
2403 This macro initializes a list head structure by setting the head
2404 entry to \a NULL (empty list) and recreating the embedded lock.
2406 #define AST_RWLIST_HEAD_INIT(head) { \
2407 (head)->first = NULL; \
2408 (head)->last = NULL; \
2409 ast_rwlock_init(&(head)->lock); \
2413 \brief Destroys a list head structure.
2414 \param head This is a pointer to the list head structure
2416 This macro destroys a list head structure by setting the head
2417 entry to \a NULL (empty list) and destroying the embedded lock.
2418 It does not free the structure from memory.
2420 #define AST_LIST_HEAD_DESTROY(head) { \
2421 (head)->first = NULL; \
2422 (head)->last = NULL; \
2423 ast_mutex_destroy(&(head)->lock); \
2427 \brief Destroys an rwlist head structure.
2428 \param head This is a pointer to the list head structure
2430 This macro destroys a list head structure by setting the head
2431 entry to \a NULL (empty list) and destroying the embedded lock.
2432 It does not free the structure from memory.
2434 #define AST_RWLIST_HEAD_DESTROY(head) { \
2435 (head)->first = NULL; \
2436 (head)->last = NULL; \
2437 ast_rwlock_destroy(&(head)->lock); \
2441 \brief Initializes a list head structure.
2442 \param head This is a pointer to the list head structure
2444 This macro initializes a list head structure by setting the head
2445 entry to \a NULL (empty list). There is no embedded lock handling
2448 #define AST_LIST_HEAD_INIT_NOLOCK(head) { \
2449 (head)->first = NULL; \
2450 (head)->last = NULL; \
2454 \brief Inserts a list entry after a given entry.
2455 \param head This is a pointer to the list head structure
2456 \param listelm This is a pointer to the entry after which the new entry should
2458 \param elm This is a pointer to the entry to be inserted.
2459 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2460 used to link entries of this list together.
2462 #define AST_LIST_INSERT_AFTER(head, listelm, elm, field) do { \
2463 (elm)->field.next = (listelm)->field.next; \
2464 (listelm)->field.next = (elm); \
2465 if ((head)->last == (listelm)) \
2466 (head)->last = (elm); \
2469 #define AST_RWLIST_INSERT_AFTER AST_LIST_INSERT_AFTER
2472 \brief Inserts a list entry at the head of a list.
2473 \param head This is a pointer to the list head structure
2474 \param elm This is a pointer to the entry to be inserted.
2475 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2476 used to link entries of this list together.
2478 #define AST_LIST_INSERT_HEAD(head, elm, field) do { \
2479 (elm)->field.next = (head)->first; \
2480 (head)->first = (elm); \
2481 if (!(head)->last) \
2482 (head)->last = (elm); \
2485 #define AST_RWLIST_INSERT_HEAD AST_LIST_INSERT_HEAD
2488 \brief Appends a list entry to the tail of a list.
2489 \param head This is a pointer to the list head structure
2490 \param elm This is a pointer to the entry to be appended.
2491 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2492 used to link entries of this list together.
2494 Note: The link field in the appended entry is \b not modified, so if it is
2495 actually the head of a list itself, the entire list will be appended
2496 temporarily (until the next AST_LIST_INSERT_TAIL is performed).
2498 #define AST_LIST_INSERT_TAIL(head, elm, field) do { \
2499 if (!(head)->first) { \
2500 (head)->first = (elm); \
2501 (head)->last = (elm); \
2503 (head)->last->field.next = (elm); \
2504 (head)->last = (elm); \
2508 #define AST_RWLIST_INSERT_TAIL AST_LIST_INSERT_TAIL
2511 \brief Appends a whole list to the tail of a list.
2512 \param head This is a pointer to the list head structure
2513 \param list This is a pointer to the list to be appended.
2514 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2515 used to link entries of this list together.
2517 #define AST_LIST_APPEND_LIST(head, list, field) do { \
2518 if (!(head)->first) { \
2519 (head)->first = (list)->first; \
2520 (head)->last = (list)->last; \
2522 (head)->last->field.next = (list)->first; \
2523 (head)->last = (list)->last; \
2527 #define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
2530 \brief Removes and returns the head entry from a list.
2531 \param head This is a pointer to the list head structure
2532 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2533 used to link entries of this list together.
2535 Removes the head entry from the list, and returns a pointer to it.
2536 This macro is safe to call on an empty list.
2538 #define AST_LIST_REMOVE_HEAD(head, field) ({ \
2539 typeof((head)->first) cur = (head)->first; \
2541 (head)->first = cur->field.next; \
2542 cur->field.next = NULL; \
2543 if ((head)->last == cur) \
2544 (head)->last = NULL; \
2549 #define AST_RWLIST_REMOVE_HEAD AST_LIST_REMOVE_HEAD
2552 \brief Removes a specific entry from a list.
2553 \param head This is a pointer to the list head structure
2554 \param elm This is a pointer to the entry to be removed.
2555 \param field This is the name of the field (declared using AST_LIST_ENTRY())
2556 used to link entries of this list together.
2557 \warning The removed entry is \b not freed nor modified in any way.
2559 #define AST_LIST_REMOVE(head, elm, field) do { \
2560 if ((head)->first == (elm)) { \
2561 (head)->first = (elm)->field.next; \
2562 if ((head)->last == (elm)) \
2563 (head)->last = NULL; \
2565 typeof(elm) curelm = (head)->first; \
2566 while (curelm && (curelm->field.next != (elm))) \
2567 curelm = curelm->field.next; \
2569 curelm->field.next = (elm)->field.next; \
2570 if ((head)->last == (elm)) \
2571 (head)->last = curelm; \
2574 (elm)->field.next = NULL; \
2577 #define AST_RWLIST_REMOVE AST_LIST_REMOVE
2582 AST_LIST_ENTRY(ast_var_t
) entries
;
2587 AST_LIST_HEAD_NOLOCK(varshead
, ast_var_t
);
2589 AST_RWLOCK_DEFINE_STATIC(globalslock
);
2590 static struct varshead globals
= AST_LIST_HEAD_NOLOCK_INIT_VALUE
;
2593 /* IN CONFLICT: struct ast_var_t *ast_var_assign(const char *name, const char *value); */
2595 static struct ast_var_t
*ast_var_assign(const char *name
, const char *value
);
2597 static void ast_var_delete(struct ast_var_t
*var
);
2600 #define AST_MAX_EXTENSION 80 /*!< Max length of an extension */
2604 #define PRIORITY_HINT -1 /*!< Special Priority for a hint */
2606 enum ast_extension_states
{
2607 AST_EXTENSION_REMOVED
= -2, /*!< Extension removed */
2608 AST_EXTENSION_DEACTIVATED
= -1, /*!< Extension hint removed */
2609 AST_EXTENSION_NOT_INUSE
= 0, /*!< No device INUSE or BUSY */
2610 AST_EXTENSION_INUSE
= 1 << 0, /*!< One or more devices INUSE */
2611 AST_EXTENSION_BUSY
= 1 << 1, /*!< All devices BUSY */
2612 AST_EXTENSION_UNAVAILABLE
= 1 << 2, /*!< All devices UNAVAILABLE/UNREGISTERED */
2613 AST_EXTENSION_RINGING
= 1 << 3, /*!< All devices RINGING */
2614 AST_EXTENSION_ONHOLD
= 1 << 4, /*!< All devices ONHOLD */
2617 struct ast_custom_function
{
2618 const char *name
; /*!< Name */
2619 const char *synopsis
; /*!< Short description for "show functions" */
2620 const char *desc
; /*!< Help text that explains it all */
2621 const char *syntax
; /*!< Syntax description */
2622 int (*read
)(struct ast_channel
*, const char *, char *, char *, size_t); /*!< Read function, if read is supported */
2623 int (*write
)(struct ast_channel
*, const char *, char *, const char *); /*!< Write function, if write is supported */
2624 AST_RWLIST_ENTRY(ast_custom_function
) acflist
;
2627 typedef int (ast_switch_f
)(struct ast_channel
*chan
, const char *context
,
2628 const char *exten
, int priority
, const char *callerid
, const char *data
);
2631 AST_LIST_ENTRY(ast_switch
) list
;
2632 const char *name
; /*!< Name of the switch */
2633 const char *description
; /*!< Description of the switch */
2635 ast_switch_f
*exists
;
2636 ast_switch_f
*canmatch
;
2638 ast_switch_f
*matchmore
;
2642 static char *config
= "extensions.conf";
2643 static char *registrar
= "conf2ael";
2644 static char userscontext
[AST_MAX_EXTENSION
] = "default";
2645 static int static_config
= 0;
2646 static int write_protect_config
= 1;
2647 static int autofallthrough_config
= 0;
2648 static int clearglobalvars_config
= 0;
2649 /*! Go no deeper than this through includes (not counting loops) */
2650 #define AST_PBX_MAX_STACK 128
2651 static void pbx_substitute_variables_helper(struct ast_channel
*c
,const char *cp1
,char *cp2
,int count
);
2654 /* stolen from callerid.c */
2656 /*! \brief Clean up phone string
2657 * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
2658 * Basically, remove anything that could be invalid in a pattern.
2660 static void ast_shrink_phone_number(char *n
)
2665 for (x
=0; n
[x
]; x
++) {
2684 if (!strchr("()", n
[x
]))
2692 /* stolen from chanvars.c */
2694 static const char *ast_var_name(const struct ast_var_t
*var
)
2698 if (var
== NULL
|| (name
= var
->name
) == NULL
)
2700 /* Return the name without the initial underscores */
2701 if (name
[0] == '_') {
2710 /* stolen from asterisk.c */
2712 static struct ast_flags ast_options
= { AST_DEFAULT_OPTIONS
};
2713 static int option_verbose
= 0; /*!< Verbosity level */
2714 static int option_debug
= 0; /*!< Debug level */
2717 /* experiment 1: see if it's easier just to use existing config code
2718 * to read in the extensions.conf file. In this scenario,
2719 I have to rip/copy code from other modules, because they
2720 are staticly declared as-is. A solution would be to move
2721 the ripped code to another location and make them available
2722 to other modules and standalones */
2724 /* Our own version of ast_log, since the expr parser uses it. -- stolen from utils/check_expr.c */
2726 static void ast_log(int level
, const char *file
, int line
, const char *function
, const char *fmt
, ...)
2731 printf("LOG: lev:%d file:%s line:%d func: %s ",
2732 level
, file
, line
, function
);
2738 static void __attribute__((format (printf
, 1, 2))) ast_verbose(const char *fmt
, ...)
2743 printf("VERBOSE: ");
2749 /* stolen from main/utils.c */
2750 static char *ast_process_quotes_and_slashes(char *start
, char find
, char replace_with
)
2752 char *dataPut
= start
;
2756 for (; *start
; start
++) {
2758 *dataPut
++ = *start
; /* Always goes verbatim */
2761 if (*start
== '\\') {
2762 inEscape
= 1; /* Do not copy \ into the data */
2763 } else if (*start
== '\'') {
2764 inQuotes
= 1 - inQuotes
; /* Do not copy ' into the data */
2766 /* Replace , with |, unless in quotes */
2767 *dataPut
++ = inQuotes
? *start
: ((*start
== find
) ? replace_with
: *start
);
2771 if (start
!= dataPut
)
2776 static int ast_true(const char *s
)
2778 if (ast_strlen_zero(s
))
2781 /* Determine if this is a true value */
2782 if (!strcasecmp(s
, "yes") ||
2783 !strcasecmp(s
, "true") ||
2784 !strcasecmp(s
, "y") ||
2785 !strcasecmp(s
, "t") ||
2786 !strcasecmp(s
, "1") ||
2787 !strcasecmp(s
, "on"))
2793 /* stolen from pbx.c */
2794 #define VAR_BUF_SIZE 4096
2796 #define VAR_NORMAL 1
2797 #define VAR_SOFTTRAN 2
2798 #define VAR_HARDTRAN 3
2800 #define BACKGROUND_SKIP (1 << 0)
2801 #define BACKGROUND_NOANSWER (1 << 1)
2802 #define BACKGROUND_MATCHEXTEN (1 << 2)
2803 #define BACKGROUND_PLAYBACK (1 << 3)
2806 \brief ast_exten: An extension
2807 The dialplan is saved as a linked list with each context
2808 having it's own linked list of extensions - one item per
2812 char *exten
; /*!< Extension name */
2813 int matchcid
; /*!< Match caller id ? */
2814 const char *cidmatch
; /*!< Caller id to match for this extension */
2815 int priority
; /*!< Priority */
2816 const char *label
; /*!< Label */
2817 struct ast_context
*parent
; /*!< The context this extension belongs to */
2818 const char *app
; /*!< Application to execute */
2819 struct ast_app
*cached_app
; /*!< Cached location of application */
2820 void *data
; /*!< Data to use (arguments) */
2821 void (*datad
)(void *); /*!< Data destructor */
2822 struct ast_exten
*peer
; /*!< Next higher priority with our extension */
2823 const char *registrar
; /*!< Registrar */
2824 struct ast_exten
*next
; /*!< Extension with a greater ID */
2828 typedef int (*ast_state_cb_type
)(char *context
, char* id
, enum ast_extension_states state
, void *data
);
2830 int hastime
; /*!< If time construct exists */
2831 unsigned int monthmask
; /*!< Mask for month */
2832 unsigned int daymask
; /*!< Mask for date */
2833 unsigned int dowmask
; /*!< Mask for day of week (mon-sun) */
2834 unsigned int minmask
[24]; /*!< Mask for minute */
2837 /*! \brief ast_include: include= support in extensions.conf */
2838 struct ast_include
{
2840 const char *rname
; /*!< Context to include */
2841 const char *registrar
; /*!< Registrar */
2842 int hastime
; /*!< If time construct exists */
2843 struct ast_timing timing
; /*!< time construct */
2844 struct ast_include
*next
; /*!< Link them together */
2848 /*! \brief ast_sw: Switch statement in extensions.conf */
2851 const char *registrar
; /*!< Registrar */
2852 char *data
; /*!< Data load */
2854 AST_LIST_ENTRY(ast_sw
) list
;
2859 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
2860 struct ast_ignorepat
{
2861 const char *registrar
;
2862 struct ast_ignorepat
*next
;
2863 const char pattern
[0];
2866 /*! \brief ast_context: An extension context */
2867 struct ast_context
{
2868 ast_rwlock_t lock
; /*!< A lock to prevent multiple threads from clobbering the context */
2869 struct ast_exten
*root
; /*!< The root of the list of extensions */
2870 struct ast_context
*next
; /*!< Link them together */
2871 struct ast_include
*includes
; /*!< Include other contexts */
2872 struct ast_ignorepat
*ignorepats
; /*!< Patterns for which to continue playing dialtone */
2873 const char *registrar
; /*!< Registrar */
2874 AST_LIST_HEAD_NOLOCK(, ast_sw
) alts
; /*!< Alternative switches */
2875 ast_mutex_t macrolock
; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
2876 char name
[0]; /*!< Name of the context */
2880 /*! \brief ast_app: A registered application */
2882 int (*execute
)(struct ast_channel
*chan
, void *data
);
2883 const char *synopsis
; /*!< Synopsis text for 'show applications' */
2884 const char *description
; /*!< Description (help text) for 'show application <name>' */
2885 AST_RWLIST_ENTRY(ast_app
) list
; /*!< Next app in list */
2886 void *module
; /*!< Module this app belongs to */
2887 char name
[0]; /*!< Name of the application */
2891 /*! \brief ast_state_cb: An extension state notify register item */
2892 struct ast_state_cb
{
2895 ast_state_cb_type callback
;
2896 struct ast_state_cb
*next
;
2899 /*! \brief Structure for dial plan hints
2901 \note Hints are pointers from an extension in the dialplan to one or
2902 more devices (tech/name)
2903 - See \ref AstExtState
2906 struct ast_exten
*exten
; /*!< Extension */
2907 int laststate
; /*!< Last known state */
2908 struct ast_state_cb
*callbacks
; /*!< Callback list for this extension */
2909 AST_RWLIST_ENTRY(ast_hint
) list
;/*!< Pointer to next hint in list */
2915 struct ast_state_cb
*callbacks
;
2917 AST_LIST_ENTRY(store_hint
) list
;
2921 AST_LIST_HEAD(store_hints
, store_hint
);
2923 static const struct cfextension_states
{
2924 int extension_state
;
2925 const char * const text
;
2926 } extension_states
[] = {
2927 { AST_EXTENSION_NOT_INUSE
, "Idle" },
2928 { AST_EXTENSION_INUSE
, "InUse" },
2929 { AST_EXTENSION_BUSY
, "Busy" },
2930 { AST_EXTENSION_UNAVAILABLE
, "Unavailable" },
2931 { AST_EXTENSION_RINGING
, "Ringing" },
2932 { AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
, "InUse&Ringing" },
2933 { AST_EXTENSION_ONHOLD
, "Hold" },
2934 { AST_EXTENSION_INUSE
| AST_EXTENSION_ONHOLD
, "InUse&Hold" }
2936 #define STATUS_NO_CONTEXT 1
2937 #define STATUS_NO_EXTENSION 2
2938 #define STATUS_NO_PRIORITY 3
2939 #define STATUS_NO_LABEL 4
2940 #define STATUS_SUCCESS 5
2943 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
2944 #if defined(__FreeBSD__)
2945 #include <machine/cpufunc.h>
2946 #elif defined(linux)
2947 static __inline
uint64_t
2952 __asm
__volatile(".byte 0x0f, 0x31" : "=A" (rv
));
2956 #else /* supply a dummy function on other platforms */
2957 static __inline
uint64_t
2965 static struct ast_var_t
*ast_var_assign(const char *name
, const char *value
)
2967 struct ast_var_t
*var
;
2968 int name_len
= strlen(name
) + 1;
2969 int value_len
= strlen(value
) + 1;
2971 if (!(var
= ast_calloc(sizeof(*var
) + name_len
+ value_len
, sizeof(char)))) {
2975 ast_copy_string(var
->name
, name
, name_len
);
2976 var
->value
= var
->name
+ name_len
;
2977 ast_copy_string(var
->value
, value
, value_len
);
2982 static void ast_var_delete(struct ast_var_t
*var
)
2989 /* chopped this one off at the knees! */
2990 static int ast_func_write(struct ast_channel
*chan
, const char *function
, const char *value
)
2993 /* ast_log(LOG_ERROR, "Function %s not registered\n", function); we are not interested in the details here */
2998 static unsigned int ast_app_separate_args(char *buf
, char delim
, char **array
, int arraylen
)
3002 int paren
= 0, quote
= 0;
3004 if (!buf
|| !array
|| !arraylen
)
3007 memset(array
, 0, arraylen
* sizeof(*array
));
3011 for (argc
= 0; *scan
&& (argc
< arraylen
- 1); argc
++) {
3013 for (; *scan
; scan
++) {
3016 else if (*scan
== ')') {
3019 } else if (*scan
== '"' && delim
!= '"') {
3020 quote
= quote
? 0 : 1;
3021 /* Remove quote character from argument */
3022 memmove(scan
, scan
+ 1, strlen(scan
));
3024 } else if (*scan
== '\\') {
3025 /* Literal character, don't parse */
3026 memmove(scan
, scan
+ 1, strlen(scan
));
3027 } else if ((*scan
== delim
) && !paren
&& !quote
) {
3035 array
[argc
++] = scan
;
3040 static void pbx_builtin_setvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
3042 struct ast_var_t
*newvariable
;
3043 struct varshead
*headp
;
3044 const char *nametail
= name
;
3046 /* XXX may need locking on the channel ? */
3047 if (name
[strlen(name
)-1] == ')') {
3048 char *function
= ast_strdupa(name
);
3050 ast_func_write(chan
, function
, value
);
3056 /* For comparison purposes, we have to strip leading underscores */
3057 if (*nametail
== '_') {
3059 if (*nametail
== '_')
3063 AST_LIST_TRAVERSE (headp
, newvariable
, entries
) {
3064 if (strcasecmp(ast_var_name(newvariable
), nametail
) == 0) {
3065 /* there is already such a variable, delete it */
3066 AST_LIST_REMOVE(headp
, newvariable
, entries
);
3067 ast_var_delete(newvariable
);
3073 if ((option_verbose
> 1) && (headp
== &globals
))
3074 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
3075 newvariable
= ast_var_assign(name
, value
);
3076 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
3081 static int pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
3083 char *name
, *value
, *mydata
;
3085 char *argv
[24]; /* this will only support a maximum of 24 variables being set in a single operation */
3089 if (ast_strlen_zero(data
)) {
3090 ast_log(LOG_WARNING
, "Set requires at least one variable name/value pair.\n");
3094 mydata
= ast_strdupa(data
);
3095 argc
= ast_app_separate_args(mydata
, '|', argv
, sizeof(argv
) / sizeof(argv
[0]));
3097 /* check for a trailing flags argument */
3098 if ((argc
> 1) && !strchr(argv
[argc
-1], '=')) {
3100 if (strchr(argv
[argc
], 'g'))
3104 for (x
= 0; x
< argc
; x
++) {
3106 if ((value
= strchr(name
, '='))) {
3108 pbx_builtin_setvar_helper((global
) ? NULL
: chan
, name
, value
);
3110 ast_log(LOG_WARNING
, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name
);
3116 int localized_pbx_builtin_setvar(struct ast_channel
*chan
, void *data
);
3118 int localized_pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
3120 return pbx_builtin_setvar(chan
, data
);
3124 /*! \brief Helper for get_range.
3125 * return the index of the matching entry, starting from 1.
3126 * If names is not supplied, try numeric values.
3129 static int lookup_name(const char *s
, char *const names
[], int max
)
3134 for (i
= 0; names
[i
]; i
++) {
3135 if (!strcasecmp(s
, names
[i
]))
3138 } else if (sscanf(s
, "%d", &i
) == 1 && i
>= 1 && i
<= max
) {
3141 return 0; /* error return */
3144 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3145 * names, if supplied, is an array of names that should be mapped to numbers.
3147 static unsigned get_range(char *src
, int max
, char *const names
[], const char *msg
)
3149 int s
, e
; /* start and ending position */
3150 unsigned int mask
= 0;
3152 /* Check for whole range */
3153 if (ast_strlen_zero(src
) || !strcmp(src
, "*")) {
3157 /* Get start and ending position */
3158 char *c
= strchr(src
, '-');
3161 /* Find the start */
3162 s
= lookup_name(src
, names
, max
);
3164 ast_log(LOG_WARNING
, "Invalid %s '%s', assuming none\n", msg
, src
);
3168 if (c
) { /* find end of range */
3169 e
= lookup_name(c
, names
, max
);
3171 ast_log(LOG_WARNING
, "Invalid end %s '%s', assuming none\n", msg
, c
);
3178 /* Fill the mask. Remember that ranges are cyclic */
3179 mask
= 1 << e
; /* initialize with last element */
3192 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3193 static void get_timerange(struct ast_timing
*i
, char *times
)
3201 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3202 memset(i
->minmask
, 0, sizeof(i
->minmask
));
3204 /* 2-minutes per bit, since the mask has only 32 bits :( */
3205 /* Star is all times */
3206 if (ast_strlen_zero(times
) || !strcmp(times
, "*")) {
3207 for (x
=0; x
<24; x
++)
3208 i
->minmask
[x
] = 0x3fffffff; /* 30 bits */
3211 /* Otherwise expect a range */
3212 e
= strchr(times
, '-');
3214 ast_log(LOG_WARNING
, "Time range is not valid. Assuming no restrictions based on time.\n");
3218 /* XXX why skip non digits ? */
3219 while (*e
&& !isdigit(*e
))
3222 ast_log(LOG_WARNING
, "Invalid time range. Assuming no restrictions based on time.\n");
3225 if (sscanf(times
, "%d:%d", &s1
, &s2
) != 2) {
3226 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", times
);
3229 if (sscanf(e
, "%d:%d", &e1
, &e2
) != 2) {
3230 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", e
);
3233 /* XXX this needs to be optimized */
3235 s1
= s1
* 30 + s2
/2;
3236 if ((s1
< 0) || (s1
>= 24*30)) {
3237 ast_log(LOG_WARNING
, "%s isn't a valid start time. Assuming no time.\n", times
);
3240 e1
= e1
* 30 + e2
/2;
3241 if ((e1
< 0) || (e1
>= 24*30)) {
3242 ast_log(LOG_WARNING
, "%s isn't a valid end time. Assuming no time.\n", e
);
3245 /* Go through the time and enable each appropriate bit */
3246 for (x
=s1
;x
!= e1
;x
= (x
+ 1) % (24 * 30)) {
3247 i
->minmask
[x
/30] |= (1 << (x
% 30));
3249 /* Do the last one */
3250 i
->minmask
[x
/30] |= (1 << (x
% 30));
3252 for (cth
=0; cth
<24; cth
++) {
3253 /* Initialize masks to blank */
3254 i
->minmask
[cth
] = 0;
3255 for (ctm
=0; ctm
<30; ctm
++) {
3257 /* First hour with more than one hour */
3258 (((cth
== s1
) && (ctm
>= s2
)) &&
3261 || (((cth
== s1
) && (ctm
>= s2
)) &&
3262 ((cth
== e1
) && (ctm
<= e2
)))
3263 /* In between first and last hours (more than 2 hours) */
3266 /* Last hour with more than one hour */
3268 ((cth
== e1
) && (ctm
<= e2
)))
3270 i
->minmask
[cth
] |= (1 << (ctm
/ 2));
3278 static void null_datad(void *foo
)
3282 /*! \brief Find realtime engine for realtime family */
3283 static struct ast_config_engine
*find_engine(const char *family
, char *database
, int dbsiz
, char *table
, int tabsiz
)
3285 struct ast_config_engine
*eng
, *ret
= NULL
;
3286 struct ast_config_map
*map
;
3289 for (map
= config_maps
; map
; map
= map
->next
) {
3290 if (!strcasecmp(family
, map
->name
)) {
3292 ast_copy_string(database
, map
->database
, dbsiz
);
3294 ast_copy_string(table
, map
->table
? map
->table
: family
, tabsiz
);
3299 /* Check if the required driver (engine) exist */
3301 for (eng
= config_engine_list
; !ret
&& eng
; eng
= eng
->next
) {
3302 if (!strcasecmp(eng
->name
, map
->driver
))
3308 /* if we found a mapping, but the engine is not available, then issue a warning */
3310 ast_log(LOG_WARNING
, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map
->name
, map
->driver
);
3315 struct ast_category
*ast_config_get_current_category(const struct ast_config
*cfg
);
3317 struct ast_category
*ast_config_get_current_category(const struct ast_config
*cfg
)
3319 return cfg
->current
;
3322 static struct ast_category
*ast_category_new(const char *name
, const char *in_file
, int lineno
);
3324 static struct ast_category
*ast_category_new(const char *name
, const char *in_file
, int lineno
)
3326 struct ast_category
*category
;
3328 if ((category
= ast_calloc(1, sizeof(*category
))))
3329 ast_copy_string(category
->name
, name
, sizeof(category
->name
));
3330 category
->file
= strdup(in_file
);
3331 category
->lineno
= lineno
; /* if you don't know the lineno, set it to 999999 or something real big */
3335 struct ast_category
*localized_category_get(const struct ast_config
*config
, const char *category_name
);
3337 struct ast_category
*localized_category_get(const struct ast_config
*config
, const char *category_name
)
3339 return category_get(config
, category_name
, 0);
3342 static void move_variables(struct ast_category
*old
, struct ast_category
*new)
3344 struct ast_variable
*var
= old
->root
;
3347 /* we can just move the entire list in a single op */
3348 ast_variable_append(new, var
);
3351 struct ast_variable
*next
= var
->next
;
3353 ast_variable_append(new, var
);
3359 static void inherit_category(struct ast_category
*new, const struct ast_category
*base
)
3361 struct ast_variable
*var
;
3363 for (var
= base
->root
; var
; var
= var
->next
)
3364 ast_variable_append(new, variable_clone(var
));
3367 static void ast_category_append(struct ast_config
*config
, struct ast_category
*category
);
3369 static void ast_category_append(struct ast_config
*config
, struct ast_category
*category
)
3372 config
->last
->next
= category
;
3374 config
->root
= category
;
3375 config
->last
= category
;
3376 config
->current
= category
;
3379 static void ast_category_destroy(struct ast_category
*cat
);
3381 static void ast_category_destroy(struct ast_category
*cat
)
3383 ast_variables_destroy(cat
->root
);
3390 static struct ast_config_engine text_file_engine
= {
3392 .load_func
= config_text_file_load
,
3396 static struct ast_config
*ast_config_internal_load(const char *filename
, struct ast_config
*cfg
, int withcomments
, const char *suggested_incl_file
);
3398 static struct ast_config
*ast_config_internal_load(const char *filename
, struct ast_config
*cfg
, int withcomments
, const char *suggested_incl_file
)
3402 struct ast_config_engine
*loader
= &text_file_engine
;
3403 struct ast_config
*result
;
3405 if (cfg
->include_level
== cfg
->max_include_level
) {
3406 ast_log(LOG_WARNING
, "Maximum Include level (%d) exceeded\n", cfg
->max_include_level
);
3410 cfg
->include_level
++;
3411 /* silence is golden!
3412 ast_log(LOG_WARNING, "internal loading file %s level=%d\n", filename, cfg->include_level);
3415 if (strcmp(filename
, extconfig_conf
) && strcmp(filename
, "asterisk.conf") && config_engine_list
) {
3416 struct ast_config_engine
*eng
;
3418 eng
= find_engine(filename
, db
, sizeof(db
), table
, sizeof(table
));
3421 if (eng
&& eng
->load_func
) {
3424 eng
= find_engine("global", db
, sizeof(db
), table
, sizeof(table
));
3425 if (eng
&& eng
->load_func
)
3430 result
= loader
->load_func(db
, table
, filename
, cfg
, withcomments
, suggested_incl_file
);
3431 /* silence is golden
3432 ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
3436 result
->include_level
--;
3442 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
)
3446 struct ast_variable
*v
;
3447 char cmd
[512], exec_file
[512];
3448 int object
, do_exec
, do_include
;
3450 /* Actually parse the entry */
3451 if (cur
[0] == '[') {
3452 struct ast_category
*newcat
= NULL
;
3455 /* A category header */
3456 c
= strchr(cur
, ']');
3458 ast_log(LOG_WARNING
, "parse error: no closing ']', line %d of %s\n", lineno
, configfile
);
3466 if (!(*cat
= newcat
= ast_category_new(catname
, ast_strlen_zero(suggested_include_file
)?configfile
:suggested_include_file
, lineno
))) {
3469 (*cat
)->lineno
= lineno
;
3472 if (withcomments
&& comment_buffer
&& comment_buffer
[0] ) {
3473 newcat
->precomments
= ALLOC_COMMENT(comment_buffer
);
3475 if (withcomments
&& lline_buffer
&& lline_buffer
[0] ) {
3476 newcat
->sameline
= ALLOC_COMMENT(lline_buffer
);
3481 /* If there are options or categories to inherit from, process them now */
3483 if (!(cur
= strchr(c
, ')'))) {
3484 ast_log(LOG_WARNING
, "parse error: no closing ')', line %d of %s\n", lineno
, configfile
);
3488 while ((cur
= strsep(&c
, ","))) {
3489 if (!strcasecmp(cur
, "!")) {
3490 (*cat
)->ignored
= 1;
3491 } else if (!strcasecmp(cur
, "+")) {
3492 *cat
= category_get(cfg
, catname
, 1);
3494 ast_config_destroy(cfg
);
3496 ast_category_destroy(newcat
);
3497 ast_log(LOG_WARNING
, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname
, lineno
, configfile
);
3501 move_variables(newcat
, *cat
);
3502 ast_category_destroy(newcat
);
3506 struct ast_category
*base
;
3508 base
= category_get(cfg
, cur
, 1);
3510 ast_log(LOG_WARNING
, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur
, lineno
, configfile
);
3513 inherit_category(*cat
, base
);
3518 ast_category_append(cfg
, *cat
);
3519 } else if (cur
[0] == '#') {
3523 while(*c
&& (*c
> 32)) c
++;
3526 /* Find real argument */
3527 c
= ast_skip_blanks(c
+ 1);
3532 do_include
= !strcasecmp(cur
, "include");
3534 do_exec
= !strcasecmp(cur
, "exec");
3537 if (do_exec
&& !ast_opt_exec_includes
) {
3538 ast_log(LOG_WARNING
, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
3541 if (do_include
|| do_exec
) {
3544 char real_inclusion_name
[256];
3545 struct ast_config_include
*inclu
;
3547 /* Strip off leading and trailing "'s and <>'s */
3548 while((*c
== '<') || (*c
== '>') || (*c
== '\"')) c
++;
3549 /* Get rid of leading mess */
3552 while (!ast_strlen_zero(cur
)) {
3553 c
= cur
+ strlen(cur
) - 1;
3554 if ((*c
== '>') || (*c
== '<') || (*c
== '\"'))
3559 /* #exec </path/to/executable>
3560 We create a tmp file, then we #include it, then we delete it. */
3562 snprintf(exec_file
, sizeof(exec_file
), "/var/tmp/exec.%d.%ld", (int)time(NULL
), (long)pthread_self());
3563 snprintf(cmd
, sizeof(cmd
), "%s > %s 2>&1", cur
, exec_file
);
3564 ast_safe_system(cmd
);
3567 exec_file
[0] = '\0';
3569 /* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
3571 /* record this inclusion */
3572 inclu
= ast_include_new(cfg
, configfile
, cur
, do_exec
, cur2
, lineno
, real_inclusion_name
, sizeof(real_inclusion_name
));
3574 do_include
= ast_config_internal_load(cur
, cfg
, withcomments
, real_inclusion_name
) ? 1 : 0;
3575 if(!ast_strlen_zero(exec_file
))
3579 /* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
3582 ast_log(LOG_WARNING
, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
3583 do_exec
? "exec" : "include",
3584 do_exec
? "/path/to/executable" : "filename",
3590 ast_log(LOG_WARNING
, "Unknown directive '%s' at line %d of %s\n", cur
, lineno
, configfile
);
3592 /* Just a line (variable = value) */
3594 ast_log(LOG_WARNING
,
3595 "parse error: No category context for line %d of %s\n", lineno
, configfile
);
3598 c
= strchr(cur
, '=');
3602 /* Ignore > in => */
3608 if ((v
= ast_variable_new(ast_strip(cur
), ast_strip(c
), configfile
))) {
3611 /* Put and reset comments */
3613 ast_variable_append(*cat
, v
);
3615 if (withcomments
&& comment_buffer
&& comment_buffer
[0] ) {
3616 v
->precomments
= ALLOC_COMMENT(comment_buffer
);
3618 if (withcomments
&& lline_buffer
&& lline_buffer
[0] ) {
3619 v
->sameline
= ALLOC_COMMENT(lline_buffer
);
3628 ast_log(LOG_WARNING
, "EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno
, configfile
);
3634 static int use_local_dir
= 1;
3636 void localized_use_local_dir(void);
3637 void localized_use_conf_dir(void);
3639 void localized_use_local_dir(void)
3644 void localized_use_conf_dir(void)
3650 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
)
3654 char *new_buf
, *comment_p
, *process_buf
;
3657 int comment
= 0, nest
[MAX_NESTED_COMMENTS
];
3658 struct ast_category
*cat
= NULL
;
3660 struct stat statbuf
;
3662 cat
= ast_config_get_current_category(cfg
);
3664 if (filename
[0] == '/') {
3665 ast_copy_string(fn
, filename
, sizeof(fn
));
3668 snprintf(fn
, sizeof(fn
), "./%s", filename
);
3670 snprintf(fn
, sizeof(fn
), "%s/%s", ast_config_AST_CONFIG_DIR
, filename
);
3673 if (withcomments
&& cfg
&& cfg
->include_level
< 2 ) {
3677 #ifdef AST_INCLUDE_GLOB
3682 globbuf
.gl_offs
= 0; /* initialize it to silence gcc */
3684 glob_ret
= glob(fn
, GLOB_NOCHECK
, NULL
, &globbuf
);
3686 glob_ret
= glob(fn
, GLOB_NOMAGIC
|GLOB_BRACE
, NULL
, &globbuf
);
3688 if (glob_ret
== GLOB_NOSPACE
)
3689 ast_log(LOG_WARNING
,
3690 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn
);
3691 else if (glob_ret
== GLOB_ABORTED
)
3692 ast_log(LOG_WARNING
,
3693 "Glob Expansion of pattern '%s' failed: Read error\n", fn
);
3695 /* loop over expanded files */
3697 for (i
=0; i
<globbuf
.gl_pathc
; i
++) {
3698 ast_copy_string(fn
, globbuf
.gl_pathv
[i
], sizeof(fn
));
3701 if (stat(fn
, &statbuf
))
3704 if (!S_ISREG(statbuf
.st_mode
)) {
3705 ast_log(LOG_WARNING
, "'%s' is not a regular file, ignoring\n", fn
);
3708 if (option_verbose
> 1) {
3709 ast_verbose(VERBOSE_PREFIX_2
"Parsing '%s': ", fn
);
3712 if (!(f
= fopen(fn
, "r"))) {
3714 ast_log(LOG_DEBUG
, "No file to parse: %s\n", fn
);
3715 if (option_verbose
> 1)
3716 ast_verbose( "Not found (%s)\n", strerror(errno
));
3721 ast_log(LOG_DEBUG
, "Parsing %s\n", fn
);
3722 if (option_verbose
> 1)
3723 ast_verbose("Found\n");
3726 if (fgets(buf
, sizeof(buf
), f
)) {
3727 if ( withcomments
) {
3728 CB_ADD(lline_buffer
); /* add the current lline buffer to the comment buffer */
3729 lline_buffer
[0] = 0; /* erase the lline buffer */
3738 while ((comment_p
= strchr(new_buf
, COMMENT_META
))) {
3739 if ((comment_p
> new_buf
) && (*(comment_p
-1) == '\\')) {
3740 /* Yuck, gotta memmove */
3741 memmove(comment_p
- 1, comment_p
, strlen(comment_p
) + 1);
3742 new_buf
= comment_p
;
3743 } else if(comment_p
[1] == COMMENT_TAG
&& comment_p
[2] == COMMENT_TAG
&& (comment_p
[3] != '-')) {
3744 /* Meta-Comment start detected ";--" */
3745 if (comment
< MAX_NESTED_COMMENTS
) {
3747 new_buf
= comment_p
+ 3;
3749 nest
[comment
-1] = lineno
;
3751 ast_log(LOG_ERROR
, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS
);
3753 } else if ((comment_p
>= new_buf
+ 2) &&
3754 (*(comment_p
- 1) == COMMENT_TAG
) &&
3755 (*(comment_p
- 2) == COMMENT_TAG
)) {
3756 /* Meta-Comment end detected */
3758 new_buf
= comment_p
+ 1;
3760 /* Back to non-comment now */
3762 /* Actually have to move what's left over the top, then continue */
3764 oldptr
= process_buf
+ strlen(process_buf
);
3765 if ( withcomments
) {
3767 CB_ADD_LEN(oldptr
+1,new_buf
-oldptr
-1);
3770 memmove(oldptr
, new_buf
, strlen(new_buf
) + 1);
3773 process_buf
= new_buf
;
3777 /* If ; is found, and we are not nested in a comment,
3778 we immediately stop all comment processing */
3779 if ( withcomments
) {
3783 new_buf
= comment_p
;
3785 new_buf
= comment_p
+ 1;
3788 if( withcomments
&& comment
&& !process_buf
)
3790 CB_ADD(buf
); /* the whole line is a comment, store it */
3794 char *buf
= ast_strip(process_buf
);
3795 if (!ast_strlen_zero(buf
)) {
3796 if (process_text_line(cfg
, &cat
, buf
, lineno
, filename
, withcomments
, suggested_include_file
)) {
3807 ast_log(LOG_WARNING
,"Unterminated comment detected beginning on line %d\n", nest
[comment
]);
3809 #ifdef AST_INCLUDE_GLOB
3817 if (cfg
&& cfg
->include_level
== 1 && withcomments
&& comment_buffer
) {
3818 if (comment_buffer
) {
3819 free(comment_buffer
);
3823 comment_buffer_size
=0;
3824 lline_buffer_size
=0;
3834 static struct ast_config
*ast_config_new(void) ;
3836 static struct ast_config
*ast_config_new(void)
3838 struct ast_config
*config
;
3840 if ((config
= ast_calloc(1, sizeof(*config
))))
3841 config
->max_include_level
= MAX_INCLUDE_LEVEL
;
3845 struct ast_config
*localized_config_load(const char *filename
);
3847 struct ast_config
*localized_config_load(const char *filename
)
3849 struct ast_config
*cfg
;
3850 struct ast_config
*result
;
3852 cfg
= ast_config_new();
3856 result
= ast_config_internal_load(filename
, cfg
, 0, "");
3858 ast_config_destroy(cfg
);
3863 struct ast_config
*localized_config_load_with_comments(const char *filename
);
3865 struct ast_config
*localized_config_load_with_comments(const char *filename
)
3867 struct ast_config
*cfg
;
3868 struct ast_config
*result
;
3870 cfg
= ast_config_new();
3874 result
= ast_config_internal_load(filename
, cfg
, 1, "");
3876 ast_config_destroy(cfg
);
3881 static struct ast_category
*next_available_category(struct ast_category
*cat
)
3883 for (; cat
&& cat
->ignored
; cat
= cat
->next
);
3888 static char *ast_category_browse(struct ast_config
*config
, const char *prev
)
3890 struct ast_category
*cat
= NULL
;
3892 if (prev
&& config
->last_browse
&& (config
->last_browse
->name
== prev
))
3893 cat
= config
->last_browse
->next
;
3894 else if (!prev
&& config
->root
)
3897 for (cat
= config
->root
; cat
; cat
= cat
->next
) {
3898 if (cat
->name
== prev
) {
3904 for (cat
= config
->root
; cat
; cat
= cat
->next
) {
3905 if (!strcasecmp(cat
->name
, prev
)) {
3914 cat
= next_available_category(cat
);
3916 config
->last_browse
= cat
;
3917 return (cat
) ? cat
->name
: NULL
;
3922 void ast_config_set_current_category(struct ast_config
*cfg
, const struct ast_category
*cat
);
3924 void ast_config_set_current_category(struct ast_config
*cfg
, const struct ast_category
*cat
)
3926 /* cast below is just to silence compiler warning about dropping "const" */
3927 cfg
->current
= (struct ast_category
*) cat
;
3930 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
3931 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
3932 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
3933 be shocked and mystified as to why things are not showing up in the files!
3935 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
3936 and line number are stored for each include, plus the name of the file included, so that these statements may be
3937 included in the output files on a file_save operation.
3939 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
3940 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
3941 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
3942 and a header gets added.
3944 vars and category heads are output in the order they are stored in the config file. So, if the software
3945 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
3946 file/lineno data probably won't get changed.
3950 static void gen_header(FILE *f1
, const char *configfile
, const char *fn
, const char *generator
)
3955 ast_copy_string(date
, ctime(&t
), sizeof(date
));
3957 fprintf(f1
, ";!\n");
3958 fprintf(f1
, ";! Automatically generated configuration file\n");
3959 if (strcmp(configfile
, fn
))
3960 fprintf(f1
, ";! Filename: %s (%s)\n", configfile
, fn
);
3962 fprintf(f1
, ";! Filename: %s\n", configfile
);
3963 fprintf(f1
, ";! Generator: %s\n", generator
);
3964 fprintf(f1
, ";! Creation Date: %s", date
);
3965 fprintf(f1
, ";!\n");
3968 static void set_fn(char *fn
, int fn_size
, const char *file
, const char *configfile
)
3970 if (!file
|| file
[0] == 0) {
3971 if (configfile
[0] == '/')
3972 ast_copy_string(fn
, configfile
, fn_size
);
3974 snprintf(fn
, fn_size
, "%s/%s", ast_config_AST_CONFIG_DIR
, configfile
);
3975 } else if (file
[0] == '/')
3976 ast_copy_string(fn
, file
, fn_size
);
3978 snprintf(fn
, fn_size
, "%s/%s", ast_config_AST_CONFIG_DIR
, file
);
3981 int localized_config_text_file_save(const char *configfile
, const struct ast_config
*cfg
, const char *generator
);
3983 int localized_config_text_file_save(const char *configfile
, const struct ast_config
*cfg
, const char *generator
)
3987 struct ast_variable
*var
;
3988 struct ast_category
*cat
;
3989 struct ast_comment
*cmt
;
3990 struct ast_config_include
*incl
;
3993 /* reset all the output flags, in case this isn't our first time saving this data */
3995 for (incl
=cfg
->includes
; incl
; incl
= incl
->next
)
3998 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
3999 are all truncated to zero bytes and have that nice header*/
4001 for (incl
=cfg
->includes
; incl
; incl
= incl
->next
)
4003 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*/
4006 set_fn(fn
, sizeof(fn
), incl
->included_file
, configfile
); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
4009 gen_header(f1
, configfile
, fn
, generator
);
4010 fclose(f1
); /* this should zero out the file */
4012 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn
, strerror(errno
));
4017 set_fn(fn
, sizeof(fn
), 0, configfile
); /* just set fn to absolute ver of configfile */
4019 if ((f
= fopen(fn
, "w+"))) {
4021 if ((f
= fopen(fn
, "w"))) {
4023 if (option_verbose
> 1)
4024 ast_verbose(VERBOSE_PREFIX_2
"Saving '%s': ", fn
);
4026 gen_header(f
, configfile
, fn
, generator
);
4030 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
4031 /* since each var, cat, and associated comments can come from any file, we have to be
4032 mobile, and open each file, print, and close it on an entry-by-entry basis */
4035 set_fn(fn
, sizeof(fn
), cat
->file
, configfile
);
4039 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn
, strerror(errno
));
4043 /* dump any includes that happen before this category header */
4044 for (incl
=cfg
->includes
; incl
; incl
= incl
->next
) {
4045 if (strcmp(incl
->include_location_file
, cat
->file
) == 0){
4046 if (cat
->lineno
> incl
->include_location_lineno
&& !incl
->output
) {
4048 fprintf(f
,"#exec \"%s\"\n", incl
->exec_file
);
4050 fprintf(f
,"#include \"%s\"\n", incl
->included_file
);
4056 /* Dump section with any appropriate comment */
4057 for (cmt
= cat
->precomments
; cmt
; cmt
=cmt
->next
) {
4058 if (cmt
->cmt
[0] != ';' || cmt
->cmt
[1] != '!')
4059 fprintf(f
,"%s", cmt
->cmt
);
4061 if (!cat
->precomments
)
4063 fprintf(f
, "[%s]", cat
->name
);
4064 for(cmt
= cat
->sameline
; cmt
; cmt
=cmt
->next
) {
4065 fprintf(f
,"%s", cmt
->cmt
);
4073 set_fn(fn
, sizeof(fn
), var
->file
, configfile
);
4077 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn
, strerror(errno
));
4081 /* dump any includes that happen before this category header */
4082 for (incl
=cfg
->includes
; incl
; incl
= incl
->next
) {
4083 if (strcmp(incl
->include_location_file
, var
->file
) == 0){
4084 if (var
->lineno
> incl
->include_location_lineno
&& !incl
->output
) {
4086 fprintf(f
,"#exec \"%s\"\n", incl
->exec_file
);
4088 fprintf(f
,"#include \"%s\"\n", incl
->included_file
);
4094 for (cmt
= var
->precomments
; cmt
; cmt
=cmt
->next
) {
4095 if (cmt
->cmt
[0] != ';' || cmt
->cmt
[1] != '!')
4096 fprintf(f
,"%s", cmt
->cmt
);
4099 fprintf(f
, "%s %s %s %s", var
->name
, (var
->object
? "=>" : "="), var
->value
, var
->sameline
->cmt
);
4101 fprintf(f
, "%s %s %s\n", var
->name
, (var
->object
? "=>" : "="), var
->value
);
4102 if (var
->blanklines
) {
4103 blanklines
= var
->blanklines
;
4104 while (blanklines
--)
4115 if ((option_verbose
> 1) && !option_debug
)
4116 ast_verbose("Saved\n");
4119 ast_log(LOG_DEBUG
, "Unable to open for writing: %s\n", fn
);
4120 if (option_verbose
> 1)
4121 ast_verbose(VERBOSE_PREFIX_2
"Unable to write (%s)", strerror(errno
));
4125 /* Now, for files with trailing #include/#exec statements,
4126 we have to make sure every entry is output */
4128 for (incl
=cfg
->includes
; incl
; incl
= incl
->next
) {
4129 if (!incl
->output
) {
4130 /* open the respective file */
4131 set_fn(fn
, sizeof(fn
), incl
->include_location_file
, configfile
);
4135 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn
, strerror(errno
));
4139 /* output the respective include */
4141 fprintf(f
,"#exec \"%s\"\n", incl
->exec_file
);
4143 fprintf(f
,"#include \"%s\"\n", incl
->included_file
);
4152 /* ================ the Line ========================================
4153 above this line, you have what you need to load a config file,
4154 and below it, you have what you need to process the extensions.conf
4155 file into the context/exten/prio stuff. They are both in one file
4156 to make things simpler */
4158 static struct ast_context
*local_contexts
= NULL
;
4159 static struct ast_context
*contexts
= NULL
;
4163 #define EXT_DATA_SIZE 256
4165 #define EXT_DATA_SIZE 8192
4168 * When looking up extensions, we can have different requests
4169 * identified by the 'action' argument, as follows.
4170 * Note that the coding is such that the low 4 bits are the
4171 * third argument to extension_match_core.
4174 E_MATCHMORE
= 0x00, /* extension can match but only with more 'digits' */
4175 E_CANMATCH
= 0x01, /* extension can match with or without more 'digits' */
4176 E_MATCH
= 0x02, /* extension is an exact match */
4177 E_MATCH_MASK
= 0x03, /* mask for the argument to extension_match_core() */
4178 E_SPAWN
= 0x12, /* want to spawn an extension. Requires exact match */
4179 E_FINDLABEL
= 0x22 /* returns the priority for a given label. Requires exact match */
4183 static AST_RWLIST_HEAD_STATIC(switches
, ast_switch
);
4186 #define SWITCH_DATA_LENGTH 256
4188 static const char *ast_get_extension_app(struct ast_exten
*e
)
4190 return e
? e
->app
: NULL
;
4193 static const char *ast_get_extension_name(struct ast_exten
*exten
)
4195 return exten
? exten
->exten
: NULL
;
4198 static AST_RWLIST_HEAD_STATIC(hints
, ast_hint
);
4200 /*! \brief ast_change_hint: Change hint for an extension */
4201 static int ast_change_hint(struct ast_exten
*oe
, struct ast_exten
*ne
)
4203 struct ast_hint
*hint
;
4206 AST_RWLIST_TRAVERSE(&hints
, hint
, list
) {
4207 if (hint
->exten
== oe
) {
4217 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
4218 static int ast_add_hint(struct ast_exten
*e
)
4220 struct ast_hint
*hint
;
4226 /* Search if hint exists, do nothing */
4227 AST_RWLIST_TRAVERSE(&hints
, hint
, list
) {
4228 if (hint
->exten
== e
) {
4229 if (option_debug
> 1)
4230 ast_log(LOG_DEBUG
, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
4235 if (option_debug
> 1)
4236 ast_log(LOG_DEBUG
, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
4238 if (!(hint
= ast_calloc(1, sizeof(*hint
)))) {
4241 /* Initialize and insert new item at the top */
4243 AST_RWLIST_INSERT_HEAD(&hints
, hint
, list
);
4248 /*! \brief add the extension in the priority chain.
4249 * returns 0 on success, -1 on failure
4251 static int add_pri(struct ast_context
*con
, struct ast_exten
*tmp
,
4252 struct ast_exten
*el
, struct ast_exten
*e
, int replace
)
4254 struct ast_exten
*ep
;
4256 for (ep
= NULL
; e
; ep
= e
, e
= e
->peer
) {
4257 if (e
->priority
>= tmp
->priority
)
4260 if (!e
) { /* go at the end, and ep is surely set because the list is not empty */
4262 return 0; /* success */
4264 if (e
->priority
== tmp
->priority
) {
4265 /* Can't have something exactly the same. Is this a
4266 replacement? If so, replace, otherwise, bonk. */
4268 ast_log(LOG_WARNING
, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp
->exten
, tmp
->priority
, con
->name
);
4269 tmp
->datad(tmp
->data
);
4273 /* we are replacing e, so copy the link fields and then update
4274 * whoever pointed to e to point to us
4276 tmp
->next
= e
->next
; /* not meaningful if we are not first in the peer list */
4277 tmp
->peer
= e
->peer
; /* always meaningful */
4278 if (ep
) /* We're in the peer list, just insert ourselves */
4280 else if (el
) /* We're the first extension. Take over e's functions */
4282 else /* We're the very first extension. */
4284 if (tmp
->priority
== PRIORITY_HINT
)
4285 ast_change_hint(e
,tmp
);
4286 /* Destroy the old one */
4289 } else { /* Slip ourselves in just before e */
4291 tmp
->next
= e
->next
; /* extension chain, or NULL if e is not the first extension */
4292 if (ep
) /* Easy enough, we're just in the peer list */
4294 else { /* we are the first in some peer list, so link in the ext list */
4296 el
->next
= tmp
; /* in the middle... */
4298 con
->root
= tmp
; /* ... or at the head */
4299 e
->next
= NULL
; /* e is no more at the head, so e->next must be reset */
4301 /* And immediately return success. */
4302 if (tmp
->priority
== PRIORITY_HINT
)
4308 /*! \brief ast_remove_hint: Remove hint from extension */
4309 static int ast_remove_hint(struct ast_exten
*e
)
4311 /* Cleanup the Notifys if hint is removed */
4312 struct ast_hint
*hint
;
4313 struct ast_state_cb
*cblist
, *cbprev
;
4319 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints
, hint
, list
) {
4320 if (hint
->exten
== e
) {
4322 cblist
= hint
->callbacks
;
4324 /* Notify with -1 and remove all callbacks */
4326 cblist
= cblist
->next
;
4329 hint
->callbacks
= NULL
;
4330 AST_RWLIST_REMOVE_CURRENT(&hints
, list
);
4336 AST_RWLIST_TRAVERSE_SAFE_END
4341 static void destroy_exten(struct ast_exten
*e
)
4343 if (e
->priority
== PRIORITY_HINT
)
4380 static int ast_build_timing(struct ast_timing
*i
, const char *info_in
)
4382 char info_save
[256];
4385 /* Check for empty just in case */
4386 if (ast_strlen_zero(info_in
))
4388 /* make a copy just in case we were passed a static string */
4389 ast_copy_string(info_save
, info_in
, sizeof(info_save
));
4391 /* Assume everything except time */
4392 i
->monthmask
= 0xfff; /* 12 bits */
4393 i
->daymask
= 0x7fffffffU
; /* 31 bits */
4394 i
->dowmask
= 0x7f; /* 7 bits */
4395 /* on each call, use strsep() to move info to the next argument */
4396 get_timerange(i
, strsep(&info
, "|"));
4398 i
->dowmask
= get_range(strsep(&info
, "|"), 7, days
, "day of week");
4400 i
->daymask
= get_range(strsep(&info
, "|"), 31, NULL
, "day");
4402 i
->monthmask
= get_range(strsep(&info
, "|"), 12, months
, "month");
4407 * \brief helper functions to sort extensions and patterns in the desired way,
4408 * so that more specific patterns appear first.
4410 * ext_cmp1 compares individual characters (or sets of), returning
4411 * an int where bits 0-7 are the ASCII code of the first char in the set,
4412 * while bit 8-15 are the cardinality of the set minus 1.
4413 * This way more specific patterns (smaller cardinality) appear first.
4414 * Wildcards have a special value, so that we can directly compare them to
4415 * sets by subtracting the two values. In particular:
4416 * 0x000xx one character, xx
4417 * 0x0yyxx yy character set starting with xx
4418 * 0x10000 '.' (one or more of anything)
4419 * 0x20000 '!' (zero or more of anything)
4420 * 0x30000 NUL (end of string)
4421 * 0x40000 error in set.
4422 * The pointer to the string is advanced according to needs.
4424 * 1. the empty set is equivalent to NUL.
4425 * 2. given that a full set has always 0 as the first element,
4426 * we could encode the special cases as 0xffXX where XX
4427 * is 1, 2, 3, 4 as used above.
4429 static int ext_cmp1(const char **p
)
4432 int c
, cmin
= 0xff, count
= 0;
4435 /* load, sign extend and advance pointer until we find
4436 * a valid character.
4438 while ( (c
= *(*p
)++) && (c
== ' ' || c
== '-') )
4439 ; /* ignore some characters */
4441 /* always return unless we have a set of chars */
4443 default: /* ordinary character */
4444 return 0x0000 | (c
& 0xff);
4446 case 'N': /* 2..9 */
4447 return 0x0700 | '2' ;
4449 case 'X': /* 0..9 */
4450 return 0x0900 | '0';
4452 case 'Z': /* 1..9 */
4453 return 0x0800 | '1';
4455 case '.': /* wildcard */
4458 case '!': /* earlymatch */
4459 return 0x20000; /* less specific than NULL */
4461 case '\0': /* empty string */
4465 case '[': /* pattern */
4468 /* locate end of set */
4469 end
= strchr(*p
, ']');
4472 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
4473 return 0x40000; /* XXX make this entry go last... */
4476 bzero(chars
, sizeof(chars
)); /* clear all chars in the set */
4477 for (; *p
< end
; (*p
)++) {
4478 unsigned char c1
, c2
; /* first-last char in range */
4479 c1
= (unsigned char)((*p
)[0]);
4480 if (*p
+ 2 < end
&& (*p
)[1] == '-') { /* this is a range */
4481 c2
= (unsigned char)((*p
)[2]);
4482 *p
+= 2; /* skip a total of 3 chars */
4483 } else /* individual character */
4487 for (; c1
<= c2
; c1
++) {
4488 uint32_t mask
= 1 << (c1
% 32);
4489 if ( (chars
[ c1
/ 32 ] & mask
) == 0)
4491 chars
[ c1
/ 32 ] |= mask
;
4495 return count
== 0 ? 0x30000 : (count
| cmin
);
4499 * \brief the full routine to compare extensions in rules.
4501 static int ext_cmp(const char *a
, const char *b
)
4503 /* make sure non-patterns come first.
4504 * If a is not a pattern, it either comes first or
4505 * we use strcmp to compare the strings.
4510 return (b
[0] == '_') ? -1 : strcmp(a
, b
);
4512 /* Now we know a is a pattern; if b is not, a comes first */
4515 #if 0 /* old mode for ext matching */
4516 return strcmp(a
, b
);
4518 /* ok we need full pattern sorting routine */
4519 while (!ret
&& a
&& b
)
4520 ret
= ext_cmp1(&a
) - ext_cmp1(&b
);
4524 return (ret
> 0) ? 1 : -1;
4527 /*! \brief copy a string skipping whitespace */
4528 static int ext_strncpy(char *dst
, const char *src
, int len
)
4532 while (*src
&& (count
< len
- 1)) {
4535 /* otherwise exten => [a-b],1,... doesn't work */
4552 * Wrapper around _extension_match_core() to do performance measurement
4553 * using the profiling code.
4555 static int ast_check_timing(const struct ast_timing
*i
)
4558 time_t t
= time(NULL
);
4560 localtime_r(&t
,&tm
);
4562 /* If it's not the right month, return */
4563 if (!(i
->monthmask
& (1 << tm
.tm_mon
)))
4566 /* If it's not that time of the month.... */
4567 /* Warning, tm_mday has range 1..31! */
4568 if (!(i
->daymask
& (1 << (tm
.tm_mday
-1))))
4571 /* If it's not the right day of the week */
4572 if (!(i
->dowmask
& (1 << tm
.tm_wday
)))
4575 /* Sanity check the hour just to be safe */
4576 if ((tm
.tm_hour
< 0) || (tm
.tm_hour
> 23)) {
4577 ast_log(LOG_WARNING
, "Insane time...\n");
4581 /* Now the tough part, we calculate if it fits
4582 in the right time based on min/hour */
4583 if (!(i
->minmask
[tm
.tm_hour
] & (1 << (tm
.tm_min
/ 2))))
4586 /* If we got this far, then we're good */
4591 static struct ast_switch
*pbx_findswitch(const char *sw
)
4593 struct ast_switch
*asw
;
4595 AST_RWLIST_TRAVERSE(&switches
, asw
, list
) {
4596 if (!strcasecmp(asw
->name
, sw
))
4605 static struct ast_context
*ast_walk_contexts(struct ast_context
*con
);
4607 static struct ast_context
*ast_walk_contexts(struct ast_context
*con
)
4609 return con
? con
->next
: contexts
;
4612 struct ast_context
*localized_walk_contexts(struct ast_context
*con
);
4613 struct ast_context
*localized_walk_contexts(struct ast_context
*con
)
4615 return ast_walk_contexts(con
);
4620 static struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
4621 struct ast_exten
*exten
);
4623 static struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
4624 struct ast_exten
*exten
)
4627 return con
? con
->root
: NULL
;
4632 struct ast_exten
*localized_walk_context_extensions(struct ast_context
*con
,
4633 struct ast_exten
*exten
);
4634 struct ast_exten
*localized_walk_context_extensions(struct ast_context
*con
,
4635 struct ast_exten
*exten
)
4637 return ast_walk_context_extensions(con
,exten
);
4641 static struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
4642 struct ast_exten
*priority
);
4644 static struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
4645 struct ast_exten
*priority
)
4647 return priority
? priority
->peer
: exten
;
4650 struct ast_exten
*localized_walk_extension_priorities(struct ast_exten
*exten
,
4651 struct ast_exten
*priority
);
4652 struct ast_exten
*localized_walk_extension_priorities(struct ast_exten
*exten
,
4653 struct ast_exten
*priority
)
4655 return ast_walk_extension_priorities(exten
, priority
);
4660 static struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
4661 struct ast_include
*inc
);
4663 static struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
4664 struct ast_include
*inc
)
4667 return con
? con
->includes
: NULL
;
4672 struct ast_include
*localized_walk_context_includes(struct ast_context
*con
,
4673 struct ast_include
*inc
);
4674 struct ast_include
*localized_walk_context_includes(struct ast_context
*con
,
4675 struct ast_include
*inc
)
4677 return ast_walk_context_includes(con
, inc
);
4681 static struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
4684 static struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
4688 return con
? AST_LIST_FIRST(&con
->alts
) : NULL
;
4690 return AST_LIST_NEXT(sw
, list
);
4693 struct ast_sw
*localized_walk_context_switches(struct ast_context
*con
,
4695 struct ast_sw
*localized_walk_context_switches(struct ast_context
*con
,
4698 return ast_walk_context_switches(con
, sw
);
4702 static struct ast_context
*ast_context_find(const char *name
);
4704 static struct ast_context
*ast_context_find(const char *name
)
4706 struct ast_context
*tmp
= NULL
;
4707 while ( (tmp
= ast_walk_contexts(tmp
)) ) {
4708 if (!name
|| !strcasecmp(name
, tmp
->name
))
4714 /* request and result for pbx_find_extension */
4715 struct pbx_find_info
{
4717 const char *context
;
4722 char *incstack
[AST_PBX_MAX_STACK
]; /* filled during the search */
4723 int stacklen
; /* modified during the search */
4724 int status
; /* set on return */
4725 struct ast_switch
*swo
; /* set on return */
4726 const char *data
; /* set on return */
4727 const char *foundcontext
; /* set on return */
4731 * Internal function for ast_extension_{match|close}
4732 * return 0 on no-match, 1 on match, 2 on early match.
4733 * mode is as follows:
4734 * E_MATCH success only on exact match
4735 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
4736 * E_CANMATCH either of the above.
4739 static int _extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
4741 mode
&= E_MATCH_MASK
; /* only consider the relevant bits */
4743 if ( (mode
== E_MATCH
) && (pattern
[0] == '_') && (strcasecmp(pattern
,data
)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
4746 if (pattern
[0] != '_') { /* not a pattern, try exact or partial match */
4747 int ld
= strlen(data
), lp
= strlen(pattern
);
4749 if (lp
< ld
) /* pattern too short, cannot match */
4751 /* depending on the mode, accept full or partial match or both */
4752 if (mode
== E_MATCH
)
4753 return !strcmp(pattern
, data
); /* 1 on match, 0 on fail */
4754 if (ld
== 0 || !strncasecmp(pattern
, data
, ld
)) /* partial or full match */
4755 return (mode
== E_MATCHMORE
) ? lp
> ld
: 1; /* XXX should consider '!' and '/' ? */
4759 pattern
++; /* skip leading _ */
4761 * XXX below we stop at '/' which is a separator for the CID info. However we should
4762 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
4764 while (*data
&& *pattern
&& *pattern
!= '/') {
4767 if (*data
== '-') { /* skip '-' in data (just a separator) */
4771 switch (toupper(*pattern
)) {
4772 case '[': /* a range */
4773 end
= strchr(pattern
+1, ']'); /* XXX should deal with escapes ? */
4775 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
4776 return 0; /* unconditional failure */
4778 for (pattern
++; pattern
!= end
; pattern
++) {
4779 if (pattern
+2 < end
&& pattern
[1] == '-') { /* this is a range */
4780 if (*data
>= pattern
[0] && *data
<= pattern
[2])
4781 break; /* match found */
4783 pattern
+= 2; /* skip a total of 3 chars */
4786 } else if (*data
== pattern
[0])
4787 break; /* match found */
4791 pattern
= end
; /* skip and continue */
4794 if (*data
< '2' || *data
> '9')
4798 if (*data
< '0' || *data
> '9')
4802 if (*data
< '1' || *data
> '9')
4805 case '.': /* Must match, even with more digits */
4807 case '!': /* Early match */
4810 case '-': /* Ignore these in patterns */
4811 data
--; /* compensate the final data++ */
4814 if (*data
!= *pattern
)
4820 if (*data
) /* data longer than pattern, no match */
4823 * match so far, but ran off the end of the data.
4824 * Depending on what is next, determine match or not.
4826 if (*pattern
== '\0' || *pattern
== '/') /* exact match */
4827 return (mode
== E_MATCHMORE
) ? 0 : 1; /* this is a failure for E_MATCHMORE */
4828 else if (*pattern
== '!') /* early match */
4830 else /* partial match */
4831 return (mode
== E_MATCH
) ? 0 : 1; /* this is a failure for E_MATCH */
4834 static int extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
4837 i
= _extension_match_core(pattern
, data
, mode
);
4841 static int ast_extension_match(const char *pattern
, const char *data
);
4843 static int ast_extension_match(const char *pattern
, const char *data
)
4845 return extension_match_core(pattern
, data
, E_MATCH
);
4848 static int matchcid(const char *cidpattern
, const char *callerid
)
4850 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
4851 failing to get a number should count as a match, otherwise not */
4853 if (ast_strlen_zero(callerid
))
4854 return ast_strlen_zero(cidpattern
) ? 1 : 0;
4856 return ast_extension_match(cidpattern
, callerid
);
4859 static inline int include_valid(struct ast_include
*i
)
4864 return ast_check_timing(&(i
->timing
));
4869 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
4870 struct ast_context
*bypass
,
4871 struct pbx_find_info
*q
,
4872 const char *context
,
4876 const char *callerid
,
4877 enum ext_match_t action
);
4880 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
4881 struct ast_context
*bypass
,
4882 struct pbx_find_info
*q
,
4883 const char *context
,
4887 const char *callerid
,
4888 enum ext_match_t action
)
4891 struct ast_context
*tmp
;
4892 struct ast_exten
*e
, *eroot
;
4893 struct ast_include
*i
;
4895 /* Initialize status if appropriate */
4896 if (q
->stacklen
== 0) {
4897 q
->status
= STATUS_NO_CONTEXT
;
4900 q
->foundcontext
= NULL
;
4901 } else if (q
->stacklen
>= AST_PBX_MAX_STACK
) {
4902 ast_log(LOG_WARNING
, "Maximum PBX stack exceeded\n");
4905 /* Check first to see if we've already been checked */
4906 for (x
= 0; x
< q
->stacklen
; x
++) {
4907 if (!strcasecmp(q
->incstack
[x
], context
))
4910 if (bypass
) /* bypass means we only look there */
4912 else { /* look in contexts */
4914 while ((tmp
= ast_walk_contexts(tmp
)) ) {
4915 if (!strcmp(tmp
->name
, context
))
4921 if (q
->status
< STATUS_NO_EXTENSION
)
4922 q
->status
= STATUS_NO_EXTENSION
;
4924 /* scan the list trying to match extension and CID */
4926 while ( (eroot
= ast_walk_context_extensions(tmp
, eroot
)) ) {
4927 int match
= extension_match_core(eroot
->exten
, exten
, action
);
4928 /* 0 on fail, 1 on match, 2 on earlymatch */
4930 if (!match
|| (eroot
->matchcid
&& !matchcid(eroot
->cidmatch
, callerid
)))
4931 continue; /* keep trying */
4932 if (match
== 2 && action
== E_MATCHMORE
) {
4933 /* We match an extension ending in '!'.
4934 * The decision in this case is final and is NULL (no match).
4938 /* found entry, now look for the right priority */
4939 if (q
->status
< STATUS_NO_PRIORITY
)
4940 q
->status
= STATUS_NO_PRIORITY
;
4942 while ( (e
= ast_walk_extension_priorities(eroot
, e
)) ) {
4943 /* Match label or priority */
4944 if (action
== E_FINDLABEL
) {
4945 if (q
->status
< STATUS_NO_LABEL
)
4946 q
->status
= STATUS_NO_LABEL
;
4947 if (label
&& e
->label
&& !strcmp(label
, e
->label
))
4948 break; /* found it */
4949 } else if (e
->priority
== priority
) {
4950 break; /* found it */
4951 } /* else keep searching */
4953 if (e
) { /* found a valid match */
4954 q
->status
= STATUS_SUCCESS
;
4955 q
->foundcontext
= context
;
4959 #ifdef NOT_RIGHT_NOW
4960 /* Check alternative switches??? */
4961 AST_LIST_TRAVERSE(&tmp
->alts
, sw
, list
) {
4962 struct ast_switch
*asw
= pbx_findswitch(sw
->name
);
4963 ast_switch_f
*aswf
= NULL
;
4967 ast_log(LOG_WARNING
, "No such switch '%s'\n", sw
->name
);
4970 /* No need to Substitute variables now; we shouldn't be here if there's any */
4972 /* equivalent of extension_match_core() at the switch level */
4973 if (action
== E_CANMATCH
)
4974 aswf
= asw
->canmatch
;
4975 else if (action
== E_MATCHMORE
)
4976 aswf
= asw
->matchmore
;
4977 else /* action == E_MATCH */
4979 datap
= sw
->eval
? sw
->tmpdata
: sw
->data
;
4980 res
= !aswf
? 0 : aswf(chan
, context
, exten
, priority
, callerid
, datap
);
4981 if (res
) { /* Got a match */
4984 q
->foundcontext
= context
;
4985 /* XXX keep status = STATUS_NO_CONTEXT ? */
4990 q
->incstack
[q
->stacklen
++] = tmp
->name
; /* Setup the stack */
4991 /* Now try any includes we have in this context */
4992 for (i
= tmp
->includes
; i
; i
= i
->next
) {
4993 if (include_valid(i
)) {
4994 if ((e
= pbx_find_extension(NULL
, bypass
, q
, i
->rname
, exten
, priority
, label
, callerid
, action
)))
5003 struct ast_exten
*localized_find_extension(struct ast_context
*bypass
,
5004 struct pbx_find_info
*q
,
5005 const char *context
,
5009 const char *callerid
,
5010 enum ext_match_t action
);
5012 struct ast_exten
*localized_find_extension(struct ast_context
*bypass
,
5013 struct pbx_find_info
*q
,
5014 const char *context
,
5018 const char *callerid
,
5019 enum ext_match_t action
)
5021 return pbx_find_extension(NULL
, bypass
, q
, context
, exten
, priority
, label
, callerid
, action
);
5025 static struct ast_context
*contexts
;
5026 AST_RWLOCK_DEFINE_STATIC(conlock
); /*!< Lock for the ast_context list */
5028 static const char *ast_get_context_name(struct ast_context
*con
);
5030 static const char *ast_get_context_name(struct ast_context
*con
)
5032 return con
? con
->name
: NULL
;
5037 * ENOMEM - out of memory
5038 * EBUSY - can't lock
5039 * EEXIST - already included
5040 * EINVAL - there is no existence of context for inclusion
5042 static int ast_context_add_include2(struct ast_context
*con
, const char *value
,
5043 const char *registrar
);
5045 static int ast_context_add_include2(struct ast_context
*con
, const char *value
,
5046 const char *registrar
)
5048 struct ast_include
*new_include
;
5050 struct ast_include
*i
, *il
= NULL
; /* include, include_last */
5054 length
= sizeof(struct ast_include
);
5055 length
+= 2 * (strlen(value
) + 1);
5057 /* allocate new include structure ... */
5058 if (!(new_include
= ast_calloc(1, length
)))
5060 /* Fill in this structure. Use 'p' for assignments, as the fields
5061 * in the structure are 'const char *'
5063 p
= new_include
->stuff
;
5064 new_include
->name
= p
;
5066 p
+= strlen(value
) + 1;
5067 new_include
->rname
= p
;
5069 /* Strip off timing info, and process if it is there */
5070 if ( (c
= strchr(p
, '|')) ) {
5072 new_include
->hastime
= ast_build_timing(&(new_include
->timing
), c
);
5074 new_include
->next
= NULL
;
5075 new_include
->registrar
= registrar
;
5078 /* ... go to last include and check if context is already included too... */
5079 for (i
= con
->includes
; i
; i
= i
->next
) {
5080 if (!strcasecmp(i
->name
, new_include
->name
)) {
5088 /* ... include new context into context list, unlock, return */
5090 il
->next
= new_include
;
5092 con
->includes
= new_include
;
5093 if (option_verbose
> 2)
5094 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include
->name
, ast_get_context_name(con
));
5099 int localized_context_add_include2(struct ast_context
*con
, const char *value
,
5100 const char *registrar
);
5101 int localized_context_add_include2(struct ast_context
*con
, const char *value
,
5102 const char *registrar
)
5104 return ast_context_add_include2(con
, value
, registrar
);
5109 static int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
);
5111 static int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
5113 struct ast_ignorepat
*ignorepat
, *ignorepatc
, *ignorepatl
= NULL
;
5115 length
= sizeof(struct ast_ignorepat
);
5116 length
+= strlen(value
) + 1;
5117 if (!(ignorepat
= ast_calloc(1, length
)))
5119 /* The cast to char * is because we need to write the initial value.
5120 * The field is not supposed to be modified otherwise
5122 strcpy((char *)ignorepat
->pattern
, value
);
5123 ignorepat
->next
= NULL
;
5124 ignorepat
->registrar
= registrar
;
5125 for (ignorepatc
= con
->ignorepats
; ignorepatc
; ignorepatc
= ignorepatc
->next
) {
5126 ignorepatl
= ignorepatc
;
5127 if (!strcasecmp(ignorepatc
->pattern
, value
)) {
5134 ignorepatl
->next
= ignorepat
;
5136 con
->ignorepats
= ignorepat
;
5141 int localized_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
);
5143 int localized_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
5145 return ast_context_add_ignorepat2(con
, value
, registrar
);
5150 * Lock context list functions ...
5153 static int ast_wrlock_contexts(void)
5155 return ast_rwlock_wrlock(&conlock
);
5158 static int ast_unlock_contexts(void)
5160 return ast_rwlock_unlock(&conlock
);
5163 static int ast_wrlock_context(struct ast_context
*con
)
5165 return ast_rwlock_wrlock(&con
->lock
);
5168 static int ast_unlock_context(struct ast_context
*con
)
5170 return ast_rwlock_unlock(&con
->lock
);
5175 * ENOMEM - out of memory
5176 * EBUSY - can't lock
5177 * EEXIST - already included
5178 * EINVAL - there is no existence of context for inclusion
5180 static int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
5181 const char *data
, int eval
, const char *registrar
);
5183 static int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
5184 const char *data
, int eval
, const char *registrar
)
5186 struct ast_sw
*new_sw
;
5191 length
= sizeof(struct ast_sw
);
5192 length
+= strlen(value
) + 1;
5194 length
+= strlen(data
);
5197 /* Create buffer for evaluation of variables */
5198 length
+= SWITCH_DATA_LENGTH
;
5202 /* allocate new sw structure ... */
5203 if (!(new_sw
= ast_calloc(1, length
)))
5205 /* ... fill in this structure ... */
5208 strcpy(new_sw
->name
, value
);
5209 p
+= strlen(value
) + 1;
5212 strcpy(new_sw
->data
, data
);
5213 p
+= strlen(data
) + 1;
5215 strcpy(new_sw
->data
, "");
5219 new_sw
->tmpdata
= p
;
5220 new_sw
->eval
= eval
;
5221 new_sw
->registrar
= registrar
;
5223 /* ... go to last sw and check if context is already swd too... */
5224 AST_LIST_TRAVERSE(&con
->alts
, i
, list
) {
5225 if (!strcasecmp(i
->name
, new_sw
->name
) && !strcasecmp(i
->data
, new_sw
->data
)) {
5232 /* ... sw new context into context list, unlock, return */
5233 AST_LIST_INSERT_TAIL(&con
->alts
, new_sw
, list
);
5235 if (option_verbose
> 2)
5236 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw
->name
, new_sw
->data
, ast_get_context_name(con
));
5241 int localized_context_add_switch2(struct ast_context
*con
, const char *value
,
5242 const char *data
, int eval
, const char *registrar
);
5244 int localized_context_add_switch2(struct ast_context
*con
, const char *value
,
5245 const char *data
, int eval
, const char *registrar
)
5247 return ast_context_add_switch2(con
, value
, data
, eval
, registrar
);
5250 static struct ast_context
*__ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
, int existsokay
)
5252 struct ast_context
*tmp
, **local_contexts
;
5253 int length
= sizeof(struct ast_context
) + strlen(name
) + 1;
5256 ast_wrlock_contexts();
5257 local_contexts
= &contexts
;
5259 local_contexts
= extcontexts
;
5261 for (tmp
= *local_contexts
; tmp
; tmp
= tmp
->next
) {
5262 if (!strcasecmp(tmp
->name
, name
)) {
5264 ast_log(LOG_WARNING
, "Tried to register context '%s', already in use\n", name
);
5268 ast_unlock_contexts();
5272 if ((tmp
= ast_calloc(1, length
))) {
5273 ast_rwlock_init(&tmp
->lock
);
5274 ast_mutex_init(&tmp
->macrolock
);
5275 strcpy(tmp
->name
, name
);
5277 tmp
->registrar
= registrar
;
5278 tmp
->next
= *local_contexts
;
5279 tmp
->includes
= NULL
;
5280 tmp
->ignorepats
= NULL
;
5281 *local_contexts
= tmp
;
5283 ast_log(LOG_DEBUG
, "Registered context '%s'\n", tmp
->name
);
5284 if (option_verbose
> 2)
5285 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp
->name
);
5289 ast_unlock_contexts();
5294 * Main interface to add extensions to the list for out context.
5296 * We sort extensions in order of matching preference, so that we can
5297 * stop the search as soon as we find a suitable match.
5298 * This ordering also takes care of wildcards such as '.' (meaning
5299 * "one or more of any character") and '!' (which is 'earlymatch',
5300 * meaning "zero or more of any character" but also impacts the
5301 * return value from CANMATCH and EARLYMATCH.
5303 * The extension match rules defined in the devmeeting 2006.05.05 are
5304 * quite simple: WE SELECT THE LONGEST MATCH.
5305 * In detail, "longest" means the number of matched characters in
5306 * the extension. In case of ties (e.g. _XXX and 333) in the length
5307 * of a pattern, we give priority to entries with the smallest cardinality
5308 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
5309 * while the latter has 7, etc.
5310 * In case of same cardinality, the first element in the range counts.
5311 * If we still have a tie, any final '!' will make this as a possibly
5312 * less specific pattern.
5314 * EBUSY - can't lock
5315 * EEXIST - extension with the same priority exist and no replace is set
5318 static int ast_add_extension2(struct ast_context
*con
,
5319 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
5320 const char *application
, void *data
, void (*datad
)(void *),
5321 const char *registrar
)
5324 * Sort extensions (or patterns) according to the rules indicated above.
5325 * These are implemented by the function ext_cmp()).
5326 * All priorities for the same ext/pattern/cid are kept in a list,
5327 * using the 'peer' field as a link field..
5329 struct ast_exten
*tmp
, *e
, *el
= NULL
;
5334 /* if we are adding a hint, and there are global variables, and the hint
5335 contains variable references, then expand them --- NOT In this situation!!!
5338 length
= sizeof(struct ast_exten
);
5339 length
+= strlen(extension
) + 1;
5340 length
+= strlen(application
) + 1;
5342 length
+= strlen(label
) + 1;
5344 length
+= strlen(callerid
) + 1;
5346 length
++; /* just the '\0' */
5348 /* Be optimistic: Build the extension structure first */
5351 if (!(tmp
= ast_calloc(1, length
)))
5354 /* use p as dst in assignments, as the fields are const char * */
5359 p
+= strlen(label
) + 1;
5362 p
+= ext_strncpy(p
, extension
, strlen(extension
) + 1) + 1;
5363 tmp
->priority
= priority
;
5364 tmp
->cidmatch
= p
; /* but use p for assignments below */
5366 p
+= ext_strncpy(p
, callerid
, strlen(callerid
) + 1) + 1;
5373 strcpy(p
, application
);
5377 tmp
->registrar
= registrar
;
5379 res
= 0; /* some compilers will think it is uninitialized otherwise */
5380 for (e
= con
->root
; e
; el
= e
, e
= e
->next
) { /* scan the extension list */
5381 res
= ext_cmp(e
->exten
, extension
);
5382 if (res
== 0) { /* extension match, now look at cidmatch */
5383 if (!e
->matchcid
&& !tmp
->matchcid
)
5385 else if (tmp
->matchcid
&& !e
->matchcid
)
5387 else if (e
->matchcid
&& !tmp
->matchcid
)
5390 res
= strcasecmp(e
->cidmatch
, tmp
->cidmatch
);
5395 if (e
&& res
== 0) { /* exact match, insert in the pri chain */
5396 res
= add_pri(con
, tmp
, el
, e
, replace
);
5398 errno
= EEXIST
; /* XXX do we care ? */
5399 return 0; /* XXX should we return -1 maybe ? */
5403 * not an exact match, this is the first entry with this pattern,
5404 * so insert in the main list right before 'e' (if any)
5411 if (tmp
->priority
== PRIORITY_HINT
)
5415 if (tmp
->matchcid
) {
5416 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d (CID match '%s') to %s\n",
5417 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
5419 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d to %s\n",
5420 tmp
->exten
, tmp
->priority
, con
->name
);
5423 if (option_verbose
> 2) {
5424 if (tmp
->matchcid
) {
5425 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
5426 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
5428 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
5429 tmp
->exten
, tmp
->priority
, con
->name
);
5435 int localized_add_extension2(struct ast_context
*con
,
5436 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
5437 const char *application
, void *data
, void (*datad
)(void *),
5438 const char *registrar
);
5440 int localized_add_extension2(struct ast_context
*con
,
5441 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
5442 const char *application
, void *data
, void (*datad
)(void *),
5443 const char *registrar
)
5445 return ast_add_extension2(con
, replace
, extension
, priority
, label
, callerid
, application
, data
, datad
, registrar
);
5450 /*! \brief The return value depends on the action:
5452 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
5453 * and return 0 on failure, -1 on match;
5454 * E_FINDLABEL maps the label to a priority, and returns
5455 * the priority on success, ... XXX
5456 * E_SPAWN, spawn an application,
5457 * and return 0 on success, -1 on failure.
5459 static int pbx_extension_helper(struct ast_channel
*c
, struct ast_context
*con
,
5460 const char *context
, const char *exten
, int priority
,
5461 const char *label
, const char *callerid
, enum ext_match_t action
)
5463 struct ast_exten
*e
;
5465 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is reset in pbx_find_extension */
5467 int matching_action
= (action
== E_MATCH
|| action
== E_CANMATCH
|| action
== E_MATCHMORE
);
5469 e
= pbx_find_extension(NULL
, con
, &q
, context
, exten
, priority
, label
, callerid
, action
);
5471 if (matching_action
) {
5472 return -1; /* success, we found it */
5473 } else if (action
== E_FINDLABEL
) { /* map the label to a priority */
5475 return res
; /* the priority we were looking for */
5476 } else { /* spawn */
5481 } else if (q
.swo
) { /* not found here, but in another switch */
5482 if (matching_action
)
5486 ast_log(LOG_WARNING
, "No execution engine for switch %s\n", q
.swo
->name
);
5489 return q
.swo
->exec(c
, q
.foundcontext
? q
.foundcontext
: context
, exten
, priority
, callerid
, q
.data
);
5491 } else { /* not found anywhere, see what happened */
5493 case STATUS_NO_CONTEXT
:
5494 if (!matching_action
)
5495 ast_log(LOG_NOTICE
, "Cannot find extension context '%s'\n", context
);
5497 case STATUS_NO_EXTENSION
:
5498 if (!matching_action
)
5499 ast_log(LOG_NOTICE
, "Cannot find extension '%s' in context '%s'\n", exten
, context
);
5501 case STATUS_NO_PRIORITY
:
5502 if (!matching_action
)
5503 ast_log(LOG_NOTICE
, "No such priority %d in extension '%s' in context '%s'\n", priority
, exten
, context
);
5505 case STATUS_NO_LABEL
:
5507 ast_log(LOG_NOTICE
, "No such label '%s' in extension '%s' in context '%s'\n", label
, exten
, context
);
5511 ast_log(LOG_DEBUG
, "Shouldn't happen!\n");
5514 return (matching_action
) ? 0 : -1;
5518 static int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
);
5520 static int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
)
5522 return pbx_extension_helper(c
, con
, NULL
, exten
, 0, label
, callerid
, E_FINDLABEL
);
5525 static struct ast_context
*ast_context_find_or_create(struct ast_context
**extcontexts
, void *tab
, const char *name
, const char *registrar
)
5527 return __ast_context_create(extcontexts
, name
, registrar
, 1);
5530 struct ast_context
*localized_context_find_or_create(struct ast_context
**extcontexts
, void *tab
, const char *name
, const char *registrar
);
5531 struct ast_context
*localized_context_find_or_create(struct ast_context
**extcontexts
, void *tab
, const char *name
, const char *registrar
)
5533 return __ast_context_create(extcontexts
, name
, registrar
, 1);
5537 /* chopped this one off at the knees */
5538 static int ast_func_read(struct ast_channel
*chan
, const char *function
, char *workspace
, size_t len
)
5540 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
5544 /*! \brief extract offset:length from variable name.
5545 * Returns 1 if there is a offset:length part, which is
5546 * trimmed off (values go into variables)
5548 static int parse_variable_name(char *var
, int *offset
, int *length
, int *isfunc
)
5555 for (; *var
; var
++) {
5559 } else if (*var
== ')') {
5561 } else if (*var
== ':' && parens
== 0) {
5563 sscanf(var
, "%d:%d", offset
, length
);
5564 return 1; /* offset:length valid */
5570 static const char *ast_var_value(const struct ast_var_t
*var
)
5572 return (var
? var
->value
: NULL
);
5575 /*! \brief takes a substring. It is ok to call with value == workspace.
5577 * offset < 0 means start from the end of the string and set the beginning
5578 * to be that many characters back.
5579 * length is the length of the substring. A value less than 0 means to leave
5580 * that many off the end.
5581 * Always return a copy in workspace.
5583 static char *substring(const char *value
, int offset
, int length
, char *workspace
, size_t workspace_len
)
5585 char *ret
= workspace
;
5586 int lr
; /* length of the input string after the copy */
5588 ast_copy_string(workspace
, value
, workspace_len
); /* always make a copy */
5590 lr
= strlen(ret
); /* compute length after copy, so we never go out of the workspace */
5592 /* Quick check if no need to do anything */
5593 if (offset
== 0 && length
>= lr
) /* take the whole string */
5596 if (offset
< 0) { /* translate negative offset into positive ones */
5597 offset
= lr
+ offset
;
5598 if (offset
< 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
5602 /* too large offset result in empty string so we know what to return */
5604 return ret
+ lr
; /* the final '\0' */
5606 ret
+= offset
; /* move to the start position */
5607 if (length
>= 0 && length
< lr
- offset
) /* truncate if necessary */
5609 else if (length
< 0) {
5610 if (lr
> offset
- length
) /* After we remove from the front and from the rear, is there anything left? */
5611 ret
[lr
+ length
- offset
] = '\0';
5619 /*! \brief Support for Asterisk built-in variables in the dialplan
5621 - \ref AstVar Channel variables
5622 - \ref AstCauses The HANGUPCAUSE variable
5624 static void pbx_retrieve_variable(struct ast_channel
*c
, const char *var
, char **ret
, char *workspace
, int workspacelen
, struct varshead
*headp
)
5626 const char not_found
= '\0';
5628 const char *s
; /* the result */
5630 int i
, need_substring
;
5631 struct varshead
*places
[2] = { headp
, &globals
}; /* list of places where we may look */
5634 * Make a copy of var because parse_variable_name() modifies the string.
5635 * Then if called directly, we might need to run substring() on the result;
5636 * remember this for later in 'need_substring', 'offset' and 'length'
5638 tmpvar
= ast_strdupa(var
); /* parse_variable_name modifies the string */
5639 need_substring
= parse_variable_name(tmpvar
, &offset
, &length
, &i
/* ignored */);
5642 * Look first into predefined variables, then into variable lists.
5643 * Variable 's' points to the result, according to the following rules:
5644 * s == ¬_found (set at the beginning) means that we did not find a
5645 * matching variable and need to look into more places.
5646 * If s != ¬_found, s is a valid result string as follows:
5647 * s = NULL if the variable does not have a value;
5648 * you typically do this when looking for an unset predefined variable.
5649 * s = workspace if the result has been assembled there;
5650 * typically done when the result is built e.g. with an snprintf(),
5651 * so we don't need to do an additional copy.
5652 * s != workspace in case we have a string, that needs to be copied
5653 * (the ast_copy_string is done once for all at the end).
5654 * Typically done when the result is already available in some string.
5656 s
= ¬_found
; /* default value */
5657 if (s
== ¬_found
) { /* look for more */
5658 if (!strcmp(var
, "EPOCH")) {
5659 snprintf(workspace
, workspacelen
, "%u",(int)time(NULL
));
5664 /* if not found, look into chanvars or global vars */
5665 for (i
= 0; s
== ¬_found
&& i
< (sizeof(places
) / sizeof(places
[0])); i
++) {
5666 struct ast_var_t
*variables
;
5669 if (places
[i
] == &globals
)
5670 ast_rwlock_rdlock(&globalslock
);
5671 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
5672 if (strcasecmp(ast_var_name(variables
), var
)==0) {
5673 s
= ast_var_value(variables
);
5677 if (places
[i
] == &globals
)
5678 ast_rwlock_unlock(&globalslock
);
5680 if (s
== ¬_found
|| s
== NULL
)
5684 ast_copy_string(workspace
, s
, workspacelen
);
5687 *ret
= substring(*ret
, offset
, length
, workspace
, workspacelen
);
5691 static void pbx_substitute_variables_helper_full(struct ast_channel
*c
, struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
5693 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
5696 const char *tmp
, *whereweare
;
5697 int length
, offset
, offset2
, isfunction
;
5698 char *workspace
= NULL
;
5699 char *ltmp
= NULL
, *var
= NULL
;
5700 char *nextvar
, *nextexp
, *nextthing
;
5702 int pos
, brackets
, needsub
, len
;
5704 *cp2
= 0; /* just in case there's nothing to do */
5706 while (!ast_strlen_zero(whereweare
) && count
) {
5707 /* Assume we're copying the whole remaining string */
5708 pos
= strlen(whereweare
);
5711 nextthing
= strchr(whereweare
, '$');
5713 switch (nextthing
[1]) {
5715 nextvar
= nextthing
;
5716 pos
= nextvar
- whereweare
;
5719 nextexp
= nextthing
;
5720 pos
= nextexp
- whereweare
;
5726 /* Can't copy more than 'count' bytes */
5730 /* Copy that many bytes */
5731 memcpy(cp2
, whereweare
, pos
);
5740 /* We have a variable. Find the start and end, and determine
5741 if we are going to have to recursively call ourselves on the
5743 vars
= vare
= nextvar
+ 2;
5747 /* Find the end of it */
5748 while (brackets
&& *vare
) {
5749 if ((vare
[0] == '$') && (vare
[1] == '{')) {
5751 } else if (vare
[0] == '{') {
5753 } else if (vare
[0] == '}') {
5755 } else if ((vare
[0] == '$') && (vare
[1] == '['))
5760 ast_log(LOG_NOTICE
, "Error in extension logic (missing '}' in '%s')\n", cp1
);
5761 len
= vare
- vars
- 1;
5763 /* Skip totally over variable string */
5764 whereweare
+= (len
+ 3);
5767 var
= alloca(VAR_BUF_SIZE
);
5769 /* Store variable name (and truncate) */
5770 ast_copy_string(var
, vars
, len
+ 1);
5772 /* Substitute if necessary */
5775 ltmp
= alloca(VAR_BUF_SIZE
);
5777 memset(ltmp
, 0, VAR_BUF_SIZE
);
5778 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
5785 workspace
= alloca(VAR_BUF_SIZE
);
5787 workspace
[0] = '\0';
5789 parse_variable_name(vars
, &offset
, &offset2
, &isfunction
);
5791 /* Evaluate function */
5792 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
5794 ast_log(LOG_DEBUG
, "Function result is '%s'\n", cp4
? cp4
: "(null)");
5796 /* Retrieve variable value */
5797 pbx_retrieve_variable(c
, vars
, &cp4
, workspace
, VAR_BUF_SIZE
, headp
);
5800 cp4
= substring(cp4
, offset
, offset2
, workspace
, VAR_BUF_SIZE
);
5802 length
= strlen(cp4
);
5805 memcpy(cp2
, cp4
, length
);
5810 } else if (nextexp
) {
5811 /* We have an expression. Find the start and end, and determine
5812 if we are going to have to recursively call ourselves on the
5814 vars
= vare
= nextexp
+ 2;
5818 /* Find the end of it */
5819 while (brackets
&& *vare
) {
5820 if ((vare
[0] == '$') && (vare
[1] == '[')) {
5824 } else if (vare
[0] == '[') {
5826 } else if (vare
[0] == ']') {
5828 } else if ((vare
[0] == '$') && (vare
[1] == '{')) {
5835 ast_log(LOG_NOTICE
, "Error in extension logic (missing ']')\n");
5836 len
= vare
- vars
- 1;
5838 /* Skip totally over expression */
5839 whereweare
+= (len
+ 3);
5842 var
= alloca(VAR_BUF_SIZE
);
5844 /* Store variable name (and truncate) */
5845 ast_copy_string(var
, vars
, len
+ 1);
5847 /* Substitute if necessary */
5850 ltmp
= alloca(VAR_BUF_SIZE
);
5852 memset(ltmp
, 0, VAR_BUF_SIZE
);
5853 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
5859 length
= ast_expr(vars
, cp2
, count
, NULL
);
5863 ast_log(LOG_DEBUG
, "Expression result is '%s'\n", cp2
);
5873 static void pbx_substitute_variables_helper(struct ast_channel
*c
, const char *cp1
, char *cp2
, int count
)
5875 pbx_substitute_variables_helper_full(c
, NULL
, cp1
, cp2
, count
);
5879 static int pbx_load_config(const char *config_file
);
5881 static int pbx_load_config(const char *config_file
)
5883 struct ast_config
*cfg
;
5886 char realvalue
[256];
5888 struct ast_context
*con
;
5889 struct ast_variable
*v
;
5893 cfg
= localized_config_load(config_file
);
5897 /* Use existing config to populate the PBX table */
5898 static_config
= ast_true(ast_variable_retrieve(cfg
, "general", "static"));
5899 write_protect_config
= ast_true(ast_variable_retrieve(cfg
, "general", "writeprotect"));
5900 if ((aft
= ast_variable_retrieve(cfg
, "general", "autofallthrough")))
5901 autofallthrough_config
= ast_true(aft
);
5902 clearglobalvars_config
= ast_true(ast_variable_retrieve(cfg
, "general", "clearglobalvars"));
5903 ast_set2_flag(&ast_options
, ast_true(ast_variable_retrieve(cfg
, "general", "priorityjumping")), AST_OPT_FLAG_PRIORITY_JUMPING
);
5905 if ((cxt
= ast_variable_retrieve(cfg
, "general", "userscontext")))
5906 ast_copy_string(userscontext
, cxt
, sizeof(userscontext
));
5908 ast_copy_string(userscontext
, "default", sizeof(userscontext
));
5910 for (v
= ast_variable_browse(cfg
, "globals"); v
; v
= v
->next
) {
5911 memset(realvalue
, 0, sizeof(realvalue
));
5912 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
5913 pbx_builtin_setvar_helper(NULL
, v
->name
, realvalue
);
5915 for (cxt
= NULL
; (cxt
= ast_category_browse(cfg
, cxt
)); ) {
5916 /* All categories but "general" or "globals" are considered contexts */
5917 if (!strcasecmp(cxt
, "general") || !strcasecmp(cxt
, "globals"))
5919 con
=ast_context_find_or_create(&local_contexts
,NULL
,cxt
, registrar
);
5923 for (v
= ast_variable_browse(cfg
, cxt
); v
; v
= v
->next
) {
5924 if (!strcasecmp(v
->name
, "exten")) {
5925 char *tc
= ast_strdup(v
->value
);
5928 char realext
[256]="";
5929 char *plus
, *firstp
, *firstc
;
5930 char *pri
, *appl
, *data
, *cidmatch
;
5932 char *ext
= strsep(&stringp
, ",");
5935 pbx_substitute_variables_helper(NULL
, ext
, realext
, sizeof(realext
) - 1);
5936 cidmatch
= strchr(realext
, '/');
5939 ast_shrink_phone_number(cidmatch
);
5941 pri
= strsep(&stringp
, ",");
5944 label
= strchr(pri
, '(');
5947 end
= strchr(label
, ')');
5951 ast_log(LOG_WARNING
, "Label missing trailing ')' at line %d\n", v
->lineno
);
5953 plus
= strchr(pri
, '+');
5956 if (!strcmp(pri
,"hint"))
5958 else if (!strcmp(pri
, "next") || !strcmp(pri
, "n")) {
5962 ast_log(LOG_WARNING
, "Can't use 'next' priority on the first entry!\n");
5963 } else if (!strcmp(pri
, "same") || !strcmp(pri
, "s")) {
5967 ast_log(LOG_WARNING
, "Can't use 'same' priority on the first entry!\n");
5968 } else if (sscanf(pri
, "%d", &ipri
) != 1 &&
5969 (ipri
= ast_findlabel_extension2(NULL
, con
, realext
, pri
, cidmatch
)) < 1) {
5970 ast_log(LOG_WARNING
, "Invalid priority/label '%s' at line %d\n", pri
, v
->lineno
);
5973 appl
= S_OR(stringp
, "");
5974 /* Find the first occurrence of either '(' or ',' */
5975 firstc
= strchr(appl
, ',');
5976 firstp
= strchr(appl
, '(');
5977 if (firstc
&& (!firstp
|| firstc
< firstp
)) {
5978 /* comma found, no parenthesis */
5979 /* or both found, but comma found first */
5980 appl
= strsep(&stringp
, ",");
5982 } else if (!firstc
&& !firstp
) {
5986 /* Final remaining case is parenthesis found first */
5987 appl
= strsep(&stringp
, "(");
5989 end
= strrchr(data
, ')');
5990 if ((end
= strrchr(data
, ')'))) {
5993 ast_log(LOG_WARNING
, "No closing parenthesis found? '%s(%s'\n", appl
, data
);
5995 ast_process_quotes_and_slashes(data
, ',', '|');
6000 appl
= ast_skip_blanks(appl
);
6005 if (!ast_opt_dont_warn
&& !strcmp(realext
, "_."))
6006 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
);
6007 if (ast_add_extension2(con
, 0, realext
, ipri
, label
, cidmatch
, appl
, strdup(data
), ast_free
, registrar
)) {
6008 ast_log(LOG_WARNING
, "Unable to register extension at line %d\n", v
->lineno
);
6013 } else if (!strcasecmp(v
->name
, "include")) {
6014 memset(realvalue
, 0, sizeof(realvalue
));
6015 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
6016 if (ast_context_add_include2(con
, realvalue
, registrar
))
6017 ast_log(LOG_WARNING
, "Unable to include context '%s' in context '%s'\n", v
->value
, cxt
);
6018 } else if (!strcasecmp(v
->name
, "ignorepat")) {
6019 memset(realvalue
, 0, sizeof(realvalue
));
6020 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
6021 if (ast_context_add_ignorepat2(con
, realvalue
, registrar
))
6022 ast_log(LOG_WARNING
, "Unable to include ignorepat '%s' in context '%s'\n", v
->value
, cxt
);
6023 } else if (!strcasecmp(v
->name
, "switch") || !strcasecmp(v
->name
, "lswitch") || !strcasecmp(v
->name
, "eswitch")) {
6024 char *stringp
= realvalue
;
6027 memset(realvalue
, 0, sizeof(realvalue
));
6028 if (!strcasecmp(v
->name
, "switch"))
6029 pbx_substitute_variables_helper(NULL
, v
->value
, realvalue
, sizeof(realvalue
) - 1);
6031 ast_copy_string(realvalue
, v
->value
, sizeof(realvalue
));
6032 appl
= strsep(&stringp
, "/");
6033 data
= strsep(&stringp
, ""); /* XXX what for ? */
6036 if (ast_context_add_switch2(con
, appl
, data
, !strcasecmp(v
->name
, "eswitch"), registrar
))
6037 ast_log(LOG_WARNING
, "Unable to include switch '%s' in context '%s'\n", v
->value
, cxt
);
6039 ast_log(LOG_WARNING
, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v
->name
, v
->lineno
);
6043 ast_config_destroy(cfg
);
6047 static void __ast_context_destroy(struct ast_context
*con
, const char *registrar
)
6049 struct ast_context
*tmp
, *tmpl
=NULL
;
6050 struct ast_include
*tmpi
;
6052 struct ast_exten
*e
, *el
, *en
;
6053 struct ast_ignorepat
*ipi
;
6055 for (tmp
= contexts
; tmp
; ) {
6056 struct ast_context
*next
; /* next starting point */
6057 for (; tmp
; tmpl
= tmp
, tmp
= tmp
->next
) {
6059 ast_log(LOG_DEBUG
, "check ctx %s %s\n", tmp
->name
, tmp
->registrar
);
6060 if ( (!registrar
|| !strcasecmp(registrar
, tmp
->registrar
)) &&
6061 (!con
|| !strcasecmp(tmp
->name
, con
->name
)) )
6062 break; /* found it */
6064 if (!tmp
) /* not found, we are done */
6066 ast_wrlock_context(tmp
);
6068 ast_log(LOG_DEBUG
, "delete ctx %s %s\n", tmp
->name
, tmp
->registrar
);
6074 /* Okay, now we're safe to let it go -- in a sense, we were
6075 ready to let it go as soon as we locked it. */
6076 ast_unlock_context(tmp
);
6077 for (tmpi
= tmp
->includes
; tmpi
; ) { /* Free includes */
6078 struct ast_include
*tmpil
= tmpi
;
6082 for (ipi
= tmp
->ignorepats
; ipi
; ) { /* Free ignorepats */
6083 struct ast_ignorepat
*ipl
= ipi
;
6087 while ((sw
= AST_LIST_REMOVE_HEAD(&tmp
->alts
, list
)))
6089 for (e
= tmp
->root
; e
;) {
6090 for (en
= e
->peer
; en
;) {
6099 ast_rwlock_destroy(&tmp
->lock
);
6101 /* if we have a specific match, we are done, otherwise continue */
6102 tmp
= con
? NULL
: next
;
6106 void localized_context_destroy(struct ast_context
*con
, const char *registrar
);
6108 void localized_context_destroy(struct ast_context
*con
, const char *registrar
)
6110 ast_wrlock_contexts();
6111 __ast_context_destroy(con
,registrar
);
6112 ast_unlock_contexts();
6116 static void ast_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
6118 struct ast_context
*tmp
, *lasttmp
= NULL
;
6120 /* it is very important that this function hold the hint list lock _and_ the conlock
6121 during its operation; not only do we need to ensure that the list of contexts
6122 and extensions does not change, but also that no hint callbacks (watchers) are
6123 added or removed during the merge/delete process
6125 in addition, the locks _must_ be taken in this order, because there are already
6126 other code paths that use this order
6128 ast_wrlock_contexts();
6132 /* XXX remove previous contexts from same registrar */
6134 ast_log(LOG_DEBUG
, "must remove any reg %s\n", registrar
);
6135 __ast_context_destroy(NULL
,registrar
);
6141 /* XXX remove contexts with the same name */
6143 ast_log(LOG_WARNING
, "must remove %s reg %s\n", tmp
->name
, tmp
->registrar
);
6144 __ast_context_destroy(tmp
,tmp
->registrar
);
6150 lasttmp
->next
= contexts
;
6151 contexts
= *extcontexts
;
6152 *extcontexts
= NULL
;
6154 ast_log(LOG_WARNING
, "Requested contexts didn't get merged\n");
6156 ast_unlock_contexts();
6161 void localized_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
);
6163 void localized_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
6165 ast_merge_contexts_and_delete(extcontexts
, registrar
);
6168 static int ast_context_verify_includes(struct ast_context
*con
)
6170 struct ast_include
*inc
= NULL
;
6173 while ( (inc
= ast_walk_context_includes(con
, inc
)) )
6174 if (!ast_context_find(inc
->rname
)) {
6176 if (strcasecmp(inc
->rname
,"parkedcalls")!=0)
6177 ast_log(LOG_WARNING
, "Context '%s' tries to include the nonexistent context '%s'\n",
6178 ast_get_context_name(con
), inc
->rname
);
6183 int localized_context_verify_includes(struct ast_context
*con
);
6185 int localized_context_verify_includes(struct ast_context
*con
)
6187 return ast_context_verify_includes(con
);
6190 int localized_pbx_load_module(void);
6192 int localized_pbx_load_module(void)
6194 struct ast_context
*con
;
6196 if(!pbx_load_config(config
))
6197 return -1 /* AST_MODULE_LOAD_DECLINE*/;
6199 /* pbx_load_users(); */ /* does this affect the dialplan? */
6201 ast_merge_contexts_and_delete(&local_contexts
, registrar
);
6203 for (con
= NULL
; (con
= ast_walk_contexts(con
));)
6204 ast_context_verify_includes(con
);
6206 printf("=== Loading extensions.conf ===\n");
6208 while ((con
= ast_walk_contexts(con
)) ) {
6209 printf("Context: %s\n", con
->name
);
6211 printf("=========\n");