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