fixes some memory leaks and redundant conditions
[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         free(data);
303         return 0;
304 }
305
306 void pbx_builtin_setvar(void *chan, void *data)
307 {
308         struct namelist *x = create_name(data);
309         if(!no_comp)
310                 printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
311
312         if( dump_extensions ) {
313                 x = create_name(data);
314                 ADD_LAST(globalvars,x);
315         }
316 }
317         
318
319 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
320 {
321         struct ast_context *x = calloc(1, sizeof(*x));
322         if (!x)
323                 return NULL;
324         x->next = context_list;
325         context_list = x;
326         if (!no_comp)
327                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
328         conts++;
329         strncpy(x->name, name, sizeof(x->name) - 1);
330         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
331         return x;
332 }
333
334 struct ast_context * ast_context_find_or_create(void **extcontexts, void *tab, const char *name, const char *registrar)
335 {
336         struct ast_context *x = calloc(1, sizeof(*x));
337         if (!x)
338                 return NULL;
339         x->next = context_list;
340         context_list = x;
341         if (!no_comp)
342                 printf("Executed ast_context_find_or_create(conts, name=%s, registrar=%s);\n", name, registrar);
343         conts++;
344         strncpy(x->name, name, sizeof(x->name) - 1);
345         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
346         return x;
347 }
348
349 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
350 {
351         if(!no_comp)
352                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
353         if( dump_extensions ) {
354                 struct namelist *x;
355                 x = create_name(value);
356                 ADD_LAST(con->ignorepats,x);
357         }
358 }
359
360 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
361 {
362         if(!no_comp)
363                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
364         if( dump_extensions ) {
365                 struct namelist *x;
366                 x = create_name((char*)value);
367                 ADD_LAST(con->includes,x);
368         }
369 }
370
371 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
372 {
373         if(!no_comp)
374                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
375         if( dump_extensions ) {
376                 struct namelist *x;
377                 x = create_name((char*)value);
378                 strncpy(x->name2,data,100);
379                 if( eval ) {
380
381                         ADD_LAST(con->switches,x);
382
383                 } else {
384
385                         ADD_LAST(con->eswitches,x);
386                 }
387         }
388 }
389
390 void ast_merge_contexts_and_delete(void)
391 {
392         if(!no_comp)
393                 printf("Executed ast_merge_contexts_and_delete();\n");
394 }
395
396 void ast_context_verify_includes(void)
397 {
398         if(!no_comp)
399                 printf("Executed ast_context_verify_includes();\n");
400 }
401
402 struct ast_context * ast_walk_contexts(void)
403 {
404         if(!no_comp)
405                 printf("Executed ast_walk_contexts();\n");
406         return 0;
407 }
408
409 void ast_cli_unregister_multiple(void)
410 {
411         if(!no_comp)
412                 printf("Executed ast_cli_unregister_multiple();\n");
413 }
414
415 void ast_context_destroy(void)
416 {
417         if( !no_comp)
418                 printf("Executed ast_context_destroy();\n");
419 }
420
421 void filter_leading_space_from_exprs(char *str)
422 {
423         /*  Mainly for aesthetics */
424         char *t, *v, *u = str;
425         
426         while ( u && *u ) {
427
428                 if( *u == '$' && *(u+1) == '[' ) {
429                         t = u+2;
430                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
431                                 v = t;
432                                 while ( *v ) {
433                                         *v = *(v+1);
434                                         v++;
435                                 }
436                         }
437                 }
438                 
439                 u++;
440         }
441 }
442
443 void filter_newlines(char *str)
444 {
445         /* remove all newlines, returns  */
446         char *t=str;
447         while( t && *t ) {
448                 if( *t == '\n' || *t == '\r' ) {
449                         *t = ' '; /* just replace newlines and returns with spaces; they act as
450                                                  token separators, and just blindly removing them could be
451                                                  harmful. */
452                 }
453                 t++;
454         }
455 }
456
457
458 extern struct module_symbols mod_data;
459 int ael_external_load_module(void);
460
461
462 int main(int argc, char **argv)
463 {
464         int i;
465         struct namelist *n;
466         struct ast_context *lp,*lp2;
467         
468         for(i=1;i<argc;i++) {
469                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
470                         no_comp =1;
471                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
472                         quiet = 1;
473                         no_comp =1;
474                 }
475                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
476                         use_curr_dir =1;
477                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
478                         dump_extensions =1;
479         }
480         
481         if( !quiet ) {
482                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
483                 if( !no_comp )
484                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
485                 if( !use_curr_dir )
486                         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");
487                 if( !dump_extensions )
488                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
489         }
490
491         if( use_curr_dir ) {
492                 strcpy(config_dir, ".");
493                 localized_use_local_dir();
494         }
495         else {
496                 strcpy(config_dir, "/etc/asterisk");
497                 localized_use_conf_dir();
498         }
499         strcpy(var_dir, "/var/lib/asterisk");
500         
501         if( dump_extensions ) {
502                 dumpfile = fopen("extensions.conf.aeldump","w");
503                 if( !dumpfile ) {
504                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
505                         exit(10);
506                 }
507                 
508         }
509
510         FIRST_TIME = 1;
511         
512         ael_external_load_module();
513         
514         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
515
516         if( dump_extensions && dumpfile ) {
517         
518                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
519                                                                                                                  extensions in them */
520                         if( lp->extension_count == 0 ) {
521                                 
522                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
523                                 
524                                 for(n=lp->ignorepats;n;n=n->next) {
525                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
526                                 }
527                                 for(n=lp->includes;n;n=n->next) {
528                                         fprintf(dumpfile, "include => %s\n", n->name);
529                                 }
530                                 for(n=lp->switches;n;n=n->next) {
531                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
532                                 }
533                                 for(n=lp->eswitches;n;n=n->next) {
534                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
535                                 }
536                         }
537                 }
538         }
539         
540         if( dump_extensions && dumpfile )
541                 fclose(dumpfile);
542         
543         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
544                 lp2 = lp->next;
545                 lp->next = 0;
546
547                 destroy_namelist(lp->includes);
548                 destroy_namelist(lp->ignorepats);
549                 destroy_namelist(lp->switches);
550                 destroy_namelist(lp->eswitches);
551
552                 free(lp);
553         }
554         
555     return 0;
556 }
557
558 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
559
560 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
561 {
562         return 0;
563 }
564
565 unsigned int ast_hashtab_hash_contexts(const void *obj);
566
567 unsigned int ast_hashtab_hash_contexts(const void *obj)
568 {
569         return 0;
570 }
571
572 #ifdef DEBUG_THREADS
573 #if !defined(LOW_MEMORY)
574 void ast_mark_lock_acquired(void *lock_addr)
575 {
576 }
577 #ifdef HAVE_BKTR
578 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
579 {
580 }
581
582 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
583         int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
584 {
585 }
586
587 int ast_bt_get_addresses(struct ast_bt *bt)
588 {
589         return 0;
590 }
591
592 #else
593 void ast_remove_lock_info(void *lock_addr)
594 {
595 }
596
597 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
598         int line_num, const char *func, const char *lock_name, void *lock_addr)
599 {
600 }
601 #endif /* HAVE_BKTR */
602 #endif /* !defined(LOW_MEMORY) */
603 #endif /* DEBUG_THREADS */