- Make res_timing_pthread allow a max rate of 100/sec instead of 50/sec
[asterisk-bristuff.git] / utils / extconf.c
blob4295abec5cbae4a735e76cf454865b6799906450
1 /*
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.
26 #undef DEBUG_THREADS
28 #include "asterisk/compat.h"
29 #include "asterisk/paths.h" /* we use AST_CONFIG_DIR */
31 #include <errno.h>
32 #include <time.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/resource.h>
37 #include <sys/wait.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <locale.h>
41 #include <ctype.h>
42 #if !defined(SOLARIS) && !defined(__CYGWIN__)
43 #include <err.h>
44 #endif
45 #include <regex.h>
46 #include <limits.h>
47 #include <pthread.h>
48 #include <netdb.h>
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
54 #endif
55 # include <glob.h>
56 #endif
58 #define AST_API_MODULE 1 /* gimme the inline defs! */
59 struct ast_channel
61 char x; /* basically empty! */
66 #include "asterisk/inline_api.h"
67 #include "asterisk/endian.h"
68 #include "asterisk/ast_expr.h"
70 /* logger.h */
72 #define EVENTLOG "event_log"
73 #define QUEUELOG "queue_log"
75 #define DEBUG_M(a) { \
76 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__
108 #ifdef LOG_DEBUG
109 #undef LOG_DEBUG
110 #endif
111 #define __LOG_DEBUG 0
112 #define LOG_DEBUG __LOG_DEBUG, _A_
114 #ifdef LOG_EVENT
115 #undef LOG_EVENT
116 #endif
117 #define __LOG_EVENT 1
118 #define LOG_EVENT __LOG_EVENT, _A_
120 #ifdef LOG_NOTICE
121 #undef LOG_NOTICE
122 #endif
123 #define __LOG_NOTICE 2
124 #define LOG_NOTICE __LOG_NOTICE, _A_
126 #ifdef LOG_WARNING
127 #undef LOG_WARNING
128 #endif
129 #define __LOG_WARNING 3
130 #define LOG_WARNING __LOG_WARNING, _A_
132 #ifdef LOG_ERROR
133 #undef LOG_ERROR
134 #endif
135 #define __LOG_ERROR 4
136 #define LOG_ERROR __LOG_ERROR, _A_
138 #ifdef LOG_VERBOSE
139 #undef LOG_VERBOSE
140 #endif
141 #define __LOG_VERBOSE 5
142 #define LOG_VERBOSE __LOG_VERBOSE, _A_
144 #ifdef LOG_DTMF
145 #undef LOG_DTMF
146 #endif
147 #define __LOG_DTMF 6
148 #define LOG_DTMF __LOG_DTMF, _A_
150 /* lock.h */
152 #ifndef HAVE_MTX_PROFILE
153 #define __MTX_PROF(a) return pthread_mutex_lock((a))
154 #else
155 #define __MTX_PROF(a) do { \
156 int i; \
157 /* profile only non-blocking events */ \
158 ast_mark(mtx_prof, 1); \
159 i = pthread_mutex_trylock((a)); \
160 ast_mark(mtx_prof, 0); \
161 if (!i) \
162 return i; \
163 else \
164 return pthread_mutex_lock((a)); \
165 } while (0)
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
180 #else
181 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
182 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
183 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
185 #ifdef DEBUG_THREADS
187 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
189 #ifdef THREAD_CRASH
190 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
191 #else
192 #define DO_THREAD_CRASH do { } while (0)
193 #endif
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];
205 int 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);
234 DO_THREAD_CRASH;
235 return 0;
238 #endif
240 t->file[0] = filename;
241 t->lineno[0] = lineno;
242 t->func[0] = func;
243 t->thread[0] = 0;
244 t->reentrancy = 0;
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)
264 int res;
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);
272 #endif
274 res = pthread_mutex_trylock(&t->mutex);
275 switch (res) {
276 case 0:
277 pthread_mutex_unlock(&t->mutex);
278 break;
279 case EINVAL:
280 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
281 filename, lineno, func, mutex_name);
282 break;
283 case EBUSY:
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);
288 break;
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
295 else
296 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
297 #endif
298 t->file[0] = filename;
299 t->lineno[0] = lineno;
300 t->func[0] = func;
302 return res;
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)
308 int res;
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);
315 ast_mutex_init(t);
317 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
319 #ifdef DETECT_DEADLOCKS
321 time_t seconds = time(NULL);
322 time_t current;
323 do {
324 #ifdef HAVE_MTX_PROFILE
325 ast_mark(mtx_prof, 1);
326 #endif
327 res = pthread_mutex_trylock(&t->mutex);
328 #ifdef HAVE_MTX_PROFILE
329 ast_mark(mtx_prof, 0);
330 #endif
331 if (res == EBUSY) {
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);
340 usleep(200);
342 } while (res == EBUSY);
344 #else
345 #ifdef HAVE_MTX_PROFILE
346 ast_mark(mtx_prof, 1);
347 res = pthread_mutex_trylock(&t->mutex);
348 ast_mark(mtx_prof, 0);
349 if (res)
350 #endif
351 res = pthread_mutex_lock(&t->mutex);
352 #endif /* DETECT_DEADLOCKS */
354 if (!res) {
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();
360 t->reentrancy++;
361 } else {
362 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
363 filename, lineno, func, mutex_name);
365 } else {
366 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
367 filename, lineno, func, strerror(errno));
368 DO_THREAD_CRASH;
371 return res;
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)
377 int res;
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);
384 ast_mutex_init(t);
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();
394 t->reentrancy++;
395 } else {
396 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
397 filename, lineno, func, mutex_name);
399 } else {
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);
404 return res;
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)
410 int res;
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);
418 #endif
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);
425 DO_THREAD_CRASH;
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);
431 t->reentrancy = 0;
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));
444 DO_THREAD_CRASH;
447 return 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)
478 int res;
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);
486 #endif
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);
493 DO_THREAD_CRASH;
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);
499 t->reentrancy = 0;
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));
512 DO_THREAD_CRASH;
513 } else {
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();
519 t->reentrancy++;
520 } else {
521 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
522 filename, lineno, func, mutex_name);
526 return res;
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)
533 int res;
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);
541 #endif
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);
548 DO_THREAD_CRASH;
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);
554 t->reentrancy = 0;
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));
567 DO_THREAD_CRASH;
568 } else {
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();
574 t->reentrancy++;
575 } else {
576 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
577 filename, lineno, func, mutex_name);
581 return res;
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)
626 __MTX_PROF(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__
707 #ifndef __linux__
708 #define pthread_create __use_ast_pthread_create_instead__
709 #endif
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);
721 #endif
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); \
769 #else
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
773 #endif
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
782 * a single lock.
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"
789 #endif
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),
813 __asm __volatile (
814 " lock xaddl %0, %1 ; "
815 : "+r" (v), /* 0 (result) */
816 "=m" (*p) /* 1 */
817 : "m" (*p)); /* 2 */
818 return (v);
820 #else
821 static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
823 int ret;
824 ret = *p;
825 *p += v;
826 return ret;
828 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
830 return ast_atomic_fetchadd_int_slow(p, v);
832 #endif
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;
851 #else
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) */
857 #endif
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)
869 #else
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);
883 #endif
886 #include "asterisk/hashtab.h"
887 #include "asterisk/ael_structs.h"
888 #include "asterisk/pval.h"
890 /* from utils.h */
892 static unsigned int __unsigned_int_flags_dummy;
894 struct ast_flags { /* stolen from utils.h */
895 unsigned int flags;
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); \
908 if (value) \
909 (p)->flags |= (flag); \
910 else \
911 (p)->flags &= ~(flag); \
912 } while (0)
915 #ifdef __AST_DEBUG_MALLOC
916 static void ast_free(void *ptr) attribute_unused;
917 static void ast_free(void *ptr)
919 free(ptr);
921 #else
922 #define ast_free free
923 #endif
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__)
940 AST_INLINE_API(
941 void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
943 void *p;
945 if (!(p = malloc(len)))
946 MALLOC_FAILURE_MSG;
948 return p;
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__)
963 AST_INLINE_API(
964 void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
966 void *p;
968 if (!(p = calloc(num, len)))
969 MALLOC_FAILURE_MSG;
971 return p;
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__)
999 AST_INLINE_API(
1000 void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
1002 void *newp;
1004 if (!(newp = realloc(p, len)))
1005 MALLOC_FAILURE_MSG;
1007 return newp;
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__)
1026 AST_INLINE_API(
1027 char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
1029 char *newstr = NULL;
1031 if (str) {
1032 if (!(newstr = strdup(str)))
1033 MALLOC_FAILURE_MSG;
1036 return newstr;
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__)
1055 AST_INLINE_API(
1056 char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
1058 char *newstr = NULL;
1060 if (str) {
1061 if (!(newstr = strndup(str, len)))
1062 MALLOC_FAILURE_MSG;
1065 return newstr;
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__)
1080 AST_INLINE_API(
1081 __attribute__((format (printf, 5, 6)))
1082 int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
1084 int res;
1085 va_list ap;
1087 va_start(ap, fmt);
1088 if ((res = vasprintf(ret, fmt, ap)) == -1)
1089 MALLOC_FAILURE_MSG;
1090 va_end(ap);
1092 return res;
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))
1107 AST_INLINE_API(
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),
1111 int res;
1113 if ((res = vasprintf(ret, fmt, ap)) == -1)
1114 MALLOC_FAILURE_MSG;
1116 return res;
1120 #else
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) \
1144 (__extension__ \
1145 ({ \
1146 const char *__old = (s); \
1147 size_t __len = strlen(__old) + 1; \
1148 char *__new = __builtin_alloca(__len); \
1149 memcpy (__new, __old, __len); \
1150 __new; \
1152 #endif
1155 /* from config.c */
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;
1172 #define CB_INCR 250
1174 struct ast_comment {
1175 struct ast_comment *next;
1176 char cmt[0];
1179 static void CB_INIT(void)
1181 if (!comment_buffer) {
1182 comment_buffer = ast_malloc(CB_INCR);
1183 if (!comment_buffer)
1184 return;
1185 comment_buffer[0] = 0;
1186 comment_buffer_size = CB_INCR;
1187 lline_buffer = ast_malloc(CB_INCR);
1188 if (!lline_buffer)
1189 return;
1190 lline_buffer[0] = 0;
1191 lline_buffer_size = CB_INCR;
1192 } else {
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);
1202 if (rem < siz+1) {
1203 comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
1204 if (!comment_buffer)
1205 return;
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;
1215 if (rem < len+1) {
1216 comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
1217 if (!comment_buffer)
1218 return;
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);
1229 if (rem < siz+1) {
1230 lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
1231 if (!lline_buffer)
1232 return;
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)
1259 unsigned int level;
1261 level = safe_system_level++;
1263 /* only replace the handler if it has not already been done */
1264 if (level == 0)
1265 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
1269 void ast_unreplace_sigchld(void);
1271 void ast_unreplace_sigchld(void)
1273 unsigned int level;
1275 level = --safe_system_level;
1277 /* only restore the handler if we are the last one */
1278 if (level == 0)
1279 signal(SIGCHLD, safe_system_prev_handler);
1283 int ast_safe_system(const char *s);
1285 int ast_safe_system(const char *s)
1287 pid_t pid;
1288 #ifdef HAVE_WORKING_FORK
1289 int x;
1290 #endif
1291 int res;
1292 struct rusage rusage;
1293 int status;
1295 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1296 ast_replace_sigchld();
1298 #ifdef HAVE_WORKING_FORK
1299 pid = fork();
1300 #else
1301 pid = vfork();
1302 #endif
1304 if (pid == 0) {
1305 #ifdef HAVE_WORKING_FORK
1306 /* Close file descriptors and launch system command */
1307 for (x = STDERR_FILENO + 1; x < 4096; x++)
1308 close(x);
1309 #endif
1310 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1311 _exit(1);
1312 } else if (pid > 0) {
1313 for(;;) {
1314 res = wait4(pid, &status, 0, &rusage);
1315 if (res > -1) {
1316 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1317 break;
1318 } else if (errno != EINTR)
1319 break;
1321 } else {
1322 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1323 res = -1;
1326 ast_unreplace_sigchld();
1327 #else
1328 res = -1;
1329 #endif
1331 return res;
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);
1338 return x;
1341 static struct ast_config_map {
1342 struct ast_config_map *next;
1343 char *name;
1344 char *driver;
1345 char *database;
1346 char *table;
1347 char stuff[0];
1348 } *config_maps = NULL;
1350 static struct ast_config_engine *config_engine_list;
1352 #define MAX_INCLUDE_LEVEL 10
1355 struct ast_category {
1356 char name[80];
1357 int ignored; /*!< do not let user of the config see this category */
1358 int include_level;
1359 char *file; /*!< the file name from whence this declaration was read */
1360 int lineno;
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;
1368 struct ast_config {
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 */
1373 int include_level;
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 {
1397 char *name;
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))
1416 AST_INLINE_API(
1417 void ast_copy_string(char *dst, const char *src, size_t size),
1419 while (*src && size) {
1420 *dst++ = *src++;
1421 size--;
1423 if (__builtin_expect(!size, 0))
1424 dst--;
1425 *dst = '\0';
1429 AST_INLINE_API(
1430 char *ast_skip_blanks(const char *str),
1432 while (*str && *str < 33)
1433 str++;
1434 return (char *)str;
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
1444 AST_INLINE_API(
1445 char *ast_trim_blanks(char *str),
1447 char *work = str;
1449 if (work) {
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
1456 for it */
1457 while ((work >= str) && *work < 33)
1458 *(work--) = '\0';
1460 return str;
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.
1473 AST_INLINE_API(
1474 char *ast_strip(char *s),
1476 s = ast_skip_blanks(s);
1477 if (s)
1478 ast_trim_blanks(s);
1479 return s;
1484 /* from config.h */
1486 struct ast_variable {
1487 char *name;
1488 char *value;
1489 char *file;
1490 int lineno;
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;
1496 char stuff[0];
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);
1527 return variable;
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);
1539 if (inc)
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);
1544 } else
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);
1552 else
1553 inc->included_file = ast_strdup(included_file);
1555 inc->exec = is_exec;
1556 if (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;
1563 return 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 */
1576 return;
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);
1591 else {
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);
1601 else {
1602 free(cat->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);
1610 else {
1611 free(v->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)
1625 return x;
1627 return 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)
1635 if (!variable)
1636 return;
1637 if (category->last)
1638 category->last->next = variable;
1639 else
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))
1655 return cat;
1658 for (cat = config->root; cat; cat = cat->next) {
1659 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
1660 return cat;
1663 return NULL;
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;
1677 else
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;
1687 if (category) {
1688 for (v = ast_variable_browse(config, category); v; v = v->next) {
1689 if (!strcasecmp(variable, v->name))
1690 return v->value;
1692 } else {
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))
1698 return v->value;
1701 return NULL;
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);
1708 if (new) {
1709 new->lineno = old->lineno;
1710 new->object = old->object;
1711 new->blanklines = old->blanklines;
1712 /* TODO: clone comments? */
1715 return new;
1718 static void ast_variables_destroy(struct ast_variable *v)
1720 struct ast_variable *vn;
1722 while (v) {
1723 vn = v;
1724 v = v->next;
1725 free(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);
1741 free(incl);
1745 static void ast_config_destroy(struct ast_config *cfg)
1747 struct ast_category *cat, *catn;
1749 if (!cfg)
1750 return;
1752 ast_includes_destroy(cfg->includes);
1754 cat = cfg->root;
1755 while (cat) {
1756 ast_variables_destroy(cat->root);
1757 catn = cat;
1758 cat = cat->next;
1759 free(catn);
1761 free(cfg);
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),
1776 /*! Keep quiet */
1777 AST_OPT_FLAG_QUIET = (1 << 2),
1778 /*! Console mode */
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),
1804 /*! Reconnect */
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;
1864 /* linkedlists.h */
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.
1957 Example usage:
1958 \code
1959 static AST_LIST_HEAD(entry_list, entry) entries;
1960 \endcode
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) \
1966 struct name { \
1967 struct type *first; \
1968 struct type *last; \
1969 ast_mutex_t lock; \
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.
1983 Example usage:
1984 \code
1985 static AST_RWLIST_HEAD(entry_list, entry) entries;
1986 \endcode
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) \
1992 struct name { \
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.
2009 Example usage:
2010 \code
2011 static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
2012 \endcode
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) \
2018 struct name { \
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 { \
2027 .first = NULL, \
2028 .last = NULL, \
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 { \
2036 .first = NULL, \
2037 .last = NULL, \
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 { \
2045 .first = NULL, \
2046 .last = NULL, \
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.
2058 Example usage:
2059 \code
2060 static AST_LIST_HEAD_STATIC(entry_list, entry);
2061 \endcode
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) \
2068 struct name { \
2069 struct type *first; \
2070 struct type *last; \
2071 ast_mutex_t lock; \
2072 } name; \
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
2082 #else
2083 #define AST_LIST_HEAD_STATIC(name, type) \
2084 struct name { \
2085 struct type *first; \
2086 struct type *last; \
2087 ast_mutex_t lock; \
2088 } name = AST_LIST_HEAD_INIT_VALUE
2089 #endif
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.
2100 Example usage:
2101 \code
2102 static AST_RWLIST_HEAD_STATIC(entry_list, entry);
2103 \endcode
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) \
2110 struct name { \
2111 struct type *first; \
2112 struct type *last; \
2113 ast_rwlock_t lock; \
2114 } name; \
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
2124 #else
2125 #define AST_RWLIST_HEAD_STATIC(name, type) \
2126 struct name { \
2127 struct type *first; \
2128 struct type *last; \
2129 ast_rwlock_t lock; \
2130 } name = AST_RWLIST_HEAD_INIT_VALUE
2131 #endif
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) \
2139 struct name { \
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); \
2156 } while (0)
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); \
2170 } while (0)
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); \
2183 } while (0)
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:
2193 \code
2194 struct list_entry {
2196 AST_LIST_ENTRY(list_entry) list;
2198 \endcode
2200 The field name \a list here is arbitrary, and can be anything you wish.
2202 #define AST_LIST_ENTRY(type) \
2203 struct { \
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
2250 this macro.
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:
2257 \code
2258 static AST_LIST_HEAD(entry_list, list_entry) entries;
2260 struct list_entry {
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)
2270 \endcode
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
2291 this macro.
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:
2299 \code
2300 static AST_LIST_HEAD(entry_list, list_entry) entries;
2302 struct list_entry {
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;
2313 \endcode
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; \
2325 (var); \
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; \
2347 if (__list_prev) \
2348 __list_prev->field.next = __list_next; \
2349 else \
2350 (head)->first = __list_next; \
2351 if (!__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()
2364 block.
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; \
2370 } else { \
2371 (elm)->field.next = (head)->first; \
2372 (head)->first = (elm); \
2374 __new_prev = (elm); \
2375 } while (0)
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
2446 with this macro.
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
2457 be inserted.
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); \
2467 } while (0)
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); \
2483 } while (0)
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); \
2502 } else { \
2503 (head)->last->field.next = (elm); \
2504 (head)->last = (elm); \
2506 } while (0)
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; \
2521 } else { \
2522 (head)->last->field.next = (list)->first; \
2523 (head)->last = (list)->last; \
2525 } while (0)
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; \
2540 if (cur) { \
2541 (head)->first = cur->field.next; \
2542 cur->field.next = NULL; \
2543 if ((head)->last == cur) \
2544 (head)->last = NULL; \
2546 cur; \
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; \
2564 } else { \
2565 typeof(elm) curelm = (head)->first; \
2566 while (curelm && (curelm->field.next != (elm))) \
2567 curelm = curelm->field.next; \
2568 if (curelm) { \
2569 curelm->field.next = (elm)->field.next; \
2570 if ((head)->last == (elm)) \
2571 (head)->last = curelm; \
2574 (elm)->field.next = NULL; \
2575 } while (0)
2577 #define AST_RWLIST_REMOVE AST_LIST_REMOVE
2579 /* chanvars.h */
2581 struct ast_var_t {
2582 AST_LIST_ENTRY(ast_var_t) entries;
2583 char *value;
2584 char name[0];
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);
2599 /*from channel.h */
2600 #define AST_MAX_EXTENSION 80 /*!< Max length of an extension */
2603 /* from pbx.h */
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);
2630 struct ast_switch {
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;
2637 ast_switch_f *exec;
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)
2662 int x, y=0;
2663 int bracketed = 0;
2665 for (x=0; n[x]; x++) {
2666 switch(n[x]) {
2667 case '[':
2668 bracketed++;
2669 n[y++] = n[x];
2670 break;
2671 case ']':
2672 bracketed--;
2673 n[y++] = n[x];
2674 break;
2675 case '-':
2676 if (bracketed)
2677 n[y++] = n[x];
2678 break;
2679 case '.':
2680 if (!n[x+1])
2681 n[y++] = n[x];
2682 break;
2683 default:
2684 if (!strchr("()", n[x]))
2685 n[y++] = n[x];
2688 n[y] = '\0';
2692 /* stolen from chanvars.c */
2694 static const char *ast_var_name(const struct ast_var_t *var)
2696 const char *name;
2698 if (var == NULL || (name = var->name) == NULL)
2699 return NULL;
2700 /* Return the name without the initial underscores */
2701 if (name[0] == '_') {
2702 name++;
2703 if (name[0] == '_')
2704 name++;
2706 return name;
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, ...)
2728 va_list vars;
2729 va_start(vars,fmt);
2731 printf("LOG: lev:%d file:%s line:%d func: %s ",
2732 level, file, line, function);
2733 vprintf(fmt, vars);
2734 fflush(stdout);
2735 va_end(vars);
2738 static void __attribute__((format (printf, 1, 2))) ast_verbose(const char *fmt, ...)
2740 va_list vars;
2741 va_start(vars,fmt);
2743 printf("VERBOSE: ");
2744 vprintf(fmt, vars);
2745 fflush(stdout);
2746 va_end(vars);
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;
2753 int inEscape = 0;
2754 int inQuotes = 0;
2756 for (; *start; start++) {
2757 if (inEscape) {
2758 *dataPut++ = *start; /* Always goes verbatim */
2759 inEscape = 0;
2760 } else {
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 */
2765 } else {
2766 /* Replace , with |, unless in quotes */
2767 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
2771 if (start != dataPut)
2772 *dataPut = 0;
2773 return dataPut;
2776 static int ast_true(const char *s)
2778 if (ast_strlen_zero(s))
2779 return 0;
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"))
2788 return -1;
2790 return 0;
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
2809 priority.
2811 struct ast_exten {
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 */
2825 char stuff[0];
2827 /* from pbx.h */
2828 typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
2829 struct ast_timing {
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 */
2836 /* end of pbx.h */
2837 /*! \brief ast_include: include= support in extensions.conf */
2838 struct ast_include {
2839 const char *name;
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 */
2845 char stuff[0];
2848 /*! \brief ast_sw: Switch statement in extensions.conf */
2849 struct ast_sw {
2850 char *name;
2851 const char *registrar; /*!< Registrar */
2852 char *data; /*!< Data load */
2853 int eval;
2854 AST_LIST_ENTRY(ast_sw) list;
2855 char *tmpdata;
2856 char stuff[0];
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 */
2881 struct ast_app {
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 &lt;name&gt;' */
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 {
2893 int id;
2894 void *data;
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
2905 struct ast_hint {
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 */
2912 struct store_hint {
2913 char *context;
2914 char *exten;
2915 struct ast_state_cb *callbacks;
2916 int laststate;
2917 AST_LIST_ENTRY(store_hint) list;
2918 char data[1];
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
2948 rdtsc(void)
2950 uint64_t rv;
2952 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
2953 return (rv);
2955 #endif
2956 #else /* supply a dummy function on other platforms */
2957 static __inline uint64_t
2958 rdtsc(void)
2960 return 0;
2962 #endif
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)))) {
2972 return NULL;
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);
2979 return var;
2982 static void ast_var_delete(struct ast_var_t *var)
2984 if (var)
2985 free(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 */
2995 return -1;
2998 static unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
3000 int argc;
3001 char *scan;
3002 int paren = 0, quote = 0;
3004 if (!buf || !array || !arraylen)
3005 return 0;
3007 memset(array, 0, arraylen * sizeof(*array));
3009 scan = buf;
3011 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
3012 array[argc] = scan;
3013 for (; *scan; scan++) {
3014 if (*scan == '(')
3015 paren++;
3016 else if (*scan == ')') {
3017 if (paren)
3018 paren--;
3019 } else if (*scan == '"' && delim != '"') {
3020 quote = quote ? 0 : 1;
3021 /* Remove quote character from argument */
3022 memmove(scan, scan + 1, strlen(scan));
3023 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) {
3028 *scan++ = '\0';
3029 break;
3034 if (*scan)
3035 array[argc++] = scan;
3037 return argc;
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);
3051 return;
3054 headp = &globals;
3056 /* For comparison purposes, we have to strip leading underscores */
3057 if (*nametail == '_') {
3058 nametail++;
3059 if (*nametail == '_')
3060 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);
3068 break;
3072 if (value) {
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;
3084 int argc;
3085 char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
3086 int global = 0;
3087 int x;
3089 if (ast_strlen_zero(data)) {
3090 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
3091 return 0;
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], '=')) {
3099 argc--;
3100 if (strchr(argv[argc], 'g'))
3101 global = 1;
3104 for (x = 0; x < argc; x++) {
3105 name = argv[x];
3106 if ((value = strchr(name, '='))) {
3107 *value++ = '\0';
3108 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
3109 } else
3110 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
3113 return(0);
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)
3131 int i;
3133 if (names) {
3134 for (i = 0; names[i]; i++) {
3135 if (!strcasecmp(s, names[i]))
3136 return i+1;
3138 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
3139 return i;
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, "*")) {
3154 s = 0;
3155 e = max - 1;
3156 } else {
3157 /* Get start and ending position */
3158 char *c = strchr(src, '-');
3159 if (c)
3160 *c++ = '\0';
3161 /* Find the start */
3162 s = lookup_name(src, names, max);
3163 if (!s) {
3164 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
3165 return 0;
3167 s--;
3168 if (c) { /* find end of range */
3169 e = lookup_name(c, names, max);
3170 if (!e) {
3171 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
3172 return 0;
3174 e--;
3175 } else
3176 e = s;
3178 /* Fill the mask. Remember that ranges are cyclic */
3179 mask = 1 << e; /* initialize with last element */
3180 while (s != e) {
3181 if (s >= max) {
3182 s = 0;
3183 mask |= (1 << s);
3184 } else {
3185 mask |= (1 << s);
3186 s++;
3189 return mask;
3192 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3193 static void get_timerange(struct ast_timing *i, char *times)
3195 char *e;
3196 int x;
3197 int s1, s2;
3198 int e1, e2;
3199 /* int cth, ctm; */
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 */
3209 return;
3211 /* Otherwise expect a range */
3212 e = strchr(times, '-');
3213 if (!e) {
3214 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3215 return;
3217 *e++ = '\0';
3218 /* XXX why skip non digits ? */
3219 while (*e && !isdigit(*e))
3220 e++;
3221 if (!*e) {
3222 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3223 return;
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);
3227 return;
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);
3231 return;
3233 /* XXX this needs to be optimized */
3234 #if 1
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);
3238 return;
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);
3243 return;
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));
3251 #else
3252 for (cth=0; cth<24; cth++) {
3253 /* Initialize masks to blank */
3254 i->minmask[cth] = 0;
3255 for (ctm=0; ctm<30; ctm++) {
3256 if (
3257 /* First hour with more than one hour */
3258 (((cth == s1) && (ctm >= s2)) &&
3259 ((cth < e1)))
3260 /* Only one hour */
3261 || (((cth == s1) && (ctm >= s2)) &&
3262 ((cth == e1) && (ctm <= e2)))
3263 /* In between first and last hours (more than 2 hours) */
3264 || ((cth > s1) &&
3265 (cth < e1))
3266 /* Last hour with more than one hour */
3267 || ((cth > s1) &&
3268 ((cth == e1) && (ctm <= e2)))
3270 i->minmask[cth] |= (1 << (ctm / 2));
3273 #endif
3274 /* All done */
3275 return;
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)) {
3291 if (database)
3292 ast_copy_string(database, map->database, dbsiz);
3293 if (table)
3294 ast_copy_string(table, map->table ? map->table : family, tabsiz);
3295 break;
3299 /* Check if the required driver (engine) exist */
3300 if (map) {
3301 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
3302 if (!strcasecmp(eng->name, map->driver))
3303 ret = eng;
3308 /* if we found a mapping, but the engine is not available, then issue a warning */
3309 if (map && !ret)
3310 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
3312 return ret;
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 */
3332 return category;
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;
3345 old->root = NULL;
3346 #if 1
3347 /* we can just move the entire list in a single op */
3348 ast_variable_append(new, var);
3349 #else
3350 while (var) {
3351 struct ast_variable *next = var->next;
3352 var->next = NULL;
3353 ast_variable_append(new, var);
3354 var = next;
3356 #endif
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)
3371 if (config->last)
3372 config->last->next = category;
3373 else
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);
3384 if (cat->file)
3385 free(cat->file);
3387 free(cat);
3390 static struct ast_config_engine text_file_engine = {
3391 .name = "text",
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)
3400 char db[256];
3401 char table[256];
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);
3407 return NULL;
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) {
3422 loader = eng;
3423 } else {
3424 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
3425 if (eng && eng->load_func)
3426 loader = eng;
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);
3435 if (result)
3436 result->include_level--;
3438 return result;
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)
3444 char *c;
3445 char *cur = buf;
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;
3453 char *catname;
3455 /* A category header */
3456 c = strchr(cur, ']');
3457 if (!c) {
3458 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
3459 return -1;
3461 *c++ = '\0';
3462 cur++;
3463 if (*c++ != '(')
3464 c = NULL;
3465 catname = cur;
3466 if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
3467 return -1;
3469 (*cat)->lineno = lineno;
3471 /* add comments */
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);
3478 if( withcomments )
3479 CB_RESET();
3481 /* If there are options or categories to inherit from, process them now */
3482 if (c) {
3483 if (!(cur = strchr(c, ')'))) {
3484 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
3485 return -1;
3487 *cur = '\0';
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);
3493 if (!*cat) {
3494 ast_config_destroy(cfg);
3495 if (newcat)
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);
3498 return -1;
3500 if (newcat) {
3501 move_variables(newcat, *cat);
3502 ast_category_destroy(newcat);
3503 newcat = NULL;
3505 } else {
3506 struct ast_category *base;
3508 base = category_get(cfg, cur, 1);
3509 if (!base) {
3510 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
3511 return -1;
3513 inherit_category(*cat, base);
3517 if (newcat)
3518 ast_category_append(cfg, *cat);
3519 } else if (cur[0] == '#') {
3520 /* A directive */
3521 cur++;
3522 c = cur;
3523 while(*c && (*c > 32)) c++;
3524 if (*c) {
3525 *c = '\0';
3526 /* Find real argument */
3527 c = ast_skip_blanks(c + 1);
3528 if (!*c)
3529 c = NULL;
3530 } else
3531 c = NULL;
3532 do_include = !strcasecmp(cur, "include");
3533 if(!do_include)
3534 do_exec = !strcasecmp(cur, "exec");
3535 else
3536 do_exec = 0;
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");
3539 do_exec = 0;
3541 if (do_include || do_exec) {
3542 if (c) {
3543 char *cur2;
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 */
3550 cur = c;
3551 cur2 = cur;
3552 while (!ast_strlen_zero(cur)) {
3553 c = cur + strlen(cur) - 1;
3554 if ((*c == '>') || (*c == '<') || (*c == '\"'))
3555 *c = '\0';
3556 else
3557 break;
3559 /* #exec </path/to/executable>
3560 We create a tmp file, then we #include it, then we delete it. */
3561 if (do_exec) {
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);
3565 cur = exec_file;
3566 } else
3567 exec_file[0] = '\0';
3568 /* A #include */
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))
3576 unlink(exec_file);
3577 if(!do_include)
3578 return 0;
3579 /* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
3581 } else {
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",
3585 lineno,
3586 configfile);
3589 else
3590 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
3591 } else {
3592 /* Just a line (variable = value) */
3593 if (!*cat) {
3594 ast_log(LOG_WARNING,
3595 "parse error: No category context for line %d of %s\n", lineno, configfile);
3596 return -1;
3598 c = strchr(cur, '=');
3599 if (c) {
3600 *c = 0;
3601 c++;
3602 /* Ignore > in => */
3603 if (*c== '>') {
3604 object = 1;
3605 c++;
3606 } else
3607 object = 0;
3608 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), configfile))) {
3609 v->lineno = lineno;
3610 v->object = object;
3611 /* Put and reset comments */
3612 v->blanklines = 0;
3613 ast_variable_append(*cat, v);
3614 /* add comments */
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);
3621 if( withcomments )
3622 CB_RESET();
3624 } else {
3625 return -1;
3627 } else {
3628 ast_log(LOG_WARNING, "EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno, configfile);
3631 return 0;
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)
3641 use_local_dir = 1;
3644 void localized_use_conf_dir(void)
3646 use_local_dir = 0;
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)
3652 char fn[256];
3653 char buf[8192];
3654 char *new_buf, *comment_p, *process_buf;
3655 FILE *f;
3656 int lineno=0;
3657 int comment = 0, nest[MAX_NESTED_COMMENTS];
3658 struct ast_category *cat = NULL;
3659 int count = 0;
3660 struct stat statbuf;
3662 cat = ast_config_get_current_category(cfg);
3664 if (filename[0] == '/') {
3665 ast_copy_string(fn, filename, sizeof(fn));
3666 } else {
3667 if (use_local_dir)
3668 snprintf(fn, sizeof(fn), "./%s", filename);
3669 else
3670 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
3673 if (withcomments && cfg && cfg->include_level < 2 ) {
3674 CB_INIT();
3677 #ifdef AST_INCLUDE_GLOB
3679 int glob_ret;
3680 glob_t globbuf;
3682 globbuf.gl_offs = 0; /* initialize it to silence gcc */
3683 #ifdef SOLARIS
3684 glob_ret = glob(fn, GLOB_NOCHECK, NULL, &globbuf);
3685 #else
3686 glob_ret = glob(fn, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
3687 #endif
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);
3694 else {
3695 /* loop over expanded files */
3696 int i;
3697 for (i=0; i<globbuf.gl_pathc; i++) {
3698 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
3699 #endif
3700 do {
3701 if (stat(fn, &statbuf))
3702 continue;
3704 if (!S_ISREG(statbuf.st_mode)) {
3705 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
3706 continue;
3708 if (option_verbose > 1) {
3709 ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
3710 fflush(stdout);
3712 if (!(f = fopen(fn, "r"))) {
3713 if (option_debug)
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));
3717 continue;
3719 count++;
3720 if (option_debug)
3721 ast_log(LOG_DEBUG, "Parsing %s\n", fn);
3722 if (option_verbose > 1)
3723 ast_verbose("Found\n");
3724 while(!feof(f)) {
3725 lineno++;
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 */
3732 new_buf = buf;
3733 if (comment)
3734 process_buf = NULL;
3735 else
3736 process_buf = buf;
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) {
3746 *comment_p = '\0';
3747 new_buf = comment_p + 3;
3748 comment++;
3749 nest[comment-1] = lineno;
3750 } else {
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 */
3757 comment--;
3758 new_buf = comment_p + 1;
3759 if (!comment) {
3760 /* Back to non-comment now */
3761 if (process_buf) {
3762 /* Actually have to move what's left over the top, then continue */
3763 char *oldptr;
3764 oldptr = process_buf + strlen(process_buf);
3765 if ( withcomments ) {
3766 CB_ADD(";");
3767 CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
3770 memmove(oldptr, new_buf, strlen(new_buf) + 1);
3771 new_buf = oldptr;
3772 } else
3773 process_buf = new_buf;
3775 } else {
3776 if (!comment) {
3777 /* If ; is found, and we are not nested in a comment,
3778 we immediately stop all comment processing */
3779 if ( withcomments ) {
3780 LLB_ADD(comment_p);
3782 *comment_p = '\0';
3783 new_buf = comment_p;
3784 } else
3785 new_buf = comment_p + 1;
3788 if( withcomments && comment && !process_buf )
3790 CB_ADD(buf); /* the whole line is a comment, store it */
3793 if (process_buf) {
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)) {
3797 cfg = NULL;
3798 break;
3804 fclose(f);
3805 } while(0);
3806 if (comment) {
3807 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
3809 #ifdef AST_INCLUDE_GLOB
3810 if (!cfg)
3811 break;
3813 globfree(&globbuf);
3816 #endif
3817 if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
3818 if (comment_buffer) {
3819 free(comment_buffer);
3820 free(lline_buffer);
3821 comment_buffer=0;
3822 lline_buffer=0;
3823 comment_buffer_size=0;
3824 lline_buffer_size=0;
3827 if (count == 0)
3828 return NULL;
3830 return cfg;
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;
3842 return config;
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();
3853 if (!cfg)
3854 return NULL;
3856 result = ast_config_internal_load(filename, cfg, 0, "");
3857 if (!result)
3858 ast_config_destroy(cfg);
3860 return result;
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();
3871 if (!cfg)
3872 return NULL;
3874 result = ast_config_internal_load(filename, cfg, 1, "");
3875 if (!result)
3876 ast_config_destroy(cfg);
3878 return result;
3881 static struct ast_category *next_available_category(struct ast_category *cat)
3883 for (; cat && cat->ignored; cat = cat->next);
3885 return cat;
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)
3895 cat = config->root;
3896 else if (prev) {
3897 for (cat = config->root; cat; cat = cat->next) {
3898 if (cat->name == prev) {
3899 cat = cat->next;
3900 break;
3903 if (!cat) {
3904 for (cat = config->root; cat; cat = cat->next) {
3905 if (!strcasecmp(cat->name, prev)) {
3906 cat = cat->next;
3907 break;
3913 if (cat)
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)
3952 char date[256]="";
3953 time_t t;
3954 time(&t);
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);
3961 else
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);
3973 else
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);
3977 else
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)
3985 FILE *f;
3986 char fn[256];
3987 struct ast_variable *var;
3988 struct ast_category *cat;
3989 struct ast_comment *cmt;
3990 struct ast_config_include *incl;
3991 int blanklines = 0;
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)
3996 incl->output = 0;
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*/
4004 FILE *f1;
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 */
4007 f1 = fopen(fn,"w");
4008 if (f1) {
4009 gen_header(f1, configfile, fn, generator);
4010 fclose(f1); /* this should zero out the file */
4011 } else {
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 */
4018 #ifdef __CYGWIN__
4019 if ((f = fopen(fn, "w+"))) {
4020 #else
4021 if ((f = fopen(fn, "w"))) {
4022 #endif
4023 if (option_verbose > 1)
4024 ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
4026 gen_header(f, configfile, fn, generator);
4027 cat = cfg->root;
4028 fclose(f);
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 */
4034 while(cat) {
4035 set_fn(fn, sizeof(fn), cat->file, configfile);
4036 f = fopen(fn, "a");
4037 if (!f)
4039 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
4040 return -1;
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) {
4047 if (incl->exec)
4048 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
4049 else
4050 fprintf(f,"#include \"%s\"\n", incl->included_file);
4051 incl->output = 1;
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)
4062 fprintf(f,"\n");
4063 fprintf(f, "[%s]", cat->name);
4064 for(cmt = cat->sameline; cmt; cmt=cmt->next) {
4065 fprintf(f,"%s", cmt->cmt);
4067 if (!cat->sameline)
4068 fprintf(f,"\n");
4069 fclose(f);
4071 var = cat->root;
4072 while(var) {
4073 set_fn(fn, sizeof(fn), var->file, configfile);
4074 f = fopen(fn, "a");
4075 if (!f)
4077 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
4078 return -1;
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) {
4085 if (incl->exec)
4086 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
4087 else
4088 fprintf(f,"#include \"%s\"\n", incl->included_file);
4089 incl->output = 1;
4094 for (cmt = var->precomments; cmt; cmt=cmt->next) {
4095 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
4096 fprintf(f,"%s", cmt->cmt);
4098 if (var->sameline)
4099 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
4100 else
4101 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
4102 if (var->blanklines) {
4103 blanklines = var->blanklines;
4104 while (blanklines--)
4105 fprintf(f, "\n");
4108 fclose(f);
4111 var = var->next;
4113 cat = cat->next;
4115 if ((option_verbose > 1) && !option_debug)
4116 ast_verbose("Saved\n");
4117 } else {
4118 if (option_debug)
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));
4122 return -1;
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);
4132 f = fopen(fn, "a");
4133 if (!f)
4135 ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
4136 return -1;
4139 /* output the respective include */
4140 if (incl->exec)
4141 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
4142 else
4143 fprintf(f,"#include \"%s\"\n", incl->included_file);
4144 fclose(f);
4145 incl->output = 1;
4149 return 0;
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;
4160 struct ast_context;
4161 struct ast_app;
4162 #ifdef LOW_MEMORY
4163 #define EXT_DATA_SIZE 256
4164 #else
4165 #define EXT_DATA_SIZE 8192
4166 #endif
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.
4173 enum ext_match_t {
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 */
4182 #ifdef NOT_ANYMORE
4183 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
4184 #endif
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;
4204 int res = -1;
4206 AST_RWLIST_TRAVERSE(&hints, hint, list) {
4207 if (hint->exten == oe) {
4208 hint->exten = ne;
4209 res = 0;
4210 break;
4214 return res;
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;
4222 if (!e)
4223 return -1;
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));
4231 return -1;
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)))) {
4239 return -1;
4241 /* Initialize and insert new item at the top */
4242 hint->exten = e;
4243 AST_RWLIST_INSERT_HEAD(&hints, hint, list);
4245 return 0;
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)
4258 break;
4260 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
4261 ep->peer = tmp;
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. */
4267 if (!replace) {
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);
4270 free(tmp);
4271 return -1;
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 */
4279 ep->peer = tmp;
4280 else if (el) /* We're the first extension. Take over e's functions */
4281 el->next = tmp;
4282 else /* We're the very first extension. */
4283 con->root = tmp;
4284 if (tmp->priority == PRIORITY_HINT)
4285 ast_change_hint(e,tmp);
4286 /* Destroy the old one */
4287 e->datad(e->data);
4288 free(e);
4289 } else { /* Slip ourselves in just before e */
4290 tmp->peer = 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 */
4293 ep->peer = tmp;
4294 else { /* we are the first in some peer list, so link in the ext list */
4295 if (el)
4296 el->next = tmp; /* in the middle... */
4297 else
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)
4303 ast_add_hint(tmp);
4305 return 0;
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;
4314 int res = -1;
4316 if (!e)
4317 return -1;
4319 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
4320 if (hint->exten == e) {
4321 cbprev = NULL;
4322 cblist = hint->callbacks;
4323 while (cblist) {
4324 /* Notify with -1 and remove all callbacks */
4325 cbprev = cblist;
4326 cblist = cblist->next;
4327 free(cbprev);
4329 hint->callbacks = NULL;
4330 AST_RWLIST_REMOVE_CURRENT(&hints, list);
4331 free(hint);
4332 res = 0;
4333 break;
4336 AST_RWLIST_TRAVERSE_SAFE_END
4338 return res;
4341 static void destroy_exten(struct ast_exten *e)
4343 if (e->priority == PRIORITY_HINT)
4344 ast_remove_hint(e);
4346 if (e->datad)
4347 e->datad(e->data);
4348 free(e);
4351 char *days[] =
4353 "sun",
4354 "mon",
4355 "tue",
4356 "wed",
4357 "thu",
4358 "fri",
4359 "sat",
4360 NULL,
4363 char *months[] =
4365 "jan",
4366 "feb",
4367 "mar",
4368 "apr",
4369 "may",
4370 "jun",
4371 "jul",
4372 "aug",
4373 "sep",
4374 "oct",
4375 "nov",
4376 "dec",
4377 NULL,
4380 static int ast_build_timing(struct ast_timing *i, const char *info_in)
4382 char info_save[256];
4383 char *info;
4385 /* Check for empty just in case */
4386 if (ast_strlen_zero(info_in))
4387 return 0;
4388 /* make a copy just in case we were passed a static string */
4389 ast_copy_string(info_save, info_in, sizeof(info_save));
4390 info = 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, "|"));
4397 if (info)
4398 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
4399 if (info)
4400 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
4401 if (info)
4402 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
4403 return 1;
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.
4423 * NOTES:
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)
4431 uint32_t chars[8];
4432 int c, cmin = 0xff, count = 0;
4433 const char *end;
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 */
4442 switch (c) {
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 */
4456 return 0x10000;
4458 case '!': /* earlymatch */
4459 return 0x20000; /* less specific than NULL */
4461 case '\0': /* empty string */
4462 *p = NULL;
4463 return 0x30000;
4465 case '[': /* pattern */
4466 break;
4468 /* locate end of set */
4469 end = strchr(*p, ']');
4471 if (end == NULL) {
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 */
4484 c2 = c1;
4485 if (c1 < cmin)
4486 cmin = c1;
4487 for (; c1 <= c2; c1++) {
4488 uint32_t mask = 1 << (c1 % 32);
4489 if ( (chars[ c1 / 32 ] & mask) == 0)
4490 count += 0x100;
4491 chars[ c1 / 32 ] |= mask;
4494 (*p)++;
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.
4507 int ret = 0;
4509 if (a[0] != '_')
4510 return (b[0] == '_') ? -1 : strcmp(a, b);
4512 /* Now we know a is a pattern; if b is not, a comes first */
4513 if (b[0] != '_')
4514 return 1;
4515 #if 0 /* old mode for ext matching */
4516 return strcmp(a, b);
4517 #endif
4518 /* ok we need full pattern sorting routine */
4519 while (!ret && a && b)
4520 ret = ext_cmp1(&a) - ext_cmp1(&b);
4521 if (ret == 0)
4522 return 0;
4523 else
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)
4530 int count=0;
4532 while (*src && (count < len - 1)) {
4533 switch(*src) {
4534 case ' ':
4535 /* otherwise exten => [a-b],1,... doesn't work */
4536 /* case '-': */
4537 /* Ignore */
4538 break;
4539 default:
4540 *dst = *src;
4541 dst++;
4543 src++;
4544 count++;
4546 *dst = '\0';
4548 return count;
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)
4557 struct tm tm;
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)))
4564 return 0;
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))))
4569 return 0;
4571 /* If it's not the right day of the week */
4572 if (!(i->dowmask & (1 << tm.tm_wday)))
4573 return 0;
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");
4578 return 0;
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))))
4584 return 0;
4586 /* If we got this far, then we're good */
4587 return 1;
4590 #ifdef NOT_ANYMORE
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))
4597 break;
4600 return asw;
4602 #endif
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)
4626 if (!exten)
4627 return con ? con->root : NULL;
4628 else
4629 return exten->next;
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)
4666 if (!inc)
4667 return con ? con->includes : NULL;
4668 else
4669 return inc->next;
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,
4682 struct ast_sw *sw);
4684 static struct ast_sw *ast_walk_context_switches(struct ast_context *con,
4685 struct ast_sw *sw)
4687 if (!sw)
4688 return con ? AST_LIST_FIRST(&con->alts) : NULL;
4689 else
4690 return AST_LIST_NEXT(sw, list);
4693 struct ast_sw *localized_walk_context_switches(struct ast_context *con,
4694 struct ast_sw *sw);
4695 struct ast_sw *localized_walk_context_switches(struct ast_context *con,
4696 struct ast_sw *sw)
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))
4709 break;
4711 return tmp;
4714 /* request and result for pbx_find_extension */
4715 struct pbx_find_info {
4716 #if 0
4717 const char *context;
4718 const char *exten;
4719 int priority;
4720 #endif
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. !!! */
4744 return 1;
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 */
4750 return 0;
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 '/' ? */
4756 else
4757 return 0;
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 != '/') {
4765 const char *end;
4767 if (*data == '-') { /* skip '-' in data (just a separator) */
4768 data++;
4769 continue;
4771 switch (toupper(*pattern)) {
4772 case '[': /* a range */
4773 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
4774 if (end == NULL) {
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 */
4782 else {
4783 pattern += 2; /* skip a total of 3 chars */
4784 continue;
4786 } else if (*data == pattern[0])
4787 break; /* match found */
4789 if (pattern == end)
4790 return 0;
4791 pattern = end; /* skip and continue */
4792 break;
4793 case 'N':
4794 if (*data < '2' || *data > '9')
4795 return 0;
4796 break;
4797 case 'X':
4798 if (*data < '0' || *data > '9')
4799 return 0;
4800 break;
4801 case 'Z':
4802 if (*data < '1' || *data > '9')
4803 return 0;
4804 break;
4805 case '.': /* Must match, even with more digits */
4806 return 1;
4807 case '!': /* Early match */
4808 return 2;
4809 case ' ':
4810 case '-': /* Ignore these in patterns */
4811 data--; /* compensate the final data++ */
4812 break;
4813 default:
4814 if (*data != *pattern)
4815 return 0;
4817 data++;
4818 pattern++;
4820 if (*data) /* data longer than pattern, no match */
4821 return 0;
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 */
4829 return 2;
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)
4836 int i;
4837 i = _extension_match_core(pattern, data, mode);
4838 return i;
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)
4861 if (!i->hastime)
4862 return 1;
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,
4873 const char *exten,
4874 int priority,
4875 const char *label,
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,
4884 const char *exten,
4885 int priority,
4886 const char *label,
4887 const char *callerid,
4888 enum ext_match_t action)
4890 int x;
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;
4898 q->swo = NULL;
4899 q->data = NULL;
4900 q->foundcontext = NULL;
4901 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
4902 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
4903 return NULL;
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))
4908 return NULL;
4910 if (bypass) /* bypass means we only look there */
4911 tmp = bypass;
4912 else { /* look in contexts */
4913 tmp = NULL;
4914 while ((tmp = ast_walk_contexts(tmp)) ) {
4915 if (!strcmp(tmp->name, context))
4916 break;
4918 if (!tmp)
4919 return NULL;
4921 if (q->status < STATUS_NO_EXTENSION)
4922 q->status = STATUS_NO_EXTENSION;
4924 /* scan the list trying to match extension and CID */
4925 eroot = NULL;
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).
4936 return NULL;
4938 /* found entry, now look for the right priority */
4939 if (q->status < STATUS_NO_PRIORITY)
4940 q->status = STATUS_NO_PRIORITY;
4941 e = NULL;
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;
4956 return e;
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;
4964 char *datap;
4966 if (!asw) {
4967 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
4968 continue;
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 */
4978 aswf = asw->exists;
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 */
4982 q->swo = asw;
4983 q->data = datap;
4984 q->foundcontext = context;
4985 /* XXX keep status = STATUS_NO_CONTEXT ? */
4986 return NULL;
4989 #endif
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)))
4995 return e;
4996 if (q->swo)
4997 return NULL;
5000 return NULL;
5003 struct ast_exten *localized_find_extension(struct ast_context *bypass,
5004 struct pbx_find_info *q,
5005 const char *context,
5006 const char *exten,
5007 int priority,
5008 const char *label,
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,
5015 const char *exten,
5016 int priority,
5017 const char *label,
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;
5036 * errno values
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;
5049 char *c;
5050 struct ast_include *i, *il = NULL; /* include, include_last */
5051 int length;
5052 char *p;
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)))
5059 return -1;
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;
5065 strcpy(p, value);
5066 p += strlen(value) + 1;
5067 new_include->rname = p;
5068 strcpy(p, value);
5069 /* Strip off timing info, and process if it is there */
5070 if ( (c = strchr(p, '|')) ) {
5071 *c++ = '\0';
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)) {
5081 free(new_include);
5082 errno = EEXIST;
5083 return -1;
5085 il = i;
5088 /* ... include new context into context list, unlock, return */
5089 if (il)
5090 il->next = new_include;
5091 else
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));
5096 return 0;
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;
5114 int length;
5115 length = sizeof(struct ast_ignorepat);
5116 length += strlen(value) + 1;
5117 if (!(ignorepat = ast_calloc(1, length)))
5118 return -1;
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)) {
5128 /* Already there */
5129 errno = EEXIST;
5130 return -1;
5133 if (ignorepatl)
5134 ignorepatl->next = ignorepat;
5135 else
5136 con->ignorepats = ignorepat;
5137 return 0;
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);
5174 * errno values
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;
5187 struct ast_sw *i;
5188 int length;
5189 char *p;
5191 length = sizeof(struct ast_sw);
5192 length += strlen(value) + 1;
5193 if (data)
5194 length += strlen(data);
5195 length++;
5196 if (eval) {
5197 /* Create buffer for evaluation of variables */
5198 length += SWITCH_DATA_LENGTH;
5199 length++;
5202 /* allocate new sw structure ... */
5203 if (!(new_sw = ast_calloc(1, length)))
5204 return -1;
5205 /* ... fill in this structure ... */
5206 p = new_sw->stuff;
5207 new_sw->name = p;
5208 strcpy(new_sw->name, value);
5209 p += strlen(value) + 1;
5210 new_sw->data = p;
5211 if (data) {
5212 strcpy(new_sw->data, data);
5213 p += strlen(data) + 1;
5214 } else {
5215 strcpy(new_sw->data, "");
5216 p++;
5218 if (eval)
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)) {
5226 free(new_sw);
5227 errno = EEXIST;
5228 return -1;
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));
5238 return 0;
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;
5255 if (!extcontexts) {
5256 ast_wrlock_contexts();
5257 local_contexts = &contexts;
5258 } else
5259 local_contexts = extcontexts;
5261 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
5262 if (!strcasecmp(tmp->name, name)) {
5263 if (!existsokay) {
5264 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
5265 tmp = NULL;
5267 if (!extcontexts)
5268 ast_unlock_contexts();
5269 return tmp;
5272 if ((tmp = ast_calloc(1, length))) {
5273 ast_rwlock_init(&tmp->lock);
5274 ast_mutex_init(&tmp->macrolock);
5275 strcpy(tmp->name, name);
5276 tmp->root = NULL;
5277 tmp->registrar = registrar;
5278 tmp->next = *local_contexts;
5279 tmp->includes = NULL;
5280 tmp->ignorepats = NULL;
5281 *local_contexts = tmp;
5282 if (option_debug)
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);
5288 if (!extcontexts)
5289 ast_unlock_contexts();
5290 return tmp;
5293 /*! \brief
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;
5330 int res;
5331 int length;
5332 char *p;
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;
5341 if (label)
5342 length += strlen(label) + 1;
5343 if (callerid)
5344 length += strlen(callerid) + 1;
5345 else
5346 length ++; /* just the '\0' */
5348 /* Be optimistic: Build the extension structure first */
5349 if (datad == NULL)
5350 datad = null_datad;
5351 if (!(tmp = ast_calloc(1, length)))
5352 return -1;
5354 /* use p as dst in assignments, as the fields are const char * */
5355 p = tmp->stuff;
5356 if (label) {
5357 tmp->label = p;
5358 strcpy(p, label);
5359 p += strlen(label) + 1;
5361 tmp->exten = p;
5362 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
5363 tmp->priority = priority;
5364 tmp->cidmatch = p; /* but use p for assignments below */
5365 if (callerid) {
5366 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
5367 tmp->matchcid = 1;
5368 } else {
5369 *p++ = '\0';
5370 tmp->matchcid = 0;
5372 tmp->app = p;
5373 strcpy(p, application);
5374 tmp->parent = con;
5375 tmp->data = data;
5376 tmp->datad = datad;
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)
5384 res = 0;
5385 else if (tmp->matchcid && !e->matchcid)
5386 res = 1;
5387 else if (e->matchcid && !tmp->matchcid)
5388 res = -1;
5389 else
5390 res = strcasecmp(e->cidmatch, tmp->cidmatch);
5392 if (res >= 0)
5393 break;
5395 if (e && res == 0) { /* exact match, insert in the pri chain */
5396 res = add_pri(con, tmp, el, e, replace);
5397 if (res < 0) {
5398 errno = EEXIST; /* XXX do we care ? */
5399 return 0; /* XXX should we return -1 maybe ? */
5401 } else {
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)
5406 tmp->next = e;
5407 if (el)
5408 el->next = tmp;
5409 else
5410 con->root = tmp;
5411 if (tmp->priority == PRIORITY_HINT)
5412 ast_add_hint(tmp);
5414 if (option_debug) {
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);
5418 } else {
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);
5427 } else {
5428 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
5429 tmp->exten, tmp->priority, con->name);
5432 return 0;
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;
5464 int res;
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);
5470 if (e) {
5471 if (matching_action) {
5472 return -1; /* success, we found it */
5473 } else if (action == E_FINDLABEL) { /* map the label to a priority */
5474 res = e->priority;
5475 return res; /* the priority we were looking for */
5476 } else { /* spawn */
5478 /* NOT!!!!! */
5479 return 0;
5481 } else if (q.swo) { /* not found here, but in another switch */
5482 if (matching_action)
5483 return -1;
5484 else {
5485 if (!q.swo->exec) {
5486 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
5487 res = -1;
5489 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
5491 } else { /* not found anywhere, see what happened */
5492 switch (q.status) {
5493 case STATUS_NO_CONTEXT:
5494 if (!matching_action)
5495 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
5496 break;
5497 case STATUS_NO_EXTENSION:
5498 if (!matching_action)
5499 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
5500 break;
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);
5504 break;
5505 case STATUS_NO_LABEL:
5506 if (context)
5507 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
5508 break;
5509 default:
5510 if (option_debug)
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);
5541 return -1;
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)
5550 int parens=0;
5552 *offset = 0;
5553 *length = INT_MAX;
5554 *isfunc = 0;
5555 for (; *var; var++) {
5556 if (*var == '(') {
5557 (*isfunc)++;
5558 parens++;
5559 } else if (*var == ')') {
5560 parens--;
5561 } else if (*var == ':' && parens == 0) {
5562 *var++ = '\0';
5563 sscanf(var, "%d:%d", offset, length);
5564 return 1; /* offset:length valid */
5567 return 0;
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 */
5594 return ret;
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 */
5599 offset = 0;
5602 /* too large offset result in empty string so we know what to return */
5603 if (offset >= lr)
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 */
5608 ret[length] = '\0';
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';
5612 else
5613 ret[0] = '\0';
5616 return ret;
5619 /*! \brief Support for Asterisk built-in variables in the dialplan
5620 \note See also
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';
5627 char *tmpvar;
5628 const char *s; /* the result */
5629 int offset, length;
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 == &not_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 != &not_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 = &not_found; /* default value */
5657 if (s == &not_found) { /* look for more */
5658 if (!strcmp(var, "EPOCH")) {
5659 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
5662 s = workspace;
5664 /* if not found, look into chanvars or global vars */
5665 for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
5666 struct ast_var_t *variables;
5667 if (!places[i])
5668 continue;
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);
5674 break;
5677 if (places[i] == &globals)
5678 ast_rwlock_unlock(&globalslock);
5680 if (s == &not_found || s == NULL)
5681 *ret = NULL;
5682 else {
5683 if (s != workspace)
5684 ast_copy_string(workspace, s, workspacelen);
5685 *ret = workspace;
5686 if (need_substring)
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
5694 zero-filled */
5695 char *cp4;
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;
5701 char *vars, *vare;
5702 int pos, brackets, needsub, len;
5704 *cp2 = 0; /* just in case there's nothing to do */
5705 whereweare=tmp=cp1;
5706 while (!ast_strlen_zero(whereweare) && count) {
5707 /* Assume we're copying the whole remaining string */
5708 pos = strlen(whereweare);
5709 nextvar = NULL;
5710 nextexp = NULL;
5711 nextthing = strchr(whereweare, '$');
5712 if (nextthing) {
5713 switch (nextthing[1]) {
5714 case '{':
5715 nextvar = nextthing;
5716 pos = nextvar - whereweare;
5717 break;
5718 case '[':
5719 nextexp = nextthing;
5720 pos = nextexp - whereweare;
5721 break;
5725 if (pos) {
5726 /* Can't copy more than 'count' bytes */
5727 if (pos > count)
5728 pos = count;
5730 /* Copy that many bytes */
5731 memcpy(cp2, whereweare, pos);
5733 count -= pos;
5734 cp2 += pos;
5735 whereweare += pos;
5736 *cp2 = 0;
5739 if (nextvar) {
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
5742 contents */
5743 vars = vare = nextvar + 2;
5744 brackets = 1;
5745 needsub = 0;
5747 /* Find the end of it */
5748 while (brackets && *vare) {
5749 if ((vare[0] == '$') && (vare[1] == '{')) {
5750 needsub++;
5751 } else if (vare[0] == '{') {
5752 brackets++;
5753 } else if (vare[0] == '}') {
5754 brackets--;
5755 } else if ((vare[0] == '$') && (vare[1] == '['))
5756 needsub++;
5757 vare++;
5759 if (brackets)
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);
5766 if (!var)
5767 var = alloca(VAR_BUF_SIZE);
5769 /* Store variable name (and truncate) */
5770 ast_copy_string(var, vars, len + 1);
5772 /* Substitute if necessary */
5773 if (needsub) {
5774 if (!ltmp)
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);
5779 vars = ltmp;
5780 } else {
5781 vars = var;
5784 if (!workspace)
5785 workspace = alloca(VAR_BUF_SIZE);
5787 workspace[0] = '\0';
5789 parse_variable_name(vars, &offset, &offset2, &isfunction);
5790 if (isfunction) {
5791 /* Evaluate function */
5792 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
5793 if (option_debug)
5794 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
5795 } else {
5796 /* Retrieve variable value */
5797 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
5799 if (cp4) {
5800 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
5802 length = strlen(cp4);
5803 if (length > count)
5804 length = count;
5805 memcpy(cp2, cp4, length);
5806 count -= length;
5807 cp2 += length;
5808 *cp2 = 0;
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
5813 contents */
5814 vars = vare = nextexp + 2;
5815 brackets = 1;
5816 needsub = 0;
5818 /* Find the end of it */
5819 while (brackets && *vare) {
5820 if ((vare[0] == '$') && (vare[1] == '[')) {
5821 needsub++;
5822 brackets++;
5823 vare++;
5824 } else if (vare[0] == '[') {
5825 brackets++;
5826 } else if (vare[0] == ']') {
5827 brackets--;
5828 } else if ((vare[0] == '$') && (vare[1] == '{')) {
5829 needsub++;
5830 vare++;
5832 vare++;
5834 if (brackets)
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);
5841 if (!var)
5842 var = alloca(VAR_BUF_SIZE);
5844 /* Store variable name (and truncate) */
5845 ast_copy_string(var, vars, len + 1);
5847 /* Substitute if necessary */
5848 if (needsub) {
5849 if (!ltmp)
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);
5854 vars = ltmp;
5855 } else {
5856 vars = var;
5859 length = ast_expr(vars, cp2, count, NULL);
5861 if (length) {
5862 if (option_debug)
5863 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
5864 count -= length;
5865 cp2 += length;
5866 *cp2 = 0;
5868 } else
5869 break;
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;
5884 char *end;
5885 char *label;
5886 char realvalue[256];
5887 int lastpri = -2;
5888 struct ast_context *con;
5889 struct ast_variable *v;
5890 const char *cxt;
5891 const char *aft;
5893 cfg = localized_config_load(config_file);
5894 if (!cfg)
5895 return 0;
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));
5907 else
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"))
5918 continue;
5919 con=ast_context_find_or_create(&local_contexts,NULL,cxt, registrar);
5920 if (con == NULL)
5921 continue;
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);
5926 if (tc) {
5927 int ipri = -2;
5928 char realext[256]="";
5929 char *plus, *firstp, *firstc;
5930 char *pri, *appl, *data, *cidmatch;
5931 char *stringp = tc;
5932 char *ext = strsep(&stringp, ",");
5933 if (!ext)
5934 ext="";
5935 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
5936 cidmatch = strchr(realext, '/');
5937 if (cidmatch) {
5938 *cidmatch++ = '\0';
5939 ast_shrink_phone_number(cidmatch);
5941 pri = strsep(&stringp, ",");
5942 if (!pri)
5943 pri="";
5944 label = strchr(pri, '(');
5945 if (label) {
5946 *label++ = '\0';
5947 end = strchr(label, ')');
5948 if (end)
5949 *end = '\0';
5950 else
5951 ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
5953 plus = strchr(pri, '+');
5954 if (plus)
5955 *plus++ = '\0';
5956 if (!strcmp(pri,"hint"))
5957 ipri=PRIORITY_HINT;
5958 else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
5959 if (lastpri > -2)
5960 ipri = lastpri + 1;
5961 else
5962 ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
5963 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
5964 if (lastpri > -2)
5965 ipri = lastpri;
5966 else
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);
5971 ipri = 0;
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, ",");
5981 data = stringp;
5982 } else if (!firstc && !firstp) {
5983 /* Neither found */
5984 data = "";
5985 } else {
5986 /* Final remaining case is parenthesis found first */
5987 appl = strsep(&stringp, "(");
5988 data = stringp;
5989 end = strrchr(data, ')');
5990 if ((end = strrchr(data, ')'))) {
5991 *end = '\0';
5992 } else {
5993 ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
5995 ast_process_quotes_and_slashes(data, ',', '|');
5998 if (!data)
5999 data="";
6000 appl = ast_skip_blanks(appl);
6001 if (ipri) {
6002 if (plus)
6003 ipri += atoi(plus);
6004 lastpri = ipri;
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);
6011 free(tc);
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;
6025 char *appl, *data;
6027 memset(realvalue, 0, sizeof(realvalue));
6028 if (!strcasecmp(v->name, "switch"))
6029 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
6030 else
6031 ast_copy_string(realvalue, v->value, sizeof(realvalue));
6032 appl = strsep(&stringp, "/");
6033 data = strsep(&stringp, ""); /* XXX what for ? */
6034 if (!data)
6035 data = "";
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);
6038 } else {
6039 ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
6043 ast_config_destroy(cfg);
6044 return 1;
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;
6051 struct ast_sw *sw;
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) {
6058 if (option_debug)
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 */
6065 break;
6066 ast_wrlock_context(tmp);
6067 if (option_debug)
6068 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
6069 next = tmp->next;
6070 if (tmpl)
6071 tmpl->next = next;
6072 else
6073 contexts = next;
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;
6079 tmpi = tmpi->next;
6080 free(tmpil);
6082 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
6083 struct ast_ignorepat *ipl = ipi;
6084 ipi = ipi->next;
6085 free(ipl);
6087 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
6088 free(sw);
6089 for (e = tmp->root; e;) {
6090 for (en = e->peer; en;) {
6091 el = en;
6092 en = en->peer;
6093 destroy_exten(el);
6095 el = e;
6096 e = e->next;
6097 destroy_exten(el);
6099 ast_rwlock_destroy(&tmp->lock);
6100 free(tmp);
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();
6130 tmp = *extcontexts;
6131 if (registrar) {
6132 /* XXX remove previous contexts from same registrar */
6133 if (option_debug)
6134 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
6135 __ast_context_destroy(NULL,registrar);
6136 while (tmp) {
6137 lasttmp = tmp;
6138 tmp = tmp->next;
6140 } else {
6141 /* XXX remove contexts with the same name */
6142 while (tmp) {
6143 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
6144 __ast_context_destroy(tmp,tmp->registrar);
6145 lasttmp = tmp;
6146 tmp = tmp->next;
6149 if (lasttmp) {
6150 lasttmp->next = contexts;
6151 contexts = *extcontexts;
6152 *extcontexts = NULL;
6153 } else
6154 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
6156 ast_unlock_contexts();
6158 return;
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;
6171 int res = 0;
6173 while ( (inc = ast_walk_context_includes(con, inc)) )
6174 if (!ast_context_find(inc->rname)) {
6175 res = -1;
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);
6180 return res;
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");
6207 con = 0;
6208 while ((con = ast_walk_contexts(con)) ) {
6209 printf("Context: %s\n", con->name);
6211 printf("=========\n");
6213 return 0;