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