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