00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "asterisk.h"
00026
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 136726 $")
00028
00029 #include <sys/types.h>
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <ctype.h>
00035 #include <errno.h>
00036 #include <regex.h>
00037 #include <sys/stat.h>
00038
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/config.h"
00041 #include "asterisk/module.h"
00042 #include "asterisk/logger.h"
00043 #include "asterisk/cli.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/callerid.h"
00046 #include "asterisk/ael_structs.h"
00047 #ifdef AAL_ARGCHECK
00048 #include "asterisk/argdesc.h"
00049 #include <dirent.h>
00050 #endif
00051
00052 static char expr_output[2096];
00053
00054
00055
00056 #define DEBUG_READ (1 << 0)
00057 #define DEBUG_TOKENS (1 << 1)
00058 #define DEBUG_MACROS (1 << 2)
00059 #define DEBUG_CONTEXTS (1 << 3)
00060
00061 #define AST_MAX_FILENAME_LEN 256
00062
00063 static char *config = "extensions.ael";
00064 static char *registrar = "pbx_ael";
00065 static int pbx_load_module(void);
00066
00067 static int errs, warns;
00068 static int notes;
00069
00070 #ifndef AAL_ARGCHECK
00071
00072
00073
00074
00075
00076
00077 struct argapp
00078 {
00079 struct argapp *next;
00080 };
00081
00082 #endif
00083
00084 #ifdef AAL_ARGCHECK
00085 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00086 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00087 int ael_is_funcname(char *name);
00088 #endif
00089
00090 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00091 void check_pval(pval *item, struct argapp *apps, int in_globals);
00092 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00093 void check_switch_expr(pval *item, struct argapp *apps);
00094 void ast_expr_register_extra_error_info(char *errmsg);
00095 void ast_expr_clear_extra_error_info(void);
00096 int ast_expr(char *expr, char *buf, int length);
00097 struct pval *find_macro(char *name);
00098 struct pval *find_context(char *name);
00099 struct pval *find_context(char *name);
00100 struct pval *find_macro(char *name);
00101 struct ael_priority *new_prio(void);
00102 struct ael_extension *new_exten(void);
00103 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten);
00104 void destroy_extensions(struct ael_extension *exten);
00105 static void linkexten(struct ael_extension *exten, struct ael_extension *add);
00106 static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context );
00107 void set_priorities(struct ael_extension *exten);
00108 void add_extensions(struct ael_extension *exten);
00109 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
00110 void destroy_pval(pval *item);
00111 void destroy_pval_item(pval *item);
00112 int is_float(char *arg );
00113 int is_int(char *arg );
00114 int is_empty(char *arg);
00115 static pval *current_db=0;
00116 static pval *current_context=0;
00117 static pval *current_extension=0;
00118
00119 static const char *match_context;
00120 static const char *match_exten;
00121 static const char *match_label;
00122 static int in_abstract_context;
00123 static int count_labels;
00124 static int label_count;
00125 static int return_on_context_match;
00126 static pval *last_matched_label;
00127 struct pval *match_pval(pval *item);
00128 static void check_timerange(pval *p);
00129 static void check_dow(pval *DOW);
00130 static void check_day(pval *DAY);
00131 static void check_month(pval *MON);
00132 static void check_expr2_input(pval *expr, char *str);
00133 static int extension_matches(pval *here, const char *exten, const char *pattern);
00134 static void check_goto(pval *item);
00135 static void find_pval_goto_item(pval *item, int lev);
00136 static void find_pval_gotos(pval *item, int lev);
00137
00138 static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont);
00139 static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont);
00140 static void print_pval_list(FILE *fin, pval *item, int depth);
00141
00142 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext);
00143 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label);
00144 static pval *get_goto_target(pval *item);
00145 static int label_inside_case(pval *label);
00146 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem);
00147 static void fix_gotos_in_extensions(struct ael_extension *exten);
00148 static pval *get_extension_or_contxt(pval *p);
00149 static pval *get_contxt(pval *p);
00150 static void remove_spaces_before_equals(char *str);
00151 static void substitute_commas(char *str);
00152
00153
00154 static void substitute_commas(char *str)
00155 {
00156 char *p = str;
00157
00158 while (p && *p)
00159 {
00160 if (*p == ',' && ((p != str && *(p-1) != '\\')
00161 || p == str))
00162 *p = '|';
00163 if (*p == '\\' && *(p+1) == ',') {
00164 char *q = p;
00165 while (*q) {
00166 *q = *(q+1);
00167 q++;
00168 }
00169 }
00170 p++;
00171 }
00172 }
00173
00174
00175
00176
00177 static void print_pval(FILE *fin, pval *item, int depth)
00178 {
00179 int i;
00180 pval *lp;
00181
00182 for (i=0; i<depth; i++) {
00183 fprintf(fin, "\t");
00184 }
00185
00186 switch ( item->type ) {
00187 case PV_WORD:
00188 fprintf(fin,"%s;\n", item->u1.str);
00189 break;
00190
00191 case PV_MACRO:
00192 fprintf(fin,"macro %s(", item->u1.str);
00193 for (lp=item->u2.arglist; lp; lp=lp->next) {
00194 if (lp != item->u2.arglist )
00195 fprintf(fin,", ");
00196 fprintf(fin,"%s", lp->u1.str);
00197 }
00198 fprintf(fin,") {\n");
00199 print_pval_list(fin,item->u3.macro_statements,depth+1);
00200 for (i=0; i<depth; i++) {
00201 fprintf(fin,"\t");
00202 }
00203 fprintf(fin,"};\n\n");
00204 break;
00205
00206 case PV_CONTEXT:
00207 if ( item->u3.abstract )
00208 fprintf(fin,"abstract context %s {\n", item->u1.str);
00209 else
00210 fprintf(fin,"context %s {\n", item->u1.str);
00211 print_pval_list(fin,item->u2.statements,depth+1);
00212 for (i=0; i<depth; i++) {
00213 fprintf(fin,"\t");
00214 }
00215 fprintf(fin,"};\n\n");
00216 break;
00217
00218 case PV_MACRO_CALL:
00219 fprintf(fin,"&%s(", item->u1.str);
00220 for (lp=item->u2.arglist; lp; lp=lp->next) {
00221 if ( lp != item->u2.arglist )
00222 fprintf(fin,", ");
00223 fprintf(fin,"%s", lp->u1.str);
00224 }
00225 fprintf(fin,");\n");
00226 break;
00227
00228 case PV_APPLICATION_CALL:
00229 fprintf(fin,"%s(", item->u1.str);
00230 for (lp=item->u2.arglist; lp; lp=lp->next) {
00231 if ( lp != item->u2.arglist )
00232 fprintf(fin,",");
00233 fprintf(fin,"%s", lp->u1.str);
00234 }
00235 fprintf(fin,");\n");
00236 break;
00237
00238 case PV_CASE:
00239 fprintf(fin,"case %s:\n", item->u1.str);
00240 print_pval_list(fin,item->u2.statements, depth+1);
00241 break;
00242
00243 case PV_PATTERN:
00244 fprintf(fin,"pattern %s:\n", item->u1.str);
00245 print_pval_list(fin,item->u2.statements, depth+1);
00246 break;
00247
00248 case PV_DEFAULT:
00249 fprintf(fin,"default:\n");
00250 print_pval_list(fin,item->u2.statements, depth+1);
00251 break;
00252
00253 case PV_CATCH:
00254 fprintf(fin,"catch %s {\n", item->u1.str);
00255 print_pval_list(fin,item->u2.statements, depth+1);
00256 for (i=0; i<depth; i++) {
00257 fprintf(fin,"\t");
00258 }
00259 fprintf(fin,"};\n");
00260 break;
00261
00262 case PV_SWITCHES:
00263 fprintf(fin,"switches {\n");
00264 print_pval_list(fin,item->u1.list,depth+1);
00265 for (i=0; i<depth; i++) {
00266 fprintf(fin,"\t");
00267 }
00268 fprintf(fin,"};\n");
00269 break;
00270
00271 case PV_ESWITCHES:
00272 fprintf(fin,"eswitches {\n");
00273 print_pval_list(fin,item->u1.list,depth+1);
00274 for (i=0; i<depth; i++) {
00275 fprintf(fin,"\t");
00276 }
00277 fprintf(fin,"};\n");
00278 break;
00279
00280 case PV_INCLUDES:
00281 fprintf(fin,"includes {\n");
00282 for (lp=item->u1.list; lp; lp=lp->next) {
00283 for (i=0; i<depth+1; i++) {
00284 fprintf(fin,"\t");
00285 }
00286 fprintf(fin,"%s", lp->u1.str);
00287 if ( lp->u2.arglist )
00288 fprintf(fin,"|%s|%s|%s|%s",
00289 lp->u2.arglist->u1.str,
00290 lp->u2.arglist->next->u1.str,
00291 lp->u2.arglist->next->next->u1.str,
00292 lp->u2.arglist->next->next->next->u1.str
00293 );
00294 fprintf(fin,";\n");
00295 }
00296
00297 print_pval_list(fin,item->u1.list,depth+1);
00298 for (i=0; i<depth; i++) {
00299 fprintf(fin,"\t");
00300 }
00301 fprintf(fin,"};\n");
00302 break;
00303
00304 case PV_STATEMENTBLOCK:
00305 fprintf(fin,"{\n");
00306 print_pval_list(fin,item->u1.list, depth+1);
00307 for (i=0; i<depth; i++) {
00308 fprintf(fin,"\t");
00309 }
00310 fprintf(fin,"};\n");
00311 break;
00312
00313 case PV_VARDEC:
00314 fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
00315 break;
00316
00317 case PV_GOTO:
00318 fprintf(fin,"goto %s", item->u1.list->u1.str);
00319 if ( item->u1.list->next )
00320 fprintf(fin,"|%s", item->u1.list->next->u1.str);
00321 if ( item->u1.list->next && item->u1.list->next->next )
00322 fprintf(fin,"|%s", item->u1.list->next->next->u1.str);
00323 fprintf(fin,"\n");
00324 break;
00325
00326 case PV_LABEL:
00327 fprintf(fin,"%s:\n", item->u1.str);
00328 break;
00329
00330 case PV_FOR:
00331 fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
00332 print_pval_list(fin,item->u4.for_statements,depth+1);
00333 break;
00334
00335 case PV_WHILE:
00336 fprintf(fin,"while (%s)\n", item->u1.str);
00337 print_pval_list(fin,item->u2.statements,depth+1);
00338 break;
00339
00340 case PV_BREAK:
00341 fprintf(fin,"break;\n");
00342 break;
00343
00344 case PV_RETURN:
00345 fprintf(fin,"return;\n");
00346 break;
00347
00348 case PV_CONTINUE:
00349 fprintf(fin,"continue;\n");
00350 break;
00351
00352 case PV_RANDOM:
00353 case PV_IFTIME:
00354 case PV_IF:
00355 if ( item->type == PV_IFTIME ) {
00356
00357 fprintf(fin,"ifTime ( %s|%s|%s|%s )\n",
00358 item->u1.list->u1.str,
00359 item->u1.list->next->u1.str,
00360 item->u1.list->next->next->u1.str,
00361 item->u1.list->next->next->next->u1.str
00362 );
00363 } else if ( item->type == PV_RANDOM ) {
00364 fprintf(fin,"random ( %s )\n", item->u1.str );
00365 } else
00366 fprintf(fin,"if ( %s )\n", item->u1.str);
00367 if ( item->u2.statements && item->u2.statements->next ) {
00368 for (i=0; i<depth; i++) {
00369 fprintf(fin,"\t");
00370 }
00371 fprintf(fin,"{\n");
00372 print_pval_list(fin,item->u2.statements,depth+1);
00373 for (i=0; i<depth; i++) {
00374 fprintf(fin,"\t");
00375 }
00376 if ( item->u3.else_statements )
00377 fprintf(fin,"}\n");
00378 else
00379 fprintf(fin,"};\n");
00380 } else if (item->u2.statements ) {
00381 print_pval_list(fin,item->u2.statements,depth+1);
00382 } else {
00383 if (item->u3.else_statements )
00384 fprintf(fin, " {} ");
00385 else
00386 fprintf(fin, " {}; ");
00387 }
00388 if ( item->u3.else_statements ) {
00389 for (i=0; i<depth; i++) {
00390 fprintf(fin,"\t");
00391 }
00392 fprintf(fin,"else\n");
00393 print_pval_list(fin,item->u3.else_statements, depth);
00394 }
00395 break;
00396
00397 case PV_SWITCH:
00398 fprintf(fin,"switch( %s ) {\n", item->u1.str);
00399 print_pval_list(fin,item->u2.statements,depth+1);
00400 for (i=0; i<depth; i++) {
00401 fprintf(fin,"\t");
00402 }
00403 fprintf(fin,"}\n");
00404 break;
00405
00406 case PV_EXTENSION:
00407 if ( item->u4.regexten )
00408 fprintf(fin, "regexten ");
00409 if ( item->u3.hints )
00410 fprintf(fin,"hints(%s) ", item->u3.hints);
00411
00412 fprintf(fin,"%s => \n", item->u1.str);
00413 print_pval_list(fin,item->u2.statements,depth+1);
00414 break;
00415
00416 case PV_IGNOREPAT:
00417 fprintf(fin,"ignorepat => %s\n", item->u1.str);
00418 break;
00419
00420 case PV_GLOBALS:
00421 fprintf(fin,"globals {\n");
00422 print_pval_list(fin,item->u1.statements,depth+1);
00423 for (i=0; i<depth; i++) {
00424 fprintf(fin,"\t");
00425 }
00426 fprintf(fin,"}\n");
00427 break;
00428 }
00429 }
00430
00431 static void print_pval_list(FILE *fin, pval *item, int depth)
00432 {
00433 pval *i;
00434
00435 for (i=item; i; i=i->next) {
00436 print_pval(fin, i, depth);
00437 }
00438 }
00439
00440 #if 0
00441 static void ael2_print(char *fname, pval *tree)
00442 {
00443 FILE *fin = fopen(fname,"w");
00444 if ( !fin ) {
00445 ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
00446 return;
00447 }
00448 print_pval_list(fin, tree, 0);
00449 fclose(fin);
00450 }
00451 #endif
00452
00453
00454
00455
00456 void traverse_pval_template(pval *item, int depth);
00457 void traverse_pval_item_template(pval *item, int depth);
00458
00459
00460 void traverse_pval_item_template(pval *item, int depth)
00461
00462 {
00463 pval *lp;
00464
00465 switch ( item->type ) {
00466 case PV_WORD:
00467
00468 break;
00469
00470 case PV_MACRO:
00471
00472
00473
00474
00475
00476
00477
00478 for (lp=item->u2.arglist; lp; lp=lp->next) {
00479
00480 }
00481 traverse_pval_item_template(item->u3.macro_statements,depth+1);
00482 break;
00483
00484 case PV_CONTEXT:
00485
00486
00487
00488
00489 traverse_pval_item_template(item->u2.statements,depth+1);
00490 break;
00491
00492 case PV_MACRO_CALL:
00493
00494
00495
00496
00497
00498 for (lp=item->u2.arglist; lp; lp=lp->next) {
00499 }
00500 break;
00501
00502 case PV_APPLICATION_CALL:
00503
00504
00505
00506
00507
00508 for (lp=item->u2.arglist; lp; lp=lp->next) {
00509 }
00510 break;
00511
00512 case PV_CASE:
00513
00514
00515
00516 traverse_pval_item_template(item->u2.statements,depth+1);
00517 break;
00518
00519 case PV_PATTERN:
00520
00521
00522
00523 traverse_pval_item_template(item->u2.statements,depth+1);
00524 break;
00525
00526 case PV_DEFAULT:
00527
00528
00529
00530 traverse_pval_item_template(item->u2.statements,depth+1);
00531 break;
00532
00533 case PV_CATCH:
00534
00535
00536
00537 traverse_pval_item_template(item->u2.statements,depth+1);
00538 break;
00539
00540 case PV_SWITCHES:
00541
00542
00543 traverse_pval_item_template(item->u1.list,depth+1);
00544 break;
00545
00546 case PV_ESWITCHES:
00547
00548
00549 traverse_pval_item_template(item->u1.list,depth+1);
00550 break;
00551
00552 case PV_INCLUDES:
00553
00554
00555
00556 traverse_pval_item_template(item->u1.list,depth+1);
00557 traverse_pval_item_template(item->u2.arglist,depth+1);
00558 break;
00559
00560 case PV_STATEMENTBLOCK:
00561
00562
00563 traverse_pval_item_template(item->u1.list,depth+1);
00564 break;
00565
00566 case PV_VARDEC:
00567
00568
00569
00570 break;
00571
00572 case PV_GOTO:
00573
00574
00575
00576
00577 if ( item->u1.list->next )
00578 ;
00579 if ( item->u1.list->next && item->u1.list->next->next )
00580 ;
00581
00582 break;
00583
00584 case PV_LABEL:
00585
00586
00587 break;
00588
00589 case PV_FOR:
00590
00591
00592
00593
00594
00595
00596 traverse_pval_item_template(item->u4.for_statements,depth+1);
00597 break;
00598
00599 case PV_WHILE:
00600
00601
00602
00603
00604 traverse_pval_item_template(item->u2.statements,depth+1);
00605 break;
00606
00607 case PV_BREAK:
00608
00609
00610 break;
00611
00612 case PV_RETURN:
00613
00614
00615 break;
00616
00617 case PV_CONTINUE:
00618
00619
00620 break;
00621
00622 case PV_IFTIME:
00623
00624
00625
00626
00627
00628
00629 traverse_pval_item_template(item->u2.statements,depth+1);
00630 if ( item->u3.else_statements ) {
00631 traverse_pval_item_template(item->u3.else_statements,depth+1);
00632 }
00633 break;
00634
00635 case PV_RANDOM:
00636
00637
00638
00639
00640
00641
00642 traverse_pval_item_template(item->u2.statements,depth+1);
00643 if ( item->u3.else_statements ) {
00644 traverse_pval_item_template(item->u3.else_statements,depth+1);
00645 }
00646 break;
00647
00648 case PV_IF:
00649
00650
00651
00652
00653
00654
00655 traverse_pval_item_template(item->u2.statements,depth+1);
00656 if ( item->u3.else_statements ) {
00657 traverse_pval_item_template(item->u3.else_statements,depth+1);
00658 }
00659 break;
00660
00661 case PV_SWITCH:
00662
00663
00664
00665
00666
00667 traverse_pval_item_template(item->u2.statements,depth+1);
00668 break;
00669
00670 case PV_EXTENSION:
00671
00672
00673
00674
00675
00676
00677 traverse_pval_item_template(item->u2.statements,depth+1);
00678 break;
00679
00680 case PV_IGNOREPAT:
00681
00682
00683 break;
00684
00685 case PV_GLOBALS:
00686
00687
00688 traverse_pval_item_template(item->u1.statements,depth+1);
00689 break;
00690 }
00691 }
00692
00693 void traverse_pval_template(pval *item, int depth)
00694
00695 {
00696 pval *i;
00697
00698 for (i=item; i; i=i->next) {
00699 traverse_pval_item_template(i, depth);
00700 }
00701 }
00702
00703
00704
00705
00706
00707
00708
00709
00710 static int extension_matches(pval *here, const char *exten, const char *pattern)
00711 {
00712 int err1;
00713 regex_t preg;
00714
00715
00716 if( !strcmp(pattern,exten) == 0 )
00717 return 1;
00718
00719 if ( pattern[0] == '_' ) {
00720 char reg1[2000];
00721 const char *p;
00722 char *r = reg1;
00723
00724 if ( strlen(pattern)*5 >= 2000 ) {
00725 ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
00726 pattern);
00727 return 0;
00728 }
00729
00730 *r++ = '^';
00731 *r++ = '_';
00732 *r++ = '?';
00733 for (p=pattern+1; *p; p++) {
00734 switch ( *p ) {
00735 case 'X':
00736 *r++ = '[';
00737 *r++ = '0';
00738 *r++ = '-';
00739 *r++ = '9';
00740 *r++ = 'X';
00741 *r++ = ']';
00742 break;
00743
00744 case 'Z':
00745 *r++ = '[';
00746 *r++ = '1';
00747 *r++ = '-';
00748 *r++ = '9';
00749 *r++ = 'Z';
00750 *r++ = ']';
00751 break;
00752
00753 case 'N':
00754 *r++ = '[';
00755 *r++ = '2';
00756 *r++ = '-';
00757 *r++ = '9';
00758 *r++ = 'N';
00759 *r++ = ']';
00760 break;
00761
00762 case '[':
00763 while ( *p && *p != ']' ) {
00764 *r++ = *p++;
00765 }
00766 if ( *p != ']') {
00767 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
00768 here->filename, here->startline, here->endline, pattern);
00769 }
00770 break;
00771
00772 case '.':
00773 case '!':
00774 *r++ = '.';
00775 *r++ = '*';
00776 break;
00777 case '*':
00778 *r++ = '\\';
00779 *r++ = '*';
00780 break;
00781 default:
00782 *r++ = *p;
00783 break;
00784
00785 }
00786 }
00787 *r++ = '$';
00788 *r++ = *p++;
00789 err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
00790 if ( err1 ) {
00791 char errmess[500];
00792 regerror(err1,&preg,errmess,sizeof(errmess));
00793 regfree(&preg);
00794 ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
00795 reg1, err1);
00796 return 0;
00797 }
00798 err1 = regexec(&preg, exten, 0, 0, 0);
00799 regfree(&preg);
00800
00801 if ( err1 ) {
00802
00803
00804 return 0;
00805 } else {
00806
00807
00808 return 1;
00809 }
00810
00811
00812 } else {
00813 if ( strcmp(exten,pattern) == 0 ) {
00814 return 1;
00815 } else
00816 return 0;
00817 }
00818 }
00819
00820
00821 static void check_expr2_input(pval *expr, char *str)
00822 {
00823 int spaces = strspn(str,"\t \n");
00824 if ( !strncmp(str+spaces,"$[",2) ) {
00825 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
00826 expr->filename, expr->startline, expr->endline, str);
00827 warns++;
00828 }
00829 }
00830
00831 static void check_includes(pval *includes)
00832 {
00833 struct pval *p4;
00834 for (p4=includes->u1.list; p4; p4=p4->next) {
00835
00836
00837 char *incl_context = p4->u1.str;
00838
00839 struct pval *that_other_context = find_context(incl_context);
00840 if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
00841 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
00842 (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
00843 includes->filename, includes->startline, includes->endline, incl_context, incl_context);
00844 warns++;
00845 }
00846 }
00847 }
00848
00849
00850 static void check_timerange(pval *p)
00851 {
00852 char *times;
00853 char *e;
00854 int s1, s2;
00855 int e1, e2;
00856
00857 times = ast_strdupa(p->u1.str);
00858
00859
00860 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
00861 return;
00862 }
00863
00864 e = strchr(times, '-');
00865 if (!e) {
00866 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",
00867 p->filename, p->startline, p->endline, times);
00868 warns++;
00869 return;
00870 }
00871 *e = '\0';
00872 e++;
00873 while (*e && !isdigit(*e))
00874 e++;
00875 if (!*e) {
00876 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
00877 p->filename, p->startline, p->endline, p->u1.str);
00878 warns++;
00879 }
00880 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
00881 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
00882 p->filename, p->startline, p->endline, times);
00883 warns++;
00884 }
00885 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
00886 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
00887 p->filename, p->startline, p->endline, times);
00888 warns++;
00889 }
00890
00891 s1 = s1 * 30 + s2/2;
00892 if ((s1 < 0) || (s1 >= 24*30)) {
00893 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
00894 p->filename, p->startline, p->endline, times);
00895 warns++;
00896 }
00897 e1 = e1 * 30 + e2/2;
00898 if ((e1 < 0) || (e1 >= 24*30)) {
00899 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
00900 p->filename, p->startline, p->endline, e);
00901 warns++;
00902 }
00903 return;
00904 }
00905
00906 static char *days[] =
00907 {
00908 "sun",
00909 "mon",
00910 "tue",
00911 "wed",
00912 "thu",
00913 "fri",
00914 "sat",
00915 };
00916
00917
00918 static void check_dow(pval *DOW)
00919 {
00920 char *dow;
00921 char *c;
00922
00923 int s, e;
00924
00925 dow = ast_strdupa(DOW->u1.str);
00926
00927
00928 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
00929 return;
00930
00931 c = strchr(dow, '-');
00932 if (c) {
00933 *c = '\0';
00934 c++;
00935 } else
00936 c = NULL;
00937
00938 s = 0;
00939 while ((s < 7) && strcasecmp(dow, days[s])) s++;
00940 if (s >= 7) {
00941 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",
00942 DOW->filename, DOW->startline, DOW->endline, dow);
00943 warns++;
00944 }
00945 if (c) {
00946 e = 0;
00947 while ((e < 7) && strcasecmp(c, days[e])) e++;
00948 if (e >= 7) {
00949 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",
00950 DOW->filename, DOW->startline, DOW->endline, c);
00951 warns++;
00952 }
00953 } else
00954 e = s;
00955 }
00956
00957 static void check_day(pval *DAY)
00958 {
00959 char *day;
00960 char *c;
00961
00962 int s, e;
00963
00964 day = ast_strdupa(DAY->u1.str);
00965
00966
00967 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
00968 return;
00969 }
00970
00971 c = strchr(day, '-');
00972 if (c) {
00973 *c = '\0';
00974 c++;
00975 }
00976
00977 if (sscanf(day, "%d", &s) != 1) {
00978 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
00979 DAY->filename, DAY->startline, DAY->endline, day);
00980 warns++;
00981 }
00982 else if ((s < 1) || (s > 31)) {
00983 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",
00984 DAY->filename, DAY->startline, DAY->endline, day);
00985 warns++;
00986 }
00987 s--;
00988 if (c) {
00989 if (sscanf(c, "%d", &e) != 1) {
00990 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
00991 DAY->filename, DAY->startline, DAY->endline, c);
00992 warns++;
00993 }
00994 else if ((e < 1) || (e > 31)) {
00995 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",
00996 DAY->filename, DAY->startline, DAY->endline, day);
00997 warns++;
00998 }
00999 e--;
01000 } else
01001 e = s;
01002 }
01003
01004 static char *months[] =
01005 {
01006 "jan",
01007 "feb",
01008 "mar",
01009 "apr",
01010 "may",
01011 "jun",
01012 "jul",
01013 "aug",
01014 "sep",
01015 "oct",
01016 "nov",
01017 "dec",
01018 };
01019
01020 static void check_month(pval *MON)
01021 {
01022 char *mon;
01023 char *c;
01024
01025 int s, e;
01026
01027 mon = ast_strdupa(MON->u1.str);
01028
01029
01030 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
01031 return ;
01032
01033 c = strchr(mon, '-');
01034 if (c) {
01035 *c = '\0';
01036 c++;
01037 }
01038
01039 s = 0;
01040 while ((s < 12) && strcasecmp(mon, months[s])) s++;
01041 if (s >= 12) {
01042 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01043 MON->filename, MON->startline, MON->endline, mon);
01044 warns++;
01045 }
01046 if (c) {
01047 e = 0;
01048 while ((e < 12) && strcasecmp(mon, months[e])) e++;
01049 if (e >= 12) {
01050 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01051 MON->filename, MON->startline, MON->endline, c);
01052 warns++;
01053 }
01054 } else
01055 e = s;
01056 }
01057
01058 static int check_break(pval *item)
01059 {
01060 pval *p = item;
01061
01062 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
01063
01064
01065 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN
01066 || p->type == PV_WHILE || p->type == PV_FOR ) {
01067 return 1;
01068 }
01069 p = p->dad;
01070 }
01071 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
01072 item->filename, item->startline, item->endline);
01073 errs++;
01074
01075 return 0;
01076 }
01077
01078 static int check_continue(pval *item)
01079 {
01080 pval *p = item;
01081
01082 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
01083
01084
01085 if( p->type == PV_WHILE || p->type == PV_FOR ) {
01086 return 1;
01087 }
01088 p = p->dad;
01089 }
01090 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
01091 item->filename, item->startline, item->endline);
01092 errs++;
01093
01094 return 0;
01095 }
01096
01097
01098
01099
01100 static void check_label(pval *item)
01101 {
01102
01103
01104
01105 struct pval *curr;
01106 struct pval *x;
01107
01108
01109 if( !current_extension )
01110 curr = current_context;
01111 else
01112 curr = current_extension;
01113
01114 x = find_first_label_in_current_context((char *)item->u1.str, curr);
01115
01116 if( x && x != item )
01117 {
01118 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
01119 item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
01120 errs++;
01121 }
01122
01123 }
01124
01125 static pval *get_goto_target(pval *item)
01126 {
01127
01128 pval *curr_ext = get_extension_or_contxt(item);
01129 pval *curr_cont;
01130
01131 if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01132 struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext);
01133 return x;
01134 }
01135
01136 curr_cont = get_contxt(item);
01137
01138
01139 if (item->u1.list->next && !item->u1.list->next->next) {
01140 if (!strstr((item->u1.list)->u1.str,"${")
01141 && !strstr(item->u1.list->next->u1.str,"${") ) {
01142 struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont);
01143 return x;
01144 }
01145 }
01146
01147
01148 if (item->u1.list->next && item->u1.list->next->next) {
01149
01150 pval *first = item->u1.list;
01151 pval *second = item->u1.list->next;
01152 pval *third = item->u1.list->next->next;
01153
01154 if (!strstr((item->u1.list)->u1.str,"${")
01155 && !strstr(item->u1.list->next->u1.str,"${")
01156 && !strstr(item->u1.list->next->next->u1.str,"${")) {
01157 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01158 if (!x) {
01159
01160 struct pval *p3;
01161 struct pval *that_context = find_context(item->u1.list->u1.str);
01162
01163
01164
01165 if (that_context) {
01166 for (p3=that_context->u2.statements; p3; p3=p3->next) {
01167 if (p3->type == PV_INCLUDES) {
01168 struct pval *p4;
01169 for (p4=p3->u1.list; p4; p4=p4->next) {
01170
01171
01172 char *incl_context = p4->u1.str;
01173
01174 struct pval *that_other_context = find_context(incl_context);
01175 if (that_other_context) {
01176 struct pval *x3;
01177 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01178 if (x3) {
01179 return x3;
01180 }
01181 }
01182 }
01183 }
01184 }
01185 }
01186 }
01187 return x;
01188 }
01189 }
01190 return 0;
01191 }
01192
01193 static void check_goto(pval *item)
01194 {
01195
01196 if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
01197 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n",
01198 item->filename, item->startline, item->endline);
01199 errs++;
01200 }
01201
01202
01203
01204 if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01205 struct pval *z = get_extension_or_contxt(item);
01206 struct pval *x = 0;
01207 if (z)
01208 x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z);
01209
01210
01211 if (!x) {
01212 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n",
01213 item->filename, item->startline, item->endline, item->u1.list->u1.str);
01214 errs++;
01215 }
01216 else
01217 return;
01218 }
01219
01220
01221 if (item->u1.list->next && !item->u1.list->next->next) {
01222
01223
01224
01225 if (!strstr((item->u1.list)->u1.str,"${")
01226 && !strstr(item->u1.list->next->u1.str,"${") ) {
01227 struct pval *z = get_contxt(item);
01228 struct pval *x = 0;
01229
01230 if (z)
01231 x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
01232
01233 if (!x) {
01234 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",
01235 item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
01236 errs++;
01237 }
01238 else
01239 return;
01240 }
01241 }
01242
01243
01244 if (item->u1.list->next && item->u1.list->next->next) {
01245
01246 pval *first = item->u1.list;
01247 pval *second = item->u1.list->next;
01248 pval *third = item->u1.list->next->next;
01249
01250
01251
01252 if (!strstr((item->u1.list)->u1.str,"${")
01253 && !strstr(item->u1.list->next->u1.str,"${")
01254 && !strstr(item->u1.list->next->next->u1.str,"${")) {
01255 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01256 if (!x) {
01257 struct pval *p3;
01258 struct pval *found = 0;
01259 struct pval *that_context = find_context(item->u1.list->u1.str);
01260
01261
01262
01263 if (that_context) {
01264 for (p3=that_context->u2.statements; p3; p3=p3->next) {
01265 if (p3->type == PV_INCLUDES) {
01266 struct pval *p4;
01267 for (p4=p3->u1.list; p4; p4=p4->next) {
01268
01269
01270 char *incl_context = p4->u1.str;
01271
01272 struct pval *that_other_context = find_context(incl_context);
01273 if (that_other_context) {
01274 struct pval *x3;
01275 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01276 if (x3) {
01277 found = x3;
01278 break;
01279 }
01280 }
01281 }
01282 }
01283 }
01284 if (!found) {
01285 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n",
01286 item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
01287 errs++;
01288 }
01289 } else {
01290
01291 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: no context %s could be found that matches the goto target!\n",
01292 item->filename, item->startline, item->endline, item->u1.list->u1.str);
01293 warns++;
01294 }
01295 }
01296 }
01297 }
01298 }
01299
01300
01301 static void find_pval_goto_item(pval *item, int lev)
01302 {
01303 struct pval *p4;
01304
01305 if (lev>100) {
01306 ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %d\n\n", item->type);
01307 return;
01308 }
01309
01310 switch ( item->type ) {
01311 case PV_MACRO:
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321 find_pval_gotos(item->u3.macro_statements,lev+1);
01322
01323 break;
01324
01325 case PV_CONTEXT:
01326
01327
01328
01329
01330 break;
01331
01332 case PV_CASE:
01333
01334
01335
01336
01337 find_pval_gotos(item->u2.statements,lev+1);
01338 break;
01339
01340 case PV_PATTERN:
01341
01342
01343
01344
01345 find_pval_gotos(item->u2.statements,lev+1);
01346 break;
01347
01348 case PV_DEFAULT:
01349
01350
01351
01352
01353 find_pval_gotos(item->u2.statements,lev+1);
01354 break;
01355
01356 case PV_CATCH:
01357
01358
01359
01360
01361 find_pval_gotos(item->u2.statements,lev+1);
01362 break;
01363
01364 case PV_STATEMENTBLOCK:
01365
01366
01367
01368 find_pval_gotos(item->u1.list,lev+1);
01369 break;
01370
01371 case PV_GOTO:
01372
01373
01374
01375 check_goto(item);
01376 break;
01377
01378 case PV_INCLUDES:
01379
01380
01381 for (p4=item->u1.list; p4; p4=p4->next) {
01382
01383
01384 char *incl_context = p4->u1.str;
01385
01386 struct pval *that_context = find_context(incl_context);
01387 if (that_context && that_context->u2.statements) {
01388
01389 find_pval_gotos(that_context->u2.statements,lev+1);
01390 }
01391 }
01392 break;
01393
01394 case PV_FOR:
01395
01396
01397
01398
01399
01400
01401
01402 find_pval_gotos(item->u4.for_statements,lev+1);
01403 break;
01404
01405 case PV_WHILE:
01406
01407
01408
01409
01410
01411 find_pval_gotos(item->u2.statements,lev+1);
01412 break;
01413
01414 case PV_RANDOM:
01415
01416
01417
01418
01419
01420
01421
01422 case PV_IFTIME:
01423
01424
01425
01426
01427
01428
01429 case PV_IF:
01430
01431
01432
01433
01434
01435
01436
01437 find_pval_gotos(item->u2.statements,lev+1);
01438
01439 if (item->u3.else_statements) {
01440
01441 find_pval_gotos(item->u3.else_statements,lev+1);
01442 }
01443 break;
01444
01445 case PV_SWITCH:
01446
01447
01448
01449
01450
01451
01452 find_pval_gotos(item->u3.else_statements,lev+1);
01453 break;
01454
01455 case PV_EXTENSION:
01456
01457
01458
01459
01460
01461
01462
01463
01464 find_pval_gotos(item->u2.statements,lev+1);
01465 break;
01466
01467 default:
01468 break;
01469 }
01470 }
01471
01472 static void find_pval_gotos(pval *item,int lev)
01473 {
01474 pval *i;
01475
01476 for (i=item; i; i=i->next) {
01477
01478 find_pval_goto_item(i, lev);
01479 }
01480 }
01481
01482
01483
01484
01485 static struct pval *match_pval_item(pval *item)
01486 {
01487 pval *x;
01488
01489 switch ( item->type ) {
01490 case PV_MACRO:
01491
01492
01493
01494
01495
01496
01497
01498
01499 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01500
01501
01502
01503 if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01504
01505 return item;
01506 }
01507
01508
01509 if (!return_on_context_match) {
01510
01511 if ((x=match_pval(item->u3.macro_statements))) {
01512
01513 return x;
01514 }
01515 }
01516 } else {
01517
01518 }
01519
01520 break;
01521
01522 case PV_CONTEXT:
01523
01524
01525
01526
01527
01528 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01529 if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01530
01531
01532 return item;
01533 }
01534
01535 if (!return_on_context_match ) {
01536
01537 if ((x=match_pval(item->u2.statements))) {
01538
01539 return x;
01540 }
01541 }
01542 } else {
01543
01544 }
01545 break;
01546
01547 case PV_CASE:
01548
01549
01550
01551
01552 if ((x=match_pval(item->u2.statements))) {
01553
01554 return x;
01555 }
01556 break;
01557
01558 case PV_PATTERN:
01559
01560
01561
01562
01563 if ((x=match_pval(item->u2.statements))) {
01564
01565 return x;
01566 }
01567 break;
01568
01569 case PV_DEFAULT:
01570
01571
01572
01573
01574 if ((x=match_pval(item->u2.statements))) {
01575
01576 return x;
01577 }
01578 break;
01579
01580 case PV_CATCH:
01581
01582
01583
01584
01585 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01586
01587 if (strcmp(match_label,"1") == 0) {
01588 if (item->u2.statements) {
01589 struct pval *p5 = item->u2.statements;
01590 while (p5 && p5->type == PV_LABEL)
01591 p5 = p5->next;
01592 if (p5)
01593 return p5;
01594 else
01595 return 0;
01596 }
01597 else
01598 return 0;
01599 }
01600
01601 if ((x=match_pval(item->u2.statements))) {
01602
01603 return x;
01604 }
01605 } else {
01606
01607 }
01608 break;
01609
01610 case PV_STATEMENTBLOCK:
01611
01612
01613
01614 if ((x=match_pval(item->u1.list))) {
01615
01616 return x;
01617 }
01618 break;
01619
01620 case PV_LABEL:
01621
01622
01623
01624
01625
01626 if (count_labels) {
01627 if (!strcmp(match_label, item->u1.str)) {
01628 label_count++;
01629 last_matched_label = item;
01630 }
01631
01632 } else {
01633 if (!strcmp(match_label, item->u1.str)) {
01634
01635 return item;
01636 }
01637 }
01638 break;
01639
01640 case PV_FOR:
01641
01642
01643
01644
01645
01646
01647
01648 if ((x=match_pval(item->u4.for_statements))) {
01649
01650 return x;
01651 }
01652 break;
01653
01654 case PV_WHILE:
01655
01656
01657
01658
01659
01660 if ((x=match_pval(item->u2.statements))) {
01661
01662 return x;
01663 }
01664 break;
01665
01666 case PV_RANDOM:
01667
01668
01669
01670
01671
01672
01673
01674 case PV_IFTIME:
01675
01676
01677
01678
01679
01680
01681 case PV_IF:
01682
01683
01684
01685
01686
01687
01688
01689 if ((x=match_pval(item->u2.statements))) {
01690 return x;
01691 }
01692 if (item->u3.else_statements) {
01693 if ((x=match_pval(item->u3.else_statements))) {
01694
01695 return x;
01696 }
01697 }
01698 break;
01699
01700 case PV_SWITCH:
01701
01702
01703
01704
01705
01706
01707 if ((x=match_pval(item->u2.statements))) {
01708
01709 return x;
01710 }
01711 break;
01712
01713 case PV_EXTENSION:
01714
01715
01716
01717
01718
01719
01720
01721 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01722
01723 if (strcmp(match_label,"1") == 0) {
01724 if (item->u2.statements) {
01725 struct pval *p5 = item->u2.statements;
01726 while (p5 && p5->type == PV_LABEL)
01727 p5 = p5->next;
01728 if (p5)
01729 return p5;
01730 else
01731 return 0;
01732 }
01733 else
01734 return 0;
01735 }
01736
01737 if ((x=match_pval(item->u2.statements))) {
01738
01739 return x;
01740 }
01741 } else {
01742
01743 }
01744 break;
01745 default:
01746
01747 break;
01748 }
01749 return 0;
01750 }
01751
01752 struct pval *match_pval(pval *item)
01753 {
01754 pval *i;
01755
01756 for (i=item; i; i=i->next) {
01757 pval *x;
01758
01759
01760 if ((x = match_pval_item(i))) {
01761
01762 return x;
01763 }
01764 }
01765 return 0;
01766 }
01767
01768 #if 0
01769 int count_labels_in_current_context(char *label)
01770 {
01771 label_count = 0;
01772 count_labels = 1;
01773 return_on_context_match = 0;
01774 match_pval(current_context->u2.statements);
01775
01776 return label_count;
01777 }
01778 #endif
01779
01780 struct pval *find_first_label_in_current_context(char *label, pval *curr_cont)
01781 {
01782
01783 struct pval *ret;
01784 struct pval *p3;
01785 struct pval *startpt = ((curr_cont->type==PV_MACRO)?curr_cont->u3.macro_statements: curr_cont->u2.statements);
01786
01787 count_labels = 0;
01788 return_on_context_match = 0;
01789 match_context = "*";
01790 match_exten = "*";
01791 match_label = label;
01792
01793 ret = match_pval(curr_cont);
01794 if (ret)
01795 return ret;
01796
01797
01798
01799 for (p3=startpt; p3; p3=p3->next) {
01800 if (p3->type == PV_INCLUDES) {
01801 struct pval *p4;
01802 for (p4=p3->u1.list; p4; p4=p4->next) {
01803
01804
01805 char *incl_context = p4->u1.str;
01806
01807 struct pval *that_context = find_context(incl_context);
01808 if (that_context) {
01809 struct pval *x3;
01810 x3 = find_first_label_in_current_context(label, that_context);
01811 if (x3) {
01812 return x3;
01813 }
01814 }
01815 }
01816 }
01817 }
01818 return 0;
01819 }
01820
01821 struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont)
01822 {
01823
01824 struct pval *ret;
01825 struct pval *p3;
01826 struct pval *startpt;
01827
01828 count_labels = 0;
01829 return_on_context_match = 0;
01830 match_context = "*";
01831 match_exten = exten;
01832 match_label = label;
01833 if (curr_cont->type == PV_MACRO)
01834 startpt = curr_cont->u3.macro_statements;
01835 else
01836 startpt = curr_cont->u2.statements;
01837
01838 ret = match_pval(startpt);
01839 if (ret)
01840 return ret;
01841
01842
01843
01844 for (p3=startpt; p3; p3=p3->next) {
01845 if (p3->type == PV_INCLUDES) {
01846 struct pval *p4;
01847 for (p4=p3->u1.list; p4; p4=p4->next) {
01848
01849
01850 char *incl_context = p4->u1.str;
01851
01852 struct pval *that_context = find_context(incl_context);
01853 if (that_context) {
01854 struct pval *x3;
01855 x3 = find_label_in_current_context(exten, label, that_context);
01856 if (x3) {
01857 return x3;
01858 }
01859 }
01860 }
01861 }
01862 }
01863 return 0;
01864 }
01865
01866 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext)
01867 {
01868
01869 count_labels = 0;
01870 return_on_context_match = 0;
01871 match_context = "*";
01872 match_exten = "*";
01873 match_label = label;
01874 return match_pval(curr_ext);
01875 }
01876
01877 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label)
01878 {
01879
01880 count_labels = 0;
01881 return_on_context_match = 0;
01882
01883 match_context = context;
01884 match_exten = exten;
01885 match_label = label;
01886
01887 return match_pval(current_db);
01888 }
01889
01890
01891 struct pval *find_macro(char *name)
01892 {
01893 return_on_context_match = 1;
01894 count_labels = 0;
01895 match_context = name;
01896 match_exten = "*";
01897 match_label = "*";
01898 return match_pval(current_db);
01899 }
01900
01901 struct pval *find_context(char *name)
01902 {
01903 return_on_context_match = 1;
01904 count_labels = 0;
01905 match_context = name;
01906 match_exten = "*";
01907 match_label = "*";
01908 return match_pval(current_db);
01909 }
01910
01911 int is_float(char *arg )
01912 {
01913 char *s;
01914 for (s=arg; *s; s++) {
01915 if (*s != '.' && (*s < '0' || *s > '9'))
01916 return 0;
01917 }
01918 return 1;
01919 }
01920 int is_int(char *arg )
01921 {
01922 char *s;
01923 for (s=arg; *s; s++) {
01924 if (*s < '0' || *s > '9')
01925 return 0;
01926 }
01927 return 1;
01928 }
01929 int is_empty(char *arg)
01930 {
01931 if (!arg)
01932 return 1;
01933 if (*arg == 0)
01934 return 1;
01935 while (*arg) {
01936 if (*arg != ' ' && *arg != '\t')
01937 return 0;
01938 arg++;
01939 }
01940 return 1;
01941 }
01942
01943 #ifdef AAL_ARGCHECK
01944 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app)
01945 {
01946 struct argchoice *ac;
01947 char *opcop,*q,*p;
01948
01949 switch (should->dtype) {
01950 case ARGD_OPTIONSET:
01951 if ( strstr(is->u1.str,"${") )
01952 return 0;
01953
01954 opcop = ast_strdupa(is->u1.str);
01955
01956 for (q=opcop;*q;q++) {
01957 if ( *q == '(' ) {
01958 p = q+1;
01959 while (*p && *p != ')' )
01960 *p++ = '+';
01961 q = p+1;
01962 }
01963 }
01964
01965 for (ac=app->opts; ac; ac=ac->next) {
01966 if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0)
01967 return 0;
01968 }
01969 for (ac=app->opts; ac; ac=ac->next) {
01970 if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
01971 char *p = strchr(opcop,ac->name[0]);
01972
01973 if (p && *p == 'j') {
01974 ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n",
01975 is->filename, is->startline, is->endline, app->name);
01976 errs++;
01977 }
01978
01979 if (p) {
01980 *p = '+';
01981 if (ac->name[1] == '(') {
01982 if (*(p+1) != '(') {
01983 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",
01984 is->filename, is->startline, is->endline, ac->name[0], app->name);
01985 warns++;
01986 }
01987 }
01988 }
01989 }
01990 }
01991 for (q=opcop; *q; q++) {
01992 if ( *q != '+' && *q != '(' && *q != ')') {
01993 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",
01994 is->filename, is->startline, is->endline, *q, app->name);
01995 warns++;
01996 }
01997 }
01998 return 1;
01999 break;
02000 default:
02001 return 0;
02002 }
02003
02004 }
02005
02006 int option_matches( struct argdesc *should, pval *is, struct argapp *app)
02007 {
02008 struct argchoice *ac;
02009 char *opcop;
02010
02011 switch (should->dtype) {
02012 case ARGD_STRING:
02013 if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED)
02014 return 0;
02015 if (is->u1.str && strlen(is->u1.str) > 0)
02016 return 1;
02017 break;
02018
02019 case ARGD_INT:
02020 if (is_int(is->u1.str))
02021 return 1;
02022 else
02023 return 0;
02024 break;
02025
02026 case ARGD_FLOAT:
02027 if (is_float(is->u1.str))
02028 return 1;
02029 else
02030 return 0;
02031 break;
02032
02033 case ARGD_ENUM:
02034 if( !is->u1.str || strlen(is->u1.str) == 0 )
02035 return 1;
02036 for (ac=should->choices; ac; ac=ac->next) {
02037 if (strcmp(ac->name,is->u1.str) == 0)
02038 return 1;
02039 }
02040 return 0;
02041 break;
02042
02043 case ARGD_OPTIONSET:
02044 opcop = ast_strdupa(is->u1.str);
02045
02046 for (ac=app->opts; ac; ac=ac->next) {
02047 if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0)
02048 return 1;
02049 }
02050 for (ac=app->opts; ac; ac=ac->next) {
02051 if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
02052 char *p = strchr(opcop,ac->name[0]);
02053
02054 if (p) {
02055 *p = '+';
02056 if (ac->name[1] == '(') {
02057 if (*(p+1) == '(') {
02058 char *q = p+1;
02059 while (*q && *q != ')') {
02060 *q++ = '+';
02061 }
02062 *q = '+';
02063 }
02064 }
02065 }
02066 }
02067 }
02068 return 1;
02069 break;
02070 case ARGD_VARARG:
02071 return 1;
02072 break;
02073 }
02074 return 1;
02075 }
02076 #endif
02077
02078 int check_app_args(pval* appcall, pval *arglist, struct argapp *app)
02079 {
02080 #ifdef AAL_ARGCHECK
02081 struct argdesc *ad = app->args;
02082 pval *pa;
02083 int z;
02084
02085 for (pa = arglist; pa; pa=pa->next) {
02086 if (!ad) {
02087 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
02088 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
02089 warns++;
02090 return 1;
02091 } else {
02092
02093 do {
02094 if ( ad->dtype == ARGD_VARARG )
02095 break;
02096
02097 z= option_matches( ad, pa, app);
02098 if (!z) {
02099 if ( !arglist )
02100 arglist=appcall;
02101
02102 if (ad->type == ARGD_REQUIRED) {
02103 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02104 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02105 warns++;
02106 return 1;
02107 }
02108 } else if (z && ad->dtype == ARGD_OPTIONSET) {
02109 option_matches_j( ad, pa, app);
02110 }
02111 ad = ad->next;
02112 } while (ad && !z);
02113 }
02114 }
02115
02116 for ( ; ad; ad=ad->next) {
02117 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
02118 if ( !arglist )
02119 arglist=appcall;
02120 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02121 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02122 warns++;
02123 return 1;
02124 }
02125 }
02126 return 0;
02127 #else
02128 return 0;
02129 #endif
02130 }
02131
02132 void check_switch_expr(pval *item, struct argapp *apps)
02133 {
02134 #ifdef AAL_ARGCHECK
02135
02136 char *buff1, *p;
02137 struct argapp *a,*a2;
02138 struct appsetvar *v,*v2;
02139 struct argchoice *c;
02140 pval *t;
02141
02142 p = item->u1.str;
02143 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
02144 p++;
02145
02146 buff1 = ast_strdupa(p);
02147
02148 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
02149 buff1[strlen(buff1)-1] = 0;
02150
02151 v = 0;
02152 for (a=apps; a; a=a->next) {
02153 for (v=a->setvars;v;v=v->next) {
02154 if (strcmp(v->name,buff1) == 0) {
02155 break;
02156 }
02157 }
02158 if ( v )
02159 break;
02160 }
02161 if (v && v->vals) {
02162
02163 int def= 0;
02164 int pat = 0;
02165 int f1 = 0;
02166
02167
02168 for (t=item->u2.statements; t; t=t->next) {
02169 if (t->type == PV_DEFAULT) {
02170 def =1;
02171 break;
02172 }
02173 if (t->type == PV_PATTERN) {
02174 pat++;
02175 }
02176 }
02177 if (def || pat)
02178 return;
02179 for (c=v->vals; c; c=c->next) {
02180 f1 = 0;
02181 for (t=item->u2.statements; t; t=t->next) {
02182 if (t->type == PV_CASE || t->type == PV_PATTERN) {
02183 if (!strcmp(t->u1.str,c->name)) {
02184 f1 = 1;
02185 break;
02186 }
02187 }
02188 }
02189 if (!f1) {
02190 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
02191 item->filename, item->startline, item->endline, item->u1.str, c->name);
02192 warns++;
02193 }
02194 }
02195
02196 f1 = 0;
02197 t = current_extension->u2.statements;
02198 if ( t && t->type == PV_STATEMENTBLOCK )
02199 t = t->u1.statements;
02200 for (; t && t != item; t=t->next) {
02201 if (t->type == PV_APPLICATION_CALL) {
02202
02203 for (a2=apps; a2; a2=a2->next) {
02204 if (strcasecmp(a2->name, t->u1.str)==0) {
02205 for (v2=a2->setvars; v2; v2=v2->next) {
02206 if (strcmp(v2->name, buff1) == 0) {
02207
02208 f1 = 1;
02209 break;
02210 }
02211 }
02212 }
02213 if (f1)
02214 break;
02215 }
02216 }
02217 if (f1)
02218 break;
02219 }
02220
02221
02222 if (!f1) {
02223 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",
02224 item->filename, item->startline, item->endline, item->u1.str);
02225 warns++;
02226 }
02227 }
02228 #else
02229 pval *t,*tl=0,*p2;
02230 int def= 0;
02231
02232
02233 for (t=item->u2.statements; t; t=t->next) {
02234 if (t->type == PV_DEFAULT) {
02235 def =1;
02236 break;
02237 }
02238 tl = t;
02239 }
02240 if (def)
02241 return;
02242
02243 p2 = tl->next = calloc(1, sizeof(struct pval));
02244
02245 p2->type = PV_DEFAULT;
02246 p2->startline = tl->startline;
02247 p2->endline = tl->endline;
02248 p2->startcol = tl->startcol;
02249 p2->endcol = tl->endcol;
02250 p2->filename = strdup(tl->filename);
02251 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
02252 p2->filename, p2->startline, p2->endline);
02253 warns++;
02254
02255 #endif
02256 }
02257
02258 static void check_context_names(void)
02259 {
02260 pval *i,*j;
02261 for (i=current_db; i; i=i->next) {
02262 if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02263 for (j=i->next; j; j=j->next) {
02264 if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02265 if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
02266 {
02267 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n",
02268 i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline);
02269 errs++;
02270 }
02271 }
02272 }
02273 }
02274 }
02275 }
02276
02277 static void check_abstract_reference(pval *abstract_context)
02278 {
02279 pval *i,*j;
02280
02281
02282
02283
02284 for (i=current_db; i; i=i->next) {
02285 if (i->type == PV_CONTEXT) {
02286 for (j=i->u2. statements; j; j=j->next) {
02287 if ( j->type == PV_INCLUDES ) {
02288 struct pval *p4;
02289 for (p4=j->u1.list; p4; p4=p4->next) {
02290
02291
02292 if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
02293 return;
02294 }
02295 }
02296 }
02297 }
02298 }
02299 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",
02300 abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
02301 warns++;
02302 }
02303
02304
02305 void check_pval_item(pval *item, struct argapp *apps, int in_globals)
02306 {
02307 pval *lp;
02308 #ifdef AAL_ARGCHECK
02309 struct argapp *app, *found;
02310 #endif
02311 struct pval *macro_def;
02312 struct pval *app_def;
02313
02314 char errmsg[4096];
02315 char *strp;
02316
02317 switch (item->type) {
02318 case PV_WORD:
02319
02320
02321 break;
02322
02323 case PV_MACRO:
02324
02325
02326
02327
02328
02329
02330
02331 in_abstract_context = 0;
02332 current_context = item;
02333 current_extension = 0;
02334 for (lp=item->u2.arglist; lp; lp=lp->next) {
02335
02336 }
02337 check_pval(item->u3.macro_statements, apps,in_globals);
02338 break;
02339
02340 case PV_CONTEXT:
02341
02342
02343
02344
02345 current_context = item;
02346 current_extension = 0;
02347 if ( item->u3.abstract ) {
02348 in_abstract_context = 1;
02349 check_abstract_reference(item);
02350 } else
02351 in_abstract_context = 0;
02352 check_pval(item->u2.statements, apps,in_globals);
02353 break;
02354
02355 case PV_MACRO_CALL:
02356
02357
02358
02359
02360
02361 macro_def = find_macro(item->u1.str);
02362 if (!macro_def) {
02363
02364 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s ! Hopefully it is present in extensions.conf! \n",
02365 item->filename, item->startline, item->endline, item->u1.str);
02366 warns++;
02367 } else if (macro_def->type != PV_MACRO) {
02368 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
02369 item->filename, item->startline, item->endline, item->u1.str);
02370 errs++;
02371 } else {
02372
02373 int hereargs = 0;
02374 int thereargs = 0;
02375
02376 for (lp=item->u2.arglist; lp; lp=lp->next) {
02377 hereargs++;
02378 }
02379 for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
02380 thereargs++;
02381 }
02382 if (hereargs != thereargs ) {
02383 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",
02384 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
02385 errs++;
02386 }
02387 }
02388 break;
02389
02390 case PV_APPLICATION_CALL:
02391
02392
02393
02394
02395
02396
02397 app_def = find_context(item->u1.str);
02398 if (app_def && app_def->type == PV_MACRO) {
02399 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
02400 item->filename, item->startline, item->endline, item->u1.str);
02401 errs++;
02402 }
02403 if (strcasecmp(item->u1.str,"GotoIf") == 0
02404 || strcasecmp(item->u1.str,"GotoIfTime") == 0
02405 || strcasecmp(item->u1.str,"while") == 0
02406 || strcasecmp(item->u1.str,"endwhile") == 0
02407 || strcasecmp(item->u1.str,"random") == 0
02408 || strcasecmp(item->u1.str,"execIf") == 0 ) {
02409 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s needs to be re-written using AEL if, while, goto, etc. keywords instead!\n",
02410 item->filename, item->startline, item->endline, item->u1.str);
02411 warns++;
02412 }
02413 #ifdef AAL_ARGCHECK
02414 found = 0;
02415 for (app=apps; app; app=app->next) {
02416 if (strcasecmp(app->name, item->u1.str) == 0) {
02417 found =app;
02418 break;
02419 }
02420 }
02421 if (!found) {
02422 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
02423 item->filename, item->startline, item->endline, item->u1.str);
02424 warns++;
02425 } else
02426 check_app_args(item, item->u2.arglist, app);
02427 #endif
02428 break;
02429
02430 case PV_CASE:
02431
02432
02433
02434
02435
02436 check_pval(item->u2.statements, apps,in_globals);
02437 break;
02438
02439 case PV_PATTERN:
02440
02441
02442
02443
02444
02445
02446 check_pval(item->u2.statements, apps,in_globals);
02447 break;
02448
02449 case PV_DEFAULT:
02450
02451
02452
02453
02454 check_pval(item->u2.statements, apps,in_globals);
02455 break;
02456
02457 case PV_CATCH:
02458
02459
02460
02461 check_pval(item->u2.statements, apps,in_globals);
02462 break;
02463
02464 case PV_SWITCHES:
02465
02466
02467 check_pval(item->u1.list, apps,in_globals);
02468 break;
02469
02470 case PV_ESWITCHES:
02471
02472
02473 check_pval(item->u1.list, apps,in_globals);
02474 break;
02475
02476 case PV_INCLUDES:
02477
02478
02479 check_pval(item->u1.list, apps,in_globals);
02480 check_includes(item);
02481 for (lp=item->u1.list; lp; lp=lp->next){
02482 char *incl_context = lp->u1.str;
02483 struct pval *that_context = find_context(incl_context);
02484
02485 if ( lp->u2.arglist ) {
02486 check_timerange(lp->u2.arglist);
02487 check_dow(lp->u2.arglist->next);
02488 check_day(lp->u2.arglist->next->next);
02489 check_month(lp->u2.arglist->next->next->next);
02490 }
02491
02492 if (that_context) {
02493 find_pval_gotos(that_context->u2.statements,0);
02494
02495 }
02496 }
02497 break;
02498
02499 case PV_STATEMENTBLOCK:
02500
02501
02502 check_pval(item->u1.list, apps,in_globals);
02503 break;
02504
02505 case PV_VARDEC:
02506
02507
02508
02509
02510 if( !in_globals ) {
02511 snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", config, item->startline, item->startcol, item->endcol, item->u2.val);
02512 ast_expr_register_extra_error_info(errmsg);
02513 ast_expr(item->u2.val, expr_output, sizeof(expr_output));
02514 ast_expr_clear_extra_error_info();
02515 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
02516 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02517 item->filename, item->startline, item->endline, item->u2.val);
02518 warns++;
02519 }
02520 check_expr2_input(item,item->u2.val);
02521 }
02522 break;
02523
02524 case PV_GOTO:
02525
02526
02527
02528
02529 if ( in_abstract_context )
02530 break;
02531
02532 check_goto(item);
02533 break;
02534
02535 case PV_LABEL:
02536
02537
02538 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
02539 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
02540 item->filename, item->startline, item->endline, item->u1.str);
02541 warns++;
02542 }
02543
02544 check_label(item);
02545 break;
02546
02547 case PV_FOR:
02548
02549
02550
02551
02552
02553
02554 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", config, item->startline, item->startcol, item->endcol, item->u2.for_test);
02555 ast_expr_register_extra_error_info(errmsg);
02556
02557 strp = strchr(item->u1.for_init, '=');
02558 if (strp) {
02559 ast_expr(strp+1, expr_output, sizeof(expr_output));
02560 }
02561 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output));
02562 strp = strchr(item->u3.for_inc, '=');
02563 if (strp) {
02564 ast_expr(strp+1, expr_output, sizeof(expr_output));
02565 }
02566 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
02567 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02568 item->filename, item->startline, item->endline, item->u2.for_test);
02569 warns++;
02570 }
02571 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
02572 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02573 item->filename, item->startline, item->endline, item->u3.for_inc);
02574 warns++;
02575 }
02576 check_expr2_input(item,item->u2.for_test);
02577 check_expr2_input(item,item->u3.for_inc);
02578
02579 ast_expr_clear_extra_error_info();
02580 check_pval(item->u4.for_statements, apps,in_globals);
02581 break;
02582
02583 case PV_WHILE:
02584
02585
02586
02587
02588 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02589 ast_expr_register_extra_error_info(errmsg);
02590 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02591 ast_expr_clear_extra_error_info();
02592 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02593 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02594 item->filename, item->startline, item->endline, item->u1.str);
02595 warns++;
02596 }
02597 check_expr2_input(item,item->u1.str);
02598 check_pval(item->u2.statements, apps,in_globals);
02599 break;
02600
02601 case PV_BREAK:
02602
02603
02604 check_break(item);
02605 break;
02606
02607 case PV_RETURN:
02608
02609
02610 break;
02611
02612 case PV_CONTINUE:
02613
02614
02615 check_continue(item);
02616 break;
02617
02618 case PV_RANDOM:
02619
02620
02621
02622
02623
02624
02625 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02626 ast_expr_register_extra_error_info(errmsg);
02627 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02628 ast_expr_clear_extra_error_info();
02629 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02630 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
02631 item->filename, item->startline, item->endline, item->u1.str);
02632 warns++;
02633 }
02634 check_expr2_input(item,item->u1.str);
02635 check_pval(item->u2.statements, apps,in_globals);
02636 if (item->u3.else_statements) {
02637 check_pval(item->u3.else_statements, apps,in_globals);
02638 }
02639 break;
02640
02641 case PV_IFTIME:
02642
02643
02644
02645
02646
02647
02648 if ( item->u2.arglist ) {
02649 check_timerange(item->u1.list);
02650 check_dow(item->u1.list->next);
02651 check_day(item->u1.list->next->next);
02652 check_month(item->u1.list->next->next->next);
02653 }
02654
02655 check_pval(item->u2.statements, apps,in_globals);
02656 if (item->u3.else_statements) {
02657 check_pval(item->u3.else_statements, apps,in_globals);
02658 }
02659 break;
02660
02661 case PV_IF:
02662
02663
02664
02665
02666
02667
02668 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02669 ast_expr_register_extra_error_info(errmsg);
02670 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02671 ast_expr_clear_extra_error_info();
02672 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02673 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
02674 item->filename, item->startline, item->endline, item->u1.str);
02675 warns++;
02676 }
02677 check_expr2_input(item,item->u1.str);
02678 check_pval(item->u2.statements, apps,in_globals);
02679 if (item->u3.else_statements) {
02680 check_pval(item->u3.else_statements, apps,in_globals);
02681 }
02682 break;
02683
02684 case PV_SWITCH:
02685
02686
02687
02688
02689
02690
02691
02692 check_switch_expr(item, apps);
02693 check_pval(item->u2.statements, apps,in_globals);
02694 break;
02695
02696 case PV_EXTENSION:
02697
02698
02699
02700
02701
02702
02703 current_extension = item ;
02704
02705 check_pval(item->u2.statements, apps,in_globals);
02706 break;
02707
02708 case PV_IGNOREPAT:
02709
02710
02711 break;
02712
02713 case PV_GLOBALS:
02714
02715
02716 in_abstract_context = 0;
02717 check_pval(item->u1.statements, apps, 1);
02718 break;
02719 default:
02720 break;
02721 }
02722 }
02723
02724 void check_pval(pval *item, struct argapp *apps, int in_globals)
02725 {
02726 pval *i;
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739 for (i=item; i; i=i->next) {
02740 check_pval_item(i,apps,in_globals);
02741 }
02742 }
02743
02744 static void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
02745 {
02746
02747 #ifdef AAL_ARGCHECK
02748 int argapp_errs =0;
02749 char *rfilename, *rdirname, *xappsfilename;
02750 DIR *dir = NULL;
02751 struct dirent *de;
02752 #endif
02753 struct argapp *apps=0, *xapps=0, *app;
02754
02755 if (!item)
02756 return;
02757 #ifdef AAL_ARGCHECK
02758 rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR));
02759 sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
02760
02761 apps = argdesc_parse(rfilename, &argapp_errs);
02762
02763 if (argapp_errs == 0) {
02764 ast_log(LOG_NOTICE, "AEL load process: parsed default apps desc file '%s'.\n", rfilename);
02765 } else {
02766 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing apps file '%s'.\n", argapp_errs, rfilename);
02767 }
02768
02769
02770 rdirname = alloca(16 + strlen(ast_config_AST_VAR_DIR));
02771 sprintf(rdirname, "%s/applist.d", ast_config_AST_VAR_DIR);
02772 dir = opendir(rdirname);
02773 if (!dir) {
02774 ast_log(LOG_WARNING, "Unable to open ael2 extra apps dir. %s is not a valid directory\n", rdirname);
02775 } else {
02776
02777 argapp_errs = 0;
02778
02779 xappsfilename = alloca(AST_MAX_FILENAME_LEN + strlen(rdirname));
02780 while ((de = readdir(dir))) {
02781 xappsfilename[0] = 0;
02782 if ((strlen(de->d_name) > 4) && !strcasecmp(de->d_name + strlen(de->d_name) - 5, ".apps")) {
02783 sprintf(xappsfilename, "%s/%s", rdirname, de->d_name);
02784 xapps = argdesc_parse(xappsfilename, &argapp_errs);
02785
02786 if(xapps != NULL) {
02787 if (argapp_errs == 0) {
02788 ast_log(LOG_NOTICE, "AEL load process: parsed extra apps desc file '%s'.\n", xappsfilename);
02789 } else {
02790 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing extra apps file '%s'.\n", argapp_errs, xappsfilename);
02791 }
02792 app=xapps;
02793 while (app->next != NULL) {
02794 app=app->next;
02795 }
02796 app->next = apps;
02797 apps = xapps;
02798 } else {
02799 ast_log(LOG_WARNING, "AEL load process: no apps desc found into file '%s'.\n", xappsfilename);
02800 }
02801 }
02802 }
02803 }
02804 #endif
02805 current_db = item;
02806 errs = warns = notes = 0;
02807
02808 check_context_names();
02809 check_pval(item, apps, 0);
02810
02811 #ifdef AAL_ARGCHECK
02812 argdesc_destroy(apps);
02813 #endif
02814 current_db = 0;
02815
02816 *arg_errs = errs;
02817 *arg_warns = warns;
02818 *arg_notes = notes;
02819 }
02820
02821
02822
02823
02824
02825 static int control_statement_count = 0;
02826
02827 struct ael_priority *new_prio(void)
02828 {
02829 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02830 return x;
02831 }
02832
02833 struct ael_extension *new_exten(void)
02834 {
02835 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02836 return x;
02837 }
02838
02839 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
02840 {
02841 char *p1, *p2;
02842
02843 if (!exten->plist) {
02844 exten->plist = prio;
02845 exten->plist_last = prio;
02846 } else {
02847 exten->plist_last->next = prio;
02848 exten->plist_last = prio;
02849 }
02850 if( !prio->exten )
02851 prio->exten = exten;
02852
02853
02854
02855
02856
02857 if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
02858 while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
02859 p2 = malloc(strlen(prio->appargs)+5);
02860 *p1 = 0;
02861 strcpy(p2, prio->appargs);
02862 strcat(p2, "${~~EXTEN~~}");
02863 if (*(p1+8))
02864 strcat(p2, p1+8);
02865 free(prio->appargs);
02866 prio->appargs = p2;
02867 }
02868 while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
02869 p2 = malloc(strlen(prio->appargs)+5);
02870 *p1 = 0;
02871 strcpy(p2, prio->appargs);
02872 strcat(p2, "${~~EXTEN~~:");
02873 if (*(p1+8))
02874 strcat(p2, p1+8);
02875 free(prio->appargs);
02876 prio->appargs = p2;
02877 }
02878 }
02879 }
02880
02881 void destroy_extensions(struct ael_extension *exten)
02882 {
02883 struct ael_extension *ne, *nen;
02884 for (ne=exten; ne; ne=nen) {
02885 struct ael_priority *pe, *pen;
02886
02887 if (ne->name)
02888 free(ne->name);
02889
02890
02891
02892
02893
02894 if (ne->hints)
02895 free(ne->hints);
02896
02897 for (pe=ne->plist; pe; pe=pen) {
02898 pen = pe->next;
02899 if (pe->app)
02900 free(pe->app);
02901 pe->app = 0;
02902 if (pe->appargs)
02903 free(pe->appargs);
02904 pe->appargs = 0;
02905 pe->origin = 0;
02906 pe->goto_true = 0;
02907 pe->goto_false = 0;
02908 free(pe);
02909 }
02910 nen = ne->next_exten;
02911 ne->next_exten = 0;
02912 ne->plist =0;
02913 ne->plist_last = 0;
02914 ne->next_exten = 0;
02915 ne->loop_break = 0;
02916 ne->loop_continue = 0;
02917 free(ne);
02918 }
02919 }
02920
02921 static int label_inside_case(pval *label)
02922 {
02923 pval *p = label;
02924
02925 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
02926 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
02927 return 1;
02928 }
02929
02930 p = p->dad;
02931 }
02932 return 0;
02933 }
02934
02935 static void linkexten(struct ael_extension *exten, struct ael_extension *add)
02936 {
02937 add->next_exten = exten->next_exten;
02938 exten->next_exten = add;
02939 }
02940
02941 static void remove_spaces_before_equals(char *str)
02942 {
02943 char *p;
02944 while( str && *str && *str != '=' )
02945 {
02946 if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02947 {
02948 p = str;
02949 while( *p )
02950 {
02951 *p = *(p+1);
02952 p++;
02953 }
02954 }
02955 else
02956 str++;
02957 }
02958 }
02959
02960 static void gen_match_to_pattern(char *pattern, char *result)
02961 {
02962
02963 char *p=pattern, *t=result;
02964 while (*p) {
02965 if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02966 *t++ = '9';
02967 else if (*p == '[') {
02968 char *z = p+1;
02969 while (*z != ']')
02970 z++;
02971 if (*(z+1)== ']')
02972 z++;
02973 *t++=*(p+1);
02974 p = z;
02975 } else {
02976 *t++ = *p;
02977 }
02978 p++;
02979 }
02980 *t++ = 0;
02981 }
02982
02983
02984
02985 int find_switch_item(pval *item);
02986 int contains_switch(pval *item);
02987
02988
02989 int find_switch_item(pval *item)
02990 {
02991 switch ( item->type ) {
02992 case PV_WORD:
02993
02994 break;
02995
02996 case PV_MACRO:
02997
02998
02999
03000
03001
03002
03003
03004
03005 if (contains_switch(item->u3.macro_statements))
03006 return 1;
03007 break;
03008
03009 case PV_CONTEXT:
03010
03011
03012
03013
03014
03015 if (contains_switch(item->u2.statements))
03016 return 1;
03017 break;
03018
03019 case PV_MACRO_CALL:
03020
03021
03022
03023
03024
03025 break;
03026
03027 case PV_APPLICATION_CALL:
03028
03029
03030
03031
03032
03033 break;
03034
03035 case PV_CASE:
03036
03037
03038
03039
03040 if (contains_switch(item->u2.statements))
03041 return 1;
03042 break;
03043
03044 case PV_PATTERN:
03045
03046
03047
03048
03049 if (contains_switch(item->u2.statements))
03050 return 1;
03051 break;
03052
03053 case PV_DEFAULT:
03054
03055
03056
03057
03058 if (contains_switch(item->u2.statements))
03059 return 1;
03060 break;
03061
03062 case PV_CATCH:
03063
03064
03065
03066
03067 if (contains_switch(item->u2.statements))
03068 return 1;
03069 break;
03070
03071 case PV_SWITCHES:
03072
03073
03074 break;
03075
03076 case PV_ESWITCHES:
03077
03078
03079 break;
03080
03081 case PV_INCLUDES:
03082
03083
03084
03085 break;
03086
03087 case PV_STATEMENTBLOCK:
03088
03089
03090 if (contains_switch(item->u1.list) )
03091 return 1;
03092 break;
03093
03094 case PV_VARDEC:
03095
03096
03097
03098 break;
03099
03100 case PV_GOTO:
03101
03102
03103
03104 break;
03105
03106 case PV_LABEL:
03107
03108
03109 break;
03110
03111 case PV_FOR:
03112
03113
03114
03115
03116
03117
03118 if (contains_switch(item->u4.for_statements))
03119 return 1;
03120 break;
03121
03122 case PV_WHILE:
03123
03124
03125
03126
03127 if (contains_switch(item->u2.statements))
03128 return 1;
03129 break;
03130
03131 case PV_BREAK:
03132
03133
03134 break;
03135
03136 case PV_RETURN:
03137
03138
03139 break;
03140
03141 case PV_CONTINUE:
03142
03143
03144 break;
03145
03146 case PV_IFTIME:
03147
03148
03149
03150
03151
03152
03153 if (contains_switch(item->u2.statements))
03154 return 1;
03155 if ( item->u3.else_statements ) {
03156 if (contains_switch(item->u3.else_statements))
03157 return 1;
03158 }
03159 break;
03160
03161 case PV_RANDOM:
03162
03163
03164
03165
03166
03167
03168 if (contains_switch(item->u2.statements))
03169 return 1;
03170 if ( item->u3.else_statements ) {
03171 if (contains_switch(item->u3.else_statements))
03172 return 1;
03173 }
03174 break;
03175
03176 case PV_IF:
03177
03178
03179
03180
03181
03182
03183 if (contains_switch(item->u2.statements))
03184 return 1;
03185 if ( item->u3.else_statements ) {
03186 if (contains_switch(item->u3.else_statements))
03187 return 1;
03188 }
03189 break;
03190
03191 case PV_SWITCH:
03192
03193
03194
03195
03196
03197 return 1;
03198 break;
03199
03200 case PV_EXTENSION:
03201
03202
03203
03204
03205
03206
03207 if (contains_switch(item->u2.statements))
03208 return 1;
03209 break;
03210
03211 case PV_IGNOREPAT:
03212
03213
03214 break;
03215
03216 case PV_GLOBALS:
03217
03218
03219 break;
03220 }
03221 return 0;
03222 }
03223
03224 int contains_switch(pval *item)
03225 {
03226 pval *i;
03227
03228 for (i=item; i; i=i->next) {
03229 if (find_switch_item(i))
03230 return 1;
03231 }
03232 return 0;
03233 }
03234
03235
03236 static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context )
03237 {
03238 pval *p,*p2,*p3;
03239 struct ael_priority *pr;
03240 struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
03241 struct ael_priority *while_test, *while_loop, *while_end;
03242 struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
03243 struct ael_priority *if_test, *if_end, *if_skip, *if_false;
03244 #ifdef OLD_RAND_ACTION
03245 struct ael_priority *rand_test, *rand_end, *rand_skip;
03246 #endif
03247 char buf1[2000];
03248 char buf2[2000];
03249 char *strp, *strp2;
03250 char new_label[2000];
03251 int default_exists;
03252 int local_control_statement_count;
03253 struct ael_priority *loop_break_save;
03254 struct ael_priority *loop_continue_save;
03255 struct ael_extension *switch_case,*switch_null;
03256
03257 if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) {
03258 if (contains_switch(statement)) {
03259 if (mother_exten) {
03260 if (!mother_exten->has_switch) {
03261 switch_set = new_prio();
03262 switch_set->type = AEL_APPCALL;
03263 switch_set->app = strdup("Set");
03264 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03265 linkprio(exten, switch_set, mother_exten);
03266 mother_exten->has_switch = 1;
03267 mother_exten->checked_switch = 1;
03268 if (exten) {
03269 exten->has_switch = 1;
03270 exten->checked_switch = 1;
03271 }
03272 }
03273 } else if (exten) {
03274 if (!exten->has_switch) {
03275 switch_set = new_prio();
03276 switch_set->type = AEL_APPCALL;
03277 switch_set->app = strdup("Set");
03278 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03279 linkprio(exten, switch_set, mother_exten);
03280 exten->has_switch = 1;
03281 exten->checked_switch = 1;
03282 if (mother_exten) {
03283 mother_exten->has_switch = 1;
03284 mother_exten->checked_switch = 1;
03285 }
03286 }
03287 }
03288 } else {
03289 if (mother_exten) {
03290 mother_exten->checked_switch = 1;
03291 }
03292 if (exten) {
03293 exten->checked_switch = 1;
03294 }
03295 }
03296 }
03297 for (p=statement; p; p=p->next) {
03298 switch (p->type) {
03299 case PV_VARDEC:
03300 pr = new_prio();
03301 pr->type = AEL_APPCALL;
03302 snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
03303 pr->app = strdup("Set");
03304 remove_spaces_before_equals(buf1);
03305 pr->appargs = strdup(buf1);
03306 pr->origin = p;
03307 linkprio(exten, pr, mother_exten);
03308 break;
03309
03310 case PV_GOTO:
03311 pr = new_prio();
03312 pr->type = AEL_APPCALL;
03313 p->u2.goto_target = get_goto_target(p);
03314 if( p->u2.goto_target ) {
03315 p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target);
03316 }
03317
03318 if (!p->u1.list->next) {
03319 pr->app = strdup("Goto");
03320 if (!mother_exten)
03321 pr->appargs = strdup(p->u1.list->u1.str);
03322 else {
03323 snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
03324 pr->appargs = strdup(buf1);
03325 }
03326
03327 } else if (p->u1.list->next && !p->u1.list->next->next) {
03328 snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
03329 pr->app = strdup("Goto");
03330 pr->appargs = strdup(buf1);
03331 } else if (p->u1.list->next && p->u1.list->next->next) {
03332 snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str,
03333 p->u1.list->next->u1.str,
03334 p->u1.list->next->next->u1.str);
03335 pr->app = strdup("Goto");
03336 pr->appargs = strdup(buf1);
03337 }
03338 pr->origin = p;
03339 linkprio(exten, pr, mother_exten);
03340 break;
03341
03342 case PV_LABEL:
03343 pr = new_prio();
03344 pr->type = AEL_LABEL;
03345 pr->origin = p;
03346 p->u3.compiled_label = exten;
03347 linkprio(exten, pr, mother_exten);
03348 break;
03349
03350 case PV_FOR:
03351 control_statement_count++;
03352 loop_break_save = exten->loop_break;
03353 loop_continue_save = exten->loop_continue;
03354 snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
03355 for_init = new_prio();
03356 for_inc = new_prio();
03357 for_test = new_prio();
03358 for_loop = new_prio();
03359 for_end = new_prio();
03360 for_init->type = AEL_APPCALL;
03361 for_inc->type = AEL_APPCALL;
03362 for_test->type = AEL_FOR_CONTROL;
03363 for_test->goto_false = for_end;
03364 for_loop->type = AEL_CONTROL1;
03365 for_end->type = AEL_APPCALL;
03366 for_init->app = strdup("Set");
03367
03368 strcpy(buf2,p->u1.for_init);
03369 remove_spaces_before_equals(buf2);
03370 strp = strchr(buf2, '=');
03371 if (strp) {
03372 strp2 = strchr(p->u1.for_init, '=');
03373 *(strp+1) = 0;
03374 strcat(buf2,"$[");
03375 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03376 strcat(buf2,"]");
03377 for_init->appargs = strdup(buf2);
03378
03379 } else {
03380 strp2 = p->u1.for_init;
03381 while (*strp2 && isspace(*strp2))
03382 strp2++;
03383 if (*strp2 == '&') {
03384 char *strp3 = strp2+1;
03385 while (*strp3 && isspace(*strp3))
03386 strp3++;
03387 strcpy(buf2, strp3);
03388 strp3 = strchr(buf2,'(');
03389 if (strp3) {
03390 *strp3 = '|';
03391 }
03392 while ((strp3=strchr(buf2,','))) {
03393 *strp3 = '|';
03394 }
03395 strp3 = strrchr(buf2, ')');
03396 if (strp3)
03397 *strp3 = 0;
03398
03399 for_init->appargs = strdup(buf2);
03400 if (for_init->app)
03401 free(for_init->app);
03402 for_init->app = strdup("Macro");
03403 } else {
03404 char *strp3;
03405 strcpy(buf2, strp2);
03406 strp3 = strchr(buf2,'(');
03407 if (strp3) {
03408 *strp3 = 0;
03409 if (for_init->app)
03410 free(for_init->app);
03411 for_init->app = strdup(buf2);
03412 for_init->appargs = strdup(strp3+1);
03413 strp3 = strrchr(for_init->appargs, ')');
03414 if (strp3)
03415 *strp3 = 0;
03416 }
03417 }
03418 }
03419
03420 strcpy(buf2,p->u3.for_inc);
03421 remove_spaces_before_equals(buf2);
03422 strp = strchr(buf2, '=');
03423 if (strp) {
03424 strp2 = strchr(p->u3.for_inc, '=');
03425 *(strp+1) = 0;
03426 strcat(buf2,"$[");
03427 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03428 strcat(buf2,"]");
03429 for_inc->appargs = strdup(buf2);
03430 for_inc->app = strdup("Set");
03431 } else {
03432 strp2 = p->u3.for_inc;
03433 while (*strp2 && isspace(*strp2))
03434 strp2++;
03435 if (*strp2 == '&') {
03436 char *strp3 = strp2+1;
03437 while (*strp3 && isspace(*strp3))
03438 strp3++;
03439 strcpy(buf2, strp3);
03440 strp3 = strchr(buf2,'(');
03441 if (strp3) {
03442 *strp3 = '|';
03443 }
03444 while ((strp3=strchr(buf2,','))) {
03445 *strp3 = '|';
03446 }
03447 strp3 = strrchr(buf2, ')');
03448 if (strp3)
03449 *strp3 = 0;
03450
03451 for_inc->appargs = strdup(buf2);
03452
03453 for_inc->app = strdup("Macro");
03454 } else {
03455 char *strp3;
03456 strcpy(buf2, strp2);
03457 strp3 = strchr(buf2,'(');
03458 if (strp3) {
03459 *strp3 = 0;
03460 for_inc->app = strdup(buf2);
03461 for_inc->appargs = strdup(strp3+1);
03462 strp3 = strrchr(for_inc->appargs, ')');
03463 if (strp3)
03464 *strp3 = 0;
03465 }
03466 }
03467 }
03468 snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03469 for_test->app = 0;
03470 for_test->appargs = strdup(buf1);
03471 for_loop->goto_true = for_test;
03472 snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03473 for_end->app = strdup("NoOp");
03474 for_end->appargs = strdup(buf1);
03475
03476 linkprio(exten, for_init, mother_exten);
03477 linkprio(exten, for_test, mother_exten);
03478
03479
03480 exten->loop_break = for_end;
03481 exten->loop_continue = for_inc;
03482
03483 gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context);
03484
03485 linkprio(exten, for_inc, mother_exten);
03486 linkprio(exten, for_loop, mother_exten);
03487 linkprio(exten, for_end, mother_exten);
03488
03489
03490 exten->loop_break = loop_break_save;
03491 exten->loop_continue = loop_continue_save;
03492 for_loop->origin = p;
03493 break;
03494
03495 case PV_WHILE:
03496 control_statement_count++;
03497 loop_break_save = exten->loop_break;
03498 loop_continue_save = exten->loop_continue;
03499 snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03500 while_test = new_prio();
03501 while_loop = new_prio();
03502 while_end = new_prio();
03503 while_test->type = AEL_FOR_CONTROL;
03504 while_test->goto_false = while_end;
03505 while_loop->type = AEL_CONTROL1;
03506 while_end->type = AEL_APPCALL;
03507 snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03508 while_test->app = 0;
03509 while_test->appargs = strdup(buf1);
03510 while_loop->goto_true = while_test;
03511 snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03512 while_end->app = strdup("NoOp");
03513 while_end->appargs = strdup(buf1);
03514
03515 linkprio(exten, while_test, mother_exten);
03516
03517
03518 exten->loop_break = while_end;
03519 exten->loop_continue = while_test;
03520
03521 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03522
03523 linkprio(exten, while_loop, mother_exten);
03524 linkprio(exten, while_end, mother_exten);
03525
03526
03527 exten->loop_break = loop_break_save;
03528 exten->loop_continue = loop_continue_save;
03529 while_loop->origin = p;
03530 break;
03531
03532 case PV_SWITCH:
03533 control_statement_count++;
03534 local_control_statement_count = control_statement_count;
03535 loop_break_save = exten->loop_break;
03536 loop_continue_save = exten->loop_continue;
03537 snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03538 switch_test = new_prio();
03539 switch_end = new_prio();
03540 switch_test->type = AEL_APPCALL;
03541 switch_end->type = AEL_APPCALL;
03542 strncpy(buf2,p->u1.str,sizeof(buf2));
03543 buf2[sizeof(buf2)-1] = 0;
03544 substitute_commas(buf2);
03545 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, buf2);
03546 switch_test->app = strdup("Goto");
03547 switch_test->appargs = strdup(buf1);
03548 snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03549 switch_end->app = strdup("NoOp");
03550 switch_end->appargs = strdup(buf1);
03551 switch_end->origin = p;
03552 switch_end->exten = exten;
03553
03554 linkprio(exten, switch_test, mother_exten);
03555 linkprio(exten, switch_end, mother_exten);
03556
03557 exten->loop_break = switch_end;
03558 exten->loop_continue = 0;
03559 default_exists = 0;
03560
03561 for (p2=p->u2.statements; p2; p2=p2->next) {
03562
03563 if (p2->type == PV_CASE) {
03564
03565 switch_case = new_exten();
03566 if (mother_exten && mother_exten->checked_switch) {
03567 switch_case->has_switch = mother_exten->has_switch;
03568 switch_case->checked_switch = mother_exten->checked_switch;
03569 }
03570 if (exten && exten->checked_switch) {
03571 switch_case->has_switch = exten->has_switch;
03572 switch_case->checked_switch = exten->checked_switch;
03573 }
03574 switch_case->context = this_context;
03575 switch_case->is_switch = 1;
03576
03577 switch_case->loop_break = exten->loop_break;
03578 switch_case->loop_continue = exten->loop_continue;
03579
03580 linkexten(exten,switch_case);
03581 strncpy(buf2,p2->u1.str,sizeof(buf2));
03582 buf2[sizeof(buf2)-1] = 0;
03583 substitute_commas(buf2);
03584 snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, buf2);
03585 switch_case->name = strdup(buf1);
03586 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03587
03588 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03589
03590
03591 for (p3=p2->u2.statements; p3; p3=p3->next) {
03592 if (!p3->next)
03593 break;
03594 }
03595
03596 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
03597
03598 if (p2->next && p2->next->type == PV_CASE) {
03599 fall_thru = new_prio();
03600 fall_thru->type = AEL_APPCALL;
03601 fall_thru->app = strdup("Goto");
03602 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03603 buf2[sizeof(buf2)-1] = 0;
03604 substitute_commas(buf2);
03605 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03606 fall_thru->appargs = strdup(buf1);
03607 linkprio(switch_case, fall_thru, mother_exten);
03608 } else if (p2->next && p2->next->type == PV_PATTERN) {
03609 fall_thru = new_prio();
03610 fall_thru->type = AEL_APPCALL;
03611 fall_thru->app = strdup("Goto");
03612 gen_match_to_pattern(p2->next->u1.str, buf2);
03613 substitute_commas(buf2);
03614 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2);
03615 fall_thru->appargs = strdup(buf1);
03616 linkprio(switch_case, fall_thru, mother_exten);
03617 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03618 fall_thru = new_prio();
03619 fall_thru->type = AEL_APPCALL;
03620 fall_thru->app = strdup("Goto");
03621 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03622 fall_thru->appargs = strdup(buf1);
03623 linkprio(switch_case, fall_thru, mother_exten);
03624 } else if (!p2->next) {
03625 fall_thru = new_prio();
03626 fall_thru->type = AEL_CONTROL1;
03627 fall_thru->goto_true = switch_end;
03628 fall_thru->app = strdup("Goto");
03629 linkprio(switch_case, fall_thru, mother_exten);
03630 }
03631 }
03632 if (switch_case->return_needed) {
03633 char buf[2000];
03634 struct ael_priority *np2 = new_prio();
03635 np2->type = AEL_APPCALL;
03636 np2->app = strdup("NoOp");
03637 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03638 np2->appargs = strdup(buf);
03639 linkprio(switch_case, np2, mother_exten);
03640 switch_case-> return_target = np2;
03641 }
03642 } else if (p2->type == PV_PATTERN) {
03643
03644 switch_case = new_exten();
03645 if (mother_exten && mother_exten->checked_switch) {
03646 switch_case->has_switch = mother_exten->has_switch;
03647 switch_case->checked_switch = mother_exten->checked_switch;
03648 }
03649 if (exten && exten->checked_switch) {
03650 switch_case->has_switch = exten->has_switch;
03651 switch_case->checked_switch = exten->checked_switch;
03652 }
03653 switch_case->context = this_context;
03654 switch_case->is_switch = 1;
03655
03656 switch_case->loop_break = exten->loop_break;
03657 switch_case->loop_continue = exten->loop_continue;
03658
03659 linkexten(exten,switch_case);
03660 strncpy(buf2,p2->u1.str,sizeof(buf2));
03661 buf2[sizeof(buf2)-1] = 0;
03662 substitute_commas(buf2);
03663 snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, buf2);
03664 switch_case->name = strdup(buf1);
03665 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03666
03667 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03668
03669 for (p3=p2->u2.statements; p3; p3=p3->next) {
03670 if (!p3->next)
03671 break;
03672 }
03673
03674 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03675
03676 if (p2->next && p2->next->type == PV_CASE) {
03677 fall_thru = new_prio();
03678 fall_thru->type = AEL_APPCALL;
03679 fall_thru->app = strdup("Goto");
03680 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03681 buf2[sizeof(buf2)-1] = 0;
03682 substitute_commas(buf2);
03683 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03684 fall_thru->appargs = strdup(buf1);
03685 linkprio(switch_case, fall_thru, mother_exten);
03686 } else if (p2->next && p2->next->type == PV_PATTERN) {
03687 fall_thru = new_prio();
03688 fall_thru->type = AEL_APPCALL;
03689 fall_thru->app = strdup("Goto");
03690 gen_match_to_pattern(p2->next->u1.str, buf2);
03691 substitute_commas(buf2);
03692 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03693 fall_thru->appargs = strdup(buf1);
03694 linkprio(switch_case, fall_thru, mother_exten);
03695 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03696 fall_thru = new_prio();
03697 fall_thru->type = AEL_APPCALL;
03698 fall_thru->app = strdup("Goto");
03699 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03700 fall_thru->appargs = strdup(buf1);
03701 linkprio(switch_case, fall_thru, mother_exten);
03702 } else if (!p2->next) {
03703 fall_thru = new_prio();
03704 fall_thru->type = AEL_CONTROL1;
03705 fall_thru->goto_true = switch_end;
03706 fall_thru->app = strdup("Goto");
03707 linkprio(switch_case, fall_thru, mother_exten);
03708 }
03709 }
03710 if (switch_case->return_needed) {
03711 char buf[2000];
03712 struct ael_priority *np2 = new_prio();
03713 np2->type = AEL_APPCALL;
03714 np2->app = strdup("NoOp");
03715 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03716 np2->appargs = strdup(buf);
03717 linkprio(switch_case, np2, mother_exten);
03718 switch_case-> return_target = np2;
03719 }
03720 } else if (p2->type == PV_DEFAULT) {
03721
03722 switch_case = new_exten();
03723 if (mother_exten && mother_exten->checked_switch) {
03724 switch_case->has_switch = mother_exten->has_switch;
03725 switch_case->checked_switch = mother_exten->checked_switch;
03726 }
03727 if (exten && exten->checked_switch) {
03728 switch_case->has_switch = exten->has_switch;
03729 switch_case->checked_switch = exten->checked_switch;
03730 }
03731 switch_case->context = this_context;
03732 switch_case->is_switch = 1;
03733
03734
03735
03736
03737
03738 default_exists++;
03739 switch_null = new_exten();
03740 if (mother_exten && mother_exten->checked_switch) {
03741 switch_null->has_switch = mother_exten->has_switch;
03742 switch_null->checked_switch = mother_exten->checked_switch;
03743 }
03744 if (exten && exten->checked_switch) {
03745 switch_null->has_switch = exten->has_switch;
03746 switch_null->checked_switch = exten->checked_switch;
03747 }
03748 switch_null->context = this_context;
03749 switch_null->is_switch = 1;
03750 switch_empty = new_prio();
03751 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03752 switch_empty->app = strdup("Goto");
03753 switch_empty->appargs = strdup(buf1);
03754 linkprio(switch_null, switch_empty, mother_exten);
03755 snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count);
03756 switch_null->name = strdup(buf1);
03757 switch_null->loop_break = exten->loop_break;
03758 switch_null->loop_continue = exten->loop_continue;
03759 linkexten(exten,switch_null);
03760
03761
03762 switch_case->loop_break = exten->loop_break;
03763 switch_case->loop_continue = exten->loop_continue;
03764 linkexten(exten,switch_case);
03765 snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count);
03766 switch_case->name = strdup(buf1);
03767
03768 snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count);
03769
03770 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03771
03772
03773 for (p3=p2->u2.statements; p3; p3=p3->next) {
03774 if (!p3->next)
03775 break;
03776 }
03777
03778 if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03779
03780 if (p2->next && p2->next->type == PV_CASE) {
03781 fall_thru = new_prio();
03782 fall_thru->type = AEL_APPCALL;
03783 fall_thru->app = strdup("Goto");
03784 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03785 buf2[sizeof(buf2)-1] = 0;
03786 substitute_commas(buf2);
03787 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03788 fall_thru->appargs = strdup(buf1);
03789 linkprio(switch_case, fall_thru, mother_exten);
03790 } else if (p2->next && p2->next->type == PV_PATTERN) {
03791 fall_thru = new_prio();
03792 fall_thru->type = AEL_APPCALL;
03793 fall_thru->app = strdup("Goto");
03794 gen_match_to_pattern(p2->next->u1.str, buf2);
03795 substitute_commas(buf2);
03796 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03797 fall_thru->appargs = strdup(buf1);
03798 linkprio(switch_case, fall_thru, mother_exten);
03799 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03800 fall_thru = new_prio();
03801 fall_thru->type = AEL_APPCALL;
03802 fall_thru->app = strdup("Goto");
03803 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03804 fall_thru->appargs = strdup(buf1);
03805 linkprio(switch_case, fall_thru, mother_exten);
03806 } else if (!p2->next) {
03807 fall_thru = new_prio();
03808 fall_thru->type = AEL_CONTROL1;
03809 fall_thru->goto_true = switch_end;
03810 fall_thru->app = strdup("Goto");
03811 linkprio(switch_case, fall_thru, mother_exten);
03812 }
03813 }
03814 if (switch_case->return_needed) {
03815 char buf[2000];
03816 struct ael_priority *np2 = new_prio();
03817 np2->type = AEL_APPCALL;
03818 np2->app = strdup("NoOp");
03819 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03820 np2->appargs = strdup(buf);
03821 linkprio(switch_case, np2, mother_exten);
03822 switch_case-> return_target = np2;
03823 }
03824 } else {
03825
03826 }
03827 }
03828
03829 exten->loop_break = loop_break_save;
03830 exten->loop_continue = loop_continue_save;
03831 switch_test->origin = p;
03832 switch_end->origin = p;
03833 break;
03834
03835 case PV_MACRO_CALL:
03836 pr = new_prio();
03837 pr->type = AEL_APPCALL;
03838 snprintf(buf1,sizeof(buf1),"%s", p->u1.str);
03839 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03840 strcat(buf1,"|");
03841 strcat(buf1,p2->u1.str);
03842 }
03843 pr->app = strdup("Macro");
03844 pr->appargs = strdup(buf1);
03845 pr->origin = p;
03846 linkprio(exten, pr, mother_exten);
03847 break;
03848
03849 case PV_APPLICATION_CALL:
03850 pr = new_prio();
03851 pr->type = AEL_APPCALL;
03852 buf1[0] = 0;
03853 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03854 if (p2 != p->u2.arglist )
03855 strcat(buf1,"|");
03856 substitute_commas(p2->u1.str);
03857 strcat(buf1,p2->u1.str);
03858 }
03859 pr->app = strdup(p->u1.str);
03860 pr->appargs = strdup(buf1);
03861 pr->origin = p;
03862 linkprio(exten, pr, mother_exten);
03863 break;
03864
03865 case PV_BREAK:
03866 pr = new_prio();
03867 pr->type = AEL_CONTROL1;
03868 pr->goto_true = exten->loop_break;
03869 pr->origin = p;
03870 linkprio(exten, pr, mother_exten);
03871 break;
03872
03873 case PV_RETURN:
03874 pr = new_prio();
03875 pr->type = AEL_RETURN;
03876 exten->return_needed++;
03877 pr->app = strdup("Goto");
03878 pr->appargs = strdup("");
03879 pr->origin = p;
03880 linkprio(exten, pr, mother_exten);
03881 break;
03882
03883 case PV_CONTINUE:
03884 pr = new_prio();
03885 pr->type = AEL_CONTROL1;
03886 pr->goto_true = exten->loop_continue;
03887 pr->origin = p;
03888 linkprio(exten, pr, mother_exten);
03889 break;
03890
03891 #ifdef OLD_RAND_ACTION
03892 case PV_RANDOM:
03893 control_statement_count++;
03894 snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count);
03895 rand_test = new_prio();
03896 rand_test->type = AEL_RAND_CONTROL;
03897 snprintf(buf1,sizeof(buf1),"$[%s]",
03898 p->u1.str );
03899 rand_test->app = 0;
03900 rand_test->appargs = strdup(buf1);
03901 rand_test->origin = p;
03902
03903 rand_end = new_prio();
03904 rand_end->type = AEL_APPCALL;
03905 snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count);
03906 rand_end->app = strdup("NoOp");
03907 rand_end->appargs = strdup(buf1);
03908
03909 rand_skip = new_prio();
03910 rand_skip->type = AEL_CONTROL1;
03911 rand_skip->goto_true = rand_end;
03912 rand_skip->origin = p;
03913
03914 rand_test->goto_true = rand_skip;
03915
03916 linkprio(exten, rand_test, mother_exten);
03917
03918 if (p->u3.else_statements) {
03919 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03920 }
03921
03922 linkprio(exten, rand_skip, mother_exten);
03923
03924 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03925
03926 linkprio(exten, rand_end, mother_exten);
03927
03928 break;
03929 #endif
03930
03931 case PV_IFTIME:
03932 control_statement_count++;
03933 snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count);
03934
03935 if_test = new_prio();
03936 if_test->type = AEL_IFTIME_CONTROL;
03937 snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s",
03938 p->u1.list->u1.str,
03939 p->u1.list->next->u1.str,
03940 p->u1.list->next->next->u1.str,
03941 p->u1.list->next->next->next->u1.str);
03942 if_test->app = 0;
03943 if_test->appargs = strdup(buf1);
03944 if_test->origin = p;
03945
03946 if_end = new_prio();
03947 if_end->type = AEL_APPCALL;
03948 snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count);
03949 if_end->app = strdup("NoOp");
03950 if_end->appargs = strdup(buf1);
03951
03952 if (p->u3.else_statements) {
03953 if_skip = new_prio();
03954 if_skip->type = AEL_CONTROL1;
03955 if_skip->goto_true = if_end;
03956 if_skip->origin = p;
03957
03958 } else {
03959 if_skip = 0;
03960
03961 if_test->goto_false = if_end;
03962 }
03963
03964 if_false = new_prio();
03965 if_false->type = AEL_CONTROL1;
03966 if (p->u3.else_statements) {
03967 if_false->goto_true = if_skip;
03968 } else {
03969 if_false->goto_true = if_end;
03970 }
03971
03972
03973 linkprio(exten, if_test, mother_exten);
03974 linkprio(exten, if_false, mother_exten);
03975
03976
03977
03978 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03979
03980 if (p->u3.else_statements) {
03981 linkprio(exten, if_skip, mother_exten);
03982 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03983
03984 }
03985
03986 linkprio(exten, if_end, mother_exten);
03987
03988 break;
03989
03990 case PV_RANDOM:
03991 case PV_IF:
03992 control_statement_count++;
03993 snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count);
03994
03995 if_test = new_prio();
03996 if_end = new_prio();
03997 if_test->type = AEL_IF_CONTROL;
03998 if_end->type = AEL_APPCALL;
03999 if ( p->type == PV_RANDOM )
04000 snprintf(buf1,sizeof(buf1),"$[${RAND(0|99)} < (%s)]",p->u1.str);
04001 else {
04002 char buf[8000];
04003 strcpy(buf,p->u1.str);
04004 substitute_commas(buf);
04005 snprintf(buf1,sizeof(buf1),"$[%s]",buf);
04006 }
04007
04008 if_test->app = 0;
04009 if_test->appargs = strdup(buf1);
04010 snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count);
04011 if_end->app = strdup("NoOp");
04012 if_end->appargs = strdup(buf1);
04013 if_test->origin = p;
04014
04015 if (p->u3.else_statements) {
04016 if_skip = new_prio();
04017 if_skip->type = AEL_CONTROL1;
04018 if_skip->goto_true = if_end;
04019 if_test->goto_false = if_skip;;
04020 } else {
04021 if_skip = 0;
04022 if_test->goto_false = if_end;;
04023 }
04024
04025
04026 linkprio(exten, if_test, mother_exten);
04027
04028
04029
04030 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
04031
04032 if (p->u3.else_statements) {
04033 linkprio(exten, if_skip, mother_exten);
04034 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
04035
04036 }
04037
04038 linkprio(exten, if_end, mother_exten);
04039
04040 break;
04041
04042 case PV_STATEMENTBLOCK:
04043 gen_prios(exten, label, p->u1.list, mother_exten, this_context );
04044 break;
04045
04046 case PV_CATCH:
04047 control_statement_count++;
04048
04049
04050 switch_case = new_exten();
04051 if (mother_exten && mother_exten->checked_switch) {
04052 switch_case->has_switch = mother_exten->has_switch;
04053 switch_case->checked_switch = mother_exten->checked_switch;
04054 }
04055 if (exten && exten->checked_switch) {
04056 switch_case->has_switch = exten->has_switch;
04057 switch_case->checked_switch = exten->checked_switch;
04058 }
04059
04060 switch_case->context = this_context;
04061 linkexten(exten,switch_case);
04062 switch_case->name = strdup(p->u1.str);
04063 snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count);
04064
04065 gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context);
04066 if (switch_case->return_needed) {
04067 char buf[2000];
04068 struct ael_priority *np2 = new_prio();
04069 np2->type = AEL_APPCALL;
04070 np2->app = strdup("NoOp");
04071 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
04072 np2->appargs = strdup(buf);
04073 linkprio(switch_case, np2, mother_exten);
04074 switch_case-> return_target = np2;
04075 }
04076
04077 break;
04078 default:
04079 break;
04080 }
04081 }
04082 }
04083
04084 void set_priorities(struct ael_extension *exten)
04085 {
04086 int i;
04087 struct ael_priority *pr;
04088 do {
04089 if (exten->is_switch)
04090 i = 10;
04091 else if (exten->regexten)
04092 i=2;
04093 else
04094 i=1;
04095
04096 for (pr=exten->plist; pr; pr=pr->next) {
04097 pr->priority_num = i;
04098
04099 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) )
04100
04101
04102
04103 i++;
04104 }
04105
04106 exten = exten->next_exten;
04107 } while ( exten );
04108 }
04109
04110 void add_extensions(struct ael_extension *exten)
04111 {
04112 struct ael_priority *pr;
04113 char *label=0;
04114 char realext[AST_MAX_EXTENSION];
04115 if (!exten) {
04116 ast_log(LOG_WARNING, "This file is Empty!\n" );
04117 return;
04118 }
04119 do {
04120 struct ael_priority *last = 0;
04121
04122 memset(realext, '\0', sizeof(realext));
04123 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
04124 if (exten->hints) {
04125 if (ast_add_extension2(exten->context, 0 , realext, PRIORITY_HINT, NULL, exten->cidmatch,
04126 exten->hints, NULL, ast_free, registrar)) {
04127 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
04128 exten->name);
04129 }
04130 }
04131
04132 for (pr=exten->plist; pr; pr=pr->next) {
04133 char app[2000];
04134 char appargs[2000];
04135
04136
04137
04138
04139 if (pr->type == AEL_LABEL) {
04140 last = pr;
04141 continue;
04142 }
04143
04144 if (pr->app)
04145 strcpy(app, pr->app);
04146 else
04147 app[0] = 0;
04148 if (pr->appargs )
04149 strcpy(appargs, pr->appargs);
04150 else
04151 appargs[0] = 0;
04152 switch( pr->type ) {
04153 case AEL_APPCALL:
04154
04155 break;
04156
04157 case AEL_CONTROL1:
04158
04159 strcpy(app,"Goto");
04160 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
04161 snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
04162 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
04163 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
04164 } else
04165 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
04166 break;
04167
04168 case AEL_FOR_CONTROL:
04169 strcpy(app,"GotoIf");
04170 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04171 break;
04172
04173 case AEL_IF_CONTROL:
04174 strcpy(app,"GotoIf");
04175 if (pr->origin->u3.else_statements )
04176 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
04177 else
04178 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04179 break;
04180
04181 case AEL_RAND_CONTROL:
04182 strcpy(app,"Random");
04183 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
04184 break;
04185
04186 case AEL_IFTIME_CONTROL:
04187 strcpy(app,"GotoIfTime");
04188 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
04189 break;
04190
04191 case AEL_RETURN:
04192 strcpy(app,"Goto");
04193 snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
04194 break;
04195
04196 default:
04197 break;
04198 }
04199 if (last && last->type == AEL_LABEL ) {
04200 label = last->origin->u1.str;
04201 }
04202 else
04203 label = 0;
04204
04205 if (ast_add_extension2(exten->context, 0 , realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
04206 app, strdup(appargs), ast_free, registrar)) {
04207 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
04208 exten->name);
04209 }
04210 last = pr;
04211 }
04212 exten = exten->next_exten;
04213 } while ( exten );
04214 }
04215
04216 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
04217 {
04218
04219 struct ael_extension *lptr;
04220 if( !*list ) {
04221 *list = newmem;
04222 return;
04223 }
04224 lptr = *list;
04225
04226 while( lptr->next_exten ) {
04227 lptr = lptr->next_exten;
04228 }
04229
04230 lptr->next_exten = newmem;
04231 }
04232
04233 static pval *get_extension_or_contxt(pval *p)
04234 {
04235 while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04236
04237 p = p->dad;
04238 }
04239
04240 return p;
04241 }
04242
04243 static pval *get_contxt(pval *p)
04244 {
04245 while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04246
04247 p = p->dad;
04248 }
04249
04250 return p;
04251 }
04252
04253 static void fix_gotos_in_extensions(struct ael_extension *exten)
04254 {
04255 struct ael_extension *e;
04256 for(e=exten;e;e=e->next_exten) {
04257
04258 struct ael_priority *p;
04259 for(p=e->plist;p;p=p->next) {
04260
04261 if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
04262
04263
04264
04265 pval *target = p->origin->u2.goto_target;
04266 struct ael_extension *z = target->u3.compiled_label;
04267 pval *pv2 = p->origin;
04268 char buf1[500];
04269 char *apparg_save = p->appargs;
04270
04271 p->appargs = 0;
04272 if (!pv2->u1.list->next) {
04273 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
04274 p->appargs = strdup(buf1);
04275
04276 } else if (pv2->u1.list->next && !pv2->u1.list->next->next) {
04277 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
04278 p->appargs = strdup(buf1);
04279 } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
04280 snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str,
04281 z->name,
04282 pv2->u1.list->next->next->u1.str);
04283 p->appargs = strdup(buf1);
04284 }
04285 else
04286 printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
04287
04288 if( apparg_save ) {
04289 free(apparg_save);
04290 }
04291 }
04292 }
04293 }
04294 }
04295
04296
04297 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
04298 {
04299 pval *p,*p2;
04300 struct ast_context *context;
04301 char buf[2000];
04302 struct ael_extension *exten;
04303 struct ael_extension *exten_list = 0;
04304
04305 for (p=root; p; p=p->next ) {
04306
04307 switch (p->type) {
04308 case PV_GLOBALS:
04309
04310 for (p2=p->u1.list; p2; p2=p2->next) {
04311 char buf2[2000];
04312 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
04313 pbx_builtin_setvar(NULL, buf2);
04314 }
04315 break;
04316 default:
04317 break;
04318 }
04319 }
04320
04321 for (p=root; p; p=p->next ) {
04322 pval *lp;
04323 int argc;
04324
04325 switch (p->type) {
04326 case PV_MACRO:
04327 strcpy(buf,"macro-");
04328 strcat(buf,p->u1.str);
04329 context = ast_context_create(local_contexts, buf, registrar);
04330
04331 exten = new_exten();
04332 exten->context = context;
04333 exten->name = strdup("s");
04334 argc = 1;
04335 for (lp=p->u2.arglist; lp; lp=lp->next) {
04336
04337 struct ael_priority *np2 = new_prio();
04338 np2->type = AEL_APPCALL;
04339 np2->app = strdup("Set");
04340 snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++);
04341 remove_spaces_before_equals(buf);
04342 np2->appargs = strdup(buf);
04343 linkprio(exten, np2, NULL);
04344 }
04345
04346 for (p2=p->u3.macro_statements; p2; p2=p2->next) {
04347 pval *p3;
04348
04349 switch (p2->type) {
04350 case PV_INCLUDES:
04351 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04352 if ( p3->u2.arglist ) {
04353 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s",
04354 p3->u1.str,
04355 p3->u2.arglist->u1.str,
04356 p3->u2.arglist->next->u1.str,
04357 p3->u2.arglist->next->next->u1.str,
04358 p3->u2.arglist->next->next->next->u1.str);
04359 ast_context_add_include2(context, buf, registrar);
04360 } else
04361 ast_context_add_include2(context, p3->u1.str, registrar);
04362 }
04363 break;
04364 default:
04365 break;
04366 }
04367 }
04368
04369 gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
04370 if (exten->return_needed) {
04371 struct ael_priority *np2 = new_prio();
04372 np2->type = AEL_APPCALL;
04373 np2->app = strdup("NoOp");
04374 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
04375 np2->appargs = strdup(buf);
04376 linkprio(exten, np2, NULL);
04377 exten-> return_target = np2;
04378 }
04379
04380 set_priorities(exten);
04381 attach_exten(&exten_list, exten);
04382 break;
04383
04384 case PV_GLOBALS:
04385
04386 break;
04387
04388 case PV_CONTEXT:
04389 context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
04390
04391
04392 for (p2=p->u2.statements; p2; p2=p2->next) {
04393 pval *p3;
04394 char *s3;
04395
04396 switch (p2->type) {
04397 case PV_EXTENSION:
04398 exten = new_exten();
04399 exten->name = strdup(p2->u1.str);
04400 exten->context = context;
04401
04402 if( (s3=strchr(exten->name, '/') ) != 0 )
04403 {
04404 *s3 = 0;
04405 exten->cidmatch = s3+1;
04406 }
04407
04408 if ( p2->u3.hints )
04409 exten->hints = strdup(p2->u3.hints);
04410 exten->regexten = p2->u4.regexten;
04411 gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
04412 if (exten->return_needed) {
04413 struct ael_priority *np2 = new_prio();
04414 np2->type = AEL_APPCALL;
04415 np2->app = strdup("NoOp");
04416 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04417 np2->appargs = strdup(buf);
04418 linkprio(exten, np2, NULL);
04419 exten-> return_target = np2;
04420 }
04421
04422 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04423 struct ael_priority *np2 = new_prio();
04424 np2->type = AEL_APPCALL;
04425 np2->app = strdup("NoOp");
04426 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04427 np2->appargs = strdup(buf);
04428 linkprio(exten, np2, NULL);
04429 }
04430
04431 set_priorities(exten);
04432 attach_exten(&exten_list, exten);
04433 break;
04434
04435 case PV_IGNOREPAT:
04436 ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04437 break;
04438
04439 case PV_INCLUDES:
04440 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04441 if ( p3->u2.arglist ) {
04442 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s",
04443 p3->u1.str,
04444 p3->u2.arglist->u1.str,
04445 p3->u2.arglist->next->u1.str,
04446 p3->u2.arglist->next->next->u1.str,
04447 p3->u2.arglist->next->next->next->u1.str);
04448 ast_context_add_include2(context, buf, registrar);
04449 } else
04450 ast_context_add_include2(context, p3->u1.str, registrar);
04451 }
04452 break;
04453
04454 case PV_SWITCHES:
04455 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04456 char *c = strchr(p3->u1.str, '/');
04457 if (c) {
04458 *c = '\0';
04459 c++;
04460 } else
04461 c = "";
04462
04463 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04464 }
04465 break;
04466
04467 case PV_ESWITCHES:
04468 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04469 char *c = strchr(p3->u1.str, '/');
04470 if (c) {
04471 *c = '\0';
04472 c++;
04473 } else
04474 c = "";
04475
04476 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04477 }
04478 break;
04479 default:
04480 break;
04481 }
04482 }
04483
04484 break;
04485
04486 default:
04487
04488 break;
04489
04490 }
04491 }
04492
04493
04494
04495 fix_gotos_in_extensions(exten_list);
04496 add_extensions(exten_list);
04497 destroy_extensions(exten_list);
04498
04499 }
04500
04501
04502 static int aeldebug = 0;
04503
04504
04505
04506
04507
04508 static int pbx_load_module(void)
04509 {
04510 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04511 char *rfilename;
04512 struct ast_context *local_contexts=NULL, *con;
04513 struct pval *parse_tree;
04514
04515 ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04516 if (config[0] == '/')
04517 rfilename = (char *)config;
04518 else {
04519 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04520 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04521 }
04522 ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04523
04524 if (access(rfilename,R_OK) != 0) {
04525 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04526 return AST_MODULE_LOAD_DECLINE;
04527 }
04528
04529 parse_tree = ael2_parse(rfilename, &errs);
04530 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04531 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04532 if (errs == 0 && sem_err == 0) {
04533 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04534 ast_compile_ael2(&local_contexts, parse_tree);
04535 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04536
04537 ast_merge_contexts_and_delete(&local_contexts, registrar);
04538 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04539 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04540 ast_context_verify_includes(con);
04541 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04542 } else {
04543 ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
04544 destroy_pval(parse_tree);
04545 return AST_MODULE_LOAD_DECLINE;
04546 }
04547 destroy_pval(parse_tree);
04548
04549 return AST_MODULE_LOAD_SUCCESS;
04550 }
04551
04552
04553 static int ael2_debug_read(int fd, int argc, char *argv[])
04554 {
04555 aeldebug |= DEBUG_READ;
04556 return 0;
04557 }
04558
04559 static int ael2_debug_tokens(int fd, int argc, char *argv[])
04560 {
04561 aeldebug |= DEBUG_TOKENS;
04562 return 0;
04563 }
04564
04565 static int ael2_debug_macros(int fd, int argc, char *argv[])
04566 {
04567 aeldebug |= DEBUG_MACROS;
04568 return 0;
04569 }
04570
04571 static int ael2_debug_contexts(int fd, int argc, char *argv[])
04572 {
04573 aeldebug |= DEBUG_CONTEXTS;
04574 return 0;
04575 }
04576
04577 static int ael2_no_debug(int fd, int argc, char *argv[])
04578 {
04579 aeldebug = 0;
04580 return 0;
04581 }
04582
04583 static int ael2_reload(int fd, int argc, char *argv[])
04584 {
04585 return (pbx_load_module());
04586 }
04587
04588 static struct ast_cli_entry cli_ael_no_debug = {
04589 { "ael", "no", "debug", NULL },
04590 ael2_no_debug, NULL,
04591 NULL };
04592
04593 static struct ast_cli_entry cli_ael[] = {
04594 { { "ael", "reload", NULL },
04595 ael2_reload, "Reload AEL configuration" },
04596
04597 { { "ael", "debug", "read", NULL },
04598 ael2_debug_read, "Enable AEL read debug (does nothing)" },
04599
04600 { { "ael", "debug", "tokens", NULL },
04601 ael2_debug_tokens, "Enable AEL tokens debug (does nothing)" },
04602
04603 { { "ael", "debug", "macros", NULL },
04604 ael2_debug_macros, "Enable AEL macros debug (does nothing)" },
04605
04606 { { "ael", "debug", "contexts", NULL },
04607 ael2_debug_contexts, "Enable AEL contexts debug (does nothing)" },
04608
04609 { { "ael", "nodebug", NULL },
04610 ael2_no_debug, "Disable AEL debug messages",
04611 NULL, NULL, &cli_ael_no_debug },
04612 };
04613
04614 static int unload_module(void)
04615 {
04616 ast_context_destroy(NULL, registrar);
04617 ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04618 return 0;
04619 }
04620
04621 static int load_module(void)
04622 {
04623 ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04624 return (pbx_load_module());
04625 }
04626
04627 static int reload(void)
04628 {
04629 return pbx_load_module();
04630 }
04631
04632 #ifdef STANDALONE_AEL
04633 #define AST_MODULE "ael"
04634 int ael_external_load_module(void);
04635 int ael_external_load_module(void)
04636 {
04637 pbx_load_module();
04638 return 1;
04639 }
04640 #endif
04641
04642 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
04643 .load = load_module,
04644 .unload = unload_module,
04645 .reload = reload,
04646 );
04647
04648
04649
04650
04651
04652
04653 void destroy_pval_item(pval *item)
04654 {
04655 if (item == NULL) {
04656 ast_log(LOG_WARNING, "null item\n");
04657 return;
04658 }
04659
04660 if (item->filename)
04661 free(item->filename);
04662
04663 switch (item->type) {
04664 case PV_WORD:
04665
04666 if (item->u1.str )
04667 free(item->u1.str);
04668 if ( item->u2.arglist )
04669 destroy_pval(item->u2.arglist);
04670 break;
04671
04672 case PV_MACRO:
04673
04674
04675
04676
04677
04678
04679
04680 destroy_pval(item->u2.arglist);
04681 if (item->u1.str )
04682 free(item->u1.str);
04683 destroy_pval(item->u3.macro_statements);
04684 break;
04685
04686 case PV_CONTEXT:
04687
04688
04689
04690
04691 if (item->u1.str)
04692 free(item->u1.str);
04693 destroy_pval(item->u2.statements);
04694 break;
04695
04696 case PV_MACRO_CALL:
04697
04698
04699
04700
04701
04702 if (item->u1.str)
04703 free(item->u1.str);
04704 destroy_pval(item->u2.arglist);
04705 break;
04706
04707 case PV_APPLICATION_CALL:
04708
04709
04710
04711
04712
04713 if (item->u1.str)
04714 free(item->u1.str);
04715 destroy_pval(item->u2.arglist);
04716 break;
04717
04718 case PV_CASE:
04719
04720
04721
04722 if (item->u1.str)
04723 free(item->u1.str);
04724 destroy_pval(item->u2.statements);
04725 break;
04726
04727 case PV_PATTERN:
04728
04729
04730
04731 if (item->u1.str)
04732 free(item->u1.str);
04733 destroy_pval(item->u2.statements);
04734 break;
04735
04736 case PV_DEFAULT:
04737
04738
04739
04740 destroy_pval(item->u2.statements);
04741 break;
04742
04743 case PV_CATCH:
04744
04745
04746
04747 if (item->u1.str)
04748 free(item->u1.str);
04749 destroy_pval(item->u2.statements);
04750 break;
04751
04752 case PV_SWITCHES:
04753
04754
04755 destroy_pval(item->u1.list);
04756 break;
04757
04758 case PV_ESWITCHES:
04759
04760
04761 destroy_pval(item->u1.list);
04762 break;
04763
04764 case PV_INCLUDES:
04765
04766
04767
04768 destroy_pval(item->u1.list);
04769 break;
04770
04771 case PV_STATEMENTBLOCK:
04772
04773
04774 destroy_pval(item->u1.list);
04775 break;
04776
04777 case PV_VARDEC:
04778
04779
04780
04781 if (item->u1.str)
04782 free(item->u1.str);
04783 if (item->u2.val)
04784 free(item->u2.val);
04785 break;
04786
04787 case PV_GOTO:
04788
04789
04790
04791
04792 destroy_pval(item->u1.list);
04793 break;
04794
04795 case PV_LABEL:
04796
04797
04798 if (item->u1.str)
04799 free(item->u1.str);
04800 break;
04801
04802 case PV_FOR:
04803
04804
04805
04806
04807
04808
04809 if (item->u1.for_init)
04810 free(item->u1.for_init);
04811 if (item->u2.for_test)
04812 free(item->u2.for_test);
04813 if (item->u3.for_inc)
04814 free(item->u3.for_inc);
04815 destroy_pval(item->u4.for_statements);
04816 break;
04817
04818 case PV_WHILE:
04819
04820
04821
04822
04823 if (item->u1.str)
04824 free(item->u1.str);
04825 destroy_pval(item->u2.statements);
04826 break;
04827
04828 case PV_BREAK:
04829
04830
04831 break;
04832
04833 case PV_RETURN:
04834
04835
04836 break;
04837
04838 case PV_CONTINUE:
04839
04840
04841 break;
04842
04843 case PV_IFTIME:
04844
04845
04846
04847
04848
04849
04850 destroy_pval(item->u1.list);
04851 destroy_pval(item->u2.statements);
04852 if (item->u3.else_statements) {
04853 destroy_pval(item->u3.else_statements);
04854 }
04855 break;
04856
04857 case PV_RANDOM:
04858
04859
04860
04861
04862
04863
04864 case PV_IF:
04865
04866
04867
04868
04869
04870
04871 if (item->u1.str)
04872 free(item->u1.str);
04873 destroy_pval(item->u2.statements);
04874 if (item->u3.else_statements) {
04875 destroy_pval(item->u3.else_statements);
04876 }
04877 break;
04878
04879 case PV_SWITCH:
04880
04881
04882
04883
04884
04885 if (item->u1.str)
04886 free(item->u1.str);
04887 destroy_pval(item->u2.statements);
04888 break;
04889
04890 case PV_EXTENSION:
04891
04892
04893
04894
04895
04896
04897 if (item->u1.str)
04898 free(item->u1.str);
04899 if (item->u3.hints)
04900 free(item->u3.hints);
04901 destroy_pval(item->u2.statements);
04902 break;
04903
04904 case PV_IGNOREPAT:
04905
04906
04907 if (item->u1.str)
04908 free(item->u1.str);
04909 break;
04910
04911 case PV_GLOBALS:
04912
04913
04914 destroy_pval(item->u1.statements);
04915 break;
04916 }
04917 free(item);
04918 }
04919
04920 void destroy_pval(pval *item)
04921 {
04922 pval *i,*nxt;
04923
04924 for (i=item; i; i=nxt) {
04925 nxt = i->next;
04926
04927 destroy_pval_item(i);
04928 }
04929 }
04930
04931 #ifdef AAL_ARGCHECK
04932 static char *ael_funclist[] =
04933 {
04934 "AGENT",
04935 "ARRAY",
04936 "BASE64_DECODE",
04937 "BASE64_ENCODE",
04938 "CALLERID",
04939 "CDR",
04940 "CHANNEL",
04941 "CHECKSIPDOMAIN",
04942 "CHECK_MD5",
04943 "CURL",
04944 "CUT",
04945 "DB",
04946 "DB_EXISTS",
04947 "DUNDILOOKUP",
04948 "ENUMLOOKUP",
04949 "ENV",
04950 "EVAL",
04951 "EXISTS",
04952 "FIELDQTY",
04953 "FILTER",
04954 "GROUP",
04955 "GROUP_COUNT",
04956 "GROUP_LIST",
04957 "GROUP_MATCH_COUNT",
04958 "IAXPEER",
04959 "IF",
04960 "IFTIME",
04961 "ISNULL",
04962 "KEYPADHASH",
04963 "LANGUAGE",
04964 "LEN",
04965 "MATH",
04966 "MD5",
04967 "MUSICCLASS",
04968 "QUEUEAGENTCOUNT",
04969 "QUEUE_MEMBER_COUNT",
04970 "QUEUE_MEMBER_LIST",
04971 "QUOTE",
04972 "RAND",
04973 "REGEX",
04974 "SET",
04975 "SHA1",
04976 "SIPCHANINFO",
04977 "SIPPEER",
04978 "SIP_HEADER",
04979 "SORT",
04980 "STAT",
04981 "STRFTIME",
04982 "STRPTIME",
04983 "TIMEOUT",
04984 "TXTCIDNAME",
04985 "URIDECODE",
04986 "URIENCODE",
04987 "VMCOUNT"
04988 };
04989
04990
04991 int ael_is_funcname(char *name)
04992 {
04993 int s,t;
04994 t = sizeof(ael_funclist)/sizeof(char*);
04995 s = 0;
04996 while ((s < t) && strcasecmp(name, ael_funclist[s]))
04997 s++;
04998 if ( s < t )
04999 return 1;
05000 else
05001 return 0;
05002 }
05003 #endif