2006-04-24 17:41:27 +00:00
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
2006-05-20 00:41:36 +00:00
#include <stdarg.h>
2006-04-24 17:41:27 +00:00
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <limits.h>
2006-05-01 19:23:43 +00:00
2006-04-27 00:05:05 +00:00
#include "asterisk/ast_expr.h"
2006-08-21 02:11:39 +00:00
#include "asterisk/channel.h"
2006-04-27 00:05:05 +00:00
#include "asterisk/module.h"
2006-08-21 02:11:39 +00:00
#include "asterisk/app.h"
2006-04-24 17:41:27 +00:00
#include "asterisk/ael_structs.h"
2006-05-01 19:23:43 +00:00
2006-08-09 01:17:47 +00:00
struct namelist
{
char name [ 100 ];
char name2 [ 100 ];
struct namelist * next ;
};
struct ast_context
{
int extension_count ;
char name [ 100 ];
char registrar [ 100 ];
struct namelist * includes ;
struct namelist * ignorepats ;
struct namelist * switches ;
struct namelist * eswitches ;
struct namelist * includes_last ;
struct namelist * ignorepats_last ;
struct namelist * switches_last ;
struct namelist * eswitches_last ;
struct ast_context * next ;
};
#define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
void destroy_namelist ( struct namelist * x );
void destroy_namelist ( struct namelist * x )
{
struct namelist * z , * z2 ;
for ( z = x ; z ; z = z2 )
{
z2 = z -> next ;
z -> next = 0 ;
free ( z );
}
}
struct namelist * create_name ( char * name );
struct namelist * create_name ( char * name )
{
2006-10-24 01:27:42 +00:00
struct namelist * x = calloc ( 1 , sizeof ( * x ));
if ( ! x )
return NULL ;
strncpy ( x -> name , name , sizeof ( x -> name ) - 1 );
2006-08-09 01:17:47 +00:00
return x ;
}
struct ast_context * context_list ;
struct ast_context * last_context ;
struct namelist * globalvars ;
struct namelist * globalvars_last ;
2006-04-24 17:41:27 +00:00
int conts = 0 , extens = 0 , priors = 0 ;
char last_exten [ 18000 ];
2006-06-10 04:34:48 +00:00
char ast_config_AST_CONFIG_DIR [ PATH_MAX ];
char ast_config_AST_VAR_DIR [ PATH_MAX ];
2006-04-24 17:41:27 +00:00
2006-05-20 00:41:36 +00:00
void ast_add_profile ( void );
2006-04-24 17:41:27 +00:00
void ast_cli_register_multiple ( void );
void ast_register_file_version ( void );
void ast_unregister_file_version ( void );
2006-08-09 01:17:47 +00:00
int ast_add_extension2 ( struct ast_context * con ,
2006-04-24 17:41:27 +00:00
int replace , const char * extension , int priority , const char * label , const char * callerid ,
const char * application , void * data , void ( * datad )( void * ),
const char * registrar );
void pbx_builtin_setvar ( void * chan , void * data );
2006-08-09 01:17:47 +00:00
struct ast_context * ast_context_create ( void ** extcontexts , const char * name , const char * registrar );
void ast_context_add_ignorepat2 ( struct ast_context * con , const char * value , const char * registrar );
void ast_context_add_include2 ( struct ast_context * con , const char * value , const char * registrar );
void ast_context_add_switch2 ( struct ast_context * con , const char * value , const char * data , int eval , const char * registrar );
2006-04-24 17:41:27 +00:00
void ast_merge_contexts_and_delete ( void );
void ast_context_verify_includes ( void );
struct ast_context * ast_walk_contexts ( void );
void ast_cli_unregister_multiple ( void );
void ast_context_destroy ( void );
void ast_log ( int level , const char * file , int line , const char * function , const char * fmt , ...);
char * ast_process_quotes_and_slashes ( char * start , char find , char replace_with );
void ast_verbose ( const char * fmt , ...);
struct ast_app * pbx_findapp ( const char * app );
2006-08-09 01:17:47 +00:00
void filter_leading_space_from_exprs ( char * str );
void filter_newlines ( char * str );
2006-08-11 21:30:03 +00:00
static int quiet = 0 ;
2006-04-24 17:41:27 +00:00
static int no_comp = 0 ;
static int use_curr_dir = 0 ;
2006-08-09 01:17:47 +00:00
static int dump_extensions = 0 ;
static int FIRST_TIME = 0 ;
static FILE * dumpfile ;
2006-04-24 17:41:27 +00:00
struct ast_app * pbx_findapp ( const char * app )
{
return ( struct ast_app * ) 1 ; /* so as not to trigger an error */
}
2006-05-20 00:41:36 +00:00
void ast_add_profile ( void )
{
if ( ! no_comp )
printf ( "Executed ast_add_profile(); \n " );
}
2006-08-25 20:43:51 +00:00
int ast_loader_register ( int ( * updater )( void ))
{
return 1 ;
}
int ast_loader_unregister ( int ( * updater )( void ))
{
return 1 ;
}
void ast_module_register ( const struct ast_module_info * x )
{
}
void ast_module_unregister ( const struct ast_module_info * x )
{
}
2006-04-24 17:41:27 +00:00
void ast_cli_register_multiple ( void )
{
if ( ! no_comp )
2006-08-11 21:30:03 +00:00
printf ( "Executed ast_cli_register_multiple(); \n " );
2006-04-24 17:41:27 +00:00
}
void ast_register_file_version ( void )
{
2006-08-11 21:30:03 +00:00
/* if(!no_comp)
printf("Executed ast_register_file_version();\n"); */
/* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
2006-04-24 17:41:27 +00:00
}
void ast_unregister_file_version ( void )
{
2006-08-11 21:30:03 +00:00
/* if(!no_comp)
printf("Executed ast_unregister_file_version();\n"); */
/* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
2006-04-24 17:41:27 +00:00
}
2006-08-09 01:17:47 +00:00
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 )
2006-04-24 17:41:27 +00:00
{
priors ++ ;
2006-08-09 01:17:47 +00:00
con -> extension_count ++ ;
2006-04-24 17:41:27 +00:00
if ( strcmp ( extension , last_exten ) != 0 ) {
extens ++ ;
strcpy ( last_exten , extension );
}
if ( ! label ) {
label = "(null)" ;
}
if ( ! callerid ) {
callerid = "(null)" ;
}
if ( ! application ) {
application = "(null)" ;
}
2006-08-09 01:17:47 +00:00
2006-04-24 17:41:27 +00:00
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_add_extension2(context=%s, rep=%d, exten=%s, priority=%d, label=%s, callerid=%s, appl=%s, data=%s, FREE, registrar=%s); \n " ,
con -> name , replace , extension , priority , label , callerid , application , ( data ? ( char * ) data : "(null)" ), registrar );
if ( dump_extensions && dumpfile ) {
struct namelist * n ;
2007-03-02 05:21:36 +00:00
char * data2 , * data3 = 0 ;
int commacount = 0 ;
2006-08-09 01:17:47 +00:00
if ( FIRST_TIME ) {
FIRST_TIME = 0 ;
if ( globalvars )
fprintf ( dumpfile , "[globals] \n " );
for ( n = globalvars ; n ; n = n -> next ) {
fprintf ( dumpfile , "%s \n " , n -> name );
}
}
/* print out each extension , possibly the context header also */
if ( con != last_context ) {
fprintf ( dumpfile , " \n\n [%s] \n " , con -> name );
last_context = con ;
for ( n = con -> ignorepats ; n ; n = n -> next ) {
fprintf ( dumpfile , "ignorepat => %s \n " , n -> name );
}
for ( n = con -> includes ; n ; n = n -> next ) {
fprintf ( dumpfile , "include => %s \n " , n -> name );
}
for ( n = con -> switches ; n ; n = n -> next ) {
fprintf ( dumpfile , "switch => %s/%s \n " , n -> name , n -> name2 );
}
for ( n = con -> eswitches ; n ; n = n -> next ) {
fprintf ( dumpfile , "eswitch => %s/%s \n " , n -> name , n -> name2 );
}
}
if ( data ) {
filter_newlines (( char * ) data );
filter_leading_space_from_exprs (( char * ) data );
2007-03-02 05:21:36 +00:00
/* compiling turns commas into vertical bars in the app data, and also removes the backslash from before escaped commas;
we have to restore the escaping backslash in front of any commas; the vertical bars are OK to leave as-is */
for ( data2 = data ; * data2 ; data2 ++ ) {
if ( * data2 == ',' )
commacount ++ ; /* we need to know how much bigger the string will grow-- one backslash for each comma */
}
if ( commacount )
{
char * d3 , * d4 ;
data2 = ( char * ) malloc ( strlen ( data ) + commacount + 1 );
data3 = data ;
d3 = data ;
d4 = data2 ;
while ( * d3 ) {
if ( * d3 == ',' ) {
* d4 ++ = '\\' ; /* put a backslash in front of each comma */
* d4 ++ = * d3 ++ ;
} else
* d4 ++ = * d3 ++ ; /* or just copy the char */
}
* d4 ++ = 0 ; /* cap off the new string */
data = data2 ;
} else
data2 = 0 ;
2006-08-09 01:17:47 +00:00
if ( strcmp ( label , "(null)" ) != 0 )
fprintf ( dumpfile , "exten => %s,%d(%s),%s(%s) \n " , extension , priority , label , application , ( char * ) data );
else
fprintf ( dumpfile , "exten => %s,%d,%s(%s) \n " , extension , priority , application , ( char * ) data );
2006-04-24 17:41:27 +00:00
2007-03-02 05:21:36 +00:00
if ( data2 ) {
free ( data2 );
data2 = 0 ;
data = data3 ; /* restore data to pre-messedup state */
}
2006-08-09 01:17:47 +00:00
} else {
if ( strcmp ( label , "(null)" ) != 0 )
fprintf ( dumpfile , "exten => %s,%d(%s),%s \n " , extension , priority , label , application );
else
fprintf ( dumpfile , "exten => %s,%d,%s \n " , extension , priority , application );
}
}
2006-04-24 17:41:27 +00:00
/* since add_extension2 is responsible for the malloc'd data stuff */
if ( data )
free ( data );
return 0 ;
}
void pbx_builtin_setvar ( void * chan , void * data )
{
2006-08-09 01:17:47 +00:00
struct namelist * x = create_name (( char * ) data );
2006-04-24 17:41:27 +00:00
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed pbx_builtin_setvar(chan, data=%s); \n " , ( char * ) data );
if ( dump_extensions ) {
x = create_name (( char * ) data );
ADD_LAST ( globalvars , x );
}
2006-04-24 17:41:27 +00:00
}
2006-08-09 01:17:47 +00:00
struct ast_context * ast_context_create ( void ** extcontexts , const char * name , const char * registrar )
2006-04-24 17:41:27 +00:00
{
2006-10-24 01:27:42 +00:00
struct ast_context * x = calloc ( 1 , sizeof ( * x ));
if ( ! x )
return NULL ;
2006-08-09 01:17:47 +00:00
x -> next = context_list ;
context_list = x ;
2006-10-24 01:27:42 +00:00
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_context_create(conts, name=%s, registrar=%s); \n " , name , registrar );
2006-04-24 17:41:27 +00:00
conts ++ ;
2006-10-24 01:27:42 +00:00
strncpy ( x -> name , name , sizeof ( x -> name ) - 1 );
strncpy ( x -> registrar , registrar , sizeof ( x -> registrar ) - 1 );
2006-08-09 01:17:47 +00:00
return x ;
2006-04-24 17:41:27 +00:00
}
2006-08-09 01:17:47 +00:00
void ast_context_add_ignorepat2 ( struct ast_context * con , const char * value , const char * registrar )
2006-04-24 17:41:27 +00:00
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s); \n " , value , registrar );
if ( dump_extensions ) {
struct namelist * x ;
x = create_name (( char * ) value );
ADD_LAST ( con -> ignorepats , x );
}
2006-04-24 17:41:27 +00:00
}
2006-08-09 01:17:47 +00:00
void ast_context_add_include2 ( struct ast_context * con , const char * value , const char * registrar )
2006-04-24 17:41:27 +00:00
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_context_add_include2(con, value=%s, registrar=%s); \n " , value , registrar );
if ( dump_extensions ) {
struct namelist * x ;
x = create_name (( char * ) value );
ADD_LAST ( con -> includes , x );
}
2006-04-24 17:41:27 +00:00
}
2006-08-09 01:17:47 +00:00
void ast_context_add_switch2 ( struct ast_context * con , const char * value , const char * data , int eval , const char * registrar )
2006-04-24 17:41:27 +00:00
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s); \n " , value , data , eval , registrar );
if ( dump_extensions ) {
struct namelist * x ;
x = create_name (( char * ) value );
strncpy ( x -> name2 , data , 100 );
if ( eval ) {
ADD_LAST ( con -> switches , x );
} else {
ADD_LAST ( con -> eswitches , x );
}
}
2006-04-24 17:41:27 +00:00
}
void ast_merge_contexts_and_delete ( void )
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_merge_contexts_and_delete(); \n " );
2006-04-24 17:41:27 +00:00
}
void ast_context_verify_includes ( void )
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_context_verify_includes(); \n " );
2006-04-24 17:41:27 +00:00
}
struct ast_context * ast_walk_contexts ( void )
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_walk_contexts(); \n " );
2006-04-24 17:41:27 +00:00
return 0 ;
}
void ast_cli_unregister_multiple ( void )
{
if ( ! no_comp )
2006-08-09 01:17:47 +00:00
printf ( "Executed ast_cli_unregister_multiple(); \n " );
2006-04-24 17:41:27 +00:00
}
void ast_context_destroy ( void )
{
2006-08-11 21:30:03 +00:00
if ( ! no_comp )
printf ( "Executed ast_context_destroy(); \n " );
2006-04-24 17:41:27 +00:00
}
void ast_log ( int level , const char * file , int line , const char * function , const char * fmt , ...)
{
va_list vars ;
va_start ( vars , fmt );
2006-08-11 21:30:03 +00:00
if ( ! quiet || level > 2 ) {
printf ( "LOG: lev:%d file:%s line:%d func: %s " ,
2006-04-24 17:41:27 +00:00
level , file , line , function );
2006-08-11 21:30:03 +00:00
vprintf ( fmt , vars );
fflush ( stdout );
va_end ( vars );
}
2006-04-24 17:41:27 +00:00
}
void ast_verbose ( const char * fmt , ...)
{
va_list vars ;
va_start ( vars , fmt );
printf ( "VERBOSE: " );
vprintf ( fmt , vars );
fflush ( stdout );
va_end ( vars );
}
char * ast_process_quotes_and_slashes ( char * start , char find , char replace_with )
{
char * dataPut = start ;
int inEscape = 0 ;
int inQuotes = 0 ;
for (; * start ; start ++ ) {
if ( inEscape ) {
* dataPut ++ = * start ; /* Always goes verbatim */
inEscape = 0 ;
} else {
if ( * start == '\\' ) {
inEscape = 1 ; /* Do not copy \ into the data */
} else if ( * start == '\'' ) {
inQuotes = 1 - inQuotes ; /* Do not copy ' into the data */
} else {
/* Replace , with |, unless in quotes */
* dataPut ++ = inQuotes ? * start : (( * start == find ) ? replace_with : * start );
}
}
}
if ( start != dataPut )
* dataPut = 0 ;
return dataPut ;
}
2006-08-09 01:17:47 +00:00
void filter_leading_space_from_exprs ( char * str )
{
/* Mainly for aesthetics */
char * t , * v , * u = str ;
while ( u && * u ) {
2006-04-24 17:41:27 +00:00
2006-08-09 01:17:47 +00:00
if ( * u == '$' && * ( u + 1 ) == '[' ) {
t = u + 2 ;
while ( * t == '\n' || * t == '\r' || * t == '\t' || * t == ' ' ) {
v = t ;
while ( * v ) {
* v = * ( v + 1 );
v ++ ;
}
}
}
u ++ ;
}
}
void filter_newlines ( char * str )
{
/* remove all newlines, returns */
char * t = str ;
while ( t && * t ) {
if ( * t == '\n' || * t == '\r' ) {
* t = ' ' ; /* just replace newlines and returns with spaces; they act as
token separators, and just blindly removing them could be
harmful. */
}
t ++ ;
}
}
extern struct module_symbols mod_data ;
2006-08-28 15:31:14 +00:00
extern int ael_external_load_module ( void );
2006-04-24 17:41:27 +00:00
int main ( int argc , char ** argv )
{
int i ;
2006-08-09 01:17:47 +00:00
struct namelist * n ;
struct ast_context * lp , * lp2 ;
2006-04-24 17:41:27 +00:00
2006-08-09 01:17:47 +00:00
for ( i = 1 ; i < argc ; i ++ ) {
2006-04-24 17:41:27 +00:00
if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'n' )
no_comp = 1 ;
2006-08-11 21:30:03 +00:00
if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'q' ) {
quiet = 1 ;
no_comp = 1 ;
}
2006-04-24 17:41:27 +00:00
if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'd' )
use_curr_dir = 1 ;
2006-08-09 01:17:47 +00:00
if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'w' )
dump_extensions = 1 ;
2006-04-24 17:41:27 +00:00
}
2006-08-11 21:30:03 +00:00
if ( ! quiet ) {
printf ( " \n (If you find progress and other non-error messages irritating, you can use -q to suppress them) \n " );
if ( ! no_comp )
printf ( " \n (You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler) \n\n " );
if ( ! use_curr_dir )
printf ( " \n (You can use the -d option if you want to use the current working directory as the CONFIG_DIR. I will look in this dir for extensions.ael* and its included files) \n\n " );
if ( ! dump_extensions )
printf ( " \n (You can use the -w option to dump extensions.conf format to extensions.conf.aeldump) \n " );
}
2006-08-09 01:17:47 +00:00
if ( use_curr_dir ) {
2006-04-24 17:41:27 +00:00
strcpy ( ast_config_AST_CONFIG_DIR , "." );
}
2006-08-09 01:17:47 +00:00
else {
2006-04-24 17:41:27 +00:00
strcpy ( ast_config_AST_CONFIG_DIR , "/etc/asterisk" );
}
strcpy ( ast_config_AST_VAR_DIR , "/var/lib/asterisk" );
2006-08-09 01:17:47 +00:00
if ( dump_extensions ) {
dumpfile = fopen ( "extensions.conf.aeldump" , "w" );
if ( ! dumpfile ) {
printf ( " \n\n Sorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again! \n\n " );
exit ( 10 );
}
}
FIRST_TIME = 1 ;
2006-08-25 20:43:51 +00:00
ael_external_load_module ();
2006-04-24 17:41:27 +00:00
ast_log ( 4 , "ael2_parse" , __LINE__ , "main" , "%d contexts, %d extensions, %d priorities \n " , conts , extens , priors );
2006-08-09 01:17:47 +00:00
if ( dump_extensions && dumpfile ) {
for ( lp = context_list ; lp ; lp = lp -> next ) { /* print out any contexts that didn't have any
extensions in them */
if ( lp -> extension_count == 0 ) {
fprintf ( dumpfile , " \n\n [%s] \n " , lp -> name );
for ( n = lp -> ignorepats ; n ; n = n -> next ) {
fprintf ( dumpfile , "ignorepat => %s \n " , n -> name );
}
for ( n = lp -> includes ; n ; n = n -> next ) {
fprintf ( dumpfile , "include => %s \n " , n -> name );
}
for ( n = lp -> switches ; n ; n = n -> next ) {
fprintf ( dumpfile , "switch => %s/%s \n " , n -> name , n -> name2 );
}
for ( n = lp -> eswitches ; n ; n = n -> next ) {
fprintf ( dumpfile , "eswitch => %s/%s \n " , n -> name , n -> name2 );
}
}
}
}
if ( dump_extensions && dumpfile )
fclose ( dumpfile );
for ( lp = context_list ; lp ; lp = lp2 ) { /* free the ast_context structs */
lp2 = lp -> next ;
lp -> next = 0 ;
destroy_namelist ( lp -> includes );
destroy_namelist ( lp -> ignorepats );
destroy_namelist ( lp -> switches );
destroy_namelist ( lp -> eswitches );
free ( lp );
}
2006-04-24 17:41:27 +00:00
return 0 ;
}