Merged revisions 48554 via svnmerge from
[asterisk/asterisk.git] / utils / ael_main.c
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <locale.h>
7 #include <ctype.h>
8 #if !defined(SOLARIS) && !defined(__CYGWIN__)
9 #include <err.h>
10 #endif
11 #include <errno.h>
12 #include <regex.h>
13 #include <limits.h>
14
15 #include "asterisk/ast_expr.h"
16 #include "asterisk/channel.h"
17 #include "asterisk/module.h"
18 #include "asterisk/app.h"
19 #include "asterisk/ael_structs.h"
20
21 struct namelist
22 {
23         char name[100];
24         char name2[100];
25         struct namelist *next;
26 };
27
28 struct ast_context 
29 {
30         int extension_count;
31         char name[100];
32         char registrar[100];
33         struct namelist *includes;
34         struct namelist *ignorepats;
35         struct namelist *switches;
36         struct namelist *eswitches;
37
38         struct namelist *includes_last;
39         struct namelist *ignorepats_last;
40         struct namelist *switches_last;
41         struct namelist *eswitches_last;
42
43         struct ast_context *next;
44 };
45
46 #define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
47
48 void destroy_namelist(struct namelist *x);
49 void destroy_namelist(struct namelist *x)
50 {
51         struct namelist *z,*z2;
52         for(z=x; z; z = z2)
53         {
54                 z2 = z->next;
55                 z->next = 0;
56                 free(z);
57         }
58 }
59
60 struct namelist *create_name(char *name);
61 struct namelist *create_name(char *name)
62 {
63         struct namelist *x = calloc(1, sizeof(*x));
64         if (!x)
65                 return NULL;
66         strncpy(x->name, name, sizeof(x->name) - 1);
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 = calloc(1, sizeof(*x));
257         if (!x)
258                 return NULL;
259         x->next = context_list;
260         context_list = x;
261         if (!no_comp)
262                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
263         conts++;
264         strncpy(x->name, name, sizeof(x->name) - 1);
265         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
266         return x;
267 }
268
269 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
270 {
271         if(!no_comp)
272                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
273         if( dump_extensions ) {
274                 struct namelist *x;
275                 x = create_name((char*)value);
276                 ADD_LAST(con->ignorepats,x);
277         }
278 }
279
280 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
281 {
282         if(!no_comp)
283                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
284         if( dump_extensions ) {
285                 struct namelist *x;
286                 x = create_name((char*)value);
287                 ADD_LAST(con->includes,x);
288         }
289 }
290
291 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
292 {
293         if(!no_comp)
294                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
295         if( dump_extensions ) {
296                 struct namelist *x;
297                 x = create_name((char*)value);
298                 strncpy(x->name2,data,100);
299                 if( eval ) {
300
301                         ADD_LAST(con->switches,x);
302
303                 } else {
304
305                         ADD_LAST(con->eswitches,x);
306                 }
307         }
308 }
309
310 void ast_merge_contexts_and_delete(void)
311 {
312         if(!no_comp)
313                 printf("Executed ast_merge_contexts_and_delete();\n");
314 }
315
316 void ast_context_verify_includes(void)
317 {
318         if(!no_comp)
319                 printf("Executed ast_context_verify_includes();\n");
320 }
321
322 struct ast_context * ast_walk_contexts(void)
323 {
324         if(!no_comp)
325                 printf("Executed ast_walk_contexts();\n");
326         return 0;
327 }
328
329 void ast_cli_unregister_multiple(void)
330 {
331         if(!no_comp)
332                 printf("Executed ast_cli_unregister_multiple();\n");
333 }
334
335 void ast_context_destroy(void)
336 {
337         if( !no_comp)
338                 printf("Executed ast_context_destroy();\n");
339 }
340
341 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
342 {
343         va_list vars;
344         va_start(vars,fmt);
345         if( !quiet || level > 2 ) {
346             printf("LOG: lev:%d file:%s  line:%d func: %s  ",
347                    level, file, line, function);
348             vprintf(fmt, vars);
349             fflush(stdout);
350             va_end(vars);
351         }
352 }
353
354 void ast_verbose(const char *fmt, ...)
355 {
356         va_list vars;
357         va_start(vars,fmt);
358
359         printf("VERBOSE: ");
360         vprintf(fmt, vars);
361         fflush(stdout);
362         va_end(vars);
363 }
364
365 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
366 {
367         char *dataPut = start;
368         int inEscape = 0;
369         int inQuotes = 0;
370
371         for (; *start; start++) {
372                 if (inEscape) {
373                         *dataPut++ = *start;       /* Always goes verbatim */
374                         inEscape = 0;
375                 } else {
376                         if (*start == '\\') {
377                                 inEscape = 1;      /* Do not copy \ into the data */
378                         } else if (*start == '\'') {
379                                 inQuotes = 1-inQuotes;   /* Do not copy ' into the data */
380                         } else {
381                                 /* Replace , with |, unless in quotes */
382                                 *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
383                         }
384                 }
385         }
386         if (start != dataPut)
387                 *dataPut = 0;
388         return dataPut;
389 }
390
391 void filter_leading_space_from_exprs(char *str)
392 {
393         /*  Mainly for aesthetics */
394         char *t, *v, *u = str;
395         
396         while ( u && *u ) {
397
398                 if( *u == '$' && *(u+1) == '[' ) {
399                         t = u+2;
400                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
401                                 v = t;
402                                 while ( *v ) {
403                                         *v = *(v+1);
404                                         v++;
405                                 }
406                         }
407                 }
408                 
409                 u++;
410         }
411 }
412
413 void filter_newlines(char *str)
414 {
415         /* remove all newlines, returns  */
416         char *t=str;
417         while( t && *t ) {
418                 if( *t == '\n' || *t == '\r' ) {
419                         *t = ' '; /* just replace newlines and returns with spaces; they act as
420                                                  token separators, and just blindly removing them could be
421                                                  harmful. */
422                 }
423                 t++;
424         }
425 }
426
427
428 extern struct module_symbols mod_data;
429 extern int ael_external_load_module(void);
430
431 int main(int argc, char **argv)
432 {
433         int i;
434         struct namelist *n;
435         struct ast_context *lp,*lp2;
436         
437         for(i=1;i<argc;i++) {
438                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
439                         no_comp =1;
440                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
441                         quiet = 1;
442                         no_comp =1;
443                 }
444                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
445                         use_curr_dir =1;
446                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
447                         dump_extensions =1;
448         }
449         
450         if( !quiet ) {
451                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
452                 if( !no_comp )
453                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
454                 if( !use_curr_dir )
455                         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");
456                 if( !dump_extensions )
457                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
458         }
459
460         if( use_curr_dir ) {
461                 strcpy(ast_config_AST_CONFIG_DIR, ".");
462         }
463         else {
464                 strcpy(ast_config_AST_CONFIG_DIR, "/etc/asterisk");
465         }
466         strcpy(ast_config_AST_VAR_DIR, "/var/lib/asterisk");
467         
468         if( dump_extensions ) {
469                 dumpfile = fopen("extensions.conf.aeldump","w");
470                 if( !dumpfile ) {
471                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
472                         exit(10);
473                 }
474                 
475         }
476
477         FIRST_TIME = 1;
478         
479         ael_external_load_module();
480         
481         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
482
483         if( dump_extensions && dumpfile ) {
484         
485                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
486                                                                                                                  extensions in them */
487                         if( lp->extension_count == 0 ) {
488                                 
489                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
490                                 
491                                 for(n=lp->ignorepats;n;n=n->next) {
492                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
493                                 }
494                                 for(n=lp->includes;n;n=n->next) {
495                                         fprintf(dumpfile, "include => %s\n", n->name);
496                                 }
497                                 for(n=lp->switches;n;n=n->next) {
498                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
499                                 }
500                                 for(n=lp->eswitches;n;n=n->next) {
501                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
502                                 }
503                         }
504                 }
505         }
506         
507         if( dump_extensions && dumpfile )
508                 fclose(dumpfile);
509         
510         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
511                 lp2 = lp->next;
512                 lp->next = 0;
513
514                 destroy_namelist(lp->includes);
515                 destroy_namelist(lp->ignorepats);
516                 destroy_namelist(lp->switches);
517                 destroy_namelist(lp->eswitches);
518
519                 free(lp);
520         }
521         
522     return 0;
523 }