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