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