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: 119929 $")
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 if (lev>100) {
01305 ast_log(LOG_ERROR,"find_pval_goto in infinite loop!\n\n");
01306 return;
01307 }
01308
01309 switch ( item->type ) {
01310 case PV_MACRO:
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320 find_pval_gotos(item->u3.macro_statements,lev+1);
01321
01322 break;
01323
01324 case PV_CONTEXT:
01325
01326
01327
01328
01329 break;
01330
01331 case PV_CASE:
01332
01333
01334
01335 find_pval_gotos(item->u2.statements,lev+1);
01336 break;
01337
01338 case PV_PATTERN:
01339
01340
01341
01342 find_pval_gotos(item->u2.statements,lev+1);
01343 break;
01344
01345 case PV_DEFAULT:
01346
01347
01348
01349 find_pval_gotos(item->u2.statements,lev+1);
01350 break;
01351
01352 case PV_CATCH:
01353
01354
01355
01356 find_pval_gotos(item->u2.statements,lev+1);
01357 break;
01358
01359 case PV_STATEMENTBLOCK:
01360
01361
01362 find_pval_gotos(item->u1.list,lev+1);
01363 break;
01364
01365 case PV_GOTO:
01366
01367
01368
01369 check_goto(item);
01370 break;
01371
01372 case PV_INCLUDES:
01373
01374
01375 for (p4=item->u1.list; p4; p4=p4->next) {
01376
01377
01378 char *incl_context = p4->u1.str;
01379
01380 struct pval *that_context = find_context(incl_context);
01381 if (that_context) {
01382 find_pval_gotos(that_context,lev+1);
01383 }
01384 }
01385 break;
01386
01387 case PV_FOR:
01388
01389
01390
01391
01392
01393
01394 find_pval_gotos(item->u4.for_statements,lev+1);
01395 break;
01396
01397 case PV_WHILE:
01398
01399
01400
01401
01402 find_pval_gotos(item->u2.statements,lev+1);
01403 break;
01404
01405 case PV_RANDOM:
01406
01407
01408
01409
01410
01411
01412
01413 case PV_IFTIME:
01414
01415
01416
01417
01418
01419
01420 case PV_IF:
01421
01422
01423
01424
01425
01426
01427 find_pval_gotos(item->u2.statements,lev+1);
01428
01429 if (item->u3.else_statements) {
01430 find_pval_gotos(item->u3.else_statements,lev+1);
01431 }
01432 break;
01433
01434 case PV_SWITCH:
01435
01436
01437
01438
01439
01440 find_pval_gotos(item->u3.else_statements,lev+1);
01441 break;
01442
01443 case PV_EXTENSION:
01444
01445
01446
01447
01448
01449
01450
01451 find_pval_gotos(item->u2.statements,lev+1);
01452 break;
01453
01454 default:
01455 break;
01456 }
01457 }
01458
01459 static void find_pval_gotos(pval *item,int lev)
01460 {
01461 pval *i;
01462
01463 for (i=item; i; i=i->next) {
01464
01465 find_pval_goto_item(i, lev);
01466 }
01467 }
01468
01469
01470
01471
01472 static struct pval *match_pval_item(pval *item)
01473 {
01474 pval *x;
01475
01476 switch ( item->type ) {
01477 case PV_MACRO:
01478
01479
01480
01481
01482
01483
01484
01485
01486 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01487
01488
01489
01490 if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01491
01492 return item;
01493 }
01494
01495
01496 if (!return_on_context_match) {
01497
01498 if ((x=match_pval(item->u3.macro_statements))) {
01499
01500 return x;
01501 }
01502 }
01503 } else {
01504
01505 }
01506
01507 break;
01508
01509 case PV_CONTEXT:
01510
01511
01512
01513
01514
01515 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01516 if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01517
01518
01519 return item;
01520 }
01521
01522 if (!return_on_context_match ) {
01523
01524 if ((x=match_pval(item->u2.statements))) {
01525
01526 return x;
01527 }
01528 }
01529 } else {
01530
01531 }
01532 break;
01533
01534 case PV_CASE:
01535
01536
01537
01538
01539 if ((x=match_pval(item->u2.statements))) {
01540
01541 return x;
01542 }
01543 break;
01544
01545 case PV_PATTERN:
01546
01547
01548
01549
01550 if ((x=match_pval(item->u2.statements))) {
01551
01552 return x;
01553 }
01554 break;
01555
01556 case PV_DEFAULT:
01557
01558
01559
01560
01561 if ((x=match_pval(item->u2.statements))) {
01562
01563 return x;
01564 }
01565 break;
01566
01567 case PV_CATCH:
01568
01569
01570
01571
01572 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01573
01574 if (strcmp(match_label,"1") == 0) {
01575 if (item->u2.statements) {
01576 struct pval *p5 = item->u2.statements;
01577 while (p5 && p5->type == PV_LABEL)
01578 p5 = p5->next;
01579 if (p5)
01580 return p5;
01581 else
01582 return 0;
01583 }
01584 else
01585 return 0;
01586 }
01587
01588 if ((x=match_pval(item->u2.statements))) {
01589
01590 return x;
01591 }
01592 } else {
01593
01594 }
01595 break;
01596
01597 case PV_STATEMENTBLOCK:
01598
01599
01600
01601 if ((x=match_pval(item->u1.list))) {
01602
01603 return x;
01604 }
01605 break;
01606
01607 case PV_LABEL:
01608
01609
01610
01611
01612
01613 if (count_labels) {
01614 if (!strcmp(match_label, item->u1.str)) {
01615 label_count++;
01616 last_matched_label = item;
01617 }
01618
01619 } else {
01620 if (!strcmp(match_label, item->u1.str)) {
01621
01622 return item;
01623 }
01624 }
01625 break;
01626
01627 case PV_FOR:
01628
01629
01630
01631
01632
01633
01634
01635 if ((x=match_pval(item->u4.for_statements))) {
01636
01637 return x;
01638 }
01639 break;
01640
01641 case PV_WHILE:
01642
01643
01644
01645
01646
01647 if ((x=match_pval(item->u2.statements))) {
01648
01649 return x;
01650 }
01651 break;
01652
01653 case PV_RANDOM:
01654
01655
01656
01657
01658
01659
01660
01661 case PV_IFTIME:
01662
01663
01664
01665
01666
01667
01668 case PV_IF:
01669
01670
01671
01672
01673
01674
01675
01676 if ((x=match_pval(item->u2.statements))) {
01677 return x;
01678 }
01679 if (item->u3.else_statements) {
01680 if ((x=match_pval(item->u3.else_statements))) {
01681
01682 return x;
01683 }
01684 }
01685 break;
01686
01687 case PV_SWITCH:
01688
01689
01690
01691
01692
01693
01694 if ((x=match_pval(item->u2.statements))) {
01695
01696 return x;
01697 }
01698 break;
01699
01700 case PV_EXTENSION:
01701
01702
01703
01704
01705
01706
01707
01708 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01709
01710 if (strcmp(match_label,"1") == 0) {
01711 if (item->u2.statements) {
01712 struct pval *p5 = item->u2.statements;
01713 while (p5 && p5->type == PV_LABEL)
01714 p5 = p5->next;
01715 if (p5)
01716 return p5;
01717 else
01718 return 0;
01719 }
01720 else
01721 return 0;
01722 }
01723
01724 if ((x=match_pval(item->u2.statements))) {
01725
01726 return x;
01727 }
01728 } else {
01729
01730 }
01731 break;
01732 default:
01733
01734 break;
01735 }
01736 return 0;
01737 }
01738
01739 struct pval *match_pval(pval *item)
01740 {
01741 pval *i;
01742
01743 for (i=item; i; i=i->next) {
01744 pval *x;
01745
01746
01747 if ((x = match_pval_item(i))) {
01748
01749 return x;
01750 }
01751 }
01752 return 0;
01753 }
01754
01755 #if 0
01756 int count_labels_in_current_context(char *label)
01757 {
01758 label_count = 0;
01759 count_labels = 1;
01760 return_on_context_match = 0;
01761 match_pval(current_context->u2.statements);
01762
01763 return label_count;
01764 }
01765 #endif
01766
01767 struct pval *find_first_label_in_current_context(char *label, pval *curr_cont)
01768 {
01769
01770 struct pval *ret;
01771 struct pval *p3;
01772 struct pval *startpt = ((curr_cont->type==PV_MACRO)?curr_cont->u3.macro_statements: curr_cont->u2.statements);
01773
01774 count_labels = 0;
01775 return_on_context_match = 0;
01776 match_context = "*";
01777 match_exten = "*";
01778 match_label = label;
01779
01780 ret = match_pval(curr_cont);
01781 if (ret)
01782 return ret;
01783
01784
01785
01786 for (p3=startpt; p3; p3=p3->next) {
01787 if (p3->type == PV_INCLUDES) {
01788 struct pval *p4;
01789 for (p4=p3->u1.list; p4; p4=p4->next) {
01790
01791
01792 char *incl_context = p4->u1.str;
01793
01794 struct pval *that_context = find_context(incl_context);
01795 if (that_context) {
01796 struct pval *x3;
01797 x3 = find_first_label_in_current_context(label, that_context);
01798 if (x3) {
01799 return x3;
01800 }
01801 }
01802 }
01803 }
01804 }
01805 return 0;
01806 }
01807
01808 struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont)
01809 {
01810
01811 struct pval *ret;
01812 struct pval *p3;
01813 struct pval *startpt;
01814
01815 count_labels = 0;
01816 return_on_context_match = 0;
01817 match_context = "*";
01818 match_exten = exten;
01819 match_label = label;
01820 if (curr_cont->type == PV_MACRO)
01821 startpt = curr_cont->u3.macro_statements;
01822 else
01823 startpt = curr_cont->u2.statements;
01824
01825 ret = match_pval(startpt);
01826 if (ret)
01827 return ret;
01828
01829
01830
01831 for (p3=startpt; p3; p3=p3->next) {
01832 if (p3->type == PV_INCLUDES) {
01833 struct pval *p4;
01834 for (p4=p3->u1.list; p4; p4=p4->next) {
01835
01836
01837 char *incl_context = p4->u1.str;
01838
01839 struct pval *that_context = find_context(incl_context);
01840 if (that_context) {
01841 struct pval *x3;
01842 x3 = find_label_in_current_context(exten, label, that_context);
01843 if (x3) {
01844 return x3;
01845 }
01846 }
01847 }
01848 }
01849 }
01850 return 0;
01851 }
01852
01853 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext)
01854 {
01855
01856 count_labels = 0;
01857 return_on_context_match = 0;
01858 match_context = "*";
01859 match_exten = "*";
01860 match_label = label;
01861 return match_pval(curr_ext);
01862 }
01863
01864 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label)
01865 {
01866
01867 count_labels = 0;
01868 return_on_context_match = 0;
01869
01870 match_context = context;
01871 match_exten = exten;
01872 match_label = label;
01873
01874 return match_pval(current_db);
01875 }
01876
01877
01878 struct pval *find_macro(char *name)
01879 {
01880 return_on_context_match = 1;
01881 count_labels = 0;
01882 match_context = name;
01883 match_exten = "*";
01884 match_label = "*";
01885 return match_pval(current_db);
01886 }
01887
01888 struct pval *find_context(char *name)
01889 {
01890 return_on_context_match = 1;
01891 count_labels = 0;
01892 match_context = name;
01893 match_exten = "*";
01894 match_label = "*";
01895 return match_pval(current_db);
01896 }
01897
01898 int is_float(char *arg )
01899 {
01900 char *s;
01901 for (s=arg; *s; s++) {
01902 if (*s != '.' && (*s < '0' || *s > '9'))
01903 return 0;
01904 }
01905 return 1;
01906 }
01907 int is_int(char *arg )
01908 {
01909 char *s;
01910 for (s=arg; *s; s++) {
01911 if (*s < '0' || *s > '9')
01912 return 0;
01913 }
01914 return 1;
01915 }
01916 int is_empty(char *arg)
01917 {
01918 if (!arg)
01919 return 1;
01920 if (*arg == 0)
01921 return 1;
01922 while (*arg) {
01923 if (*arg != ' ' && *arg != '\t')
01924 return 0;
01925 arg++;
01926 }
01927 return 1;
01928 }
01929
01930 #ifdef AAL_ARGCHECK
01931 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app)
01932 {
01933 struct argchoice *ac;
01934 char *opcop,*q,*p;
01935
01936 switch (should->dtype) {
01937 case ARGD_OPTIONSET:
01938 if ( strstr(is->u1.str,"${") )
01939 return 0;
01940
01941 opcop = ast_strdupa(is->u1.str);
01942
01943 for (q=opcop;*q;q++) {
01944 if ( *q == '(' ) {
01945 p = q+1;
01946 while (*p && *p != ')' )
01947 *p++ = '+';
01948 q = p+1;
01949 }
01950 }
01951
01952 for (ac=app->opts; ac; ac=ac->next) {
01953 if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0)
01954 return 0;
01955 }
01956 for (ac=app->opts; ac; ac=ac->next) {
01957 if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
01958 char *p = strchr(opcop,ac->name[0]);
01959
01960 if (p && *p == 'j') {
01961 ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n",
01962 is->filename, is->startline, is->endline, app->name);
01963 errs++;
01964 }
01965
01966 if (p) {
01967 *p = '+';
01968 if (ac->name[1] == '(') {
01969 if (*(p+1) != '(') {
01970 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",
01971 is->filename, is->startline, is->endline, ac->name[0], app->name);
01972 warns++;
01973 }
01974 }
01975 }
01976 }
01977 }
01978 for (q=opcop; *q; q++) {
01979 if ( *q != '+' && *q != '(' && *q != ')') {
01980 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",
01981 is->filename, is->startline, is->endline, *q, app->name);
01982 warns++;
01983 }
01984 }
01985 return 1;
01986 break;
01987 default:
01988 return 0;
01989 }
01990
01991 }
01992
01993 int option_matches( struct argdesc *should, pval *is, struct argapp *app)
01994 {
01995 struct argchoice *ac;
01996 char *opcop;
01997
01998 switch (should->dtype) {
01999 case ARGD_STRING:
02000 if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED)
02001 return 0;
02002 if (is->u1.str && strlen(is->u1.str) > 0)
02003 return 1;
02004 break;
02005
02006 case ARGD_INT:
02007 if (is_int(is->u1.str))
02008 return 1;
02009 else
02010 return 0;
02011 break;
02012
02013 case ARGD_FLOAT:
02014 if (is_float(is->u1.str))
02015 return 1;
02016 else
02017 return 0;
02018 break;
02019
02020 case ARGD_ENUM:
02021 if( !is->u1.str || strlen(is->u1.str) == 0 )
02022 return 1;
02023 for (ac=should->choices; ac; ac=ac->next) {
02024 if (strcmp(ac->name,is->u1.str) == 0)
02025 return 1;
02026 }
02027 return 0;
02028 break;
02029
02030 case ARGD_OPTIONSET:
02031 opcop = ast_strdupa(is->u1.str);
02032
02033 for (ac=app->opts; ac; ac=ac->next) {
02034 if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0)
02035 return 1;
02036 }
02037 for (ac=app->opts; ac; ac=ac->next) {
02038 if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
02039 char *p = strchr(opcop,ac->name[0]);
02040
02041 if (p) {
02042 *p = '+';
02043 if (ac->name[1] == '(') {
02044 if (*(p+1) == '(') {
02045 char *q = p+1;
02046 while (*q && *q != ')') {
02047 *q++ = '+';
02048 }
02049 *q = '+';
02050 }
02051 }
02052 }
02053 }
02054 }
02055 return 1;
02056 break;
02057 case ARGD_VARARG:
02058 return 1;
02059 break;
02060 }
02061 return 1;
02062 }
02063 #endif
02064
02065 int check_app_args(pval* appcall, pval *arglist, struct argapp *app)
02066 {
02067 #ifdef AAL_ARGCHECK
02068 struct argdesc *ad = app->args;
02069 pval *pa;
02070 int z;
02071
02072 for (pa = arglist; pa; pa=pa->next) {
02073 if (!ad) {
02074 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
02075 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
02076 warns++;
02077 return 1;
02078 } else {
02079
02080 do {
02081 if ( ad->dtype == ARGD_VARARG )
02082 break;
02083
02084 z= option_matches( ad, pa, app);
02085 if (!z) {
02086 if ( !arglist )
02087 arglist=appcall;
02088
02089 if (ad->type == ARGD_REQUIRED) {
02090 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02091 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02092 warns++;
02093 return 1;
02094 }
02095 } else if (z && ad->dtype == ARGD_OPTIONSET) {
02096 option_matches_j( ad, pa, app);
02097 }
02098 ad = ad->next;
02099 } while (ad && !z);
02100 }
02101 }
02102
02103 for ( ; ad; ad=ad->next) {
02104 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
02105 if ( !arglist )
02106 arglist=appcall;
02107 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02108 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02109 warns++;
02110 return 1;
02111 }
02112 }
02113 return 0;
02114 #else
02115 return 0;
02116 #endif
02117 }
02118
02119 void check_switch_expr(pval *item, struct argapp *apps)
02120 {
02121 #ifdef AAL_ARGCHECK
02122
02123 char *buff1, *p;
02124 struct argapp *a,*a2;
02125 struct appsetvar *v,*v2;
02126 struct argchoice *c;
02127 pval *t;
02128
02129 p = item->u1.str;
02130 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
02131 p++;
02132
02133 buff1 = ast_strdupa(p);
02134
02135 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
02136 buff1[strlen(buff1)-1] = 0;
02137
02138 v = 0;
02139 for (a=apps; a; a=a->next) {
02140 for (v=a->setvars;v;v=v->next) {
02141 if (strcmp(v->name,buff1) == 0) {
02142 break;
02143 }
02144 }
02145 if ( v )
02146 break;
02147 }
02148 if (v && v->vals) {
02149
02150 int def= 0;
02151 int pat = 0;
02152 int f1 = 0;
02153
02154
02155 for (t=item->u2.statements; t; t=t->next) {
02156 if (t->type == PV_DEFAULT) {
02157 def =1;
02158 break;
02159 }
02160 if (t->type == PV_PATTERN) {
02161 pat++;
02162 }
02163 }
02164 if (def || pat)
02165 return;
02166 for (c=v->vals; c; c=c->next) {
02167 f1 = 0;
02168 for (t=item->u2.statements; t; t=t->next) {
02169 if (t->type == PV_CASE || t->type == PV_PATTERN) {
02170 if (!strcmp(t->u1.str,c->name)) {
02171 f1 = 1;
02172 break;
02173 }
02174 }
02175 }
02176 if (!f1) {
02177 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
02178 item->filename, item->startline, item->endline, item->u1.str, c->name);
02179 warns++;
02180 }
02181 }
02182
02183 f1 = 0;
02184 t = current_extension->u2.statements;
02185 if ( t && t->type == PV_STATEMENTBLOCK )
02186 t = t->u1.statements;
02187 for (; t && t != item; t=t->next) {
02188 if (t->type == PV_APPLICATION_CALL) {
02189
02190 for (a2=apps; a2; a2=a2->next) {
02191 if (strcasecmp(a2->name, t->u1.str)==0) {
02192 for (v2=a2->setvars; v2; v2=v2->next) {
02193 if (strcmp(v2->name, buff1) == 0) {
02194
02195 f1 = 1;
02196 break;
02197 }
02198 }
02199 }
02200 if (f1)
02201 break;
02202 }
02203 }
02204 if (f1)
02205 break;
02206 }
02207
02208
02209 if (!f1) {
02210 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",
02211 item->filename, item->startline, item->endline, item->u1.str);
02212 warns++;
02213 }
02214 }
02215 #else
02216 pval *t,*tl=0,*p2;
02217 int def= 0;
02218
02219
02220 for (t=item->u2.statements; t; t=t->next) {
02221 if (t->type == PV_DEFAULT) {
02222 def =1;
02223 break;
02224 }
02225 tl = t;
02226 }
02227 if (def)
02228 return;
02229
02230 p2 = tl->next = calloc(1, sizeof(struct pval));
02231
02232 p2->type = PV_DEFAULT;
02233 p2->startline = tl->startline;
02234 p2->endline = tl->endline;
02235 p2->startcol = tl->startcol;
02236 p2->endcol = tl->endcol;
02237 p2->filename = strdup(tl->filename);
02238 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
02239 p2->filename, p2->startline, p2->endline);
02240 warns++;
02241
02242 #endif
02243 }
02244
02245 static void check_context_names(void)
02246 {
02247 pval *i,*j;
02248 for (i=current_db; i; i=i->next) {
02249 if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02250 for (j=i->next; j; j=j->next) {
02251 if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02252 if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
02253 {
02254 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",
02255 i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline);
02256 errs++;
02257 }
02258 }
02259 }
02260 }
02261 }
02262 }
02263
02264 static void check_abstract_reference(pval *abstract_context)
02265 {
02266 pval *i,*j;
02267
02268
02269
02270
02271 for (i=current_db; i; i=i->next) {
02272 if (i->type == PV_CONTEXT) {
02273 for (j=i->u2. statements; j; j=j->next) {
02274 if ( j->type == PV_INCLUDES ) {
02275 struct pval *p4;
02276 for (p4=j->u1.list; p4; p4=p4->next) {
02277
02278
02279 if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
02280 return;
02281 }
02282 }
02283 }
02284 }
02285 }
02286 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",
02287 abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
02288 warns++;
02289 }
02290
02291
02292 void check_pval_item(pval *item, struct argapp *apps, int in_globals)
02293 {
02294 pval *lp;
02295 #ifdef AAL_ARGCHECK
02296 struct argapp *app, *found;
02297 #endif
02298 struct pval *macro_def;
02299 struct pval *app_def;
02300
02301 char errmsg[4096];
02302 char *strp;
02303
02304 switch (item->type) {
02305 case PV_WORD:
02306
02307
02308 break;
02309
02310 case PV_MACRO:
02311
02312
02313
02314
02315
02316
02317
02318 in_abstract_context = 0;
02319 current_context = item;
02320 current_extension = 0;
02321 for (lp=item->u2.arglist; lp; lp=lp->next) {
02322
02323 }
02324 check_pval(item->u3.macro_statements, apps,in_globals);
02325 break;
02326
02327 case PV_CONTEXT:
02328
02329
02330
02331
02332 current_context = item;
02333 current_extension = 0;
02334 if ( item->u3.abstract ) {
02335 in_abstract_context = 1;
02336 check_abstract_reference(item);
02337 } else
02338 in_abstract_context = 0;
02339 check_pval(item->u2.statements, apps,in_globals);
02340 break;
02341
02342 case PV_MACRO_CALL:
02343
02344
02345
02346
02347
02348 macro_def = find_macro(item->u1.str);
02349 if (!macro_def) {
02350
02351 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s ! Hopefully it is present in extensions.conf! \n",
02352 item->filename, item->startline, item->endline, item->u1.str);
02353 warns++;
02354 } else if (macro_def->type != PV_MACRO) {
02355 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
02356 item->filename, item->startline, item->endline, item->u1.str);
02357 errs++;
02358 } else {
02359
02360 int hereargs = 0;
02361 int thereargs = 0;
02362
02363 for (lp=item->u2.arglist; lp; lp=lp->next) {
02364 hereargs++;
02365 }
02366 for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
02367 thereargs++;
02368 }
02369 if (hereargs != thereargs ) {
02370 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",
02371 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
02372 errs++;
02373 }
02374 }
02375 break;
02376
02377 case PV_APPLICATION_CALL:
02378
02379
02380
02381
02382
02383
02384 app_def = find_context(item->u1.str);
02385 if (app_def && app_def->type == PV_MACRO) {
02386 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
02387 item->filename, item->startline, item->endline, item->u1.str);
02388 errs++;
02389 }
02390 if (strcasecmp(item->u1.str,"GotoIf") == 0
02391 || strcasecmp(item->u1.str,"GotoIfTime") == 0
02392 || strcasecmp(item->u1.str,"while") == 0
02393 || strcasecmp(item->u1.str,"endwhile") == 0
02394 || strcasecmp(item->u1.str,"random") == 0
02395 || strcasecmp(item->u1.str,"execIf") == 0 ) {
02396 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",
02397 item->filename, item->startline, item->endline, item->u1.str);
02398 warns++;
02399 }
02400 #ifdef AAL_ARGCHECK
02401 found = 0;
02402 for (app=apps; app; app=app->next) {
02403 if (strcasecmp(app->name, item->u1.str) == 0) {
02404 found =app;
02405 break;
02406 }
02407 }
02408 if (!found) {
02409 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
02410 item->filename, item->startline, item->endline, item->u1.str);
02411 warns++;
02412 } else
02413 check_app_args(item, item->u2.arglist, app);
02414 #endif
02415 break;
02416
02417 case PV_CASE:
02418
02419
02420
02421
02422
02423 check_pval(item->u2.statements, apps,in_globals);
02424 break;
02425
02426 case PV_PATTERN:
02427
02428
02429
02430
02431
02432
02433 check_pval(item->u2.statements, apps,in_globals);
02434 break;
02435
02436 case PV_DEFAULT:
02437
02438
02439
02440
02441 check_pval(item->u2.statements, apps,in_globals);
02442 break;
02443
02444 case PV_CATCH:
02445
02446
02447
02448 check_pval(item->u2.statements, apps,in_globals);
02449 break;
02450
02451 case PV_SWITCHES:
02452
02453
02454 check_pval(item->u1.list, apps,in_globals);
02455 break;
02456
02457 case PV_ESWITCHES:
02458
02459
02460 check_pval(item->u1.list, apps,in_globals);
02461 break;
02462
02463 case PV_INCLUDES:
02464
02465
02466 check_pval(item->u1.list, apps,in_globals);
02467 check_includes(item);
02468 for (lp=item->u1.list; lp; lp=lp->next){
02469 char *incl_context = lp->u1.str;
02470 struct pval *that_context = find_context(incl_context);
02471
02472 if ( lp->u2.arglist ) {
02473 check_timerange(lp->u2.arglist);
02474 check_dow(lp->u2.arglist->next);
02475 check_day(lp->u2.arglist->next->next);
02476 check_month(lp->u2.arglist->next->next->next);
02477 }
02478
02479 if (that_context) {
02480 find_pval_gotos(that_context->u2.statements,0);
02481
02482 }
02483 }
02484 break;
02485
02486 case PV_STATEMENTBLOCK:
02487
02488
02489 check_pval(item->u1.list, apps,in_globals);
02490 break;
02491
02492 case PV_VARDEC:
02493
02494
02495
02496
02497 if( !in_globals ) {
02498 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);
02499 ast_expr_register_extra_error_info(errmsg);
02500 ast_expr(item->u2.val, expr_output, sizeof(expr_output));
02501 ast_expr_clear_extra_error_info();
02502 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
02503 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02504 item->filename, item->startline, item->endline, item->u2.val);
02505 warns++;
02506 }
02507 check_expr2_input(item,item->u2.val);
02508 }
02509 break;
02510
02511 case PV_GOTO:
02512
02513
02514
02515
02516 if ( in_abstract_context )
02517 break;
02518
02519 check_goto(item);
02520 break;
02521
02522 case PV_LABEL:
02523
02524
02525 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
02526 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
02527 item->filename, item->startline, item->endline, item->u1.str);
02528 warns++;
02529 }
02530
02531 check_label(item);
02532 break;
02533
02534 case PV_FOR:
02535
02536
02537
02538
02539
02540
02541 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);
02542 ast_expr_register_extra_error_info(errmsg);
02543
02544 strp = strchr(item->u1.for_init, '=');
02545 if (strp) {
02546 ast_expr(strp+1, expr_output, sizeof(expr_output));
02547 }
02548 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output));
02549 strp = strchr(item->u3.for_inc, '=');
02550 if (strp) {
02551 ast_expr(strp+1, expr_output, sizeof(expr_output));
02552 }
02553 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
02554 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02555 item->filename, item->startline, item->endline, item->u2.for_test);
02556 warns++;
02557 }
02558 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
02559 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02560 item->filename, item->startline, item->endline, item->u3.for_inc);
02561 warns++;
02562 }
02563 check_expr2_input(item,item->u2.for_test);
02564 check_expr2_input(item,item->u3.for_inc);
02565
02566 ast_expr_clear_extra_error_info();
02567 check_pval(item->u4.for_statements, apps,in_globals);
02568 break;
02569
02570 case PV_WHILE:
02571
02572
02573
02574
02575 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02576 ast_expr_register_extra_error_info(errmsg);
02577 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02578 ast_expr_clear_extra_error_info();
02579 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02580 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02581 item->filename, item->startline, item->endline, item->u1.str);
02582 warns++;
02583 }
02584 check_expr2_input(item,item->u1.str);
02585 check_pval(item->u2.statements, apps,in_globals);
02586 break;
02587
02588 case PV_BREAK:
02589
02590
02591 check_break(item);
02592 break;
02593
02594 case PV_RETURN:
02595
02596
02597 break;
02598
02599 case PV_CONTINUE:
02600
02601
02602 check_continue(item);
02603 break;
02604
02605 case PV_RANDOM:
02606
02607
02608
02609
02610
02611
02612 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02613 ast_expr_register_extra_error_info(errmsg);
02614 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02615 ast_expr_clear_extra_error_info();
02616 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02617 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
02618 item->filename, item->startline, item->endline, item->u1.str);
02619 warns++;
02620 }
02621 check_expr2_input(item,item->u1.str);
02622 check_pval(item->u2.statements, apps,in_globals);
02623 if (item->u3.else_statements) {
02624 check_pval(item->u3.else_statements, apps,in_globals);
02625 }
02626 break;
02627
02628 case PV_IFTIME:
02629
02630
02631
02632
02633
02634
02635 if ( item->u2.arglist ) {
02636 check_timerange(item->u1.list);
02637 check_dow(item->u1.list->next);
02638 check_day(item->u1.list->next->next);
02639 check_month(item->u1.list->next->next->next);
02640 }
02641
02642 check_pval(item->u2.statements, apps,in_globals);
02643 if (item->u3.else_statements) {
02644 check_pval(item->u3.else_statements, apps,in_globals);
02645 }
02646 break;
02647
02648 case PV_IF:
02649
02650
02651
02652
02653
02654
02655 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02656 ast_expr_register_extra_error_info(errmsg);
02657 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02658 ast_expr_clear_extra_error_info();
02659 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02660 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
02661 item->filename, item->startline, item->endline, item->u1.str);
02662 warns++;
02663 }
02664 check_expr2_input(item,item->u1.str);
02665 check_pval(item->u2.statements, apps,in_globals);
02666 if (item->u3.else_statements) {
02667 check_pval(item->u3.else_statements, apps,in_globals);
02668 }
02669 break;
02670
02671 case PV_SWITCH:
02672
02673
02674
02675
02676
02677
02678
02679 check_switch_expr(item, apps);
02680 check_pval(item->u2.statements, apps,in_globals);
02681 break;
02682
02683 case PV_EXTENSION:
02684
02685
02686
02687
02688
02689
02690 current_extension = item ;
02691
02692 check_pval(item->u2.statements, apps,in_globals);
02693 break;
02694
02695 case PV_IGNOREPAT:
02696
02697
02698 break;
02699
02700 case PV_GLOBALS:
02701
02702
02703 in_abstract_context = 0;
02704 check_pval(item->u1.statements, apps, 1);
02705 break;
02706 default:
02707 break;
02708 }
02709 }
02710
02711 void check_pval(pval *item, struct argapp *apps, int in_globals)
02712 {
02713 pval *i;
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726 for (i=item; i; i=i->next) {
02727 check_pval_item(i,apps,in_globals);
02728 }
02729 }
02730
02731 static void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
02732 {
02733
02734 #ifdef AAL_ARGCHECK
02735 int argapp_errs =0;
02736 char *rfilename, *rdirname, *xappsfilename;
02737 DIR *dir = NULL;
02738 struct dirent *de;
02739 #endif
02740 struct argapp *apps=0, *xapps=0, *app;
02741
02742 if (!item)
02743 return;
02744 #ifdef AAL_ARGCHECK
02745 rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR));
02746 sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
02747
02748 apps = argdesc_parse(rfilename, &argapp_errs);
02749
02750 if (argapp_errs == 0) {
02751 ast_log(LOG_NOTICE, "AEL load process: parsed default apps desc file '%s'.\n", rfilename);
02752 } else {
02753 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing apps file '%s'.\n", argapp_errs, rfilename);
02754 }
02755
02756
02757 rdirname = alloca(16 + strlen(ast_config_AST_VAR_DIR));
02758 sprintf(rdirname, "%s/applist.d", ast_config_AST_VAR_DIR);
02759 dir = opendir(rdirname);
02760 if (!dir) {
02761 ast_log(LOG_WARNING, "Unable to open ael2 extra apps dir. %s is not a valid directory\n", rdirname);
02762 } else {
02763
02764 argapp_errs = 0;
02765
02766 xappsfilename = alloca(AST_MAX_FILENAME_LEN + strlen(rdirname));
02767 while ((de = readdir(dir))) {
02768 xappsfilename[0] = 0;
02769 if ((strlen(de->d_name) > 4) && !strcasecmp(de->d_name + strlen(de->d_name) - 5, ".apps")) {
02770 sprintf(xappsfilename, "%s/%s", rdirname, de->d_name);
02771 xapps = argdesc_parse(xappsfilename, &argapp_errs);
02772
02773 if(xapps != NULL) {
02774 if (argapp_errs == 0) {
02775 ast_log(LOG_NOTICE, "AEL load process: parsed extra apps desc file '%s'.\n", xappsfilename);
02776 } else {
02777 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing extra apps file '%s'.\n", argapp_errs, xappsfilename);
02778 }
02779 app=xapps;
02780 while (app->next != NULL) {
02781 app=app->next;
02782 }
02783 app->next = apps;
02784 apps = xapps;
02785 } else {
02786 ast_log(LOG_WARNING, "AEL load process: no apps desc found into file '%s'.\n", xappsfilename);
02787 }
02788 }
02789 }
02790 }
02791 #endif
02792 current_db = item;
02793 errs = warns = notes = 0;
02794
02795 check_context_names();
02796 check_pval(item, apps, 0);
02797
02798 #ifdef AAL_ARGCHECK
02799 argdesc_destroy(apps);
02800 #endif
02801 current_db = 0;
02802
02803 *arg_errs = errs;
02804 *arg_warns = warns;
02805 *arg_notes = notes;
02806 }
02807
02808
02809
02810
02811
02812 static int control_statement_count = 0;
02813
02814 struct ael_priority *new_prio(void)
02815 {
02816 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02817 return x;
02818 }
02819
02820 struct ael_extension *new_exten(void)
02821 {
02822 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02823 return x;
02824 }
02825
02826 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
02827 {
02828 char *p1, *p2;
02829
02830 if (!exten->plist) {
02831 exten->plist = prio;
02832 exten->plist_last = prio;
02833 } else {
02834 exten->plist_last->next = prio;
02835 exten->plist_last = prio;
02836 }
02837 if( !prio->exten )
02838 prio->exten = exten;
02839
02840
02841
02842
02843
02844 if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
02845 while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
02846 p2 = malloc(strlen(prio->appargs)+5);
02847 *p1 = 0;
02848 strcpy(p2, prio->appargs);
02849 strcat(p2, "${~~EXTEN~~}");
02850 if (*(p1+8))
02851 strcat(p2, p1+8);
02852 free(prio->appargs);
02853 prio->appargs = p2;
02854 }
02855 while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
02856 p2 = malloc(strlen(prio->appargs)+5);
02857 *p1 = 0;
02858 strcpy(p2, prio->appargs);
02859 strcat(p2, "${~~EXTEN~~:");
02860 if (*(p1+8))
02861 strcat(p2, p1+8);
02862 free(prio->appargs);
02863 prio->appargs = p2;
02864 }
02865 }
02866 }
02867
02868 void destroy_extensions(struct ael_extension *exten)
02869 {
02870 struct ael_extension *ne, *nen;
02871 for (ne=exten; ne; ne=nen) {
02872 struct ael_priority *pe, *pen;
02873
02874 if (ne->name)
02875 free(ne->name);
02876
02877
02878
02879
02880
02881 if (ne->hints)
02882 free(ne->hints);
02883
02884 for (pe=ne->plist; pe; pe=pen) {
02885 pen = pe->next;
02886 if (pe->app)
02887 free(pe->app);
02888 pe->app = 0;
02889 if (pe->appargs)
02890 free(pe->appargs);
02891 pe->appargs = 0;
02892 pe->origin = 0;
02893 pe->goto_true = 0;
02894 pe->goto_false = 0;
02895 free(pe);
02896 }
02897 nen = ne->next_exten;
02898 ne->next_exten = 0;
02899 ne->plist =0;
02900 ne->plist_last = 0;
02901 ne->next_exten = 0;
02902 ne->loop_break = 0;
02903 ne->loop_continue = 0;
02904 free(ne);
02905 }
02906 }
02907
02908 static int label_inside_case(pval *label)
02909 {
02910 pval *p = label;
02911
02912 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
02913 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
02914 return 1;
02915 }
02916
02917 p = p->dad;
02918 }
02919 return 0;
02920 }
02921
02922 static void linkexten(struct ael_extension *exten, struct ael_extension *add)
02923 {
02924 add->next_exten = exten->next_exten;
02925 exten->next_exten = add;
02926 }
02927
02928 static void remove_spaces_before_equals(char *str)
02929 {
02930 char *p;
02931 while( str && *str && *str != '=' )
02932 {
02933 if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02934 {
02935 p = str;
02936 while( *p )
02937 {
02938 *p = *(p+1);
02939 p++;
02940 }
02941 }
02942 else
02943 str++;
02944 }
02945 }
02946
02947 static void gen_match_to_pattern(char *pattern, char *result)
02948 {
02949
02950 char *p=pattern, *t=result;
02951 while (*p) {
02952 if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02953 *t++ = '9';
02954 else if (*p == '[') {
02955 char *z = p+1;
02956 while (*z != ']')
02957 z++;
02958 if (*(z+1)== ']')
02959 z++;
02960 *t++=*(p+1);
02961 p = z;
02962 } else {
02963 *t++ = *p;
02964 }
02965 p++;
02966 }
02967 *t++ = 0;
02968 }
02969
02970 static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context )
02971 {
02972 pval *p,*p2,*p3;
02973 struct ael_priority *pr;
02974 struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
02975 struct ael_priority *while_test, *while_loop, *while_end;
02976 struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
02977 struct ael_priority *if_test, *if_end, *if_skip, *if_false;
02978 #ifdef OLD_RAND_ACTION
02979 struct ael_priority *rand_test, *rand_end, *rand_skip;
02980 #endif
02981 char buf1[2000];
02982 char buf2[2000];
02983 char *strp, *strp2;
02984 char new_label[2000];
02985 int default_exists;
02986 int local_control_statement_count;
02987 struct ael_priority *loop_break_save;
02988 struct ael_priority *loop_continue_save;
02989 struct ael_extension *switch_case,*switch_null;
02990
02991 for (p=statement; p; p=p->next) {
02992 switch (p->type) {
02993 case PV_VARDEC:
02994 pr = new_prio();
02995 pr->type = AEL_APPCALL;
02996 snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
02997 pr->app = strdup("Set");
02998 remove_spaces_before_equals(buf1);
02999 pr->appargs = strdup(buf1);
03000 pr->origin = p;
03001 linkprio(exten, pr, mother_exten);
03002 break;
03003
03004 case PV_GOTO:
03005 pr = new_prio();
03006 pr->type = AEL_APPCALL;
03007 p->u2.goto_target = get_goto_target(p);
03008 if( p->u2.goto_target ) {
03009 p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target);
03010 }
03011
03012 if (!p->u1.list->next) {
03013 pr->app = strdup("Goto");
03014 if (!mother_exten)
03015 pr->appargs = strdup(p->u1.list->u1.str);
03016 else {
03017 snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
03018 pr->appargs = strdup(buf1);
03019 }
03020
03021 } else if (p->u1.list->next && !p->u1.list->next->next) {
03022 snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
03023 pr->app = strdup("Goto");
03024 pr->appargs = strdup(buf1);
03025 } else if (p->u1.list->next && p->u1.list->next->next) {
03026 snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str,
03027 p->u1.list->next->u1.str,
03028 p->u1.list->next->next->u1.str);
03029 pr->app = strdup("Goto");
03030 pr->appargs = strdup(buf1);
03031 }
03032 pr->origin = p;
03033 linkprio(exten, pr, mother_exten);
03034 break;
03035
03036 case PV_LABEL:
03037 pr = new_prio();
03038 pr->type = AEL_LABEL;
03039 pr->origin = p;
03040 p->u3.compiled_label = exten;
03041 linkprio(exten, pr, mother_exten);
03042 break;
03043
03044 case PV_FOR:
03045 control_statement_count++;
03046 loop_break_save = exten->loop_break;
03047 loop_continue_save = exten->loop_continue;
03048 snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
03049 for_init = new_prio();
03050 for_inc = new_prio();
03051 for_test = new_prio();
03052 for_loop = new_prio();
03053 for_end = new_prio();
03054 for_init->type = AEL_APPCALL;
03055 for_inc->type = AEL_APPCALL;
03056 for_test->type = AEL_FOR_CONTROL;
03057 for_test->goto_false = for_end;
03058 for_loop->type = AEL_CONTROL1;
03059 for_end->type = AEL_APPCALL;
03060 for_init->app = strdup("Set");
03061
03062 strcpy(buf2,p->u1.for_init);
03063 remove_spaces_before_equals(buf2);
03064 strp = strchr(buf2, '=');
03065 if (strp) {
03066 strp2 = strchr(p->u1.for_init, '=');
03067 *(strp+1) = 0;
03068 strcat(buf2,"$[");
03069 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03070 strcat(buf2,"]");
03071 for_init->appargs = strdup(buf2);
03072
03073 } else {
03074 strp2 = p->u1.for_init;
03075 while (*strp2 && isspace(*strp2))
03076 strp2++;
03077 if (*strp2 == '&') {
03078 char *strp3 = strp2+1;
03079 while (*strp3 && isspace(*strp3))
03080 strp3++;
03081 strcpy(buf2, strp3);
03082 strp3 = strchr(buf2,'(');
03083 if (strp3) {
03084 *strp3 = '|';
03085 }
03086 while ((strp3=strchr(buf2,','))) {
03087 *strp3 = '|';
03088 }
03089 strp3 = strrchr(buf2, ')');
03090 if (strp3)
03091 *strp3 = 0;
03092
03093 for_init->appargs = strdup(buf2);
03094 if (for_init->app)
03095 free(for_init->app);
03096 for_init->app = strdup("Macro");
03097 } else {
03098 char *strp3;
03099 strcpy(buf2, strp2);
03100 strp3 = strchr(buf2,'(');
03101 if (strp3) {
03102 *strp3 = 0;
03103 if (for_init->app)
03104 free(for_init->app);
03105 for_init->app = strdup(buf2);
03106 for_init->appargs = strdup(strp3+1);
03107 strp3 = strrchr(for_init->appargs, ')');
03108 if (strp3)
03109 *strp3 = 0;
03110 }
03111 }
03112 }
03113
03114 strcpy(buf2,p->u3.for_inc);
03115 remove_spaces_before_equals(buf2);
03116 strp = strchr(buf2, '=');
03117 if (strp) {
03118 strp2 = strchr(p->u3.for_inc, '=');
03119 *(strp+1) = 0;
03120 strcat(buf2,"$[");
03121 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03122 strcat(buf2,"]");
03123 for_inc->appargs = strdup(buf2);
03124 for_inc->app = strdup("Set");
03125 } else {
03126 strp2 = p->u3.for_inc;
03127 while (*strp2 && isspace(*strp2))
03128 strp2++;
03129 if (*strp2 == '&') {
03130 char *strp3 = strp2+1;
03131 while (*strp3 && isspace(*strp3))
03132 strp3++;
03133 strcpy(buf2, strp3);
03134 strp3 = strchr(buf2,'(');
03135 if (strp3) {
03136 *strp3 = '|';
03137 }
03138 while ((strp3=strchr(buf2,','))) {
03139 *strp3 = '|';
03140 }
03141 strp3 = strrchr(buf2, ')');
03142 if (strp3)
03143 *strp3 = 0;
03144
03145 for_inc->appargs = strdup(buf2);
03146
03147 for_inc->app = strdup("Macro");
03148 } else {
03149 char *strp3;
03150 strcpy(buf2, strp2);
03151 strp3 = strchr(buf2,'(');
03152 if (strp3) {
03153 *strp3 = 0;
03154 for_inc->app = strdup(buf2);
03155 for_inc->appargs = strdup(strp3+1);
03156 strp3 = strrchr(for_inc->appargs, ')');
03157 if (strp3)
03158 *strp3 = 0;
03159 }
03160 }
03161 }
03162 snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03163 for_test->app = 0;
03164 for_test->appargs = strdup(buf1);
03165 for_loop->goto_true = for_test;
03166 snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03167 for_end->app = strdup("NoOp");
03168 for_end->appargs = strdup(buf1);
03169
03170 linkprio(exten, for_init, mother_exten);
03171 linkprio(exten, for_test, mother_exten);
03172
03173
03174 exten->loop_break = for_end;
03175 exten->loop_continue = for_inc;
03176
03177 gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context);
03178
03179 linkprio(exten, for_inc, mother_exten);
03180 linkprio(exten, for_loop, mother_exten);
03181 linkprio(exten, for_end, mother_exten);
03182
03183
03184 exten->loop_break = loop_break_save;
03185 exten->loop_continue = loop_continue_save;
03186 for_loop->origin = p;
03187 break;
03188
03189 case PV_WHILE:
03190 control_statement_count++;
03191 loop_break_save = exten->loop_break;
03192 loop_continue_save = exten->loop_continue;
03193 snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03194 while_test = new_prio();
03195 while_loop = new_prio();
03196 while_end = new_prio();
03197 while_test->type = AEL_FOR_CONTROL;
03198 while_test->goto_false = while_end;
03199 while_loop->type = AEL_CONTROL1;
03200 while_end->type = AEL_APPCALL;
03201 snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03202 while_test->app = 0;
03203 while_test->appargs = strdup(buf1);
03204 while_loop->goto_true = while_test;
03205 snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03206 while_end->app = strdup("NoOp");
03207 while_end->appargs = strdup(buf1);
03208
03209 linkprio(exten, while_test, mother_exten);
03210
03211
03212 exten->loop_break = while_end;
03213 exten->loop_continue = while_test;
03214
03215 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03216
03217 linkprio(exten, while_loop, mother_exten);
03218 linkprio(exten, while_end, mother_exten);
03219
03220
03221 exten->loop_break = loop_break_save;
03222 exten->loop_continue = loop_continue_save;
03223 while_loop->origin = p;
03224 break;
03225
03226 case PV_SWITCH:
03227 control_statement_count++;
03228 local_control_statement_count = control_statement_count;
03229 loop_break_save = exten->loop_break;
03230 loop_continue_save = exten->loop_continue;
03231 snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03232 if ((mother_exten && !mother_exten->has_switch)) {
03233 switch_set = new_prio();
03234 switch_set->type = AEL_APPCALL;
03235 switch_set->app = strdup("Set");
03236 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03237 linkprio(exten, switch_set, mother_exten);
03238 mother_exten->has_switch = 1;
03239 } else if ((exten && !exten->has_switch)) {
03240 switch_set = new_prio();
03241 switch_set->type = AEL_APPCALL;
03242 switch_set->app = strdup("Set");
03243 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03244 linkprio(exten, switch_set, exten);
03245 exten->has_switch = 1;
03246 }
03247 switch_test = new_prio();
03248 switch_end = new_prio();
03249 switch_test->type = AEL_APPCALL;
03250 switch_end->type = AEL_APPCALL;
03251 strncpy(buf2,p->u1.str,sizeof(buf2));
03252 buf2[sizeof(buf2)-1] = 0;
03253 substitute_commas(buf2);
03254 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, buf2);
03255 switch_test->app = strdup("Goto");
03256 switch_test->appargs = strdup(buf1);
03257 snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03258 switch_end->app = strdup("NoOp");
03259 switch_end->appargs = strdup(buf1);
03260 switch_end->origin = p;
03261 switch_end->exten = exten;
03262
03263 linkprio(exten, switch_test, mother_exten);
03264 linkprio(exten, switch_end, mother_exten);
03265
03266 exten->loop_break = switch_end;
03267 exten->loop_continue = 0;
03268 default_exists = 0;
03269
03270 for (p2=p->u2.statements; p2; p2=p2->next) {
03271
03272 if (p2->type == PV_CASE) {
03273
03274 switch_case = new_exten();
03275 switch_case->context = this_context;
03276 switch_case->is_switch = 1;
03277
03278 switch_case->loop_break = exten->loop_break;
03279 switch_case->loop_continue = exten->loop_continue;
03280
03281 linkexten(exten,switch_case);
03282 strncpy(buf2,p2->u1.str,sizeof(buf2));
03283 buf2[sizeof(buf2)-1] = 0;
03284 substitute_commas(buf2);
03285 snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, buf2);
03286 switch_case->name = strdup(buf1);
03287 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03288
03289 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03290
03291
03292 for (p3=p2->u2.statements; p3; p3=p3->next) {
03293 if (!p3->next)
03294 break;
03295 }
03296
03297 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
03298
03299 if (p2->next && p2->next->type == PV_CASE) {
03300 fall_thru = new_prio();
03301 fall_thru->type = AEL_APPCALL;
03302 fall_thru->app = strdup("Goto");
03303 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03304 buf2[sizeof(buf2)-1] = 0;
03305 substitute_commas(buf2);
03306 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03307 fall_thru->appargs = strdup(buf1);
03308 linkprio(switch_case, fall_thru, mother_exten);
03309 } else if (p2->next && p2->next->type == PV_PATTERN) {
03310 fall_thru = new_prio();
03311 fall_thru->type = AEL_APPCALL;
03312 fall_thru->app = strdup("Goto");
03313 gen_match_to_pattern(p2->next->u1.str, buf2);
03314 substitute_commas(buf2);
03315 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2);
03316 fall_thru->appargs = strdup(buf1);
03317 linkprio(switch_case, fall_thru, mother_exten);
03318 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03319 fall_thru = new_prio();
03320 fall_thru->type = AEL_APPCALL;
03321 fall_thru->app = strdup("Goto");
03322 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03323 fall_thru->appargs = strdup(buf1);
03324 linkprio(switch_case, fall_thru, mother_exten);
03325 } else if (!p2->next) {
03326 fall_thru = new_prio();
03327 fall_thru->type = AEL_CONTROL1;
03328 fall_thru->goto_true = switch_end;
03329 fall_thru->app = strdup("Goto");
03330 linkprio(switch_case, fall_thru, mother_exten);
03331 }
03332 }
03333 if (switch_case->return_needed) {
03334 char buf[2000];
03335 struct ael_priority *np2 = new_prio();
03336 np2->type = AEL_APPCALL;
03337 np2->app = strdup("NoOp");
03338 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03339 np2->appargs = strdup(buf);
03340 linkprio(switch_case, np2, mother_exten);
03341 switch_case-> return_target = np2;
03342 }
03343 } else if (p2->type == PV_PATTERN) {
03344
03345 switch_case = new_exten();
03346 switch_case->context = this_context;
03347 switch_case->is_switch = 1;
03348
03349 switch_case->loop_break = exten->loop_break;
03350 switch_case->loop_continue = exten->loop_continue;
03351
03352 linkexten(exten,switch_case);
03353 strncpy(buf2,p2->u1.str,sizeof(buf2));
03354 buf2[sizeof(buf2)-1] = 0;
03355 substitute_commas(buf2);
03356 snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, buf2);
03357 switch_case->name = strdup(buf1);
03358 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03359
03360 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03361
03362 for (p3=p2->u2.statements; p3; p3=p3->next) {
03363 if (!p3->next)
03364 break;
03365 }
03366
03367 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03368
03369 if (p2->next && p2->next->type == PV_CASE) {
03370 fall_thru = new_prio();
03371 fall_thru->type = AEL_APPCALL;
03372 fall_thru->app = strdup("Goto");
03373 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03374 buf2[sizeof(buf2)-1] = 0;
03375 substitute_commas(buf2);
03376 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03377 fall_thru->appargs = strdup(buf1);
03378 linkprio(switch_case, fall_thru, mother_exten);
03379 } else if (p2->next && p2->next->type == PV_PATTERN) {
03380 fall_thru = new_prio();
03381 fall_thru->type = AEL_APPCALL;
03382 fall_thru->app = strdup("Goto");
03383 gen_match_to_pattern(p2->next->u1.str, buf2);
03384 substitute_commas(buf2);
03385 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03386 fall_thru->appargs = strdup(buf1);
03387 linkprio(switch_case, fall_thru, mother_exten);
03388 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03389 fall_thru = new_prio();
03390 fall_thru->type = AEL_APPCALL;
03391 fall_thru->app = strdup("Goto");
03392 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03393 fall_thru->appargs = strdup(buf1);
03394 linkprio(switch_case, fall_thru, mother_exten);
03395 } else if (!p2->next) {
03396 fall_thru = new_prio();
03397 fall_thru->type = AEL_CONTROL1;
03398 fall_thru->goto_true = switch_end;
03399 fall_thru->app = strdup("Goto");
03400 linkprio(switch_case, fall_thru, mother_exten);
03401 }
03402 }
03403 if (switch_case->return_needed) {
03404 char buf[2000];
03405 struct ael_priority *np2 = new_prio();
03406 np2->type = AEL_APPCALL;
03407 np2->app = strdup("NoOp");
03408 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03409 np2->appargs = strdup(buf);
03410 linkprio(switch_case, np2, mother_exten);
03411 switch_case-> return_target = np2;
03412 }
03413 } else if (p2->type == PV_DEFAULT) {
03414
03415 switch_case = new_exten();
03416 switch_case->context = this_context;
03417 switch_case->is_switch = 1;
03418
03419
03420
03421
03422
03423 default_exists++;
03424 switch_null = new_exten();
03425 switch_null->context = this_context;
03426 switch_null->is_switch = 1;
03427 switch_empty = new_prio();
03428 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03429 switch_empty->app = strdup("Goto");
03430 switch_empty->appargs = strdup(buf1);
03431 linkprio(switch_null, switch_empty, mother_exten);
03432 snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count);
03433 switch_null->name = strdup(buf1);
03434 switch_null->loop_break = exten->loop_break;
03435 switch_null->loop_continue = exten->loop_continue;
03436 linkexten(exten,switch_null);
03437
03438
03439 switch_case->loop_break = exten->loop_break;
03440 switch_case->loop_continue = exten->loop_continue;
03441 linkexten(exten,switch_case);
03442 snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count);
03443 switch_case->name = strdup(buf1);
03444
03445 snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count);
03446
03447 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03448
03449
03450 for (p3=p2->u2.statements; p3; p3=p3->next) {
03451 if (!p3->next)
03452 break;
03453 }
03454
03455 if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03456
03457 if (p2->next && p2->next->type == PV_CASE) {
03458 fall_thru = new_prio();
03459 fall_thru->type = AEL_APPCALL;
03460 fall_thru->app = strdup("Goto");
03461 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03462 buf2[sizeof(buf2)-1] = 0;
03463 substitute_commas(buf2);
03464 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03465 fall_thru->appargs = strdup(buf1);
03466 linkprio(switch_case, fall_thru, mother_exten);
03467 } else if (p2->next && p2->next->type == PV_PATTERN) {
03468 fall_thru = new_prio();
03469 fall_thru->type = AEL_APPCALL;
03470 fall_thru->app = strdup("Goto");
03471 gen_match_to_pattern(p2->next->u1.str, buf2);
03472 substitute_commas(buf2);
03473 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03474 fall_thru->appargs = strdup(buf1);
03475 linkprio(switch_case, fall_thru, mother_exten);
03476 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03477 fall_thru = new_prio();
03478 fall_thru->type = AEL_APPCALL;
03479 fall_thru->app = strdup("Goto");
03480 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03481 fall_thru->appargs = strdup(buf1);
03482 linkprio(switch_case, fall_thru, mother_exten);
03483 } else if (!p2->next) {
03484 fall_thru = new_prio();
03485 fall_thru->type = AEL_CONTROL1;
03486 fall_thru->goto_true = switch_end;
03487 fall_thru->app = strdup("Goto");
03488 linkprio(switch_case, fall_thru, mother_exten);
03489 }
03490 }
03491 if (switch_case->return_needed) {
03492 char buf[2000];
03493 struct ael_priority *np2 = new_prio();
03494 np2->type = AEL_APPCALL;
03495 np2->app = strdup("NoOp");
03496 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03497 np2->appargs = strdup(buf);
03498 linkprio(switch_case, np2, mother_exten);
03499 switch_case-> return_target = np2;
03500 }
03501 } else {
03502
03503 }
03504 }
03505
03506 exten->loop_break = loop_break_save;
03507 exten->loop_continue = loop_continue_save;
03508 switch_test->origin = p;
03509 switch_end->origin = p;
03510 break;
03511
03512 case PV_MACRO_CALL:
03513 pr = new_prio();
03514 pr->type = AEL_APPCALL;
03515 snprintf(buf1,sizeof(buf1),"%s", p->u1.str);
03516 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03517 strcat(buf1,"|");
03518 strcat(buf1,p2->u1.str);
03519 }
03520 pr->app = strdup("Macro");
03521 pr->appargs = strdup(buf1);
03522 pr->origin = p;
03523 linkprio(exten, pr, mother_exten);
03524 break;
03525
03526 case PV_APPLICATION_CALL:
03527 pr = new_prio();
03528 pr->type = AEL_APPCALL;
03529 buf1[0] = 0;
03530 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03531 if (p2 != p->u2.arglist )
03532 strcat(buf1,"|");
03533 substitute_commas(p2->u1.str);
03534 strcat(buf1,p2->u1.str);
03535 }
03536 pr->app = strdup(p->u1.str);
03537 pr->appargs = strdup(buf1);
03538 pr->origin = p;
03539 linkprio(exten, pr, mother_exten);
03540 break;
03541
03542 case PV_BREAK:
03543 pr = new_prio();
03544 pr->type = AEL_CONTROL1;
03545 pr->goto_true = exten->loop_break;
03546 pr->origin = p;
03547 linkprio(exten, pr, mother_exten);
03548 break;
03549
03550 case PV_RETURN:
03551 pr = new_prio();
03552 pr->type = AEL_RETURN;
03553 exten->return_needed++;
03554 pr->app = strdup("Goto");
03555 pr->appargs = strdup("");
03556 pr->origin = p;
03557 linkprio(exten, pr, mother_exten);
03558 break;
03559
03560 case PV_CONTINUE:
03561 pr = new_prio();
03562 pr->type = AEL_CONTROL1;
03563 pr->goto_true = exten->loop_continue;
03564 pr->origin = p;
03565 linkprio(exten, pr, mother_exten);
03566 break;
03567
03568 #ifdef OLD_RAND_ACTION
03569 case PV_RANDOM:
03570 control_statement_count++;
03571 snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count);
03572 rand_test = new_prio();
03573 rand_test->type = AEL_RAND_CONTROL;
03574 snprintf(buf1,sizeof(buf1),"$[%s]",
03575 p->u1.str );
03576 rand_test->app = 0;
03577 rand_test->appargs = strdup(buf1);
03578 rand_test->origin = p;
03579
03580 rand_end = new_prio();
03581 rand_end->type = AEL_APPCALL;
03582 snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count);
03583 rand_end->app = strdup("NoOp");
03584 rand_end->appargs = strdup(buf1);
03585
03586 rand_skip = new_prio();
03587 rand_skip->type = AEL_CONTROL1;
03588 rand_skip->goto_true = rand_end;
03589 rand_skip->origin = p;
03590
03591 rand_test->goto_true = rand_skip;
03592
03593 linkprio(exten, rand_test, mother_exten);
03594
03595 if (p->u3.else_statements) {
03596 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03597 }
03598
03599 linkprio(exten, rand_skip, mother_exten);
03600
03601 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03602
03603 linkprio(exten, rand_end, mother_exten);
03604
03605 break;
03606 #endif
03607
03608 case PV_IFTIME:
03609 control_statement_count++;
03610 snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count);
03611
03612 if_test = new_prio();
03613 if_test->type = AEL_IFTIME_CONTROL;
03614 snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s",
03615 p->u1.list->u1.str,
03616 p->u1.list->next->u1.str,
03617 p->u1.list->next->next->u1.str,
03618 p->u1.list->next->next->next->u1.str);
03619 if_test->app = 0;
03620 if_test->appargs = strdup(buf1);
03621 if_test->origin = p;
03622
03623 if_end = new_prio();
03624 if_end->type = AEL_APPCALL;
03625 snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count);
03626 if_end->app = strdup("NoOp");
03627 if_end->appargs = strdup(buf1);
03628
03629 if (p->u3.else_statements) {
03630 if_skip = new_prio();
03631 if_skip->type = AEL_CONTROL1;
03632 if_skip->goto_true = if_end;
03633 if_skip->origin = p;
03634
03635 } else {
03636 if_skip = 0;
03637
03638 if_test->goto_false = if_end;
03639 }
03640
03641 if_false = new_prio();
03642 if_false->type = AEL_CONTROL1;
03643 if (p->u3.else_statements) {
03644 if_false->goto_true = if_skip;
03645 } else {
03646 if_false->goto_true = if_end;
03647 }
03648
03649
03650 linkprio(exten, if_test, mother_exten);
03651 linkprio(exten, if_false, mother_exten);
03652
03653
03654
03655 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03656
03657 if (p->u3.else_statements) {
03658 linkprio(exten, if_skip, mother_exten);
03659 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03660
03661 }
03662
03663 linkprio(exten, if_end, mother_exten);
03664
03665 break;
03666
03667 case PV_RANDOM:
03668 case PV_IF:
03669 control_statement_count++;
03670 snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count);
03671
03672 if_test = new_prio();
03673 if_end = new_prio();
03674 if_test->type = AEL_IF_CONTROL;
03675 if_end->type = AEL_APPCALL;
03676 if ( p->type == PV_RANDOM )
03677 snprintf(buf1,sizeof(buf1),"$[${RAND(0,99)} < (%s)]",p->u1.str);
03678 else
03679 snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03680 if_test->app = 0;
03681 if_test->appargs = strdup(buf1);
03682 snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count);
03683 if_end->app = strdup("NoOp");
03684 if_end->appargs = strdup(buf1);
03685 if_test->origin = p;
03686
03687 if (p->u3.else_statements) {
03688 if_skip = new_prio();
03689 if_skip->type = AEL_CONTROL1;
03690 if_skip->goto_true = if_end;
03691 if_test->goto_false = if_skip;;
03692 } else {
03693 if_skip = 0;
03694 if_test->goto_false = if_end;;
03695 }
03696
03697
03698 linkprio(exten, if_test, mother_exten);
03699
03700
03701
03702 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03703
03704 if (p->u3.else_statements) {
03705 linkprio(exten, if_skip, mother_exten);
03706 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03707
03708 }
03709
03710 linkprio(exten, if_end, mother_exten);
03711
03712 break;
03713
03714 case PV_STATEMENTBLOCK:
03715 gen_prios(exten, label, p->u1.list, mother_exten, this_context );
03716 break;
03717
03718 case PV_CATCH:
03719 control_statement_count++;
03720
03721
03722 switch_case = new_exten();
03723 switch_case->context = this_context;
03724 linkexten(exten,switch_case);
03725 switch_case->name = strdup(p->u1.str);
03726 snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count);
03727
03728 gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context);
03729 if (switch_case->return_needed) {
03730 char buf[2000];
03731 struct ael_priority *np2 = new_prio();
03732 np2->type = AEL_APPCALL;
03733 np2->app = strdup("NoOp");
03734 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03735 np2->appargs = strdup(buf);
03736 linkprio(switch_case, np2, mother_exten);
03737 switch_case-> return_target = np2;
03738 }
03739
03740 break;
03741 default:
03742 break;
03743 }
03744 }
03745 }
03746
03747 void set_priorities(struct ael_extension *exten)
03748 {
03749 int i;
03750 struct ael_priority *pr;
03751 do {
03752 if (exten->is_switch)
03753 i = 10;
03754 else if (exten->regexten)
03755 i=2;
03756 else
03757 i=1;
03758
03759 for (pr=exten->plist; pr; pr=pr->next) {
03760 pr->priority_num = i;
03761
03762 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) )
03763
03764
03765
03766 i++;
03767 }
03768
03769 exten = exten->next_exten;
03770 } while ( exten );
03771 }
03772
03773 void add_extensions(struct ael_extension *exten)
03774 {
03775 struct ael_priority *pr;
03776 char *label=0;
03777 char realext[AST_MAX_EXTENSION];
03778 if (!exten) {
03779 ast_log(LOG_WARNING, "This file is Empty!\n" );
03780 return;
03781 }
03782 do {
03783 struct ael_priority *last = 0;
03784
03785 memset(realext, '\0', sizeof(realext));
03786 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
03787 if (exten->hints) {
03788 if (ast_add_extension2(exten->context, 0 , realext, PRIORITY_HINT, NULL, exten->cidmatch,
03789 exten->hints, NULL, ast_free, registrar)) {
03790 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
03791 exten->name);
03792 }
03793 }
03794
03795 for (pr=exten->plist; pr; pr=pr->next) {
03796 char app[2000];
03797 char appargs[2000];
03798
03799
03800
03801
03802 if (pr->type == AEL_LABEL) {
03803 last = pr;
03804 continue;
03805 }
03806
03807 if (pr->app)
03808 strcpy(app, pr->app);
03809 else
03810 app[0] = 0;
03811 if (pr->appargs )
03812 strcpy(appargs, pr->appargs);
03813 else
03814 appargs[0] = 0;
03815 switch( pr->type ) {
03816 case AEL_APPCALL:
03817
03818 break;
03819
03820 case AEL_CONTROL1:
03821
03822 strcpy(app,"Goto");
03823 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
03824 snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
03825 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
03826 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
03827 } else
03828 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
03829 break;
03830
03831 case AEL_FOR_CONTROL:
03832 strcpy(app,"GotoIf");
03833 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03834 break;
03835
03836 case AEL_IF_CONTROL:
03837 strcpy(app,"GotoIf");
03838 if (pr->origin->u3.else_statements )
03839 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
03840 else
03841 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03842 break;
03843
03844 case AEL_RAND_CONTROL:
03845 strcpy(app,"Random");
03846 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
03847 break;
03848
03849 case AEL_IFTIME_CONTROL:
03850 strcpy(app,"GotoIfTime");
03851 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
03852 break;
03853
03854 case AEL_RETURN:
03855 strcpy(app,"Goto");
03856 snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
03857 break;
03858
03859 default:
03860 break;
03861 }
03862 if (last && last->type == AEL_LABEL ) {
03863 label = last->origin->u1.str;
03864 }
03865 else
03866 label = 0;
03867
03868 if (ast_add_extension2(exten->context, 0 , realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
03869 app, strdup(appargs), ast_free, registrar)) {
03870 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
03871 exten->name);
03872 }
03873 last = pr;
03874 }
03875 exten = exten->next_exten;
03876 } while ( exten );
03877 }
03878
03879 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
03880 {
03881
03882 struct ael_extension *lptr;
03883 if( !*list ) {
03884 *list = newmem;
03885 return;
03886 }
03887 lptr = *list;
03888
03889 while( lptr->next_exten ) {
03890 lptr = lptr->next_exten;
03891 }
03892
03893 lptr->next_exten = newmem;
03894 }
03895
03896 static pval *get_extension_or_contxt(pval *p)
03897 {
03898 while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
03899
03900 p = p->dad;
03901 }
03902
03903 return p;
03904 }
03905
03906 static pval *get_contxt(pval *p)
03907 {
03908 while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
03909
03910 p = p->dad;
03911 }
03912
03913 return p;
03914 }
03915
03916 static void fix_gotos_in_extensions(struct ael_extension *exten)
03917 {
03918 struct ael_extension *e;
03919 for(e=exten;e;e=e->next_exten) {
03920
03921 struct ael_priority *p;
03922 for(p=e->plist;p;p=p->next) {
03923
03924 if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
03925
03926
03927
03928 pval *target = p->origin->u2.goto_target;
03929 struct ael_extension *z = target->u3.compiled_label;
03930 pval *pv2 = p->origin;
03931 char buf1[500];
03932 char *apparg_save = p->appargs;
03933
03934 p->appargs = 0;
03935 if (!pv2->u1.list->next) {
03936 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
03937 p->appargs = strdup(buf1);
03938
03939 } else if (pv2->u1.list->next && !pv2->u1.list->next->next) {
03940 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
03941 p->appargs = strdup(buf1);
03942 } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
03943 snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str,
03944 z->name,
03945 pv2->u1.list->next->next->u1.str);
03946 p->appargs = strdup(buf1);
03947 }
03948 else
03949 printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
03950
03951 if( apparg_save ) {
03952 free(apparg_save);
03953 }
03954 }
03955 }
03956 }
03957 }
03958
03959
03960 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
03961 {
03962 pval *p,*p2;
03963 struct ast_context *context;
03964 char buf[2000];
03965 struct ael_extension *exten;
03966 struct ael_extension *exten_list = 0;
03967
03968 for (p=root; p; p=p->next ) {
03969
03970 switch (p->type) {
03971 case PV_GLOBALS:
03972
03973 for (p2=p->u1.list; p2; p2=p2->next) {
03974 char buf2[2000];
03975 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
03976 pbx_builtin_setvar(NULL, buf2);
03977 }
03978 break;
03979 default:
03980 break;
03981 }
03982 }
03983
03984 for (p=root; p; p=p->next ) {
03985 pval *lp;
03986 int argc;
03987
03988 switch (p->type) {
03989 case PV_MACRO:
03990 strcpy(buf,"macro-");
03991 strcat(buf,p->u1.str);
03992 context = ast_context_create(local_contexts, buf, registrar);
03993
03994 exten = new_exten();
03995 exten->context = context;
03996 exten->name = strdup("s");
03997 argc = 1;
03998 for (lp=p->u2.arglist; lp; lp=lp->next) {
03999
04000 struct ael_priority *np2 = new_prio();
04001 np2->type = AEL_APPCALL;
04002 np2->app = strdup("Set");
04003 snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++);
04004 remove_spaces_before_equals(buf);
04005 np2->appargs = strdup(buf);
04006 linkprio(exten, np2, NULL);
04007 }
04008
04009 for (p2=p->u3.macro_statements; p2; p2=p2->next) {
04010 pval *p3;
04011
04012 switch (p2->type) {
04013 case PV_INCLUDES:
04014 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04015 if ( p3->u2.arglist ) {
04016 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s",
04017 p3->u1.str,
04018 p3->u2.arglist->u1.str,
04019 p3->u2.arglist->next->u1.str,
04020 p3->u2.arglist->next->next->u1.str,
04021 p3->u2.arglist->next->next->next->u1.str);
04022 ast_context_add_include2(context, buf, registrar);
04023 } else
04024 ast_context_add_include2(context, p3->u1.str, registrar);
04025 }
04026 break;
04027 default:
04028 break;
04029 }
04030 }
04031
04032 gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
04033 if (exten->return_needed) {
04034 struct ael_priority *np2 = new_prio();
04035 np2->type = AEL_APPCALL;
04036 np2->app = strdup("NoOp");
04037 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
04038 np2->appargs = strdup(buf);
04039 linkprio(exten, np2, NULL);
04040 exten-> return_target = np2;
04041 }
04042
04043 set_priorities(exten);
04044 attach_exten(&exten_list, exten);
04045 break;
04046
04047 case PV_GLOBALS:
04048
04049 break;
04050
04051 case PV_CONTEXT:
04052 context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
04053
04054
04055 for (p2=p->u2.statements; p2; p2=p2->next) {
04056 pval *p3;
04057 char *s3;
04058
04059 switch (p2->type) {
04060 case PV_EXTENSION:
04061 exten = new_exten();
04062 exten->name = strdup(p2->u1.str);
04063 exten->context = context;
04064
04065 if( (s3=strchr(exten->name, '/') ) != 0 )
04066 {
04067 *s3 = 0;
04068 exten->cidmatch = s3+1;
04069 }
04070
04071 if ( p2->u3.hints )
04072 exten->hints = strdup(p2->u3.hints);
04073 exten->regexten = p2->u4.regexten;
04074 gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
04075 if (exten->return_needed) {
04076 struct ael_priority *np2 = new_prio();
04077 np2->type = AEL_APPCALL;
04078 np2->app = strdup("NoOp");
04079 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04080 np2->appargs = strdup(buf);
04081 linkprio(exten, np2, NULL);
04082 exten-> return_target = np2;
04083 }
04084
04085 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04086 struct ael_priority *np2 = new_prio();
04087 np2->type = AEL_APPCALL;
04088 np2->app = strdup("NoOp");
04089 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04090 np2->appargs = strdup(buf);
04091 linkprio(exten, np2, NULL);
04092 }
04093
04094 set_priorities(exten);
04095 attach_exten(&exten_list, exten);
04096 break;
04097
04098 case PV_IGNOREPAT:
04099 ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04100 break;
04101
04102 case PV_INCLUDES:
04103 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04104 if ( p3->u2.arglist ) {
04105 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s",
04106 p3->u1.str,
04107 p3->u2.arglist->u1.str,
04108 p3->u2.arglist->next->u1.str,
04109 p3->u2.arglist->next->next->u1.str,
04110 p3->u2.arglist->next->next->next->u1.str);
04111 ast_context_add_include2(context, buf, registrar);
04112 } else
04113 ast_context_add_include2(context, p3->u1.str, registrar);
04114 }
04115 break;
04116
04117 case PV_SWITCHES:
04118 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04119 char *c = strchr(p3->u1.str, '/');
04120 if (c) {
04121 *c = '\0';
04122 c++;
04123 } else
04124 c = "";
04125
04126 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04127 }
04128 break;
04129
04130 case PV_ESWITCHES:
04131 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04132 char *c = strchr(p3->u1.str, '/');
04133 if (c) {
04134 *c = '\0';
04135 c++;
04136 } else
04137 c = "";
04138
04139 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04140 }
04141 break;
04142 default:
04143 break;
04144 }
04145 }
04146
04147 break;
04148
04149 default:
04150
04151 break;
04152
04153 }
04154 }
04155
04156
04157
04158 fix_gotos_in_extensions(exten_list);
04159 add_extensions(exten_list);
04160 destroy_extensions(exten_list);
04161
04162 }
04163
04164
04165 static int aeldebug = 0;
04166
04167
04168
04169
04170
04171 static int pbx_load_module(void)
04172 {
04173 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04174 char *rfilename;
04175 struct ast_context *local_contexts=NULL, *con;
04176 struct pval *parse_tree;
04177
04178 ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04179 if (config[0] == '/')
04180 rfilename = (char *)config;
04181 else {
04182 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04183 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04184 }
04185 ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04186
04187 if (access(rfilename,R_OK) != 0) {
04188 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04189 return AST_MODULE_LOAD_DECLINE;
04190 }
04191
04192 parse_tree = ael2_parse(rfilename, &errs);
04193 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04194 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04195 if (errs == 0 && sem_err == 0) {
04196 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04197 ast_compile_ael2(&local_contexts, parse_tree);
04198 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04199
04200 ast_merge_contexts_and_delete(&local_contexts, registrar);
04201 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04202 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04203 ast_context_verify_includes(con);
04204 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04205 } else {
04206 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);
04207 destroy_pval(parse_tree);
04208 return AST_MODULE_LOAD_DECLINE;
04209 }
04210 destroy_pval(parse_tree);
04211
04212 return AST_MODULE_LOAD_SUCCESS;
04213 }
04214
04215
04216 static int ael2_debug_read(int fd, int argc, char *argv[])
04217 {
04218 aeldebug |= DEBUG_READ;
04219 return 0;
04220 }
04221
04222 static int ael2_debug_tokens(int fd, int argc, char *argv[])
04223 {
04224 aeldebug |= DEBUG_TOKENS;
04225 return 0;
04226 }
04227
04228 static int ael2_debug_macros(int fd, int argc, char *argv[])
04229 {
04230 aeldebug |= DEBUG_MACROS;
04231 return 0;
04232 }
04233
04234 static int ael2_debug_contexts(int fd, int argc, char *argv[])
04235 {
04236 aeldebug |= DEBUG_CONTEXTS;
04237 return 0;
04238 }
04239
04240 static int ael2_no_debug(int fd, int argc, char *argv[])
04241 {
04242 aeldebug = 0;
04243 return 0;
04244 }
04245
04246 static int ael2_reload(int fd, int argc, char *argv[])
04247 {
04248 return (pbx_load_module());
04249 }
04250
04251 static struct ast_cli_entry cli_ael_no_debug = {
04252 { "ael", "no", "debug", NULL },
04253 ael2_no_debug, NULL,
04254 NULL };
04255
04256 static struct ast_cli_entry cli_ael[] = {
04257 { { "ael", "reload", NULL },
04258 ael2_reload, "Reload AEL configuration" },
04259
04260 { { "ael", "debug", "read", NULL },
04261 ael2_debug_read, "Enable AEL read debug (does nothing)" },
04262
04263 { { "ael", "debug", "tokens", NULL },
04264 ael2_debug_tokens, "Enable AEL tokens debug (does nothing)" },
04265
04266 { { "ael", "debug", "macros", NULL },
04267 ael2_debug_macros, "Enable AEL macros debug (does nothing)" },
04268
04269 { { "ael", "debug", "contexts", NULL },
04270 ael2_debug_contexts, "Enable AEL contexts debug (does nothing)" },
04271
04272 { { "ael", "nodebug", NULL },
04273 ael2_no_debug, "Disable AEL debug messages",
04274 NULL, NULL, &cli_ael_no_debug },
04275 };
04276
04277 static int unload_module(void)
04278 {
04279 ast_context_destroy(NULL, registrar);
04280 ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04281 return 0;
04282 }
04283
04284 static int load_module(void)
04285 {
04286 ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04287 return (pbx_load_module());
04288 }
04289
04290 static int reload(void)
04291 {
04292 return pbx_load_module();
04293 }
04294
04295 #ifdef STANDALONE_AEL
04296 #define AST_MODULE "ael"
04297 int ael_external_load_module(void);
04298 int ael_external_load_module(void)
04299 {
04300 pbx_load_module();
04301 return 1;
04302 }
04303 #endif
04304
04305 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
04306 .load = load_module,
04307 .unload = unload_module,
04308 .reload = reload,
04309 );
04310
04311
04312
04313
04314
04315
04316 void destroy_pval_item(pval *item)
04317 {
04318 if (item == NULL) {
04319 ast_log(LOG_WARNING, "null item\n");
04320 return;
04321 }
04322
04323 if (item->filename)
04324 free(item->filename);
04325
04326 switch (item->type) {
04327 case PV_WORD:
04328
04329 if (item->u1.str )
04330 free(item->u1.str);
04331 if ( item->u2.arglist )
04332 destroy_pval(item->u2.arglist);
04333 break;
04334
04335 case PV_MACRO:
04336
04337
04338
04339
04340
04341
04342
04343 destroy_pval(item->u2.arglist);
04344 if (item->u1.str )
04345 free(item->u1.str);
04346 destroy_pval(item->u3.macro_statements);
04347 break;
04348
04349 case PV_CONTEXT:
04350
04351
04352
04353
04354 if (item->u1.str)
04355 free(item->u1.str);
04356 destroy_pval(item->u2.statements);
04357 break;
04358
04359 case PV_MACRO_CALL:
04360
04361
04362
04363
04364
04365 if (item->u1.str)
04366 free(item->u1.str);
04367 destroy_pval(item->u2.arglist);
04368 break;
04369
04370 case PV_APPLICATION_CALL:
04371
04372
04373
04374
04375
04376 if (item->u1.str)
04377 free(item->u1.str);
04378 destroy_pval(item->u2.arglist);
04379 break;
04380
04381 case PV_CASE:
04382
04383
04384
04385 if (item->u1.str)
04386 free(item->u1.str);
04387 destroy_pval(item->u2.statements);
04388 break;
04389
04390 case PV_PATTERN:
04391
04392
04393
04394 if (item->u1.str)
04395 free(item->u1.str);
04396 destroy_pval(item->u2.statements);
04397 break;
04398
04399 case PV_DEFAULT:
04400
04401
04402
04403 destroy_pval(item->u2.statements);
04404 break;
04405
04406 case PV_CATCH:
04407
04408
04409
04410 if (item->u1.str)
04411 free(item->u1.str);
04412 destroy_pval(item->u2.statements);
04413 break;
04414
04415 case PV_SWITCHES:
04416
04417
04418 destroy_pval(item->u1.list);
04419 break;
04420
04421 case PV_ESWITCHES:
04422
04423
04424 destroy_pval(item->u1.list);
04425 break;
04426
04427 case PV_INCLUDES:
04428
04429
04430
04431 destroy_pval(item->u1.list);
04432 break;
04433
04434 case PV_STATEMENTBLOCK:
04435
04436
04437 destroy_pval(item->u1.list);
04438 break;
04439
04440 case PV_VARDEC:
04441
04442
04443
04444 if (item->u1.str)
04445 free(item->u1.str);
04446 if (item->u2.val)
04447 free(item->u2.val);
04448 break;
04449
04450 case PV_GOTO:
04451
04452
04453
04454
04455 destroy_pval(item->u1.list);
04456 break;
04457
04458 case PV_LABEL:
04459
04460
04461 if (item->u1.str)
04462 free(item->u1.str);
04463 break;
04464
04465 case PV_FOR:
04466
04467
04468
04469
04470
04471
04472 if (item->u1.for_init)
04473 free(item->u1.for_init);
04474 if (item->u2.for_test)
04475 free(item->u2.for_test);
04476 if (item->u3.for_inc)
04477 free(item->u3.for_inc);
04478 destroy_pval(item->u4.for_statements);
04479 break;
04480
04481 case PV_WHILE:
04482
04483
04484
04485
04486 if (item->u1.str)
04487 free(item->u1.str);
04488 destroy_pval(item->u2.statements);
04489 break;
04490
04491 case PV_BREAK:
04492
04493
04494 break;
04495
04496 case PV_RETURN:
04497
04498
04499 break;
04500
04501 case PV_CONTINUE:
04502
04503
04504 break;
04505
04506 case PV_IFTIME:
04507
04508
04509
04510
04511
04512
04513 destroy_pval(item->u1.list);
04514 destroy_pval(item->u2.statements);
04515 if (item->u3.else_statements) {
04516 destroy_pval(item->u3.else_statements);
04517 }
04518 break;
04519
04520 case PV_RANDOM:
04521
04522
04523
04524
04525
04526
04527 case PV_IF:
04528
04529
04530
04531
04532
04533
04534 if (item->u1.str)
04535 free(item->u1.str);
04536 destroy_pval(item->u2.statements);
04537 if (item->u3.else_statements) {
04538 destroy_pval(item->u3.else_statements);
04539 }
04540 break;
04541
04542 case PV_SWITCH:
04543
04544
04545
04546
04547
04548 if (item->u1.str)
04549 free(item->u1.str);
04550 destroy_pval(item->u2.statements);
04551 break;
04552
04553 case PV_EXTENSION:
04554
04555
04556
04557
04558
04559
04560 if (item->u1.str)
04561 free(item->u1.str);
04562 if (item->u3.hints)
04563 free(item->u3.hints);
04564 destroy_pval(item->u2.statements);
04565 break;
04566
04567 case PV_IGNOREPAT:
04568
04569
04570 if (item->u1.str)
04571 free(item->u1.str);
04572 break;
04573
04574 case PV_GLOBALS:
04575
04576
04577 destroy_pval(item->u1.statements);
04578 break;
04579 }
04580 free(item);
04581 }
04582
04583 void destroy_pval(pval *item)
04584 {
04585 pval *i,*nxt;
04586
04587 for (i=item; i; i=nxt) {
04588 nxt = i->next;
04589
04590 destroy_pval_item(i);
04591 }
04592 }
04593
04594 #ifdef AAL_ARGCHECK
04595 static char *ael_funclist[] =
04596 {
04597 "AGENT",
04598 "ARRAY",
04599 "BASE64_DECODE",
04600 "BASE64_ENCODE",
04601 "CALLERID",
04602 "CDR",
04603 "CHANNEL",
04604 "CHECKSIPDOMAIN",
04605 "CHECK_MD5",
04606 "CURL",
04607 "CUT",
04608 "DB",
04609 "DB_EXISTS",
04610 "DUNDILOOKUP",
04611 "ENUMLOOKUP",
04612 "ENV",
04613 "EVAL",
04614 "EXISTS",
04615 "FIELDQTY",
04616 "FILTER",
04617 "GROUP",
04618 "GROUP_COUNT",
04619 "GROUP_LIST",
04620 "GROUP_MATCH_COUNT",
04621 "IAXPEER",
04622 "IF",
04623 "IFTIME",
04624 "ISNULL",
04625 "KEYPADHASH",
04626 "LANGUAGE",
04627 "LEN",
04628 "MATH",
04629 "MD5",
04630 "MUSICCLASS",
04631 "QUEUEAGENTCOUNT",
04632 "QUEUE_MEMBER_COUNT",
04633 "QUEUE_MEMBER_LIST",
04634 "QUOTE",
04635 "RAND",
04636 "REGEX",
04637 "SET",
04638 "SHA1",
04639 "SIPCHANINFO",
04640 "SIPPEER",
04641 "SIP_HEADER",
04642 "SORT",
04643 "STAT",
04644 "STRFTIME",
04645 "STRPTIME",
04646 "TIMEOUT",
04647 "TXTCIDNAME",
04648 "URIDECODE",
04649 "URIENCODE",
04650 "VMCOUNT"
04651 };
04652
04653
04654 int ael_is_funcname(char *name)
04655 {
04656 int s,t;
04657 t = sizeof(ael_funclist)/sizeof(char*);
04658 s = 0;
04659 while ((s < t) && strcasecmp(name, ael_funclist[s]))
04660 s++;
04661 if ( s < t )
04662 return 1;
04663 else
04664 return 0;
04665 }
04666 #endif