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