Changes to fix all problems reported in 7804 are included here.
[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 int ast_loader_register(int (*updater)(void))
123 {
124         return 1;
125 }
126
127 int ast_loader_unregister(int (*updater)(void))
128 {
129         return 1;
130 }
131 void ast_module_register(const struct ast_module_info *x)
132 {
133 }
134
135 void ast_module_unregister(const struct ast_module_info *x)
136 {
137 }
138
139
140 void ast_cli_register_multiple(void)
141 {
142         if(!no_comp)
143                 printf("Executed ast_cli_register_multiple();\n");
144 }
145
146 void ast_register_file_version(void)
147 {
148         /* if(!no_comp)
149                 printf("Executed ast_register_file_version();\n"); */
150         /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
151 }
152
153 void ast_unregister_file_version(void)
154 {
155         /* if(!no_comp)
156                 printf("Executed ast_unregister_file_version();\n"); */
157         /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
158
159 }
160 int ast_add_extension2(struct ast_context *con,
161                         int replace, const char *extension, int priority, const char *label, const char *callerid,
162                         const char *application, void *data, void (*datad)(void *),
163                         const char *registrar)
164 {
165         priors++;
166         con->extension_count++;
167         if (strcmp(extension,last_exten) != 0) {
168                 extens++;
169                 strcpy(last_exten, extension);
170         }
171         if (!label) {
172                 label = "(null)";
173         }
174         if (!callerid) {
175                 callerid = "(null)";
176         }
177         if (!application) {
178                 application = "(null)";
179         }
180
181         if(!no_comp)
182                 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",
183                            con->name, replace, extension, priority, label, callerid, application, (data?(char*)data:"(null)"), registrar);
184
185         if( dump_extensions && dumpfile ) {
186                 struct namelist *n;
187
188                 if( FIRST_TIME ) {
189                         FIRST_TIME = 0;
190                         
191                         if( globalvars )
192                                 fprintf(dumpfile,"[globals]\n");
193                         
194                         for(n=globalvars;n;n=n->next) {
195                                 fprintf(dumpfile, "%s\n", n->name);
196                         }
197                 }
198                 
199                 /* print out each extension , possibly the context header also */
200                 if( con != last_context ) {
201                         fprintf(dumpfile,"\n\n[%s]\n", con->name);
202                         last_context = con;
203                         for(n=con->ignorepats;n;n=n->next) {
204                                 fprintf(dumpfile, "ignorepat => %s\n", n->name);
205                         }
206                         for(n=con->includes;n;n=n->next) {
207                                 fprintf(dumpfile, "include => %s\n", n->name);
208                         }
209                         for(n=con->switches;n;n=n->next) {
210                                 fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
211                         }
212                         for(n=con->eswitches;n;n=n->next) {
213                                 fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
214                         }
215                         
216                 }
217                 if( data ) {
218                         filter_newlines((char*)data);
219                         filter_leading_space_from_exprs((char*)data);
220
221                         if( strcmp(label,"(null)") != 0  )
222                                 fprintf(dumpfile,"exten => %s,%d(%s),%s(%s)\n", extension, priority, label, application, (char*)data);
223                         else
224                                 fprintf(dumpfile,"exten => %s,%d,%s(%s)\n", extension, priority, application, (char*)data);
225
226                 } else {
227
228                         if( strcmp(label,"(null)") != 0  )
229                                 fprintf(dumpfile,"exten => %s,%d(%s),%s\n", extension, priority, label, application);
230                         else
231                                 fprintf(dumpfile,"exten => %s,%d,%s\n", extension, priority, application);
232                 }
233         }
234         
235         /* since add_extension2 is responsible for the malloc'd data stuff */
236         if( data )
237                 free(data);
238         return 0;
239 }
240
241 void pbx_builtin_setvar(void *chan, void *data)
242 {
243         struct namelist *x = create_name((char*)data);
244         if(!no_comp)
245                 printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
246
247         if( dump_extensions ) {
248                 x = create_name((char*)data);
249                 ADD_LAST(globalvars,x);
250         }
251 }
252         
253
254 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
255 {
256         struct ast_context *x = (struct ast_context *)calloc(sizeof(struct ast_context),1);
257         x->next = context_list;
258         context_list = x;
259         if(!no_comp)
260                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
261         conts++;
262         strncpy(x->name,name,100);
263         strncpy(x->registrar,registrar,100);
264         return x;
265 }
266
267 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
268 {
269         if(!no_comp)
270                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
271         if( dump_extensions ) {
272                 struct namelist *x;
273                 x = create_name((char*)value);
274                 ADD_LAST(con->ignorepats,x);
275         }
276 }
277
278 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
279 {
280         if(!no_comp)
281                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
282         if( dump_extensions ) {
283                 struct namelist *x;
284                 x = create_name((char*)value);
285                 ADD_LAST(con->includes,x);
286         }
287 }
288
289 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
290 {
291         if(!no_comp)
292                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
293         if( dump_extensions ) {
294                 struct namelist *x;
295                 x = create_name((char*)value);
296                 strncpy(x->name2,data,100);
297                 if( eval ) {
298
299                         ADD_LAST(con->switches,x);
300
301                 } else {
302
303                         ADD_LAST(con->eswitches,x);
304                 }
305         }
306 }
307
308 void ast_merge_contexts_and_delete(void)
309 {
310         if(!no_comp)
311                 printf("Executed ast_merge_contexts_and_delete();\n");
312 }
313
314 void ast_context_verify_includes(void)
315 {
316         if(!no_comp)
317                 printf("Executed ast_context_verify_includes();\n");
318 }
319
320 struct ast_context * ast_walk_contexts(void)
321 {
322         if(!no_comp)
323                 printf("Executed ast_walk_contexts();\n");
324         return 0;
325 }
326
327 void ast_cli_unregister_multiple(void)
328 {
329         if(!no_comp)
330                 printf("Executed ast_cli_unregister_multiple();\n");
331 }
332
333 void ast_context_destroy(void)
334 {
335         if( !no_comp)
336                 printf("Executed ast_context_destroy();\n");
337 }
338
339 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
340 {
341         va_list vars;
342         va_start(vars,fmt);
343         if( !quiet || level > 2 ) {
344             printf("LOG: lev:%d file:%s  line:%d func: %s  ",
345                    level, file, line, function);
346             vprintf(fmt, vars);
347             fflush(stdout);
348             va_end(vars);
349         }
350 }
351
352 void ast_verbose(const char *fmt, ...)
353 {
354         va_list vars;
355         va_start(vars,fmt);
356
357         printf("VERBOSE: ");
358         vprintf(fmt, vars);
359         fflush(stdout);
360         va_end(vars);
361 }
362
363 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
364 {
365         char *dataPut = start;
366         int inEscape = 0;
367         int inQuotes = 0;
368
369         for (; *start; start++) {
370                 if (inEscape) {
371                         *dataPut++ = *start;       /* Always goes verbatim */
372                         inEscape = 0;
373                 } else {
374                         if (*start == '\\') {
375                                 inEscape = 1;      /* Do not copy \ into the data */
376                         } else if (*start == '\'') {
377                                 inQuotes = 1-inQuotes;   /* Do not copy ' into the data */
378                         } else {
379                                 /* Replace , with |, unless in quotes */
380                                 *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
381                         }
382                 }
383         }
384         if (start != dataPut)
385                 *dataPut = 0;
386         return dataPut;
387 }
388
389 void filter_leading_space_from_exprs(char *str)
390 {
391         /*  Mainly for aesthetics */
392         char *t, *v, *u = str;
393         
394         while ( u && *u ) {
395
396                 if( *u == '$' && *(u+1) == '[' ) {
397                         t = u+2;
398                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
399                                 v = t;
400                                 while ( *v ) {
401                                         *v = *(v+1);
402                                         v++;
403                                 }
404                         }
405                 }
406                 
407                 u++;
408         }
409 }
410
411 void filter_newlines(char *str)
412 {
413         /* remove all newlines, returns  */
414         char *t=str;
415         while( t && *t ) {
416                 if( *t == '\n' || *t == '\r' ) {
417                         *t = ' '; /* just replace newlines and returns with spaces; they act as
418                                                  token separators, and just blindly removing them could be
419                                                  harmful. */
420                 }
421                 t++;
422         }
423 }
424
425
426 extern struct module_symbols mod_data;
427 extern ael_external_load_module(void);
428
429 int main(int argc, char **argv)
430 {
431         int i;
432         struct namelist *n;
433         struct ast_context *lp,*lp2;
434         
435         for(i=1;i<argc;i++) {
436                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
437                         no_comp =1;
438                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
439                         quiet = 1;
440                         no_comp =1;
441                 }
442                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
443                         use_curr_dir =1;
444                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
445                         dump_extensions =1;
446         }
447         
448         if( !quiet ) {
449                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
450                 if( !no_comp )
451                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
452                 if( !use_curr_dir )
453                         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");
454                 if( !dump_extensions )
455                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
456         }
457
458         if( use_curr_dir ) {
459                 strcpy(ast_config_AST_CONFIG_DIR, ".");
460         }
461         else {
462                 strcpy(ast_config_AST_CONFIG_DIR, "/etc/asterisk");
463         }
464         strcpy(ast_config_AST_VAR_DIR, "/var/lib/asterisk");
465         
466         if( dump_extensions ) {
467                 dumpfile = fopen("extensions.conf.aeldump","w");
468                 if( !dumpfile ) {
469                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
470                         exit(10);
471                 }
472                 
473         }
474
475         FIRST_TIME = 1;
476         
477         ael_external_load_module();
478         
479         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
480
481         if( dump_extensions && dumpfile ) {
482         
483                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
484                                                                                                                  extensions in them */
485                         if( lp->extension_count == 0 ) {
486                                 
487                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
488                                 
489                                 for(n=lp->ignorepats;n;n=n->next) {
490                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
491                                 }
492                                 for(n=lp->includes;n;n=n->next) {
493                                         fprintf(dumpfile, "include => %s\n", n->name);
494                                 }
495                                 for(n=lp->switches;n;n=n->next) {
496                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
497                                 }
498                                 for(n=lp->eswitches;n;n=n->next) {
499                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
500                                 }
501                         }
502                 }
503         }
504         
505         if( dump_extensions && dumpfile )
506                 fclose(dumpfile);
507         
508         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
509                 lp2 = lp->next;
510                 lp->next = 0;
511
512                 destroy_namelist(lp->includes);
513                 destroy_namelist(lp->ignorepats);
514                 destroy_namelist(lp->switches);
515                 destroy_namelist(lp->eswitches);
516
517                 free(lp);
518         }
519         
520     return 0;
521 }