53 |
static void rc_stmt_destroy(RC_STMT *stmt); |
static void rc_stmt_destroy(RC_STMT *stmt); |
54 |
static void rc_stmt_list_destroy(RC_STMT *stmt); |
static void rc_stmt_list_destroy(RC_STMT *stmt); |
55 |
static void rc_stmt_print(RC_STMT *stmt, int level); |
static void rc_stmt_print(RC_STMT *stmt, int level); |
56 |
static void reg_option_init(); |
static int reg_option_add(int *flag, char *opt); |
|
static int reg_option_add(char *opt); |
|
57 |
|
|
58 |
static RC_SECTION *rc_section; |
static RC_SECTION *rc_section; |
|
static int reg_opt; |
|
|
static int perlre; |
|
59 |
|
|
60 |
static int debug_level; |
static int debug_level; |
61 |
|
|
74 |
}; |
}; |
75 |
|
|
76 |
%token EOL T_BEGIN T_END AND OR EQ NE |
%token EOL T_BEGIN T_END AND OR EQ NE |
77 |
%token T_HEADER T_COMMAND IF FI ELSE RULE DONE |
%token T_HEADER T_COMMAND T_BODY IF FI ELSE RULE DONE |
78 |
%token <string> IDENT STRING REGEX D_BEGIN |
%token <string> IDENT STRING REGEX D_BEGIN |
79 |
|
|
80 |
%left OR |
%left OR |
81 |
%left AND |
%left AND |
82 |
|
%left NOT |
83 |
|
|
84 |
%type <string> begin keyword |
%type <string> begin keyword string option |
85 |
%type <section> section seclist |
%type <section> section seclist |
86 |
%type <stmtlist> stmtlist |
%type <stmtlist> stmtlist |
87 |
%type <stmt> stmt asgn_stmt cond_stmt rule_stmt |
%type <stmt> stmt asgn_stmt cond_stmt rule_stmt |
88 |
%type <cond> cond |
%type <num> part optlist |
89 |
%type <num> cond_lhs |
%type <node> rule_start cond expr |
|
%type <node> cond_rhs compat_rx_list rx_list regex rule_start |
|
|
%type <regex> compat_rx |
|
90 |
|
|
91 |
%% |
%% |
92 |
|
|
180 |
cond_stmt: if cond stmtlist fi |
cond_stmt: if cond stmtlist fi |
181 |
{ |
{ |
182 |
$$ = rc_stmt_create(rc_stmt_cond); |
$$ = rc_stmt_create(rc_stmt_cond); |
183 |
$$->v.cond = $2; |
$$->v.cond.node = $2; |
184 |
$$->v.cond.iftrue = $3.head; |
$$->v.cond.iftrue = $3.head; |
185 |
$$->v.cond.iffalse = NULL; |
$$->v.cond.iffalse = NULL; |
186 |
} |
} |
187 |
| if cond stmtlist else stmtlist fi |
| if cond stmtlist else stmtlist fi |
188 |
{ |
{ |
189 |
$$ = rc_stmt_create(rc_stmt_cond); |
$$ = rc_stmt_create(rc_stmt_cond); |
190 |
$$->v.cond = $2; |
$$->v.cond.node = $2; |
191 |
$$->v.cond.iftrue = $3.head; |
$$->v.cond.iftrue = $3.head; |
192 |
$$->v.cond.iffalse = $5.head; |
$$->v.cond.iffalse = $5.head; |
193 |
} |
} |
194 |
; |
; |
195 |
|
|
196 |
cond : cond_lhs { reg_option_init(); } optlist cond_rhs |
cond : expr |
197 |
|
| '(' cond ')' |
198 |
{ |
{ |
199 |
$$.method = $1; |
$$ = $2; |
|
$$.node = $4; |
|
200 |
} |
} |
201 |
; |
| cond AND cond |
|
|
|
|
cond_lhs : T_HEADER |
|
202 |
{ |
{ |
203 |
$$ = HEADER; |
$$ = rc_node_create(rc_node_bool); |
204 |
|
$$->v.bool.op = bool_and; |
205 |
|
$$->v.bool.left = $1; |
206 |
|
$$->v.bool.right = $3; |
207 |
} |
} |
208 |
| T_COMMAND |
| cond OR cond |
209 |
{ |
{ |
210 |
$$ = COMMAND; |
$$ = rc_node_create(rc_node_bool); |
211 |
|
$$->v.bool.op = bool_or; |
212 |
|
$$->v.bool.left = $1; |
213 |
|
$$->v.bool.right = $3; |
214 |
} |
} |
215 |
; |
| NOT cond |
|
|
|
|
optlist : /* empty */ |
|
|
| option |
|
|
| optlist option |
|
|
; |
|
|
|
|
|
option : ':' IDENT |
|
216 |
{ |
{ |
217 |
int rc = reg_option_add($2); |
$$ = rc_node_create(rc_node_bool); |
218 |
xfree($2); |
$$->v.bool.op = bool_not; |
219 |
if (rc) |
$$->v.bool.left = $2; |
220 |
YYERROR; |
$$->v.bool.right = NULL; |
221 |
} |
} |
222 |
; |
; |
223 |
|
|
224 |
cond_rhs : compat_rx_list |
expr : part '[' string ']' optlist string |
|
| rx_list |
|
|
; |
|
|
|
|
|
compat_rx_list: compat_rx |
|
225 |
{ |
{ |
226 |
$$ = rc_node_create(rc_node_re); |
$$ = rc_node_create(rc_node_expr); |
227 |
$$->v.re = $1; |
$$->v.expr.part = $1; |
228 |
|
$$->v.expr.key = $3; |
229 |
|
$$->v.expr.re = anubis_regex_compile($6, $5); |
230 |
} |
} |
231 |
| compat_rx_list compat_rx |
| part optlist string |
232 |
{ |
{ |
233 |
RC_NODE *node; |
$$ = rc_node_create(rc_node_expr); |
234 |
|
$$->v.expr.part = $1; |
235 |
node = rc_node_create(rc_node_bool); |
$$->v.expr.key = NULL; |
236 |
node->v.bool.op = bool_not; |
$$->v.expr.re = anubis_regex_compile($3, $2); |
|
node->v.bool.left = rc_node_create(rc_node_re); |
|
|
node->v.bool.left->v.re = $2; |
|
|
|
|
|
$$ = rc_node_create(rc_node_bool); |
|
|
$$->v.bool.op = bool_and; |
|
|
$$->v.bool.left = $1; |
|
|
$$->v.bool.right = node; |
|
237 |
} |
} |
238 |
; |
| T_BODY optlist string |
|
|
|
|
compat_rx: REGEX |
|
239 |
{ |
{ |
240 |
$$ = anubis_regex_compile($1, reg_opt); |
$$ = rc_node_create(rc_node_expr); |
241 |
if (!$$) |
$$->v.expr.part = BODY; |
242 |
YYERROR; |
$$->v.expr.key = NULL; |
243 |
|
$$->v.expr.re = anubis_regex_compile($3, $2); |
244 |
} |
} |
245 |
; |
; |
246 |
|
|
247 |
rx_list : regex |
part : T_HEADER |
|
| rx_list and regex |
|
248 |
{ |
{ |
249 |
$$ = rc_node_create(rc_node_bool); |
$$ = HEADER; |
|
$$->v.bool.op = bool_and; |
|
|
$$->v.bool.left = $1; |
|
|
$$->v.bool.right = $3; |
|
250 |
} |
} |
251 |
| rx_list or regex |
| T_COMMAND |
252 |
{ |
{ |
253 |
$$ = rc_node_create(rc_node_bool); |
$$ = COMMAND; |
|
$$->v.bool.op = bool_or; |
|
|
$$->v.bool.left = $1; |
|
|
$$->v.bool.right = $3; |
|
254 |
} |
} |
255 |
; |
; |
256 |
|
|
257 |
regex : '(' rx_list ')' |
optlist : /* empty */ |
258 |
{ |
{ |
259 |
$$ = $2; |
$$ = 0; |
260 |
} |
} |
261 |
| EQ STRING |
| option |
262 |
{ |
{ |
263 |
RC_REGEX *re = anubis_regex_compile($2, reg_opt); |
int rc; |
264 |
|
$$ = 0; |
265 |
if (!re) |
rc = reg_option_add(&$$, $1); |
266 |
|
xfree($1); |
267 |
|
if (rc) |
268 |
YYERROR; |
YYERROR; |
|
$$ = rc_node_create(rc_node_re); |
|
|
$$->v.re = re; |
|
269 |
} |
} |
270 |
| NE STRING |
| optlist option |
271 |
{ |
{ |
272 |
RC_REGEX *re = anubis_regex_compile($2, reg_opt); |
int rc = reg_option_add(&$1, $2); |
273 |
|
xfree($2); |
274 |
if (!re) |
if (rc) |
275 |
YYERROR; |
YYERROR; |
276 |
|
$$ = $1; |
|
$$ = rc_node_create(rc_node_bool); |
|
|
$$->v.bool.op = bool_not; |
|
|
$$->v.bool.left = rc_node_create(rc_node_re); |
|
|
$$->v.bool.left->v.re = re; |
|
|
$$->v.bool.right = NULL; |
|
277 |
} |
} |
278 |
; |
; |
279 |
|
|
280 |
and : /* empty */ |
option : ':' IDENT |
281 |
| AND |
{ |
282 |
; |
$$ = $2; |
283 |
|
} |
|
or : OR |
|
284 |
; |
; |
285 |
|
|
286 |
if : IF |
if : IF |
300 |
} |
} |
301 |
; |
; |
302 |
|
|
303 |
rule_start: RULE optlist cond_rhs |
rule_start: RULE optlist string |
304 |
{ |
{ |
305 |
$$ = $3; |
$$ = rc_node_create(rc_node_expr); |
306 |
|
$$->v.expr.part = HEADER; |
307 |
|
$$->v.expr.key = strdup(X_ANUBIS_RULE_HEADER); |
308 |
|
$$->v.expr.re = anubis_regex_compile($3, $2); |
309 |
} |
} |
310 |
; |
; |
311 |
|
|
312 |
|
string : STRING |
313 |
|
| IDENT |
314 |
|
; |
315 |
|
|
316 |
%% |
%% |
317 |
|
|
318 |
int |
int |
450 |
rc_bool_destroy(&node->v.bool); |
rc_bool_destroy(&node->v.bool); |
451 |
break; |
break; |
452 |
|
|
453 |
case rc_node_re: |
case rc_node_expr: |
454 |
anubis_regex_free(node->v.re); |
free(node->v.expr.key); |
455 |
|
anubis_regex_free(node->v.expr.re); |
456 |
} |
} |
457 |
xfree(node); |
xfree(node); |
458 |
} |
} |
459 |
|
|
460 |
|
static char * |
461 |
|
part_string(int part) |
462 |
|
{ |
463 |
|
switch (part) { |
464 |
|
case NIL: |
465 |
|
return "NIL"; |
466 |
|
case COMMAND: |
467 |
|
return "COMMAND"; |
468 |
|
case HEADER: |
469 |
|
return "HEADER"; |
470 |
|
case BODY: |
471 |
|
return "BODY"; |
472 |
|
default: |
473 |
|
return "UNKNOWN"; |
474 |
|
} |
475 |
|
} |
476 |
|
|
477 |
void |
void |
478 |
rc_node_print(RC_NODE *node) |
rc_node_print(RC_NODE *node) |
479 |
{ |
{ |
480 |
switch (node->type) { |
switch (node->type) { |
481 |
case rc_node_re: |
case rc_node_expr: |
482 |
printf("%s", anubis_regex_source(node->v.re)); |
printf("%s", part_string(node->v.expr.part)); |
483 |
|
if (node->v.expr.key && node->v.expr.key[0] != '\n') |
484 |
|
printf("[%s]",node->v.expr.key); |
485 |
|
printf(" %s", anubis_regex_source(node->v.expr.re)); |
486 |
break; |
break; |
487 |
|
|
488 |
case rc_node_bool: |
case rc_node_bool: |
619 |
} |
} |
620 |
} |
} |
621 |
|
|
|
|
|
|
void |
|
|
reg_option_init() |
|
|
{ |
|
|
reg_opt = 0; |
|
|
} |
|
|
|
|
622 |
int |
int |
623 |
reg_option_add(char *opt) |
reg_option_add(int *flag, char *opt) |
624 |
{ |
{ |
625 |
if (strcasecmp(opt, "basic") == 0) |
if (strcasecmp(opt, "basic") == 0) |
626 |
reg_opt |= R_BASIC; |
*flag |= R_BASIC; |
627 |
else if (strcasecmp(opt, "scase") == 0) |
else if (strcasecmp(opt, "scase") == 0) |
628 |
reg_opt |= R_SCASE; |
*flag |= R_SCASE; |
629 |
#ifdef HAVE_PCRE |
#ifdef HAVE_PCRE |
630 |
else if (strcasecmp(opt, "perlre") == 0) |
else if (strcasecmp(opt, "perlre") == 0) |
631 |
reg_opt |= R_PERLRE; |
*flag |= R_PERLRE; |
632 |
#endif |
#endif |
633 |
else { |
else { |
634 |
yyerror(_("Unknown regexp option")); |
yyerror(_("Unknown regexp option")); |
682 |
int method; |
int method; |
683 |
int cmp_method; |
int cmp_method; |
684 |
struct rc_secdef_child *child; |
struct rc_secdef_child *child; |
685 |
|
MESSAGE *msg; |
686 |
void *data; |
void *data; |
|
char *line; |
|
687 |
int refcnt; |
int refcnt; |
688 |
char **refstr; |
char **refstr; |
689 |
}; |
}; |
708 |
str = substitute(asgn->rhs, env->refstr); |
str = substitute(asgn->rhs, env->refstr); |
709 |
else |
else |
710 |
str = asgn->rhs; |
str = asgn->rhs; |
711 |
p->parser(env->method, key, str, env->data, p->data, env->line); |
p->parser(env->method, key, str, p->data, env->data, env->msg); |
712 |
|
} |
713 |
|
|
714 |
|
|
715 |
|
int |
716 |
|
re_eval_list(struct eval_env *env, char *key, RC_REGEX *re, struct list *list) |
717 |
|
{ |
718 |
|
ASSOC *p; |
719 |
|
int rc = 0; |
720 |
|
|
721 |
|
for (p = list_first(list); rc == 0 && p; p = list_next(list)) { |
722 |
|
if (!p->key || strcasecmp(p->key, key) == 0) |
723 |
|
rc = anubis_regex_match(re, p->value, |
724 |
|
&env->refcnt, &env->refstr); |
725 |
|
} |
726 |
|
return rc; |
727 |
|
} |
728 |
|
|
729 |
|
int |
730 |
|
re_eval_text(struct eval_env *env, RC_REGEX *re, char *text) |
731 |
|
{ |
732 |
|
/*FIXME*/ |
733 |
|
return anubis_regex_match(re, text, &env->refcnt, &env->refstr); |
734 |
|
} |
735 |
|
|
736 |
|
int |
737 |
|
expr_eval(struct eval_env *env, RC_EXPR *expr) |
738 |
|
{ |
739 |
|
int rc; |
740 |
|
|
741 |
|
if (env->refstr && anubis_regex_refcnt(expr->re)) { |
742 |
|
xfree_pptr(env->refstr); |
743 |
|
env->refstr = NULL; |
744 |
|
env->refcnt = 0; |
745 |
|
} |
746 |
|
|
747 |
|
switch (expr->part) { |
748 |
|
case COMMAND: |
749 |
|
rc = re_eval_list(env, expr->key, expr->re, |
750 |
|
env->msg->commands); |
751 |
|
break; |
752 |
|
|
753 |
|
case HEADER: |
754 |
|
rc = re_eval_list(env, expr->key, expr->re, env->msg->header); |
755 |
|
break; |
756 |
|
|
757 |
|
case BODY: |
758 |
|
rc = re_eval_text(env, expr->re, env->msg->body); |
759 |
|
break; |
760 |
|
|
761 |
|
default: |
762 |
|
abort(); |
763 |
|
} |
764 |
|
return rc; |
765 |
} |
} |
766 |
|
|
767 |
int |
int |
774 |
case rc_node_bool: |
case rc_node_bool: |
775 |
rc = bool_eval(env, &node->v.bool); |
rc = bool_eval(env, &node->v.bool); |
776 |
break; |
break; |
777 |
case rc_node_re: |
case rc_node_expr: |
778 |
if (env->refstr && anubis_regex_refcnt(node->v.re)) { |
rc = expr_eval(env, &node->v.expr); |
|
xfree_pptr(env->refstr); |
|
|
env->refstr = NULL; |
|
|
env->refcnt = 0; |
|
|
} |
|
|
rc = anubis_regex_match(node->v.re, env->line, |
|
|
&env->refcnt, &env->refstr); |
|
779 |
break; |
break; |
780 |
|
|
781 |
default: |
default: |
809 |
void |
void |
810 |
cond_eval(struct eval_env *env, RC_COND *cond) |
cond_eval(struct eval_env *env, RC_COND *cond) |
811 |
{ |
{ |
812 |
if (cond->method != env->cmp_method) |
if (node_eval(env, cond->node)) |
|
stmt_list_eval(env, cond->iffalse); |
|
|
else if (node_eval(env, cond->node)) |
|
813 |
stmt_list_eval(env, cond->iftrue); |
stmt_list_eval(env, cond->iftrue); |
814 |
else |
else |
815 |
stmt_list_eval(env, cond->iffalse); |
stmt_list_eval(env, cond->iffalse); |
818 |
void |
void |
819 |
rule_eval(struct eval_env *env, RC_RULE *rule) |
rule_eval(struct eval_env *env, RC_RULE *rule) |
820 |
{ |
{ |
821 |
if (env->cmp_method == HEADER && node_eval(env, rule->node)) |
if (node_eval(env, rule->node)) |
822 |
stmt_list_eval(env, rule->stmt); |
stmt_list_eval(env, rule->stmt); |
823 |
} |
} |
824 |
|
|
842 |
|
|
843 |
void |
void |
844 |
rc_run_section(int method, RC_SECTION *sec, struct rc_secdef *secdef, |
rc_run_section(int method, RC_SECTION *sec, struct rc_secdef *secdef, |
845 |
int cmp_method, char *line, void *data) |
void *data, MESSAGE *msg) |
846 |
{ |
{ |
847 |
if (!sec) |
if (!sec) |
848 |
return; |
return; |
850 |
if (strcmp(sec->name, secdef->name) == 0) { |
if (strcmp(sec->name, secdef->name) == 0) { |
851 |
struct eval_env env; |
struct eval_env env; |
852 |
env.method = method; |
env.method = method; |
|
env.cmp_method = cmp_method; |
|
853 |
env.child = secdef->child; |
env.child = secdef->child; |
|
env.line = line; |
|
854 |
env.refcnt = 0; |
env.refcnt = 0; |
855 |
env.refstr = NULL; |
env.refstr = NULL; |
856 |
|
env.msg = msg; |
857 |
env.data = data; |
env.data = data; |
858 |
|
|
859 |
stmt_list_eval(&env, sec->stmt); |
stmt_list_eval(&env, sec->stmt); |
870 |
rc_run_section_list(int method, RC_SECTION *sec, struct rc_secdef *secdef) |
rc_run_section_list(int method, RC_SECTION *sec, struct rc_secdef *secdef) |
871 |
{ |
{ |
872 |
for (; sec; sec = sec->next) |
for (; sec; sec = sec->next) |
873 |
rc_run_section(method, sec, secdef, NIL, NULL, NULL); |
rc_run_section(method, sec, secdef, NULL, NULL); |
874 |
} |
} |
875 |
|
|
876 |
|
|