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