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