Codebase list fdm / f60b425
Allow actions to chain other actions. Also clean up some replstr stuff and remove a few leftover bits. Nicholas Marriott 17 years ago
6 changed file(s) with 173 addition(s) and 64 deletion(s). Raw diff Collapse all Expand all
00 04 May 2007
11
22 * "match tag ..." is now not supported.
3 * Permit actions to call other actions:
4
5 action "one" ...
6 action "two" ...
7 action "three" {
8 ...
9 actions { "one" "two" }
10 }
11
12 A maximum of five levels is permitted, spoiling the
13
14 action "x" { action "x" }
15
16 fun.
317
418 30 April 2007
519
3030 - fetch smallest/largest mails first. best pattern? probably 1 small, then in
3131 decreasing size order, but with longer queue necessary
3232 - document set verify-certificates/no-verify (http://cvs.mirbsd.de/src/etc/ssl.certs.shar)
33 - document chained actions
126126 struct replstr value;
127127 };
128128
129 /* Deliver action data. */
130 struct deliver_action_data {
131 struct replstrs *actions;
132 };
133
129134 /* deliver-smtp.c */
130135 extern struct deliver deliver_smtp;
131136
4949 #define DEFMAILQUEUE 2
5050 #define DEFMAILSIZE (32 * 1024 * 1024) /* 32 MB */
5151 #define MAXMAILSIZE IO_MAXBUFFERLEN
52 #define MAXACTIONCHAIN 5
5253 #define DEFTIMEOUT (900 * 1000)
5354 #define LOCKSLEEPTIME 10000
5455 #define LOCKRETRIES 1000
256257 */
257258 struct replstr {
258259 char *str;
259 };
260 } __packed;
260261 ARRAY_DECL(replstrs, struct replstr);
261262
262263 /* Similar to replstr but needs expand_path too. */
263264 struct replpath {
264265 char *str;
265 };
266 } __packed;
266267
267268 /* Server description. */
268269 struct server {
826827 extern struct macros macros;
827828 struct users *weed_users(struct users *);
828829 struct strings *weed_strings(struct strings *);
830 void free_replstrs(struct replstrs *);
831 char *fmt_replstrs(const char *, struct replstrs *);
829832 void free_strings(struct strings *);
830833 char *fmt_strings(const char *, struct strings *);
831834 char *fmt_users(const char *, struct users *);
2828 void apply_result(struct expritem *, int *, int);
2929
3030 struct users *find_delivery_users(struct mail_ctx *, struct action *, int *);
31 int fill_delivery_queue(struct mail_ctx *, struct rule *);
32 void fill_delivery_action(struct mail_ctx *, struct rule *,
31 int fill_from_strings(struct mail_ctx *, struct rule *,
32 struct replstrs *);
33 int fill_from_string(struct mail_ctx *, struct rule *,
34 struct replstr *);
35 int fill_from_action(struct mail_ctx *, struct rule *,
3336 struct action *, struct users *);
3437
3538 int start_action(struct mail_ctx *, struct deliver_ctx *);
3942 #define ACTION_DONE 0
4043 #define ACTION_ERROR 1
4144 #define ACTION_PARENT 2
45
46 /*
47 * Number of chained actions. Limit on recursion with things like:
48 *
49 * action "name" { action "name" }
50 */
51 u_int chained;
4252
4353 int
4454 mail_match(struct mail_ctx *mctx, struct msg *msg, struct msgbuf *msgbuf)
242252 if (mctx->rule->lambda != NULL) {
243253 users = find_delivery_users(mctx, NULL, &should_free);
244254
245 fill_delivery_action(mctx,
246 mctx->rule, mctx->rule->lambda, users);
255 chained = MAXACTIONCHAIN;
256 if (fill_from_action(mctx,
257 mctx->rule, mctx->rule->lambda, users) != 0) {
258 if (should_free)
259 ARRAY_FREEALL(users);
260 return (MAIL_ERROR);
261 }
247262
248263 if (should_free)
249264 ARRAY_FREEALL(users);
254269 * Fill the delivery action queue.
255270 */
256271 if (!ARRAY_EMPTY(mctx->rule->actions)) {
257 if (fill_delivery_queue(mctx, mctx->rule) != 0)
272 chained = MAXACTIONCHAIN;
273 if (fill_from_strings(mctx,
274 mctx->rule, mctx->rule->actions) != 0)
258275 return (MAIL_ERROR);
259276 error = MAIL_DELIVER;
260277 }
397414 }
398415
399416 int
400 fill_delivery_queue(struct mail_ctx *mctx, struct rule *r)
401 {
402 struct account *a = mctx->account;
403 struct mail *m = mctx->mail;
404 struct action *t;
405 struct actions *ta;
406 u_int i, j;
407 char *s;
408 struct replstr *rs;
409 struct users *users;
410 int should_free;
411
412 for (i = 0; i < ARRAY_LENGTH(r->actions); i++) {
413 rs = &ARRAY_ITEM(r->actions, i, struct replstr);
414 s = replacestr(rs, m->tags, m, &m->rml);
415
416 log_debug2("%s: looking for actions matching: %s", a->name, s);
417 ta = match_actions(s);
418 if (ARRAY_EMPTY(ta))
419 goto empty;
420 xfree(s);
421
422 log_debug2("%s: found %u actions", a->name, ARRAY_LENGTH(ta));
423 for (j = 0; j < ARRAY_LENGTH(ta); j++) {
424 t = ARRAY_ITEM(ta, j, struct action *);
425 users = find_delivery_users(mctx, t, &should_free);
426
427 fill_delivery_action(mctx, r, t, users);
428
417 fill_from_strings(struct mail_ctx *mctx, struct rule *r, struct replstrs *rsa)
418 {
419 struct account *a = mctx->account;
420 u_int i;
421 struct replstr *rs;
422
423 chained--;
424 if (chained == 0) {
425 log_warnx("%s: too many chained actions", a->name);
426 return (1);
427 }
428
429 for (i = 0; i < ARRAY_LENGTH(rsa); i++) {
430 rs = &ARRAY_ITEM(rsa, i, struct replstr);
431 if (fill_from_string(mctx, r, rs) != 0)
432 return (1);
433 }
434
435 return (0);
436 }
437
438 int
439 fill_from_string(struct mail_ctx *mctx, struct rule *r, struct replstr *rs)
440 {
441 struct account *a = mctx->account;
442 struct mail *m = mctx->mail;
443 struct action *t;
444 struct actions *ta;
445 u_int i;
446 char *s;
447 struct users *users;
448 int should_free;
449
450 s = replacestr(rs, m->tags, m, &m->rml);
451
452 log_debug2("%s: looking for actions matching: %s", a->name, s);
453 ta = match_actions(s);
454 if (ARRAY_EMPTY(ta))
455 goto empty;
456 xfree(s);
457
458 log_debug2("%s: found %u actions", a->name, ARRAY_LENGTH(ta));
459 for (i = 0; i < ARRAY_LENGTH(ta); i++) {
460 t = ARRAY_ITEM(ta, i, struct action *);
461 users = find_delivery_users(mctx, t, &should_free);
462
463 if (fill_from_action(mctx, r, t, users) != 0) {
429464 if (should_free)
430465 ARRAY_FREEALL(users);
431 }
432
433 ARRAY_FREEALL(ta);
434 }
435
466 ARRAY_FREEALL(ta);
467 return (1);
468 }
469
470 if (should_free)
471 ARRAY_FREEALL(users);
472 }
473
474 ARRAY_FREEALL(ta);
436475 return (0);
437476
438477 empty:
478 log_warnx("%s: no actions matching: %s (%s)", a->name, s, rs->str);
439479 xfree(s);
440480 ARRAY_FREEALL(ta);
441 log_warnx("%s: no actions matching: %s (%s)", a->name, s, rs->str);
442481 return (1);
443
444 }
445
446 void
447 fill_delivery_action(struct mail_ctx *mctx, struct rule *r, struct action *t,
482 }
483
484 int
485 fill_from_action(struct mail_ctx *mctx, struct rule *r, struct action *t,
448486 struct users *users)
449487 {
450 struct account *a = mctx->account;
451 struct mail *m = mctx->mail;
452 struct actitem *ti;
453 struct deliver_ctx *dctx;
454 u_int i;
488 struct account *a = mctx->account;
489 struct mail *m = mctx->mail;
490 struct deliver_action_data *data;
491 struct actitem *ti;
492 struct deliver_ctx *dctx;
493 u_int i;
455494
456495 for (i = 0; i < ARRAY_LENGTH(users); i++) {
457496 TAILQ_FOREACH(ti, t->list, entry) {
497 if (ti->deliver == NULL) {
498 data = ti->data;
499 if (fill_from_strings(mctx, r,
500 data->actions) != 0)
501 return (1);
502 continue;
503 }
504
458505 dctx = xcalloc(1, sizeof *dctx);
459506 dctx->action = t;
460507 dctx->actitem = ti;
469516 TAILQ_INSERT_TAIL(&mctx->dqueue, dctx, entry);
470517 }
471518 }
519
520 return (0);
472521 }
473522
474523 int
186186 }
187187
188188 return (up);
189 }
190
191 char *
192 fmt_replstrs(const char *prefix, struct replstrs *rsp)
193 {
194 return (fmt_strings(prefix, (struct strings *) rsp)); /* XXX */
195 }
196
197 void
198 free_replstrs(struct replstrs *rsp)
199 {
200 return (free_strings((struct strings *) rsp)); /* XXX */
189201 }
190202
191203 char *
389401 log_debug2("added rule %u:%s%s matches=%slambda=%s", r->idx,
390402 sa, su, s, desc);
391403 } else if (r->actions != NULL) {
392 ss = fmt_strings(NULL, (struct strings *) r->actions);
404 ss = fmt_replstrs(NULL, r->actions);
393405 log_debug2("added rule %u:%s%s matches=%sactions=%s", r->idx,
394406 sa, su, s, ss);
395407 xfree(ss);
420432 void
421433 make_actlist(struct actlist *tl, char *buf, size_t len)
422434 {
423 struct actitem *ti;
424 char desc[DESCBUFSIZE];
425 size_t off;
435 struct actitem *ti;
436 struct deliver_action_data *data;
437 char desc[DESCBUFSIZE], *s;
438 size_t off;
426439
427440 off = 0;
428441 TAILQ_FOREACH(ti, tl, entry) {
429 ti->deliver->desc(ti, desc, sizeof desc);
442 if (ti->deliver != NULL)
443 ti->deliver->desc(ti, desc, sizeof desc);
444 else {
445 data = ti->data;
446 s = fmt_replstrs(NULL, data->actions);
447 xsnprintf(desc, sizeof desc, "action %s", s);
448 xfree(s);
449 }
430450 off += xsnprintf(buf + off, len - off, "%u:%s ", ti->idx, desc);
431451 if (off >= len)
432452 break;
493513 xfree(data->server.port);
494514 if (data->server.ai != NULL)
495515 freeaddrinfo(data->server.ai);
516 } else if (ti->deliver == NULL) {
517 struct deliver_action_data *data = ti->data;
518 free_replstrs(data->actions);
519 ARRAY_FREEALL(data->actions);
496520 }
497521 if (ti->data != NULL)
498522 xfree(ti->data);
513537 if (r->users != NULL)
514538 ARRAY_FREEALL(r->users);
515539 if (r->actions != NULL) {
516 free_strings((struct strings *) r->actions);
540 free_replstrs(r->actions);
517541 ARRAY_FREEALL(r->actions);
518542 }
519543
17721796 data->hdr.str = $2;
17731797 data->value.str = $3;
17741798 }
1775 | TOKAPPENDSTRING strv
1799 | TOKAPPENDSTRING strv
17761800 /** [$2: strv (char *)] */
17771801 {
17781802 struct deliver_append_string_data *data;
18711895 data->key.str = $2;
18721896 data->value.str = $4;
18731897 }
1898 | actions
1899 {
1900 struct deliver_action_data *data;
1901
1902 /*
1903 * This is a special-case, handled when the list of delivery
1904 * targets is resolved rather than by calling a deliver
1905 * function, so the deliver pointer is NULL.
1906 */
1907 $$ = xcalloc(1, sizeof *$$);
1908 $$->deliver = NULL;
1909
1910 data = xcalloc(1, sizeof *data);
1911 $$->data = data;
1912
1913 data->actions = $1;
1914 }
18741915 | TOKDROP
18751916 {
18761917 $$ = xcalloc(1, sizeof *$$);
20102051 }
20112052
20122053 /** ACTIONS: <replstrs> (struct replstrs *) */
2013 actions: actionp TOKNONE
2014 {
2015 $$ = NULL;
2016 }
2017 | actionp strv
2054 actions: actionp strv
20182055 /** [$2: strv (char *)] */
20192056 {
20202057 if (*$2 == '\0')