46 #define ASTMM_LIBC ASTMM_IGNORE
57 #include <sys/types.h>
59 #include <sys/resource.h>
65 #if !defined(SOLARIS) && !defined(__CYGWIN__)
72 #include <sys/param.h>
75 static void ast_log(
int level,
const char *file,
int line,
const char *
function,
const char *fmt, ...) __attribute__((format(printf, 5, 6)));
76 void ast_verbose(const
char *fmt, ...) __attribute__((format(printf, 1, 2)));
78 #define AST_API_MODULE 1
93 #define EVENTLOG "event_log"
94 #define QUEUELOG "queue_log"
96 #define DEBUG_M(a) { \
100 #define VERBOSE_PREFIX_1 " "
101 #define VERBOSE_PREFIX_2 " == "
102 #define VERBOSE_PREFIX_3 " -- "
103 #define VERBOSE_PREFIX_4 " > "
107 void ast_queue_log(
const char *queuename,
const char *callid,
const char *agent,
const char *
event,
const char *fmt, ...)
108 __attribute__((format(printf, 5, 6)));
115 #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
120 #define __LOG_DEBUG 0
121 #define LOG_DEBUG __LOG_DEBUG, _A_
126 #define __LOG_EVENT 1
127 #define LOG_EVENT __LOG_EVENT, _A_
132 #define __LOG_NOTICE 2
133 #define LOG_NOTICE __LOG_NOTICE, _A_
138 #define __LOG_WARNING 3
139 #define LOG_WARNING __LOG_WARNING, _A_
144 #define __LOG_ERROR 4
145 #define LOG_ERROR __LOG_ERROR, _A_
150 #define __LOG_VERBOSE 5
151 #define LOG_VERBOSE __LOG_VERBOSE, _A_
157 #define LOG_DTMF __LOG_DTMF, _A_
160 #define _ASTERISK_LOCK_H
162 #ifndef HAVE_MTX_PROFILE
163 #define __MTX_PROF(a) return pthread_mutex_lock((a))
167 #define __MTX_PROF(a) do { \
170 ast_mark(mtx_prof, 1); \
171 i = pthread_mutex_trylock((a)); \
172 ast_mark(mtx_prof, 0); \
176 return pthread_mutex_lock((a)); \
180 #define AST_PTHREADT_NULL (pthread_t) -1
181 #define AST_PTHREADT_STOP (pthread_t) -2
183 #if defined(SOLARIS) || defined(BSD)
184 #define AST_MUTEX_INIT_W_CONSTRUCTORS
189 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
190 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
191 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
193 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
194 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
199 #define log_mutex_error(canlog, ...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
202 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
204 #define DO_THREAD_CRASH do { } while (0)
207 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
209 #define AST_MAX_REENTRANCY 10
212 pthread_mutex_t mutex;
214 unsigned int track:1;
215 const char *file[AST_MAX_REENTRANCY];
216 int lineno[AST_MAX_REENTRANCY];
218 const char *func[AST_MAX_REENTRANCY];
219 pthread_t
thread[AST_MAX_REENTRANCY];
224 typedef pthread_cond_t ast_cond_t;
226 static pthread_mutex_t empty_mutex;
228 static void __attribute__((constructor)) init_empty_mutex(
void)
230 memset(&empty_mutex, 0,
sizeof(empty_mutex));
233 static inline int __ast_pthread_mutex_init_attr(
const char *filename,
int lineno,
const char *func,
235 pthread_mutexattr_t *attr)
237 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
238 int canlog = strcmp(filename,
"logger.c");
240 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
241 if ((t->mutex) != (empty_mutex)) {
242 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is already initialized.\n",
243 filename, lineno, func, mutex_name);
244 log_mutex_error(canlog,
"%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
245 t->file[0], t->lineno[0], t->func[0], mutex_name);
252 t->file[0] = filename;
253 t->lineno[0] = lineno;
258 return pthread_mutex_init(&t->mutex, attr);
261 static inline int __ast_pthread_mutex_init(
const char *filename,
int lineno,
const char *func,
264 static pthread_mutexattr_t attr;
266 pthread_mutexattr_init(&attr);
267 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
269 return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
271 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
273 static inline int __ast_pthread_mutex_destroy(
const char *filename,
int lineno,
const char *func,
277 int canlog = strcmp(filename,
"logger.c");
279 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
280 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
281 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
282 filename, lineno, func, mutex_name);
286 res = pthread_mutex_trylock(&t->mutex);
289 pthread_mutex_unlock(&t->mutex);
292 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
293 filename, lineno, func, mutex_name);
296 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
297 filename, lineno, func, mutex_name);
298 log_mutex_error(canlog,
"%s line %d (%s): Error: '%s' was locked here.\n",
299 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
303 if ((res = pthread_mutex_destroy(&t->mutex)))
304 log_mutex_error(canlog,
"%s line %d (%s): Error destroying mutex: %s\n",
305 filename, lineno, func, strerror(res));
306 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
308 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
310 t->file[0] = filename;
311 t->lineno[0] = lineno;
317 static inline int __ast_pthread_mutex_lock(
const char *filename,
int lineno,
const char *func,
321 int canlog = strcmp(filename,
"logger.c");
323 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
324 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
325 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
326 filename, lineno, func, mutex_name);
331 #ifdef DETECT_DEADLOCKS
333 time_t seconds = time(NULL);
336 #ifdef HAVE_MTX_PROFILE
337 ast_mark(mtx_prof, 1);
339 res = pthread_mutex_trylock(&t->mutex);
340 #ifdef HAVE_MTX_PROFILE
341 ast_mark(mtx_prof, 0);
344 current = time(NULL);
345 if ((current - seconds) && (!((current - seconds) % 5))) {
346 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
347 filename, lineno, func, (
int)(current - seconds), mutex_name);
348 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
349 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
350 t->func[t->reentrancy-1], mutex_name);
354 }
while (res == EBUSY);
357 #ifdef HAVE_MTX_PROFILE
358 ast_mark(mtx_prof, 1);
359 res = pthread_mutex_trylock(&t->mutex);
360 ast_mark(mtx_prof, 0);
363 res = pthread_mutex_lock(&t->mutex);
367 if (t->reentrancy < AST_MAX_REENTRANCY) {
368 t->file[t->reentrancy] = filename;
369 t->lineno[t->reentrancy] = lineno;
370 t->func[t->reentrancy] = func;
371 t->thread[t->reentrancy] = pthread_self();
374 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
375 filename, lineno, func, mutex_name);
378 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining mutex: %s\n",
379 filename, lineno, func, strerror(errno));
386 static inline int __ast_pthread_mutex_trylock(
const char *filename,
int lineno,
const char *func,
390 int canlog = strcmp(filename,
"logger.c");
392 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
393 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
394 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
395 filename, lineno, func, mutex_name);
400 if (!(res = pthread_mutex_trylock(&t->mutex))) {
401 if (t->reentrancy < AST_MAX_REENTRANCY) {
402 t->file[t->reentrancy] = filename;
403 t->lineno[t->reentrancy] = lineno;
404 t->func[t->reentrancy] = func;
405 t->thread[t->reentrancy] = pthread_self();
408 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
409 filename, lineno, func, mutex_name);
412 log_mutex_error(canlog,
"%s line %d (%s): Warning: '%s' was locked here.\n",
413 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
419 static inline int __ast_pthread_mutex_unlock(
const char *filename,
int lineno,
const char *func,
423 int canlog = strcmp(filename,
"logger.c");
425 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
426 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
427 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
428 filename, lineno, func, mutex_name);
432 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
433 log_mutex_error(canlog,
"%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
434 filename, lineno, func, mutex_name);
435 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
436 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
440 if (--t->reentrancy < 0) {
441 log_mutex_error(canlog,
"%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
442 filename, lineno, func, mutex_name);
446 if (t->reentrancy < AST_MAX_REENTRANCY) {
447 t->file[t->reentrancy] = NULL;
448 t->lineno[t->reentrancy] = 0;
449 t->func[t->reentrancy] = NULL;
450 t->thread[t->reentrancy] = 0;
453 if ((res = pthread_mutex_unlock(&t->mutex))) {
454 log_mutex_error(canlog,
"%s line %d (%s): Error releasing mutex: %s\n",
455 filename, lineno, func, strerror(res));
467 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
469 static inline int ast_mutex_init(ast_mutex_t *pmutex)
471 pthread_mutexattr_t attr;
473 pthread_mutexattr_init(&attr);
474 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
476 return pthread_mutex_init(pmutex, &attr);
479 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
481 typedef pthread_cond_t ast_cond_t;
485 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
488 #define __AST_MUTEX_DEFINE(scope, mutex) \
489 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
490 static void __attribute__((constructor)) init_##mutex(void) \
492 ast_mutex_init(&mutex); \
496 #define __AST_MUTEX_DEFINE(scope, mutex) \
497 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
500 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
501 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
502 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
504 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
506 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
508 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
511 #define pthread_create __use_ast_pthread_create_instead__
518 pthread_rwlockattr_t attr;
520 pthread_rwlockattr_init(&attr);
522 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
523 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
526 return pthread_rwlock_init(prwlock, &attr);
529 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
531 return pthread_rwlock_destroy(prwlock);
534 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
536 return pthread_rwlock_unlock(prwlock);
539 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
541 return pthread_rwlock_rdlock(prwlock);
544 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
546 return pthread_rwlock_wrlock(prwlock);
551 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
552 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
553 scope ast_rwlock_t rwlock; \
554 static void __attribute__((constructor)) init_##rwlock(void) \
556 ast_rwlock_init(&rwlock); \
558 static void __attribute__((destructor)) fini_##rwlock(void) \
560 ast_rwlock_destroy(&rwlock); \
563 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
564 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
565 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
568 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
580 #if defined(HAVE_OSX_ATOMICS)
581 #include "libkern/OSAtomic.h"
589 #if defined(HAVE_GCC_ATOMICS)
592 return __sync_fetch_and_add(p, v);
594 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
597 return OSAtomicAdd32(v, (int32_t *) p);
599 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
602 return OSAtomicAdd64(v, (int64_t *) p);
603 #elif defined (__i386__) || defined(__x86_64__)
607 " lock xaddl %0, %1 ; "
614 static int ast_atomic_fetchadd_int_slow(
volatile int *p,
int v)
623 return ast_atomic_fetchadd_int_slow(p, v);
630 #
if defined(HAVE_GCC_ATOMICS)
633 return __sync_sub_and_fetch(p, 1) == 0;
635 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
638 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
640 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
643 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
652 #ifdef DEBUG_CHANNEL_LOCKS
670 #include "asterisk/pval.h"
677 #define ast_test_flag(p,flag) ({ \
678 typeof ((p)->flags) __p = (p)->flags; \
679 unsigned int __x = 0; \
680 (void) (&__p == &__x); \
681 ((p)->flags & (flag)); \
684 #define ast_set2_flag(p,value,flag) do { \
685 typeof ((p)->flags) __p = (p)->flags; \
686 unsigned int __x = 0; \
687 (void) (&__p == &__x); \
689 (p)->flags |= (flag); \
691 (p)->flags &= ~(flag); \
696 #define MAX_NESTED_COMMENTS 128
697 #define COMMENT_START ";--"
698 #define COMMENT_END "--;"
699 #define COMMENT_META ';'
700 #define COMMENT_TAG '-'
702 static char *extconfig_conf =
"extconfig.conf";
709 static int lline_buffer_size;
718 static void CB_INIT(
void)
720 if (!comment_buffer) {
724 comment_buffer[0] = 0;
725 comment_buffer_size = CB_INCR;
730 lline_buffer_size = CB_INCR;
732 comment_buffer[0] = 0;
737 static void CB_ADD(
char *str)
739 int rem = comment_buffer_size - strlen(comment_buffer) - 1;
740 int siz = strlen(str);
742 comment_buffer =
ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
745 comment_buffer_size += CB_INCR+siz+1;
747 strcat(comment_buffer,str);
750 static void CB_ADD_LEN(
char *str,
int len)
752 int cbl = strlen(comment_buffer) + 1;
753 int rem = comment_buffer_size - cbl;
755 comment_buffer =
ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
758 comment_buffer_size += CB_INCR+len+1;
760 strncat(comment_buffer,str,len);
761 comment_buffer[cbl+len-1] = 0;
764 static void LLB_ADD(
char *str)
766 int rem = lline_buffer_size - strlen(lline_buffer) - 1;
767 int siz = strlen(str);
769 lline_buffer =
ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
772 lline_buffer_size += CB_INCR + siz + 1;
774 strcat(lline_buffer,str);
777 static void CB_RESET(
void )
779 comment_buffer[0] = 0;
786 static struct sigaction safe_system_prev_handler;
794 static struct sigaction null_sig_handler = {
796 .sa_flags = SA_RESTART,
805 level = safe_system_level++;
809 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
823 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
832 #ifdef HAVE_WORKING_FORK
838 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
841 #ifdef HAVE_WORKING_FORK
848 #ifdef HAVE_WORKING_FORK
850 for (x = STDERR_FILENO + 1; x < 4096; x++)
853 execl(
"/bin/sh",
"/bin/sh",
"-c", s, (
char *) NULL);
855 }
else if (pid > 0) {
857 res = waitpid(pid, &status, 0);
859 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
861 }
else if (errno != EINTR)
865 ast_log(LOG_WARNING,
"Fork failed: %s\n", strerror(errno));
877 static struct ast_comment *ALLOC_COMMENT(
const char *buffer)
880 strcpy(x->
cmt, buffer);
891 } *config_maps = NULL;
895 #define MAX_INCLUDE_LEVEL 10
917 int max_include_level;
933 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);
934 typedef struct ast_variable *realtime_var_get(
const char *database,
const char *table, va_list ap);
935 typedef struct ast_config *realtime_multi_get(
const char *database,
const char *table, va_list ap);
936 typedef int realtime_update(
const char *database,
const char *table,
const char *keyfield,
const char *entity, va_list ap);
941 config_load_func *load_func;
942 realtime_var_get *realtime_func;
943 realtime_multi_get *realtime_multi_func;
944 realtime_update *update_func;
952 static force_inline
int ast_strlen_zero(
const char *s)
954 return (!s || (*s ==
'\0'));
957 #define S_OR(a, b) (!ast_strlen_zero(a) ? (a) : (b))
962 while (*src && size) {
966 if (__builtin_expect(!size, 0))
975 while (*str && *str < 33)
992 work += strlen(work) - 1;
999 while ((work >= str) && *work < 33)
1041 static const char *ast_variable_retrieve(
const struct ast_config *config,
const char *category,
const char *variable);
1044 struct ast_config *localized_config_load_with_comments(
const char *filename);
1051 void localized_ast_include_rename(
struct ast_config *
conf,
const char *from_file,
const char *to_file);
1053 static struct ast_variable *ast_variable_new(
const char *
name,
const char *
value,
const char *filename);
1055 static struct ast_variable *ast_variable_new(
const char *
name,
const char *
value,
const char *filename)
1058 int name_len = strlen(name) + 1;
1059 size_t value_len = strlen(value) + 1;
1060 size_t filename_len = strlen(filename) + 1;
1062 if ((variable =
ast_calloc(1, name_len + value_len + filename_len +
sizeof(*variable)))) {
1064 variable->
value = variable->
stuff + name_len;
1065 variable->
file = variable->
value + value_len;
1066 strcpy(variable->
name,name);
1082 inc = ast_include_find(conf, included_file);
1086 snprintf(real_included_file_name, real_included_file_name_size,
"%s~~%d", included_file, inc->
inclusion_count);
1087 ast_log(LOG_WARNING,
"'%s', line %d: Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
1089 *real_included_file_name = 0;
1094 if (!ast_strlen_zero(real_included_file_name))
1099 inc->
exec = is_exec;
1110 void localized_ast_include_rename(
struct ast_config *conf,
const char *from_file,
const char *to_file)
1116 int from_len = strlen(from_file);
1117 int to_len = strlen(to_file);
1119 if (strcmp(from_file, to_file) == 0)
1133 if (from_len >= to_len)
1141 for (cat = conf->
root; cat; cat = cat->
next) {
1142 if (strcmp(cat->
file,from_file) == 0) {
1143 if (from_len >= to_len)
1144 strcpy(cat->
file, to_file);
1147 cat->
file = strdup(to_file);
1150 for (v = cat->
root; v; v = v->
next) {
1151 if (strcmp(v->
file,from_file) == 0) {
1152 if (from_len >= to_len)
1153 strcpy(v->
file, to_file);
1156 v->
file = strdup(to_file);
1184 category->
root = variable;
1185 category->
last = variable;
1197 for (cat = config->
root; cat; cat = cat->
next) {
1198 if (cat->name == category_name && (ignored || !cat->
ignored))
1202 for (cat = config->
root; cat; cat = cat->
next) {
1203 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->
ignored))
1212 return category_get(config, category_name, 0);
1224 return (cat) ? cat->
root : NULL;
1227 static const char *ast_variable_retrieve(
const struct ast_config *config,
const char *category,
const char *variable)
1232 for (v = ast_variable_browse(config, category); v; v = v->
next) {
1233 if (!strcasecmp(variable, v->
name))
1239 for (cat = config->
root; cat; cat = cat->
next)
1240 for (v = cat->
root; v; v = v->
next)
1241 if (!strcasecmp(variable, v->
name))
1253 new->lineno = old->lineno;
1254 new->object = old->
object;
1277 for (incl=incls; incl; incl = inclnext) {
1278 inclnext = incl->
next;
1296 ast_includes_destroy(cfg->
includes);
1358 #define AST_CACHE_DIR_LEN 512
1359 #define AST_FILENAME_MAX 80
1362 #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
1366 #define ast_opt_exec_includes ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
1367 #define ast_opt_no_fork ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
1368 #define ast_opt_quiet ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
1369 #define ast_opt_console ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
1370 #define ast_opt_high_priority ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
1371 #define ast_opt_init_keys ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
1372 #define ast_opt_remote ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
1373 #define ast_opt_exec ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
1374 #define ast_opt_no_color ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
1375 #define ast_fully_booted ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
1376 #define ast_opt_transcode_via_slin ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
1377 #define ast_opt_priority_jumping ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
1378 #define ast_opt_dump_core ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
1379 #define ast_opt_cache_record_files ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
1380 #define ast_opt_timestamp ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
1381 #define ast_opt_override_config ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
1382 #define ast_opt_reconnect ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
1383 #define ast_opt_transmit_silence ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
1384 #define ast_opt_dont_warn ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
1385 #define ast_opt_always_fork ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
1386 #define ast_opt_mute ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
1392 extern char ast_defaultlanguage[];
1394 extern pid_t ast_mainpid;
1396 extern char record_cache_dir[AST_CACHE_DIR_LEN];
1397 extern char debug_filename[AST_FILENAME_MAX];
1413 #define AST_RWLIST_WRLOCK(head) \
1414 ast_rwlock_wrlock(&(head)->lock)
1424 #define AST_RWLIST_RDLOCK(head) \
1425 ast_rwlock_rdlock(&(head)->lock)
1435 #define AST_RWLIST_UNLOCK(head) \
1436 ast_rwlock_unlock(&(head)->lock)
1457 #define AST_LIST_HEAD(name, type) \
1459 struct type *first; \
1460 struct type *last; \
1483 #define AST_RWLIST_HEAD(name, type) \
1485 struct type *first; \
1486 struct type *last; \
1487 ast_rwlock_t lock; \
1509 #define AST_LIST_HEAD_NOLOCK(name, type) \
1511 struct type *first; \
1512 struct type *last; \
1518 #define AST_LIST_HEAD_INIT_VALUE { \
1521 .lock = AST_MUTEX_INIT_VALUE, \
1527 #define AST_RWLIST_HEAD_INIT_VALUE { \
1530 .lock = AST_RWLOCK_INIT_VALUE, \
1536 #define AST_LIST_HEAD_NOLOCK_INIT_VALUE { \
1558 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
1559 #define AST_LIST_HEAD_STATIC(name, type) \
1561 struct type *first; \
1562 struct type *last; \
1565 static void __attribute__((constructor)) init_##name(void) \
1567 AST_LIST_HEAD_INIT(&name); \
1569 static void __attribute__((destructor)) fini_##name(void) \
1571 AST_LIST_HEAD_DESTROY(&name); \
1573 struct __dummy_##name
1575 #define AST_LIST_HEAD_STATIC(name, type) \
1577 struct type *first; \
1578 struct type *last; \
1580 } name = AST_LIST_HEAD_INIT_VALUE
1600 #ifndef AST_RWLOCK_INIT_VALUE
1601 #define AST_RWLIST_HEAD_STATIC(name, type) \
1603 struct type *first; \
1604 struct type *last; \
1605 ast_rwlock_t lock; \
1607 static void __attribute__((constructor)) init_##name(void) \
1609 AST_RWLIST_HEAD_INIT(&name); \
1611 static void __attribute__((destructor)) fini_##name(void) \
1613 AST_RWLIST_HEAD_DESTROY(&name); \
1615 struct __dummy_##name
1617 #define AST_RWLIST_HEAD_STATIC(name, type) \
1619 struct type *first; \
1620 struct type *last; \
1621 ast_rwlock_t lock; \
1622 } name = AST_RWLIST_HEAD_INIT_VALUE
1630 #define AST_LIST_HEAD_NOLOCK_STATIC(name, type) \
1632 struct type *first; \
1633 struct type *last; \
1634 } name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
1644 #define AST_LIST_HEAD_SET(head, entry) do { \
1645 (head)->first = (entry); \
1646 (head)->last = (entry); \
1647 ast_mutex_init(&(head)->lock); \
1658 #define AST_RWLIST_HEAD_SET(head, entry) do { \
1659 (head)->first = (entry); \
1660 (head)->last = (entry); \
1661 ast_rwlock_init(&(head)->lock); \
1672 #define AST_LIST_HEAD_SET_NOLOCK(head, entry) do { \
1673 (head)->first = (entry); \
1674 (head)->last = (entry); \
1694 #define AST_LIST_ENTRY(type) \
1696 struct type *next; \
1699 #define AST_RWLIST_ENTRY AST_LIST_ENTRY
1705 #define AST_LIST_FIRST(head) ((head)->first)
1707 #define AST_RWLIST_FIRST AST_LIST_FIRST
1713 #define AST_LIST_LAST(head) ((head)->last)
1715 #define AST_RWLIST_LAST AST_LIST_LAST
1723 #define AST_LIST_NEXT(elm, field) ((elm)->field.next)
1725 #define AST_RWLIST_NEXT AST_LIST_NEXT
1733 #define AST_LIST_EMPTY(head) (AST_LIST_FIRST(head) == NULL)
1735 #define AST_RWLIST_EMPTY AST_LIST_EMPTY
1773 #define AST_LIST_TRAVERSE(head,var,field) \
1774 for((var) = (head)->first; (var); (var) = (var)->field.next)
1776 #define AST_RWLIST_TRAVERSE AST_LIST_TRAVERSE
1811 #define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) { \
1812 typeof((head)->first) __list_next; \
1813 typeof((head)->first) __list_prev = NULL; \
1814 typeof((head)->first) __new_prev = NULL; \
1815 for ((var) = (head)->first, __new_prev = (var), \
1816 __list_next = (var) ? (var)->field.next : NULL; \
1818 __list_prev = __new_prev, (var) = __list_next, \
1819 __new_prev = (var), \
1820 __list_next = (var) ? (var)->field.next : NULL \
1823 #define AST_RWLIST_TRAVERSE_SAFE_BEGIN AST_LIST_TRAVERSE_SAFE_BEGIN
1836 #define AST_LIST_REMOVE_CURRENT(head, field) \
1837 __new_prev->field.next = NULL; \
1838 __new_prev = __list_prev; \
1840 __list_prev->field.next = __list_next; \
1842 (head)->first = __list_next; \
1844 (head)->last = __list_prev;
1846 #define AST_RWLIST_REMOVE_CURRENT AST_LIST_REMOVE_CURRENT
1858 #define AST_LIST_INSERT_BEFORE_CURRENT(head, elm, field) do { \
1859 if (__list_prev) { \
1860 (elm)->field.next = __list_prev->field.next; \
1861 __list_prev->field.next = elm; \
1863 (elm)->field.next = (head)->first; \
1864 (head)->first = (elm); \
1866 __new_prev = (elm); \
1869 #define AST_RWLIST_INSERT_BEFORE_CURRENT AST_LIST_INSERT_BEFORE_CURRENT
1874 #define AST_LIST_TRAVERSE_SAFE_END }
1876 #define AST_RWLIST_TRAVERSE_SAFE_END AST_LIST_TRAVERSE_SAFE_END
1885 #define AST_LIST_HEAD_INIT(head) { \
1886 (head)->first = NULL; \
1887 (head)->last = NULL; \
1888 ast_mutex_init(&(head)->lock); \
1898 #define AST_RWLIST_HEAD_INIT(head) { \
1899 (head)->first = NULL; \
1900 (head)->last = NULL; \
1901 ast_rwlock_init(&(head)->lock); \
1912 #define AST_RWLIST_HEAD_DESTROY(head) { \
1913 (head)->first = NULL; \
1914 (head)->last = NULL; \
1915 ast_rwlock_destroy(&(head)->lock); \
1926 #define AST_LIST_HEAD_INIT_NOLOCK(head) { \
1927 (head)->first = NULL; \
1928 (head)->last = NULL; \
1940 #define AST_LIST_INSERT_AFTER(head, listelm, elm, field) do { \
1941 (elm)->field.next = (listelm)->field.next; \
1942 (listelm)->field.next = (elm); \
1943 if ((head)->last == (listelm)) \
1944 (head)->last = (elm); \
1947 #define AST_RWLIST_INSERT_AFTER AST_LIST_INSERT_AFTER
1956 #define AST_LIST_INSERT_HEAD(head, elm, field) do { \
1957 (elm)->field.next = (head)->first; \
1958 (head)->first = (elm); \
1959 if (!(head)->last) \
1960 (head)->last = (elm); \
1963 #define AST_RWLIST_INSERT_HEAD AST_LIST_INSERT_HEAD
1976 #define AST_LIST_INSERT_TAIL(head, elm, field) do { \
1977 if (!(head)->first) { \
1978 (head)->first = (elm); \
1979 (head)->last = (elm); \
1981 (head)->last->field.next = (elm); \
1982 (head)->last = (elm); \
1986 #define AST_RWLIST_INSERT_TAIL AST_LIST_INSERT_TAIL
1995 #define AST_LIST_APPEND_LIST(head, list, field) do { \
1996 if (!(head)->first) { \
1997 (head)->first = (list)->first; \
1998 (head)->last = (list)->last; \
2000 (head)->last->field.next = (list)->first; \
2001 (head)->last = (list)->last; \
2005 #define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
2016 #define AST_LIST_REMOVE_HEAD(head, field) ({ \
2017 typeof((head)->first) cur = (head)->first; \
2019 (head)->first = cur->field.next; \
2020 cur->field.next = NULL; \
2021 if ((head)->last == cur) \
2022 (head)->last = NULL; \
2027 #define AST_RWLIST_REMOVE_HEAD AST_LIST_REMOVE_HEAD
2037 #define AST_LIST_REMOVE(head, elm, field) do { \
2038 if ((head)->first == (elm)) { \
2039 (head)->first = (elm)->field.next; \
2040 if ((head)->last == (elm)) \
2041 (head)->last = NULL; \
2043 typeof(elm) curelm = (head)->first; \
2044 while (curelm && (curelm->field.next != (elm))) \
2045 curelm = curelm->field.next; \
2047 curelm->field.next = (elm)->field.next; \
2048 if ((head)->last == (elm)) \
2049 (head)->last = curelm; \
2052 (elm)->field.next = NULL; \
2055 #define AST_RWLIST_REMOVE AST_LIST_REMOVE
2067 AST_RWLOCK_DEFINE_STATIC(globalslock);
2073 static struct ast_var_t *ast_var_assign(
const char *name,
const char *value);
2075 static void ast_var_delete(
struct ast_var_t *var);
2078 #define AST_MAX_EXTENSION 80
2082 #define PRIORITY_HINT -1
2111 const char *description;
2120 static char *config_filename =
"extensions.conf";
2121 static char *global_registrar =
"conf2ael";
2123 static int static_config = 0;
2124 static int write_protect_config = 1;
2125 static int autofallthrough_config = 0;
2126 static int clearglobalvars_config = 0;
2127 static void pbx_substitute_variables_helper(
struct ast_channel *c,
const char *cp1,
char *cp2,
int count);
2141 for (x=0; n[x]; x++) {
2160 if (!strchr(
"()", n[x]))
2170 static const char *ast_var_name(
const struct ast_var_t *var)
2174 if (var == NULL || (name = var->name) == NULL)
2177 if (name[0] ==
'_') {
2194 static void ast_log(
int level,
const char *file,
int line,
const char *
function,
const char *fmt, ...)
2199 printf(
"LOG: lev:%d file:%s line:%d func: %s ",
2200 level, file, line,
function);
2206 void __attribute__((format(printf, 1, 2))) ast_verbose(const
char *fmt, ...)
2211 printf(
"VERBOSE: ");
2220 char *dataPut = start;
2224 for (; *start; start++) {
2226 *dataPut++ = *start;
2229 if (*start ==
'\\') {
2231 }
else if (*start ==
'\'') {
2232 inQuotes = 1 - inQuotes;
2235 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
2239 if (start != dataPut)
2246 if (ast_strlen_zero(s))
2250 if (!strcasecmp(s,
"yes") ||
2251 !strcasecmp(s,
"true") ||
2252 !strcasecmp(s,
"y") ||
2253 !strcasecmp(s,
"t") ||
2254 !strcasecmp(s,
"1") ||
2255 !strcasecmp(s,
"on"))
2261 #define ONE_MILLION 1000000
2266 static struct timeval tvfix(struct timeval a)
2268 if (a.tv_usec >= ONE_MILLION) {
2269 ast_log(LOG_WARNING,
"warning too large timestamp %ld.%ld\n",
2270 (
long)a.tv_sec, (
long int) a.tv_usec);
2271 a.tv_sec += a.tv_usec / ONE_MILLION;
2272 a.tv_usec %= ONE_MILLION;
2273 }
else if (a.tv_usec < 0) {
2274 ast_log(LOG_WARNING,
"warning negative timestamp %ld.%ld\n",
2275 (
long)a.tv_sec, (
long int) a.tv_usec);
2281 struct timeval
ast_tvadd(struct timeval a, struct timeval b);
2282 struct timeval
ast_tvadd(struct timeval a, struct timeval b)
2287 a.tv_sec += b.tv_sec;
2288 a.tv_usec += b.tv_usec;
2289 if (a.tv_usec >= ONE_MILLION) {
2291 a.tv_usec -= ONE_MILLION;
2296 struct timeval
ast_tvsub(struct timeval a, struct timeval b);
2297 struct timeval
ast_tvsub(struct timeval a, struct timeval b)
2302 a.tv_sec -= b.tv_sec;
2303 a.tv_usec -= b.tv_usec;
2304 if (a.tv_usec < 0) {
2306 a.tv_usec += ONE_MILLION;
2312 void ast_mark_lock_failed(
void *lock_addr);
2313 void ast_mark_lock_failed(
void *lock_addr)
2319 #define VAR_BUF_SIZE 4096
2321 #define VAR_NORMAL 1
2322 #define VAR_SOFTTRAN 2
2323 #define VAR_HARDTRAN 3
2325 #define BACKGROUND_SKIP (1 << 0)
2326 #define BACKGROUND_NOANSWER (1 << 1)
2327 #define BACKGROUND_MATCHEXTEN (1 << 2)
2328 #define BACKGROUND_PLAYBACK (1 << 3)
2339 const char *cidmatch;
2346 void (*datad)(
void *);
2356 unsigned int monthmask;
2357 unsigned int daymask;
2358 unsigned int dowmask;
2359 unsigned int minmask[48];
2367 const char *registrar;
2377 const char *registrar;
2387 const char *registrar;
2388 struct ast_ignorepat *next;
2399 const char *registrar;
2410 AST_RWLIST_ENTRY(ast_app) list;
2421 struct ast_state_cb *next;
2448 #define STATUS_NO_CONTEXT 1
2449 #define STATUS_NO_EXTENSION 2
2450 #define STATUS_NO_PRIORITY 3
2451 #define STATUS_NO_LABEL 4
2452 #define STATUS_SUCCESS 5
2454 static struct ast_var_t *ast_var_assign(
const char *name,
const char *value)
2457 int name_len = strlen(name) + 1;
2458 int value_len = strlen(value) + 1;
2460 if (!(var =
ast_calloc(
sizeof(*var) + name_len + value_len,
sizeof(
char)))) {
2465 var->value = var->name + name_len;
2471 static void ast_var_delete(
struct ast_var_t *var)
2486 static unsigned int ast_app_separate_args(
char *buf,
char delim,
char **array,
int arraylen)
2490 int paren = 0, quote = 0;
2492 if (!buf || !array || !arraylen)
2495 memset(array, 0, arraylen *
sizeof(*array));
2499 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
2501 for (; *scan; scan++) {
2504 else if (*scan ==
')') {
2507 }
else if (*scan ==
'"' && delim !=
'"') {
2508 quote = quote ? 0 : 1;
2510 memmove(scan, scan + 1, strlen(scan));
2512 }
else if (*scan ==
'\\') {
2514 memmove(scan, scan + 1, strlen(scan));
2515 }
else if ((*scan == delim) && !paren && !quote) {
2523 array[argc++] = scan;
2532 const char *nametail =
name;
2535 if (name[strlen(name)-1] ==
')') {
2545 if (*nametail ==
'_') {
2547 if (*nametail ==
'_')
2552 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
2555 ast_var_delete(newvariable);
2560 if (value && (newvariable = ast_var_assign(name, value))) {
2561 if ((option_verbose > 1) && (headp == &globals))
2562 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name, value);
2570 char *
name, *value, *mydata;
2576 if (ast_strlen_zero(data)) {
2577 ast_log(LOG_WARNING,
"Set requires at least one variable name/value pair.\n");
2582 argc = ast_app_separate_args(mydata,
'|', argv,
sizeof(argv) /
sizeof(argv[0]));
2585 if ((argc > 1) && !strchr(argv[argc-1],
'=')) {
2587 if (strchr(argv[argc],
'g'))
2591 for (x = 0; x < argc; x++) {
2593 if ((value = strchr(name,
'='))) {
2597 ast_log(LOG_WARNING,
"Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
2603 int localized_pbx_builtin_setvar(
struct ast_channel *chan,
const void *data);
2605 int localized_pbx_builtin_setvar(
struct ast_channel *chan,
const void *data)
2619 if (names && *s >
'9') {
2620 for (i = 0; names[i]; i++) {
2621 if (!strcasecmp(s, names[i])) {
2628 if (sscanf(s,
"%2d", &i) == 1 && i >= 1 && i <= max) {
2638 static unsigned get_range(
char *src,
int max,
char *
const names[],
const char *msg)
2641 unsigned int mask = 0;
2645 if (ast_strlen_zero(src) || !strcmp(src,
"*")) {
2646 return (1 << max) - 1;
2649 while ((part = strsep(&src,
"&"))) {
2651 char *endpart = strchr(part,
'-');
2656 if ((start =
lookup_name(part, names, max)) < 0) {
2657 ast_log(LOG_WARNING,
"Invalid %s '%s', skipping element\n", msg, part);
2661 if ((end =
lookup_name(endpart, names, max)) < 0) {
2662 ast_log(LOG_WARNING,
"Invalid end %s '%s', skipping element\n", msg, endpart);
2670 while (start != end) {
2674 mask |= (1 << start);
2684 char *endpart, *part;
2688 int minute_start, minute_end;
2695 if (ast_strlen_zero(times) || !strcmp(times,
"*")) {
2697 for (x = 0; x < 48; x++) {
2703 while ((part = strsep(×,
"&"))) {
2704 if (!(endpart = strchr(part,
'-'))) {
2705 if (sscanf(part,
"%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
2706 ast_log(LOG_WARNING,
"%s isn't a valid time.\n", part);
2709 i->
minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
2714 while (*endpart && !isdigit(*endpart)) {
2718 ast_log(LOG_WARNING,
"Invalid time range starting with '%s-'.\n", part);
2721 if (sscanf(part,
"%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
2722 ast_log(LOG_WARNING,
"'%s' isn't a valid start time.\n", part);
2725 if (sscanf(endpart,
"%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
2726 ast_log(LOG_WARNING,
"'%s' isn't a valid end time.\n", endpart);
2729 minute_start = st_h * 60 + st_m;
2730 minute_end = endh * 60 + endm;
2732 for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
2733 i->
minmask[x / 30] |= (1 << (x % 30));
2736 i->
minmask[x / 30] |= (1 << (x % 30));
2742 static void null_datad(
void *foo)
2753 for (map = config_maps; map; map = map->next) {
2754 if (!strcasecmp(family, map->
name)) {
2765 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
2766 if (!strcasecmp(eng->name, map->
driver))
2774 ast_log(LOG_WARNING,
"Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->
name, map->
driver);
2783 return cfg->current;
2792 if ((category =
ast_calloc(1,
sizeof(*category))))
2794 category->
file = strdup(in_file);
2795 category->lineno = lineno;
2803 return category_get(config, category_name, 0);
2812 ast_variable_append(
new, var);
2817 ast_variable_append(
new, var);
2827 for (var = base->
root; var; var = var->
next)
2828 ast_variable_append(
new, variable_clone(var));
2838 config->
root = category;
2839 config->
last = category;
2840 config->current = category;
2843 static void ast_category_destroy(
struct ast_category *cat);
2845 static void ast_category_destroy(
struct ast_category *cat)
2860 static struct ast_config *ast_config_internal_load(
const char *filename,
struct ast_config *cfg,
int withcomments,
const char *suggested_incl_file);
2862 static struct ast_config *ast_config_internal_load(
const char *filename,
struct ast_config *cfg,
int withcomments,
const char *suggested_incl_file)
2865 char table[256] =
"";
2869 if (cfg->include_level == cfg->max_include_level) {
2870 ast_log(LOG_WARNING,
"Maximum Include level (%d) exceeded\n", cfg->max_include_level);
2874 cfg->include_level++;
2879 if (strcmp(filename, extconfig_conf) && strcmp(filename,
"asterisk.conf") && config_engine_list) {
2882 eng =
find_engine(filename, db,
sizeof(db), table,
sizeof(table));
2885 if (eng && eng->load_func) {
2888 eng =
find_engine(
"global", db,
sizeof(db), table,
sizeof(table));
2889 if (eng && eng->load_func)
2894 result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
2900 result->include_level--;
2911 char exec_file[512];
2912 int object, do_exec, do_include;
2915 if (cur[0] ==
'[') {
2920 c = strchr(cur,
']');
2922 ast_log(LOG_WARNING,
"parse error: no closing ']', line %d of %s\n", lineno, configfile);
2930 if (!(*cat = newcat =
ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
2933 (*cat)->lineno = lineno;
2936 if (withcomments && comment_buffer && comment_buffer[0] ) {
2937 newcat->precomments = ALLOC_COMMENT(comment_buffer);
2939 if (withcomments && lline_buffer && lline_buffer[0] ) {
2940 newcat->sameline = ALLOC_COMMENT(lline_buffer);
2947 if (!(cur = strchr(c,
')'))) {
2948 ast_log(LOG_WARNING,
"parse error: no closing ')', line %d of %s\n", lineno, configfile);
2952 while ((cur = strsep(&c,
","))) {
2953 if (!strcasecmp(cur,
"!")) {
2954 (*cat)->ignored = 1;
2955 }
else if (!strcasecmp(cur,
"+")) {
2956 *cat = category_get(cfg, catname, 1);
2960 ast_category_destroy(newcat);
2961 ast_log(LOG_WARNING,
"Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
2965 move_variables(newcat, *cat);
2966 ast_category_destroy(newcat);
2972 base = category_get(cfg, cur, 1);
2974 ast_log(LOG_WARNING,
"Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
2977 inherit_category(*cat, base);
2983 }
else if (cur[0] ==
'#') {
2987 while(*c && (*c > 32)) c++;
2996 do_include = !strcasecmp(cur,
"include");
2998 do_exec = !strcasecmp(cur,
"exec");
3001 if (do_exec && !ast_opt_exec_includes) {
3002 ast_log(LOG_WARNING,
"Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
3005 if (do_include || do_exec) {
3008 char real_inclusion_name[525];
3011 while((*c ==
'<') || (*c ==
'>') || (*c ==
'\"')) c++;
3015 while (!ast_strlen_zero(cur)) {
3016 c = cur + strlen(cur) - 1;
3017 if ((*c ==
'>') || (*c ==
'<') || (*c ==
'\"'))
3027 snprintf(exec_file,
sizeof(exec_file),
"/var/tmp/exec.%d.%ld", (
int)time(NULL), (
long)pthread_self());
3028 if (snprintf(cmd,
sizeof(cmd),
"%s > %s 2>&1", cur, exec_file) >=
sizeof(cmd)) {
3029 ast_log(LOG_ERROR,
"Failed to construct command string to execute %s.\n", cur);
3036 exec_file[0] =
'\0';
3041 ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name,
sizeof(real_inclusion_name));
3043 do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
3044 if(!ast_strlen_zero(exec_file))
3051 ast_log(LOG_WARNING,
"Directive '#%s' needs an argument (%s) at line %d of %s\n",
3052 do_exec ?
"exec" :
"include",
3053 do_exec ?
"/path/to/executable" :
"filename",
3059 ast_log(LOG_WARNING,
"Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
3063 ast_log(LOG_WARNING,
3064 "parse error: No category context for line %d of %s\n", lineno, configfile);
3067 c = strchr(cur,
'=');
3082 ast_variable_append(*cat, v);
3084 if (withcomments && comment_buffer && comment_buffer[0] ) {
3085 v->precomments = ALLOC_COMMENT(comment_buffer);
3087 if (withcomments && lline_buffer && lline_buffer[0] ) {
3088 v->sameline = ALLOC_COMMENT(lline_buffer);
3097 ast_log(LOG_WARNING,
"EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno, configfile);
3103 static int use_local_dir = 1;
3105 void localized_use_local_dir(
void);
3106 void localized_use_conf_dir(
void);
3108 void localized_use_local_dir(
void)
3113 void localized_use_conf_dir(
void)
3123 char *new_buf, *comment_p, *process_buf;
3126 int comment = 0, nest[MAX_NESTED_COMMENTS];
3129 struct stat statbuf;
3133 if (filename[0] ==
'/') {
3137 snprintf(fn,
sizeof(fn),
"./%s", filename);
3139 snprintf(fn,
sizeof(fn),
"%s/%s", ast_config_AST_CONFIG_DIR, filename);
3142 if (withcomments && cfg && cfg->include_level < 2 ) {
3147 if (stat(fn, &statbuf))
3150 if (!S_ISREG(statbuf.st_mode)) {
3151 ast_log(LOG_WARNING,
"'%s' is not a regular file, ignoring\n", fn);
3154 if (option_verbose > 1) {
3155 ast_verbose(VERBOSE_PREFIX_2
"Parsing '%s': ", fn);
3158 if (!(f = fopen(fn,
"r"))) {
3160 ast_log(LOG_DEBUG,
"No file to parse: %s\n", fn);
3161 if (option_verbose > 1)
3162 ast_verbose(
"Not found (%s)\n", strerror(errno));
3167 ast_log(LOG_DEBUG,
"Parsing %s\n", fn);
3168 if (option_verbose > 1)
3169 ast_verbose(
"Found\n");
3172 if (fgets(buf,
sizeof(buf), f)) {
3173 if ( withcomments ) {
3174 CB_ADD(lline_buffer);
3175 lline_buffer[0] = 0;
3184 while ((comment_p = strchr(new_buf, COMMENT_META))) {
3185 if ((comment_p > new_buf) && (*(comment_p-1) ==
'\\')) {
3187 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
3188 new_buf = comment_p;
3189 }
else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] !=
'-')) {
3191 if (comment < MAX_NESTED_COMMENTS) {
3193 new_buf = comment_p + 3;
3195 nest[comment-1] = lineno;
3197 ast_log(LOG_ERROR,
"Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
3199 }
else if ((comment_p >= new_buf + 2) &&
3200 (*(comment_p - 1) == COMMENT_TAG) &&
3201 (*(comment_p - 2) == COMMENT_TAG)) {
3204 new_buf = comment_p + 1;
3210 oldptr = process_buf + strlen(process_buf);
3211 if ( withcomments ) {
3213 CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
3216 memmove(oldptr, new_buf, strlen(new_buf) + 1);
3219 process_buf = new_buf;
3225 if ( withcomments ) {
3229 new_buf = comment_p;
3231 new_buf = comment_p + 1;
3234 if( withcomments && comment && !process_buf )
3240 char *stripped_process_buf =
ast_strip(process_buf);
3241 if (!ast_strlen_zero(stripped_process_buf)) {
3242 if (
process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
3253 ast_log(LOG_WARNING,
"Unterminated comment detected beginning on line %d\n", nest[comment]);
3255 if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
3256 if (comment_buffer) {
3257 free(comment_buffer);
3261 comment_buffer_size=0;
3262 lline_buffer_size=0;
3278 if ((config =
ast_calloc(1,
sizeof(*config))))
3279 config->max_include_level = MAX_INCLUDE_LEVEL;
3283 struct ast_config *localized_config_load(
const char *filename);
3285 struct ast_config *localized_config_load(
const char *filename)
3294 result = ast_config_internal_load(filename, cfg, 0,
"");
3301 struct ast_config *localized_config_load_with_comments(
const char *filename);
3303 struct ast_config *localized_config_load_with_comments(
const char *filename)
3312 result = ast_config_internal_load(filename, cfg, 1,
"");
3332 else if (!prev && config->
root)
3335 for (cat = config->
root; cat; cat = cat->
next) {
3336 if (cat->name == prev) {
3342 for (cat = config->
root; cat; cat = cat->
next) {
3343 if (!strcasecmp(cat->name, prev)) {
3352 cat = next_available_category(cat);
3355 return (cat) ? cat->name : NULL;
3388 static void gen_header(FILE *f1,
const char *configfile,
const char *fn,
const char *generator)
3395 fprintf(f1,
";!\n");
3396 fprintf(f1,
";! Automatically generated configuration file\n");
3397 if (strcmp(configfile, fn))
3398 fprintf(f1,
";! Filename: %s (%s)\n", configfile, fn);
3400 fprintf(f1,
";! Filename: %s\n", configfile);
3401 fprintf(f1,
";! Generator: %s\n", generator);
3402 fprintf(f1,
";! Creation Date: %s", date);
3403 fprintf(f1,
";!\n");
3406 static void set_fn(
char *fn,
int fn_size,
const char *file,
const char *configfile)
3408 if (!file || file[0] == 0) {
3409 if (configfile[0] ==
'/')
3412 snprintf(fn, fn_size,
"%s/%s", ast_config_AST_CONFIG_DIR, configfile);
3413 }
else if (file[0] ==
'/')
3416 snprintf(fn, fn_size,
"%s/%s", ast_config_AST_CONFIG_DIR, file);
3419 int localized_config_text_file_save(
const char *configfile,
const struct ast_config *cfg,
const char *generator);
3421 int localized_config_text_file_save(
const char *configfile,
const struct ast_config *cfg,
const char *generator)
3447 gen_header(f1, configfile, fn, generator);
3450 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn, strerror(errno));
3455 set_fn(fn,
sizeof(fn), 0, configfile);
3457 if ((f = fopen(fn,
"w+"))) {
3459 if ((f = fopen(fn,
"w"))) {
3461 if (option_verbose > 1)
3462 ast_verbose(VERBOSE_PREFIX_2
"Saving '%s': ", fn);
3464 gen_header(f, configfile, fn, generator);
3473 set_fn(fn,
sizeof(fn), cat->
file, configfile);
3477 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn, strerror(errno));
3486 fprintf(f,
"#exec \"%s\"\n", incl->
exec_file);
3495 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
3496 if (cmt->
cmt[0] !=
';' || cmt->
cmt[1] !=
'!')
3497 fprintf(f,
"%s", cmt->
cmt);
3499 if (!cat->precomments)
3501 fprintf(f,
"[%s]", cat->name);
3502 for(cmt = cat->sameline; cmt; cmt=cmt->next) {
3503 fprintf(f,
"%s", cmt->
cmt);
3511 set_fn(fn,
sizeof(fn), var->
file, configfile);
3515 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn, strerror(errno));
3524 fprintf(f,
"#exec \"%s\"\n", incl->
exec_file);
3532 for (cmt = var->precomments; cmt; cmt=cmt->next) {
3533 if (cmt->
cmt[0] !=
';' || cmt->
cmt[1] !=
'!')
3534 fprintf(f,
"%s", cmt->
cmt);
3537 fprintf(f,
"%s %s %s %s", var->
name, (var->
object ?
"=>" :
"="), var->
value, var->sameline->
cmt);
3539 fprintf(f,
"%s %s %s\n", var->
name, (var->
object ?
"=>" :
"="), var->
value);
3542 while (blanklines--)
3553 if ((option_verbose > 1) && !option_debug)
3554 ast_verbose(
"Saved\n");
3557 ast_log(LOG_DEBUG,
"Unable to open for writing: %s\n", fn);
3558 if (option_verbose > 1)
3559 ast_verbose(VERBOSE_PREFIX_2
"Unable to write (%s)", strerror(errno));
3573 ast_verbose(VERBOSE_PREFIX_2
"Unable to write %s (%s)", fn, strerror(errno));
3579 fprintf(f,
"#exec \"%s\"\n", incl->
exec_file);
3601 #define EXT_DATA_SIZE 256
3603 #define EXT_DATA_SIZE 8192
3610 #define SWITCH_DATA_LENGTH 256
3612 static const char *ast_get_extension_app(
struct ast_exten *e)
3614 return e ? e->
app : NULL;
3617 static const char *ast_get_extension_name(
struct ast_exten *exten)
3619 return exten ? exten->
exten : NULL;
3630 AST_RWLIST_TRAVERSE(&
hints, hint, list) {
3631 if (hint->
exten == oe) {
3651 AST_RWLIST_TRAVERSE(&
hints, hint, list) {
3652 if (hint->
exten == e) {
3653 if (option_debug > 1)
3654 ast_log(LOG_DEBUG,
"HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3659 if (option_debug > 1)
3660 ast_log(LOG_DEBUG,
"HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3662 if (!(hint =
ast_calloc(1,
sizeof(*hint)))) {
3667 AST_RWLIST_INSERT_HEAD(&
hints, hint, list);
3680 for (ep = NULL; e ; ep = e, e = e->
peer) {
3688 if (e->priority == tmp->
priority) {
3692 ast_log(LOG_WARNING,
"Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->
exten, tmp->
priority, con->
name);
3743 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&
hints, hint, list) {
3744 if (hint->
exten == e) {
3750 cblist = cblist->next;
3754 AST_RWLIST_REMOVE_CURRENT(&
hints, list);
3760 AST_RWLIST_TRAVERSE_SAFE_END
3765 static void destroy_exten(
struct ast_exten *e)
3809 int j, num_fields, last_sep = -1;
3814 if (ast_strlen_zero(info_in)) {
3822 for (j = 0, num_fields = 1; info[j] !=
'\0'; j++) {
3823 if (info[j] ==
'|' || info[j] ==
',') {
3830 if (num_fields == 5) {
3875 int c, cmin = 0xff, count = 0;
3881 while ( (c = *(*p)++) && (c ==
' ' || c ==
'-') )
3887 return 0x0000 | (c & 0xff);
3890 return 0x0700 |
'2' ;
3893 return 0x0900 |
'0';
3896 return 0x0800 |
'1';
3912 end = strchr(*p,
']');
3915 ast_log(LOG_WARNING,
"Wrong usage of [] in the extension\n");
3919 memset(chars,
'\0',
sizeof(chars));
3920 for (; *p < end ; (*p)++) {
3921 unsigned char c1, c2;
3922 c1 = (
unsigned char)((*p)[0]);
3923 if (*p + 2 < end && (*p)[1] ==
'-') {
3924 c2 = (
unsigned char)((*p)[2]);
3930 for (; c1 <= c2; c1++) {
3931 uint32_t mask = 1 << (c1 % 32);
3932 if ( (chars[ c1 / 32 ] & mask) == 0)
3934 chars[ c1 / 32 ] |= mask;
3938 return count == 0 ? 0x30000 : (count | cmin);
3953 return (b[0] ==
'_') ? -1 : strcmp(a, b);
3959 return strcmp(a, b);
3962 while (!ret && a && b)
3967 return (ret > 0) ? 1 : -1;
3975 while (*src && (count < len - 1)) {
4012 AST_RWLIST_TRAVERSE(&
switches, asw, list) {
4013 if (!strcasecmp(asw->
name, sw))
4026 return con ? con->
next : contexts;
4032 return ast_walk_contexts(con);
4044 return con ? con->
root : NULL;
4054 return ast_walk_context_extensions(con,exten);
4064 return priority ? priority->
peer :
exten;
4072 return ast_walk_extension_priorities(exten, priority);
4089 int ast_context_includes_count(
struct ast_context *con);
4090 int ast_context_includes_count(
struct ast_context *con)
4095 while ((inc = ast_walk_context_includes(con, inc))) {
4107 return ast_walk_context_includes(con, inc);
4122 int ast_context_ignorepats_count(
struct ast_context *con);
4123 int ast_context_ignorepats_count(
struct ast_context *con)
4128 while ((ip = ast_walk_context_ignorepats(con, ip))) {
4153 return ast_walk_context_switches(con, sw);
4156 int ast_context_switches_count(
struct ast_context *con);
4157 int ast_context_switches_count(
struct ast_context *con)
4160 struct ast_sw *sw = NULL;
4162 while ((sw = ast_walk_context_switches(con, sw))) {
4175 while ( (tmp = ast_walk_contexts(tmp)) ) {
4176 if (!name || !strcasecmp(name, tmp->
name))
4191 static int _extension_match_core(
const char *pattern,
const char *data,
enum ext_match_t mode)
4193 mode &= E_MATCH_MASK;
4195 if ( (mode == E_MATCH) && (pattern[0] ==
'_') && (strcasecmp(pattern,data)==0) )
4198 if (pattern[0] !=
'_') {
4199 int ld = strlen(data), lp = strlen(pattern);
4204 if (mode == E_MATCH)
4205 return !strcmp(pattern, data);
4206 if (ld == 0 || !strncasecmp(pattern, data, ld))
4207 return (mode == E_MATCHMORE) ? lp > ld : 1;
4216 while (*data && *pattern && *pattern !=
'/') {
4223 switch (toupper(*pattern)) {
4225 end = strchr(pattern+1,
']');
4227 ast_log(LOG_WARNING,
"Wrong usage of [] in the extension\n");
4230 for (pattern++; pattern != end; pattern++) {
4231 if (pattern+2 < end && pattern[1] ==
'-') {
4232 if (*data >= pattern[0] && *data <= pattern[2])
4238 }
else if (*data == pattern[0])
4246 if (*data < '2' || *data >
'9')
4250 if (*data < '0' || *data >
'9')
4254 if (*data < '1' || *data >
'9')
4266 if (*data != *pattern)
4278 if (*pattern ==
'\0' || *pattern ==
'/')
4279 return (mode == E_MATCHMORE) ? 0 : 1;
4280 else if (*pattern ==
'!')
4283 return (mode == E_MATCH) ? 0 : 1;
4286 static int extension_match_core(
const char *pattern,
const char *data,
enum ext_match_t mode)
4289 i = _extension_match_core(pattern, data, mode);
4297 return extension_match_core(pattern, data, E_MATCH);
4300 static int matchcid(
const char *cidpattern,
const char *callerid)
4305 if (ast_strlen_zero(callerid))
4306 return ast_strlen_zero(cidpattern) ? 1 : 0;
4311 static inline int include_valid(
struct ast_include *i)
4324 const char *context,
4328 const char *callerid,
4335 const char *context,
4339 const char *callerid,
4352 if (q->stacklen == 0) {
4353 q->status = STATUS_NO_CONTEXT;
4356 q->foundcontext = NULL;
4357 }
else if (q->stacklen >= AST_PBX_MAX_STACK) {
4358 ast_log(LOG_WARNING,
"Maximum PBX stack exceeded\n");
4362 for (x = 0; x < q->stacklen; x++) {
4363 if (!strcasecmp(q->incstack[x], context))
4370 while ((tmp = ast_walk_contexts(tmp)) ) {
4371 if (!strcmp(tmp->
name, context))
4377 if (q->status < STATUS_NO_EXTENSION)
4378 q->status = STATUS_NO_EXTENSION;
4382 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
4383 int match = extension_match_core(eroot->
exten, exten, action);
4388 if (match == 2 && action == E_MATCHMORE) {
4395 if (q->status < STATUS_NO_PRIORITY)
4396 q->status = STATUS_NO_PRIORITY;
4398 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
4400 if (action == E_FINDLABEL) {
4401 if (q->status < STATUS_NO_LABEL)
4402 q->status = STATUS_NO_LABEL;
4403 if (label && e->
label && !strcmp(label, e->
label))
4405 }
else if (e->
priority == priority) {
4410 q->status = STATUS_SUCCESS;
4411 q->foundcontext = context;
4415 #ifdef NOT_RIGHT_NOW
4423 ast_log(LOG_WARNING,
"No such switch '%s'\n", sw->name);
4429 if (action == E_CANMATCH)
4430 aswf = asw->canmatch;
4431 else if (action == E_MATCHMORE)
4432 aswf = asw->matchmore;
4435 datap = sw->eval ? sw->tmpdata : sw->
data;
4436 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
4440 q->foundcontext = context;
4446 q->incstack[q->stacklen++] = tmp->
name;
4449 if (include_valid(i)) {
4450 if ((e = pbx_find_extension(NULL, bypass, q, i->
rname, exten, priority, label, callerid, action)))
4461 const char *context,
4465 const char *callerid,
4470 const char *context,
4474 const char *callerid,
4477 return pbx_find_extension(NULL, bypass, q, context, exten, priority, label, callerid, action);
4484 static const char *ast_get_context_name(
struct ast_context *con);
4486 static const char *ast_get_context_name(
struct ast_context *con)
4488 return con ? con->
name : NULL;
4499 const char *registrar);
4502 const char *registrar)
4511 length += 2 * (strlen(value) + 1);
4519 p = new_include->stuff;
4520 new_include->name = p;
4522 p += strlen(value) + 1;
4523 new_include->
rname = p;
4526 if ( (c = strchr(p,
'|')) || (c = strchr(p,
',')) ) {
4530 new_include->
next = NULL;
4536 if (!strcasecmp(i->name, new_include->name)) {
4546 il->
next = new_include;
4549 if (option_verbose > 2)
4550 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
4555 int localized_context_add_include2(
struct ast_context *con,
const char *value,
4556 const char *registrar);
4557 int localized_context_add_include2(
struct ast_context *con,
const char *value,
4558 const char *registrar)
4565 static int ast_context_add_ignorepat2(
struct ast_context *con,
const char *value,
const char *registrar);
4567 static int ast_context_add_ignorepat2(
struct ast_context *con,
const char *value,
const char *registrar)
4569 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
4572 length += strlen(value) + 1;
4578 strcpy((
char *)ignorepat->pattern, value);
4579 ignorepat->next = NULL;
4580 ignorepat->registrar = registrar;
4581 for (ignorepatc = con->
ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
4582 ignorepatl = ignorepatc;
4583 if (!strcasecmp(ignorepatc->pattern, value)) {
4590 ignorepatl->next = ignorepat;
4597 int localized_context_add_ignorepat2(
struct ast_context *con,
const char *value,
const char *registrar);
4599 int localized_context_add_ignorepat2(
struct ast_context *con,
const char *value,
const char *registrar)
4601 return ast_context_add_ignorepat2(con, value, registrar);
4611 return ast_rwlock_wrlock(&
conlock);
4616 return ast_rwlock_unlock(&
conlock);
4621 return ast_rwlock_wrlock(&con->
lock);
4626 return ast_rwlock_unlock(&con->
lock);
4637 const char *data,
int eval,
const char *registrar);
4640 const char *data,
int eval,
const char *registrar)
4647 length =
sizeof(
struct ast_sw);
4648 length += strlen(value) + 1;
4650 length += strlen(data);
4654 length += SWITCH_DATA_LENGTH;
4664 strcpy(new_sw->name, value);
4665 p += strlen(value) + 1;
4668 strcpy(new_sw->
data, data);
4669 p += strlen(data) + 1;
4671 strcpy(new_sw->
data,
"");
4675 new_sw->tmpdata = p;
4676 new_sw->eval = eval;
4681 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->
data, new_sw->
data)) {
4691 if (option_verbose > 2)
4692 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->
data, ast_get_context_name(con));
4697 int localized_context_add_switch2(
struct ast_context *con,
const char *value,
4698 const char *data,
int eval,
const char *registrar);
4700 int localized_context_add_switch2(
struct ast_context *con,
const char *value,
4701 const char *data,
int eval,
const char *registrar)
4706 static struct ast_context *__ast_context_create(
struct ast_context **extcontexts,
const char *name,
const char *registrar,
int existsokay)
4709 int length =
sizeof(
struct ast_context) + strlen(name) + 1;
4713 loc_contexts = &contexts;
4715 loc_contexts = extcontexts;
4717 for (tmp = *loc_contexts; tmp; tmp = tmp->
next) {
4718 if (!strcasecmp(tmp->
name, name)) {
4720 ast_log(LOG_WARNING,
"Tried to register context '%s', already in use\n", name);
4730 strcpy(tmp->
name, name);
4733 tmp->
next = *loc_contexts;
4736 *loc_contexts = tmp;
4738 ast_log(LOG_DEBUG,
"Registered context '%s'\n", tmp->
name);
4739 if (option_verbose > 2)
4740 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp->
name);
4774 int replace,
const char *
extension,
int priority,
const char *label,
const char *callerid,
4775 const char *application,
void *data,
void (*datad)(
void *),
4776 const char *registrar)
4794 length += strlen(extension) + 1;
4795 length += strlen(application) + 1;
4797 length += strlen(label) + 1;
4799 length += strlen(callerid) + 1;
4814 p += strlen(label) + 1;
4817 p +=
ext_strncpy(p, extension, strlen(extension) + 1) + 1;
4821 p +=
ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
4828 strcpy(p, application);
4835 for (e = con->
root; e; el = e, e = e->
next) {
4850 if (e && res == 0) {
4851 res =
add_pri(con, tmp, el, e, replace);
4871 ast_log(LOG_DEBUG,
"Added extension '%s' priority %d (CID match '%s') to %s\n",
4874 ast_log(LOG_DEBUG,
"Added extension '%s' priority %d to %s\n",
4878 if (option_verbose > 2) {
4880 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
4883 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
4890 int localized_add_extension2(
struct ast_context *con,
4891 int replace,
const char *extension,
int priority,
const char *label,
const char *callerid,
4892 const char *application,
void *data,
void (*
datad)(
void *),
4893 const char *registrar);
4895 int localized_add_extension2(
struct ast_context *con,
4896 int replace,
const char *extension,
int priority,
const char *label,
const char *callerid,
4897 const char *application,
void *data,
void (*
datad)(
void *),
4898 const char *registrar)
4900 return ast_add_extension2(con, replace, extension, priority, label, callerid, application, data,
datad, registrar);
4915 const char *context,
const char *exten,
int priority,
4916 const char *label,
const char *callerid,
enum ext_match_t action)
4922 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
4924 e = pbx_find_extension(NULL, con, &q, context, exten, priority, label, callerid, action);
4926 if (matching_action) {
4928 }
else if (action == E_FINDLABEL) {
4937 if (matching_action)
4941 ast_log(LOG_WARNING,
"No execution engine for switch %s\n", q.swo->
name);
4944 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
4948 case STATUS_NO_CONTEXT:
4949 if (!matching_action)
4950 ast_log(LOG_NOTICE,
"Cannot find extension context '%s'\n", context);
4952 case STATUS_NO_EXTENSION:
4953 if (!matching_action)
4954 ast_log(LOG_NOTICE,
"Cannot find extension '%s' in context '%s'\n", exten, context);
4956 case STATUS_NO_PRIORITY:
4957 if (!matching_action)
4958 ast_log(LOG_NOTICE,
"No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
4960 case STATUS_NO_LABEL:
4962 ast_log(LOG_NOTICE,
"No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
4966 ast_log(LOG_DEBUG,
"Shouldn't happen!\n");
4969 return (matching_action) ? 0 : -1;
4982 return __ast_context_create(extcontexts, name, registrar, 1);
4988 return __ast_context_create(extcontexts, name, registrar, 1);
4995 ast_log(LOG_ERROR,
"Function %s not registered\n",
function);
5010 for (; *var; var++) {
5014 }
else if (*var ==
')') {
5016 }
else if (*var ==
':' && parens == 0) {
5018 sscanf(var,
"%30d:%30d", offset, length);
5025 static const char *ast_var_value(
const struct ast_var_t *var)
5027 return (var ? var->value : NULL);
5038 static char *
substring(
const char *value,
int offset,
int length,
char *workspace,
size_t workspace_len)
5040 char *ret = workspace;
5048 if (offset == 0 && length >= lr)
5052 offset = lr + offset;
5062 if (length >= 0 && length < lr - offset)
5064 else if (length < 0) {
5065 if (lr > offset - length)
5066 ret[lr + length - offset] =
'\0';
5081 const char not_found =
'\0';
5085 int i, need_substring;
5086 struct varshead *places[2] = { headp, &globals };
5112 if (s == ¬_found) {
5113 if (!strcmp(var,
"EPOCH")) {
5114 snprintf(workspace, workspacelen,
"%u",(
int)time(NULL));
5120 for (i = 0; s == ¬_found && i < (
sizeof(places) /
sizeof(places[0])); i++) {
5124 if (places[i] == &globals)
5125 ast_rwlock_rdlock(&globalslock);
5127 if (strcasecmp(ast_var_name(variables), var)==0) {
5128 s = ast_var_value(variables);
5132 if (places[i] == &globals)
5133 ast_rwlock_unlock(&globalslock);
5135 if (s == ¬_found || s == NULL)
5142 *ret =
substring(*ret, offset, length, workspace, workspacelen);
5146 static void pbx_substitute_variables_helper_full(
struct ast_channel *c,
struct varshead *headp,
const char *cp1,
char *cp2,
int count)
5151 const char *tmp, *whereweare;
5152 int length, offset, offset2, isfunction;
5153 char *workspace = NULL;
5154 char *ltmp = NULL, *var = NULL;
5155 char *nextvar, *nextexp, *nextthing;
5157 int pos, brackets, needsub, len;
5161 while (!ast_strlen_zero(whereweare) && count) {
5163 pos = strlen(whereweare);
5166 nextthing = strchr(whereweare,
'$');
5168 switch (nextthing[1]) {
5170 nextvar = nextthing;
5171 pos = nextvar - whereweare;
5174 nextexp = nextthing;
5175 pos = nextexp - whereweare;
5186 memcpy(cp2, whereweare, pos);
5198 vars = vare = nextvar + 2;
5203 while (brackets && *vare) {
5204 if ((vare[0] ==
'$') && (vare[1] ==
'{')) {
5206 }
else if (vare[0] ==
'{') {
5208 }
else if (vare[0] ==
'}') {
5210 }
else if ((vare[0] ==
'$') && (vare[1] ==
'['))
5215 ast_log(LOG_NOTICE,
"Error in extension logic (missing '}' in '%s')\n", cp1);
5216 len = vare - vars - 1;
5219 whereweare += (len + 3);
5222 var = alloca(VAR_BUF_SIZE);
5230 ltmp = alloca(VAR_BUF_SIZE);
5232 memset(ltmp, 0, VAR_BUF_SIZE);
5233 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
5240 workspace = alloca(VAR_BUF_SIZE);
5242 workspace[0] =
'\0';
5247 cp4 =
ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
5249 ast_log(LOG_DEBUG,
"Function result is '%s'\n", cp4 ? cp4 :
"(null)");
5255 cp4 =
substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
5257 length = strlen(cp4);
5260 memcpy(cp2, cp4, length);
5265 }
else if (nextexp) {
5269 vars = vare = nextexp + 2;
5274 while (brackets && *vare) {
5275 if ((vare[0] ==
'$') && (vare[1] ==
'[')) {
5279 }
else if (vare[0] ==
'[') {
5281 }
else if (vare[0] ==
']') {
5283 }
else if ((vare[0] ==
'$') && (vare[1] ==
'{')) {
5290 ast_log(LOG_NOTICE,
"Error in extension logic (missing ']')\n");
5291 len = vare - vars - 1;
5294 whereweare += (len + 3);
5297 var = alloca(VAR_BUF_SIZE);
5305 ltmp = alloca(VAR_BUF_SIZE);
5307 memset(ltmp, 0, VAR_BUF_SIZE);
5308 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
5314 length =
ast_expr(vars, cp2, count, NULL);
5318 ast_log(LOG_DEBUG,
"Expression result is '%s'\n", cp2);
5328 static void pbx_substitute_variables_helper(
struct ast_channel *c,
const char *cp1,
char *cp2,
int count)
5330 pbx_substitute_variables_helper_full(c, NULL, cp1, cp2, count);
5334 static int pbx_load_config(
const char *
config_file);
5336 static int pbx_load_config(
const char *
config_file)
5341 char realvalue[256];
5348 cfg = localized_config_load(config_file);
5353 static_config =
ast_true(ast_variable_retrieve(cfg,
"general",
"static"));
5354 write_protect_config =
ast_true(ast_variable_retrieve(cfg,
"general",
"writeprotect"));
5355 if ((aft = ast_variable_retrieve(cfg,
"general",
"autofallthrough")))
5356 autofallthrough_config =
ast_true(aft);
5357 clearglobalvars_config =
ast_true(ast_variable_retrieve(cfg,
"general",
"clearglobalvars"));
5359 if ((cxt = ast_variable_retrieve(cfg,
"general",
"userscontext")))
5364 for (v = ast_variable_browse(cfg,
"globals"); v; v = v->
next) {
5365 memset(realvalue, 0,
sizeof(realvalue));
5366 pbx_substitute_variables_helper(NULL, v->
value, realvalue,
sizeof(realvalue) - 1);
5371 if (!strcasecmp(cxt,
"general") || !strcasecmp(cxt,
"globals"))
5377 for (v = ast_variable_browse(cfg, cxt); v; v = v->
next) {
5378 if (!strcasecmp(v->
name,
"exten")) {
5382 char realext[256]=
"";
5383 char *plus, *firstp, *firstc;
5384 char *pri, *appl, *data, *cidmatch;
5386 char *ext = strsep(&stringp,
",");
5389 pbx_substitute_variables_helper(NULL, ext, realext,
sizeof(realext) - 1);
5390 cidmatch = strchr(realext,
'/');
5395 pri = strsep(&stringp,
",");
5398 label = strchr(pri,
'(');
5401 end = strchr(label,
')');
5405 ast_log(LOG_WARNING,
"Label missing trailing ')' at line %d\n", v->lineno);
5407 plus = strchr(pri,
'+');
5410 if (!strcmp(pri,
"hint"))
5412 else if (!strcmp(pri,
"next") || !strcmp(pri,
"n")) {
5416 ast_log(LOG_WARNING,
"Can't use 'next' priority on the first entry!\n");
5417 }
else if (!strcmp(pri,
"same") || !strcmp(pri,
"s")) {
5421 ast_log(LOG_WARNING,
"Can't use 'same' priority on the first entry!\n");
5422 }
else if (sscanf(pri,
"%30d", &ipri) != 1 &&
5424 ast_log(LOG_WARNING,
"Invalid priority/label '%s' at line %d\n", pri, v->lineno);
5427 appl =
S_OR(stringp,
"");
5429 firstc = strchr(appl,
',');
5430 firstp = strchr(appl,
'(');
5431 if (firstc && (!firstp || firstc < firstp)) {
5434 appl = strsep(&stringp,
",");
5436 }
else if (!firstc && !firstp) {
5441 appl = strsep(&stringp,
"(");
5443 end = strrchr(data,
')');
5444 if ((end = strrchr(data,
')'))) {
5447 ast_log(LOG_WARNING,
"No closing parenthesis found? '%s(%s'\n", appl, data);
5459 if (!ast_opt_dont_warn && !strcmp(realext,
"_."))
5460 ast_log(LOG_WARNING,
"The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno);
5462 ast_log(LOG_WARNING,
"Unable to register extension at line %d\n", v->lineno);
5467 }
else if (!strcasecmp(v->
name,
"include")) {
5468 memset(realvalue, 0,
sizeof(realvalue));
5469 pbx_substitute_variables_helper(NULL, v->
value, realvalue,
sizeof(realvalue) - 1);
5471 ast_log(LOG_WARNING,
"Unable to include context '%s' in context '%s'\n", v->
value, cxt);
5472 }
else if (!strcasecmp(v->
name,
"ignorepat")) {
5473 memset(realvalue, 0,
sizeof(realvalue));
5474 pbx_substitute_variables_helper(NULL, v->
value, realvalue,
sizeof(realvalue) - 1);
5475 if (ast_context_add_ignorepat2(con, realvalue, global_registrar))
5476 ast_log(LOG_WARNING,
"Unable to include ignorepat '%s' in context '%s'\n", v->
value, cxt);
5477 }
else if (!strcasecmp(v->
name,
"switch") || !strcasecmp(v->
name,
"lswitch") || !strcasecmp(v->
name,
"eswitch")) {
5478 char *stringp= realvalue;
5481 memset(realvalue, 0,
sizeof(realvalue));
5482 if (!strcasecmp(v->
name,
"switch"))
5483 pbx_substitute_variables_helper(NULL, v->
value, realvalue,
sizeof(realvalue) - 1);
5486 appl = strsep(&stringp,
"/");
5487 data = strsep(&stringp,
"");
5491 ast_log(LOG_WARNING,
"Unable to include switch '%s' in context '%s'\n", v->
value, cxt);
5493 ast_log(LOG_WARNING,
"==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->
name, v->lineno);
5501 static void __ast_context_destroy(
struct ast_context *con,
const char *registrar)
5509 for (tmp = contexts; tmp; ) {
5511 for (; tmp; tmpl = tmp, tmp = tmp->
next) {
5513 ast_log(LOG_DEBUG,
"check ctx %s %s\n", tmp->name, tmp->registrar);
5514 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
5515 (!con || !strcasecmp(tmp->name, con->
name)) )
5522 ast_log(LOG_DEBUG,
"delete ctx %s %s\n", tmp->name, tmp->registrar);
5531 for (tmpi = tmp->includes; tmpi; ) {
5536 for (ipi = tmp->ignorepats; ipi; ) {
5543 for (e = tmp->root; e;) {
5544 for (en = e->
peer; en;) {
5553 ast_rwlock_destroy(&tmp->lock);
5556 tmp = con ? NULL : next;
5560 void localized_context_destroy(
struct ast_context *con,
const char *registrar);
5562 void localized_context_destroy(
struct ast_context *con,
const char *registrar)
5565 __ast_context_destroy(con,registrar);
5588 ast_log(LOG_DEBUG,
"must remove any reg %s\n", registrar);
5589 __ast_context_destroy(NULL,registrar);
5597 ast_log(LOG_WARNING,
"must remove %s reg %s\n", tmp->
name, tmp->
registrar);
5598 __ast_context_destroy(tmp,tmp->
registrar);
5604 lasttmp->
next = contexts;
5605 contexts = *extcontexts;
5606 *extcontexts = NULL;
5608 ast_log(LOG_WARNING,
"Requested contexts didn't get merged\n");
5625 while ( (inc = ast_walk_context_includes(con, inc)) )
5628 if (strcasecmp(inc->
rname,
"parkedcalls")!=0)
5629 ast_log(LOG_WARNING,
"Context '%s' tries to include the nonexistent context '%s'\n",
5630 ast_get_context_name(con), inc->
rname);
5635 int localized_context_verify_includes(
struct ast_context *con);
5637 int localized_context_verify_includes(
struct ast_context *con)
5642 int localized_pbx_load_module(
void);
5644 int localized_pbx_load_module(
void)
5648 if(!pbx_load_config(config_filename))
5655 for (con = NULL; (con = ast_walk_contexts(con));)
5658 printf(
"=== Loading extensions.conf ===\n");
5660 while ((con = ast_walk_contexts(con)) ) {
5661 printf(
"Context: %s\n", con->
name);
5663 printf(
"=========\n");
5674 gettimeofday(&t, NULL);
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
ast_include: include= support in extensions.conf
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
struct ast_variable * next
struct ast_category * next
int ast_unlock_context(struct ast_context *con)
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Support for Asterisk built-in variables in the dialplan.
Main Channel structure associated with a channel.
ast_extension_states
Extension states.
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
#define ast_realloc(p, len)
A wrapper for realloc()
struct ast_include * next
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
char * file
The file name from whence this declaration was read.
static char * substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
takes a substring. It is ok to call with value == workspace.
struct ast_include * includes
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
static int lookup_name(const char *s, char *const names[], int max)
Helper for get_range. return the index of the matching entry, starting from 1. If names is not suppli...
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
char * include_location_file
file name in which the include occurs
Time-related functions and macros.
char context[AST_MAX_CONTEXT]
struct ast_config_include * includes
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
int ast_build_timing(struct ast_timing *i, const char *info_in)
Construct a timing bitmap, for use in time-based conditionals.
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
The return value depends on the action:
struct ast_ignorepat * ignorepats
ast_state_cb: An extension state notify register item
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
Structure for variables, used for configurations and for channel variables.
int ast_context_add_switch2(struct ast_context *con, const char *sw, const char *data, int eval, const char *registrar)
Adds a switch (first param is a ast_context)
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
static int ast_remove_hint(struct ast_exten *e)
ast_remove_hint: Remove hint from extension
static int comment_buffer_size
struct ast_category * prev
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
static int ext_cmp1(const char **p)
helper functions to sort extensions and patterns in the desired way, so that more specific patterns a...
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int ast_wrlock_contexts(void)
Write locks the context list.
double ast_option_maxload
#define ast_strdup(str)
A wrapper for strdup()
char * ast_process_quotes_and_slashes(char *start, char find, char replace_with)
Process a string to find and replace characters.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
static unsigned get_range(char *src, int max, char *const names[], const char *msg)
helper function to return a range up to max (7, 12, 31 respectively). names, if supplied, is an array of names that should be mapped to numbers.
char * exec_file
if it's an exec, you'll have both the /var/tmp to read, and the original script
void ast_free_ptr(void *ptr)
free() wrapper
static ast_rwlock_t conlock
static void ast_shrink_phone_number(char *n)
Clean up phone string remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets...
Configuration engine structure, used to define realtime drivers.
struct ast_context * next
static int add_pri(struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace)
add the extension in the priority chain. returns 0 on success, -1 on failure
int ast_check_timing(const struct ast_timing *i)
Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified...
All configuration options for http media cache.
struct ast_category * last
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
static char * lline_buffer
static const char config_file[]
void localized_merge_contexts_and_delete(struct ast_context **extcontexts, void *tab, const char *registrar)
static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, struct ast_flags flags, struct ast_str *comment_buffer, struct ast_str *lline_buffer, const char *suggested_include_file, struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
parse one line in the configuration.
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
struct ast_context * ast_context_find(const char *name)
Find a context.
ast_sw: Switch statement in extensions.conf
Asterisk file paths, configured in asterisk.conf.
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
Set the category within the configuration as being current.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Inlinable API function macro.
Data structure associated with a custom dialplan function.
Asterisk architecture endianess compatibility definitions.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
struct ast_switch * pbx_findswitch(const char *sw)
char * included_file
file name included
structure to hold extensions
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
static int ast_add_hint(struct ast_exten *e)
ast_add_hint: Add hint to hint list, check initial extension state
static void _null_sig_handler(int sig)
NULL handler so we can collect the child exit status.
#define ast_malloc(len)
A wrapper for malloc()
struct ast_variable * root
char stuff[0]
Contents of file, name, and value in that order stuffed here.
int ast_language_is_prefix
The following variable controls the layout of localized sound files. If 0, use the historical layout ...
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
External configuration handlers (realtime and static configuration)
static char * comment_buffer
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
struct ast_category * last_browse
static void get_timerange(struct ast_timing *i, char *times)
store a bitmask of valid times, one bit each 2 minute
struct ast_exten * exten
Hint extension.
int( ast_switch_f)(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
All switch functions have the same interface, so define a type for them.
struct ast_ignorepats ignorepats
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
ast_ignorepat: Ignore patterns in dial plan
int ast_unlock_contexts(void)
Unlocks contexts.
static unsigned int safe_system_level
Keep track of how many threads are currently trying to wait*() on a child process.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Structure for dial plan hints.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
extract offset:length from variable name. Returns 1 if there is a offset:length part, which is trimmed off (values go into variables)
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
General Definitions for Asterisk top level program Included by asterisk.h to handle platform-specific...
int include_location_lineno
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define ast_calloc(num, len)
A wrapper for calloc()
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Structures for AEL - the Asterisk extension language.
void ast_console_puts(const char *string)
write the string to the root console, and all attached network console clients
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
ast_change_hint: Change hint for an extension
int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
Parse and set a single channel variable, where the name and value are separated with an '=' character...
static struct ast_config * config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
#define AST_DEFAULT_OPTIONS
Structure used to handle boolean flags.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
struct ast_includes includes
static int ext_strncpy(char *dst, const char *src, int len)
copy a string skipping whitespace
static int ext_cmp(const char *a, const char *b)
the full routine to compare extensions in rules.
#define AST_MAX_EXTENSION
struct ast_variable * last
struct ast_context * localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
Structure for rwlock and tracking information.
struct ast_config_include * next
static struct ast_config_engine * find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
Find realtime engine for realtime family.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
ast_app: A registered application
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
struct ast_context * parent
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
struct ast_category * root
int(* ast_state_cb_type)(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Typedef for devicestate and hint callbacks.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
struct ast_state_cb * callbacks
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
ast_context: An extension context
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
struct ao2_container * callbacks
static int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Main interface to add extensions to the list for out context.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
char exten[AST_MAX_EXTENSION]
Structure for mutex and tracking information.
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0. Useful e.g. to check if a refcount h...