00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "asterisk.h"
00026
00027 #if !defined(STANDALONE_AEL)
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 144924 $")
00029 #endif
00030
00031 #include <sys/types.h>
00032 #include <stdlib.h>
00033 #include <unistd.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <ctype.h>
00037 #include <errno.h>
00038 #include <regex.h>
00039 #include <sys/stat.h>
00040
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/callerid.h"
00048 #include "asterisk/ael_structs.h"
00049 #ifdef AAL_ARGCHECK
00050 #include "asterisk/argdesc.h"
00051 #endif
00052
00053 static char expr_output[2096];
00054
00055
00056
00057 #define DEBUG_READ (1 << 0)
00058 #define DEBUG_TOKENS (1 << 1)
00059 #define DEBUG_MACROS (1 << 2)
00060 #define DEBUG_CONTEXTS (1 << 3)
00061
00062 static char *config = "extensions.ael";
00063 static char *registrar = "pbx_ael";
00064 static int pbx_load_module(void);
00065
00066 static int errs, warns;
00067 static int notes;
00068
00069 #ifndef AAL_ARGCHECK
00070
00071
00072
00073
00074
00075
00076 struct argapp
00077 {
00078 struct argapp *next;
00079 };
00080
00081 #endif
00082
00083 #ifdef AAL_ARGCHECK
00084 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00085 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00086 int ael_is_funcname(char *name);
00087 #endif
00088
00089 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00090 void check_pval(pval *item, struct argapp *apps, int in_globals);
00091 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00092 void check_switch_expr(pval *item, struct argapp *apps);
00093 void ast_expr_register_extra_error_info(char *errmsg);
00094 void ast_expr_clear_extra_error_info(void);
00095 int ast_expr(char *expr, char *buf, int length);
00096 struct pval *find_macro(char *name);
00097 struct pval *find_context(char *name);
00098 struct pval *find_context(char *name);
00099 struct pval *find_macro(char *name);
00100 struct ael_priority *new_prio(void);
00101 struct ael_extension *new_exten(void);
00102 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten);
00103 void destroy_extensions(struct ael_extension *exten);
00104 static void linkexten(struct ael_extension *exten, struct ael_extension *add);
00105 static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context );
00106 void set_priorities(struct ael_extension *exten);
00107 void add_extensions(struct ael_extension *exten);
00108 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
00109 void destroy_pval(pval *item);
00110 void destroy_pval_item(pval *item);
00111 int is_float(char *arg );
00112 int is_int(char *arg );
00113 int is_empty(char *arg);
00114 static pval *current_db=0;
00115 static pval *current_context=0;
00116 static pval *current_extension=0;
00117
00118 static const char *match_context;
00119 static const char *match_exten;
00120 static const char *match_label;
00121 static int in_abstract_context;
00122 static int count_labels;
00123 static int label_count;
00124 static int return_on_context_match;
00125 static pval *last_matched_label;
00126 struct pval *match_pval(pval *item);
00127 static void check_timerange(pval *p);
00128 static void check_dow(pval *DOW);
00129 static void check_day(pval *DAY);
00130 static void check_month(pval *MON);
00131 static void check_expr2_input(pval *expr, char *str);
00132 static int extension_matches(pval *here, const char *exten, const char *pattern);
00133 static void check_goto(pval *item);
00134 static void find_pval_goto_item(pval *item, int lev);
00135 static void find_pval_gotos(pval *item, int lev);
00136
00137 static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont);
00138 static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont);
00139 static void print_pval_list(FILE *fin, pval *item, int depth);
00140
00141 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext);
00142 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label);
00143 static pval *get_goto_target(pval *item);
00144 static int label_inside_case(pval *label);
00145 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem);
00146 static void fix_gotos_in_extensions(struct ael_extension *exten);
00147 static pval *get_extension_or_contxt(pval *p);
00148 static pval *get_contxt(pval *p);
00149 static void remove_spaces_before_equals(char *str);
00150 static void substitute_commas(char *str);
00151
00152
00153 static void substitute_commas(char *str)
00154 {
00155 char *p = str;
00156
00157 while (p && *p)
00158 {
00159 if (*p == ',' && ((p != str && *(p-1) != '\\')
00160 || p == str))
00161 *p = '|';
00162 if (*p == '\\' && *(p+1) == ',') {
00163 char *q = p;
00164 while (*q) {
00165 *q = *(q+1);
00166 q++;
00167 }
00168 }
00169 p++;
00170 }
00171 }
00172
00173
00174
00175
00176 static void print_pval(FILE *fin, pval *item, int depth)
00177 {
00178 int i;
00179 pval *lp;
00180
00181 for (i=0; i<depth; i++) {
00182 fprintf(fin, "\t");
00183 }
00184
00185 switch ( item->type ) {
00186 case PV_WORD:
00187 fprintf(fin,"%s;\n", item->u1.str);
00188 break;
00189
00190 case PV_MACRO:
00191 fprintf(fin,"macro %s(", item->u1.str);
00192 for (lp=item->u2.arglist; lp; lp=lp->next) {
00193 if (lp != item->u2.arglist )
00194 fprintf(fin,", ");
00195 fprintf(fin,"%s", lp->u1.str);
00196 }
00197 fprintf(fin,") {\n");
00198 print_pval_list(fin,item->u3.macro_statements,depth+1);
00199 for (i=0; i<depth; i++) {
00200 fprintf(fin,"\t");
00201 }
00202 fprintf(fin,"};\n\n");
00203 break;
00204
00205 case PV_CONTEXT:
00206 if ( item->u3.abstract )
00207 fprintf(fin,"abstract context %s {\n", item->u1.str);
00208 else
00209 fprintf(fin,"context %s {\n", item->u1.str);
00210 print_pval_list(fin,item->u2.statements,depth+1);
00211 for (i=0; i<depth; i++) {
00212 fprintf(fin,"\t");
00213 }
00214 fprintf(fin,"};\n\n");
00215 break;
00216
00217 case PV_MACRO_CALL:
00218 fprintf(fin,"&%s(", item->u1.str);
00219 for (lp=item->u2.arglist; lp; lp=lp->next) {
00220 if ( lp != item->u2.arglist )
00221 fprintf(fin,", ");
00222 fprintf(fin,"%s", lp->u1.str);
00223 }
00224 fprintf(fin,");\n");
00225 break;
00226
00227 case PV_APPLICATION_CALL:
00228 fprintf(fin,"%s(", item->u1.str);
00229 for (lp=item->u2.arglist; lp; lp=lp->next) {
00230 if ( lp != item->u2.arglist )
00231 fprintf(fin,",");
00232 fprintf(fin,"%s", lp->u1.str);
00233 }
00234 fprintf(fin,");\n");
00235 break;
00236
00237 case PV_CASE:
00238 fprintf(fin,"case %s:\n", item->u1.str);
00239 print_pval_list(fin,item->u2.statements, depth+1);
00240 break;
00241
00242 case PV_PATTERN:
00243 fprintf(fin,"pattern %s:\n", item->u1.str);
00244 print_pval_list(fin,item->u2.statements, depth+1);
00245 break;
00246
00247 case PV_DEFAULT:
00248 fprintf(fin,"default:\n");
00249 print_pval_list(fin,item->u2.statements, depth+1);
00250 break;
00251
00252 case PV_CATCH:
00253 fprintf(fin,"catch %s {\n", item->u1.str);
00254 print_pval_list(fin,item->u2.statements, depth+1);
00255 for (i=0; i<depth; i++) {
00256 fprintf(fin,"\t");
00257 }
00258 fprintf(fin,"};\n");
00259 break;
00260
00261 case PV_SWITCHES:
00262 fprintf(fin,"switches {\n");
00263 print_pval_list(fin,item->u1.list,depth+1);
00264 for (i=0; i<depth; i++) {
00265 fprintf(fin,"\t");
00266 }
00267 fprintf(fin,"};\n");
00268 break;
00269
00270 case PV_ESWITCHES:
00271 fprintf(fin,"eswitches {\n");
00272 print_pval_list(fin,item->u1.list,depth+1);
00273 for (i=0; i<depth; i++) {
00274 fprintf(fin,"\t");
00275 }
00276 fprintf(fin,"};\n");
00277 break;
00278
00279 case PV_INCLUDES:
00280 fprintf(fin,"includes {\n");
00281 for (lp=item->u1.list; lp; lp=lp->next) {
00282 for (i=0; i<depth+1; i++) {
00283 fprintf(fin,"\t");
00284 }
00285 fprintf(fin,"%s", lp->u1.str);
00286 if ( lp->u2.arglist )
00287 fprintf(fin,"|%s|%s|%s|%s",
00288 lp->u2.arglist->u1.str,
00289 lp->u2.arglist->next->u1.str,
00290 lp->u2.arglist->next->next->u1.str,
00291 lp->u2.arglist->next->next->next->u1.str
00292 );
00293 fprintf(fin,";\n");
00294 }
00295
00296 print_pval_list(fin,item->u1.list,depth+1);
00297 for (i=0; i<depth; i++) {
00298 fprintf(fin,"\t");
00299 }
00300 fprintf(fin,"};\n");
00301 break;
00302
00303 case PV_STATEMENTBLOCK:
00304 fprintf(fin,"{\n");
00305 print_pval_list(fin,item->u1.list, depth+1);
00306 for (i=0; i<depth; i++) {
00307 fprintf(fin,"\t");
00308 }
00309 fprintf(fin,"};\n");
00310 break;
00311
00312 case PV_VARDEC:
00313 fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
00314 break;
00315
00316 case PV_GOTO:
00317 fprintf(fin,"goto %s", item->u1.list->u1.str);
00318 if ( item->u1.list->next )
00319 fprintf(fin,"|%s", item->u1.list->next->u1.str);
00320 if ( item->u1.list->next && item->u1.list->next->next )
00321 fprintf(fin,"|%s", item->u1.list->next->next->u1.str);
00322 fprintf(fin,"\n");
00323 break;
00324
00325 case PV_LABEL:
00326 fprintf(fin,"%s:\n", item->u1.str);
00327 break;
00328
00329 case PV_FOR:
00330 fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
00331 print_pval_list(fin,item->u4.for_statements,depth+1);
00332 break;
00333
00334 case PV_WHILE:
00335 fprintf(fin,"while (%s)\n", item->u1.str);
00336 print_pval_list(fin,item->u2.statements,depth+1);
00337 break;
00338
00339 case PV_BREAK:
00340 fprintf(fin,"break;\n");
00341 break;
00342
00343 case PV_RETURN:
00344 fprintf(fin,"return;\n");
00345 break;
00346
00347 case PV_CONTINUE:
00348 fprintf(fin,"continue;\n");
00349 break;
00350
00351 case PV_RANDOM:
00352 case PV_IFTIME:
00353 case PV_IF:
00354 if ( item->type == PV_IFTIME ) {
00355
00356 fprintf(fin,"ifTime ( %s|%s|%s|%s )\n",
00357 item->u1.list->u1.str,
00358 item->u1.list->next->u1.str,
00359 item->u1.list->next->next->u1.str,
00360 item->u1.list->next->next->next->u1.str
00361 );
00362 } else if ( item->type == PV_RANDOM ) {
00363 fprintf(fin,"random ( %s )\n", item->u1.str );
00364 } else
00365 fprintf(fin,"if ( %s )\n", item->u1.str);
00366 if ( item->u2.statements && item->u2.statements->next ) {
00367 for (i=0; i<depth; i++) {
00368 fprintf(fin,"\t");
00369 }
00370 fprintf(fin,"{\n");
00371 print_pval_list(fin,item->u2.statements,depth+1);
00372 for (i=0; i<depth; i++) {
00373 fprintf(fin,"\t");
00374 }
00375 if ( item->u3.else_statements )
00376 fprintf(fin,"}\n");
00377 else
00378 fprintf(fin,"};\n");
00379 } else if (item->u2.statements ) {
00380 print_pval_list(fin,item->u2.statements,depth+1);
00381 } else {
00382 if (item->u3.else_statements )
00383 fprintf(fin, " {} ");
00384 else
00385 fprintf(fin, " {}; ");
00386 }
00387 if ( item->u3.else_statements ) {
00388 for (i=0; i<depth; i++) {
00389 fprintf(fin,"\t");
00390 }
00391 fprintf(fin,"else\n");
00392 print_pval_list(fin,item->u3.else_statements, depth);
00393 }
00394 break;
00395
00396 case PV_SWITCH:
00397 fprintf(fin,"switch( %s ) {\n", item->u1.str);
00398 print_pval_list(fin,item->u2.statements,depth+1);
00399 for (i=0; i<depth; i++) {
00400 fprintf(fin,"\t");
00401 }
00402 fprintf(fin,"}\n");
00403 break;
00404
00405 case PV_EXTENSION:
00406 if ( item->u4.regexten )
00407 fprintf(fin, "regexten ");
00408 if ( item->u3.hints )
00409 fprintf(fin,"hints(%s) ", item->u3.hints);
00410
00411 fprintf(fin,"%s => \n", item->u1.str);
00412 print_pval_list(fin,item->u2.statements,depth+1);
00413 break;
00414
00415 case PV_IGNOREPAT:
00416 fprintf(fin,"ignorepat => %s\n", item->u1.str);
00417 break;
00418
00419 case PV_GLOBALS:
00420 fprintf(fin,"globals {\n");
00421 print_pval_list(fin,item->u1.statements,depth+1);
00422 for (i=0; i<depth; i++) {
00423 fprintf(fin,"\t");
00424 }
00425 fprintf(fin,"}\n");
00426 break;
00427 }
00428 }
00429
00430 static void print_pval_list(FILE *fin, pval *item, int depth)
00431 {
00432 pval *i;
00433
00434 for (i=item; i; i=i->next) {
00435 print_pval(fin, i, depth);
00436 }
00437 }
00438
00439 #if 0
00440 static void ael2_print(char *fname, pval *tree)
00441 {
00442 FILE *fin = fopen(fname,"w");
00443 if ( !fin ) {
00444 ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
00445 return;
00446 }
00447 print_pval_list(fin, tree, 0);
00448 fclose(fin);
00449 }
00450 #endif
00451
00452
00453
00454
00455 void traverse_pval_template(pval *item, int depth);
00456 void traverse_pval_item_template(pval *item, int depth);
00457
00458
00459 void traverse_pval_item_template(pval *item, int depth)
00460
00461 {
00462 pval *lp;
00463
00464 switch ( item->type ) {
00465 case PV_WORD:
00466
00467 break;
00468
00469 case PV_MACRO:
00470
00471
00472
00473
00474
00475
00476
00477 for (lp=item->u2.arglist; lp; lp=lp->next) {
00478
00479 }
00480 traverse_pval_item_template(item->u3.macro_statements,depth+1);
00481 break;
00482
00483 case PV_CONTEXT:
00484
00485
00486
00487
00488 traverse_pval_item_template(item->u2.statements,depth+1);
00489 break;
00490
00491 case PV_MACRO_CALL:
00492
00493
00494
00495
00496
00497 for (lp=item->u2.arglist; lp; lp=lp->next) {
00498 }
00499 break;
00500
00501 case PV_APPLICATION_CALL:
00502
00503
00504
00505
00506
00507 for (lp=item->u2.arglist; lp; lp=lp->next) {
00508 }
00509 break;
00510
00511 case PV_CASE:
00512
00513
00514
00515 traverse_pval_item_template(item->u2.statements,depth+1);
00516 break;
00517
00518 case PV_PATTERN:
00519
00520
00521
00522 traverse_pval_item_template(item->u2.statements,depth+1);
00523 break;
00524
00525 case PV_DEFAULT:
00526
00527
00528
00529 traverse_pval_item_template(item->u2.statements,depth+1);
00530 break;
00531
00532 case PV_CATCH:
00533
00534
00535
00536 traverse_pval_item_template(item->u2.statements,depth+1);
00537 break;
00538
00539 case PV_SWITCHES:
00540
00541
00542 traverse_pval_item_template(item->u1.list,depth+1);
00543 break;
00544
00545 case PV_ESWITCHES:
00546
00547
00548 traverse_pval_item_template(item->u1.list,depth+1);
00549 break;
00550
00551 case PV_INCLUDES:
00552
00553
00554
00555 traverse_pval_item_template(item->u1.list,depth+1);
00556 traverse_pval_item_template(item->u2.arglist,depth+1);
00557 break;
00558
00559 case PV_STATEMENTBLOCK:
00560
00561
00562 traverse_pval_item_template(item->u1.list,depth+1);
00563 break;
00564
00565 case PV_VARDEC:
00566
00567
00568
00569 break;
00570
00571 case PV_GOTO:
00572
00573
00574
00575
00576 if ( item->u1.list->next )
00577 ;
00578 if ( item->u1.list->next && item->u1.list->next->next )
00579 ;
00580
00581 break;
00582
00583 case PV_LABEL:
00584
00585
00586 break;
00587
00588 case PV_FOR:
00589
00590
00591
00592
00593
00594
00595 traverse_pval_item_template(item->u4.for_statements,depth+1);
00596 break;
00597
00598 case PV_WHILE:
00599
00600
00601
00602
00603 traverse_pval_item_template(item->u2.statements,depth+1);
00604 break;
00605
00606 case PV_BREAK:
00607
00608
00609 break;
00610
00611 case PV_RETURN:
00612
00613
00614 break;
00615
00616 case PV_CONTINUE:
00617
00618
00619 break;
00620
00621 case PV_IFTIME:
00622
00623
00624
00625
00626
00627
00628 traverse_pval_item_template(item->u2.statements,depth+1);
00629 if ( item->u3.else_statements ) {
00630 traverse_pval_item_template(item->u3.else_statements,depth+1);
00631 }
00632 break;
00633
00634 case PV_RANDOM:
00635
00636
00637
00638
00639
00640
00641 traverse_pval_item_template(item->u2.statements,depth+1);
00642 if ( item->u3.else_statements ) {
00643 traverse_pval_item_template(item->u3.else_statements,depth+1);
00644 }
00645 break;
00646
00647 case PV_IF:
00648
00649
00650
00651
00652
00653
00654 traverse_pval_item_template(item->u2.statements,depth+1);
00655 if ( item->u3.else_statements ) {
00656 traverse_pval_item_template(item->u3.else_statements,depth+1);
00657 }
00658 break;
00659
00660 case PV_SWITCH:
00661
00662
00663
00664
00665
00666 traverse_pval_item_template(item->u2.statements,depth+1);
00667 break;
00668
00669 case PV_EXTENSION:
00670
00671
00672
00673
00674
00675
00676 traverse_pval_item_template(item->u2.statements,depth+1);
00677 break;
00678
00679 case PV_IGNOREPAT:
00680
00681
00682 break;
00683
00684 case PV_GLOBALS:
00685
00686
00687 traverse_pval_item_template(item->u1.statements,depth+1);
00688 break;
00689 }
00690 }
00691
00692 void traverse_pval_template(pval *item, int depth)
00693
00694 {
00695 pval *i;
00696
00697 for (i=item; i; i=i->next) {
00698 traverse_pval_item_template(i, depth);
00699 }
00700 }
00701
00702
00703
00704
00705
00706
00707
00708
00709 static int extension_matches(pval *here, const char *exten, const char *pattern)
00710 {
00711 int err1;
00712 regex_t preg;
00713
00714
00715 if( !strcmp(pattern,exten) == 0 )
00716 return 1;
00717
00718 if ( pattern[0] == '_' ) {
00719 char reg1[2000];
00720 const char *p;
00721 char *r = reg1;
00722
00723 if ( strlen(pattern)*5 >= 2000 ) {
00724 ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
00725 pattern);
00726 return 0;
00727 }
00728
00729 *r++ = '^';
00730 *r++ = '_';
00731 *r++ = '?';
00732 for (p=pattern+1; *p; p++) {
00733 switch ( *p ) {
00734 case 'X':
00735 *r++ = '[';
00736 *r++ = '0';
00737 *r++ = '-';
00738 *r++ = '9';
00739 *r++ = 'X';
00740 *r++ = ']';
00741 break;
00742
00743 case 'Z':
00744 *r++ = '[';
00745 *r++ = '1';
00746 *r++ = '-';
00747 *r++ = '9';
00748 *r++ = 'Z';
00749 *r++ = ']';
00750 break;
00751
00752 case 'N':
00753 *r++ = '[';
00754 *r++ = '2';
00755 *r++ = '-';
00756 *r++ = '9';
00757 *r++ = 'N';
00758 *r++ = ']';
00759 break;
00760
00761 case '[':
00762 while ( *p && *p != ']' ) {
00763 *r++ = *p++;
00764 }
00765 if ( *p != ']') {
00766 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
00767 here->filename, here->startline, here->endline, pattern);
00768 }
00769 break;
00770
00771 case '.':
00772 case '!':
00773 *r++ = '.';
00774 *r++ = '*';
00775 break;
00776 case '*':
00777 *r++ = '\\';
00778 *r++ = '*';
00779 break;
00780 default:
00781 *r++ = *p;
00782 break;
00783
00784 }
00785 }
00786 *r++ = '$';
00787 *r++ = *p++;
00788 err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
00789 if ( err1 ) {
00790 char errmess[500];
00791 regerror(err1,&preg,errmess,sizeof(errmess));
00792 regfree(&preg);
00793 ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
00794 reg1, err1);
00795 return 0;
00796 }
00797 err1 = regexec(&preg, exten, 0, 0, 0);
00798 regfree(&preg);
00799
00800 if ( err1 ) {
00801
00802
00803 return 0;
00804 } else {
00805
00806
00807 return 1;
00808 }
00809
00810
00811 } else {
00812 if ( strcmp(exten,pattern) == 0 ) {
00813 return 1;
00814 } else
00815 return 0;
00816 }
00817 }
00818
00819
00820 static void check_expr2_input(pval *expr, char *str)
00821 {
00822 int spaces = strspn(str,"\t \n");
00823 if ( !strncmp(str+spaces,"$[",2) ) {
00824 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
00825 expr->filename, expr->startline, expr->endline, str);
00826 warns++;
00827 }
00828 }
00829
00830 static void check_includes(pval *includes)
00831 {
00832 struct pval *p4;
00833 for (p4=includes->u1.list; p4; p4=p4->next) {
00834
00835
00836 char *incl_context = p4->u1.str;
00837
00838 struct pval *that_other_context = find_context(incl_context);
00839 if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
00840 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
00841 (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
00842 includes->filename, includes->startline, includes->endline, incl_context, incl_context);
00843 warns++;
00844 }
00845 }
00846 }
00847
00848
00849 static void check_timerange(pval *p)
00850 {
00851 char *times;
00852 char *e;
00853 int s1, s2;
00854 int e1, e2;
00855
00856 times = ast_strdupa(p->u1.str);
00857
00858
00859 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
00860 return;
00861 }
00862
00863 e = strchr(times, '-');
00864 if (!e) {
00865 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",
00866 p->filename, p->startline, p->endline, times);
00867 warns++;
00868 return;
00869 }
00870 *e = '\0';
00871 e++;
00872 while (*e && !isdigit(*e))
00873 e++;
00874 if (!*e) {
00875 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
00876 p->filename, p->startline, p->endline, p->u1.str);
00877 warns++;
00878 }
00879 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
00880 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
00881 p->filename, p->startline, p->endline, times);
00882 warns++;
00883 }
00884 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
00885 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
00886 p->filename, p->startline, p->endline, times);
00887 warns++;
00888 }
00889
00890 s1 = s1 * 30 + s2/2;
00891 if ((s1 < 0) || (s1 >= 24*30)) {
00892 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
00893 p->filename, p->startline, p->endline, times);
00894 warns++;
00895 }
00896 e1 = e1 * 30 + e2/2;
00897 if ((e1 < 0) || (e1 >= 24*30)) {
00898 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
00899 p->filename, p->startline, p->endline, e);
00900 warns++;
00901 }
00902 return;
00903 }
00904
00905 static char *days[] =
00906 {
00907 "sun",
00908 "mon",
00909 "tue",
00910 "wed",
00911 "thu",
00912 "fri",
00913 "sat",
00914 };
00915
00916
00917 static void check_dow(pval *DOW)
00918 {
00919 char *dow;
00920 char *c;
00921
00922 int s, e;
00923
00924 dow = ast_strdupa(DOW->u1.str);
00925
00926
00927 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
00928 return;
00929
00930 c = strchr(dow, '-');
00931 if (c) {
00932 *c = '\0';
00933 c++;
00934 } else
00935 c = NULL;
00936
00937 s = 0;
00938 while ((s < 7) && strcasecmp(dow, days[s])) s++;
00939 if (s >= 7) {
00940 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",
00941 DOW->filename, DOW->startline, DOW->endline, dow);
00942 warns++;
00943 }
00944 if (c) {
00945 e = 0;
00946 while ((e < 7) && strcasecmp(c, days[e])) e++;
00947 if (e >= 7) {
00948 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",
00949 DOW->filename, DOW->startline, DOW->endline, c);
00950 warns++;
00951 }
00952 } else
00953 e = s;
00954 }
00955
00956 static void check_day(pval *DAY)
00957 {
00958 char *day;
00959 char *c;
00960
00961 int s, e;
00962
00963 day = ast_strdupa(DAY->u1.str);
00964
00965
00966 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
00967 return;
00968 }
00969
00970 c = strchr(day, '-');
00971 if (c) {
00972 *c = '\0';
00973 c++;
00974 }
00975
00976 if (sscanf(day, "%d", &s) != 1) {
00977 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
00978 DAY->filename, DAY->startline, DAY->endline, day);
00979 warns++;
00980 }
00981 else if ((s < 1) || (s > 31)) {
00982 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",
00983 DAY->filename, DAY->startline, DAY->endline, day);
00984 warns++;
00985 }
00986 s--;
00987 if (c) {
00988 if (sscanf(c, "%d", &e) != 1) {
00989 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
00990 DAY->filename, DAY->startline, DAY->endline, c);
00991 warns++;
00992 }
00993 else if ((e < 1) || (e > 31)) {
00994 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",
00995 DAY->filename, DAY->startline, DAY->endline, day);
00996 warns++;
00997 }
00998 e--;
00999 } else
01000 e = s;
01001 }
01002
01003 static char *months[] =
01004 {
01005 "jan",
01006 "feb",
01007 "mar",
01008 "apr",
01009 "may",
01010 "jun",
01011 "jul",
01012 "aug",
01013 "sep",
01014 "oct",
01015 "nov",
01016 "dec",
01017 };
01018
01019 static void check_month(pval *MON)
01020 {
01021 char *mon;
01022 char *c;
01023
01024 int s, e;
01025
01026 mon = ast_strdupa(MON->u1.str);
01027
01028
01029 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
01030 return ;
01031