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