fff28b738de08629658fcda7d5eb37d0095f869e
[asterisk/asterisk.git] / utils / ael_main.c
1 /*
2  * XXX this file probably need a fair amount of cleanup, at the very least:
3  *
4  * - documenting its purpose;
5  * - removing all unnecessary headers and other stuff from the sources
6  *   it was copied from;
7  * - fixing the formatting
8  */
9
10 /*** MODULEINFO
11         <support_level>extended</support_level>
12  ***/
13
14 #include "asterisk.h"
15
16 #include <locale.h>
17 #include <ctype.h>
18 #include <regex.h>
19 #include <limits.h>
20
21 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
22
23 #include "asterisk/channel.h"
24 #include "asterisk/ast_expr.h"
25 #include "asterisk/module.h"
26 #include "asterisk/app.h"
27 #include "asterisk/lock.h"
28 #include "asterisk/hashtab.h"
29 #include "asterisk/ael_structs.h"
30 #include "asterisk/extconf.h"
31
32 int option_debug = 0;
33 int option_verbose = 0;
34 #if !defined(LOW_MEMORY)
35 void ast_register_file_version(const char *file, const char *version) { }
36 void ast_unregister_file_version(const char *file) { }
37 #endif
38
39 struct ast_flags ast_compat = { 7 };
40
41 /*** MODULEINFO
42         <depend>res_ael_share</depend>
43  ***/
44
45 struct namelist
46 {
47         char name[100];
48         char name2[100];
49         struct namelist *next;
50 };
51
52 struct ast_context 
53 {
54         int extension_count;
55         char name[100];
56         char registrar[100];
57         struct namelist *includes;
58         struct namelist *ignorepats;
59         struct namelist *switches;
60         struct namelist *eswitches;
61
62         struct namelist *includes_last;
63         struct namelist *ignorepats_last;
64         struct namelist *switches_last;
65         struct namelist *eswitches_last;
66
67         struct ast_context *next;
68 };
69
70 #define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
71
72 void destroy_namelist(struct namelist *x);
73 void destroy_namelist(struct namelist *x)
74 {
75         struct namelist *z,*z2;
76         for(z=x; z; z = z2)
77         {
78                 z2 = z->next;
79                 z->next = 0;
80                 free(z);
81         }
82 }
83
84 struct namelist *create_name(const char *name);
85 struct namelist *create_name(const char *name)
86 {
87         struct namelist *x = calloc(1, sizeof(*x));
88         if (!x)
89                 return NULL;
90         strncpy(x->name, name, sizeof(x->name) - 1);
91         return x;
92 }
93
94 struct ast_context *context_list;
95 struct ast_context *last_context;
96 struct namelist *globalvars;
97 struct namelist *globalvars_last;
98
99 int conts=0, extens=0, priors=0;
100 char last_exten[18000];
101
102 static char config_dir[PATH_MAX];
103 static char var_dir[PATH_MAX];
104 const char *ast_config_AST_CONFIG_DIR = config_dir;
105 const char *ast_config_AST_VAR_DIR = var_dir;
106
107 void ast_cli_register_multiple(void);
108 int ast_add_extension2(struct ast_context *con,
109                                            int replace, const char *extension, int priority, const char *label, const char *callerid,
110                                                 const char *application, void *data, void (*datad)(void *),
111                                            const char *registrar);
112 void pbx_builtin_setvar(void *chan, void *data);
113 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar);
114 struct ast_context * ast_context_find_or_create(void **extcontexts, void *tab, const char *name, const char *registrar);
115 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
116 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar);
117 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar);
118 void ast_merge_contexts_and_delete(void);
119 void ast_context_verify_includes(void);
120 struct ast_context * ast_walk_contexts(void);
121 void ast_cli_unregister_multiple(void);
122 void ast_context_destroy(void);
123 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...);
124 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with);
125 void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...);
126 struct ast_app *pbx_findapp(const char *app);
127 void filter_leading_space_from_exprs(char *str);
128 void filter_newlines(char *str);
129 static int quiet = 0;
130 static int no_comp = 0;
131 static int use_curr_dir = 0;
132 static int dump_extensions = 0;
133 static int FIRST_TIME = 0;
134 static FILE *dumpfile;
135
136 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
137 {
138                 va_list vars;
139                         va_start(vars,fmt);
140                         
141                                 printf("LOG: lev:%d file:%s  line:%d func: %s  ",
142                                                                    level, file, line, function);
143                                         vprintf(fmt, vars);
144                                                 fflush(stdout);
145                                                         va_end(vars);
146 }
147
148 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
149                                                                          struct ast_context *bypass,
150                                                                          struct pbx_find_info *q,
151                                                                          const char *context, 
152                                                                          const char *exten, 
153                                                                          int priority,
154                                                                          const char *label, 
155                                                                          const char *callerid, 
156                                                                          enum ext_match_t action);
157
158 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
159                                                                          struct ast_context *bypass,
160                                                                          struct pbx_find_info *q,
161                                                                          const char *context, 
162                                                                          const char *exten, 
163                                                                          int priority,
164                                                                          const char *label, 
165                                                                          const char *callerid, 
166                                                                          enum ext_match_t action)
167 {
168         return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
169 }
170
171 struct ast_app *pbx_findapp(const char *app)
172 {
173         return (struct ast_app*)1; /* so as not to trigger an error */
174 }
175
176 struct ast_custom_function *ast_custom_function_find(const char *name);
177
178
179 struct ast_custom_function *ast_custom_function_find(const char *name)
180 {
181         return 0; /* in "standalone" mode, functions are just not avail */
182 }
183
184 #if !defined(LOW_MEMORY)
185 int ast_add_profile(const char *x, uint64_t scale)
186 {
187         if (!no_comp)
188                 printf("Executed ast_add_profile();\n");
189
190         return 0;
191 }
192 #endif
193
194 int ast_loader_register(int (*updater)(void))
195 {
196         return 1;
197 }
198
199 int ast_loader_unregister(int (*updater)(void))
200 {
201         return 1;
202 }
203 void ast_module_register(const struct ast_module_info *x)
204 {
205 }
206
207 void ast_module_unregister(const struct ast_module_info *x)
208 {
209 }
210
211
212 void ast_cli_register_multiple(void)
213 {
214         if(!no_comp)
215                 printf("Executed ast_cli_register_multiple();\n");
216 }
217
218 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
219 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
220 {
221         if (cp1 && *cp1)
222                 strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for 
223                                                                                            a possible var substitution on extension names,
224                                                                                            so....! */
225         else
226                 *cp2 = 0;
227 }
228
229 int ast_add_extension2(struct ast_context *con,
230                         int replace, const char *extension, int priority, const char *label, const char *callerid,
231                         const char *application, void *data, void (*datad)(void *),
232                         const char *registrar)
233 {
234         priors++;
235         con->extension_count++;
236         if (strcmp(extension,last_exten) != 0) {
237                 extens++;
238                 strcpy(last_exten, extension);
239         }
240         if (!label) {
241                 label = "(null)";
242         }
243         if (!callerid) {
244                 callerid = "(null)";
245         }
246         if (!application) {
247                 application = "(null)";
248         }
249
250         if(!no_comp)
251                 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",
252                            con->name, replace, extension, priority, label, callerid, application, (data?(char*)data:"(null)"), registrar);
253
254         if( dump_extensions && dumpfile ) {
255                 struct namelist *n;
256
257                 if( FIRST_TIME ) {
258                         FIRST_TIME = 0;
259                         
260                         if( globalvars )
261                                 fprintf(dumpfile,"[globals]\n");
262                         
263                         for(n=globalvars;n;n=n->next) {
264                                 fprintf(dumpfile, "%s\n", n->name);
265                         }
266                 }
267                 
268                 /* print out each extension , possibly the context header also */
269                 if( con != last_context ) {
270                         fprintf(dumpfile,"\n\n[%s]\n", con->name);
271                         last_context = con;
272                         for(n=con->ignorepats;n;n=n->next) {
273                                 fprintf(dumpfile, "ignorepat => %s\n", n->name);
274                         }
275                         for(n=con->includes;n;n=n->next) {
276                                 fprintf(dumpfile, "include => %s\n", n->name);
277                         }
278                         for(n=con->switches;n;n=n->next) {
279                                 fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
280                         }
281                         for(n=con->eswitches;n;n=n->next) {
282                                 fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
283                         }
284                         
285                 }
286                 if( data ) {
287                         filter_newlines((char*)data);
288                         filter_leading_space_from_exprs((char*)data);
289                         /* in previous versions, commas were converted to '|' to separate
290                            args in app calls, but now, commas are used. There used to be
291                            code here to insert backslashes (escapes) before any commas
292                            that may have been embedded in the app args. This code is no more. */
293
294                         if( strcmp(label,"(null)") != 0  )
295                                 fprintf(dumpfile,"exten => %s,%d(%s),%s(%s)\n", extension, priority, label, application, (char*)data);
296                         else
297                                 fprintf(dumpfile,"exten => %s,%d,%s(%s)\n", extension, priority, application, (char*)data);
298
299                 } else {
300
301                         if( strcmp(label,"(null)") != 0  )
302                                 fprintf(dumpfile,"exten => %s,%d(%s),%s\n", extension, priority, label, application);
303                         else
304                                 fprintf(dumpfile,"exten => %s,%d,%s\n", extension, priority, application);
305                 }
306         }
307         
308         /* since add_extension2 is responsible for the malloc'd data stuff */
309         free(data);
310         return 0;
311 }
312
313 void pbx_builtin_setvar(void *chan, void *data)
314 {
315         struct namelist *x = create_name(data);
316         if(!no_comp)
317                 printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
318
319         if( dump_extensions ) {
320                 x = create_name(data);
321                 ADD_LAST(globalvars,x);
322         }
323 }
324         
325
326 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
327 {
328         struct ast_context *x = calloc(1, sizeof(*x));
329         if (!x)
330                 return NULL;
331         x->next = context_list;
332         context_list = x;
333         if (!no_comp)
334                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
335         conts++;
336         strncpy(x->name, name, sizeof(x->name) - 1);
337         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
338         return x;
339 }
340
341 struct ast_context * ast_context_find_or_create(void **extcontexts, void *tab, const char *name, const char *registrar)
342 {
343         struct ast_context *x = calloc(1, sizeof(*x));
344         if (!x)
345                 return NULL;
346         x->next = context_list;
347         context_list = x;
348         if (!no_comp)
349                 printf("Executed ast_context_find_or_create(conts, name=%s, registrar=%s);\n", name, registrar);
350         conts++;
351         strncpy(x->name, name, sizeof(x->name) - 1);
352         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
353         return x;
354 }
355
356 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
357 {
358         if(!no_comp)
359                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
360         if( dump_extensions ) {
361                 struct namelist *x;
362                 x = create_name(value);
363                 ADD_LAST(con->ignorepats,x);
364         }
365 }
366
367 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
368 {
369         if(!no_comp)
370                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
371         if( dump_extensions ) {
372                 struct namelist *x;
373                 x = create_name((char*)value);
374                 ADD_LAST(con->includes,x);
375         }
376 }
377
378 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
379 {
380         if(!no_comp)
381                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
382         if( dump_extensions ) {
383                 struct namelist *x;
384                 x = create_name((char*)value);
385                 strncpy(x->name2,data,100);
386                 if( eval ) {
387
388                         ADD_LAST(con->switches,x);
389
390                 } else {
391
392                         ADD_LAST(con->eswitches,x);
393                 }
394         }
395 }
396
397 void ast_merge_contexts_and_delete(void)
398 {
399         if(!no_comp)
400                 printf("Executed ast_merge_contexts_and_delete();\n");
401 }
402
403 void ast_context_verify_includes(void)
404 {
405         if(!no_comp)
406                 printf("Executed ast_context_verify_includes();\n");
407 }
408
409 struct ast_context * ast_walk_contexts(void)
410 {
411         if(!no_comp)
412                 printf("Executed ast_walk_contexts();\n");
413         return 0;
414 }
415
416 void ast_cli_unregister_multiple(void)
417 {
418         if(!no_comp)
419                 printf("Executed ast_cli_unregister_multiple();\n");
420 }
421
422 void ast_context_destroy(void)
423 {
424         if( !no_comp)
425                 printf("Executed ast_context_destroy();\n");
426 }
427
428 const char *ast_get_context_name(struct ast_context *con);
429 const char *ast_get_context_name(struct ast_context *con)
430 {
431         return con ? con->name : NULL;
432 }
433
434 struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten);
435 struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
436 {
437         return NULL;
438 }
439
440 struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc);
441 struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc)
442 {
443         return NULL;
444 }
445
446 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip);
447 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip)
448 {
449         return NULL;
450 }
451
452 struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw);
453 struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw)
454 {
455         return NULL;
456 }
457
458 void filter_leading_space_from_exprs(char *str)
459 {
460         /*  Mainly for aesthetics */
461         char *t, *v, *u = str;
462         
463         while ( u && *u ) {
464
465                 if( *u == '$' && *(u+1) == '[' ) {
466                         t = u+2;
467                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
468                                 v = t;
469                                 while ( *v ) {
470                                         *v = *(v+1);
471                                         v++;
472                                 }
473                         }
474                 }
475                 
476                 u++;
477         }
478 }
479
480 void filter_newlines(char *str)
481 {
482         /* remove all newlines, returns  */
483         char *t=str;
484         while( t && *t ) {
485                 if( *t == '\n' || *t == '\r' ) {
486                         *t = ' '; /* just replace newlines and returns with spaces; they act as
487                                                  token separators, and just blindly removing them could be
488                                                  harmful. */
489                 }
490                 t++;
491         }
492 }
493
494
495 extern struct module_symbols mod_data;
496 int ael_external_load_module(void);
497
498
499 int main(int argc, char **argv)
500 {
501         int i;
502         struct namelist *n;
503         struct ast_context *lp,*lp2;
504         
505         for(i=1;i<argc;i++) {
506                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
507                         no_comp =1;
508                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
509                         quiet = 1;
510                         no_comp =1;
511                 }
512                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
513                         use_curr_dir =1;
514                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
515                         dump_extensions =1;
516         }
517         
518         if( !quiet ) {
519                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
520                 if( !no_comp )
521                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
522                 if( !use_curr_dir )
523                         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");
524                 if( !dump_extensions )
525                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
526         }
527
528         if( use_curr_dir ) {
529                 strcpy(config_dir, ".");
530                 localized_use_local_dir();
531         }
532         else {
533                 strcpy(config_dir, "/etc/asterisk");
534                 localized_use_conf_dir();
535         }
536         strcpy(var_dir, "/var/lib/asterisk");
537         
538         if( dump_extensions ) {
539                 dumpfile = fopen("extensions.conf.aeldump","w");
540                 if( !dumpfile ) {
541                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
542                         exit(10);
543                 }
544                 
545         }
546
547         FIRST_TIME = 1;
548         
549         ael_external_load_module();
550         
551         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
552
553         if( dump_extensions && dumpfile ) {
554         
555                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
556                                                                                                                  extensions in them */
557                         if( lp->extension_count == 0 ) {
558                                 
559                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
560                                 
561                                 for(n=lp->ignorepats;n;n=n->next) {
562                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
563                                 }
564                                 for(n=lp->includes;n;n=n->next) {
565                                         fprintf(dumpfile, "include => %s\n", n->name);
566                                 }
567                                 for(n=lp->switches;n;n=n->next) {
568                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
569                                 }
570                                 for(n=lp->eswitches;n;n=n->next) {
571                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
572                                 }
573                         }
574                 }
575         }
576         
577         if( dump_extensions && dumpfile )
578                 fclose(dumpfile);
579         
580         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
581                 lp2 = lp->next;
582                 lp->next = 0;
583
584                 destroy_namelist(lp->includes);
585                 destroy_namelist(lp->ignorepats);
586                 destroy_namelist(lp->switches);
587                 destroy_namelist(lp->eswitches);
588
589                 free(lp);
590         }
591         
592     return 0;
593 }
594
595 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
596
597 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
598 {
599         return 0;
600 }
601
602 unsigned int ast_hashtab_hash_contexts(const void *obj);
603
604 unsigned int ast_hashtab_hash_contexts(const void *obj)
605 {
606         return 0;
607 }
608
609 #ifdef DEBUG_THREADS
610 #if !defined(LOW_MEMORY)
611 void ast_mark_lock_acquired(void *lock_addr)
612 {
613 }
614 #ifdef HAVE_BKTR
615 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
616 {
617 }
618
619 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
620         int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
621 {
622 }
623
624 int ast_bt_get_addresses(struct ast_bt *bt)
625 {
626         return 0;
627 }
628
629 char **ast_bt_get_symbols(void **addresses, size_t num_frames)
630 {
631         char **foo = calloc(num_frames, sizeof(char *) + 1);
632         if (foo) {
633                 int i;
634                 for (i = 0; i < num_frames; i++) {
635                         foo[i] = (char *) foo + sizeof(char *) * num_frames;
636                 }
637         }
638         return foo;
639 }
640 #else
641 void ast_remove_lock_info(void *lock_addr)
642 {
643 }
644
645 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
646         int line_num, const char *func, const char *lock_name, void *lock_addr)
647 {
648 }
649 #endif /* HAVE_BKTR */
650 #endif /* !defined(LOW_MEMORY) */
651 #endif /* DEBUG_THREADS */