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