Merged revisions 298960 via svnmerge from
[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 #if !defined(LOW_MEMORY)
30 void ast_register_file_version(const char *file, const char *version) { }
31 void ast_unregister_file_version(const char *file) { }
32 #endif
33
34 struct ast_flags ast_compat = { 7 };
35
36 /*** MODULEINFO
37         <depend>res_ael_share</depend>
38  ***/
39
40 struct namelist
41 {
42         char name[100];
43         char name2[100];
44         struct namelist *next;
45 };
46
47 struct ast_context 
48 {
49         int extension_count;
50         char name[100];
51         char registrar[100];
52         struct namelist *includes;
53         struct namelist *ignorepats;
54         struct namelist *switches;
55         struct namelist *eswitches;
56
57         struct namelist *includes_last;
58         struct namelist *ignorepats_last;
59         struct namelist *switches_last;
60         struct namelist *eswitches_last;
61
62         struct ast_context *next;
63 };
64
65 #define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
66
67 void destroy_namelist(struct namelist *x);
68 void destroy_namelist(struct namelist *x)
69 {
70         struct namelist *z,*z2;
71         for(z=x; z; z = z2)
72         {
73                 z2 = z->next;
74                 z->next = 0;
75                 free(z);
76         }
77 }
78
79 struct namelist *create_name(const char *name);
80 struct namelist *create_name(const char *name)
81 {
82         struct namelist *x = calloc(1, sizeof(*x));
83         if (!x)
84                 return NULL;
85         strncpy(x->name, name, sizeof(x->name) - 1);
86         return x;
87 }
88
89 struct ast_context *context_list;
90 struct ast_context *last_context;
91 struct namelist *globalvars;
92 struct namelist *globalvars_last;
93
94 int conts=0, extens=0, priors=0;
95 char last_exten[18000];
96
97 static char config_dir[PATH_MAX];
98 static char var_dir[PATH_MAX];
99 const char *ast_config_AST_CONFIG_DIR = config_dir;
100 const char *ast_config_AST_VAR_DIR = var_dir;
101
102 void ast_cli_register_multiple(void);
103 int ast_add_extension2(struct ast_context *con,
104                                            int replace, const char *extension, int priority, const char *label, const char *callerid,
105                                                 const char *application, void *data, void (*datad)(void *),
106                                            const char *registrar);
107 void pbx_builtin_setvar(void *chan, void *data);
108 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar);
109 struct ast_context * ast_context_find_or_create(void **extcontexts, void *tab, const char *name, const char *registrar);
110 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
111 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar);
112 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar);
113 void ast_merge_contexts_and_delete(void);
114 void ast_context_verify_includes(void);
115 struct ast_context * ast_walk_contexts(void);
116 void ast_cli_unregister_multiple(void);
117 void ast_context_destroy(void);
118 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...);
119 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with);
120 void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...);
121 struct ast_app *pbx_findapp(const char *app);
122 void filter_leading_space_from_exprs(char *str);
123 void filter_newlines(char *str);
124 static int quiet = 0;
125 static int no_comp = 0;
126 static int use_curr_dir = 0;
127 static int dump_extensions = 0;
128 static int FIRST_TIME = 0;
129 static FILE *dumpfile;
130
131 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
132 {
133                 va_list vars;
134                         va_start(vars,fmt);
135                         
136                                 printf("LOG: lev:%d file:%s  line:%d func: %s  ",
137                                                                    level, file, line, function);
138                                         vprintf(fmt, vars);
139                                                 fflush(stdout);
140                                                         va_end(vars);
141 }
142
143 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
144                                                                          struct ast_context *bypass,
145                                                                          struct pbx_find_info *q,
146                                                                          const char *context, 
147                                                                          const char *exten, 
148                                                                          int priority,
149                                                                          const char *label, 
150                                                                          const char *callerid, 
151                                                                          enum ext_match_t action);
152
153 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
154                                                                          struct ast_context *bypass,
155                                                                          struct pbx_find_info *q,
156                                                                          const char *context, 
157                                                                          const char *exten, 
158                                                                          int priority,
159                                                                          const char *label, 
160                                                                          const char *callerid, 
161                                                                          enum ext_match_t action)
162 {
163         return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
164 }
165
166 struct ast_app *pbx_findapp(const char *app)
167 {
168         return (struct ast_app*)1; /* so as not to trigger an error */
169 }
170
171 struct ast_custom_function *ast_custom_function_find(const char *name);
172
173
174 struct ast_custom_function *ast_custom_function_find(const char *name)
175 {
176         return 0; /* in "standalone" mode, functions are just not avail */
177 }
178
179 #if !defined(LOW_MEMORY)
180 int ast_add_profile(const char *x, uint64_t scale)
181 {
182         if (!no_comp)
183                 printf("Executed ast_add_profile();\n");
184
185         return 0;
186 }
187 #endif
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 void filter_leading_space_from_exprs(char *str)
424 {
425         /*  Mainly for aesthetics */
426         char *t, *v, *u = str;
427         
428         while ( u && *u ) {
429
430                 if( *u == '$' && *(u+1) == '[' ) {
431                         t = u+2;
432                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
433                                 v = t;
434                                 while ( *v ) {
435                                         *v = *(v+1);
436                                         v++;
437                                 }
438                         }
439                 }
440                 
441                 u++;
442         }
443 }
444
445 void filter_newlines(char *str)
446 {
447         /* remove all newlines, returns  */
448         char *t=str;
449         while( t && *t ) {
450                 if( *t == '\n' || *t == '\r' ) {
451                         *t = ' '; /* just replace newlines and returns with spaces; they act as
452                                                  token separators, and just blindly removing them could be
453                                                  harmful. */
454                 }
455                 t++;
456         }
457 }
458
459
460 extern struct module_symbols mod_data;
461 int ael_external_load_module(void);
462
463
464 int main(int argc, char **argv)
465 {
466         int i;
467         struct namelist *n;
468         struct ast_context *lp,*lp2;
469         
470         for(i=1;i<argc;i++) {
471                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
472                         no_comp =1;
473                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
474                         quiet = 1;
475                         no_comp =1;
476                 }
477                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
478                         use_curr_dir =1;
479                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
480                         dump_extensions =1;
481         }
482         
483         if( !quiet ) {
484                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
485                 if( !no_comp )
486                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
487                 if( !use_curr_dir )
488                         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");
489                 if( !dump_extensions )
490                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
491         }
492
493         if( use_curr_dir ) {
494                 strcpy(config_dir, ".");
495                 localized_use_local_dir();
496         }
497         else {
498                 strcpy(config_dir, "/etc/asterisk");
499                 localized_use_conf_dir();
500         }
501         strcpy(var_dir, "/var/lib/asterisk");
502         
503         if( dump_extensions ) {
504                 dumpfile = fopen("extensions.conf.aeldump","w");
505                 if( !dumpfile ) {
506                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
507                         exit(10);
508                 }
509                 
510         }
511
512         FIRST_TIME = 1;
513         
514         ael_external_load_module();
515         
516         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
517
518         if( dump_extensions && dumpfile ) {
519         
520                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
521                                                                                                                  extensions in them */
522                         if( lp->extension_count == 0 ) {
523                                 
524                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
525                                 
526                                 for(n=lp->ignorepats;n;n=n->next) {
527                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
528                                 }
529                                 for(n=lp->includes;n;n=n->next) {
530                                         fprintf(dumpfile, "include => %s\n", n->name);
531                                 }
532                                 for(n=lp->switches;n;n=n->next) {
533                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
534                                 }
535                                 for(n=lp->eswitches;n;n=n->next) {
536                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
537                                 }
538                         }
539                 }
540         }
541         
542         if( dump_extensions && dumpfile )
543                 fclose(dumpfile);
544         
545         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
546                 lp2 = lp->next;
547                 lp->next = 0;
548
549                 destroy_namelist(lp->includes);
550                 destroy_namelist(lp->ignorepats);
551                 destroy_namelist(lp->switches);
552                 destroy_namelist(lp->eswitches);
553
554                 free(lp);
555         }
556         
557     return 0;
558 }
559
560 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
561
562 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
563 {
564         return 0;
565 }
566
567 unsigned int ast_hashtab_hash_contexts(const void *obj);
568
569 unsigned int ast_hashtab_hash_contexts(const void *obj)
570 {
571         return 0;
572 }
573
574 #ifdef DEBUG_THREADS
575 #if !defined(LOW_MEMORY)
576 void ast_mark_lock_acquired(void *lock_addr)
577 {
578 }
579 #ifdef HAVE_BKTR
580 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
581 {
582 }
583
584 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
585         int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
586 {
587 }
588
589 int ast_bt_get_addresses(struct ast_bt *bt)
590 {
591         return 0;
592 }
593
594 char **ast_bt_get_symbols(void **addresses, size_t num_frames)
595 {
596         char **foo = calloc(num_frames, sizeof(char *) + 1);
597         if (foo) {
598                 int i;
599                 for (i = 0; i < num_frames; i++) {
600                         foo[i] = (char *) foo + sizeof(char *) * num_frames;
601                 }
602         }
603         return foo;
604 }
605 #else
606 void ast_remove_lock_info(void *lock_addr)
607 {
608 }
609
610 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
611         int line_num, const char *func, const char *lock_name, void *lock_addr)
612 {
613 }
614 #endif /* HAVE_BKTR */
615 #endif /* !defined(LOW_MEMORY) */
616 #endif /* DEBUG_THREADS */