Move matches and decision into struct mail so they get passed around automaticaly. Abstract the regexp stuff more.
Nicholas Marriott
17 years ago
19 | 19 | to account line |
20 | 20 | - handle multiple header instances when looking for users (other places?) |
21 | 21 | - fnmatch in find_header (don't forget ':') |
22 | - move pmatch etc into struct mail to avoid pointer nonsense? | |
23 | 22 | - add some of the other non-useless stuff reformail can do, if any |
24 | 23 | - write/append/pipe would benefit from add-from per stdout |
25 | 24 | - deliver to IMAP folder |
241 | 241 | for (;;) { |
242 | 242 | memset(&m, 0, sizeof m); |
243 | 243 | m.body = -1; |
244 | m.decision = DECISION_DROP; | |
244 | 245 | |
245 | 246 | memset(&mctx, 0, sizeof mctx); |
246 | 247 | mctx.io = io; |
247 | 248 | mctx.account = a; |
248 | 249 | mctx.mail = &m; |
249 | /* drop mail by default unless something else comes along */ | |
250 | mctx.decision = DECISION_DROP; | |
251 | 250 | |
252 | 251 | error = a->fetch->fetch(a, &m); |
253 | 252 | switch (error) { |
325 | 324 | case DECISION_NONE: |
326 | 325 | log_warnx("%s: reached end of ruleset. no " |
327 | 326 | "unmatched-mail option; keeping mail", a->name); |
328 | mctx.decision = DECISION_KEEP; | |
327 | m.decision = DECISION_KEEP; | |
329 | 328 | break; |
330 | 329 | case DECISION_KEEP: |
331 | 330 | log_debug("%s: reached end of ruleset. keeping mail", |
332 | 331 | a->name); |
333 | mctx.decision = DECISION_KEEP; | |
332 | m.decision = DECISION_KEEP; | |
334 | 333 | break; |
335 | 334 | case DECISION_DROP: |
336 | 335 | log_debug("%s: reached end of ruleset. dropping mail", |
337 | 336 | a->name); |
338 | mctx.decision = DECISION_DROP; | |
337 | m.decision = DECISION_DROP; | |
339 | 338 | break; |
340 | 339 | } |
341 | 340 | |
342 | 341 | done: |
343 | 342 | if (conf.keep_all || a->keep) |
344 | mctx.decision = DECISION_KEEP; | |
343 | m.decision = DECISION_KEEP; | |
345 | 344 | |
346 | 345 | /* finished with the message */ |
347 | switch (mctx.decision) { | |
346 | log_debug2("%s: finishing with mail: decision=%d", a->name, | |
347 | m.decision); | |
348 | switch (m.decision) { | |
348 | 349 | case DECISION_DROP: |
349 | 350 | log_debug("%s: deleting message", a->name); |
350 | 351 | if (a->fetch->delete != NULL) { |
462 | 463 | |
463 | 464 | /* tag mail if needed */ |
464 | 465 | if (r->key.str != NULL) { |
465 | tkey = replacestr(&r->key, | |
466 | m->tags, m, mctx->pm_valid, mctx->pm); | |
467 | tvalue = replacestr(&r->value, | |
468 | m->tags, m, mctx->pm_valid, mctx->pm); | |
466 | tkey = replacestr(&r->key, m->tags, m, &m->rml); | |
467 | tvalue = replacestr(&r->value, m->tags, m, &m->rml); | |
469 | 468 | |
470 | 469 | if (tkey != NULL && *tkey != '\0' && tvalue != NULL) { |
471 | 470 | log_debug2("%s: tagging message: %s (%s)", |
561 | 560 | |
562 | 561 | for (i = 0; i < ARRAY_LENGTH(r->actions); i++) { |
563 | 562 | rs = &ARRAY_ITEM(r->actions, i, struct replstr); |
564 | s = replacestr(rs, m->tags, m, mctx->pm_valid, mctx->pm); | |
563 | s = replacestr(rs, m->tags, m, &m->rml); | |
565 | 564 | |
566 | 565 | log_debug2("%s: looking for actions matching: %s", a->name, s); |
567 | 566 | ta = match_actions(s); |
612 | 611 | memset(&dctx, 0, sizeof dctx); |
613 | 612 | dctx.account = a; |
614 | 613 | dctx.mail = m; |
615 | dctx.decision = &mctx->decision; | |
616 | dctx.pm_valid = &mctx->pm_valid; | |
617 | memcpy(&dctx.pm, mctx->pm, sizeof dctx.pm); | |
618 | 614 | |
619 | 615 | if (t->deliver->deliver(&dctx, t) != DELIVER_SUCCESS) |
620 | 616 | return (1); |
657 | 653 | msg.data.action = t; |
658 | 654 | msg.data.uid = ARRAY_ITEM(users, i, uid_t); |
659 | 655 | |
660 | msg.data.pm_valid = mctx->pm_valid; | |
661 | memcpy(&msg.data.pm, mctx->pm, sizeof msg.data.pm); | |
662 | ||
663 | 656 | mail_send(m, &msg); |
664 | 657 | |
665 | 658 | if (privsep_send(mctx->io, &msg, m->tags, |
700 | 693 | /* and recreate the wrapped array */ |
701 | 694 | l = fill_wrapped(m); |
702 | 695 | log_debug2("%s: found %u wrapped lines", a->name, l); |
703 | ||
704 | /* invalidate the pmatch data since stuff may have moved */ | |
705 | mctx->pm_valid = 0; | |
706 | 696 | } |
707 | 697 | |
708 | 698 | if (find) |
39 | 39 | struct deliver_add_header_data *data = t->data; |
40 | 40 | char *hdr, *value; |
41 | 41 | |
42 | hdr = replacestr(&data->hdr, m->tags, m, *dctx->pm_valid, dctx->pm); | |
42 | hdr = replacestr(&data->hdr, m->tags, m, &m->rml); | |
43 | 43 | if (hdr == NULL || *hdr == '\0') { |
44 | 44 | if (hdr != NULL) |
45 | 45 | xfree(hdr); |
46 | 46 | log_warnx("%s: empty header", a->name); |
47 | 47 | return (DELIVER_FAILURE); |
48 | 48 | } |
49 | value = replacestr(&data->value, m->tags, m, *dctx->pm_valid, dctx->pm); | |
49 | value = replacestr(&data->value, m->tags, m, &m->rml); | |
50 | 50 | if (value == NULL) { |
51 | 51 | log_warnx("%s: bad value for header %s", a->name, hdr); |
52 | 52 | xfree(hdr); |
65 | 65 | ARRAY_FREE(&m->wrapped); |
66 | 66 | fill_wrapped(m); |
67 | 67 | |
68 | /* invalidate the pmatch data since stuff may have moved */ | |
69 | *dctx->pm_valid = 0; | |
68 | /* invalidate the match data since stuff may have moved */ | |
69 | m->rml.valid = 0; | |
70 | 70 | |
71 | 71 | xfree(hdr); |
72 | 72 | xfree(value); |
34 | 34 | int |
35 | 35 | deliver_drop_deliver(struct deliver_ctx *dctx, unused struct action *t) |
36 | 36 | { |
37 | *dctx->decision = DECISION_DROP; | |
37 | struct mail *m = dctx->mail; | |
38 | ||
39 | m->decision = DECISION_DROP; | |
38 | 40 | |
39 | 41 | return (DELIVER_SUCCESS); |
40 | 42 | } |
34 | 34 | int |
35 | 35 | deliver_keep_deliver(struct deliver_ctx *dctx, unused struct action *t) |
36 | 36 | { |
37 | *dctx->decision = DECISION_KEEP; | |
37 | struct mail *m = dctx->mail; | |
38 | ||
39 | m->decision = DECISION_KEEP; | |
38 | 40 | |
39 | 41 | return (DELIVER_SUCCESS); |
40 | 42 | } |
55 | 55 | size_t first, last; |
56 | 56 | gid_t gid; |
57 | 57 | |
58 | path = replacepath(&data->path, m->tags, m, *dctx->pm_valid, dctx->pm); | |
58 | path = replacepath(&data->path, m->tags, m, &m->rml); | |
59 | 59 | if (path == NULL || *path == '\0') { |
60 | 60 | log_warnx("%s: empty path", a->name); |
61 | 61 | goto out; |
75 | 75 | int res = DELIVER_FAILURE; |
76 | 76 | gzFile gzf = NULL; |
77 | 77 | |
78 | path = replacepath(&data->path, m->tags, m, *dctx->pm_valid, dctx->pm); | |
78 | path = replacepath(&data->path, m->tags, m, &m->rml); | |
79 | 79 | if (path == NULL || *path == '\0') { |
80 | 80 | if (path != NULL) |
81 | 81 | xfree(path); |
61 | 61 | char *lbuf; |
62 | 62 | size_t llen; |
63 | 63 | |
64 | s = replacepath(&data->cmd, m->tags, m, *dctx->pm_valid, dctx->pm); | |
64 | s = replacepath(&data->cmd, m->tags, m, &m->rml); | |
65 | 65 | if (s == NULL || *s == '\0') { |
66 | 66 | log_warnx("%s: empty command", a->name); |
67 | 67 | if (s != NULL) |
41 | 41 | size_t len, off, wrap; |
42 | 42 | u_int i; |
43 | 43 | |
44 | hdr = replacestr(&data->hdr, m->tags, m, *dctx->pm_valid, dctx->pm); | |
44 | hdr = replacestr(&data->hdr, m->tags, m, &m->rml); | |
45 | 45 | if (hdr == NULL || *hdr == '\0') { |
46 | 46 | if (hdr != NULL) |
47 | 47 | xfree(hdr); |
82 | 82 | } |
83 | 83 | } |
84 | 84 | |
85 | /* invalidate the pmatch data since stuff may have moved */ | |
86 | *dctx->pm_valid = 0; | |
85 | /* invalidate the match data since stuff may have moved */ | |
86 | m->rml.valid = 0; | |
87 | 87 | |
88 | 88 | set_wrapped(m, '\n'); |
89 | 89 | return (DELIVER_SUCCESS); |
51 | 51 | char *lbuf; |
52 | 52 | size_t llen; |
53 | 53 | |
54 | s = replacepath(&data->cmd, m->tags, m, *dctx->pm_valid, dctx->pm); | |
54 | s = replacepath(&data->cmd, m->tags, m, &m->rml); | |
55 | 55 | if (s == NULL || *s == '\0') { |
56 | 56 | log_warnx("%s: empty command", a->name); |
57 | 57 | if (s != NULL) |
86 | 86 | if (data->to.str == NULL) |
87 | 87 | to = xstrdup(from); |
88 | 88 | else { |
89 | to = replacestr(&data->to, m->tags, m, *dctx->pm_valid, | |
90 | dctx->pm); | |
89 | to = replacestr(&data->to, m->tags, m, &m->rml); | |
91 | 90 | if (to == NULL || *to == '\0') { |
92 | 91 | log_warnx("%s: empty to", a->name); |
93 | 92 | goto error; |
58 | 58 | char *path; |
59 | 59 | FILE *f; |
60 | 60 | |
61 | path = replacepath(&data->path, m->tags, m, *dctx->pm_valid, dctx->pm); | |
61 | path = replacepath(&data->path, m->tags, m, &m->rml); | |
62 | 62 | if (path == NULL || *path == '\0') { |
63 | 63 | if (path != NULL) |
64 | 64 | xfree(path); |
28 | 28 | struct mail *mail; |
29 | 29 | |
30 | 30 | struct mail wr_mail; |
31 | ||
32 | enum decision *decision; | |
33 | ||
34 | int *pm_valid; | |
35 | regmatch_t pm[NPMATCH]; | |
36 | 31 | }; |
37 | 32 | |
38 | 33 | /* Delivery types. */ |
325 | 325 | #define STRB_ENTSIZE(sb) ((sb)->ent_max * (sizeof (struct strbent))) |
326 | 326 | #define STRB_SIZE(sb) ((sizeof *(sb)) + (sb)->str_size + STRB_ENTSIZE((sb))) |
327 | 327 | |
328 | /* Regexp wrapper structs. */ | |
329 | struct re { | |
330 | char *str; | |
331 | regex_t re; | |
332 | int flags; | |
333 | }; | |
334 | ||
335 | struct rm { | |
336 | int valid; | |
337 | ||
338 | size_t so; | |
339 | size_t eo; | |
340 | }; | |
341 | ||
342 | struct rmlist { | |
343 | int valid; | |
344 | ||
345 | struct rm list[NPMATCH]; | |
346 | }; | |
347 | ||
348 | /* Regexp flags. */ | |
349 | #define RE_ICASE 0x1 | |
350 | #define RE_NOSUB 0x2 | |
351 | ||
328 | 352 | /* A single mail. */ |
329 | 353 | struct mail { |
330 | 354 | struct strb *tags; |
345 | 369 | ARRAY_DECL(, size_t *) wrapped; /* list of wrapped lines */ |
346 | 370 | |
347 | 371 | ssize_t body; /* offset of body */ |
372 | ||
373 | struct rmlist rml; /* regexp matches */ | |
374 | enum decision decision; /* final deliver decision */ | |
348 | 375 | }; |
349 | 376 | |
350 | 377 | /* An attachment. */ |
362 | 389 | TAILQ_HEAD(, attach) children; |
363 | 390 | |
364 | 391 | TAILQ_ENTRY(attach) entry; |
365 | }; | |
366 | ||
367 | /* Regexp wrapper struct. */ | |
368 | struct re { | |
369 | char *str; | |
370 | regex_t re; | |
371 | 392 | }; |
372 | 393 | |
373 | 394 | /* A single child. */ |
620 | 641 | struct msgdata { |
621 | 642 | int error; |
622 | 643 | struct mail mail; |
623 | ||
624 | int pm_valid; | |
625 | regmatch_t pm[NPMATCH]; | |
626 | 644 | |
627 | 645 | /* these only work so long as they aren't moved in either process */ |
628 | 646 | struct account *account; |
710 | 728 | |
711 | 729 | /* re.c */ |
712 | 730 | int re_compile(struct re *, char *, int, char **); |
713 | int re_execute(struct re *, char *, int, regmatch_t *, | |
714 | int, char **); | |
731 | int re_string(struct re *, char *, struct rmlist *, | |
732 | char **); | |
733 | int re_block(struct re *, void *, size_t, struct rmlist *, | |
734 | char **); | |
715 | 735 | int re_simple(struct re *, char *, char **); |
716 | 736 | void re_free(struct re *); |
717 | 737 | |
803 | 823 | const char *match_tag(struct strb *, const char *); |
804 | 824 | void default_tags(struct strb **, char *, struct account *); |
805 | 825 | void update_tags(struct strb **); |
806 | char *replace(char *, struct strb *, struct mail *, int, | |
807 | regmatch_t [NPMATCH]); | |
826 | char *replace(char *, struct strb *, struct mail *, | |
827 | struct rmlist *); | |
808 | 828 | char *replacestr(struct replstr *, struct strb *, |
809 | struct mail *, int, regmatch_t [NPMATCH]); | |
829 | struct mail *, struct rmlist *); | |
810 | 830 | char *replacepath(struct replpath *, struct strb *, |
811 | struct mail *, int, regmatch_t [NPMATCH]); | |
831 | struct mail *, struct rmlist *); | |
812 | 832 | |
813 | 833 | /* io.c */ |
814 | 834 | struct io *io_create(int, SSL *, const char *, int); |
106 | 106 | return (MATCH_FALSE); |
107 | 107 | |
108 | 108 | /* for any type or name matches, construct the value */ |
109 | if (data->op == ATTACHOP_ANYTYPE || data->op == ATTACHOP_ANYNAME) { | |
110 | value = replacestr(&data->value.str, | |
111 | m->tags, m, mctx->pm_valid, mctx->pm); | |
112 | } | |
109 | if (data->op == ATTACHOP_ANYTYPE || data->op == ATTACHOP_ANYNAME) | |
110 | value = replacestr(&data->value.str, m->tags, m, &m->rml); | |
113 | 111 | |
114 | 112 | at = m->attach; |
115 | 113 | while (at != NULL) { |
50 | 50 | msg.data.cmddata = data; |
51 | 51 | msg.data.uid = data->uid; |
52 | 52 | |
53 | msg.data.pm_valid = mctx->pm_valid; | |
54 | memcpy(&msg.data.pm, mctx->pm, sizeof msg.data.pm); | |
55 | ||
56 | 53 | mail_send(m, &msg); |
57 | 54 | |
58 | 55 | if (privsep_send(io, &msg, m->tags, STRB_SIZE(m->tags)) != 0) |
38 | 38 | struct mail *m = mctx->mail; |
39 | 39 | int res; |
40 | 40 | char *cause; |
41 | size_t so, eo; | |
41 | 42 | |
42 | if (data->area == AREA_BODY && m->body == -1) | |
43 | return (MATCH_FALSE); | |
44 | ||
43 | so = 0; | |
44 | eo = m->size; | |
45 | 45 | switch (data->area) { |
46 | 46 | case AREA_HEADERS: |
47 | mctx->pm[0].rm_so = 0; | |
48 | if (m->body == -1) | |
49 | mctx->pm[0].rm_eo = m->size; | |
50 | else | |
51 | mctx->pm[0].rm_eo = m->body; | |
47 | if (m->body != -1) | |
48 | eo = m->body; | |
52 | 49 | break; |
53 | 50 | case AREA_BODY: |
54 | mctx->pm[0].rm_so = m->body; | |
55 | mctx->pm[0].rm_eo = m->size; | |
51 | if (m->body == -1) | |
52 | return (MATCH_FALSE); | |
53 | so = m->body; | |
56 | 54 | break; |
57 | 55 | case AREA_ANY: |
58 | mctx->pm[0].rm_so = 0; | |
59 | mctx->pm[0].rm_eo = m->size; | |
60 | 56 | break; |
61 | 57 | } |
62 | 58 | |
63 | res = re_execute(&data->re, m->data, NPMATCH, mctx->pm, REG_STARTEND, | |
64 | &cause); | |
59 | res = re_block(&data->re, m->data + so, eo - so, &m->rml, &cause); | |
65 | 60 | if (res == -1) { |
66 | 61 | log_warnx("%s: %s", a->name, cause); |
67 | 62 | xfree(cause); |
68 | 63 | return (MATCH_ERROR); |
69 | 64 | } |
70 | ||
71 | mctx->pm_valid = 1; | |
72 | 65 | if (res == 0) |
73 | 66 | return (MATCH_FALSE); |
74 | 67 | return (MATCH_TRUE); |
40 | 40 | int res; |
41 | 41 | char *s, *cause; |
42 | 42 | |
43 | s = replacestr(&data->str, m->tags, m, mctx->pm_valid, mctx->pm); | |
43 | s = replacestr(&data->str, m->tags, m, &m->rml); | |
44 | 44 | log_debug2("%s: matching \"%s\" to \"%s\"", a->name, s, data->re.str); |
45 | 45 | |
46 | 46 | res = re_simple(&data->re, s, &cause); |
38 | 38 | struct mail *m = mctx->mail; |
39 | 39 | char *tag; |
40 | 40 | |
41 | tag = replacestr(&data->tag, m->tags, m, mctx->pm_valid, mctx->pm); | |
41 | tag = replacestr(&data->tag, m->tags, m, &m->rml); | |
42 | 42 | if (match_tag(m->tags, tag) != NULL) { |
43 | 43 | xfree(tag); |
44 | 44 | return (MATCH_TRUE); |
29 | 29 | struct account *account; |
30 | 30 | struct mail *mail; |
31 | 31 | |
32 | enum decision decision; | |
33 | ||
34 | 32 | int matched; |
35 | 33 | int stopped; |
36 | ||
37 | int pm_valid; | |
38 | regmatch_t pm[NPMATCH]; | |
39 | 34 | }; |
40 | 35 | |
41 | 36 | /* Match functions. */ |
64 | 64 | memset(dctx, 0, sizeof dctx); |
65 | 65 | dctx->account = msg->data.account; |
66 | 66 | dctx->mail = m; |
67 | dctx->decision = NULL; /* only altered in child */ | |
68 | dctx->pm_valid = &msg->data.pm_valid; | |
69 | memcpy(&dctx->pm, &msg->data.pm, sizeof dctx->pm); | |
70 | 67 | } |
71 | 68 | |
72 | 69 | if (mctx != NULL) { |
73 | 70 | memset(mctx, 0, sizeof mctx); |
74 | 71 | mctx->account = msg->data.account; |
75 | 72 | mctx->mail = m; |
76 | mctx->decision = DECISION_NONE; /* only altered in child */ | |
77 | mctx->pm_valid = msg->data.pm_valid; | |
78 | memcpy(&mctx->pm, &msg->data.pm, sizeof mctx->pm); | |
79 | 73 | } |
80 | 74 | } |
81 | 75 | |
282 | 276 | if (geteuid() == 0 && |
283 | 277 | fchown(md->shm.fd, conf.child_uid, conf.child_gid) != 0) |
284 | 278 | fatal("fchown"); |
279 | md->decision = m->decision; | |
285 | 280 | } |
286 | 281 | |
287 | 282 | if (parent_child(a, |
360 | 355 | char *s, *cause, *lbuf, *out, *err, tag[24]; |
361 | 356 | size_t llen; |
362 | 357 | struct cmd *cmd = NULL; |
363 | regmatch_t pm[NPMATCH]; | |
358 | struct rmlist rml; | |
364 | 359 | u_int i; |
365 | 360 | |
366 | 361 | /* if this is the parent, do nothing */ |
368 | 363 | return (0); |
369 | 364 | |
370 | 365 | /* sort out the command */ |
371 | s = replacepath(&data->cmd, m->tags, m, mctx->pm_valid, mctx->pm); | |
366 | s = replacepath(&data->cmd, m->tags, m, &m->rml); | |
372 | 367 | if (s == NULL || *s == '\0') { |
373 | 368 | log_warnx("%s: empty command", a->name); |
374 | 369 | goto error; |
406 | 401 | if (found) /* XXX stop early? */ |
407 | 402 | continue; |
408 | 403 | |
409 | found = re_execute(&data->re, out, NPMATCH, pm, 0, &cause); | |
404 | found = re_string(&data->re, out, &rml, &cause); | |
410 | 405 | if (found == -1) { |
411 | 406 | log_warnx("%s: %s", a->name, cause); |
412 | 407 | goto error; |
413 | 408 | } |
414 | 409 | if (found != 1) |
415 | 410 | continue; |
416 | /* save the pmatch */ | |
411 | /* save the matches */ | |
412 | if (!rml.valid) | |
413 | continue; | |
417 | 414 | for (i = 0; i < NPMATCH; i++) { |
418 | if (pm[i].rm_so >= pm[i].rm_eo) | |
419 | continue; | |
415 | if (!rml.list[i].valid) | |
416 | break; | |
420 | 417 | xsnprintf(tag, sizeof tag, "command%u", i); |
421 | add_tag(&m->tags, tag, "%.*s", (int) (pm[i].rm_eo - | |
422 | pm[i].rm_so), out + pm[i].rm_so); | |
418 | add_tag(&m->tags, tag, "%.*s", (int) (rml.list[i].eo - | |
419 | rml.list[i].so), out + rml.list[i].so); | |
423 | 420 | } |
424 | 421 | } while (status >= 0); |
425 | 422 | status = -1 - status; |
740 | 740 | } |
741 | 741 | |
742 | 742 | rs.str = $1; |
743 | $$ = replacestr(&rs, parse_tags, NULL, 0, NULL); | |
743 | $$ = replacestr(&rs, parse_tags, NULL, NULL); | |
744 | 744 | xfree($1); |
745 | 745 | } |
746 | 746 | |
754 | 754 | } |
755 | 755 | |
756 | 756 | rp.str = $1; |
757 | $$ = replacepath(&rp, parse_tags, NULL, 0, NULL); | |
757 | $$ = replacepath(&rp, parse_tags, NULL, NULL); | |
758 | 758 | xfree($1); |
759 | 759 | } |
760 | 760 | |
1897 | 1897 | |
1898 | 1898 | data->area = $4; |
1899 | 1899 | |
1900 | flags = REG_EXTENDED|REG_NEWLINE; | |
1900 | flags = 0; | |
1901 | 1901 | if ($2) |
1902 | flags |= REG_ICASE; | |
1902 | flags |= RE_ICASE; | |
1903 | 1903 | if (re_compile(&data->re, $3, flags, &cause) != 0) |
1904 | 1904 | yyerror("%s", cause); |
1905 | 1905 | xfree($3); |
1931 | 1931 | data->ret = $7; |
1932 | 1932 | |
1933 | 1933 | if ($9 != NULL) { |
1934 | flags = REG_EXTENDED|REG_NEWLINE; | |
1935 | if (re_compile(&data->re, $9, flags, &cause) != 0) | |
1934 | if (re_compile(&data->re, $9, 0, &cause) != 0) | |
1936 | 1935 | yyerror("%s", cause); |
1937 | 1936 | xfree($9); |
1938 | 1937 | } |
1981 | 1980 | /** [$1: not (int)] [$3: strv (char *)] [$5: strv (char *)] */ |
1982 | 1981 | { |
1983 | 1982 | struct match_string_data *data; |
1984 | int flags; | |
1985 | 1983 | char *cause; |
1986 | 1984 | |
1987 | 1985 | if (*$3 == '\0') |
1997 | 1995 | |
1998 | 1996 | data->str.str = $3; |
1999 | 1997 | |
2000 | flags = REG_EXTENDED|REG_NOSUB|REG_NEWLINE; | |
2001 | if (re_compile(&data->re, $5, flags, &cause) != 0) | |
1998 | if (re_compile(&data->re, $5, RE_NOSUB, &cause) != 0) | |
2002 | 1999 | yyerror("%s", cause); |
2003 | 2000 | xfree($5); |
2004 | 2001 | } |
17 | 17 | |
18 | 18 | #include <sys/types.h> |
19 | 19 | |
20 | #include <string.h> | |
21 | ||
20 | 22 | #include "fdm.h" |
21 | 23 | |
22 | 24 | int |
26 | 28 | size_t len; |
27 | 29 | char *buf; |
28 | 30 | |
29 | if (s == NULL) { | |
30 | *cause = xstrdup("invalid regexp"); | |
31 | return (1); | |
32 | } | |
31 | if (s == NULL) | |
32 | fatalx("re_compile: null regexp"); | |
33 | 33 | re->str = xstrdup(s); |
34 | 34 | if (*s == '\0') |
35 | 35 | return (0); |
36 | re->flags = flags; | |
37 | ||
38 | flags = REG_EXTENDED|REG_NEWLINE; | |
39 | if (re->flags & RE_NOSUB) | |
40 | flags |= REG_NOSUB; | |
41 | if (re->flags & RE_ICASE) | |
42 | flags |= REG_ICASE; | |
36 | 43 | |
37 | 44 | if ((error = regcomp(&re->re, s, flags)) != 0) { |
38 | 45 | len = regerror(error, &re->re, NULL, 0); |
46 | 53 | } |
47 | 54 | |
48 | 55 | int |
49 | re_execute(struct re *re, char *s, int npm, regmatch_t *pm, int flags, | |
50 | char **cause) | |
56 | re_string(struct re *re, char *s, struct rmlist *rml, char **cause) | |
51 | 57 | { |
52 | int res; | |
58 | int res; | |
59 | regmatch_t pm[NPMATCH]; | |
60 | u_int i; | |
61 | ||
62 | if (re->flags & RE_NOSUB) { | |
63 | if (rml != NULL) | |
64 | fatalx("re_string: nosub re but rml != NULL"); | |
65 | } else { | |
66 | if (rml == NULL) | |
67 | fatalx("re_string: !nosub re but rml == NULL"); | |
68 | } | |
69 | ||
70 | if (rml != NULL) | |
71 | memset(rml, 0, NPMATCH * (sizeof *rml)); | |
53 | 72 | |
54 | 73 | /* |
55 | 74 | * If the source string is empty, there is no regexp, so just check |
61 | 80 | return (0); |
62 | 81 | } |
63 | 82 | |
64 | res = regexec(&re->re, s, npm, pm, flags); | |
83 | res = regexec(&re->re, s, NPMATCH, pm, 0); | |
65 | 84 | if (res != 0 && res != REG_NOMATCH) { |
66 | 85 | xasprintf(cause, "%s: regexec failed", re->str); |
67 | 86 | return (-1); |
87 | } else | |
88 | ||
89 | if (rml != NULL) { | |
90 | for (i = 0; i < NPMATCH; i++) { | |
91 | if (pm[i].rm_eo <= pm[i].rm_so) | |
92 | break; | |
93 | rml->list[i].valid = 1; | |
94 | rml->list[i].so = pm[i].rm_so; | |
95 | rml->list[i].eo = pm[i].rm_eo; | |
96 | } | |
97 | rml->valid = 1; | |
68 | 98 | } |
69 | 99 | |
70 | if (res == 0) | |
71 | return (1); | |
72 | return (0); | |
100 | return (res == 0); | |
101 | } | |
102 | ||
103 | int | |
104 | re_block(struct re *re, void *buf, size_t len, struct rmlist *rml, char **cause) | |
105 | { | |
106 | int res; | |
107 | regmatch_t pm[NPMATCH]; | |
108 | u_int i; | |
109 | ||
110 | if (re->flags & RE_NOSUB) { | |
111 | if (rml != NULL) | |
112 | fatalx("re_string: nosub re but rml != NULL"); | |
113 | } else { | |
114 | if (rml == NULL) | |
115 | fatalx("re_string: !nosub re but rml == NULL"); | |
116 | } | |
117 | ||
118 | if (rml != NULL) | |
119 | memset(rml, 0, sizeof *rml); | |
120 | ||
121 | /* If the regexp is empty, just check whether the buffer is empty. */ | |
122 | if (*re->str == '\0') { | |
123 | if (len == 0) | |
124 | return (1); | |
125 | return (0); | |
126 | } | |
127 | ||
128 | pm[0].rm_so = 0; | |
129 | pm[0].rm_eo = len; | |
130 | res = regexec(&re->re, buf, NPMATCH, pm, REG_STARTEND); | |
131 | if (res != 0 && res != REG_NOMATCH) { | |
132 | xasprintf(cause, "%s: regexec failed", re->str); | |
133 | return (-1); | |
134 | } else | |
135 | ||
136 | if (rml != NULL) { | |
137 | for (i = 0; i < NPMATCH; i++) { | |
138 | if (pm[i].rm_eo <= pm[i].rm_so) | |
139 | break; | |
140 | rml->list[i].valid = 1; | |
141 | rml->list[i].so = pm[i].rm_so; | |
142 | rml->list[i].eo = pm[i].rm_eo; | |
143 | } | |
144 | rml->valid = 1; | |
145 | } | |
146 | ||
147 | return (res == 0); | |
73 | 148 | } |
74 | 149 | |
75 | 150 | int |
76 | 151 | re_simple(struct re *re, char *s, char **cause) |
77 | 152 | { |
78 | return (re_execute(re, s, 0, NULL, 0, cause)); | |
153 | return (re_string(re, s, NULL, cause)); | |
79 | 154 | } |
80 | 155 | |
81 | 156 | void |
158 | 158 | |
159 | 159 | char * |
160 | 160 | replacestr(struct replstr *rs, struct strb *tags, struct mail *m, |
161 | int pm_valid, regmatch_t pm[NPMATCH]) | |
162 | { | |
163 | return (replace(rs->str, tags, m, pm_valid, pm)); | |
161 | struct rmlist *rml) | |
162 | { | |
163 | return (replace(rs->str, tags, m, rml)); | |
164 | 164 | } |
165 | 165 | |
166 | 166 | char * |
167 | 167 | replacepath(struct replpath *rp, struct strb *tags, struct mail *m, |
168 | int pm_valid, regmatch_t pm[NPMATCH]) | |
168 | struct rmlist *rml) | |
169 | 169 | { |
170 | 170 | char *s, *ss; |
171 | 171 | |
172 | s = replace(rp->str, tags, m, pm_valid, pm); | |
172 | s = replace(rp->str, tags, m, rml); | |
173 | 173 | ss = expand_path(s); |
174 | 174 | if (ss == NULL) |
175 | 175 | return (s); |
178 | 178 | } |
179 | 179 | |
180 | 180 | char * |
181 | replace(char *src, struct strb *tags, struct mail *m, int pm_valid, | |
182 | regmatch_t pm[NPMATCH]) | |
181 | replace(char *src, struct strb *tags, struct mail *m, struct rmlist *rml) | |
183 | 182 | { |
184 | 183 | char *ptr, *tend; |
185 | 184 | const char *tptr, *alias; |
236 | 235 | break; |
237 | 236 | default: |
238 | 237 | if (ch >= '0' && ch <= '9') { |
239 | if (!pm_valid || m == NULL || pm == NULL) | |
238 | if (rml == NULL || !rml->valid || m == NULL) | |
240 | 239 | continue; |
241 | 240 | idx = ((u_char) ch) - '0'; |
242 | if (pm[idx].rm_so >= pm[idx].rm_eo) | |
241 | if (!rml->list[idx].valid) | |
243 | 242 | continue; |
244 | 243 | |
245 | tptr = m->base + pm[idx].rm_so; | |
246 | tlen = pm[idx].rm_eo - pm[idx].rm_so; | |
244 | tptr = m->base + rml->list[idx].so; | |
245 | tlen = rml->list[idx].eo - rml->list[idx].so; | |
247 | 246 | break; |
248 | 247 | } |
249 | 248 |