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