Wed Jan 8 2020 09:49:49

Asterisk developer's documentation


pval.c
Go to the documentation of this file.
1 
2 /*
3  * Asterisk -- An open source telephony toolkit.
4  *
5  * Copyright (C) 2006, Digium, Inc.
6  *
7  * Steve Murphy <murf@parsetree.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*! \file
21  *
22  * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
23  *
24  */
25 
26 /*** MODULEINFO
27  <support_level>extended</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
33 
34 #include <sys/types.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <regex.h>
42 #include <sys/stat.h>
43 
44 #include "asterisk/pbx.h"
45 #include "asterisk/config.h"
46 #include "asterisk/module.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/cli.h"
49 #include "asterisk/app.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/callerid.h"
52 #include "asterisk/pval.h"
53 #include "asterisk/ael_structs.h"
54 #ifdef AAL_ARGCHECK
55 #include "asterisk/argdesc.h"
56 #endif
57 #include "asterisk/utils.h"
58 
59 extern struct ast_flags ast_compat;
60 extern int localized_pbx_load_module(void);
61 
62 static char expr_output[2096];
63 #define BUF_SIZE 2000
64 
65 /* these functions are in ../ast_expr2.fl */
66 
67 static int errs, warns;
68 static int notes;
69 #ifdef STANDALONE
70 static int extensions_dot_conf_loaded = 0;
71 #endif
72 static char *registrar = "pbx_ael";
73 
74 static pval *current_db;
77 
78 static const char *match_context;
79 static const char *match_exten;
80 static const char *match_label;
82 static int count_labels; /* true, put matcher in label counting mode */
83 static int label_count; /* labels are only meant to be counted in a context or exten */
86 struct pval *match_pval(pval *item);
87 static void check_timerange(pval *p);
88 static void check_dow(pval *DOW);
89 static void check_day(pval *DAY);
90 static void check_month(pval *MON);
91 static void check_expr2_input(pval *expr, char *str);
92 static int extension_matches(pval *here, const char *exten, const char *pattern);
93 static void check_goto(pval *item);
94 static void find_pval_goto_item(pval *item, int lev);
95 static void find_pval_gotos(pval *item, int lev);
96 static int check_break(pval *item);
97 static int check_continue(pval *item);
98 static void check_label(pval *item);
99 static void check_macro_returns(pval *macro);
100 
101 static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont);
102 static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont);
103 static void print_pval_list(FILE *fin, pval *item, int depth);
104 
105 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext);
106 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label);
107 static pval *get_goto_target(pval *item);
108 static int label_inside_case(pval *label);
109 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem);
110 static void fix_gotos_in_extensions(struct ael_extension *exten);
111 static pval *get_extension_or_contxt(pval *p);
112 static pval *get_contxt(pval *p);
113 static void remove_spaces_before_equals(char *str);
114 
115 /* PRETTY PRINTER FOR AEL: ============================================================================= */
116 
117 static void print_pval(FILE *fin, pval *item, int depth)
118 {
119  int i;
120  pval *lp;
121 
122  for (i=0; i<depth; i++) {
123  fprintf(fin, "\t"); /* depth == indentation */
124  }
125 
126  switch ( item->type ) {
127  case PV_WORD:
128  fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */
129  break;
130 
131  case PV_MACRO:
132  fprintf(fin,"macro %s(", item->u1.str);
133  for (lp=item->u2.arglist; lp; lp=lp->next) {
134  if (lp != item->u2.arglist )
135  fprintf(fin,", ");
136  fprintf(fin,"%s", lp->u1.str);
137  }
138  fprintf(fin,") {\n");
139  print_pval_list(fin,item->u3.macro_statements,depth+1);
140  for (i=0; i<depth; i++) {
141  fprintf(fin,"\t"); /* depth == indentation */
142  }
143  fprintf(fin,"};\n\n");
144  break;
145 
146  case PV_CONTEXT:
147  if ( item->u3.abstract )
148  fprintf(fin,"abstract context %s {\n", item->u1.str);
149  else
150  fprintf(fin,"context %s {\n", item->u1.str);
151  print_pval_list(fin,item->u2.statements,depth+1);
152  for (i=0; i<depth; i++) {
153  fprintf(fin,"\t"); /* depth == indentation */
154  }
155  fprintf(fin,"};\n\n");
156  break;
157 
158  case PV_MACRO_CALL:
159  fprintf(fin,"&%s(", item->u1.str);
160  for (lp=item->u2.arglist; lp; lp=lp->next) {
161  if ( lp != item->u2.arglist )
162  fprintf(fin,", ");
163  fprintf(fin,"%s", lp->u1.str);
164  }
165  fprintf(fin,");\n");
166  break;
167 
168  case PV_APPLICATION_CALL:
169  fprintf(fin,"%s(", item->u1.str);
170  for (lp=item->u2.arglist; lp; lp=lp->next) {
171  if ( lp != item->u2.arglist )
172  fprintf(fin,",");
173  fprintf(fin,"%s", lp->u1.str);
174  }
175  fprintf(fin,");\n");
176  break;
177 
178  case PV_CASE:
179  fprintf(fin,"case %s:\n", item->u1.str);
180  print_pval_list(fin,item->u2.statements, depth+1);
181  break;
182 
183  case PV_PATTERN:
184  fprintf(fin,"pattern %s:\n", item->u1.str);
185  print_pval_list(fin,item->u2.statements, depth+1);
186  break;
187 
188  case PV_DEFAULT:
189  fprintf(fin,"default:\n");
190  print_pval_list(fin,item->u2.statements, depth+1);
191  break;
192 
193  case PV_CATCH:
194  fprintf(fin,"catch %s {\n", item->u1.str);
195  print_pval_list(fin,item->u2.statements, depth+1);
196  for (i=0; i<depth; i++) {
197  fprintf(fin,"\t"); /* depth == indentation */
198  }
199  fprintf(fin,"};\n");
200  break;
201 
202  case PV_SWITCHES:
203  fprintf(fin,"switches {\n");
204  print_pval_list(fin,item->u1.list,depth+1);
205  for (i=0; i<depth; i++) {
206  fprintf(fin,"\t"); /* depth == indentation */
207  }
208  fprintf(fin,"};\n");
209  break;
210 
211  case PV_ESWITCHES:
212  fprintf(fin,"eswitches {\n");
213  print_pval_list(fin,item->u1.list,depth+1);
214  for (i=0; i<depth; i++) {
215  fprintf(fin,"\t"); /* depth == indentation */
216  }
217  fprintf(fin,"};\n");
218  break;
219 
220  case PV_INCLUDES:
221  fprintf(fin,"includes {\n");
222  for (lp=item->u1.list; lp; lp=lp->next) {
223  for (i=0; i<depth+1; i++) {
224  fprintf(fin,"\t"); /* depth == indentation */
225  }
226  fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */
227  if (lp->u2.arglist)
228  fprintf(fin,"|%s|%s|%s|%s",
229  lp->u2.arglist->u1.str,
230  lp->u2.arglist->next->u1.str,
231  lp->u2.arglist->next->next->u1.str,
232  lp->u2.arglist->next->next->next->u1.str
233  );
234  fprintf(fin,";\n"); /* usually, words are encapsulated in something else */
235  }
236 
237  for (i=0; i<depth; i++) {
238  fprintf(fin,"\t"); /* depth == indentation */
239  }
240  fprintf(fin,"};\n");
241  break;
242 
243  case PV_STATEMENTBLOCK:
244  fprintf(fin,"{\n");
245  print_pval_list(fin,item->u1.list, depth+1);
246  for (i=0; i<depth; i++) {
247  fprintf(fin,"\t"); /* depth == indentation */
248  }
249  fprintf(fin,"}\n");
250  break;
251 
252  case PV_VARDEC:
253  fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
254  break;
255 
256  case PV_LOCALVARDEC:
257  fprintf(fin,"local %s=%s;\n", item->u1.str, item->u2.val);
258  break;
259 
260  case PV_GOTO:
261  fprintf(fin,"goto %s", item->u1.list->u1.str);
262  if ( item->u1.list->next )
263  fprintf(fin,",%s", item->u1.list->next->u1.str);
264  if ( item->u1.list->next && item->u1.list->next->next )
265  fprintf(fin,",%s", item->u1.list->next->next->u1.str);
266  fprintf(fin,"\n");
267  break;
268 
269  case PV_LABEL:
270  fprintf(fin,"%s:\n", item->u1.str);
271  break;
272 
273  case PV_FOR:
274  fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
275  print_pval_list(fin,item->u4.for_statements,depth+1);
276  break;
277 
278  case PV_WHILE:
279  fprintf(fin,"while (%s)\n", item->u1.str);
280  print_pval_list(fin,item->u2.statements,depth+1);
281  break;
282 
283  case PV_BREAK:
284  fprintf(fin,"break;\n");
285  break;
286 
287  case PV_RETURN:
288  fprintf(fin,"return;\n");
289  break;
290 
291  case PV_CONTINUE:
292  fprintf(fin,"continue;\n");
293  break;
294 
295  case PV_RANDOM:
296  case PV_IFTIME:
297  case PV_IF:
298  if ( item->type == PV_IFTIME ) {
299 
300  fprintf(fin,"ifTime ( %s|%s|%s|%s )\n",
301  item->u1.list->u1.str,
302  item->u1.list->next->u1.str,
303  item->u1.list->next->next->u1.str,
304  item->u1.list->next->next->next->u1.str
305  );
306  } else if ( item->type == PV_RANDOM ) {
307  fprintf(fin,"random ( %s )\n", item->u1.str );
308  } else
309  fprintf(fin,"if ( %s )\n", item->u1.str);
310  if ( item->u2.statements && item->u2.statements->next ) {
311  for (i=0; i<depth; i++) {
312  fprintf(fin,"\t"); /* depth == indentation */
313  }
314  fprintf(fin,"{\n");
315  print_pval_list(fin,item->u2.statements,depth+1);
316  for (i=0; i<depth; i++) {
317  fprintf(fin,"\t"); /* depth == indentation */
318  }
319  if ( item->u3.else_statements )
320  fprintf(fin,"}\n");
321  else
322  fprintf(fin,"};\n");
323  } else if (item->u2.statements ) {
324  print_pval_list(fin,item->u2.statements,depth+1);
325  } else {
326  if (item->u3.else_statements )
327  fprintf(fin, " {} ");
328  else
329  fprintf(fin, " {}; ");
330  }
331  if ( item->u3.else_statements ) {
332  for (i=0; i<depth; i++) {
333  fprintf(fin,"\t"); /* depth == indentation */
334  }
335  fprintf(fin,"else\n");
336  print_pval_list(fin,item->u3.else_statements, depth);
337  }
338  break;
339 
340  case PV_SWITCH:
341  fprintf(fin,"switch( %s ) {\n", item->u1.str);
342  print_pval_list(fin,item->u2.statements,depth+1);
343  for (i=0; i<depth; i++) {
344  fprintf(fin,"\t"); /* depth == indentation */
345  }
346  fprintf(fin,"}\n");
347  break;
348 
349  case PV_EXTENSION:
350  if ( item->u4.regexten )
351  fprintf(fin, "regexten ");
352  if ( item->u3.hints )
353  fprintf(fin,"hints(%s) ", item->u3.hints);
354 
355  fprintf(fin,"%s => ", item->u1.str);
356  print_pval_list(fin,item->u2.statements,depth+1);
357  fprintf(fin,"\n");
358  break;
359 
360  case PV_IGNOREPAT:
361  fprintf(fin,"ignorepat => %s;\n", item->u1.str);
362  break;
363 
364  case PV_GLOBALS:
365  fprintf(fin,"globals {\n");
366  print_pval_list(fin,item->u1.statements,depth+1);
367  for (i=0; i<depth; i++) {
368  fprintf(fin,"\t"); /* depth == indentation */
369  }
370  fprintf(fin,"}\n");
371  break;
372  }
373 }
374 
375 static void print_pval_list(FILE *fin, pval *item, int depth)
376 {
377  pval *i;
378 
379  for (i=item; i; i=i->next) {
380  print_pval(fin, i, depth);
381  }
382 }
383 
384 void ael2_print(char *fname, pval *tree)
385 {
386  FILE *fin = fopen(fname,"w");
387  if ( !fin ) {
388  ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
389  return;
390  }
391  print_pval_list(fin, tree, 0);
392  fclose(fin);
393 }
394 
395 
396 /* EMPTY TEMPLATE FUNCS FOR AEL TRAVERSAL: ============================================================================= */
397 
398 void traverse_pval_template(pval *item, int depth);
399 void traverse_pval_item_template(pval *item, int depth);
400 
401 
402 void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy for a pretty print (indentation),
403  but you may not need it */
404 {
405  pval *lp;
406 
407  switch ( item->type ) {
408  case PV_WORD:
409  /* fields: item->u1.str == string associated with this (word). */
410  break;
411 
412  case PV_MACRO:
413  /* fields: item->u1.str == name of macro
414  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
415  item->u2.arglist->u1.str == argument
416  item->u2.arglist->next == next arg
417 
418  item->u3.macro_statements == pval list of statements in macro body.
419  */
420  for (lp=item->u2.arglist; lp; lp=lp->next) {
421 
422  }
424  break;
425 
426  case PV_CONTEXT:
427  /* fields: item->u1.str == name of context
428  item->u2.statements == pval list of statements in context body
429  item->u3.abstract == int 1 if an abstract keyword were present
430  */
432  break;
433 
434  case PV_MACRO_CALL:
435  /* fields: item->u1.str == name of macro to call
436  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
437  item->u2.arglist->u1.str == argument
438  item->u2.arglist->next == next arg
439  */
440  for (lp=item->u2.arglist; lp; lp=lp->next) {
441  }
442  break;
443 
444  case PV_APPLICATION_CALL:
445  /* fields: item->u1.str == name of application to call
446  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
447  item->u2.arglist->u1.str == argument
448  item->u2.arglist->next == next arg
449  */
450  for (lp=item->u2.arglist; lp; lp=lp->next) {
451  }
452  break;
453 
454  case PV_CASE:
455  /* fields: item->u1.str == value of case
456  item->u2.statements == pval list of statements under the case
457  */
459  break;
460 
461  case PV_PATTERN:
462  /* fields: item->u1.str == value of case
463  item->u2.statements == pval list of statements under the case
464  */
466  break;
467 
468  case PV_DEFAULT:
469  /* fields:
470  item->u2.statements == pval list of statements under the case
471  */
473  break;
474 
475  case PV_CATCH:
476  /* fields: item->u1.str == name of extension to catch
477  item->u2.statements == pval list of statements in context body
478  */
480  break;
481 
482  case PV_SWITCHES:
483  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
484  */
485  traverse_pval_item_template(item->u1.list,depth+1);
486  break;
487 
488  case PV_ESWITCHES:
489  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
490  */
491  traverse_pval_item_template(item->u1.list,depth+1);
492  break;
493 
494  case PV_INCLUDES:
495  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
496  item->u2.arglist == pval list of 4 PV_WORD elements for time values
497  */
498  traverse_pval_item_template(item->u1.list,depth+1);
499  traverse_pval_item_template(item->u2.arglist,depth+1);
500  break;
501 
502  case PV_STATEMENTBLOCK:
503  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
504  */
505  traverse_pval_item_template(item->u1.list,depth+1);
506  break;
507 
508  case PV_LOCALVARDEC:
509  case PV_VARDEC:
510  /* fields: item->u1.str == variable name
511  item->u2.val == variable value to assign
512  */
513  break;
514 
515  case PV_GOTO:
516  /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
517  item->u1.list->u1.str == where the data on a PV_WORD will always be.
518  */
519 
520  if ( item->u1.list->next )
521  ;
522  if ( item->u1.list->next && item->u1.list->next->next )
523  ;
524 
525  break;
526 
527  case PV_LABEL:
528  /* fields: item->u1.str == label name
529  */
530  break;
531 
532  case PV_FOR:
533  /* fields: item->u1.for_init == a string containing the initalizer
534  item->u2.for_test == a string containing the loop test
535  item->u3.for_inc == a string containing the loop increment
536 
537  item->u4.for_statements == a pval list of statements in the for ()
538  */
540  break;
541 
542  case PV_WHILE:
543  /* fields: item->u1.str == the while conditional, as supplied by user
544 
545  item->u2.statements == a pval list of statements in the while ()
546  */
548  break;
549 
550  case PV_BREAK:
551  /* fields: none
552  */
553  break;
554 
555  case PV_RETURN:
556  /* fields: none
557  */
558  break;
559 
560  case PV_CONTINUE:
561  /* fields: none
562  */
563  break;
564 
565  case PV_IFTIME:
566  /* fields: item->u1.list == there are 4 linked PV_WORDs here.
567 
568  item->u2.statements == a pval list of statements in the if ()
569  item->u3.else_statements == a pval list of statements in the else
570  (could be zero)
571  */
573  if ( item->u3.else_statements ) {
575  }
576  break;
577 
578  case PV_RANDOM:
579  /* fields: item->u1.str == the random number expression, as supplied by user
580 
581  item->u2.statements == a pval list of statements in the if ()
582  item->u3.else_statements == a pval list of statements in the else
583  (could be zero)
584  */
586  if ( item->u3.else_statements ) {
588  }
589  break;
590 
591  case PV_IF:
592  /* fields: item->u1.str == the if conditional, as supplied by user
593 
594  item->u2.statements == a pval list of statements in the if ()
595  item->u3.else_statements == a pval list of statements in the else
596  (could be zero)
597  */
599  if ( item->u3.else_statements ) {
601  }
602  break;
603 
604  case PV_SWITCH:
605  /* fields: item->u1.str == the switch expression
606 
607  item->u2.statements == a pval list of statements in the switch,
608  (will be case statements, most likely!)
609  */
611  break;
612 
613  case PV_EXTENSION:
614  /* fields: item->u1.str == the extension name, label, whatever it's called
615 
616  item->u2.statements == a pval list of statements in the extension
617  item->u3.hints == a char * hint argument
618  item->u4.regexten == an int boolean. non-zero says that regexten was specified
619  */
621  break;
622 
623  case PV_IGNOREPAT:
624  /* fields: item->u1.str == the ignorepat data
625  */
626  break;
627 
628  case PV_GLOBALS:
629  /* fields: item->u1.statements == pval list of statements, usually vardecs
630  */
632  break;
633  }
634 }
635 
636 void traverse_pval_template(pval *item, int depth) /* depth comes in handy for a pretty print (indentation),
637  but you may not need it */
638 {
639  pval *i;
640 
641  for (i=item; i; i=i->next) {
642  traverse_pval_item_template(i, depth);
643  }
644 }
645 
646 
647 /* SEMANTIC CHECKING FOR AEL: ============================================================================= */
648 
649 /* (not all that is syntactically legal is good! */
650 
651 
652 static void check_macro_returns(pval *macro)
653 {
654  pval *i;
655  if (!macro->u3.macro_statements)
656  {
657  pval *z = calloc(1, sizeof(struct pval));
658  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s is empty! I will insert a return.\n",
659  macro->filename, macro->startline, macro->endline, macro->u1.str);
660 
661  z->type = PV_RETURN;
662  z->startline = macro->startline;
663  z->endline = macro->endline;
664  z->startcol = macro->startcol;
665  z->endcol = macro->endcol;
666  z->filename = strdup(macro->filename);
667 
668  macro->u3.macro_statements = z;
669  return;
670  }
671  for (i=macro->u3.macro_statements; i; i=i->next) {
672  /* if the last statement in the list is not return, then insert a return there */
673  if (i->next == NULL) {
674  if (i->type != PV_RETURN) {
675  pval *z = calloc(1, sizeof(struct pval));
676  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s does not end with a return; I will insert one.\n",
677  macro->filename, macro->startline, macro->endline, macro->u1.str);
678 
679  z->type = PV_RETURN;
680  z->startline = macro->startline;
681  z->endline = macro->endline;
682  z->startcol = macro->startcol;
683  z->endcol = macro->endcol;
684  z->filename = strdup(macro->filename);
685 
686  i->next = z;
687  return;
688  }
689  }
690  }
691  return;
692 }
693 
694 
695 
696 static int extension_matches(pval *here, const char *exten, const char *pattern)
697 {
698  int err1;
699  regex_t preg;
700 
701  /* simple case, they match exactly, the pattern and exten name */
702  if (strcmp(pattern,exten) == 0)
703  return 1;
704 
705  if (pattern[0] == '_') {
706  char reg1[2000];
707  const char *p;
708  char *r = reg1;
709 
710  if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ {
711  ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
712  pattern);
713  return 0;
714  }
715  /* form a regular expression from the pattern, and then match it against exten */
716  *r++ = '^'; /* what if the extension is a pattern ?? */
717  *r++ = '_'; /* what if the extension is a pattern ?? */
718  *r++ = '?';
719  for (p=pattern+1; *p; p++) {
720  switch ( *p ) {
721  case 'X':
722  *r++ = '[';
723  *r++ = '0';
724  *r++ = '-';
725  *r++ = '9';
726  *r++ = 'X';
727  *r++ = ']';
728  break;
729 
730  case 'Z':
731  *r++ = '[';
732  *r++ = '1';
733  *r++ = '-';
734  *r++ = '9';
735  *r++ = 'Z';
736  *r++ = ']';
737  break;
738 
739  case 'N':
740  *r++ = '[';
741  *r++ = '2';
742  *r++ = '-';
743  *r++ = '9';
744  *r++ = 'N';
745  *r++ = ']';
746  break;
747 
748  case '[':
749  while ( *p && *p != ']' ) {
750  *r++ = *p++;
751  }
752  *r++ = ']';
753  if ( *p != ']') {
754  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
755  here->filename, here->startline, here->endline, pattern);
756  }
757  break;
758 
759  case '.':
760  case '!':
761  *r++ = '.';
762  *r++ = '*';
763  break;
764  case '*':
765  *r++ = '\\';
766  *r++ = '*';
767  break;
768  default:
769  *r++ = *p;
770  break;
771 
772  }
773  }
774  *r++ = '$'; /* what if the extension is a pattern ?? */
775  *r++ = *p++; /* put in the closing null */
776  err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
777  if ( err1 ) {
778  char errmess[500];
779  regerror(err1,&preg,errmess,sizeof(errmess));
780  regfree(&preg);
781  ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
782  reg1, err1);
783  return 0;
784  }
785  err1 = regexec(&preg, exten, 0, 0, 0);
786  regfree(&preg);
787 
788  if ( err1 ) {
789  /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n",
790  err1,exten, pattern, reg1); */
791  return 0; /* no match */
792  } else {
793  /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n",
794  exten, pattern); */
795  return 1;
796  }
797 
798 
799  } else {
800  if ( strcmp(exten,pattern) == 0 ) {
801  return 1;
802  } else
803  return 0;
804  }
805 }
806 
807 
808 static void check_expr2_input(pval *expr, char *str)
809 {
810  int spaces = strspn(str,"\t \n");
811  if ( !strncmp(str+spaces,"$[",2) ) {
812  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
813  expr->filename, expr->startline, expr->endline, str);
814  warns++;
815  }
816 }
817 
818 static void check_includes(pval *includes)
819 {
820  struct pval *p4;
821  for (p4=includes->u1.list; p4; p4=p4->next) {
822  /* for each context pointed to, find it, then find a context/label that matches the
823  target here! */
824  char *incl_context = p4->u1.str;
825  /* find a matching context name */
826  struct pval *that_other_context = find_context(incl_context);
827  if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
828  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
829  (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
830  includes->filename, includes->startline, includes->endline, incl_context, incl_context);
831  warns++;
832  }
833  }
834 }
835 
836 
837 static void check_timerange(pval *p)
838 {
839  char *times;
840  char *e;
841  int s1, s2;
842  int e1, e2;
843 
844  times = ast_strdupa(p->u1.str);
845 
846  /* Star is all times */
847  if (ast_strlen_zero(times) || !strcmp(times, "*")) {
848  return;
849  }
850  /* Otherwise expect a range */
851  e = strchr(times, '-');
852  if (!e) {
853  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) requires a '-' surrounded by two 24-hour times of day!\n",
854  p->filename, p->startline, p->endline, times);
855  warns++;
856  return;
857  }
858  *e = '\0';
859  e++;
860  while (*e && !isdigit(*e))
861  e++;
862  if (!*e) {
863  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
864  p->filename, p->startline, p->endline, p->u1.str);
865  warns++;
866  }
867  if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
868  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
869  p->filename, p->startline, p->endline, times);
870  warns++;
871  }
872  if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
873  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
874  p->filename, p->startline, p->endline, times);
875  warns++;
876  }
877 
878  s1 = s1 * 30 + s2/2;
879  if ((s1 < 0) || (s1 >= 24*30)) {
880  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
881  p->filename, p->startline, p->endline, times);
882  warns++;
883  }
884  e1 = e1 * 30 + e2/2;
885  if ((e1 < 0) || (e1 >= 24*30)) {
886  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
887  p->filename, p->startline, p->endline, e);
888  warns++;
889  }
890  return;
891 }
892 
893 static char *days[] =
894 {
895  "sun",
896  "mon",
897  "tue",
898  "wed",
899  "thu",
900  "fri",
901  "sat",
902 };
903 
904 /*! \brief get_dow: Get day of week */
905 static void check_dow(pval *DOW)
906 {
907  char *dow;
908  char *c;
909  /* The following line is coincidence, really! */
910  int s, e;
911 
912  dow = ast_strdupa(DOW->u1.str);
913 
914  /* Check for all days */
915  if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
916  return;
917  /* Get start and ending days */
918  c = strchr(dow, '-');
919  if (c) {
920  *c = '\0';
921  c++;
922  } else
923  c = NULL;
924  /* Find the start */
925  s = 0;
926  while ((s < 7) && strcasecmp(dow, days[s])) s++;
927  if (s >= 7) {
928  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
929  DOW->filename, DOW->startline, DOW->endline, dow);
930  warns++;
931  }
932  if (c) {
933  e = 0;
934  while ((e < 7) && strcasecmp(c, days[e])) e++;
935  if (e >= 7) {
936  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
937  DOW->filename, DOW->startline, DOW->endline, c);
938  warns++;
939  }
940  } else
941  e = s;
942 }
943 
944 static void check_day(pval *DAY)
945 {
946  char *day;
947  char *c;
948  /* The following line is coincidence, really! */
949  int s, e;
950 
951  day = ast_strdupa(DAY->u1.str);
952 
953  /* Check for all days */
954  if (ast_strlen_zero(day) || !strcmp(day, "*")) {
955  return;
956  }
957  /* Get start and ending days */
958  c = strchr(day, '-');
959  if (c) {
960  *c = '\0';
961  c++;
962  }
963  /* Find the start */
964  if (sscanf(day, "%2d", &s) != 1) {
965  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
966  DAY->filename, DAY->startline, DAY->endline, day);
967  warns++;
968  }
969  else if ((s < 1) || (s > 31)) {
970  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number in the range [1-31]!\n",
971  DAY->filename, DAY->startline, DAY->endline, day);
972  warns++;
973  }
974  s--;
975  if (c) {
976  if (sscanf(c, "%2d", &e) != 1) {
977  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
978  DAY->filename, DAY->startline, DAY->endline, c);
979  warns++;
980  }
981  else if ((e < 1) || (e > 31)) {
982  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number in the range [1-31]!\n",
983  DAY->filename, DAY->startline, DAY->endline, day);
984  warns++;
985  }
986  e--;
987  } else
988  e = s;
989 }
990 
991 static char *months[] =
992 {
993  "jan",
994  "feb",
995  "mar",
996  "apr",
997  "may",
998  "jun",
999  "jul",
1000  "aug",
1001  "sep",
1002  "oct",
1003  "nov",
1004  "dec",
1005 };
1006 
1007 static void check_month(pval *MON)
1008 {
1009  char *mon;
1010  char *c;
1011  /* The following line is coincidence, really! */
1012  int s, e;
1013 
1014  mon = ast_strdupa(MON->u1.str);
1015 
1016  /* Check for all days */
1017  if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
1018  return ;
1019  /* Get start and ending days */
1020  c = strchr(mon, '-');
1021  if (c) {
1022  *c = '\0';
1023  c++;
1024  }
1025  /* Find the start */
1026  s = 0;
1027  while ((s < 12) && strcasecmp(mon, months[s])) s++;
1028  if (s >= 12) {
1029  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
1030  MON->filename, MON->startline, MON->endline, mon);
1031  warns++;
1032  }
1033  if (c) {
1034  e = 0;
1035  while ((e < 12) && strcasecmp(mon, months[e])) e++;
1036  if (e >= 12) {
1037  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
1038  MON->filename, MON->startline, MON->endline, c);
1039  warns++;
1040  }
1041  } else
1042  e = s;
1043 }
1044 
1045 static int check_break(pval *item)
1046 {
1047  pval *p = item;
1048 
1049  while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
1050  /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
1051  no sense */
1052  if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN
1053  || p->type == PV_WHILE || p->type == PV_FOR ) {
1054  return 1;
1055  }
1056  p = p->dad;
1057  }
1058  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
1059  item->filename, item->startline, item->endline);
1060  errs++;
1061 
1062  return 0;
1063 }
1064 
1065 static int check_continue(pval *item)
1066 {
1067  pval *p = item;
1068 
1069  while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
1070  /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
1071  no sense */
1072  if( p->type == PV_WHILE || p->type == PV_FOR ) {
1073  return 1;
1074  }
1075  p = p->dad;
1076  }
1077  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
1078  item->filename, item->startline, item->endline);
1079  errs++;
1080 
1081  return 0;
1082 }
1083 
1084 static struct pval *in_macro(pval *item)
1085 {
1086  struct pval *curr;
1087  curr = item;
1088  while( curr ) {
1089  if( curr->type == PV_MACRO ) {
1090  return curr;
1091  }
1092  curr = curr->dad;
1093  }
1094  return 0;
1095 }
1096 
1097 static struct pval *in_context(pval *item)
1098 {
1099  struct pval *curr;
1100  curr = item;
1101  while( curr ) {
1102  if( curr->type == PV_MACRO || curr->type == PV_CONTEXT ) {
1103  return curr;
1104  }
1105  curr = curr->dad;
1106  }
1107  return 0;
1108 }
1109 
1110 
1111 /* general purpose goto finder */
1112 
1113 static void check_label(pval *item)
1114 {
1115  struct pval *curr;
1116  struct pval *x;
1117  int alright = 0;
1118 
1119  /* A label outside an extension just plain does not make sense! */
1120 
1121  curr = item;
1122 
1123  while( curr ) {
1124  if( curr->type == PV_MACRO || curr->type == PV_EXTENSION ) {
1125  alright = 1;
1126  break;
1127  }
1128  curr = curr->dad;
1129  }
1130  if( !alright )
1131  {
1132  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Label %s is not within an extension or macro!\n",
1133  item->filename, item->startline, item->endline, item->u1.str);
1134  errs++;
1135  }
1136 
1137 
1138  /* basically, ensure that a label is not repeated in a context. Period.
1139  The method: well, for each label, find the first label in the context
1140  with the same name. If it's not the current label, then throw an error. */
1141 
1142 
1143  /* printf("==== check_label: ====\n"); */
1144  if( !current_extension )
1145  curr = current_context;
1146  else
1147  curr = current_extension;
1148 
1149  x = find_first_label_in_current_context((char *)item->u1.str, curr);
1150  /* printf("Hey, check_label found with item = %x, and x is %x, and currcont is %x, label name is %s\n", item,x, current_context, (char *)item->u1.str); */
1151  if( x && x != item )
1152  {
1153  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
1154  item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
1155  errs++;
1156  }
1157  /* printf("<<<<< check_label: ====\n"); */
1158 }
1159 
1160 static pval *get_goto_target(pval *item)
1161 {
1162  /* just one item-- the label should be in the current extension */
1163  pval *curr_ext = get_extension_or_contxt(item); /* containing exten, or macro */
1164  pval *curr_cont;
1165 
1166  if (!item->u1.list) {
1167  return NULL;
1168  }
1169 
1170  if (!item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
1171  struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext);
1172  return x;
1173  }
1174 
1175  curr_cont = get_contxt(item);
1176 
1177  /* TWO items */
1178  if (item->u1.list->next && !item->u1.list->next->next) {
1179  if (!strstr((item->u1.list)->u1.str,"${")
1180  && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
1181  struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont);
1182  return x;
1183  }
1184  }
1185 
1186  /* All 3 items! */
1187  if (item->u1.list->next && item->u1.list->next->next) {
1188  /* all three */
1189  pval *first = item->u1.list;
1190  pval *second = item->u1.list->next;
1191  pval *third = item->u1.list->next->next;
1192 
1193  if (!strstr((item->u1.list)->u1.str,"${")
1194  && !strstr(item->u1.list->next->u1.str,"${")
1195  && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
1196  struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
1197  if (!x) {
1198 
1199  struct pval *p3;
1200  struct pval *that_context = find_context(item->u1.list->u1.str);
1201 
1202  /* the target of the goto could be in an included context!! Fancy that!! */
1203  /* look for includes in the current context */
1204  if (that_context) {
1205  for (p3=that_context->u2.statements; p3; p3=p3->next) {
1206  if (p3->type == PV_INCLUDES) {
1207  struct pval *p4;
1208  for (p4=p3->u1.list; p4; p4=p4->next) {
1209  /* for each context pointed to, find it, then find a context/label that matches the
1210  target here! */
1211  char *incl_context = p4->u1.str;
1212  /* find a matching context name */
1213  struct pval *that_other_context = find_context(incl_context);
1214  if (that_other_context) {
1215  struct pval *x3;
1216  x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
1217  if (x3) {
1218  return x3;
1219  }
1220  }
1221  }
1222  }
1223  }
1224  }
1225  }
1226  return x;
1227  }
1228  }
1229  return NULL;
1230 }
1231 
1232 static void check_goto(pval *item)
1233 {
1234  if (!item->u1.list) {
1235  return;
1236  }
1237 
1238  /* check for the target of the goto-- does it exist? */
1239  if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
1240  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n",
1241  item->filename, item->startline, item->endline);
1242  errs++;
1243  }
1244 
1245  /* just one item-- the label should be in the current extension */
1246  if (!item->u1.list->next && !strstr(item->u1.list->u1.str,"${")) {
1247  struct pval *z = get_extension_or_contxt(item);
1248  struct pval *x = 0;
1249  if (z)
1250  x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */
1251  /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n",
1252  (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */
1253  if (!x) {
1254  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n",
1255  item->filename, item->startline, item->endline, item->u1.list->u1.str);
1256  errs++;
1257  }
1258  else
1259  return;
1260  }
1261 
1262  /* TWO items */
1263  if (item->u1.list->next && !item->u1.list->next->next) {
1264  /* two items */
1265  /* printf("Calling find_label_in_current_context with args %s, %s\n",
1266  (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */
1267  if (!strstr((item->u1.list)->u1.str,"${")
1268  && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
1269  struct pval *z = get_contxt(item);
1270  struct pval *x = 0;
1271 
1272  if (z)
1273  x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
1274 
1275  if (!x) {
1276  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label '%s,%s' exists in the current context, or any of its inclusions!\n",
1277  item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
1278  errs++;
1279  }
1280  else
1281  return;
1282  }
1283  }
1284 
1285  /* All 3 items! */
1286  if (item->u1.list->next && item->u1.list->next->next) {
1287  /* all three */
1288  pval *first = item->u1.list;
1289  pval *second = item->u1.list->next;
1290  pval *third = item->u1.list->next->next;
1291 
1292  /* printf("Calling find_label_in_current_db with args %s, %s, %s\n",
1293  (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */
1294  if (!strstr((item->u1.list)->u1.str,"${")
1295  && !strstr(item->u1.list->next->u1.str,"${")
1296  && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
1297  struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
1298  if (!x) {
1299  struct pval *p3;
1300  struct pval *found = 0;
1301  struct pval *that_context = find_context(item->u1.list->u1.str);
1302 
1303  /* the target of the goto could be in an included context!! Fancy that!! */
1304  /* look for includes in the current context */
1305  if (that_context) {
1306  for (p3=that_context->u2.statements; p3; p3=p3->next) {
1307  if (p3->type == PV_INCLUDES) {
1308  struct pval *p4;
1309  for (p4=p3->u1.list; p4; p4=p4->next) {
1310  /* for each context pointed to, find it, then find a context/label that matches the
1311  target here! */
1312  char *incl_context = p4->u1.str;
1313  /* find a matching context name */
1314  struct pval *that_other_context = find_context(incl_context);
1315  if (that_other_context) {
1316  struct pval *x3;
1317  x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
1318  if (x3) {
1319  found = x3;
1320  break;
1321  }
1322  }
1323  }
1324  }
1325  }
1326  if (!found) {
1327  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n",
1328  item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
1329  errs++;
1330  } else {
1331  struct pval *mac = in_macro(item); /* is this goto inside a macro? */
1332  if( mac ) { /* yes! */
1333  struct pval *targ = in_context(found);
1334  if( mac != targ )
1335  {
1336  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
1337  item->filename, item->startline, item->endline);
1338  warns++;
1339  }
1340  }
1341  }
1342  } else {
1343  /* here is where code would go to check for target existence in extensions.conf files */
1344 #ifdef STANDALONE
1345  struct pbx_find_info pfiq = {.stacklen = 0 };
1346  extern int localized_pbx_load_module(void);
1347  /* if this is a standalone, we will need to make sure the
1348  localized load of extensions.conf is done */
1349  if (!extensions_dot_conf_loaded) {
1351  extensions_dot_conf_loaded++;
1352  }
1353 
1354  pbx_find_extension(NULL, NULL, &pfiq, first->u1.str, second->u1.str, atoi(third->u1.str),
1355  atoi(third->u1.str) ? NULL : third->u1.str, NULL,
1356  atoi(third->u1.str) ? E_MATCH : E_FINDLABEL);
1357 
1358  if (pfiq.status != STATUS_SUCCESS) {
1359  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s, not even in extensions.conf!\n",
1360  item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
1361  warns++;
1362  }
1363 #else
1364  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s in the AEL code!\n",
1365  item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
1366  warns++;
1367 #endif
1368  }
1369  } else {
1370  struct pval *mac = in_macro(item); /* is this goto inside a macro? */
1371  if( mac ) { /* yes! */
1372  struct pval *targ = in_context(x);
1373  if( mac != targ )
1374  {
1375  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
1376  item->filename, item->startline, item->endline);
1377  warns++;
1378  }
1379  }
1380  }
1381  }
1382  }
1383 }
1384 
1385 
1386 static void find_pval_goto_item(pval *item, int lev)
1387 {
1388  struct pval *p4;
1389 
1390  if (lev>100) {
1391  ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %u\n\n", item->type);
1392  return;
1393  }
1394 
1395  switch ( item->type ) {
1396  case PV_MACRO:
1397  /* fields: item->u1.str == name of macro
1398  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
1399  item->u2.arglist->u1.str == argument
1400  item->u2.arglist->next == next arg
1401 
1402  item->u3.macro_statements == pval list of statements in macro body.
1403  */
1404 
1405  /* printf("Descending into macro %s at line %d\n", item->u1.str, item->startline); */
1406  find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */
1407 
1408  break;
1409 
1410  case PV_CONTEXT:
1411  /* fields: item->u1.str == name of context
1412  item->u2.statements == pval list of statements in context body
1413  item->u3.abstract == int 1 if an abstract keyword were present
1414  */
1415  break;
1416 
1417  case PV_CASE:
1418  /* fields: item->u1.str == value of case
1419  item->u2.statements == pval list of statements under the case
1420  */
1421  /* printf("Descending into Case of %s\n", item->u1.str); */
1422  find_pval_gotos(item->u2.statements,lev+1);
1423  break;
1424 
1425  case PV_PATTERN:
1426  /* fields: item->u1.str == value of case
1427  item->u2.statements == pval list of statements under the case
1428  */
1429  /* printf("Descending into Pattern of %s\n", item->u1.str); */
1430  find_pval_gotos(item->u2.statements,lev+1);
1431  break;
1432 
1433  case PV_DEFAULT:
1434  /* fields:
1435  item->u2.statements == pval list of statements under the case
1436  */
1437  /* printf("Descending into default\n"); */
1438  find_pval_gotos(item->u2.statements,lev+1);
1439  break;
1440 
1441  case PV_CATCH:
1442  /* fields: item->u1.str == name of extension to catch
1443  item->u2.statements == pval list of statements in context body
1444  */
1445  /* printf("Descending into catch of %s\n", item->u1.str); */
1446  find_pval_gotos(item->u2.statements,lev+1);
1447  break;
1448 
1449  case PV_STATEMENTBLOCK:
1450  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
1451  */
1452  /* printf("Descending into statement block\n"); */
1453  find_pval_gotos(item->u1.list,lev+1);
1454  break;
1455 
1456  case PV_GOTO:
1457  /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
1458  item->u1.list->u1.str == where the data on a PV_WORD will always be.
1459  */
1460  check_goto(item); /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */
1461  break;
1462 
1463  case PV_INCLUDES:
1464  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
1465  */
1466  for (p4=item->u1.list; p4; p4=p4->next) {
1467  /* for each context pointed to, find it, then find a context/label that matches the
1468  target here! */
1469  char *incl_context = p4->u1.str;
1470  /* find a matching context name */
1471  struct pval *that_context = find_context(incl_context);
1472  if (that_context && that_context->u2.statements) {
1473  /* printf("Descending into include of '%s' at line %d; that_context=%s, that_context type=%d\n", incl_context, item->startline, that_context->u1.str, that_context->type); */
1474  find_pval_gotos(that_context->u2.statements,lev+1); /* keep working up the includes */
1475  }
1476  }
1477  break;
1478 
1479  case PV_FOR:
1480  /* fields: item->u1.for_init == a string containing the initalizer
1481  item->u2.for_test == a string containing the loop test
1482  item->u3.for_inc == a string containing the loop increment
1483 
1484  item->u4.for_statements == a pval list of statements in the for ()
1485  */
1486  /* printf("Descending into for at line %d\n", item->startline); */
1487  find_pval_gotos(item->u4.for_statements,lev+1);
1488  break;
1489 
1490  case PV_WHILE:
1491  /* fields: item->u1.str == the while conditional, as supplied by user
1492 
1493  item->u2.statements == a pval list of statements in the while ()
1494  */
1495  /* printf("Descending into while at line %d\n", item->startline); */
1496  find_pval_gotos(item->u2.statements,lev+1);
1497  break;
1498 
1499  case PV_RANDOM:
1500  /* fields: item->u1.str == the random number expression, as supplied by user
1501 
1502  item->u2.statements == a pval list of statements in the if ()
1503  item->u3.else_statements == a pval list of statements in the else
1504  (could be zero)
1505  fall thru to PV_IF */
1506 
1507  case PV_IFTIME:
1508  /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list
1509 
1510  item->u2.statements == a pval list of statements in the if ()
1511  item->u3.else_statements == a pval list of statements in the else
1512  (could be zero)
1513  fall thru to PV_IF*/
1514  case PV_IF:
1515  /* fields: item->u1.str == the if conditional, as supplied by user
1516 
1517  item->u2.statements == a pval list of statements in the if ()
1518  item->u3.else_statements == a pval list of statements in the else
1519  (could be zero)
1520  */
1521  /* printf("Descending into random/iftime/if at line %d\n", item->startline); */
1522  find_pval_gotos(item->u2.statements,lev+1);
1523 
1524  if (item->u3.else_statements) {
1525  /* printf("Descending into random/iftime/if's ELSE at line %d\n", item->startline); */
1526  find_pval_gotos(item->u3.else_statements,lev+1);
1527  }
1528  break;
1529 
1530  case PV_SWITCH:
1531  /* fields: item->u1.str == the switch expression
1532 
1533  item->u2.statements == a pval list of statements in the switch,
1534  (will be case statements, most likely!)
1535  */
1536  /* printf("Descending into switch at line %d\n", item->startline); */
1537  find_pval_gotos(item->u3.else_statements,lev+1);
1538  break;
1539 
1540  case PV_EXTENSION:
1541  /* fields: item->u1.str == the extension name, label, whatever it's called
1542 
1543  item->u2.statements == a pval list of statements in the extension
1544  item->u3.hints == a char * hint argument
1545  item->u4.regexten == an int boolean. non-zero says that regexten was specified
1546  */
1547 
1548  /* printf("Descending into extension %s at line %d\n", item->u1.str, item->startline); */
1549  find_pval_gotos(item->u2.statements,lev+1);
1550  break;
1551 
1552  default:
1553  break;
1554  }
1555 }
1556 
1557 static void find_pval_gotos(pval *item,int lev)
1558 {
1559  pval *i;
1560 
1561  for (i=item; i; i=i->next) {
1562  /* printf("About to call pval_goto_item, itemcount=%d, itemtype=%d\n", item_count, i->type); */
1563  find_pval_goto_item(i, lev);
1564  }
1565 }
1566 
1567 
1568 
1569 /* general purpose label finder */
1570 static struct pval *match_pval_item(pval *item)
1571 {
1572  pval *x;
1573 
1574  switch ( item->type ) {
1575  case PV_MACRO:
1576  /* fields: item->u1.str == name of macro
1577  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
1578  item->u2.arglist->u1.str == argument
1579  item->u2.arglist->next == next arg
1580 
1581  item->u3.macro_statements == pval list of statements in macro body.
1582  */
1583  /* printf(" matching in MACRO %s, match_context=%s; retoncontmtch=%d; \n", item->u1.str, match_context, return_on_context_match); */
1584  if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
1585 
1586  /* printf("MACRO: match context is: %s\n", match_context); */
1587 
1588  if (return_on_context_match && !strcmp(item->u1.str, match_context)) /* if we're just searching for a context, don't bother descending into them */ {
1589  /* printf("Returning on matching macro %s\n", match_context); */
1590  return item;
1591  }
1592 
1593 
1594  if (!return_on_context_match) {
1595  /* printf("Descending into matching macro %s/%s\n", match_context, item->u1.str); */
1596  if ((x=match_pval(item->u3.macro_statements))) {
1597  /* printf("Responded with pval match %x\n", x); */
1598  return x;
1599  }
1600  }
1601  } else {
1602  /* printf("Skipping context/macro %s\n", item->u1.str); */
1603  }
1604 
1605  break;
1606 
1607  case PV_CONTEXT:
1608  /* fields: item->u1.str == name of context
1609  item->u2.statements == pval list of statements in context body
1610  item->u3.abstract == int 1 if an abstract keyword were present
1611  */
1612  /* printf(" matching in CONTEXT\n"); */
1613  if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
1614  if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
1615  /* printf("Returning on matching context %s\n", match_context); */
1616  /* printf("non-CONTEXT: Responded with pval match %x\n", x); */
1617  return item;
1618  }
1619 
1620  if (!return_on_context_match ) {
1621  /* printf("Descending into matching context %s\n", match_context); */
1622  if ((x=match_pval(item->u2.statements))) /* if we're just searching for a context, don't bother descending into them */ {
1623  /* printf("CONTEXT: Responded with pval match %x\n", x); */
1624  return x;
1625  }
1626  }
1627  } else {
1628  /* printf("Skipping context/macro %s\n", item->u1.str); */
1629  }
1630  break;
1631 
1632  case PV_CASE:
1633  /* fields: item->u1.str == value of case
1634  item->u2.statements == pval list of statements under the case
1635  */
1636  /* printf(" matching in CASE\n"); */
1637  if ((x=match_pval(item->u2.statements))) {
1638  /* printf("CASE: Responded with pval match %x\n", x); */
1639  return x;
1640  }
1641  break;
1642 
1643  case PV_PATTERN:
1644  /* fields: item->u1.str == value of case
1645  item->u2.statements == pval list of statements under the case
1646  */
1647  /* printf(" matching in PATTERN\n"); */
1648  if ((x=match_pval(item->u2.statements))) {
1649  /* printf("PATTERN: Responded with pval match %x\n", x); */
1650  return x;
1651  }
1652  break;
1653 
1654  case PV_DEFAULT:
1655  /* fields:
1656  item->u2.statements == pval list of statements under the case
1657  */
1658  /* printf(" matching in DEFAULT\n"); */
1659  if ((x=match_pval(item->u2.statements))) {
1660  /* printf("DEFAULT: Responded with pval match %x\n", x); */
1661  return x;
1662  }
1663  break;
1664 
1665  case PV_CATCH:
1666  /* fields: item->u1.str == name of extension to catch
1667  item->u2.statements == pval list of statements in context body
1668  */
1669  /* printf(" matching in CATCH\n"); */
1670  if ((x=match_pval(item->u2.statements))) {
1671  /* printf("CATCH: Responded with pval match %x\n", x); */
1672  return x;
1673  }
1674  break;
1675 
1676  case PV_STATEMENTBLOCK:
1677  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
1678  */
1679  /* printf(" matching in STATEMENTBLOCK\n"); */
1680  if ((x=match_pval(item->u1.list))) {
1681  /* printf("STATEMENTBLOCK: Responded with pval match %x\n", x); */
1682  return x;
1683  }
1684  break;
1685 
1686  case PV_LABEL:
1687  /* fields: item->u1.str == label name
1688  */
1689  /* printf("PV_LABEL %s (cont=%s, exten=%s\n",
1690  item->u1.str, current_context->u1.str, (current_extension?current_extension->u1.str:"<macro>"));*/
1691 
1692  if (count_labels) {
1693  if (!strcmp(match_label, item->u1.str)) {
1694  label_count++;
1695  last_matched_label = item;
1696  }
1697 
1698  } else {
1699  if (!strcmp(match_label, item->u1.str)) {
1700  /* printf("LABEL: Responded with pval match %x\n", x); */
1701  return item;
1702  }
1703  }
1704  break;
1705 
1706  case PV_FOR:
1707  /* fields: item->u1.for_init == a string containing the initalizer
1708  item->u2.for_test == a string containing the loop test
1709  item->u3.for_inc == a string containing the loop increment
1710 
1711  item->u4.for_statements == a pval list of statements in the for ()
1712  */
1713  /* printf(" matching in FOR\n"); */
1714  if ((x=match_pval(item->u4.for_statements))) {
1715  /* printf("FOR: Responded with pval match %x\n", x);*/
1716  return x;
1717  }
1718  break;
1719 
1720  case PV_WHILE:
1721  /* fields: item->u1.str == the while conditional, as supplied by user
1722 
1723  item->u2.statements == a pval list of statements in the while ()
1724  */
1725  /* printf(" matching in WHILE\n"); */
1726  if ((x=match_pval(item->u2.statements))) {
1727  /* printf("WHILE: Responded with pval match %x\n", x); */
1728  return x;
1729  }
1730  break;
1731 
1732  case PV_RANDOM:
1733  /* fields: item->u1.str == the random number expression, as supplied by user
1734 
1735  item->u2.statements == a pval list of statements in the if ()
1736  item->u3.else_statements == a pval list of statements in the else
1737  (could be zero)
1738  fall thru to PV_IF */
1739 
1740  case PV_IFTIME:
1741  /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list
1742 
1743  item->u2.statements == a pval list of statements in the if ()
1744  item->u3.else_statements == a pval list of statements in the else
1745  (could be zero)
1746  fall thru to PV_IF*/
1747  case PV_IF:
1748  /* fields: item->u1.str == the if conditional, as supplied by user
1749 
1750  item->u2.statements == a pval list of statements in the if ()
1751  item->u3.else_statements == a pval list of statements in the else
1752  (could be zero)
1753  */
1754  /* printf(" matching in IF/IFTIME/RANDOM\n"); */
1755  if ((x=match_pval(item->u2.statements))) {
1756  return x;
1757  }
1758  if (item->u3.else_statements) {
1759  if ((x=match_pval(item->u3.else_statements))) {
1760  /* printf("IF/IFTIME/RANDOM: Responded with pval match %x\n", x); */
1761  return x;
1762  }
1763  }
1764  break;
1765 
1766  case PV_SWITCH:
1767  /* fields: item->u1.str == the switch expression
1768 
1769  item->u2.statements == a pval list of statements in the switch,
1770  (will be case statements, most likely!)
1771  */
1772  /* printf(" matching in SWITCH\n"); */
1773  if ((x=match_pval(item->u2.statements))) {
1774  /* printf("SWITCH: Responded with pval match %x\n", x); */
1775  return x;
1776  }
1777  break;
1778 
1779  case PV_EXTENSION:
1780  /* fields: item->u1.str == the extension name, label, whatever it's called
1781 
1782  item->u2.statements == a pval list of statements in the extension
1783  item->u3.hints == a char * hint argument
1784  item->u4.regexten == an int boolean. non-zero says that regexten was specified
1785  */
1786  /* printf(" matching in EXTENSION\n"); */
1787  if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
1788  /* printf("Descending into matching exten %s => %s\n", match_exten, item->u1.str); */
1789  if (strcmp(match_label,"1") == 0) {
1790  if (item->u2.statements) {
1791  struct pval *p5 = item->u2.statements;
1792  while (p5 && p5->type == PV_LABEL) /* find the first non-label statement in this context. If it exists, there's a "1" */
1793  p5 = p5->next;
1794  if (p5)
1795  return p5;
1796  else
1797  return 0;
1798  }
1799  else
1800  return 0;
1801  }
1802 
1803  if ((x=match_pval(item->u2.statements))) {
1804  /* printf("EXTENSION: Responded with pval match %x\n", x); */
1805  return x;
1806  }
1807  } else {
1808  /* printf("Skipping exten %s\n", item->u1.str); */
1809  }
1810  break;
1811  default:
1812  /* printf(" matching in default = %d\n", item->type); */
1813  break;
1814  }
1815  return 0;
1816 }
1817 
1818 struct pval *match_pval(pval *item)
1819 {
1820  pval *i;
1821 
1822  for (i=item; i; i=i->next) {
1823  pval *x;
1824  /* printf(" -- match pval: item %d\n", i->type); */
1825 
1826  if ((x = match_pval_item(i))) {
1827  /* printf("match_pval: returning x=%x\n", (int)x); */
1828  return x; /* cut the search short */
1829  }
1830  }
1831  return 0;
1832 }
1833 
1834 #if 0
1835 int count_labels_in_current_context(char *label)
1836 {
1837  label_count = 0;
1838  count_labels = 1;
1839  return_on_context_match = 0;
1840  match_pval(current_context->u2.statements);
1841 
1842  return label_count;
1843 }
1844 #endif
1845 
1846 struct pval *find_first_label_in_current_context(char *label, pval *curr_cont)
1847 {
1848  /* printf(" --- Got args %s, %s\n", exten, label); */
1849  struct pval *ret;
1850  struct pval *p3;
1851 
1852  count_labels = 0;
1853  return_on_context_match = 0;
1854  match_context = "*";
1855  match_exten = "*";
1856  match_label = label;
1857 
1858  ret = match_pval(curr_cont);
1859  if (ret)
1860  return ret;
1861 
1862  /* the target of the goto could be in an included context!! Fancy that!! */
1863  /* look for includes in the current context */
1864  for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
1865  if (p3->type == PV_INCLUDES) {
1866  struct pval *p4;
1867  for (p4=p3->u1.list; p4; p4=p4->next) {
1868  /* for each context pointed to, find it, then find a context/label that matches the
1869  target here! */
1870  char *incl_context = p4->u1.str;
1871  /* find a matching context name */
1872  struct pval *that_context = find_context(incl_context);
1873  if (that_context) {
1874  struct pval *x3;
1875  x3 = find_first_label_in_current_context(label, that_context);
1876  if (x3) {
1877  return x3;
1878  }
1879  }
1880  }
1881  }
1882  }
1883  return 0;
1884 }
1885 
1886 struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont)
1887 {
1888  /* printf(" --- Got args %s, %s\n", exten, label); */
1889  struct pval *ret;
1890  struct pval *p3;
1891 
1892  count_labels = 0;
1893  return_on_context_match = 0;
1894  match_context = "*";
1895  match_exten = exten;
1896  match_label = label;
1897  ret = match_pval(curr_cont->u2.statements);
1898  if (ret)
1899  return ret;
1900 
1901  /* the target of the goto could be in an included context!! Fancy that!! */
1902  /* look for includes in the current context */
1903  for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
1904  if (p3->type == PV_INCLUDES) {
1905  struct pval *p4;
1906  for (p4=p3->u1.list; p4; p4=p4->next) {
1907  /* for each context pointed to, find it, then find a context/label that matches the
1908  target here! */
1909  char *incl_context = p4->u1.str;
1910  /* find a matching context name */
1911  struct pval *that_context = find_context(incl_context);
1912  if (that_context) {
1913  struct pval *x3;
1914  x3 = find_label_in_current_context(exten, label, that_context);
1915  if (x3) {
1916  return x3;
1917  }
1918  }
1919  }
1920  }
1921  }
1922  return 0;
1923 }
1924 
1925 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext)
1926 {
1927  /* printf(" --- Got args %s\n", label); */
1928  count_labels = 0;
1929  return_on_context_match = 0;
1930  match_context = "*";
1931  match_exten = "*";
1932  match_label = label;
1933  return match_pval(curr_ext);
1934 }
1935 
1936 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label)
1937 {
1938  /* printf(" --- Got args %s, %s, %s\n", context, exten, label); */
1939  count_labels = 0;
1940  return_on_context_match = 0;
1941 
1942  match_context = context;
1943  match_exten = exten;
1944  match_label = label;
1945 
1946  return match_pval(current_db);
1947 }
1948 
1949 
1950 struct pval *find_macro(char *name)
1951 {
1952  return_on_context_match = 1;
1953  count_labels = 0;
1954  match_context = name;
1955  match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1956  match_label = "*";
1957  return match_pval(current_db);
1958 }
1959 
1960 struct pval *find_context(char *name)
1961 {
1962  return_on_context_match = 1;
1963  count_labels = 0;
1964  match_context = name;
1965  match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1966  match_label = "*";
1967  return match_pval(current_db);
1968 }
1969 
1970 int is_float(char *arg )
1971 {
1972  char *s;
1973  for (s=arg; *s; s++) {
1974  if (*s != '.' && (*s < '0' || *s > '9'))
1975  return 0;
1976  }
1977  return 1;
1978 }
1979 int is_int(char *arg )
1980 {
1981  char *s;
1982  for (s=arg; *s; s++) {
1983  if (*s < '0' || *s > '9')
1984  return 0;
1985  }
1986  return 1;
1987 }
1988 int is_empty(char *arg)
1989 {
1990  if (!arg)
1991  return 1;
1992  if (*arg == 0)
1993  return 1;
1994  while (*arg) {
1995  if (*arg != ' ' && *arg != '\t')
1996  return 0;
1997  arg++;
1998  }
1999  return 1;
2000 }
2001 
2002 #ifdef AAL_ARGCHECK
2003 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app)
2004 {
2005  struct argchoice *ac;
2006  char *opcop,*q,*p;
2007 
2008  switch (should->dtype) {
2009  case ARGD_OPTIONSET:
2010  if ( strstr(is->u1.str,"${") )
2011  return 0; /* no checking anything if there's a var reference in there! */
2012 
2013  opcop = ast_strdupa(is->u1.str);
2014 
2015  for (q=opcop;*q;q++) { /* erase the innards of X(innard) type arguments, so we don't get confused later */
2016  if ( *q == '(' ) {
2017  p = q+1;
2018  while (*p && *p != ')' )
2019  *p++ = '+';
2020  q = p+1;
2021  }
2022  }
2023 
2024  for (ac=app->opts; ac; ac=ac->next) {
2025  if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */
2026  return 0;
2027  }
2028  for (ac=app->opts; ac; ac=ac->next) {
2029  if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
2030  char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */
2031 
2032  if (p && *p == 'j') {
2033  ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n",
2034  is->filename, is->startline, is->endline, app->name);
2035  errs++;
2036  }
2037 
2038  if (p) {
2039  *p = '+';
2040  if (ac->name[1] == '(') {
2041  if (*(p+1) != '(') {
2042  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call should have an (argument), but doesn't!\n",
2043  is->filename, is->startline, is->endline, ac->name[0], app->name);
2044  warns++;
2045  }
2046  }
2047  }
2048  }
2049  }
2050  for (q=opcop; *q; q++) {
2051  if ( *q != '+' && *q != '(' && *q != ')') {
2052  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call is not available as an option!\n",
2053  is->filename, is->startline, is->endline, *q, app->name);
2054  warns++;
2055  }
2056  }
2057  return 1;
2058  break;
2059  default:
2060  return 0;
2061  }
2062 
2063 }
2064 
2065 int option_matches( struct argdesc *should, pval *is, struct argapp *app)
2066 {
2067  struct argchoice *ac;
2068  char *opcop;
2069 
2070  switch (should->dtype) {
2071  case ARGD_STRING:
2072  if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED)
2073  return 0;
2074  if (is->u1.str && strlen(is->u1.str) > 0) /* most will match */
2075  return 1;
2076  break;
2077 
2078  case ARGD_INT:
2079  if (is_int(is->u1.str))
2080  return 1;
2081  else
2082  return 0;
2083  break;
2084 
2085  case ARGD_FLOAT:
2086  if (is_float(is->u1.str))
2087  return 1;
2088  else
2089  return 0;
2090  break;
2091 
2092  case ARGD_ENUM:
2093  if( !is->u1.str || strlen(is->u1.str) == 0 )
2094  return 1; /* a null arg in the call will match an enum, I guess! */
2095  for (ac=should->choices; ac; ac=ac->next) {
2096  if (strcmp(ac->name,is->u1.str) == 0)
2097  return 1;
2098  }
2099  return 0;
2100  break;
2101 
2102  case ARGD_OPTIONSET:
2103  opcop = ast_strdupa(is->u1.str);
2104 
2105  for (ac=app->opts; ac; ac=ac->next) {
2106  if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */
2107  return 1;
2108  }
2109  for (ac=app->opts; ac; ac=ac->next) {
2110  if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
2111  char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */
2112 
2113  if (p) {
2114  *p = '+';
2115  if (ac->name[1] == '(') {
2116  if (*(p+1) == '(') {
2117  char *q = p+1;
2118  while (*q && *q != ')') {
2119  *q++ = '+';
2120  }
2121  *q = '+';
2122  }
2123  }
2124  }
2125  }
2126  }
2127  return 1;
2128  break;
2129  case ARGD_VARARG:
2130  return 1; /* matches anything */
2131  break;
2132  }
2133  return 1; /* unless some for-sure match or non-match returns, then it must be close enough ... */
2134 }
2135 #endif
2136 
2137 int check_app_args(pval* appcall, pval *arglist, struct argapp *app)
2138 {
2139 #ifdef AAL_ARGCHECK
2140  struct argdesc *ad = app->args;
2141  pval *pa;
2142  int z;
2143 
2144  for (pa = arglist; pa; pa=pa->next) {
2145  if (!ad) {
2146  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
2147  arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
2148  warns++;
2149  return 1;
2150  } else {
2151  /* find the first entry in the ad list that will match */
2152  do {
2153  if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
2154  break;
2155 
2156  z= option_matches( ad, pa, app);
2157  if (!z) {
2158  if ( !arglist )
2159  arglist=appcall;
2160 
2161  if (ad->type == ARGD_REQUIRED) {
2162  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2163  arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2164  warns++;
2165  return 1;
2166  }
2167  } else if (z && ad->dtype == ARGD_OPTIONSET) {
2168  option_matches_j( ad, pa, app);
2169  }
2170  ad = ad->next;
2171  } while (ad && !z);
2172  }
2173  }
2174  /* any app nodes left, that are not optional? */
2175  for ( ; ad; ad=ad->next) {
2176  if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
2177  if ( !arglist )
2178  arglist=appcall;
2179  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2180  arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2181  warns++;
2182  return 1;
2183  }
2184  }
2185  return 0;
2186 #else
2187  return 0;
2188 #endif
2189 }
2190 
2191 void check_switch_expr(pval *item, struct argapp *apps)
2192 {
2193 #ifdef AAL_ARGCHECK
2194  /* get and clean the variable name */
2195  char *buff1, *p;
2196  struct argapp *a,*a2;
2197  struct appsetvar *v,*v2;
2198  struct argchoice *c;
2199  pval *t;
2200 
2201  p = item->u1.str;
2202  while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
2203  p++;
2204 
2205  buff1 = ast_strdupa(p);
2206 
2207  while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
2208  buff1[strlen(buff1)-1] = 0;
2209  /* buff1 now contains the variable name */
2210  v = 0;
2211  for (a=apps; a; a=a->next) {
2212  for (v=a->setvars;v;v=v->next) {
2213  if (strcmp(v->name,buff1) == 0) {
2214  break;
2215  }
2216  }
2217  if ( v )
2218  break;
2219  }
2220  if (v && v->vals) {
2221  /* we have a match, to a variable that has a set of determined values */
2222  int def= 0;
2223  int pat = 0;
2224  int f1 = 0;
2225 
2226  /* first of all, does this switch have a default case ? */
2227  for (t=item->u2.statements; t; t=t->next) {
2228  if (t->type == PV_DEFAULT) {
2229  def =1;
2230  break;
2231  }
2232  if (t->type == PV_PATTERN) {
2233  pat++;
2234  }
2235  }
2236  if (def || pat) /* nothing to check. All cases accounted for! */
2237  return;
2238  for (c=v->vals; c; c=c->next) {
2239  f1 = 0;
2240  for (t=item->u2.statements; t; t=t->next) {
2241  if (t->type == PV_CASE || t->type == PV_PATTERN) {
2242  if (!strcmp(t->u1.str,c->name)) {
2243  f1 = 1;
2244  break;
2245  }
2246  }
2247  }
2248  if (!f1) {
2249  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
2250  item->filename, item->startline, item->endline, item->u1.str, c->name);
2251  warns++;
2252  }
2253  }
2254  /* next, is there an app call in the current exten, that would set this var? */
2255  f1 = 0;
2256  t = current_extension->u2.statements;
2257  if ( t && t->type == PV_STATEMENTBLOCK )
2258  t = t->u1.statements;
2259  for (; t && t != item; t=t->next) {
2260  if (t->type == PV_APPLICATION_CALL) {
2261  /* find the application that matches the u1.str */
2262  for (a2=apps; a2; a2=a2->next) {
2263  if (strcasecmp(a2->name, t->u1.str)==0) {
2264  for (v2=a2->setvars; v2; v2=v2->next) {
2265  if (strcmp(v2->name, buff1) == 0) {
2266  /* found an app that sets the var */
2267  f1 = 1;
2268  break;
2269  }
2270  }
2271  }
2272  if (f1)
2273  break;
2274  }
2275  }
2276  if (f1)
2277  break;
2278  }
2279 
2280  /* see if it sets the var */
2281  if (!f1) {
2282  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find an application call in this extension that sets the expression (%s) value!\n",
2283  item->filename, item->startline, item->endline, item->u1.str);
2284  warns++;
2285  }
2286  }
2287 #else
2288  pval *t,*tl=0,*p2;
2289  int def= 0;
2290 
2291  /* first of all, does this switch have a default case ? */
2292  for (t=item->u2.statements; t; t=t->next) {
2293  if (t->type == PV_DEFAULT) {
2294  def =1;
2295  break;
2296  }
2297  tl = t;
2298  }
2299  if (def) /* nothing to check. All cases accounted for! */
2300  return;
2301  /* if no default, warn and insert a default case at the end */
2302  p2 = tl->next = calloc(1, sizeof(struct pval));
2303 
2304  p2->type = PV_DEFAULT;
2305  p2->startline = tl->startline;
2306  p2->endline = tl->endline;
2307  p2->startcol = tl->startcol;
2308  p2->endcol = tl->endcol;
2309  p2->filename = strdup(tl->filename);
2310  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
2311  p2->filename, p2->startline, p2->endline);
2312  warns++;
2313 
2314 #endif
2315 }
2316 
2317 static void check_context_names(void)
2318 {
2319  pval *i,*j;
2320  for (i=current_db; i; i=i->next) {
2321  if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
2322  for (j=i->next; j; j=j->next) {
2323  if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
2324  if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
2325  {
2326  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n",
2327  i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline);
2328  warns++;
2329  }
2330  }
2331  }
2332  }
2333  }
2334 }
2335 
2336 static void check_abstract_reference(pval *abstract_context)
2337 {
2338  pval *i,*j;
2339  /* find some context includes that reference this context */
2340 
2341 
2342  /* otherwise, print out a warning */
2343  for (i=current_db; i; i=i->next) {
2344  if (i->type == PV_CONTEXT) {
2345  for (j=i->u2. statements; j; j=j->next) {
2346  if ( j->type == PV_INCLUDES ) {
2347  struct pval *p4;
2348  for (p4=j->u1.list; p4; p4=p4->next) {
2349  /* for each context pointed to, find it, then find a context/label that matches the
2350  target here! */
2351  if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
2352  return; /* found a match! */
2353  }
2354  }
2355  }
2356  }
2357  }
2358  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find a reference to this abstract context (%s) in any other context!\n",
2359  abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
2360  warns++;
2361 }
2362 
2363 
2364 void check_pval_item(pval *item, struct argapp *apps, int in_globals)
2365 {
2366  pval *lp;
2367 #ifdef AAL_ARGCHECK
2368  struct argapp *app, *found;
2369 #endif
2370  struct pval *macro_def;
2371  struct pval *app_def;
2372 
2373  char errmsg[4096];
2374  char *strp;
2375 
2376  switch (item->type) {
2377  case PV_WORD:
2378  /* fields: item->u1.str == string associated with this (word).
2379  item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
2380  break;
2381 
2382  case PV_MACRO:
2383  /* fields: item->u1.str == name of macro
2384  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
2385  item->u2.arglist->u1.str == argument
2386  item->u2.arglist->next == next arg
2387 
2388  item->u3.macro_statements == pval list of statements in macro body.
2389  */
2390  in_abstract_context = 0;
2391  current_context = item;
2392  current_extension = 0;
2393 
2394  check_macro_returns(item);
2395 
2396  for (lp=item->u2.arglist; lp; lp=lp->next) {
2397 
2398  }
2399  check_pval(item->u3.macro_statements, apps,in_globals);
2400  break;
2401 
2402  case PV_CONTEXT:
2403  /* fields: item->u1.str == name of context
2404  item->u2.statements == pval list of statements in context body
2405  item->u3.abstract == int 1 if an abstract keyword were present
2406  */
2407  current_context = item;
2408  current_extension = 0;
2409  if ( item->u3.abstract ) {
2410  in_abstract_context = 1;
2412  } else
2413  in_abstract_context = 0;
2414  check_pval(item->u2.statements, apps,in_globals);
2415  break;
2416 
2417  case PV_MACRO_CALL:
2418  /* fields: item->u1.str == name of macro to call
2419  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
2420  item->u2.arglist->u1.str == argument
2421  item->u2.arglist->next == next arg
2422  */
2423 #ifdef STANDALONE
2424  /* if this is a standalone, we will need to make sure the
2425  localized load of extensions.conf is done */
2426  if (!extensions_dot_conf_loaded) {
2428  extensions_dot_conf_loaded++;
2429  }
2430 #endif
2431  macro_def = find_macro(item->u1.str);
2432  if (!macro_def) {
2433 #ifdef STANDALONE
2434  struct pbx_find_info pfiq = {.stacklen = 0 };
2435  struct pbx_find_info pfiq2 = {.stacklen = 0 };
2436 
2437  /* look for the macro in the extensions.conf world */
2438  pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
2439 
2440  if (pfiq.status != STATUS_SUCCESS) {
2441  char namebuf2[256];
2442  snprintf(namebuf2, 256, "macro-%s", item->u1.str);
2443 
2444  /* look for the macro in the extensions.conf world */
2445  pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
2446 
2447  if (pfiq2.status == STATUS_SUCCESS) {
2448  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (macro-%s was found in the extensions.conf stuff, but we are using gosubs!)\n",
2449  item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
2450  warns++;
2451  } else {
2452  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
2453  item->filename, item->startline, item->endline, item->u1.str);
2454  warns++;
2455  }
2456  }
2457 #else
2458  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
2459  item->filename, item->startline, item->endline, item->u1.str);
2460  warns++;
2461 
2462 #endif
2463 #ifdef THIS_IS_1DOT4
2464  char namebuf2[256];
2465  snprintf(namebuf2, 256, "macro-%s", item->u1.str);
2466 
2467  /* look for the macro in the extensions.conf world */
2468  pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
2469 
2470  if (pfiq.status != STATUS_SUCCESS) {
2471  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s was not found in the AEL, nor the extensions.conf !\n",
2472  item->filename, item->startline, item->endline, item->u1.str);
2473  warns++;
2474  }
2475 
2476 #endif
2477 
2478  } else if (macro_def->type != PV_MACRO) {
2479  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
2480  item->filename, item->startline, item->endline, item->u1.str);
2481  errs++;
2482  } else {
2483  /* macro_def is a MACRO, so do the args match in number? */
2484  int hereargs = 0;
2485  int thereargs = 0;
2486 
2487  for (lp=item->u2.arglist; lp; lp=lp->next) {
2488  hereargs++;
2489  }
2490  for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
2491  thereargs++;
2492  }
2493  if (hereargs != thereargs ) {
2494  ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The macro call to %s has %d arguments, but the macro definition has %d arguments\n",
2495  item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
2496  errs++;
2497  }
2498  }
2499  break;
2500 
2501  case PV_APPLICATION_CALL:
2502  /* fields: item->u1.str == name of application to call
2503  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
2504  item->u2.arglist->u1.str == argument
2505  item->u2.arglist->next == next arg
2506  */
2507  /* Need to check to see if the application is available! */
2508  app_def = find_context(item->u1.str);
2509  if (app_def && app_def->type == PV_MACRO) {
2510  ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
2511  item->filename, item->startline, item->endline, item->u1.str);
2512  errs++;
2513  }
2514  if (strcasecmp(item->u1.str,"GotoIf") == 0
2515  || strcasecmp(item->u1.str,"GotoIfTime") == 0
2516  || strcasecmp(item->u1.str,"while") == 0
2517  || strcasecmp(item->u1.str,"endwhile") == 0
2518  || strcasecmp(item->u1.str,"random") == 0
2519  || strcasecmp(item->u1.str,"gosub") == 0
2520  || strcasecmp(item->u1.str,"gosubif") == 0
2521  || strcasecmp(item->u1.str,"continuewhile") == 0
2522  || strcasecmp(item->u1.str,"endwhile") == 0
2523  || strcasecmp(item->u1.str,"execif") == 0
2524  || strcasecmp(item->u1.str,"execiftime") == 0
2525  || strcasecmp(item->u1.str,"exitwhile") == 0
2526  || strcasecmp(item->u1.str,"goto") == 0
2527  || strcasecmp(item->u1.str,"macro") == 0
2528  || strcasecmp(item->u1.str,"macroexclusive") == 0
2529  || strcasecmp(item->u1.str,"macroif") == 0
2530  || strcasecmp(item->u1.str,"stackpop") == 0
2531  || strcasecmp(item->u1.str,"execIf") == 0 ) {
2532  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!\n",
2533  item->filename, item->startline, item->endline, item->u1.str);
2534  warns++;
2535  }
2536  if (strcasecmp(item->u1.str,"macroexit") == 0) {
2537  ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n",
2538  item->filename, item->startline, item->endline);
2539  item->type = PV_RETURN;
2540  free(item->u1.str);
2541  item->u1.str = 0;
2542  }
2543 
2544 #ifdef AAL_ARGCHECK
2545  found = 0;
2546  for (app=apps; app; app=app->next) {
2547  if (strcasecmp(app->name, item->u1.str) == 0) {
2548  found =app;
2549  break;
2550  }
2551  }
2552  if (!found) {
2553  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
2554  item->filename, item->startline, item->endline, item->u1.str);
2555  warns++;
2556  } else
2557  check_app_args(item, item->u2.arglist, app);
2558 #endif
2559  break;
2560 
2561  case PV_CASE:
2562  /* fields: item->u1.str == value of case
2563  item->u2.statements == pval list of statements under the case
2564  */
2565  /* Make sure sequence of statements under case is terminated with goto, return, or break */
2566  /* find the last statement */
2567  check_pval(item->u2.statements, apps,in_globals);
2568  break;
2569 
2570  case PV_PATTERN:
2571  /* fields: item->u1.str == value of case
2572  item->u2.statements == pval list of statements under the case
2573  */
2574  /* Make sure sequence of statements under case is terminated with goto, return, or break */
2575  /* find the last statement */
2576 
2577  check_pval(item->u2.statements, apps,in_globals);
2578  break;
2579 
2580  case PV_DEFAULT:
2581  /* fields:
2582  item->u2.statements == pval list of statements under the case
2583  */
2584 
2585  check_pval(item->u2.statements, apps,in_globals);
2586  break;
2587 
2588  case PV_CATCH:
2589  /* fields: item->u1.str == name of extension to catch
2590  item->u2.statements == pval list of statements in context body
2591  */
2592  check_pval(item->u2.statements, apps,in_globals);
2593  break;
2594 
2595  case PV_SWITCHES:
2596  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2597  */
2598  check_pval(item->u1.list, apps,in_globals);
2599  break;
2600 
2601  case PV_ESWITCHES:
2602  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2603  */
2604  check_pval(item->u1.list, apps,in_globals);
2605  break;
2606 
2607  case PV_INCLUDES:
2608  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2609  */
2610  check_pval(item->u1.list, apps,in_globals);
2611  check_includes(item);
2612  for (lp=item->u1.list; lp; lp=lp->next){
2613  char *incl_context = lp->u1.str;
2614  struct pval *that_context = find_context(incl_context);
2615 
2616  if ( lp->u2.arglist ) {
2617  check_timerange(lp->u2.arglist);
2618  check_dow(lp->u2.arglist->next);
2619  check_day(lp->u2.arglist->next->next);
2620  check_month(lp->u2.arglist->next->next->next);
2621  }
2622 
2623  if (that_context) {
2624  find_pval_gotos(that_context->u2.statements,0);
2625 
2626  }
2627  }
2628  break;
2629 
2630  case PV_STATEMENTBLOCK:
2631  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
2632  */
2633  check_pval(item->u1.list, apps,in_globals);
2634  break;
2635 
2636  case PV_VARDEC:
2637  /* fields: item->u1.str == variable name
2638  item->u2.val == variable value to assign
2639  */
2640  /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
2641  if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
2642  snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val);
2644  ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
2646  if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
2647  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2648  item->filename, item->startline, item->endline, item->u2.val);
2649  warns++;
2650  }
2651  check_expr2_input(item,item->u2.val);
2652  }
2653  break;
2654 
2655  case PV_LOCALVARDEC:
2656  /* fields: item->u1.str == variable name
2657  item->u2.val == variable value to assign
2658  */
2659  /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
2660  snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val);
2662  ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
2664  if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
2665  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2666  item->filename, item->startline, item->endline, item->u2.val);
2667  warns++;
2668  }
2669  check_expr2_input(item,item->u2.val);
2670  break;
2671 
2672  case PV_GOTO:
2673  /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
2674  item->u1.list->u1.str == where the data on a PV_WORD will always be.
2675  */
2676  /* don't check goto's in abstract contexts */
2677  if ( in_abstract_context )
2678  break;
2679 
2680  check_goto(item);
2681  break;
2682 
2683  case PV_LABEL:
2684  /* fields: item->u1.str == label name
2685  */
2686  if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
2687  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
2688  item->filename, item->startline, item->endline, item->u1.str);
2689  warns++;
2690  }
2691 
2692  check_label(item);
2693  break;
2694 
2695  case PV_FOR:
2696  /* fields: item->u1.for_init == a string containing the initalizer
2697  item->u2.for_test == a string containing the loop test
2698  item->u3.for_inc == a string containing the loop increment
2699 
2700  item->u4.for_statements == a pval list of statements in the for ()
2701  */
2702  snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.for_test);
2704 
2705  strp = strchr(item->u1.for_init, '=');
2706  if (strp) {
2707  ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
2708  }
2709  ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL);
2710  strp = strchr(item->u3.for_inc, '=');
2711  if (strp) {
2712  ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
2713  }
2714  if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
2715  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2716  item->filename, item->startline, item->endline, item->u2.for_test);
2717  warns++;
2718  }
2719  if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
2720  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2721  item->filename, item->startline, item->endline, item->u3.for_inc);
2722  warns++;
2723  }
2724  check_expr2_input(item,item->u2.for_test);
2725  check_expr2_input(item,item->u3.for_inc);
2726 
2728  check_pval(item->u4.for_statements, apps,in_globals);
2729  break;
2730 
2731  case PV_WHILE:
2732  /* fields: item->u1.str == the while conditional, as supplied by user
2733 
2734  item->u2.statements == a pval list of statements in the while ()
2735  */
2736  snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str);
2738  ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2740  if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2741  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2742  item->filename, item->startline, item->endline, item->u1.str);
2743  warns++;
2744  }
2745  check_expr2_input(item,item->u1.str);
2746  check_pval(item->u2.statements, apps,in_globals);
2747  break;
2748 
2749  case PV_BREAK:
2750  /* fields: none
2751  */
2752  check_break(item);
2753  break;
2754 
2755  case PV_RETURN:
2756  /* fields: none
2757  */
2758  break;
2759 
2760  case PV_CONTINUE:
2761  /* fields: none
2762  */
2763  check_continue(item);
2764  break;
2765 
2766  case PV_RANDOM:
2767  /* fields: item->u1.str == the random number expression, as supplied by user
2768 
2769  item->u2.statements == a pval list of statements in the if ()
2770  item->u3.else_statements == a pval list of statements in the else
2771  (could be zero)
2772  */
2773  snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str);
2775  ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2777  if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2778  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
2779  item->filename, item->startline, item->endline, item->u1.str);
2780  warns++;
2781  }
2782  check_expr2_input(item,item->u1.str);
2783  check_pval(item->u2.statements, apps,in_globals);
2784  if (item->u3.else_statements) {
2785  check_pval(item->u3.else_statements, apps,in_globals);
2786  }
2787  break;
2788 
2789  case PV_IFTIME:
2790  /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list
2791 
2792  item->u2.statements == a pval list of statements in the if ()
2793  item->u3.else_statements == a pval list of statements in the else
2794  (could be zero)
2795  */
2796  if ( item->u2.arglist ) {
2797  check_timerange(item->u1.list);
2798  check_dow(item->u1.list->next);
2799  check_day(item->u1.list->next->next);
2800  check_month(item->u1.list->next->next->next);
2801  }
2802 
2803  check_pval(item->u2.statements, apps,in_globals);
2804  if (item->u3.else_statements) {
2805  check_pval(item->u3.else_statements, apps,in_globals);
2806  }
2807  break;
2808 
2809  case PV_IF:
2810  /* fields: item->u1.str == the if conditional, as supplied by user
2811 
2812  item->u2.statements == a pval list of statements in the if ()
2813  item->u3.else_statements == a pval list of statements in the else
2814  (could be zero)
2815  */
2816  snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str);
2818  ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2820  if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2821  ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
2822  item->filename, item->startline, item->endline, item->u1.str);
2823  warns++;
2824  }
2825  check_expr2_input(item,item->u1.str);
2826  check_pval(item->u2.statements, apps,in_globals);
2827  if (item->u3.else_statements) {
2828  check_pval(item->u3.else_statements, apps,in_globals);
2829  }
2830  break;
2831 
2832  case PV_SWITCH:
2833  /* fields: item->u1.str == the switch expression
2834 
2835  item->u2.statements == a pval list of statements in the switch,
2836  (will be case statements, most likely!)
2837  */
2838  /* we can check the switch expression, see if it matches any of the app variables...
2839  if it does, then, are all the possible cases accounted for? */
2840  check_switch_expr(item, apps);
2841  check_pval(item->u2.statements, apps,in_globals);
2842  break;
2843 
2844  case PV_EXTENSION:
2845  /* fields: item->u1.str == the extension name, label, whatever it's called
2846 
2847  item->u2.statements == a pval list of statements in the extension
2848  item->u3.hints == a char * hint argument
2849  item->u4.regexten == an int boolean. non-zero says that regexten was specified
2850  */
2851  current_extension = item ;
2852 
2853  check_pval(item->u2.statements, apps,in_globals);
2854  break;
2855 
2856  case PV_IGNOREPAT:
2857  /* fields: item->u1.str == the ignorepat data
2858  */
2859  break;
2860 
2861  case PV_GLOBALS:
2862  /* fields: item->u1.statements == pval list of statements, usually vardecs
2863  */
2864  in_abstract_context = 0;
2865  check_pval(item->u1.statements, apps, 1);
2866  break;
2867  default:
2868  break;
2869  }
2870 }
2871 
2872 void check_pval(pval *item, struct argapp *apps, int in_globals)
2873 {
2874  pval *i;
2875 
2876  /* checks to do:
2877  1. Do goto's point to actual labels?
2878  2. Do macro calls reference a macro?
2879  3. Does the number of macro args match the definition?
2880  4. Is a macro call missing its & at the front?
2881  5. Application calls-- we could check syntax for existing applications,
2882  but I need some some sort of universal description bnf for a general
2883  sort of method for checking arguments, in number, maybe even type, at least.
2884  Don't want to hand code checks for hundreds of applications.
2885  */
2886 
2887  for (i=item; i; i=i->next) {
2888  check_pval_item(i,apps,in_globals);
2889  }
2890 }
2891 
2892 void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
2893 {
2894 
2895 #ifdef AAL_ARGCHECK
2896  int argapp_errs =0;
2897  char *rfilename;
2898 #endif
2899  struct argapp *apps=0;
2900 
2901  if (!item)
2902  return; /* don't check an empty tree */
2903 #ifdef AAL_ARGCHECK
2904  rfilename = ast_alloca(10 + strlen(ast_config_AST_VAR_DIR));
2905  sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
2906 
2907  apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */
2908 #endif
2909  current_db = item;
2910  errs = warns = notes = 0;
2911 
2913  check_pval(item, apps, 0);
2914 
2915 #ifdef AAL_ARGCHECK
2916  argdesc_destroy(apps); /* taketh away */
2917 #endif
2918  current_db = 0;
2919 
2920  *arg_errs = errs;
2921  *arg_warns = warns;
2922  *arg_notes = notes;
2923 }
2924 
2925 /* =============================================================================================== */
2926 /* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */
2927 /* =============================================================================================== */
2928 
2930 
2931 struct ael_priority *new_prio(void)
2932 {
2933  struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
2934  return x;
2935 }
2936 
2938 {
2939  struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
2940  return x;
2941 }
2942 
2943 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
2944 {
2945  char *p1, *p2;
2946 
2947  if (!exten->plist) {
2948  exten->plist = prio;
2949  exten->plist_last = prio;
2950  } else {
2951  exten->plist_last->next = prio;
2952  exten->plist_last = prio;
2953  }
2954  if( !prio->exten )
2955  prio->exten = exten; /* don't override the switch value */
2956  /* The following code will cause all priorities within an extension
2957  to have ${EXTEN} or ${EXTEN: replaced with ~~EXTEN~~, which is
2958  set just before the first switch in an exten. The switches
2959  will muck up the original ${EXTEN} value, so we save it away
2960  and the user accesses this copy instead. */
2961  if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
2962  while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
2963  p2 = malloc(strlen(prio->appargs)+5);
2964  *p1 = 0;
2965  strcpy(p2, prio->appargs);
2966  strcat(p2, "${~~EXTEN~~}");
2967  if (*(p1+8))
2968  strcat(p2, p1+8);
2969  free(prio->appargs);
2970  prio->appargs = p2;
2971  }
2972  while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
2973  p2 = malloc(strlen(prio->appargs)+5);
2974  *p1 = 0;
2975  strcpy(p2, prio->appargs);
2976  strcat(p2, "${~~EXTEN~~:");
2977  if (*(p1+8))
2978  strcat(p2, p1+8);
2979  free(prio->appargs);
2980  prio->appargs = p2;
2981  }
2982  }
2983 }
2984 
2986 {
2987  struct ael_extension *ne, *nen;
2988  for (ne=exten; ne; ne=nen) {
2989  struct ael_priority *pe, *pen;
2990 
2991  if (ne->name)
2992  free(ne->name);
2993 
2994  /* cidmatch fields are allocated with name, and freed when
2995  the name field is freed. Don't do a free for this field,
2996  unless you LIKE to see a crash! */
2997 
2998  if (ne->hints)
2999  free(ne->hints);
3000 
3001  for (pe=ne->plist; pe; pe=pen) {
3002  pen = pe->next;
3003  if (pe->app)
3004  free(pe->app);
3005  pe->app = 0;
3006  if (pe->appargs)
3007  free(pe->appargs);
3008  pe->appargs = 0;
3009  pe->origin = 0;
3010  pe->goto_true = 0;
3011  pe->goto_false = 0;
3012  free(pe);
3013  }
3014  nen = ne->next_exten;
3015  ne->next_exten = 0;
3016  ne->plist =0;
3017  ne->plist_last = 0;
3018  ne->next_exten = 0;
3019  ne->loop_break = 0;
3020  ne->loop_continue = 0;
3021  free(ne);
3022  }
3023 }
3024 
3025 static int label_inside_case(pval *label)
3026 {
3027  pval *p = label;
3028 
3029  while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
3030  if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
3031  return 1;
3032  }
3033 
3034  p = p->dad;
3035  }
3036  return 0;
3037 }
3038 
3039 static void linkexten(struct ael_extension *exten, struct ael_extension *add)
3040 {
3041  add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */
3042  exten->next_exten = add;
3043 }
3044 
3046 {
3047  char *p;
3048  while( str && *str && *str != '=' )
3049  {
3050  if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
3051  {
3052  p = str;
3053  while( *p )
3054  {
3055  *p = *(p+1);
3056  p++;
3057  }
3058  }
3059  else
3060  str++;
3061  }
3062 }
3063 
3064 /* =============================================================================================== */
3065 /* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */
3066 /* =============================================================================================== */
3067 
3068 static void gen_match_to_pattern(char *pattern, char *result)
3069 {
3070  /* the result will be a string that will be matched by pattern */
3071  char *p=pattern, *t=result;
3072  while (*p) {
3073  if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
3074  *t++ = '9';
3075  else if (*p == '[') {
3076  char *z = p+1;
3077  while (*z != ']')
3078  z++;
3079  if (*(z+1)== ']')
3080  z++;
3081  *t++=*(p+1); /* use the first char in the set */
3082  p = z;
3083  } else {
3084  *t++ = *p;
3085  }
3086  p++;
3087  }
3088  *t++ = 0; /* cap it off */
3089 }
3090 
3091 /* ==== a set of routines to search for a switch statement contained in the pval description */
3092 
3093 int find_switch_item(pval *item);
3094 int contains_switch(pval *item);
3095 
3096 
3098 {
3099  switch ( item->type ) {
3100  case PV_LOCALVARDEC:
3101  /* fields: item->u1.str == string associated with this (word). */
3102  break;
3103 
3104  case PV_WORD:
3105  /* fields: item->u1.str == string associated with this (word). */
3106  break;
3107 
3108  case PV_MACRO:
3109  /* fields: item->u1.str == name of macro
3110  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
3111  item->u2.arglist->u1.str == argument
3112  item->u2.arglist->next == next arg
3113 
3114  item->u3.macro_statements == pval list of statements in macro body.
3115  */
3116  /* had better not see this */
3117  if (contains_switch(item->u3.macro_statements))
3118  return 1;
3119  break;
3120 
3121  case PV_CONTEXT:
3122  /* fields: item->u1.str == name of context
3123  item->u2.statements == pval list of statements in context body
3124  item->u3.abstract == int 1 if an abstract keyword were present
3125  */
3126  /* had better not see this */
3127  if (contains_switch(item->u2.statements))
3128  return 1;
3129  break;
3130 
3131  case PV_MACRO_CALL:
3132  /* fields: item->u1.str == name of macro to call
3133  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
3134  item->u2.arglist->u1.str == argument
3135  item->u2.arglist->next == next arg
3136  */
3137  break;
3138 
3139  case PV_APPLICATION_CALL:
3140  /* fields: item->u1.str == name of application to call
3141  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
3142  item->u2.arglist->u1.str == argument
3143  item->u2.arglist->next == next arg
3144  */
3145  break;
3146 
3147  case PV_CASE:
3148  /* fields: item->u1.str == value of case
3149  item->u2.statements == pval list of statements under the case
3150  */
3151  /* had better not see this */
3152  if (contains_switch(item->u2.statements))
3153  return 1;
3154  break;
3155 
3156  case PV_PATTERN:
3157  /* fields: item->u1.str == value of case
3158  item->u2.statements == pval list of statements under the case
3159  */
3160  /* had better not see this */
3161  if (contains_switch(item->u2.statements))
3162  return 1;
3163  break;
3164 
3165  case PV_DEFAULT:
3166  /* fields:
3167  item->u2.statements == pval list of statements under the case
3168  */
3169  /* had better not see this */
3170  if (contains_switch(item->u2.statements))
3171  return 1;
3172  break;
3173 
3174  case PV_CATCH:
3175  /* fields: item->u1.str == name of extension to catch
3176  item->u2.statements == pval list of statements in context body
3177  */
3178  /* had better not see this */
3179  if (contains_switch(item->u2.statements))
3180  return 1;
3181  break;
3182 
3183  case PV_SWITCHES:
3184  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
3185  */
3186  break;
3187 
3188  case PV_ESWITCHES:
3189  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
3190  */
3191  break;
3192 
3193  case PV_INCLUDES:
3194  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
3195  item->u2.arglist == pval list of 4 PV_WORD elements for time values
3196  */
3197  break;
3198 
3199  case PV_STATEMENTBLOCK:
3200  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
3201  */
3202  if (contains_switch(item->u1.list) )
3203  return 1;
3204  break;
3205 
3206  case PV_VARDEC:
3207  /* fields: item->u1.str == variable name
3208  item->u2.val == variable value to assign
3209  */
3210  break;
3211 
3212  case PV_GOTO:
3213  /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
3214  item->u1.list->u1.str == where the data on a PV_WORD will always be.
3215  */
3216  break;
3217 
3218  case PV_LABEL:
3219  /* fields: item->u1.str == label name
3220  */
3221  break;
3222 
3223  case PV_FOR:
3224  /* fields: item->u1.for_init == a string containing the initalizer
3225  item->u2.for_test == a string containing the loop test
3226  item->u3.for_inc == a string containing the loop increment
3227 
3228  item->u4.for_statements == a pval list of statements in the for ()
3229  */
3230  if (contains_switch(item->u4.for_statements))
3231  return 1;
3232  break;
3233 
3234  case PV_WHILE:
3235  /* fields: item->u1.str == the while conditional, as supplied by user
3236 
3237  item->u2.statements == a pval list of statements in the while ()
3238  */
3239  if (contains_switch(item->u2.statements))
3240  return 1;
3241  break;
3242 
3243  case PV_BREAK:
3244  /* fields: none
3245  */
3246  break;
3247 
3248  case PV_RETURN:
3249  /* fields: none
3250  */
3251  break;
3252 
3253  case PV_CONTINUE:
3254  /* fields: none
3255  */
3256  break;
3257 
3258  case PV_IFTIME:
3259  /* fields: item->u1.list == there are 4 linked PV_WORDs here.
3260 
3261  item->u2.statements == a pval list of statements in the if ()
3262  item->u3.else_statements == a pval list of statements in the else
3263  (could be zero)
3264  */
3265  if (contains_switch(item->u2.statements))
3266  return 1;
3267  if ( item->u3.else_statements ) {
3268  if (contains_switch(item->u3.else_statements))
3269  return 1;
3270  }
3271  break;
3272 
3273  case PV_RANDOM:
3274  /* fields: item->u1.str == the random number expression, as supplied by user
3275 
3276  item->u2.statements == a pval list of statements in the if ()
3277  item->u3.else_statements == a pval list of statements in the else
3278  (could be zero)
3279  */
3280  if (contains_switch(item->u2.statements))
3281  return 1;
3282  if ( item->u3.else_statements ) {
3283  if (contains_switch(item->u3.else_statements))
3284  return 1;
3285  }
3286  break;
3287 
3288  case PV_IF:
3289  /* fields: item->u1.str == the if conditional, as supplied by user
3290 
3291  item->u2.statements == a pval list of statements in the if ()
3292  item->u3.else_statements == a pval list of statements in the else
3293  (could be zero)
3294  */
3295  if (contains_switch(item->u2.statements))
3296  return 1;
3297  if ( item->u3.else_statements ) {
3298  if (contains_switch(item->u3.else_statements))
3299  return 1;
3300  }
3301  break;
3302 
3303  case PV_SWITCH:
3304  /* fields: item->u1.str == the switch expression
3305 
3306  item->u2.statements == a pval list of statements in the switch,
3307  (will be case statements, most likely!)
3308  */
3309  return 1; /* JACKPOT */
3310  break;
3311 
3312  case PV_EXTENSION:
3313  /* fields: item->u1.str == the extension name, label, whatever it's called
3314 
3315  item->u2.statements == a pval list of statements in the extension
3316  item->u3.hints == a char * hint argument
3317  item->u4.regexten == an int boolean. non-zero says that regexten was specified
3318  */
3319  if (contains_switch(item->u2.statements))
3320  return 1;
3321  break;
3322 
3323  case PV_IGNOREPAT:
3324  /* fields: item->u1.str == the ignorepat data
3325  */
3326  break;
3327 
3328  case PV_GLOBALS:
3329  /* fields: item->u1.statements == pval list of statements, usually vardecs
3330  */
3331  break;
3332  }
3333  return 0;
3334 }
3335 
3337 {
3338  pval *i;
3339 
3340  for (i=item; i; i=i->next) {
3341  if (find_switch_item(i))
3342  return 1;
3343  }
3344  return 0;
3345 }
3346 
3347 
3348 static int gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context )
3349 {
3350  pval *p,*p2,*p3;
3351  struct ael_priority *pr;
3352  struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
3353  struct ael_priority *while_test, *while_loop, *while_end;
3354  struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
3355  struct ael_priority *if_test, *if_end, *if_skip, *if_false;
3356 #ifdef OLD_RAND_ACTION
3357  struct ael_priority *rand_test, *rand_end, *rand_skip;
3358 #endif
3359  char *buf1;
3360  char *buf2;
3361  char *new_label;
3362  char *strp, *strp2;
3363  int default_exists;
3364  int local_control_statement_count;
3365  int first;
3366  struct ael_priority *loop_break_save;
3367  struct ael_priority *loop_continue_save;
3368  struct ael_extension *switch_case,*switch_null;
3369 
3370  if (!(buf1 = malloc(BUF_SIZE))) {
3371  return -1;
3372  }
3373  if (!(buf2 = malloc(BUF_SIZE))) {
3374  return -1;
3375  }
3376  if (!(new_label = malloc(BUF_SIZE))) {
3377  return -1;
3378  }
3379 
3380  if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) {
3381  if (contains_switch(statement)) { /* only run contains_switch if you haven't checked before */
3382  if (mother_exten) {
3383  if (!mother_exten->has_switch) {
3384  for (first = 1; first >= 0; first--) {
3385  switch_set = new_prio();
3386  switch_set->type = AEL_APPCALL;
3387  if (!ast_compat_app_set) {
3388  switch_set->app = strdup("MSet");
3389  } else {
3390  switch_set->app = strdup("Set");
3391  }
3392  /* Are we likely inside a gosub subroutine? */
3393  if (!strcmp(mother_exten->name, "~~s~~") && first) {
3394  /* If we're not actually within a gosub, this will fail, but the
3395  * second time through, it will get set. If we are within gosub,
3396  * the second time through is redundant, but acceptable. */
3397  switch_set->appargs = strdup("LOCAL(~~EXTEN~~)=${EXTEN}");
3398  } else {
3399  switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
3400  first = 0;
3401  }
3402  linkprio(exten, switch_set, mother_exten);
3403  mother_exten->has_switch = 1;
3404  mother_exten->checked_switch = 1;
3405  if (exten) {
3406  exten->has_switch = 1;
3407  exten->checked_switch = 1;
3408  }
3409  }
3410  }
3411  } else if (exten) {
3412  if (!exten->has_switch) {
3413  for (first = 1; first >= 0; first--) {
3414  switch_set = new_prio();
3415  switch_set->type = AEL_APPCALL;
3416  if (!ast_compat_app_set) {
3417  switch_set->app = strdup("MSet");
3418  } else {
3419  switch_set->app = strdup("Set");
3420  }
3421  /* Are we likely inside a gosub subroutine? */
3422  if (!strcmp(exten->name, "~~s~~")) {
3423  /* If we're not actually within a gosub, this will fail, but the
3424  * second time through, it will get set. If we are within gosub,
3425  * the second time through is redundant, but acceptable. */
3426  switch_set->appargs = strdup("LOCAL(~~EXTEN~~)=${EXTEN}");
3427  } else {
3428  switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
3429  first = 0;
3430  }
3431  linkprio(exten, switch_set, mother_exten);
3432  exten->has_switch = 1;
3433  exten->checked_switch = 1;
3434  if (mother_exten) {
3435  mother_exten->has_switch = 1;
3436  mother_exten->checked_switch = 1;
3437  }
3438  }
3439  }
3440  }
3441  } else {
3442  if (mother_exten) {
3443  mother_exten->checked_switch = 1;
3444  }
3445  if (exten) {
3446  exten->checked_switch = 1;
3447  }
3448  }
3449  }
3450  for (p=statement; p; p=p->next) {
3451  switch (p->type) {
3452  case PV_VARDEC:
3453  pr = new_prio();
3454  pr->type = AEL_APPCALL;
3455  snprintf(buf1, BUF_SIZE, "%s=$[%s]", p->u1.str, p->u2.val);
3456  if (!ast_compat_app_set) {
3457  pr->app = strdup("MSet");
3458  } else {
3459  pr->app = strdup("Set");
3460  }
3462  pr->appargs = strdup(buf1);
3463  pr->origin = p;
3464  linkprio(exten, pr, mother_exten);
3465  break;
3466 
3467  case PV_LOCALVARDEC:
3468  pr = new_prio();
3469  pr->type = AEL_APPCALL;
3470  snprintf(buf1, BUF_SIZE, "LOCAL(%s)=$[%s]", p->u1.str, p->u2.val);
3471  if (!ast_compat_app_set) {
3472  pr->app = strdup("MSet");
3473  } else {
3474  pr->app = strdup("Set");
3475  }
3477  pr->appargs = strdup(buf1);
3478  pr->origin = p;
3479  linkprio(exten, pr, mother_exten);
3480  break;
3481 
3482  case PV_GOTO:
3483  pr = new_prio();
3484  pr->type = AEL_APPCALL;
3485  p->u2.goto_target = get_goto_target(p);
3486  if( p->u2.goto_target ) {
3488  }
3489 
3490  if (!p->u1.list->next) /* just one */ {
3491  pr->app = strdup("Goto");
3492  if (!mother_exten)
3493  pr->appargs = strdup(p->u1.list->u1.str);
3494  else { /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */
3495  snprintf(buf1, BUF_SIZE, "%s,%s", mother_exten->name, p->u1.list->u1.str);
3496  pr->appargs = strdup(buf1);
3497  }
3498 
3499  } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
3500  snprintf(buf1, BUF_SIZE, "%s,%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
3501  pr->app = strdup("Goto");
3502  pr->appargs = strdup(buf1);
3503  } else if (p->u1.list->next && p->u1.list->next->next) {
3504  snprintf(buf1, BUF_SIZE, "%s,%s,%s", p->u1.list->u1.str,
3505  p->u1.list->next->u1.str,
3506  p->u1.list->next->next->u1.str);
3507  pr->app = strdup("Goto");
3508  pr->appargs = strdup(buf1);
3509  }
3510  pr->origin = p;
3511  linkprio(exten, pr, mother_exten);
3512  break;
3513 
3514  case PV_LABEL:
3515  pr = new_prio();
3516  pr->type = AEL_LABEL;
3517  pr->origin = p;
3518  p->u3.compiled_label = exten;
3519  linkprio(exten, pr, mother_exten);
3520  break;
3521 
3522  case PV_FOR:
3523  control_statement_count++;
3524  loop_break_save = exten->loop_break; /* save them, then restore before leaving */
3525  loop_continue_save = exten->loop_continue;
3526  snprintf(new_label, BUF_SIZE, "for_%s_%d", label, control_statement_count);
3527  for_init = new_prio();
3528  for_inc = new_prio();
3529  for_test = new_prio();
3530  for_loop = new_prio();
3531  for_end = new_prio();
3532  for_init->type = AEL_APPCALL;
3533  for_inc->type = AEL_APPCALL;
3534  for_test->type = AEL_FOR_CONTROL;
3535  for_test->goto_false = for_end;
3536  for_loop->type = AEL_CONTROL1; /* simple goto */
3537  for_end->type = AEL_APPCALL;
3538  if (!ast_compat_app_set) {
3539  for_init->app = strdup("MSet");
3540  } else {
3541  for_init->app = strdup("Set");
3542  }
3543 
3544  strcpy(buf2,p->u1.for_init);
3546  strp = strchr(buf2, '=');
3547  if (strp) {
3548  strp2 = strchr(p->u1.for_init, '=');
3549  *(strp+1) = 0;
3550  strcat(buf2,"$[");
3551  strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
3552  strcat(buf2,"]");
3553  for_init->appargs = strdup(buf2);
3554  } else {
3555  strp2 = p->u1.for_init;
3556  while (*strp2 && isspace(*strp2))
3557  strp2++;
3558  if (*strp2 == '&') { /* itsa macro call */
3559  char *strp3 = strp2+1;
3560  while (*strp3 && isspace(*strp3))
3561  strp3++;
3562  strcpy(buf2, strp3);
3563  strp3 = strchr(buf2,'(');
3564  if (strp3) {
3565  *strp3 = '|';
3566  }
3567  while ((strp3=strchr(buf2,','))) {
3568  *strp3 = '|';
3569  }
3570  strp3 = strrchr(buf2, ')');
3571  if (strp3)
3572  *strp3 = 0; /* remove the closing paren */
3573 
3574  for_init->appargs = strdup(buf2);
3575  free(for_init->app);
3576  for_init->app = strdup("Macro");
3577  } else { /* must be a regular app call */
3578  char *strp3;
3579  strcpy(buf2, strp2);
3580  strp3 = strchr(buf2,'(');
3581  if (strp3) {
3582  *strp3 = 0;
3583  free(for_init->app);
3584  for_init->app = strdup(buf2);
3585  for_init->appargs = strdup(strp3+1);
3586  strp3 = strrchr(for_init->appargs, ')');
3587  if (strp3)
3588  *strp3 = 0; /* remove the closing paren */
3589  }
3590  }
3591  }
3592 
3593  strcpy(buf2,p->u3.for_inc);
3595  strp = strchr(buf2, '=');
3596  if (strp) { /* there's an = in this part; that means an assignment. set it up */
3597  strp2 = strchr(p->u3.for_inc, '=');
3598  *(strp+1) = 0;
3599  strcat(buf2,"$[");
3600  strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
3601  strcat(buf2,"]");
3602  for_inc->appargs = strdup(buf2);
3603  if (!ast_compat_app_set) {
3604  for_inc->app = strdup("MSet");
3605  } else {
3606  for_inc->app = strdup("Set");
3607  }
3608  } else {
3609  strp2 = p->u3.for_inc;
3610  while (*strp2 && isspace(*strp2))
3611  strp2++;
3612  if (*strp2 == '&') { /* itsa macro call */
3613  char *strp3 = strp2+1;
3614  while (*strp3 && isspace(*strp3))
3615  strp3++;
3616  strcpy(buf2, strp3);
3617  strp3 = strchr(buf2,'(');
3618  if (strp3) {
3619  *strp3 = ',';
3620  }
3621  strp3 = strrchr(buf2, ')');
3622  if (strp3)
3623  *strp3 = 0; /* remove the closing paren */
3624 
3625  for_inc->appargs = strdup(buf2);
3626 
3627  for_inc->app = strdup("Macro");
3628  } else { /* must be a regular app call */
3629  char *strp3;
3630  strcpy(buf2, strp2);
3631  strp3 = strchr(buf2,'(');
3632  if (strp3) {
3633  *strp3 = 0;
3634  for_inc->app = strdup(buf2);
3635  for_inc->appargs = strdup(strp3+1);
3636  strp3 = strrchr(for_inc->appargs, ')');
3637  if (strp3)
3638  *strp3 = 0; /* remove the closing paren */
3639  }
3640  }
3641  }
3642  snprintf(buf1, BUF_SIZE, "$[%s]",p->u2.for_test);
3643  for_test->app = 0;
3644  for_test->appargs = strdup(buf1);
3645  for_loop->goto_true = for_test;
3646  snprintf(buf1, BUF_SIZE, "Finish for_%s_%d", label, control_statement_count);
3647  for_end->app = strdup("NoOp");
3648  for_end->appargs = strdup(buf1);
3649  /* link & load! */
3650  linkprio(exten, for_init, mother_exten);
3651  linkprio(exten, for_test, mother_exten);
3652 
3653  /* now, put the body of the for loop here */
3654  exten->loop_break = for_end;
3655  exten->loop_continue = for_inc;
3656 
3657  if (gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context)) { /* this will link in all the statements here */
3658  return -1;
3659  }
3660 
3661  linkprio(exten, for_inc, mother_exten);
3662  linkprio(exten, for_loop, mother_exten);
3663  linkprio(exten, for_end, mother_exten);
3664 
3665 
3666  exten->loop_break = loop_break_save;
3667  exten->loop_continue = loop_continue_save;
3668  for_loop->origin = p;
3669  break;
3670 
3671  case PV_WHILE:
3672  control_statement_count++;
3673  loop_break_save = exten->loop_break; /* save them, then restore before leaving */
3674  loop_continue_save = exten->loop_continue;
3675  snprintf(new_label, BUF_SIZE, "while_%s_%d", label, control_statement_count);
3676  while_test = new_prio();
3677  while_loop = new_prio();
3678  while_end = new_prio();
3679  while_test->type = AEL_FOR_CONTROL;
3680  while_test->goto_false = while_end;
3681  while_loop->type = AEL_CONTROL1; /* simple goto */
3682  while_end->type = AEL_APPCALL;
3683  snprintf(buf1, BUF_SIZE, "$[%s]",p->u1.str);
3684  while_test->app = 0;
3685  while_test->appargs = strdup(buf1);
3686  while_loop->goto_true = while_test;
3687  snprintf(buf1, BUF_SIZE, "Finish while_%s_%d", label, control_statement_count);
3688  while_end->app = strdup("NoOp");
3689  while_end->appargs = strdup(buf1);
3690 
3691  linkprio(exten, while_test, mother_exten);
3692 
3693  /* now, put the body of the for loop here */
3694  exten->loop_break = while_end;
3695  exten->loop_continue = while_test;
3696 
3697  if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the while body statements here */
3698  return -1;
3699  }
3700 
3701  linkprio(exten, while_loop, mother_exten);
3702  linkprio(exten, while_end, mother_exten);
3703 
3704 
3705  exten->loop_break = loop_break_save;
3706  exten->loop_continue = loop_continue_save;
3707  while_loop->origin = p;
3708  break;
3709 
3710  case PV_SWITCH:
3711  control_statement_count++;
3712  local_control_statement_count = control_statement_count;
3713  loop_break_save = exten->loop_break; /* save them, then restore before leaving */
3714  loop_continue_save = exten->loop_continue;
3715  snprintf(new_label, BUF_SIZE, "sw_%s_%d", label, control_statement_count);
3716  switch_test = new_prio();
3717  switch_end = new_prio();
3718  switch_test->type = AEL_APPCALL;
3719  switch_end->type = AEL_APPCALL;
3720  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", control_statement_count, p->u1.str);
3721  switch_test->app = strdup("Goto");
3722  switch_test->appargs = strdup(buf1);
3723  snprintf(buf1, BUF_SIZE, "Finish switch_%s_%d", label, control_statement_count);
3724  switch_end->app = strdup("NoOp");
3725  switch_end->appargs = strdup(buf1);
3726  switch_end->origin = p;
3727  switch_end->exten = exten;
3728 
3729  linkprio(exten, switch_test, mother_exten);
3730  linkprio(exten, switch_end, mother_exten);
3731 
3732  exten->loop_break = switch_end;
3733  exten->loop_continue = 0;
3734  default_exists = 0;
3735 
3736  for (p2=p->u2.statements; p2; p2=p2->next) {
3737  /* now, for each case/default put the body of the for loop here */
3738  if (p2->type == PV_CASE) {
3739  /* ok, generate a extension and link it in */
3740  switch_case = new_exten();
3741  if (mother_exten && mother_exten->checked_switch) {
3742  switch_case->has_switch = mother_exten->has_switch;
3743  switch_case->checked_switch = mother_exten->checked_switch;
3744  }
3745  if (exten && exten->checked_switch) {
3746  switch_case->has_switch = exten->has_switch;
3747  switch_case->checked_switch = exten->checked_switch;
3748  }
3749  switch_case->context = this_context;
3750  switch_case->is_switch = 1;
3751  /* the break/continue locations are inherited from parent */
3752  switch_case->loop_break = exten->loop_break;
3753  switch_case->loop_continue = exten->loop_continue;
3754 
3755  linkexten(exten,switch_case);
3756  snprintf(buf1, BUF_SIZE, "sw_%d_%s", local_control_statement_count, p2->u1.str);
3757  switch_case->name = strdup(buf1);
3758  snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count);
3759 
3760  if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the case body statements here */
3761  return -1;
3762  }
3763 
3764  /* here is where we write code to "fall thru" to the next case... if there is one... */
3765  for (p3=p2->u2.statements; p3; p3=p3->next) {
3766  if (!p3->next)
3767  break;
3768  }
3769  /* p3 now points the last statement... */
3770  if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
3771  /* is there a following CASE/PATTERN/DEFAULT? */
3772  if (p2->next && p2->next->type == PV_CASE) {
3773  fall_thru = new_prio();
3774  fall_thru->type = AEL_APPCALL;
3775  fall_thru->app = strdup("Goto");
3776  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
3777  fall_thru->appargs = strdup(buf1);
3778  linkprio(switch_case, fall_thru, mother_exten);
3779  } else if (p2->next && p2->next->type == PV_PATTERN) {
3780  fall_thru = new_prio();
3781  fall_thru->type = AEL_APPCALL;
3782  fall_thru->app = strdup("Goto");
3783  gen_match_to_pattern(p2->next->u1.str, buf2);
3784  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
3785  fall_thru->appargs = strdup(buf1);
3786  linkprio(switch_case, fall_thru, mother_exten);
3787  } else if (p2->next && p2->next->type == PV_DEFAULT) {
3788  fall_thru = new_prio();
3789  fall_thru->type = AEL_APPCALL;
3790  fall_thru->app = strdup("Goto");
3791  snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3792  fall_thru->appargs = strdup(buf1);
3793  linkprio(switch_case, fall_thru, mother_exten);
3794  } else if (!p2->next) {
3795  fall_thru = new_prio();
3796  fall_thru->type = AEL_CONTROL1;
3797  fall_thru->goto_true = switch_end;
3798  fall_thru->app = strdup("Goto");
3799  linkprio(switch_case, fall_thru, mother_exten);
3800  }
3801  }
3802  if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
3803  char buf[2000];
3804  struct ael_priority *np2 = new_prio();
3805  np2->type = AEL_APPCALL;
3806  np2->app = strdup("NoOp");
3807  snprintf(buf, BUF_SIZE, "End of Extension %s", switch_case->name);
3808  np2->appargs = strdup(buf);
3809  linkprio(switch_case, np2, mother_exten);
3810  switch_case-> return_target = np2;
3811  }
3812  } else if (p2->type == PV_PATTERN) {
3813  /* ok, generate a extension and link it in */
3814  switch_case = new_exten();
3815  if (mother_exten && mother_exten->checked_switch) {
3816  switch_case->has_switch = mother_exten->has_switch;
3817  switch_case->checked_switch = mother_exten->checked_switch;
3818  }
3819  if (exten && exten->checked_switch) {
3820  switch_case->has_switch = exten->has_switch;
3821  switch_case->checked_switch = exten->checked_switch;
3822  }
3823  switch_case->context = this_context;
3824  switch_case->is_switch = 1;
3825  /* the break/continue locations are inherited from parent */
3826  switch_case->loop_break = exten->loop_break;
3827  switch_case->loop_continue = exten->loop_continue;
3828 
3829  linkexten(exten,switch_case);
3830  snprintf(buf1, BUF_SIZE, "_sw_%d_%s", local_control_statement_count, p2->u1.str);
3831  switch_case->name = strdup(buf1);
3832  snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count);
3833 
3834  if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the while body statements here */
3835  return -1;
3836  }
3837  /* here is where we write code to "fall thru" to the next case... if there is one... */
3838  for (p3=p2->u2.statements; p3; p3=p3->next) {
3839  if (!p3->next)
3840  break;
3841  }
3842  /* p3 now points the last statement... */
3843  if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
3844  /* is there a following CASE/PATTERN/DEFAULT? */
3845  if (p2->next && p2->next->type == PV_CASE) {
3846  fall_thru = new_prio();
3847  fall_thru->type = AEL_APPCALL;
3848  fall_thru->app = strdup("Goto");
3849  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
3850  fall_thru->appargs = strdup(buf1);
3851  linkprio(switch_case, fall_thru, mother_exten);
3852  } else if (p2->next && p2->next->type == PV_PATTERN) {
3853  fall_thru = new_prio();
3854  fall_thru->type = AEL_APPCALL;
3855  fall_thru->app = strdup("Goto");
3856  gen_match_to_pattern(p2->next->u1.str, buf2);
3857  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
3858  fall_thru->appargs = strdup(buf1);
3859  linkprio(switch_case, fall_thru, mother_exten);
3860  } else if (p2->next && p2->next->type == PV_DEFAULT) {
3861  fall_thru = new_prio();
3862  fall_thru->type = AEL_APPCALL;
3863  fall_thru->app = strdup("Goto");
3864  snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3865  fall_thru->appargs = strdup(buf1);
3866  linkprio(switch_case, fall_thru, mother_exten);
3867  } else if (!p2->next) {
3868  fall_thru = new_prio();
3869  fall_thru->type = AEL_CONTROL1;
3870  fall_thru->goto_true = switch_end;
3871  fall_thru->app = strdup("Goto");
3872  linkprio(switch_case, fall_thru, mother_exten);
3873  }
3874  }
3875  if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
3876  char buf[2000];
3877  struct ael_priority *np2 = new_prio();
3878  np2->type = AEL_APPCALL;
3879  np2->app = strdup("NoOp");
3880  snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
3881  np2->appargs = strdup(buf);
3882  linkprio(switch_case, np2, mother_exten);
3883  switch_case-> return_target = np2;
3884  }
3885  } else if (p2->type == PV_DEFAULT) {
3886  /* ok, generate a extension and link it in */
3887  switch_case = new_exten();
3888  if (mother_exten && mother_exten->checked_switch) {
3889  switch_case->has_switch = mother_exten->has_switch;
3890  switch_case->checked_switch = mother_exten->checked_switch;
3891  }
3892  if (exten && exten->checked_switch) {
3893  switch_case->has_switch = exten->has_switch;
3894  switch_case->checked_switch = exten->checked_switch;
3895  }
3896  switch_case->context = this_context;
3897  switch_case->is_switch = 1;
3898 
3899  /* new: the default case intros a pattern with ., which covers ALMOST everything.
3900  but it doesn't cover a NULL pattern. So, we'll define a null extension to match
3901  that goto's the default extension. */
3902 
3903  default_exists++;
3904  switch_null = new_exten();
3905  if (mother_exten && mother_exten->checked_switch) {
3906  switch_null->has_switch = mother_exten->has_switch;
3907  switch_null->checked_switch = mother_exten->checked_switch;
3908  }
3909  if (exten && exten->checked_switch) {
3910  switch_null->has_switch = exten->has_switch;
3911  switch_null->checked_switch = exten->checked_switch;
3912  }
3913  switch_null->context = this_context;
3914  switch_null->is_switch = 1;
3915  switch_empty = new_prio();
3916  snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3917  switch_empty->app = strdup("Goto");
3918  switch_empty->appargs = strdup(buf1);
3919  linkprio(switch_null, switch_empty, mother_exten);
3920  snprintf(buf1, BUF_SIZE, "sw_%d_", local_control_statement_count);
3921  switch_null->name = strdup(buf1);
3922  switch_null->loop_break = exten->loop_break;
3923  switch_null->loop_continue = exten->loop_continue;
3924  linkexten(exten,switch_null);
3925 
3926  /* the break/continue locations are inherited from parent */
3927  switch_case->loop_break = exten->loop_break;
3928  switch_case->loop_continue = exten->loop_continue;
3929  linkexten(exten,switch_case);
3930  snprintf(buf1, BUF_SIZE, "_sw_%d_.", local_control_statement_count);
3931  switch_case->name = strdup(buf1);
3932 
3933  snprintf(new_label, BUF_SIZE, "sw_%s_default_%d", label, local_control_statement_count);
3934 
3935  if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the default: body statements here */
3936  return -1;
3937  }
3938 
3939  /* here is where we write code to "fall thru" to the next case... if there is one... */
3940  for (p3=p2->u2.statements; p3; p3=p3->next) {
3941  if (!p3->next)
3942  break;
3943  }
3944  /* p3 now points the last statement... */
3945  if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
3946  /* is there a following CASE/PATTERN/DEFAULT? */
3947  if (p2->next && p2->next->type == PV_CASE) {
3948  fall_thru = new_prio();
3949  fall_thru->type = AEL_APPCALL;
3950  fall_thru->app = strdup("Goto");
3951  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
3952  fall_thru->appargs = strdup(buf1);
3953  linkprio(switch_case, fall_thru, mother_exten);
3954  } else if (p2->next && p2->next->type == PV_PATTERN) {
3955  fall_thru = new_prio();
3956  fall_thru->type = AEL_APPCALL;
3957  fall_thru->app = strdup("Goto");
3958  gen_match_to_pattern(p2->next->u1.str, buf2);
3959  snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
3960  fall_thru->appargs = strdup(buf1);
3961  linkprio(switch_case, fall_thru, mother_exten);
3962  } else if (p2->next && p2->next->type == PV_DEFAULT) {
3963  fall_thru = new_prio();
3964  fall_thru->type = AEL_APPCALL;
3965  fall_thru->app = strdup("Goto");
3966  snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3967  fall_thru->appargs = strdup(buf1);
3968  linkprio(switch_case, fall_thru, mother_exten);
3969  } else if (!p2->next) {
3970  fall_thru = new_prio();
3971  fall_thru->type = AEL_CONTROL1;
3972  fall_thru->goto_true = switch_end;
3973  fall_thru->app = strdup("Goto");
3974  linkprio(switch_case, fall_thru, mother_exten);
3975  }
3976  }
3977  if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
3978  char buf[2000];
3979  struct ael_priority *np2 = new_prio();
3980  np2->type = AEL_APPCALL;
3981  np2->app = strdup("NoOp");
3982  snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
3983  np2->appargs = strdup(buf);
3984  linkprio(switch_case, np2, mother_exten);
3985  switch_case-> return_target = np2;
3986  }
3987  } else {
3988  /* what could it be??? */
3989  }
3990  }
3991 
3992  exten->loop_break = loop_break_save;
3993  exten->loop_continue = loop_continue_save;
3994  switch_test->origin = p;
3995  switch_end->origin = p;
3996  break;
3997 
3998  case PV_MACRO_CALL:
3999  pr = new_prio();
4000  pr->type = AEL_APPCALL;
4001  snprintf(buf1, BUF_SIZE, "%s,~~s~~,1", p->u1.str);
4002  first = 1;
4003  for (p2 = p->u2.arglist; p2; p2 = p2->next) {
4004  if (first)
4005  {
4006  strcat(buf1,"(");
4007  first = 0;
4008  }
4009  else
4010  strcat(buf1,",");
4011  strcat(buf1,p2->u1.str);
4012  }
4013  if (!first)
4014  strcat(buf1,")");
4015 
4016  pr->app = strdup("Gosub");
4017  pr->appargs = strdup(buf1);
4018  pr->origin = p;
4019  linkprio(exten, pr, mother_exten);
4020  break;
4021 
4022  case PV_APPLICATION_CALL:
4023  pr = new_prio();
4024  pr->type = AEL_APPCALL;
4025  buf1[0] = 0;
4026  for (p2 = p->u2.arglist; p2; p2 = p2->next) {
4027  if (p2 != p->u2.arglist )
4028  strcat(buf1,",");
4029  strcat(buf1,p2->u1.str);
4030  }
4031  pr->app = strdup(p->u1.str);
4032  pr->appargs = strdup(buf1);
4033  pr->origin = p;
4034  linkprio(exten, pr, mother_exten);
4035  break;
4036 
4037  case PV_BREAK:
4038  pr = new_prio();
4039  pr->type = AEL_CONTROL1; /* simple goto */
4040  pr->goto_true = exten->loop_break;
4041  pr->origin = p;
4042  linkprio(exten, pr, mother_exten);
4043  break;
4044 
4045  case PV_RETURN: /* hmmmm */
4046  pr = new_prio();
4047  pr->type = AEL_RETURN; /* simple Return */
4048  /* exten->return_needed++; */
4049  pr->app = strdup("Return");
4050  pr->appargs = strdup("");
4051  pr->origin = p;
4052  linkprio(exten, pr, mother_exten);
4053  break;
4054 
4055  case PV_CONTINUE:
4056  pr = new_prio();
4057  pr->type = AEL_CONTROL1; /* simple goto */
4058  pr->goto_true = exten->loop_continue;
4059  pr->origin = p;
4060  linkprio(exten, pr, mother_exten);
4061  break;
4062 
4063  case PV_IFTIME:
4064  control_statement_count++;
4065  snprintf(new_label, BUF_SIZE, "iftime_%s_%d", label, control_statement_count);
4066 
4067  if_test = new_prio();
4068  if_test->type = AEL_IFTIME_CONTROL;
4069  snprintf(buf1, BUF_SIZE, "%s,%s,%s,%s",
4070  p->u1.list->u1.str,
4071  p->u1.list->next->u1.str,
4072  p->u1.list->next->next->u1.str,
4073  p->u1.list->next->next->next->u1.str);
4074  if_test->app = 0;
4075  if_test->appargs = strdup(buf1);
4076  if_test->origin = p;
4077 
4078  if_end = new_prio();
4079  if_end->type = AEL_APPCALL;
4080  snprintf(buf1, BUF_SIZE, "Finish iftime_%s_%d", label, control_statement_count);
4081  if_end->app = strdup("NoOp");
4082  if_end->appargs = strdup(buf1);
4083 
4084  if (p->u3.else_statements) {
4085  if_skip = new_prio();
4086  if_skip->type = AEL_CONTROL1; /* simple goto */
4087  if_skip->goto_true = if_end;
4088  if_skip->origin = p;
4089 
4090  } else {
4091  if_skip = 0;
4092 
4093  if_test->goto_false = if_end;
4094  }
4095 
4096  if_false = new_prio();
4097  if_false->type = AEL_CONTROL1;
4098  if (p->u3.else_statements) {
4099  if_false->goto_true = if_skip; /* +1 */
4100  } else {
4101  if_false->goto_true = if_end;
4102  }
4103 
4104  /* link & load! */
4105  linkprio(exten, if_test, mother_exten);
4106  linkprio(exten, if_false, mother_exten);
4107 
4108  /* now, put the body of the if here */
4109 
4110  if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */
4111  return -1;
4112  }
4113 
4114  if (p->u3.else_statements) {
4115  linkprio(exten, if_skip, mother_exten);
4116  if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */
4117  return -1;
4118  }
4119  }
4120 
4121  linkprio(exten, if_end, mother_exten);
4122 
4123  break;
4124 
4125  case PV_RANDOM:
4126  case PV_IF:
4127  control_statement_count++;
4128  snprintf(new_label, BUF_SIZE, "if_%s_%d", label, control_statement_count);
4129 
4130  if_test = new_prio();
4131  if_end = new_prio();
4132  if_test->type = AEL_IF_CONTROL;
4133  if_end->type = AEL_APPCALL;
4134  if ( p->type == PV_RANDOM )
4135  snprintf(buf1, BUF_SIZE, "$[${RAND(0,99)} < (%s)]", p->u1.str);
4136  else
4137  snprintf(buf1, BUF_SIZE, "$[%s]", p->u1.str);
4138  if_test->app = 0;
4139  if_test->appargs = strdup(buf1);
4140  snprintf(buf1, BUF_SIZE, "Finish if_%s_%d", label, control_statement_count);
4141  if_end->app = strdup("NoOp");
4142  if_end->appargs = strdup(buf1);
4143  if_test->origin = p;
4144 
4145  if (p->u3.else_statements) {
4146  if_skip = new_prio();
4147  if_skip->type = AEL_CONTROL1; /* simple goto */
4148  if_skip->goto_true = if_end;
4149  if_test->goto_false = if_skip;;
4150  } else {
4151  if_skip = 0;
4152  if_test->goto_false = if_end;;
4153  }
4154 
4155  /* link & load! */
4156  linkprio(exten, if_test, mother_exten);
4157 
4158  /* now, put the body of the if here */
4159 
4160  if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */
4161  return -1;
4162  }
4163 
4164  if (p->u3.else_statements) {
4165  linkprio(exten, if_skip, mother_exten);
4166  if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */
4167  return -1;
4168  }
4169  }
4170 
4171  linkprio(exten, if_end, mother_exten);
4172 
4173  break;
4174 
4175  case PV_STATEMENTBLOCK:
4176  if (gen_prios(exten, label, p->u1.list, mother_exten, this_context)) { /* recurse into the block */
4177  return -1;
4178  }
4179  break;
4180 
4181  case PV_CATCH:
4182  control_statement_count++;
4183  /* generate an extension with name of catch, put all catch stats
4184  into this exten! */
4185  switch_case = new_exten();
4186  if (mother_exten && mother_exten->checked_switch) {
4187  switch_case->has_switch = mother_exten->has_switch;
4188  switch_case->checked_switch = mother_exten->checked_switch;
4189  }
4190  if (exten && exten->checked_switch) {
4191  switch_case->has_switch = exten->has_switch;
4192  switch_case->checked_switch = exten->checked_switch;
4193  }
4194 
4195  switch_case->context = this_context;
4196  linkexten(exten,switch_case);
4197  switch_case->name = strdup(p->u1.str);
4198  snprintf(new_label, BUF_SIZE, "catch_%s_%d",p->u1.str, control_statement_count);
4199 
4200  if (gen_prios(switch_case, new_label, p->u2.statements, mother_exten,this_context)) { /* this will link in all the catch body statements here */
4201  return -1;
4202  }
4203  if (switch_case->return_needed) { /* returns now generate a Return() app call, no longer a goto to the end of the exten */
4204  char buf[2000];
4205  struct ael_priority *np2 = new_prio();
4206  np2->type = AEL_APPCALL;
4207  np2->app = strdup("NoOp");
4208  snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
4209  np2->appargs = strdup(buf);
4210  linkprio(switch_case, np2, mother_exten);
4211  switch_case-> return_target = np2;
4212  }
4213 
4214  break;
4215  default:
4216  break;
4217  }
4218  }
4219  free(buf1);
4220  free(buf2);
4221  free(new_label);
4222  return 0;
4223 }
4224 
4226 {
4227  int i;
4228  struct ael_priority *pr;
4229  do {
4230  if (exten->is_switch)
4231  i = 10;
4232  else if (exten->regexten)
4233  i=2;
4234  else
4235  i=1;
4236 
4237  for (pr=exten->plist; pr; pr=pr->next) {
4238  pr->priority_num = i;
4239 
4240  if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
4241  but we want them to point to the right
4242  priority, which would be the next line
4243  after the label; */
4244  i++;
4245  }
4246 
4247  exten = exten->next_exten;
4248  } while ( exten );
4249 }
4250 
4252 {
4253  struct ael_priority *pr;
4254  char *label=0;
4255  char realext[AST_MAX_EXTENSION];
4256  if (!exten) {
4257  ast_log(LOG_WARNING, "This file is Empty!\n" );
4258  return;
4259  }
4260  do {
4261  struct ael_priority *last = 0;
4262 
4263  pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
4264  if (exten->hints) {
4265  if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch,
4266  exten->hints, NULL, ast_free_ptr, registrar)) {
4267  ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
4268  exten->name);
4269  }
4270  }
4271 
4272  for (pr=exten->plist; pr; pr=pr->next) {
4273  char app[2000];
4274  char appargs[2000];
4275 
4276  /* before we can add the extension, we need to prep the app/appargs;
4277  the CONTROL types need to be done after the priority numbers are calculated.
4278  */
4279  if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
4280  last = pr;
4281  continue;
4282  }
4283 
4284  if (pr->app)
4285  strcpy(app, pr->app);
4286  else
4287  app[0] = 0;
4288  if (pr->appargs )
4289  strcpy(appargs, pr->appargs);
4290  else
4291  appargs[0] = 0;
4292  switch( pr->type ) {
4293  case AEL_APPCALL:
4294  /* easy case. Everything is all set up */
4295  break;
4296 
4297  case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
4298  /* simple, unconditional goto. */
4299  strcpy(app,"Goto");
4300  if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
4301  snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
4302  } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
4303  snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
4304  } else
4305  snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
4306  break;
4307 
4308  case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */
4309  strcpy(app,"GotoIf");
4310  snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4311  break;
4312 
4313  case AEL_IF_CONTROL:
4314  strcpy(app,"GotoIf");
4315  if (pr->origin->u3.else_statements )
4316  snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
4317  else
4318  snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4319  break;
4320 
4321  case AEL_RAND_CONTROL:
4322  strcpy(app,"Random");
4323  snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
4324  break;
4325 
4326  case AEL_IFTIME_CONTROL:
4327  strcpy(app,"GotoIfTime");
4328  snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
4329  break;
4330 
4331  case AEL_RETURN:
4332  strcpy(app,"Return");
4333  appargs[0] = 0;
4334  break;
4335 
4336  default:
4337  break;
4338  }
4339  if (last && last->type == AEL_LABEL ) {
4340  label = last->origin->u1.str;
4341  }
4342  else
4343  label = 0;
4344 
4345  if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
4346  app, strdup(appargs), ast_free_ptr, registrar)) {
4347  ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
4348  exten->name);
4349  }
4350  last = pr;
4351  }
4352  exten = exten->next_exten;
4353  } while ( exten );
4354 }
4355 
4356 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
4357 {
4358  /* travel to the end of the list... */
4359  struct ael_extension *lptr;
4360  if( !*list ) {
4361  *list = newmem;
4362  return;
4363  }
4364  lptr = *list;
4365 
4366  while( lptr->next_exten ) {
4367  lptr = lptr->next_exten;
4368  }
4369  /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
4370  lptr->next_exten = newmem;
4371 }
4372 
4374 {
4375  while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
4376 
4377  p = p->dad;
4378  }
4379 
4380  return p;
4381 }
4382 
4383 static pval *get_contxt(pval *p)
4384 {
4385  while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
4386 
4387  p = p->dad;
4388  }
4389 
4390  return p;
4391 }
4392 
4394 {
4395  struct ael_extension *e;
4396  for(e=exten;e;e=e->next_exten) {
4397 
4398  struct ael_priority *p;
4399  for(p=e->plist;p;p=p->next) {
4400 
4401  if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
4402 
4403  /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
4404 
4405  pval *target = p->origin->u2.goto_target;
4406  struct ael_extension *z = target->u3.compiled_label;
4407  pval *pv2 = p->origin;
4408  char buf1[500];
4409  char *apparg_save = p->appargs;
4410 
4411  p->appargs = 0;
4412  if (!pv2->u1.list->next) /* just one -- it won't hurt to repeat the extension */ {
4413  snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->u1.str);
4414  p->appargs = strdup(buf1);
4415 
4416  } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
4417  snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->next->u1.str);
4418  p->appargs = strdup(buf1);
4419  } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
4420  snprintf(buf1,sizeof(buf1),"%s,%s,%s", pv2->u1.list->u1.str,
4421  z->name,
4422  pv2->u1.list->next->next->u1.str);
4423  p->appargs = strdup(buf1);
4424  }
4425  else
4426  printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
4427 
4428  if( apparg_save ) {
4429  free(apparg_save);
4430  }
4431  }
4432  }
4433  }
4434 }
4435 
4436 static int context_used(struct ael_extension *exten_list, struct ast_context *context)
4437 {
4438  struct ael_extension *exten;
4439  /* Check the simple elements first */
4440  if (ast_walk_context_extensions(context, NULL) || ast_walk_context_includes(context, NULL) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) {
4441  return 1;
4442  }
4443  for (exten = exten_list; exten; exten = exten->next_exten) {
4444  if (exten->context == context) {
4445  return 1;
4446  }
4447  }
4448  return 0;
4449 }
4450 
4452 {
4453  pval *p,*p2;
4454  struct ast_context *context;
4455  char buf[2000];
4456  struct ael_extension *exten;
4457  struct ael_extension *exten_list = 0;
4458 
4459  for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
4460  when we try to eval them */
4461  switch (p->type) {
4462  case PV_GLOBALS:
4463  /* just VARDEC elements */
4464  for (p2=p->u1.list; p2; p2=p2->next) {
4465  char buf2[2000];
4466  snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
4467  pbx_builtin_setvar(NULL, buf2);
4468  }
4469  break;
4470  default:
4471  break;
4472  }
4473  }
4474 
4475  for (p=root; p; p=p->next ) {
4476  pval *lp;
4477  int argc;
4478 
4479  switch (p->type) {
4480  case PV_MACRO:
4481 
4482  context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
4483 
4484  exten = new_exten();
4485  exten->context = context;
4486  exten->name = strdup("~~s~~");
4487  argc = 1;
4488  for (lp=p->u2.arglist; lp; lp=lp->next) {
4489  /* for each arg, set up a "Set" command */
4490  struct ael_priority *np2 = new_prio();
4491  np2->type = AEL_APPCALL;
4492  if (!ast_compat_app_set) {
4493  np2->app = strdup("MSet");
4494  } else {
4495  np2->app = strdup("Set");
4496  }
4497  snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
4499  np2->appargs = strdup(buf);
4500  linkprio(exten, np2, NULL);
4501  }
4502 
4503  /* CONTAINS APPCALLS, CATCH, just like extensions... */
4504  if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
4505  return -1;
4506  }
4507  if (exten->return_needed) { /* most likely, this will go away */
4508  struct ael_priority *np2 = new_prio();
4509  np2->type = AEL_APPCALL;
4510  np2->app = strdup("NoOp");
4511  snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
4512  np2->appargs = strdup(buf);
4513  linkprio(exten, np2, NULL);
4514  exten-> return_target = np2;
4515  }
4516 
4517  set_priorities(exten);
4518  attach_exten(&exten_list, exten);
4519  break;
4520 
4521  case PV_GLOBALS:
4522  /* already done */
4523  break;
4524 
4525  case PV_CONTEXT:
4526  context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
4527 
4528  /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
4529  for (p2=p->u2.statements; p2; p2=p2->next) {
4530  pval *p3;
4531  char *s3;
4532 
4533  switch (p2->type) {
4534  case PV_EXTENSION:
4535  exten = new_exten();
4536  exten->name = strdup(p2->u1.str);
4537  exten->context = context;
4538 
4539  if( (s3=strchr(exten->name, '/') ) != 0 )
4540  {
4541  *s3 = 0;
4542  exten->cidmatch = s3+1;
4543  }
4544 
4545  if ( p2->u3.hints )
4546  exten->hints = strdup(p2->u3.hints);
4547  exten->regexten = p2->u4.regexten;
4548  if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
4549  return -1;
4550  }
4551  if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
4552  struct ael_priority *np2 = new_prio();
4553  np2->type = AEL_APPCALL;
4554  np2->app = strdup("NoOp");
4555  snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
4556  np2->appargs = strdup(buf);
4557  linkprio(exten, np2, NULL);
4558  exten-> return_target = np2;
4559  }
4560  /* is the last priority in the extension a label? Then add a trailing no-op */
4561  if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
4562  struct ael_priority *np2 = new_prio();
4563  np2->type = AEL_APPCALL;
4564  np2->app = strdup("NoOp");
4565  snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
4566  np2->appargs = strdup(buf);
4567  linkprio(exten, np2, NULL);
4568  }
4569 
4570  set_priorities(exten);
4571  attach_exten(&exten_list, exten);
4572  break;
4573 
4574  case PV_IGNOREPAT:
4575  ast_context_add_ignorepat2(context, p2->u1.str, registrar);
4576  break;
4577 
4578  case PV_INCLUDES:
4579  for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4580  if ( p3->u2.arglist ) {
4581  snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s",
4582  p3->u1.str,
4583  p3->u2.arglist->u1.str,
4584  p3->u2.arglist->next->u1.str,
4585  p3->u2.arglist->next->next->u1.str,
4586  p3->u2.arglist->next->next->next->u1.str);
4587  ast_context_add_include2(context, buf, registrar);
4588  } else
4589  ast_context_add_include2(context, p3->u1.str, registrar);
4590  }
4591  break;
4592 
4593  case PV_SWITCHES:
4594  for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4595  char *c = strchr(p3->u1.str, '/');
4596  if (c) {
4597  *c = '\0';
4598  c++;
4599  } else
4600  c = "";
4601 
4602  ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
4603  }
4604  break;
4605 
4606  case PV_ESWITCHES:
4607  for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4608  char *c = strchr(p3->u1.str, '/');
4609  if (c) {
4610  *c = '\0';
4611  c++;
4612  } else
4613  c = "";
4614 
4615  ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
4616  }
4617  break;
4618  default:
4619  break;
4620  }
4621  }
4622 
4623  break;
4624 
4625  default:
4626  /* huh? what? */
4627  break;
4628 
4629  }
4630  }
4631 
4632  /* Create default "h" bubble context */
4633  if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
4634  int i;
4635  const char *h_context = "ael-builtin-h-bubble";
4636  struct ael_priority *np;
4637  struct {
4638  int priority;
4639  const char *app;
4640  const char *arg;
4641  } steps[] = {
4642  /* Start high, to avoid conflict with existing h extensions */
4643  { 1, "Goto", "9991" },
4644  /* Save the context, because after the StackPop, it disappears */
4645  { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" },
4646  /* If we're not in a Gosub frame, exit */
4647  { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" },
4648  /* Check for an "h" extension in that context */
4649  { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" },
4650  /* Pop off the stack frame to prevent an infinite loop */
4651  { 9994, "StackPop", "" },
4652  /* Finally, go there. */
4653  { 9995, "Goto", "${~~parentcxt~~},h,1" },
4654  /* Just an empty priority for jumping out early */
4655  { 9996, "NoOp", "" }
4656  };
4657  context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar);
4658  if (context_used(exten_list, context)) {
4659  int found = 0;
4660  while (!found) {
4661  /* Pick a new context name that is not used. */
4662  char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX";
4663  int fd = mkstemp(h_context_template);
4664  unlink(h_context_template);
4665  close(fd);
4666  context = ast_context_find_or_create(local_contexts, local_table, h_context_template + 5, registrar);
4667  found = !context_used(exten_list, context);
4668  }
4669  h_context = ast_get_context_name(context);
4670  }
4671  exten = new_exten();
4672  exten->context = context;
4673  exten->name = strdup("h");
4674 
4675  for (i = 0; i < ARRAY_LEN(steps); i++) {
4676  np = new_prio();
4677  np->type = AEL_APPCALL;
4678  np->priority_num = steps[i].priority;
4679  np->app = strdup(steps[i].app);
4680  np->appargs = strdup(steps[i].arg);
4681  linkprio(exten, np, NULL);
4682  }
4683  attach_exten(&exten_list, exten);
4684 
4685  /* Include the default "h" bubble context in each macro context */
4686  for (exten = exten_list; exten; exten = exten->next_exten) {
4687  /* All macros contain a "~~s~~" extension, and it's the first created. If
4688  * we perchance get a non-macro context, it's no big deal; the logic is
4689  * designed to exit out smoothly if not called from within a Gosub. */
4690  if (!strcmp(exten->name, "~~s~~")) {
4691  ast_context_add_include2(exten->context, h_context, registrar);
4692  }
4693  }
4694  }
4695 
4696  /* moved these from being done after a macro or extension were processed,
4697  to after all processing is done, for the sake of fixing gotos to labels inside cases... */
4698  /* I guess this would be considered 2nd pass of compiler now... */
4699  fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
4700  add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
4701  destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */
4702 
4703  return 0;
4704 }
4705 
4706 
4707 /* DESTROY the PVAL tree ============================================================================ */
4708 
4709 
4710 
4712 {
4713  if (item == NULL) {
4714  ast_log(LOG_WARNING, "null item\n");
4715  return;
4716  }
4717 
4718  if (item->filename)
4719  free(item->filename);
4720 
4721  switch (item->type) {
4722  case PV_WORD:
4723  /* fields: item->u1.str == string associated with this (word). */
4724  if (item->u1.str )
4725  free(item->u1.str);
4726  if ( item->u2.arglist )
4727  destroy_pval(item->u2.arglist);
4728  break;
4729 
4730  case PV_MACRO:
4731  /* fields: item->u1.str == name of macro
4732  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
4733  item->u2.arglist->u1.str == argument
4734  item->u2.arglist->next == next arg
4735 
4736  item->u3.macro_statements == pval list of statements in macro body.
4737  */
4738  destroy_pval(item->u2.arglist);
4739  if (item->u1.str )
4740  free(item->u1.str);
4742  break;
4743 
4744  case PV_CONTEXT:
4745  /* fields: item->u1.str == name of context
4746  item->u2.statements == pval list of statements in context body
4747  item->u3.abstract == int 1 if an abstract keyword were present
4748  */
4749  if (item->u1.str)
4750  free(item->u1.str);
4751  destroy_pval(item->u2.statements);
4752  break;
4753 
4754  case PV_MACRO_CALL:
4755  /* fields: item->u1.str == name of macro to call
4756  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4757  item->u2.arglist->u1.str == argument
4758  item->u2.arglist->next == next arg
4759  */
4760  if (item->u1.str)
4761  free(item->u1.str);
4762  destroy_pval(item->u2.arglist);
4763  break;
4764 
4765  case PV_APPLICATION_CALL:
4766  /* fields: item->u1.str == name of application to call
4767  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4768  item->u2.arglist->u1.str == argument
4769  item->u2.arglist->next == next arg
4770  */
4771  if (item->u1.str)
4772  free(item->u1.str);
4773  destroy_pval(item->u2.arglist);
4774  break;
4775 
4776  case PV_CASE:
4777  /* fields: item->u1.str == value of case
4778  item->u2.statements == pval list of statements under the case
4779  */
4780  if (item->u1.str)
4781  free(item->u1.str);
4782  destroy_pval(item->u2.statements);
4783  break;
4784 
4785  case PV_PATTERN:
4786  /* fields: item->u1.str == value of case
4787  item->u2.statements == pval list of statements under the case
4788  */
4789  if (item->u1.str)
4790  free(item->u1.str);
4791  destroy_pval(item->u2.statements);
4792  break;
4793 
4794  case PV_DEFAULT:
4795  /* fields:
4796  item->u2.statements == pval list of statements under the case
4797  */
4798  destroy_pval(item->u2.statements);
4799  break;
4800 
4801  case PV_CATCH:
4802  /* fields: item->u1.str == name of extension to catch
4803  item->u2.statements == pval list of statements in context body
4804  */
4805  if (item->u1.str)
4806  free(item->u1.str);
4807  destroy_pval(item->u2.statements);
4808  break;
4809 
4810  case PV_SWITCHES:
4811  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4812  */
4813  destroy_pval(item->u1.list);
4814  break;
4815 
4816  case PV_ESWITCHES:
4817  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4818  */
4819  destroy_pval(item->u1.list);
4820  break;
4821 
4822  case PV_INCLUDES:
4823  /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4824  item->u2.arglist == pval list of 4 PV_WORD elements for time values
4825  */
4826  destroy_pval(item->u1.list);
4827  break;
4828 
4829  case PV_STATEMENTBLOCK:
4830  /* fields: item->u1.list == pval list of statements in block, one per entry in the list
4831  */
4832  destroy_pval(item->u1.list);
4833  break;
4834 
4835  case PV_LOCALVARDEC:
4836  case PV_VARDEC:
4837  /* fields: item->u1.str == variable name
4838  item->u2.val == variable value to assign
4839  */
4840  if (item->u1.str)
4841  free(item->u1.str);
4842  if (item->u2.val)
4843  free(item->u2.val);
4844  break;
4845 
4846  case PV_GOTO:
4847  /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
4848  item->u1.list->u1.str == where the data on a PV_WORD will always be.
4849  */
4850 
4851  destroy_pval(item->u1.list);
4852  break;
4853 
4854  case PV_LABEL:
4855  /* fields: item->u1.str == label name
4856  */
4857  if (item->u1.str)
4858  free(item->u1.str);
4859  break;
4860 
4861  case PV_FOR:
4862  /* fields: item->u1.for_init == a string containing the initalizer
4863  item->u2.for_test == a string containing the loop test
4864  item->u3.for_inc == a string containing the loop increment
4865 
4866  item->u4.for_statements == a pval list of statements in the for ()
4867  */
4868  if (item->u1.for_init)
4869  free(item->u1.for_init);
4870  if (item->u2.for_test)
4871  free(item->u2.for_test);
4872  if (item->u3.for_inc)
4873  free(item->u3.for_inc);
4875  break;
4876 
4877  case PV_WHILE:
4878  /* fields: item->u1.str == the while conditional, as supplied by user
4879 
4880  item->u2.statements == a pval list of statements in the while ()
4881  */
4882  if (item->u1.str)
4883  free(item->u1.str);
4884  destroy_pval(item->u2.statements);
4885  break;
4886 
4887  case PV_BREAK:
4888  /* fields: none
4889  */
4890  break;
4891 
4892  case PV_RETURN:
4893  /* fields: none
4894  */
4895  break;
4896 
4897  case PV_CONTINUE:
4898  /* fields: none
4899  */
4900  break;
4901 
4902  case PV_IFTIME:
4903  /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list
4904 
4905  item->u2.statements == a pval list of statements in the if ()
4906  item->u3.else_statements == a pval list of statements in the else
4907  (could be zero)
4908  */
4909  destroy_pval(item->u1.list);
4910  destroy_pval(item->u2.statements);
4911  if (item->u3.else_statements) {
4913  }
4914  break;
4915 
4916  case PV_RANDOM:
4917  /* fields: item->u1.str == the random percentage, as supplied by user
4918 
4919  item->u2.statements == a pval list of statements in the true part ()
4920  item->u3.else_statements == a pval list of statements in the else
4921  (could be zero)
4922  fall thru to If */
4923  case PV_IF:
4924  /* fields: item->u1.str == the if conditional, as supplied by user
4925 
4926  item->u2.statements == a pval list of statements in the if ()
4927  item->u3.else_statements == a pval list of statements in the else
4928  (could be zero)
4929  */
4930  if (item->u1.str)
4931  free(item->u1.str);
4932  destroy_pval(item->u2.statements);
4933  if (item->u3.else_statements) {
4935  }
4936  break;
4937 
4938  case PV_SWITCH:
4939  /* fields: item->u1.str == the switch expression
4940 
4941  item->u2.statements == a pval list of statements in the switch,
4942  (will be case statements, most likely!)
4943  */
4944  if (item->u1.str)
4945  free(item->u1.str);
4946  destroy_pval(item->u2.statements);
4947  break;
4948 
4949  case PV_EXTENSION:
4950  /* fields: item->u1.str == the extension name, label, whatever it's called
4951 
4952  item->u2.statements == a pval list of statements in the extension
4953  item->u3.hints == a char * hint argument
4954  item->u4.regexten == an int boolean. non-zero says that regexten was specified
4955  */
4956  if (item->u1.str)
4957  free(item->u1.str);
4958  if (item->u3.hints)
4959  free(item->u3.hints);
4960  destroy_pval(item->u2.statements);
4961  break;
4962 
4963  case PV_IGNOREPAT:
4964  /* fields: item->u1.str == the ignorepat data
4965  */
4966  if (item->u1.str)
4967  free(item->u1.str);
4968  break;
4969 
4970  case PV_GLOBALS:
4971  /* fields: item->u1.statements == pval list of statements, usually vardecs
4972  */
4973  destroy_pval(item->u1.statements);
4974  break;
4975  }
4976  free(item);
4977 }
4978 
4979 void destroy_pval(pval *item)
4980 {
4981  pval *i,*nxt;
4982 
4983  for (i=item; i; i=nxt) {
4984  nxt = i->next;
4985 
4986  destroy_pval_item(i);
4987  }
4988 }
4989 
4990 #ifdef AAL_ARGCHECK
4991 static char *ael_funclist[] =
4992 {
4993  "AGENT",
4994  "ARRAY",
4995  "BASE64_DECODE",
4996  "BASE64_ENCODE",
4997  "CALLERID",
4998  "CDR",
4999  "CHANNEL",
5000  "CHECKSIPDOMAIN",
5001  "CHECK_MD5",
5002  "CURL",
5003  "CUT",
5004  "DB",
5005  "DB_EXISTS",
5006  "DUNDILOOKUP",
5007  "ENUMLOOKUP",
5008  "ENV",
5009  "EVAL",
5010  "EXISTS",
5011  "FIELDQTY",
5012  "FILTER",
5013  "GROUP",
5014  "GROUP_COUNT",
5015  "GROUP_LIST",
5016  "GROUP_MATCH_COUNT",
5017  "IAXPEER",
5018  "IF",
5019  "IFTIME",
5020  "ISNULL",
5021  "KEYPADHASH",
5022  "LANGUAGE",
5023  "LEN",
5024  "MATH",
5025  "MD5",
5026  "MUSICCLASS",
5027  "QUEUEAGENTCOUNT",
5028  "QUEUE_MEMBER_COUNT",
5029  "QUEUE_MEMBER_LIST",
5030  "QUOTE",
5031  "RAND",
5032  "REGEX",
5033  "SET",
5034  "SHA1",
5035  "SIPCHANINFO",
5036  "SIPPEER",
5037  "SIP_HEADER",
5038  "SORT",
5039  "STAT",
5040  "STRFTIME",
5041  "STRPTIME",
5042  "TIMEOUT",
5043  "TXTCIDNAME",
5044  "URIDECODE",
5045  "URIENCODE",
5046  "VMCOUNT"
5047 };
5048 
5049 
5050 int ael_is_funcname(char *name)
5051 {
5052  int s,t;
5053  t = sizeof(ael_funclist)/sizeof(char*);
5054  s = 0;
5055  while ((s < t) && strcasecmp(name, ael_funclist[s]))
5056  s++;
5057  if ( s < t )
5058  return 1;
5059  else
5060  return 0;
5061 }
5062 #endif
5063 
5064 
5065 /* PVAL PI */
5066 
5067 /* ----------------- implementation ------------------- */
5068 
5069 
5070 int pvalCheckType( pval *p, char *funcname, pvaltype type )
5071 {
5072  if (p->type != type)
5073  {
5074  ast_log(LOG_ERROR, "Func: %s the pval passed is not appropriate for this function!\n", funcname);
5075  return 0;
5076  }
5077  return 1;
5078 }
5079 
5080 
5082 {
5083  pval *p = calloc(1,sizeof(pval)); /* why, oh why, don't I use ast_calloc? Way, way, way too messy if I do! */
5084  p->type = type; /* remember, this can be used externally or internally to asterisk */
5085  return p;
5086 }
5087 
5089 {
5090  return p->type;
5091 }
5092 
5093 
5094 void pvalWordSetString( pval *p, char *str)
5095 {
5096  if (!pvalCheckType(p, "pvalWordSetString", PV_WORD))
5097  return;
5098  p->u1.str = str;
5099 }
5100 
5102 {
5103  if (!pvalCheckType(p, "pvalWordGetString", PV_WORD))
5104  return 0;
5105  return p->u1.str;
5106 }
5107 
5108 
5109 void pvalMacroSetName( pval *p, char *name)
5110 {
5111  if (!pvalCheckType(p, "pvalMacroSetName", PV_MACRO))
5112  return;
5113  p->u1.str = name;
5114 }
5115 
5117 {
5118  if (!pvalCheckType(p, "pvalMacroGetName", PV_MACRO))
5119  return 0;
5120  return p->u1.str;
5121 }
5122 
5123 void pvalMacroSetArglist( pval *p, pval *arglist )
5124 {
5125  if (!pvalCheckType(p, "pvalMacroSetArglist", PV_MACRO))
5126  return;
5127  p->u2.arglist = arglist;
5128 }
5129 
5130 void pvalMacroAddArg( pval *p, pval *arg ) /* single arg only! */
5131 {
5132  if (!pvalCheckType(p, "pvalMacroAddArg", PV_MACRO))
5133  return;
5134  if (!p->u2.arglist)
5135  p->u2.arglist = arg;
5136  else
5137  linku1(p->u2.arglist, arg);
5138 
5139 }
5140 
5142 {
5143  if (!pvalCheckType(p, "pvalMacroWalkArgs", PV_MACRO))
5144  return 0;
5145  if (!(*arg))
5146  *arg = p->u2.arglist;
5147  else {
5148  *arg = (*arg)->next;
5149  }
5150  return *arg;
5151 }
5152 
5153 void pvalMacroAddStatement( pval *p, pval *statement )
5154 {
5155  if (!pvalCheckType(p, "pvalMacroAddStatement", PV_MACRO))
5156  return;
5157  if (!p->u3.macro_statements)
5158  p->u3.macro_statements = statement;
5159  else
5160  linku1(p->u3.macro_statements, statement);
5161 
5162 
5163 }
5164 
5165 pval *pvalMacroWalkStatements( pval *p, pval **next_statement )
5166 {
5167  if (!pvalCheckType(p, "pvalMacroWalkStatements", PV_MACRO))
5168  return 0;
5169  if (!(*next_statement))
5170  *next_statement = p->u3.macro_statements;
5171  else {
5172  *next_statement = (*next_statement)->next;
5173  }
5174  return *next_statement;
5175 }
5176 
5177 
5178 
5179 void pvalContextSetName( pval *p, char *name)
5180 {
5181  if (!pvalCheckType(p, "pvalContextSetName", PV_CONTEXT))
5182  return;
5183  p->u1.str = name;
5184 }
5185 
5187 {
5188  if (!pvalCheckType(p, "pvalContextGetName", PV_CONTEXT))
5189  return 0;
5190  return p->u1.str;
5191 }
5192 
5194 {
5195  if (!pvalCheckType(p, "pvalContextSetAbstract", PV_CONTEXT))
5196  return;
5197  p->u3.abstract = 1;
5198 }
5199 
5201 {
5202  if (!pvalCheckType(p, "pvalContextUnsetAbstract", PV_CONTEXT))
5203  return;
5204  p->u3.abstract = 0;
5205 }
5206 
5208 {
5209  if (!pvalCheckType(p, "pvalContextGetAbstract", PV_CONTEXT))
5210  return 0;
5211  return p->u3.abstract;
5212 }
5213 
5214 
5215 
5216 void pvalContextAddStatement( pval *p, pval *statement) /* this includes SWITCHES, INCLUDES, IGNOREPAT, etc */
5217 {
5218  if (!pvalCheckType(p, "pvalContextAddStatement", PV_CONTEXT))
5219  return;
5220  if (!p->u2.statements)
5221  p->u2.statements = statement;
5222  else
5223  linku1(p->u2.statements, statement);
5224 }
5225 
5227 {
5228  if (!pvalCheckType(p, "pvalContextWalkStatements", PV_CONTEXT))
5229  return 0;
5230  if (!(*statements))
5231  *statements = p->u2.statements;
5232  else {
5233  *statements = (*statements)->next;
5234  }
5235  return *statements;
5236 }
5237 
5238 
5239 void pvalMacroCallSetMacroName( pval *p, char *name )
5240 {
5241  if (!pvalCheckType(p, "pvalMacroCallSetMacroName", PV_MACRO_CALL))
5242  return;
5243  p->u1.str = name;
5244 }
5245 
5247 {
5248  if (!pvalCheckType(p, "pvalMacroCallGetMacroName", PV_MACRO_CALL))
5249  return 0;
5250  return p->u1.str;
5251 }
5252 
5253 void pvalMacroCallSetArglist( pval *p, pval *arglist )
5254 {
5255  if (!pvalCheckType(p, "pvalMacroCallSetArglist", PV_MACRO_CALL))
5256  return;
5257  p->u2.arglist = arglist;
5258 }
5259 
5261 {
5262  if (!pvalCheckType(p, "pvalMacroCallGetAddArg", PV_MACRO_CALL))
5263  return;
5264  if (!p->u2.arglist)
5265  p->u2.arglist = arg;
5266  else
5267  linku1(p->u2.arglist, arg);
5268 }
5269 
5271 {
5272  if (!pvalCheckType(p, "pvalMacroCallWalkArgs", PV_MACRO_CALL))
5273  return 0;
5274  if (!(*args))
5275  *args = p->u2.arglist;
5276  else {
5277  *args = (*args)->next;
5278  }
5279  return *args;
5280 }
5281 
5282 
5283 void pvalAppCallSetAppName( pval *p, char *name )
5284 {
5285  if (!pvalCheckType(p, "pvalAppCallSetAppName", PV_APPLICATION_CALL))
5286  return;
5287  p->u1.str = name;
5288 }
5289 
5291 {
5292  if (!pvalCheckType(p, "pvalAppCallGetAppName", PV_APPLICATION_CALL))
5293  return 0;
5294  return p->u1.str;
5295 }
5296 
5297 void pvalAppCallSetArglist( pval *p, pval *arglist )
5298 {
5299  if (!pvalCheckType(p, "pvalAppCallSetArglist", PV_APPLICATION_CALL))
5300  return;
5301  p->u2.arglist = arglist;
5302 }
5303 
5304 void pvalAppCallAddArg( pval *p, pval *arg )
5305 {
5306  if (!pvalCheckType(p, "pvalAppCallAddArg", PV_APPLICATION_CALL))
5307  return;
5308  if (!p->u2.arglist)
5309  p->u2.arglist = arg;
5310  else
5311  linku1(p->u2.arglist, arg);
5312 }
5313 
5315 {
5316  if (!pvalCheckType(p, "pvalAppCallWalkArgs", PV_APPLICATION_CALL))
5317  return 0;
5318  if (!(*args))
5319  *args = p->u2.arglist;
5320  else {
5321  *args = (*args)->next;
5322  }
5323  return *args;
5324 }
5325 
5326 
5327 void pvalCasePatSetVal( pval *p, char *val )
5328 {
5329  if (!pvalCheckType(p, "pvalAppCallWalkArgs", PV_APPLICATION_CALL))
5330  return;
5331  p->u1.str = val;
5332 }
5333 
5335 {
5336  return p->u1.str;
5337 }
5338 
5339 void pvalCasePatDefAddStatement( pval *p, pval *statement )
5340 {
5341  if (!p->u2.arglist)
5342  p->u2.statements = statement;
5343  else
5344  linku1(p->u2.statements, statement);
5345 }
5346 
5348 {
5349  if (!(*statement))
5350  *statement = p->u2.statements;
5351  else {
5352  *statement = (*statement)->next;
5353  }
5354  return *statement;
5355 }
5356 
5357 
5358 void pvalCatchSetExtName( pval *p, char *name )
5359 {
5360  if (!pvalCheckType(p, "pvalCatchSetExtName", PV_CATCH))
5361  return;
5362  p->u1.str = name;
5363 }
5364 
5366 {
5367  if (!pvalCheckType(p, "pvalCatchGetExtName", PV_CATCH))
5368  return 0;
5369  return p->u1.str;
5370 }
5371 
5372 void pvalCatchSetStatement( pval *p, pval *statement )
5373 {
5374  if (!pvalCheckType(p, "pvalCatchSetStatement", PV_CATCH))
5375  return;
5376  p->u2.statements = statement;
5377 }
5378 
5380 {
5381  if (!pvalCheckType(p, "pvalCatchGetStatement", PV_CATCH))
5382  return 0;
5383  return p->u2.statements;
5384 }
5385 
5386 
5387 void pvalSwitchesAddSwitch( pval *p, char *name )
5388 {
5389  pval *s;
5390  if (!pvalCheckType(p, "pvalSwitchesAddSwitch", PV_SWITCHES))
5391  return;
5392  s = pvalCreateNode(PV_WORD);
5393  s->u1.str = name;
5394  p->u1.list = linku1(p->u1.list, s);
5395 }
5396 
5398 {
5399  if (!pvalCheckType(p, "pvalSwitchesWalkNames", PV_SWITCHES))
5400  return 0;
5401  if (!(*next_item))
5402  *next_item = p->u1.list;
5403  else {
5404  *next_item = (*next_item)->next;
5405  }
5406  return (*next_item)->u1.str;
5407 }
5408 
5409 void pvalESwitchesAddSwitch( pval *p, char *name )
5410 {
5411  pval *s;
5412  if (!pvalCheckType(p, "pvalESwitchesAddSwitch", PV_ESWITCHES))
5413  return;
5414  s = pvalCreateNode(PV_WORD);
5415  s->u1.str = name;
5416  p->u1.list = linku1(p->u1.list, s);
5417 }
5418 
5420 {
5421  if (!pvalCheckType(p, "pvalESwitchesWalkNames", PV_ESWITCHES))
5422  return 0;
5423  if (!(*next_item))
5424  *next_item = p->u1.list;
5425  else {
5426  *next_item = (*next_item)->next;
5427  }
5428  return (*next_item)->u1.str;
5429 }
5430 
5431 
5432 void pvalIncludesAddInclude( pval *p, const char *include )
5433 {
5434  pval *s;
5435  if (!pvalCheckType(p, "pvalIncludesAddSwitch", PV_INCLUDES))
5436  return;
5437  s = pvalCreateNode(PV_WORD);
5438  s->u1.str = (char *)include;
5439  p->u1.list = linku1(p->u1.list, s);
5440 }
5441  /* an include is a WORD with string set to path */
5442 
5443 void pvalIncludesAddIncludeWithTimeConstraints( pval *p, const char *include, char *hour_range, char *dom_range, char *dow_range, char *month_range )
5444 {
5445  pval *hr = pvalCreateNode(PV_WORD);
5446  pval *dom = pvalCreateNode(PV_WORD);
5447  pval *dow = pvalCreateNode(PV_WORD);
5448  pval *mon = pvalCreateNode(PV_WORD);
5449  pval *s = pvalCreateNode(PV_WORD);
5450 
5451  if (!pvalCheckType(p, "pvalIncludeAddIncludeWithTimeConstraints", PV_INCLUDES))
5452  return;
5453 
5454  s->u1.str = (char *)include;
5455  p->u1.list = linku1(p->u1.list, s);
5456 
5457  hr->u1.str = hour_range;
5458  dom->u1.str = dom_range;
5459  dow->u1.str = dow_range;
5460  mon->u1.str = month_range;
5461 
5462  s->u2.arglist = hr;
5463 
5464  hr->next = dom;
5465  dom->next = dow;
5466  dow->next = mon;
5467  mon->next = 0;
5468 }
5469  /* is this right??? come back and correct it */ /*the ptr is to the WORD */
5470 void pvalIncludeGetTimeConstraints( pval *p, char **hour_range, char **dom_range, char **dow_range, char **month_range )
5471 {
5472  if (!pvalCheckType(p, "pvalIncludeGetTimeConstraints", PV_WORD))
5473  return;
5474  if (p->u2.arglist) {
5475  *hour_range = p->u2.arglist->u1.str;
5476  *dom_range = p->u2.arglist->next->u1.str;
5477  *dow_range = p->u2.arglist->next->next->u1.str;
5478  *month_range = p->u2.arglist->next->next->next->u1.str;
5479  } else {
5480  *hour_range = 0;
5481  *dom_range = 0;
5482  *dow_range = 0;
5483  *month_range = 0;
5484  }
5485 }
5486  /* is this right??? come back and correct it */ /*the ptr is to the WORD */
5488 {
5489  if (!pvalCheckType(p, "pvalIncludesWalk", PV_INCLUDES))
5490  return 0;
5491  if (!(*next_item))
5492  *next_item = p->u1.list;
5493  else {
5494  *next_item = (*next_item)->next;
5495  }
5496  return (*next_item)->u1.str;
5497 }
5498 
5499 
5501 {
5502  if (!pvalCheckType(p, "pvalStatementBlockAddStatement", PV_STATEMENTBLOCK))
5503  return;
5504  p->u1.list = linku1(p->u1.list, statement);
5505 }
5506 
5508 {
5509  if (!pvalCheckType(p, "pvalStatementBlockWalkStatements", PV_STATEMENTBLOCK))
5510  return 0;
5511  if (!(*next_statement))
5512  *next_statement = p->u1.list;
5513  else {
5514  *next_statement = (*next_statement)->next;
5515  }
5516  return *next_statement;
5517 }
5518 
5519 void pvalVarDecSetVarname( pval *p, char *name )
5520 {
5521  if (!pvalCheckType(p, "pvalVarDecSetVarname", PV_VARDEC))
5522  return;
5523  p->u1.str = name;
5524 }
5525 
5526 void pvalVarDecSetValue( pval *p, char *value )
5527 {
5528  if (!pvalCheckType(p, "pvalVarDecSetValue", PV_VARDEC))
5529  return;
5530  p->u2.val = value;
5531 }
5532 
5534 {
5535  if (!pvalCheckType(p, "pvalVarDecGetVarname", PV_VARDEC))
5536  return 0;
5537  return p->u1.str;
5538 }
5539 
5541 {
5542  if (!pvalCheckType(p, "pvalVarDecGetValue", PV_VARDEC))
5543  return 0;
5544  return p->u2.val;
5545 }
5546 
5547 void pvalGotoSetTarget( pval *p, char *context, char *exten, char *label )
5548 {
5549  pval *con, *ext, *pri;
5550 
5551  if (!pvalCheckType(p, "pvalGotoSetTarget", PV_GOTO))
5552  return;
5553  if (context && strlen(context)) {
5554  con = pvalCreateNode(PV_WORD);
5555  ext = pvalCreateNode(PV_WORD);
5556  pri = pvalCreateNode(PV_WORD);
5557 
5558  con->u1.str = context;
5559  ext->u1.str = exten;
5560  pri->u1.str = label;
5561 
5562  con->next = ext;
5563  ext->next = pri;
5564  p->u1.list = con;
5565  } else if (exten && strlen(exten)) {
5566  ext = pvalCreateNode(PV_WORD);
5567  pri = pvalCreateNode(PV_WORD);
5568 
5569  ext->u1.str = exten;
5570  pri->u1.str = label;
5571 
5572  ext->next = pri;
5573  p->u1.list = ext;
5574  } else {
5575  pri = pvalCreateNode(PV_WORD);
5576 
5577  pri->u1.str = label;
5578 
5579  p->u1.list = pri;
5580  }
5581 }
5582 
5583 void pvalGotoGetTarget( pval *p, char **context, char **exten, char **label )
5584 {
5585  if (!pvalCheckType(p, "pvalGotoGetTarget", PV_GOTO))
5586  return;
5587  if (p->u1.list && p->u1.list->next && p->u1.list->next->next) {
5588  *context = p->u1.list->u1.str;
5589  *exten = p->u1.list->next->u1.str;
5590  *label = p->u1.list->next->next->u1.str;
5591 
5592  } else if (p->u1.list && p->u1.list->next ) {
5593  *exten = p->u1.list->u1.str;
5594  *label = p->u1.list->next->u1.str;
5595  *context = 0;
5596 
5597  } else if (p->u1.list) {
5598  *label = p->u1.list->u1.str;
5599  *context = 0;
5600  *exten = 0;
5601 
5602  } else {
5603  *context = 0;
5604  *exten = 0;
5605  *label = 0;
5606  }
5607 }
5608 
5609 
5610 void pvalLabelSetName( pval *p, char *name )
5611 {
5612  if (!pvalCheckType(p, "pvalLabelSetName", PV_LABEL))
5613  return;
5614  p->u1.str = name;
5615 }
5616 
5618 {
5619  if (!pvalCheckType(p, "pvalLabelGetName", PV_LABEL))
5620  return 0;
5621  return p->u1.str;
5622 }
5623 
5624 
5625 void pvalForSetInit( pval *p, char *init )
5626 {
5627  if (!pvalCheckType(p, "pvalForSetInit", PV_FOR))
5628  return;
5629  p->u1.for_init = init;
5630 }
5631 
5632 void pvalForSetTest( pval *p, char *test )
5633 {
5634  if (!pvalCheckType(p, "pvalForSetTest", PV_FOR))
5635  return;
5636  p->u2.for_test = test;
5637 }
5638 
5639 void pvalForSetInc( pval *p, char *inc )
5640 {
5641  if (!pvalCheckType(p, "pvalForSetInc", PV_FOR))
5642  return;
5643  p->u3.for_inc = inc;
5644 }
5645 
5646 void pvalForSetStatement( pval *p, pval *statement )
5647 {
5648  if (!pvalCheckType(p, "pvalForSetStatement", PV_FOR))
5649  return;
5650  p->u4.for_statements = statement;
5651 }
5652 
5654 {
5655  if (!pvalCheckType(p, "pvalForGetInit", PV_FOR))
5656  return 0;
5657  return p->u1.for_init;
5658 }
5659 
5661 {
5662  if (!pvalCheckType(p, "pvalForGetTest", PV_FOR))
5663  return 0;
5664  return p->u2.for_test;
5665 }
5666 
5667 char* pvalForGetInc( pval *p )
5668 {
5669  if (!pvalCheckType(p, "pvalForGetInc", PV_FOR))
5670  return 0;
5671  return p->u3.for_inc;
5672 }
5673 
5675 {
5676  if (!pvalCheckType(p, "pvalForGetStatement", PV_FOR))
5677  return 0;
5678  return p->u4.for_statements;
5679 }
5680 
5681 
5682 
5683 void pvalIfSetCondition( pval *p, char *expr )
5684 {
5685  if (!pvalCheckType(p, "pvalIfSetCondition", PV_IF))
5686  return;
5687  p->u1.str = expr;
5688 }
5689 
5691 {
5692  if (!pvalCheckType(p, "pvalIfGetCondition", PV_IFTIME))
5693  return 0;
5694  return p->u1.str;
5695 }
5696 
5697 void pvalIfTimeSetCondition( pval *p, char *hour_range, char *dow_range, char *dom_range, char *mon_range ) /* time range format: 24-hour format begin-end|dow range|dom range|month range */
5698 {
5699  pval *hr = pvalCreateNode(PV_WORD);
5700  pval *dow = pvalCreateNode(PV_WORD);
5701  pval *dom = pvalCreateNode(PV_WORD);
5702  pval *mon = pvalCreateNode(PV_WORD);
5703  if (!pvalCheckType(p, "pvalIfTimeSetCondition", PV_IFTIME))
5704  return;
5705  pvalWordSetString(hr, hour_range);
5706  pvalWordSetString(dow, dow_range);
5707  pvalWordSetString(dom, dom_range);
5708  pvalWordSetString(mon, mon_range);
5709  dom->next = mon;
5710  dow->next = dom;
5711  hr->next = dow;
5712  p->u1.list = hr;
5713 }
5714 
5715  /* is this right??? come back and correct it */
5716 void pvalIfTimeGetCondition( pval *p, char **hour_range, char **dow_range, char **dom_range, char **month_range )
5717 {
5718  if (!pvalCheckType(p, "pvalIfTimeGetCondition", PV_IFTIME))
5719  return;
5720  *hour_range = p->u1.list->u1.str;
5721  *dow_range = p->u1.list->next->u1.str;
5722  *dom_range = p->u1.list->next->next->u1.str;
5723  *month_range = p->u1.list->next->next->next->u1.str;
5724 }
5725 
5726 void pvalRandomSetCondition( pval *p, char *percent )
5727 {
5728  if (!pvalCheckType(p, "pvalRandomSetCondition", PV_RANDOM))
5729  return;
5730  p->u1.str = percent;
5731 }
5732 
5734 {
5735  if (!pvalCheckType(p, "pvalRandomGetCondition", PV_RANDOM))
5736  return 0;
5737  return p->u1.str;
5738 }
5739 
5741 {
5742  p->u2.statements = statement;
5743 }
5744 
5746 {
5747  p->u3.else_statements = statement;
5748 }
5749 
5751 {
5752  return p->u2.statements;
5753 }
5754 
5756 {
5757  return p->u3.else_statements;
5758 }
5759 
5760 void pvalSwitchSetTestexpr( pval *p, char *expr )
5761 {
5762  if (!pvalCheckType(p, "pvalSwitchSetTestexpr", PV_SWITCH))
5763  return;
5764  p->u1.str = expr;
5765 }
5766 
5768 {
5769  if (!pvalCheckType(p, "pvalSwitchGetTestexpr", PV_SWITCH))
5770  return 0;
5771  return p->u1.str;
5772 }
5773 
5774 void pvalSwitchAddCase( pval *p, pval *Case )
5775 {
5776  if (!pvalCheckType(p, "pvalSwitchAddCase", PV_SWITCH))
5777  return;
5778  if (!pvalCheckType(Case, "pvalSwitchAddCase", PV_CASE))
5779  return;
5780  if (!p->u2.statements)
5781  p->u2.statements = Case;
5782  else
5783  linku1(p->u2.statements, Case);
5784 }
5785 
5786 pval* pvalSwitchWalkCases( pval *p, pval **next_case )
5787 {
5788  if (!pvalCheckType(p, "pvalSwitchWalkCases", PV_SWITCH))
5789  return 0;
5790  if (!(*next_case))
5791  *next_case = p->u2.statements;
5792  else {
5793  *next_case = (*next_case)->next;
5794  }
5795  return *next_case;
5796 }
5797 
5798 
5799 void pvalExtenSetName( pval *p, char *name )
5800 {
5801  if (!pvalCheckType(p, "pvalExtenSetName", PV_EXTENSION))
5802  return;
5803  p->u1.str = name;
5804 }
5805 
5807 {
5808  if (!pvalCheckType(p, "pvalExtenGetName", PV_EXTENSION))
5809  return 0;
5810  return p->u1.str;
5811 }
5812 
5814 {
5815  if (!pvalCheckType(p, "pvalExtenSetRegexten", PV_EXTENSION))
5816  return;
5817  p->u4.regexten = 1;
5818 }
5819 
5821 {
5822  if (!pvalCheckType(p, "pvalExtenUnSetRegexten", PV_EXTENSION))
5823  return;
5824  p->u4.regexten = 0;
5825 }
5826 
5828 {
5829  if (!pvalCheckType(p, "pvalExtenGetRegexten", PV_EXTENSION))
5830  return 0;
5831  return p->u4.regexten;
5832 }
5833 
5834 void pvalExtenSetHints( pval *p, char *hints )
5835 {
5836  if (!pvalCheckType(p, "pvalExtenSetHints", PV_EXTENSION))
5837  return;
5838  p->u3.hints = hints;
5839 }
5840 
5842 {
5843  if (!pvalCheckType(p, "pvalExtenGetHints", PV_EXTENSION))
5844  return 0;
5845  return p->u3.hints;
5846 }
5847 
5848 void pvalExtenSetStatement( pval *p, pval *statement )
5849 {
5850  if (!pvalCheckType(p, "pvalExtenSetStatement", PV_EXTENSION))
5851  return;
5852  p->u2.statements = statement;
5853 }
5854 
5856 {
5857  if (!pvalCheckType(p, "pvalExtenGetStatement", PV_EXTENSION))
5858  return 0;
5859  return p->u2.statements;
5860 }
5861 
5862 
5863 void pvalIgnorePatSetPattern( pval *p, char *pat )
5864 {
5865  if (!pvalCheckType(p, "pvalIgnorePatSetPattern", PV_IGNOREPAT))
5866  return;
5867  p->u1.str = pat;
5868 }
5869 
5871 {
5872  if (!pvalCheckType(p, "pvalIgnorePatGetPattern", PV_IGNOREPAT))
5873  return 0;
5874  return p->u1.str;
5875 }
5876 
5877 
5878 void pvalGlobalsAddStatement( pval *p, pval *statement )
5879 {
5880  if (p->type != PV_GLOBALS) {
5881  ast_log(LOG_ERROR, "pvalGlobalsAddStatement called where first arg is not a Globals!\n");
5882  } else {
5883  if (!p->u1.statements) {
5884  p->u1.statements = statement;
5885  } else {
5886  p->u1.statements = linku1(p->u1.statements,statement);
5887  }
5888  }
5889 }
5890 
5891 pval* pvalGlobalsWalkStatements( pval *p, pval **next_statement )
5892 {
5893  if (!pvalCheckType(p, "pvalGlobalsWalkStatements", PV_GLOBALS))
5894  return 0;
5895  if (!*next_statement) {
5896  *next_statement = p;
5897  return p;
5898  } else {
5899  *next_statement = (*next_statement)->next;
5900  return (*next_statement)->next;
5901  }
5902 }
5903 
5904 
5905 void pvalTopLevAddObject( pval *p, pval *contextOrObj )
5906 {
5907  if (p) {
5908  linku1(p,contextOrObj);
5909  } else {
5910  ast_log(LOG_ERROR, "First arg to pvalTopLevel is NULL!\n");
5911  }
5912 }
5913 
5915 {
5916  if (!*next_obj) {
5917  *next_obj = p;
5918  return p;
5919  } else {
5920  *next_obj = (*next_obj)->next;
5921  return (*next_obj)->next;
5922  }
5923 }
5924 
5925 /* append second element to the list in the first one via next pointers */
5926 pval * linku1(pval *head, pval *tail)
5927 {
5928  if (!head)
5929  return tail;
5930  if (tail) {
5931  if (!head->next) {
5932  head->next = tail;
5933  } else {
5934  head->u1_last->next = tail;
5935  }
5936  head->u1_last = tail;
5937  tail->prev = head; /* the dad link only points to containers */
5938  }
5939  return head;
5940 }
5941 
pval * pvalCasePatDefWalkStatements(pval *p, pval **statement)
Definition: pval.c:5347
char * pvalSwitchGetTestexpr(pval *p)
Definition: pval.c:5767
void pvalContextUnsetAbstract(pval *p)
Definition: pval.c:5200
struct ast_include * ast_walk_context_includes(struct ast_context *con, struct ast_include *inc)
Definition: pbx.c:11203
pval * pvalMacroWalkStatements(pval *p, pval **next_statement)
Definition: pval.c:5165
union pval::@198 u1
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: pbx.c:4676
void pvalGotoSetTarget(pval *p, char *context, char *exten, char *label)
Definition: pval.c:5547
void pvalConditionalSetThenStatement(pval *p, pval *statement)
Definition: pval.c:5740
void pvalTopLevAddObject(pval *p, pval *contextOrObj)
Definition: pval.c:5905
char * pvalCasePatGetVal(pval *p)
Definition: pval.c:5334
void pvalForSetInit(pval *p, char *init)
Definition: pval.c:5625
static int context_used(struct ael_extension *exten_list, struct ast_context *context)
Definition: pval.c:4436
void check_pval_item(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2364
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
int regexten
Definition: pval.h:90
static int control_statement_count
Definition: pval.c:2929
char * for_inc
Definition: pval.h:77
void destroy_pval_item(pval *item)
Definition: pval.c:4711
int ast_context_add_include2(struct ast_context *con, const char *include, const char *registrar)
Add a context include.
Definition: pbx.c:8411
static void find_pval_gotos(pval *item, int lev)
Definition: pval.c:1557
void pvalAppCallAddArg(pval *p, pval *arg)
Definition: pval.c:5304
void check_switch_expr(pval *item, struct argapp *apps)
Definition: pval.c:2191
void pvalVarDecSetValue(pval *p, char *value)
Definition: pval.c:5526
void check_pval(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2872
struct ael_priority * new_prio(void)
Definition: pval.c:2931
Asterisk main include file. File version handling, generic pbx functions.
static struct pval * in_macro(pval *item)
Definition: pval.c:1084
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
struct pval * origin
Definition: ael_structs.h:95
static int check_break(pval *item)
Definition: pval.c:1045
static int errs
Definition: pval.c:67
struct pval * list
Definition: pval.h:60
#define malloc(a)
Definition: astmm.h:88
char * pvalMacroCallGetMacroName(pval *p)
Definition: pval.c:5246
static struct pval * find_label_in_current_extension(const char *label, pval *curr_ext)
Definition: pval.c:1925
void pvalExtenSetName(pval *p, char *name)
Definition: pval.c:5799
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
Definition: ast_expr2.c:325
Definition: pval.h:32
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
static void fix_gotos_in_extensions(struct ael_extension *exten)
Definition: pval.c:4393
Definition: pbx.c:1301
void pvalESwitchesAddSwitch(pval *p, char *name)
Definition: pval.c:5409
struct pval * dad
Definition: pval.h:96
void pvalMacroAddArg(pval *p, pval *arg)
Definition: pval.c:5130
void pvalExtenUnSetRegexten(pval *p)
Definition: pval.c:5820
void pvalCasePatSetVal(pval *p, char *val)
Definition: pval.c:5327
char * pvalMacroGetName(pval *p)
Definition: pval.c:5116
void pvalLabelSetName(pval *p, char *name)
Definition: pval.c:5610
Definition: pval.h:29
void pvalIfSetCondition(pval *p, char *expr)
Definition: pval.c:5683
void pvalExtenSetRegexten(pval *p)
Definition: pval.c:5813
struct ael_priority * goto_true
Definition: ael_structs.h:98
#define LOG_WARNING
Definition: logger.h:144
void pvalMacroSetArglist(pval *p, pval *arglist)
Definition: pval.c:5123
void pvalContextSetName(pval *p, char *name)
Definition: pval.c:5179
char * pvalIncludesWalk(pval *p, pval **next_item)
Definition: pval.c:5487
int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add an extension to an extension context, this time with an ast_context *.
Definition: pbx.c:9052
static void linkexten(struct ael_extension *exten, struct ael_extension *add)
Definition: pval.c:3039
struct ael_priority * plist_last
Definition: ael_structs.h:116
static int label_inside_case(pval *label)
Definition: pval.c:3025
void pvalWordSetString(pval *p, char *str)
Definition: pval.c:5094
void add_extensions(struct ael_extension *exten)
Definition: pval.c:4251
struct pval * statements
Definition: pval.h:61
#define ast_compat_app_set
Definition: options.h:144
Configuration File Parser.
char * pvalAppCallGetAppName(pval *p)
Definition: pval.c:5290
char * pvalExtenGetHints(pval *p)
Definition: pval.c:5841
void pvalIncludeGetTimeConstraints(pval *p, char **hour_range, char **dom_range, char **dow_range, char **month_range)
Definition: pval.c:5470
void pvalIgnorePatSetPattern(pval *p, char *pat)
Definition: pval.c:5863
static struct ast_threadstorage buf2
void pvalAppCallSetAppName(pval *p, char *name)
Definition: pval.c:5283
int pvalContextGetAbstract(pval *p)
Definition: pval.c:5207
char * pvalLabelGetName(pval *p)
Definition: pval.c:5617
struct ael_priority * plist
Definition: ael_structs.h:115
static void check_day(pval *DAY)
Definition: pval.c:944
void pvalSwitchSetTestexpr(pval *p, char *expr)
Definition: pval.c:5760
Definition: pval.h:22
int startline
Definition: pval.h:51
const char * str
Definition: app_jack.c:144
struct ael_priority * goto_false
Definition: ael_structs.h:99
pval * pvalCreateNode(pvaltype type)
Definition: pval.c:5081
char * pvalVarDecGetValue(pval *p)
Definition: pval.c:5540
char * appargs
Definition: ael_structs.h:93
int value
Definition: syslog.c:39
int is_float(char *arg)
Definition: pval.c:1970
void pvalMacroCallAddArg(pval *p, pval *arg)
Definition: pval.c:5260
int abstract
Definition: pval.h:80
const char * ext
Definition: http.c:112
Definition: pval.h:8
int ast_context_add_switch2(struct ast_context *con, const char *sw, const char *data, int eval, const char *registrar)
Adds a switch (first param is a ast_context)
Definition: pbx.c:8494
static struct ao2_container * hints
Definition: pbx.c:1314
Definition: pval.h:110
void ast_free_ptr(void *ptr)
char * pvalForGetInc(pval *p)
Definition: pval.c:5667
#define calloc(a, b)
Definition: astmm.h:79
static void check_abstract_reference(pval *abstract_context)
Definition: pval.c:2336
int pvalExtenGetRegexten(pval *p)
Definition: pval.c:5827
static int gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context)
Definition: pval.c:3348
Utility functions.
struct ael_extension * next_exten
Definition: ael_structs.h:117
union pval::@200 u3
union pval::@199 u2
static struct pval * in_context(pval *item)
Definition: pval.c:1097
struct ast_context * context
Definition: ael_structs.h:113
struct ael_extension * new_exten(void)
Definition: pval.c:2937
void pvalGotoGetTarget(pval *p, char **context, char **exten, char **label)
Definition: pval.c:5583
char * cidmatch
Definition: ael_structs.h:106
static pval * get_contxt(pval *p)
Definition: pval.c:4383
char * val
Definition: pval.h:70
#define DAY
void pvalForSetStatement(pval *p, pval *statement)
Definition: pval.c:5646
pval * pvalSwitchWalkCases(pval *p, pval **next_case)
Definition: pval.c:5786
char * pvalESwitchesWalkNames(pval *p, pval **next_item)
Definition: pval.c:5419
static const char app[]
Definition: app_adsiprog.c:49
static int check_continue(pval *item)
Definition: pval.c:1065
pval * pvalTopLevWalkObjects(pval *p, pval **next_obj)
Definition: pval.c:5914
static int notes
Definition: pval.c:68
General Asterisk PBX channel definitions.
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: pbx.c:11179
static int extension_matches(pval *here, const char *exten, const char *pattern)
Definition: pval.c:696
static pval * current_extension
Definition: pval.c:76
char * pvalVarDecGetVarname(pval *p)
Definition: pval.c:5533
static int label_count
Definition: pval.c:83
Definition: pval.h:13
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
static int in_abstract_context
Definition: pval.c:81
char * pvalIfGetCondition(pval *p)
Definition: pval.c:5690
#define AST_MAX_EXTENSION
Definition: channel.h:135
static void check_timerange(pval *p)
Definition: pval.c:837
void pvalConditionalSetElseStatement(pval *p, pval *statement)
Definition: pval.c:5745
char * filename
Definition: pval.h:55
char * pvalWordGetString(pval *p)
Definition: pval.c:5101
void pvalForSetTest(pval *p, char *test)
Definition: pval.c:5632
static void check_macro_returns(pval *macro)
Definition: pval.c:652
struct pval * goto_target
Definition: pval.h:72
pval * pvalAppCallWalkArgs(pval *p, pval **args)
Definition: pval.c:5314
static void print_pval(FILE *fin, pval *item, int depth)
Definition: pval.c:117
pvaltype pvalObjectGetType(pval *p)
Definition: pval.c:5088
Definition: pval.h:21
struct ael_extension * exten
Definition: ael_structs.h:96
void ael2_print(char *fname, pval *tree)
Definition: pval.c:384
static char next_item(const char *format)
Definition: say.c:3954
void pvalVarDecSetVarname(pval *p, char *name)
Definition: pval.c:5519
pval * pvalConditionalGetElseStatement(pval *p)
Definition: pval.c:5755
struct ast_ignorepat * ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip)
Definition: pbx.c:11212
char * str
Definition: pval.h:59
#define PRIORITY_HINT
Definition: pbx.h:53
pval * pvalConditionalGetThenStatement(pval *p)
Definition: pval.c:5750
void pvalIfTimeSetCondition(pval *p, char *hour_range, char *dow_range, char *dom_range, char *mon_range)
Definition: pval.c:5697
Definition: pval.h:48
struct ael_priority * loop_break
Definition: ael_structs.h:119
int ast_context_add_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition: pbx.c:8611
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:11073
Core PBX routines and definitions.
void destroy_pval(pval *item)
Definition: pval.c:4979
struct ast_flags ast_compat
Definition: asterisk.c:179
void pvalGlobalsAddStatement(pval *p, pval *statement)
Definition: pval.c:5878
char * for_test
Definition: pval.h:71
void pvalSwitchesAddSwitch(pval *p, char *name)
Definition: pval.c:5387
int count_labels_in_current_context(char *label)
struct ael_extension * compiled_label
Definition: pval.h:83
static struct pval * find_label_in_current_context(char *exten, char *label, pval *curr_cont)
Definition: pval.c:1886
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
struct ast_custom_function * ast_custom_function_find(const char *name)
Definition: pbx.c:3800
static char expr_output[2096]
Definition: pval.c:62
int goto_target_in_case
Definition: pval.h:82
char * hints
Definition: pval.h:81
void ast_expr_clear_extra_error_info(void)
Definition: ast_expr2f.c:2475
char * app
Definition: ael_structs.h:92
static char * registrar
Definition: pval.c:72
static void gen_match_to_pattern(char *pattern, char *result)
Definition: pval.c:3068
#define LOG_ERROR
Definition: logger.h:155
char * pvalRandomGetCondition(pval *p)
Definition: pval.c:5733
struct pval * else_statements
Definition: pval.h:78
int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
Definition: pval.c:4451
#define free(a)
Definition: astmm.h:94
static void check_goto(pval *item)
Definition: pval.c:1232
static struct @350 args
Definition: pval.h:24
union pval::@201 u4
struct pval * arglist
Definition: pval.h:68
int endcol
Definition: pval.h:54
struct ael_priority * loop_continue
Definition: ael_structs.h:120
void pvalMacroSetName(pval *p, char *name)
Definition: pval.c:5109
struct pval * u1_last
Definition: pval.h:64
#define BUF_SIZE
Definition: pval.c:63
struct sla_ringing_trunk * first
Definition: app_meetme.c:965
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int count_labels
Definition: pval.c:82
char * pvalCatchGetExtName(pval *p)
Definition: pval.c:5365
static struct ast_hashtab * local_table
Definition: pbx_config.c:61
pvaltype
Definition: pval.h:6
void pvalExtenSetStatement(pval *p, pval *statement)
Definition: pval.c:5848
static struct pval * find_label_in_current_db(const char *context, const char *exten, const char *label)
Definition: pval.c:1936
char * pvalExtenGetName(pval *p)
Definition: pval.c:5806
static void check_label(pval *item)
Definition: pval.c:1113
static struct ast_threadstorage buf1
#define STATUS_SUCCESS
Definition: extconf.h:245
Definition: pval.h:9
Definition: pval.h:31
pval * linku1(pval *head, pval *tail)
Definition: pval.c:5926
static const char name[]
static void check_includes(pval *includes)
Definition: pval.c:818
pval * pvalMacroCallWalkArgs(pval *p, pval **args)
Definition: pval.c:5270
Definition: pval.h:25
pval * pvalCatchGetStatement(pval *p)
Definition: pval.c:5379
void pvalIncludesAddIncludeWithTimeConstraints(pval *p, const char *include, char *hour_range, char *dom_range, char *dow_range, char *month_range)
Definition: pval.c:5443
void pvalContextSetAbstract(pval *p)
Definition: pval.c:5193
int contains_switch(pval *item)
Definition: pval.c:3336
struct ael_priority * next
Definition: ael_structs.h:100
Structures for AEL - the Asterisk extension language.
char * pvalIgnorePatGetPattern(pval *p)
Definition: pval.c:5870
int stacklen
Definition: extconf.h:234
pvaltype type
Definition: pval.h:50
void pvalRandomSetCondition(pval *p, char *percent)
Definition: pval.c:5726
static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
Definition: pval.c:4356
int localized_pbx_load_module(void)
int is_int(char *arg)
Definition: pval.c:1979
int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
Parse and set a single channel variable, where the name and value are separated with an &#39;=&#39; character...
Definition: pbx.c:10603
char * pvalContextGetName(pval *p)
Definition: pval.c:5186
struct pval * find_context(char *name)
Definition: pval.c:1960
static const char type[]
Definition: chan_nbs.c:57
void pvalCatchSetStatement(pval *p, pval *statement)
Definition: pval.c:5372
Structure used to handle boolean flags.
Definition: utils.h:200
void ast_expr_register_extra_error_info(char *errmsg)
Definition: ast_expr2f.c:2469
static char * months[]
Definition: pval.c:991
pval * pvalGlobalsWalkStatements(pval *p, pval **next_statement)
Definition: pval.c:5891
Support for logging to various files, console and syslog Configuration in file logger.conf.
static void check_month(pval *MON)
Definition: pval.c:1007
char * pvalSwitchesWalkNames(pval *p, pval **next_item)
Definition: pval.c:5397
void destroy_extensions(struct ael_extension *exten)
Definition: pval.c:2985
struct ast_sw * ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw)
Definition: pbx.c:11188
void pvalStatementBlockAddStatement(pval *p, pval *statement)
Definition: pval.c:5500
int priority_num
Definition: ael_structs.h:89
Definition: pval.h:30
Definition: pval.h:23
static pval * current_context
Definition: pval.c:75
static void remove_spaces_before_equals(char *str)
Definition: pval.c:3045
void set_priorities(struct ael_extension *exten)
Definition: pval.c:4225
void pvalIncludesAddInclude(pval *p, const char *include)
Definition: pval.c:5432
Standard Command Line Interface.
int find_switch_item(pval *item)
Definition: pval.c:3097
static char * days[]
Definition: pval.c:893
int check_app_args(pval *appcall, pval *arglist, struct argapp *app)
Definition: pval.c:2137
pval * pvalMacroWalkArgs(pval *p, pval **arg)
Definition: pval.c:5141
static int warns
Definition: pval.c:67
struct pval * prev
Definition: pval.h:97
static struct ast_context * local_contexts
Definition: pbx_config.c:60
struct argapp * next
Definition: pval.h:112
void pvalCasePatDefAddStatement(pval *p, pval *statement)
Definition: pval.c:5339
void pvalMacroAddStatement(pval *p, pval *statement)
Definition: pval.c:5153
int is_empty(char *arg)
Definition: pval.c:1988
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static struct pval * find_first_label_in_current_context(char *label, pval *curr_cont)
Definition: pval.c:1846
struct pval * find_macro(char *name)
Definition: pval.c:1950
pval * pvalStatementBlockWalkStatements(pval *p, pval **next_statement)
Definition: pval.c:5507
pval * pvalForGetStatement(pval *p)
Definition: pval.c:5674
struct pval * next
Definition: pval.h:93
void pvalSwitchAddCase(pval *p, pval *Case)
Definition: pval.c:5774
void pvalMacroCallSetArglist(pval *p, pval *arglist)
Definition: pval.c:5253
void ael2_semantic_check(pval *item, int *errs, int *warns, int *notes)
Definition: pval.c:2892
static void check_expr2_input(pval *expr, char *str)
Definition: pval.c:808
static const char * match_exten
Definition: pval.c:79
void pvalExtenSetHints(pval *p, char *hints)
Definition: pval.c:5834
int pvalCheckType(pval *p, char *funcname, pvaltype type)
Definition: pval.c:5070
void pvalAppCallSetArglist(pval *p, pval *arglist)
Definition: pval.c:5297
static int return_on_context_match
Definition: pval.c:84
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: pbx.c:3013
ael_priority_type type
Definition: ael_structs.h:90
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
Definition: pval.h:27
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:7726
struct pval * for_statements
Definition: pval.h:89
char * pvalForGetTest(pval *p)
Definition: pval.c:5660
#define strdup(a)
Definition: astmm.h:106
void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
Definition: pval.c:2943
void pvalCatchSetExtName(pval *p, char *name)
Definition: pval.c:5358
pval * pvalExtenGetStatement(pval *p)
Definition: pval.c:5855
void pvalMacroCallSetMacroName(pval *p, char *name)
Definition: pval.c:5239
void traverse_pval_template(pval *item, int depth)
Definition: pval.c:636
pval * pvalContextWalkStatements(pval *p, pval **statements)
Definition: pval.c:5226
static pval * get_goto_target(pval *item)
Definition: pval.c:1160
static pval * last_matched_label
Definition: pval.c:85
Asterisk module definitions.
const char * ast_config_AST_VAR_DIR
Definition: asterisk.c:261
int endline
Definition: pval.h:52
int startcol
Definition: pval.h:53
static void print_pval_list(FILE *fin, pval *item, int depth)
Definition: pval.c:375
static pval * current_db
Definition: pval.c:74
void pvalForSetInc(pval *p, char *inc)
Definition: pval.c:5639
struct pval * match_pval(pval *item)
Definition: pval.c:1818
ast_context: An extension context
Definition: pbx.c:955
void traverse_pval_item_template(pval *item, int depth)
Definition: pval.c:402
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
Definition: ast_expr2f.c:2396
static const char * match_context
Definition: pval.c:78
char * pvalForGetInit(pval *p)
Definition: pval.c:5653
Definition: pval.h:26
char * for_init
Definition: pval.h:62
Definition: pval.h:16
static void check_dow(pval *DOW)
get_dow: Get day of week
Definition: pval.c:905
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
struct pval * macro_statements
Definition: pval.h:79
static const char * match_label
Definition: pval.c:80
static void check_context_names(void)
Definition: pval.c:2317
static pval * get_extension_or_contxt(pval *p)
Definition: pval.c:4373
static struct pval * match_pval_item(pval *item)
Definition: pval.c:1570
static void find_pval_goto_item(pval *item, int lev)
Definition: pval.c:1386
void pvalContextAddStatement(pval *p, pval *statement)
Definition: pval.c:5216
void pvalIfTimeGetCondition(pval *p, char **hour_range, char **dow_range, char **dom_range, char **month_range)
Definition: pval.c:5716