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