A possibly "horrible fix" for a "horribly broken"
[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 #include "asterisk.h"
10
11 #include <locale.h>
12 #include <ctype.h>
13 #include <regex.h>
14 #include <limits.h>
15
16 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
17
18 #include "asterisk/channel.h"
19 #include "asterisk/ast_expr.h"
20 #include "asterisk/module.h"
21 #include "asterisk/app.h"
22 #include "asterisk/lock.h"
23 #include "asterisk/hashtab.h"
24 #include "asterisk/ael_structs.h"
25 #include "asterisk/extconf.h"
26
27 int option_debug = 0;
28 int option_verbose = 0;
29 void ast_register_file_version(const char *file, const char *version) { }
30 void ast_unregister_file_version(const char *file) { }
31
32 struct ast_flags ast_compat = { 7 };
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, 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 #if !defined(LOW_MEMORY)
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 #endif
186
187 int ast_loader_register(int (*updater)(void))
188 {
189         return 1;
190 }
191
192 int ast_loader_unregister(int (*updater)(void))
193 {
194         return 1;
195 }
196 void ast_module_register(const struct ast_module_info *x)
197 {
198 }
199
200 void ast_module_unregister(const struct ast_module_info *x)
201 {
202 }
203
204
205 void ast_cli_register_multiple(void)
206 {
207         if(!no_comp)
208                 printf("Executed ast_cli_register_multiple();\n");
209 }
210
211 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
212 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
213 {
214         if (cp1 && *cp1)
215                 strncpy(cp2,cp1,AST_MAX_EXTENSION); /* Right now, this routine is ONLY being called for 
216                                                                                            a possible var substitution on extension names,
217                                                                                            so....! */
218         else
219                 *cp2 = 0;
220 }
221
222 int ast_add_extension2(struct ast_context *con,
223                         int replace, const char *extension, int priority, const char *label, const char *callerid,
224                         const char *application, void *data, void (*datad)(void *),
225                         const char *registrar)
226 {
227         priors++;
228         con->extension_count++;
229         if (strcmp(extension,last_exten) != 0) {
230                 extens++;
231                 strcpy(last_exten, extension);
232         }
233         if (!label) {
234                 label = "(null)";
235         }
236         if (!callerid) {
237                 callerid = "(null)";
238         }
239         if (!application) {
240                 application = "(null)";
241         }
242
243         if(!no_comp)
244                 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",
245                            con->name, replace, extension, priority, label, callerid, application, (data?(char*)data:"(null)"), registrar);
246
247         if( dump_extensions && dumpfile ) {
248                 struct namelist *n;
249
250                 if( FIRST_TIME ) {
251                         FIRST_TIME = 0;
252                         
253                         if( globalvars )
254                                 fprintf(dumpfile,"[globals]\n");
255                         
256                         for(n=globalvars;n;n=n->next) {
257                                 fprintf(dumpfile, "%s\n", n->name);
258                         }
259                 }
260                 
261                 /* print out each extension , possibly the context header also */
262                 if( con != last_context ) {
263                         fprintf(dumpfile,"\n\n[%s]\n", con->name);
264                         last_context = con;
265                         for(n=con->ignorepats;n;n=n->next) {
266                                 fprintf(dumpfile, "ignorepat => %s\n", n->name);
267                         }
268                         for(n=con->includes;n;n=n->next) {
269                                 fprintf(dumpfile, "include => %s\n", n->name);
270                         }
271                         for(n=con->switches;n;n=n->next) {
272                                 fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
273                         }
274                         for(n=con->eswitches;n;n=n->next) {
275                                 fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
276                         }
277                         
278                 }
279                 if( data ) {
280                         filter_newlines((char*)data);
281                         filter_leading_space_from_exprs((char*)data);
282                         /* in previous versions, commas were converted to '|' to separate
283                            args in app calls, but now, commas are used. There used to be
284                            code here to insert backslashes (escapes) before any commas
285                            that may have been embedded in the app args. This code is no more. */
286
287                         if( strcmp(label,"(null)") != 0  )
288                                 fprintf(dumpfile,"exten => %s,%d(%s),%s(%s)\n", extension, priority, label, application, (char*)data);
289                         else
290                                 fprintf(dumpfile,"exten => %s,%d,%s(%s)\n", extension, priority, application, (char*)data);
291
292                 } else {
293
294                         if( strcmp(label,"(null)") != 0  )
295                                 fprintf(dumpfile,"exten => %s,%d(%s),%s\n", extension, priority, label, application);
296                         else
297                                 fprintf(dumpfile,"exten => %s,%d,%s\n", extension, priority, application);
298                 }
299         }
300         
301         /* since add_extension2 is responsible for the malloc'd data stuff */
302         if( data )
303                 free(data);
304         return 0;
305 }
306
307 void pbx_builtin_setvar(void *chan, void *data)
308 {
309         struct namelist *x = create_name(data);
310         if(!no_comp)
311                 printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
312
313         if( dump_extensions ) {
314                 x = create_name(data);
315                 ADD_LAST(globalvars,x);
316         }
317 }
318         
319
320 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
321 {
322         struct ast_context *x = calloc(1, sizeof(*x));
323         if (!x)
324                 return NULL;
325         x->next = context_list;
326         context_list = x;
327         if (!no_comp)
328                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
329         conts++;
330         strncpy(x->name, name, sizeof(x->name) - 1);
331         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
332         return x;
333 }
334
335 struct ast_context * ast_context_find_or_create(void **extcontexts, void *tab, const char *name, const char *registrar)
336 {
337         struct ast_context *x = calloc(1, sizeof(*x));
338         if (!x)
339                 return NULL;
340         x->next = context_list;
341         context_list = x;
342         if (!no_comp)
343                 printf("Executed ast_context_find_or_create(conts, name=%s, registrar=%s);\n", name, registrar);
344         conts++;
345         strncpy(x->name, name, sizeof(x->name) - 1);
346         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
347         return x;
348 }
349
350 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
351 {
352         if(!no_comp)
353                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
354         if( dump_extensions ) {
355                 struct namelist *x;
356                 x = create_name(value);
357                 ADD_LAST(con->ignorepats,x);
358         }
359 }
360
361 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
362 {
363         if(!no_comp)
364                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
365         if( dump_extensions ) {
366                 struct namelist *x;
367                 x = create_name((char*)value);
368                 ADD_LAST(con->includes,x);
369         }
370 }
371
372 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
373 {
374         if(!no_comp)
375                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
376         if( dump_extensions ) {
377                 struct namelist *x;
378                 x = create_name((char*)value);
379                 strncpy(x->name2,data,100);
380                 if( eval ) {
381
382                         ADD_LAST(con->switches,x);
383
384                 } else {
385
386                         ADD_LAST(con->eswitches,x);
387                 }
388         }
389 }
390
391 void ast_merge_contexts_and_delete(void)
392 {
393         if(!no_comp)
394                 printf("Executed ast_merge_contexts_and_delete();\n");
395 }
396
397 void ast_context_verify_includes(void)
398 {
399         if(!no_comp)
400                 printf("Executed ast_context_verify_includes();\n");
401 }
402
403 struct ast_context * ast_walk_contexts(void)
404 {
405         if(!no_comp)
406                 printf("Executed ast_walk_contexts();\n");
407         return 0;
408 }
409
410 void ast_cli_unregister_multiple(void)
411 {
412         if(!no_comp)
413                 printf("Executed ast_cli_unregister_multiple();\n");
414 }
415
416 void ast_context_destroy(void)
417 {
418         if( !no_comp)
419                 printf("Executed ast_context_destroy();\n");
420 }
421
422 void filter_leading_space_from_exprs(char *str)
423 {
424         /*  Mainly for aesthetics */
425         char *t, *v, *u = str;
426         
427         while ( u && *u ) {
428
429                 if( *u == '$' && *(u+1) == '[' ) {
430                         t = u+2;
431                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
432                                 v = t;
433                                 while ( *v ) {
434                                         *v = *(v+1);
435                                         v++;
436                                 }
437                         }
438                 }
439                 
440                 u++;
441         }
442 }
443
444 void filter_newlines(char *str)
445 {
446         /* remove all newlines, returns  */
447         char *t=str;
448         while( t && *t ) {
449                 if( *t == '\n' || *t == '\r' ) {
450                         *t = ' '; /* just replace newlines and returns with spaces; they act as
451                                                  token separators, and just blindly removing them could be
452                                                  harmful. */
453                 }
454                 t++;
455         }
456 }
457
458
459 extern struct module_symbols mod_data;
460 int ael_external_load_module(void);
461
462
463 int main(int argc, char **argv)
464 {
465         int i;
466         struct namelist *n;
467         struct ast_context *lp,*lp2;
468         
469         for(i=1;i<argc;i++) {
470                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
471                         no_comp =1;
472                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
473                         quiet = 1;
474                         no_comp =1;
475                 }
476                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
477                         use_curr_dir =1;
478                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
479                         dump_extensions =1;
480         }
481         
482         if( !quiet ) {
483                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
484                 if( !no_comp )
485                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
486                 if( !use_curr_dir )
487                         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");
488                 if( !dump_extensions )
489                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
490         }
491
492         if( use_curr_dir ) {
493                 strcpy(config_dir, ".");
494                 localized_use_local_dir();
495         }
496         else {
497                 strcpy(config_dir, "/etc/asterisk");
498                 localized_use_conf_dir();
499         }
500         strcpy(var_dir, "/var/lib/asterisk");
501         
502         if( dump_extensions ) {
503                 dumpfile = fopen("extensions.conf.aeldump","w");
504                 if( !dumpfile ) {
505                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
506                         exit(10);
507                 }
508                 
509         }
510
511         FIRST_TIME = 1;
512         
513         ael_external_load_module();
514         
515         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
516
517         if( dump_extensions && dumpfile ) {
518         
519                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
520                                                                                                                  extensions in them */
521                         if( lp->extension_count == 0 ) {
522                                 
523                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
524                                 
525                                 for(n=lp->ignorepats;n;n=n->next) {
526                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
527                                 }
528                                 for(n=lp->includes;n;n=n->next) {
529                                         fprintf(dumpfile, "include => %s\n", n->name);
530                                 }
531                                 for(n=lp->switches;n;n=n->next) {
532                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
533                                 }
534                                 for(n=lp->eswitches;n;n=n->next) {
535                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
536                                 }
537                         }
538                 }
539         }
540         
541         if( dump_extensions && dumpfile )
542                 fclose(dumpfile);
543         
544         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
545                 lp2 = lp->next;
546                 lp->next = 0;
547
548                 destroy_namelist(lp->includes);
549                 destroy_namelist(lp->ignorepats);
550                 destroy_namelist(lp->switches);
551                 destroy_namelist(lp->eswitches);
552
553                 free(lp);
554         }
555         
556     return 0;
557 }
558
559 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
560
561 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
562 {
563         return 0;
564 }
565
566 unsigned int ast_hashtab_hash_contexts(const void *obj);
567
568 unsigned int ast_hashtab_hash_contexts(const void *obj)
569 {
570         return 0;
571 }
572
573 #ifdef DEBUG_THREADS
574 #if !defined(LOW_MEMORY)
575 void ast_mark_lock_acquired(void *lock_addr)
576 {
577 }
578 #ifdef HAVE_BKTR
579 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
580 {
581 }
582
583 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
584         int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
585 {
586 }
587
588 int ast_bt_get_addresses(struct ast_bt *bt)
589 {
590         return 0;
591 }
592
593 #else
594 void ast_remove_lock_info(void *lock_addr)
595 {
596 }
597
598 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
599         int line_num, const char *func, const char *lock_name, void *lock_addr)
600 {
601 }
602 #endif /* HAVE_BKTR */
603 #endif /* !defined(LOW_MEMORY) */
604 #endif /* DEBUG_THREADS */