e89a4b4563fcae362601db6773667dc3f9520885
[asterisk/asterisk.git] / utils / ael_main.c
1 #include "asterisk/autoconfig.h"
2
3 #include <sys/types.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <string.h>
8 #include <locale.h>
9 #include <ctype.h>
10 #if !defined(SOLARIS) && !defined(__CYGWIN__)
11 #include <err.h>
12 #endif
13 #include <errno.h>
14 #include <regex.h>
15 #include <limits.h>
16
17 #include "asterisk/ast_expr.h"
18 #include "asterisk/channel.h"
19 #include "asterisk/module.h"
20 #include "asterisk/app.h"
21 #include "asterisk/ael_structs.h"
22
23 struct namelist
24 {
25         char name[100];
26         char name2[100];
27         struct namelist *next;
28 };
29
30 struct ast_context 
31 {
32         int extension_count;
33         char name[100];
34         char registrar[100];
35         struct namelist *includes;
36         struct namelist *ignorepats;
37         struct namelist *switches;
38         struct namelist *eswitches;
39
40         struct namelist *includes_last;
41         struct namelist *ignorepats_last;
42         struct namelist *switches_last;
43         struct namelist *eswitches_last;
44
45         struct ast_context *next;
46 };
47
48 #define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
49
50 void destroy_namelist(struct namelist *x);
51 void destroy_namelist(struct namelist *x)
52 {
53         struct namelist *z,*z2;
54         for(z=x; z; z = z2)
55         {
56                 z2 = z->next;
57                 z->next = 0;
58                 free(z);
59         }
60 }
61
62 struct namelist *create_name(char *name);
63 struct namelist *create_name(char *name)
64 {
65         struct namelist *x = (struct namelist *)calloc(sizeof(struct namelist),1);
66         strncpy(x->name,name,100);
67         return x;
68 }
69
70 struct ast_context *context_list;
71 struct ast_context *last_context;
72 struct namelist *globalvars;
73 struct namelist *globalvars_last;
74
75 int conts=0, extens=0, priors=0;
76 char last_exten[18000];
77 char ast_config_AST_CONFIG_DIR[PATH_MAX];
78 char ast_config_AST_VAR_DIR[PATH_MAX];
79
80 void ast_add_profile(void);
81 void ast_cli_register_multiple(void);
82 void ast_register_file_version(void);
83 void ast_unregister_file_version(void);
84 int ast_add_extension2(struct ast_context *con,
85                                            int replace, const char *extension, int priority, const char *label, const char *callerid,
86                                                 const char *application, void *data, void (*datad)(void *),
87                                            const char *registrar);
88 void pbx_builtin_setvar(void *chan, void *data);
89 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar);
90 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
91 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar);
92 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar);
93 void ast_merge_contexts_and_delete(void);
94 void ast_context_verify_includes(void);
95 struct ast_context * ast_walk_contexts(void);
96 void ast_cli_unregister_multiple(void);
97 void ast_context_destroy(void);
98 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...);
99 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with);
100 void ast_verbose(const char *fmt, ...);
101 struct ast_app *pbx_findapp(const char *app);
102 void filter_leading_space_from_exprs(char *str);
103 void filter_newlines(char *str);
104 static int quiet = 0;
105 static int no_comp = 0;
106 static int use_curr_dir = 0;
107 static int dump_extensions = 0;
108 static int FIRST_TIME = 0;
109 static FILE *dumpfile;
110
111 struct ast_app *pbx_findapp(const char *app)
112 {
113         return (struct ast_app*)1; /* so as not to trigger an error */
114 }
115
116 void ast_add_profile(void)
117 {
118         if (!no_comp)
119                 printf("Executed ast_add_profile();\n");
120 }
121
122 void ast_cli_register_multiple(void)
123 {
124         if(!no_comp)
125                 printf("Executed ast_cli_register_multiple();\n");
126 }
127
128 void ast_register_file_version(void)
129 {
130         /* if(!no_comp)
131                 printf("Executed ast_register_file_version();\n"); */
132         /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
133 }
134
135 void ast_unregister_file_version(void)
136 {
137         /* if(!no_comp)
138                 printf("Executed ast_unregister_file_version();\n"); */
139         /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
140
141 }
142 int ast_add_extension2(struct ast_context *con,
143                         int replace, const char *extension, int priority, const char *label, const char *callerid,
144                         const char *application, void *data, void (*datad)(void *),
145                         const char *registrar)
146 {
147         priors++;
148         con->extension_count++;
149         if (strcmp(extension,last_exten) != 0) {
150                 extens++;
151                 strcpy(last_exten, extension);
152         }
153         if (!label) {
154                 label = "(null)";
155         }
156         if (!callerid) {
157                 callerid = "(null)";
158         }
159         if (!application) {
160                 application = "(null)";
161         }
162
163         if(!no_comp)
164                 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",
165                            con->name, replace, extension, priority, label, callerid, application, (data?(char*)data:"(null)"), registrar);
166
167         if( dump_extensions && dumpfile ) {
168                 struct namelist *n;
169
170                 if( FIRST_TIME ) {
171                         FIRST_TIME = 0;
172                         
173                         if( globalvars )
174                                 fprintf(dumpfile,"[globals]\n");
175                         
176                         for(n=globalvars;n;n=n->next) {
177                                 fprintf(dumpfile, "%s\n", n->name);
178                         }
179                 }
180                 
181                 /* print out each extension , possibly the context header also */
182                 if( con != last_context ) {
183                         fprintf(dumpfile,"\n\n[%s]\n", con->name);
184                         last_context = con;
185                         for(n=con->ignorepats;n;n=n->next) {
186                                 fprintf(dumpfile, "ignorepat => %s\n", n->name);
187                         }
188                         for(n=con->includes;n;n=n->next) {
189                                 fprintf(dumpfile, "include => %s\n", n->name);
190                         }
191                         for(n=con->switches;n;n=n->next) {
192                                 fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
193                         }
194                         for(n=con->eswitches;n;n=n->next) {
195                                 fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
196                         }
197                         
198                 }
199                 if( data ) {
200                         filter_newlines((char*)data);
201                         filter_leading_space_from_exprs((char*)data);
202
203                         if( strcmp(label,"(null)") != 0  )
204                                 fprintf(dumpfile,"exten => %s,%d(%s),%s(%s)\n", extension, priority, label, application, (char*)data);
205                         else
206                                 fprintf(dumpfile,"exten => %s,%d,%s(%s)\n", extension, priority, application, (char*)data);
207
208                 } else {
209
210                         if( strcmp(label,"(null)") != 0  )
211                                 fprintf(dumpfile,"exten => %s,%d(%s),%s\n", extension, priority, label, application);
212                         else
213                                 fprintf(dumpfile,"exten => %s,%d,%s\n", extension, priority, application);
214                 }
215         }
216         
217         /* since add_extension2 is responsible for the malloc'd data stuff */
218         if( data )
219                 free(data);
220         return 0;
221 }
222
223 void pbx_builtin_setvar(void *chan, void *data)
224 {
225         struct namelist *x = create_name((char*)data);
226         if(!no_comp)
227                 printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
228
229         if( dump_extensions ) {
230                 x = create_name((char*)data);
231                 ADD_LAST(globalvars,x);
232         }
233 }
234         
235
236 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
237 {
238         struct ast_context *x = (struct ast_context *)calloc(sizeof(struct ast_context),1);
239         x->next = context_list;
240         context_list = x;
241         if(!no_comp)
242                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
243         conts++;
244         strncpy(x->name,name,100);
245         strncpy(x->registrar,registrar,100);
246         return x;
247 }
248
249 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
250 {
251         if(!no_comp)
252                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
253         if( dump_extensions ) {
254                 struct namelist *x;
255                 x = create_name((char*)value);
256                 ADD_LAST(con->ignorepats,x);
257         }
258 }
259
260 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
261 {
262         if(!no_comp)
263                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
264         if( dump_extensions ) {
265                 struct namelist *x;
266                 x = create_name((char*)value);
267                 ADD_LAST(con->includes,x);
268         }
269 }
270
271 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
272 {
273         if(!no_comp)
274                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
275         if( dump_extensions ) {
276                 struct namelist *x;
277                 x = create_name((char*)value);
278                 strncpy(x->name2,data,100);
279                 if( eval ) {
280
281                         ADD_LAST(con->switches,x);
282
283                 } else {
284
285                         ADD_LAST(con->eswitches,x);
286                 }
287         }
288 }
289
290 void ast_merge_contexts_and_delete(void)
291 {
292         if(!no_comp)
293                 printf("Executed ast_merge_contexts_and_delete();\n");
294 }
295
296 void ast_context_verify_includes(void)
297 {
298         if(!no_comp)
299                 printf("Executed ast_context_verify_includes();\n");
300 }
301
302 struct ast_context * ast_walk_contexts(void)
303 {
304         if(!no_comp)
305                 printf("Executed ast_walk_contexts();\n");
306         return 0;
307 }
308
309 void ast_cli_unregister_multiple(void)
310 {
311         if(!no_comp)
312                 printf("Executed ast_cli_unregister_multiple();\n");
313 }
314
315 void ast_context_destroy(void)
316 {
317         if( !no_comp)
318                 printf("Executed ast_context_destroy();\n");
319 }
320
321 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
322 {
323         va_list vars;
324         va_start(vars,fmt);
325         if( !quiet || level > 2 ) {
326             printf("LOG: lev:%d file:%s  line:%d func: %s  ",
327                    level, file, line, function);
328             vprintf(fmt, vars);
329             fflush(stdout);
330             va_end(vars);
331         }
332 }
333
334 void ast_verbose(const char *fmt, ...)
335 {
336         va_list vars;
337         va_start(vars,fmt);
338
339         printf("VERBOSE: ");
340         vprintf(fmt, vars);
341         fflush(stdout);
342         va_end(vars);
343 }
344
345 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
346 {
347         char *dataPut = start;
348         int inEscape = 0;
349         int inQuotes = 0;
350
351         for (; *start; start++) {
352                 if (inEscape) {
353                         *dataPut++ = *start;       /* Always goes verbatim */
354                         inEscape = 0;
355                 } else {
356                         if (*start == '\\') {
357                                 inEscape = 1;      /* Do not copy \ into the data */
358                         } else if (*start == '\'') {
359                                 inQuotes = 1-inQuotes;   /* Do not copy ' into the data */
360                         } else {
361                                 /* Replace , with |, unless in quotes */
362                                 *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
363                         }
364                 }
365         }
366         if (start != dataPut)
367                 *dataPut = 0;
368         return dataPut;
369 }
370
371 void filter_leading_space_from_exprs(char *str)
372 {
373         /*  Mainly for aesthetics */
374         char *t, *v, *u = str;
375         
376         while ( u && *u ) {
377
378                 if( *u == '$' && *(u+1) == '[' ) {
379                         t = u+2;
380                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
381                                 v = t;
382                                 while ( *v ) {
383                                         *v = *(v+1);
384                                         v++;
385                                 }
386                         }
387                 }
388                 
389                 u++;
390         }
391 }
392
393 void filter_newlines(char *str)
394 {
395         /* remove all newlines, returns  */
396         char *t=str;
397         while( t && *t ) {
398                 if( *t == '\n' || *t == '\r' ) {
399                         *t = ' '; /* just replace newlines and returns with spaces; they act as
400                                                  token separators, and just blindly removing them could be
401                                                  harmful. */
402                 }
403                 t++;
404         }
405 }
406
407
408 extern struct module_symbols mod_data;
409
410 int main(int argc, char **argv)
411 {
412         int i;
413         struct namelist *n;
414         struct ast_context *lp,*lp2;
415         
416         for(i=1;i<argc;i++) {
417                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
418                         no_comp =1;
419                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
420                         quiet = 1;
421                         no_comp =1;
422                 }
423                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
424                         use_curr_dir =1;
425                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
426                         dump_extensions =1;
427         }
428         
429         if( !quiet ) {
430                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
431                 if( !no_comp )
432                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
433                 if( !use_curr_dir )
434                         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");
435                 if( !dump_extensions )
436                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
437         }
438
439         if( use_curr_dir ) {
440                 strcpy(ast_config_AST_CONFIG_DIR, ".");
441         }
442         else {
443                 strcpy(ast_config_AST_CONFIG_DIR, "/etc/asterisk");
444         }
445         strcpy(ast_config_AST_VAR_DIR, "/var/lib/asterisk");
446         
447         if( dump_extensions ) {
448                 dumpfile = fopen("extensions.conf.aeldump","w");
449                 if( !dumpfile ) {
450                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
451                         exit(10);
452                 }
453                 
454         }
455
456         FIRST_TIME = 1;
457         
458         ast_module_info->load();
459         
460         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
461
462         if( dump_extensions && dumpfile ) {
463         
464                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
465                                                                                                                  extensions in them */
466                         if( lp->extension_count == 0 ) {
467                                 
468                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
469                                 
470                                 for(n=lp->ignorepats;n;n=n->next) {
471                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
472                                 }
473                                 for(n=lp->includes;n;n=n->next) {
474                                         fprintf(dumpfile, "include => %s\n", n->name);
475                                 }
476                                 for(n=lp->switches;n;n=n->next) {
477                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
478                                 }
479                                 for(n=lp->eswitches;n;n=n->next) {
480                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
481                                 }
482                         }
483                 }
484         }
485         
486         if( dump_extensions && dumpfile )
487                 fclose(dumpfile);
488         
489         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
490                 lp2 = lp->next;
491                 lp->next = 0;
492
493                 destroy_namelist(lp->includes);
494                 destroy_namelist(lp->ignorepats);
495                 destroy_namelist(lp->switches);
496                 destroy_namelist(lp->eswitches);
497
498                 free(lp);
499         }
500         
501     return 0;
502 }