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