Codebase list fdm / eab7d5b
Yet another reorganisation of the fetch code. Not quite finished, still some memory leaks in the error path. This works in much the same way as the last version, except it is a bit cleaner and tidier and I didn't forget that matching may block for the parent too (match pipe/exec) and so break that. Nicholas Marriott 17 years ago
25 changed file(s) with 1443 addition(s) and 909 deletion(s). Raw diff Collapse all Expand all
3636 cleanup.c imap-common.c fetch-imappipe.c deliver-remove-header.c \
3737 deliver-stdout.c deliver-append-string.c strb.c deliver-add-header.c \
3838 deliver-exec.c child-fetch.c parent-fetch.c child-deliver.c \
39 parent-deliver.c \
39 parent-deliver.c mail-state.c \
4040 y.tab.c lex.yy.c
4141
4242 DEFS= -DBUILD="\"$(VERSION) ($(DATE))\""
2020 cleanup.c imap-common.c fetch-imappipe.c deliver-remove-header.c \
2121 deliver-stdout.c deliver-append-string.c strb.c deliver-add-header.c \
2222 deliver-exec.c child-fetch.c parent-fetch.c child-deliver.c \
23 parent-deliver.c \
23 parent-deliver.c mail-state.c \
2424 parse.y lex.l
2525
2626 LEX= lex
3232 struct account *a = data->account;
3333 struct mail *m = data->mail;
3434 struct msg msg;
35 struct msgbuf msgbuf;
3536 int error = 0;
3637
3738 #ifndef NO_SETPROCTITLE
4950
5051 /* inform parent we're done */
5152 msg.type = MSG_DONE;
52 if (privsep_send(io, &msg, m->tags, STRB_SIZE(m->tags)) != 0)
53 msg.id = 0;
54
55 msgbuf.buf = m->tags;
56 msgbuf.len = STRB_SIZE(m->tags);
57
58 if (privsep_send(io, &msg, &msgbuf) != 0)
5359 fatalx("deliver: privsep_send error");
54 if (privsep_recv(io, &msg, NULL, 0) != 0)
60 if (privsep_recv(io, &msg, NULL) != 0)
5561 fatalx("deliver: privsep_recv error");
5662 if (msg.type != MSG_EXIT)
5763 fatalx("deliver: unexpected message");
103109 child_deliver_cmd_hook(pid_t pid, struct account *a, unused struct msg *msg,
104110 struct child_deliver_data *data, int *result)
105111 {
106 struct match_ctx *mctx = data->mctx;
107 struct mail *m = mctx->mail;
112 struct mail_ctx *mctx = data->mctx;
113 struct mail *m = data->mail;
108114 struct match_command_data *cmddata = data->cmddata;
109115 int flags, status, found = 0;
110116 char *s, *cause, *lbuf, *out, *err, tag[24];
3535 int poll_account(struct io *, struct account *);
3636 int fetch_account(struct io *, struct account *, double);
3737
38 int fetch_flush(struct account *, struct io *, int *, int *, int *,
39 const char **);
40 int fetch_poll(struct account *a, int, struct io *, struct io **);
38 int fetch_drain(u_int *, u_int *);
39 int fetch_done(struct mail_ctx *, u_int *, u_int *);
40 int fetch_match(int *, u_int *, struct msg *, struct msgbuf *);
41 int fetch_deliver(int *, struct msg *, struct msgbuf *);
42 int fetch_poll(struct io *, struct mail_ctx *, int, u_int);
4143 int fetch_transform(struct account *, struct mail *);
42 int fetch_rule(struct match_ctx *, const char **);
43
44 int run_match(struct account *, const char **);
45 int run_deliver(struct account *, struct io *, int *, const char **);
46 int run_done(struct account *, int *, int *, const char **);
47
48 void flush_queue(struct match_queue *);
49 u_int queue_length(struct match_queue *);
50
51 struct strings *get_users(struct match_ctx *, struct rule *, struct action *,
52 int *);
53
54 int do_expr(struct rule *, struct match_ctx *);
55 int do_deliver(struct rule *, struct match_ctx *);
56 int do_rules(struct match_ctx *, struct rules *, const char **);
57
58 int start_action(struct io *, struct deliver_ctx *);
59 int finish_action(struct deliver_ctx *, struct msg *, void *, size_t);
60
61 /* XXX wrap in struct (match_state?) and pass, with kept/dropped etc */
62 struct match_queue matchq;
63 struct match_queue deliverq;
64 struct match_queue doneq;
44
45 struct mail_queue matchq;
46 struct mail_queue deliverq;
47 struct mail_queue doneq;
48
49 #define ACTION_DONE 0
50 #define ACTION_ERROR 1
51 #define ACTION_PARENT 2
6552
6653 int
6754 child_fetch(struct child *child, struct io *io)
120107
121108 out:
122109 /* finish fetch */
123 if (a->fetch->finish != NULL && a->fetch->finish(a) != FETCH_SUCCESS)
124 error = 1;
110 if (a->fetch->finish != NULL) {
111 if (a->fetch->finish(a, error) != FETCH_SUCCESS)
112 error = 1;
113 }
125114
126115 io->flags &= ~IO_NOWAIT;
127116 memset(&msg, 0, sizeof msg);
128117
129118 msg.type = MSG_EXIT;
130119 log_debug3("%s: sending exit message to parent", a->name);
131 if (privsep_send(io, &msg, NULL, 0) != 0)
120 if (privsep_send(io, &msg, NULL) != 0)
132121 fatalx("child: privsep_send error");
133122 log_debug3("%s: waiting for exit message from parent", a->name);
134 if (privsep_recv(io, &msg, NULL, 0) != 0)
123 if (privsep_recv(io, &msg, NULL) != 0)
135124 fatalx("child: privsep_recv error");
136125 if (msg.type != MSG_EXIT)
137126 fatalx("child: unexpected message");
165154 }
166155
167156 int
168 run_match(struct account *a, const char **cause)
169 {
170 struct match_ctx *mctx;
171
172 if (TAILQ_EMPTY(&matchq))
173 return (0);
174
175 mctx = TAILQ_FIRST(&matchq);
176 log_debug3("%s: running match queue", a->name);
177
178 switch (fetch_rule(mctx, cause)) {
179 case FETCH_ERROR:
180 return (1);
181 case FETCH_AGAIN:
182 /* delivering mail, queue for delivery */
183 log_debug3("%s: adding to deliver queue", a->name);
184 TAILQ_REMOVE(&matchq, mctx, entry);
185 TAILQ_INSERT_TAIL(&deliverq, mctx, entry);
186 break;
187 case FETCH_COMPLETE:
188 /* finished with mail, queue on done queue */
189 log_debug3("%s: adding to done queue", a->name);
190 TAILQ_REMOVE(&matchq, mctx, entry);
191 TAILQ_INSERT_TAIL(&doneq, mctx, entry);
192
193 /*
194 * Destroy mail data now it is finished, just keep the mail
195 * structure.
196 */
197 shm_destroy(&mctx->mail->shm);
198 break;
199 }
200
201 return (0);
202 }
203
204 int
205 run_deliver(struct account *a, struct io *io, int *blocked, const char **cause)
206 {
207 struct match_ctx *mctx;
208 struct deliver_ctx *dctx;
209 struct msg msg;
210 void *buf;
211 size_t len;
212
213 *blocked = 0;
214 if (TAILQ_EMPTY(&deliverq))
215 return (0);
216
217 mctx = TAILQ_FIRST(&deliverq);
218 if (TAILQ_EMPTY(&mctx->dqueue)) {
219 /* delivery done. return to match queue */
220 log_debug3("%s: returning to match queue", a->name);
221 TAILQ_REMOVE(&deliverq, mctx, entry);
222 TAILQ_INSERT_HEAD(&matchq, mctx, entry);
223 return (0);
224 }
225
226 /* start the first action */
227 log_debug3("%s: running deliver queue", a->name);
228 dctx = TAILQ_FIRST(&mctx->dqueue);
229
230 if (dctx->blocked) {
231 /* check for reply from parent and finish */
232 if (!privsep_check(io)) {
233 *blocked = 1;
234 return (0);
235 }
236
237 if (privsep_recv(io, &msg, &buf, &len) != 0)
238 fatalx("child: privsep_recv error");
239 if (msg.type != MSG_DONE)
240 fatalx("child: unexpected message");
241
242 if (finish_action(dctx, &msg, buf, len) != 0) {
243 *cause = "delivery";
244 return (1);
245 }
246 } else {
247 if (start_action(mctx->io, dctx) != 0) {
248 *cause = "delivery";
249 return (1);
250 }
251 if (dctx->blocked) {
252 *blocked = 1;
253 return (0);
254 }
255 }
256
257 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
258 log_debug("%s: message %u delivered (rule %u, %s) after %.3f seconds",
259 a->name, mctx->mail->idx, dctx->rule->idx,
260 dctx->action->deliver->name, get_time() - dctx->tim);
261 xfree(dctx);
262 return (0);
263 }
264
265 int
266 run_done(struct account *a, int *dropped, int *kept, const char **cause)
267 {
268 struct match_ctx *mctx;
269 struct mail *m;
270 int error = 0;
271 const char *type;
272
273 if (TAILQ_EMPTY(&doneq))
274 return (0);
275
276 mctx = TAILQ_FIRST(&doneq);
277 m = mctx->mail;
278 log_debug3("%s: running done queue", a->name);
279
280 TAILQ_REMOVE(&doneq, mctx, entry);
281 ARRAY_FREE(&mctx->stack);
282 log_debug("%s: message %u done after %.3f seconds", a->name, m->idx,
283 get_time() - mctx->tim);
284 xfree(mctx);
285
286 if (a->fetch->done != NULL) {
287 switch (m->decision) {
288 case DECISION_DROP:
289 type = "deleting";
290 (*dropped)++;
291 break;
292 case DECISION_KEEP:
293 type = "keeping";
294 (*kept)++;
157 fetch_poll(struct io *pio, struct mail_ctx *mctx, int blocked, u_int queued)
158 {
159 struct account *a = mctx->account;
160 static int finished; /* fetch is complete */
161 static int holding; /* holding for queue to drop */
162 struct io *rio, *iop[NFDS];
163 char *cause;
164 u_int n;
165 int timeout, error;
166
167 n = 1;
168 iop[0] = pio;
169
170 /*
171 * If the queue is empty and the fetch finished, must be all done.
172 */
173 if (queued == 0 && finished)
174 return (FETCH_COMPLETE);
175
176 /*
177 * Update the holding flag.
178 */
179 if (queued >= MAXMAILQUEUED)
180 holding = 1;
181 if (queued < MINMAILQUEUED)
182 holding = 0;
183
184
185 /*
186 * If not finished, try to get a mail.
187 */
188 if (!finished && !holding) {
189 switch ((error = a->fetch->fetch(a, mctx->mail))) {
190 case FETCH_COMPLETE:
191 finished = 1;
192 return (FETCH_AGAIN);
193 case FETCH_AGAIN:
295194 break;
296195 default:
297 fatalx("invalid decision");
298 }
299 log_debug("%s: %s message %u", a->name, type, m->idx);
300
301 if (a->fetch->done(a, m) != FETCH_SUCCESS) {
302 *cause = type;
303 error = 1;
304 }
305 }
306
307 mail_destroy(m);
308 xfree(m);
309
310 return (error);
311 }
312
313 void
314 flush_queue(struct match_queue *mq)
315 {
316 struct match_ctx *mctx;
317 struct deliver_ctx *dctx;
318 struct mail *m;
319
320 while (!TAILQ_EMPTY(mq)) {
321 mctx = TAILQ_FIRST(mq);
322 m = mctx->mail;
323
324 TAILQ_REMOVE(mq, mctx, entry);
325 while (!TAILQ_EMPTY(&mctx->dqueue)) {
326 dctx = TAILQ_FIRST(&mctx->dqueue);
327 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
328 xfree(dctx);
329 }
330 ARRAY_FREE(&mctx->stack);
331 xfree(mctx);
332
333 mail_destroy(m);
334 xfree(m);
335 }
336 }
337
338 u_int
339 queue_length(struct match_queue *mq)
340 {
341 struct match_ctx *mctx;
342 u_int n;
343
344 n = 0;
345 TAILQ_FOREACH(mctx, mq, entry)
346 n++;
347
348 return (n);
349 }
350
351 int
352 fetch_poll(struct account *a, int blocked, struct io *pio, struct io **rio)
353 {
354 int timeout;
355 char *cause;
356 struct io *iop[NFDS];
357 u_int n;
358
359 n = 1;
360 iop[0] = pio;
361
362 if (a->fetch->fill != NULL)
196 return (error);
197 }
198 }
199
200 /*
201 * If the fetch itself not finished, fill in its io list.
202 */
203 if (!finished && a->fetch->fill != NULL)
363204 a->fetch->fill(a, iop, &n);
205
206 /*
207 * If that didn't add any fds, and we're not blocked for the parent
208 * then skip the poll entirely and tell the caller not to loop to
209 * us again immediately.
210 */
364211 if (n == 1 && !blocked)
365 return (0);
366
212 return (FETCH_NONE);
213
214 /*
215 * If the queues are empty, or blocked waiting for the parent, then
216 * let poll block.
217 */
367218 timeout = 0;
368 if (TAILQ_EMPTY(&matchq) && (TAILQ_EMPTY(&deliverq) || blocked))
219 if (blocked || queued == 0)
369220 timeout = conf.timeout;
370221
371222 log_debug3("%s: polling %u fds, timeout=%d", a->name, n, timeout);
372 switch (io_polln(iop, n, rio, timeout, &cause)) {
223 switch (io_polln(iop, n, &rio, timeout, &cause)) {
373224 case 0:
225 if (rio == pio)
226 fatalx("child: parent socket closed");
374227 log_warnx("%s: connection unexpectedly closed", a->name);
375228 return (1);
376229 case -1:
230 if (rio == pio)
231 fatalx("child: parent socket error");
377232 if (errno == EAGAIN)
378 return (0);
233 break;
379234 log_warnx("%s: %s", a->name, cause);
380235 xfree(cause);
381236 return (1);
382237 }
383238
239 return (FETCH_AGAIN);
240 }
241
242 int
243 fetch_done(struct mail_ctx *mctx, u_int *dropped, u_int *kept)
244 {
245 struct account *a = mctx->account;
246 struct mail *m = mctx->mail;
247
248 if (a->fetch->done == NULL)
249 return (0);
250
251 switch (m->decision) {
252 case DECISION_DROP:
253 (*dropped)++;
254 log_debug("%s: dropping message %u", a->name, m->idx);
255 break;
256 case DECISION_KEEP:
257 (*kept)++;
258 log_debug("%s: keeping message %u", a->name, m->idx);
259 break;
260 default:
261 fatalx("invalid decision");
262 }
263
264 if (a->fetch->done(a, m) != FETCH_SUCCESS)
265 return (1);
266
384267 return (0);
385268 }
386269
387270 int
388 fetch_flush(struct account *a, struct io *pio, int *blocked, int *dropped,
389 int *kept, const char **cause)
390 {
391 while (!TAILQ_EMPTY(&matchq) || !TAILQ_EMPTY(&deliverq)) {
392 if (run_match(a, cause) != 0)
271 fetch_drain(u_int *dropped, u_int *kept)
272 {
273 struct mail_ctx *mctx;
274
275 while (!TAILQ_EMPTY(&doneq)) {
276 mctx = TAILQ_FIRST(&doneq);
277 if (fetch_done(mctx, dropped, kept) != 0)
393278 return (1);
394 if (run_deliver(a, pio, blocked, cause) != 0)
395 return (1);
396
397 if (!TAILQ_EMPTY(&deliverq) && *blocked) {
398 pio->flags &= ~IO_NOWAIT;
399 if (!TAILQ_EMPTY(&matchq))
400 pio->flags |= IO_NOWAIT;
401 switch (io_poll(pio, NULL)) {
402 case 0:
403 fatalx("child: parent socket closed");
404 case -1:
405 if (errno == EAGAIN)
406 break;
407 fatalx("child: parent socket error");
279
280 TAILQ_REMOVE(&doneq, mctx, entry);
281
282 mail_destroy(mctx->mail);
283 xfree(mctx->mail);
284
285 xfree(mctx);
286 }
287
288 return (0);
289 }
290
291 int
292 fetch_match(int *blocked, u_int *queued, struct msg *msg, struct msgbuf *msgbuf)
293 {
294 struct mail_ctx *mctx;
295
296 if (TAILQ_EMPTY(&matchq))
297 return (0);
298
299 mctx = TAILQ_FIRST(&matchq);
300 switch (mail_match(mctx, msg, msgbuf)) {
301 case MAIL_ERROR:
302 return (1);
303 case MAIL_DELIVER:
304 TAILQ_REMOVE(&matchq, mctx, entry);
305 TAILQ_INSERT_TAIL(&deliverq, mctx, entry);
306 break;
307 case MAIL_DONE:
308 TAILQ_REMOVE(&matchq, mctx, entry);
309 TAILQ_INSERT_TAIL(&doneq, mctx, entry);
310 (*queued)--;
311 break;
312 case MAIL_BLOCKED:
313 *blocked = 1;
314 break;
315 }
316
317 return (0);
318 }
319
320 int
321 fetch_deliver(int *blocked, struct msg *msg, struct msgbuf *msgbuf)
322 {
323 struct mail_ctx *mctx;
324
325 if (TAILQ_EMPTY(&deliverq))
326 return (0);
327
328 mctx = TAILQ_FIRST(&deliverq);
329 switch (mail_deliver(mctx, msg, msgbuf)) {
330 case MAIL_ERROR:
331 return (1);
332 case MAIL_MATCH:
333 TAILQ_REMOVE(&deliverq, mctx, entry);
334 TAILQ_INSERT_TAIL(&matchq, mctx, entry);
335 break;
336 case MAIL_BLOCKED:
337 *blocked = 1;
338 break;
339 }
340
341 return (0);
342 }
343
344 int
345 fetch_account(struct io *pio, struct account *a, double tim)
346 {
347 struct mail *m;
348 struct mail_ctx *mctx;
349 struct msg msg, *msgp;
350 struct msgbuf msgbuf;
351 u_int n, queued, dropped, kept;
352 int error, blocked;
353
354 log_debug2("%s: fetching", a->name);
355 TAILQ_INIT(&matchq);
356 TAILQ_INIT(&deliverq);
357 TAILQ_INIT(&doneq);
358
359 mctx = NULL;
360 m = NULL;
361 n = queued = dropped = kept = 0;
362 for (;;) {
363 /*
364 * If the last context was queued (mail received successfully),
365 * make a new one.
366 */
367 if (mctx == NULL) {
368 m = xcalloc(1, sizeof *m);
369 m->body = -1;
370 m->decision = DECISION_DROP;
371 m->idx = ++a->idx;
372 m->tim = get_time();
373
374 mctx = xcalloc(1, sizeof *mctx);
375 mctx->account = a;
376 mctx->mail = m;
377 mctx->msgid = 0;
378 mctx->done = 0;
379
380 mctx->matched = 0;
381
382 mctx->account = a;
383 mctx->io = pio;
384
385 mctx->rule = TAILQ_FIRST(&conf.rules);
386 TAILQ_INIT(&mctx->dqueue);
387 ARRAY_INIT(&mctx->stack);
388 }
389
390 /*
391 * Loop handling mails.
392 */
393 error = FETCH_AGAIN;
394 msgp = NULL;
395 while (error == FETCH_AGAIN) {
396 blocked = 0;
397
398 /*
399 * Match a mail.
400 */
401 if (fetch_match(&blocked, &queued, msgp,&msgbuf) != 0) {
402 error = FETCH_ERROR;
403 goto out;
408404 }
409 }
410
411 if (run_done(a, dropped, kept, cause) != 0)
412 return (1);
413 }
414
415 while (!TAILQ_EMPTY(&doneq)) {
416 if (run_done(a, dropped, kept, cause) != 0)
417 return (1);
418 }
419
420 return (0);
421 }
422
423 int
424 fetch_account(struct io *pio, struct account *a, double tim)
425 {
426 struct mail *m;
427 u_int n, dropped, kept, total;
428 int error, blocked, holding;
429 const char *cause = NULL;
430 struct match_ctx *mctx;
431 struct io *rio;
432
433 log_debug2("%s: fetching", a->name);
434
435 TAILQ_INIT(&matchq);
436 TAILQ_INIT(&deliverq);
437 TAILQ_INIT(&doneq);
438
439 n = dropped = kept = 0;
440 m = NULL;
441 blocked = 0;
442 for (;;) {
443 m = xcalloc(1, sizeof *m);
444 m->body = -1;
445 m->decision = DECISION_DROP;
446 m->done = 0;
447 m->idx = ++a->idx;
448 m->tim = get_time();
449
450 /* fetch a message */
451 error = FETCH_AGAIN;
452 rio = NULL;
453 holding = 0;
454 while (error == FETCH_AGAIN) {
455 total = queue_length(&matchq) + queue_length(&deliverq);
456 if (total >= MAXMAILQUEUED)
457 holding = 1;
458 if (total < MINMAILQUEUED)
459 holding = 0;
460
461 log_debug3("%s: queue %u; blocked=%d; holding=%d",
462 a->name, total, blocked, holding);
463
464 if (!holding) {
465 if (rio != pio) {
466 error = a->fetch->fetch(a, m);
467 switch (error) {
468 case FETCH_ERROR:
469 if (rio != pio) {
470 cause = "fetching";
471 goto out;
472 }
473 fatalx("child: lost parent");
474 case FETCH_COMPLETE:
475 goto out;
476 }
477 }
405
406 /*
407 * Deliver a mail.
408 */
409 if (fetch_deliver(&blocked, msgp, &msgbuf) != 0) {
410 error = FETCH_ERROR;
411 goto out;
478412 }
479 if (error == FETCH_AGAIN) {
480 if (fetch_poll(a, blocked, pio,&rio) != 0)
481 goto out;
482 }
483
484 if (run_match(a, &cause) != 0)
413
414 /*
415 * Poll for new mails.
416 */
417 log_debug3("%s: queued %u; blocked=%d", a->name, queued,
418 blocked);
419 error = fetch_poll(pio, mctx, blocked, queued);
420 if (error == FETCH_ERROR || error == FETCH_COMPLETE)
485421 goto out;
486 if (run_deliver(a, pio, &blocked, &cause) != 0)
487 goto out;
488 }
489
490 log_debug("%s: message %u fetched after %.3f seconds", a->name,
491 m->idx, get_time() - m->tim);
492
493 if (error != FETCH_OVERSIZE && error != FETCH_EMPTY) {
422
423 /*
424 * Check for new privsep messages.
425 */
426 msgp = NULL;
427 if (!privsep_check(pio))
428 continue;
429 if (privsep_recv(pio, &msg, &msgbuf) != 0)
430 fatalx("child: privsep_recv error");
431 log_debug3("%s: got message type %d, id %u", a->name,
432 msg.type, msg.id);
433 msgp = &msg;
434 }
435
436 /*
437 * Trim "From " line.
438 */
439 if (error == FETCH_SUCCESS) {
494440 trim_from(m);
495441 if (m->size == 0)
496442 error = FETCH_EMPTY;
497443 }
498444
445 /*
446 * And handle the return code.
447 */
499448 switch (error) {
500449 case FETCH_EMPTY:
501450 log_warnx("%s: empty message", a->name);
502 cause = "fetching";
451 error = FETCH_ERROR;
503452 goto out;
504453 case FETCH_OVERSIZE:
505454 log_warnx("%s: message too big: %zu bytes (limit %zu)",
506455 a->name, m->size, conf.max_size);
507 if (conf.del_big)
456 if (conf.del_big) {
457 /*
458 * Queue on the done queue and destroy the
459 * mail file.
460 */
461 TAILQ_INSERT_TAIL(&doneq, mctx, entry);
462 shm_destroy(&mctx->mail->shm);
463
464 /*
465 * Set error to success to allocate a new
466 * context at the start of the loop.
467 */
468 mctx = NULL;
508469 break;
509 cause = "fetching";
470 }
471 error = FETCH_ERROR;
510472 goto out;
511 }
512
513 log_debug("%s: got message %u: size %zu, body %zd", a->name,
514 m->idx, m->size, m->body);
515 fetch_transform(a, m);
516
517 /* construct mctx */
518 mctx = xcalloc(1, sizeof *mctx);
519 mctx->tim = get_time();
520 mctx->io = pio;
521 mctx->account = a;
522 mctx->mail = m;
523 ARRAY_INIT(&mctx->stack);
524 mctx->rule = TAILQ_FIRST(&conf.rules);
525 mctx->matched = mctx->stopped = 0;
526 TAILQ_INIT(&mctx->dqueue);
527 m = NULL; /* clear m to avoid double-free if out later */
528
529 /* and queue it */
530 log_debug3("%s: adding to match queue", a->name);
531 TAILQ_INSERT_TAIL(&matchq, mctx, entry);
532
533 /* finish up a done mail */
534 if (run_done(a, &dropped, &kept, &cause) != 0)
473 case FETCH_SUCCESS:
474 /*
475 * Got a mail: modify it and queue it.
476 */
477 log_debug("%s: got message %u after %.3f seconds: "
478 "size %zu, body %zd", a->name, m->idx,
479 get_time() - m->tim, m->size, m->body);
480 fetch_transform(a, m);
481 TAILQ_INSERT_TAIL(&matchq, mctx, entry);
482 mctx = NULL;
483 queued++;
484 break;
485 }
486
487 /*
488 * Empty the done queue. Can get here either from FETCH_SUCCESS
489 * or FETCH_NONE.
490 */
491 if (fetch_drain(&dropped, &kept) != 0) {
492 error = FETCH_ERROR;
535493 goto out;
536 if (queue_length(&doneq) > MAXMAILQUEUED) {
537 while (queue_length(&doneq) > MINMAILQUEUED) {
538 if (run_done(a, &dropped, &kept, &cause) != 0)
539 goto out;
540 }
541 }
542
494 }
495
496 /*
497 * Purge if necessary.
498 */
543499 if (conf.purge_after == 0 || a->fetch->purge == NULL)
544500 continue;
545501
502 #if 0
546503 n++;
547504 if (n >= conf.purge_after) {
548505 log_debug("%s: got %u mails, purging", a->name, n);
506 n = 0;
549507
550508 /*
551509 * Must empty queues before purge to make sure things
552510 * like POP3 indexing don't get ballsed up.
553511 */
554 if (fetch_flush(a, pio, &blocked, &dropped, &kept,
555 &cause) != 0)
556 goto out;
557
558 if (a->fetch->purge(a) != FETCH_SUCCESS) {
559 cause = "purging";
560 goto out;
561 }
562
563 n = 0;
564 }
512 if (fetch_flush(void) != 0)
513 break;
514 if (a->fetch->purge(a) != FETCH_SUCCESS)
515 break;
516 }
517 #endif
565518 }
566519
567520 out:
568 if (m != NULL) {
521 if (mctx != NULL) {
569522 mail_destroy(m);
570523 xfree(m);
571 }
572
573 if (cause == NULL)
574 fetch_flush(a, pio, &blocked, &dropped, &kept, &cause);
575 if (cause != NULL) {
576 flush_queue(&matchq);
577 flush_queue(&deliverq);
578 flush_queue(&doneq);
579
580 log_warnx("%s: %s error. aborted", a->name, cause);
581 }
582
524
525 xfree(mctx);
526 }
527
528 /*
529 * Drain the done queue if not an error.
530 */
531 if (error != FETCH_ERROR) {
532 if (fetch_drain(&dropped, &kept) != 0)
533 error = FETCH_ERROR;
534 }
535
536 /*
537 * Report error and free queues.
538 */
539 if (error == FETCH_ERROR) {
540 log_warnx("%s: fetching error. aborted", a->name);
541 /* XXX fetch_free(); */
542 }
543
583544 tim = get_time() - tim;
584545 n = dropped + kept;
585546 if (n > 0) {
586547 log_info("%s: %u messages processed (%u kept) in %.3f seconds "
587548 "(average %.3f)", a->name, n, kept, tim, tim / n);
588 } else {
589 log_info("%s: %u messages processed in %.3f seconds",
590 a->name, n, tim);
591 }
592
593 return (cause != NULL);
549 return (error != 1);
550 }
551
552 log_info("%s: %u messages processed in %.3f seconds", a->name, n, tim);
553 return (error == FETCH_ERROR);
594554 }
595555
596556 int
637597
638598 return (FETCH_SUCCESS);
639599 }
640
641 int
642 fetch_rule(struct match_ctx *mctx, const char **cause)
643 {
644 struct account *a = mctx->account;
645 struct strings *aa;
646 struct mail *m = mctx->mail;
647 struct rule *r = mctx->rule;
648 u_int i;
649 int error;
650 char *tkey, *tvalue;
651
652 /* matching finished */
653 if (m->done) {
654 if (conf.keep_all || a->keep)
655 m->decision = DECISION_KEEP;
656 return (FETCH_COMPLETE);
657 }
658
659 /* end of ruleset reached */
660 if (r == NULL) {
661 switch (conf.impl_act) {
662 case DECISION_NONE:
663 log_warnx("%s: reached end of ruleset. no "
664 "unmatched-mail option; keeping mail", a->name);
665 m->decision = DECISION_KEEP;
666 break;
667 case DECISION_KEEP:
668 log_debug2("%s: reached end of ruleset. keeping mail",
669 a->name);
670 m->decision = DECISION_KEEP;
671 break;
672 case DECISION_DROP:
673 log_debug2("%s: reached end of ruleset. dropping mail",
674 a->name);
675 m->decision = DECISION_DROP;
676 break;
677 }
678 m->done = 1;
679 return (FETCH_SUCCESS);
680 }
681
682 mctx->rule = TAILQ_NEXT(mctx->rule, entry);
683 while (mctx->rule == NULL) {
684 if (ARRAY_EMPTY(&mctx->stack))
685 break;
686 mctx->rule = ARRAY_LAST(&mctx->stack, struct rule *);
687 mctx->rule = TAILQ_NEXT(mctx->rule, entry);
688 ARRAY_TRUNC(&mctx->stack, 1, struct rule *);
689 }
690
691 aa = r->accounts;
692 if (!ARRAY_EMPTY(aa)) {
693 for (i = 0; i < ARRAY_LENGTH(aa); i++) {
694 if (name_match(ARRAY_ITEM(aa, i, char *), a->name))
695 break;
696 }
697 if (i == ARRAY_LENGTH(aa))
698 return (FETCH_SUCCESS);
699 }
700
701 /* match all the regexps */
702 switch (r->type) {
703 case RULE_EXPRESSION:
704 /* combine wrapped lines */
705 set_wrapped(m, ' ');
706
707 /* perform the expression */
708 if ((error = do_expr(r, mctx)) == -1) {
709 *cause = "matching";
710 return (FETCH_ERROR);
711 }
712
713 /* continue if no match */
714 if (!error)
715 return (FETCH_SUCCESS);
716 break;
717 case RULE_ALL:
718 break;
719 }
720
721 /* reset wrapped lines */
722 set_wrapped(m, '\n');
723
724 /* report rule number */
725 if (TAILQ_EMPTY(&r->rules))
726 log_debug2("%s: matched to rule %u", a->name, r->idx);
727 else
728 log_debug2("%s: matched to rule %u (nested)", a->name, r->idx);
729
730 /* deal with nested rules */
731 if (!TAILQ_EMPTY(&r->rules)) {
732 log_debug2("%s: entering nested rules", a->name);
733 ARRAY_ADD(&mctx->stack, r, struct rule *);
734 mctx->rule = TAILQ_FIRST(&r->rules);
735 return (FETCH_SUCCESS);
736 }
737
738 /* tag mail if needed */
739 if (r->key.str != NULL) {
740 tkey = replacestr(&r->key, m->tags, m, &m->rml);
741 tvalue = replacestr(&r->value, m->tags, m, &m->rml);
742
743 if (tkey != NULL && *tkey != '\0' && tvalue != NULL) {
744 log_debug2("%s: tagging message: %s (%s)",
745 a->name, tkey, tvalue);
746 add_tag(&m->tags, tkey, "%s", tvalue);
747 }
748
749 if (tkey != NULL)
750 xfree(tkey);
751 if (tvalue != NULL)
752 xfree(tvalue);
753 }
754
755 /* if this rule is marked as stop, mark the mail as done */
756 if (r->stop)
757 m->done = 1;
758
759 /* handle delivery */
760 if (r->actions != NULL) {
761 log_debug2("%s: delivering message", a->name);
762 mctx->matched = 1;
763 if (do_deliver(r, mctx) != 0) {
764 *cause = "delivery";
765 return (FETCH_ERROR);
766 }
767 return (FETCH_AGAIN);
768 }
769
770 return (FETCH_SUCCESS);
771 }
772
773 int
774 do_expr(struct rule *r, struct match_ctx *mctx)
775 {
776 int fres, cres;
777 struct expritem *ei;
778 char desc[DESCBUFSIZE];
779
780 fres = 0;
781 TAILQ_FOREACH(ei, r->expr, entry) {
782 cres = ei->match->match(mctx, ei);
783 if (cres == MATCH_ERROR)
784 return (-1);
785 cres = cres == MATCH_TRUE;
786 if (ei->inverted)
787 cres = !cres;
788 switch (ei->op) {
789 case OP_NONE:
790 case OP_OR:
791 fres = fres || cres;
792 break;
793 case OP_AND:
794 fres = fres && cres;
795 break;
796 }
797
798 ei->match->desc(ei, desc, sizeof desc);
799 log_debug2("%s: tried %s%s, got %d", mctx->account->name,
800 ei->inverted ? "not " : "", desc, cres);
801 }
802
803 return (fres);
804 }
805
806 int
807 do_deliver(struct rule *r, struct match_ctx *mctx)
808 {
809 struct account *a = mctx->account;
810 struct mail *m = mctx->mail;
811 struct action *t;
812 struct actions *ta;
813 u_int i, j, k;
814 char *s;
815 struct replstr *rs;
816 struct deliver_ctx *dctx;
817 struct strings *users;
818 int should_free;
819
820 for (i = 0; i < ARRAY_LENGTH(r->actions); i++) {
821 rs = &ARRAY_ITEM(r->actions, i, struct replstr);
822 s = replacestr(rs, m->tags, m, &m->rml);
823
824 log_debug2("%s: looking for actions matching: %s", a->name, s);
825 ta = match_actions(s);
826 if (ARRAY_EMPTY(ta))
827 goto empty;
828 xfree(s);
829
830 log_debug2("%s: found %u actions", a->name, ARRAY_LENGTH(ta));
831 for (j = 0; j < ARRAY_LENGTH(ta); j++) {
832 t = ARRAY_ITEM(ta, j, struct action *);
833 users = get_users(mctx, r, t, &should_free);
834
835 for (k = 0; k < ARRAY_LENGTH(users); k++) {
836 dctx = xmalloc(sizeof *dctx);
837 dctx->action = t;
838 dctx->account = a;
839 dctx->rule = r;
840 dctx->mail = m;
841 dctx->uid = ARRAY_ITEM(users, k, uid_t);
842 dctx->blocked = 0;
843
844 TAILQ_INSERT_TAIL(&mctx->dqueue, dctx, entry);
845 }
846
847 if (should_free)
848 ARRAY_FREEALL(users);
849 }
850
851 ARRAY_FREEALL(ta);
852 }
853
854 return (0);
855
856 empty:
857 xfree(s);
858 ARRAY_FREEALL(ta);
859 log_warnx("%s: no actions matching: %s (%s)", a->name, s, rs->str);
860 return (1);
861 }
862
863 struct strings *
864 get_users(struct match_ctx *mctx, struct rule *r, struct action *t,
865 int *should_free)
866 {
867 struct account *a = mctx->account;
868 struct mail *m = mctx->mail;
869 struct strings *users;
870
871 *should_free = 0;
872 users = NULL;
873 if (r->find_uid) { /* rule comes first */
874 *should_free = 1;
875 users = find_users(m);
876 } else if (r->users != NULL) {
877 *should_free = 0;
878 users = r->users;
879 } else if (t->find_uid) { /* then action */
880 *should_free = 1;
881 users = find_users(m);
882 } else if (t->users != NULL) {
883 *should_free = 0;
884 users = t->users;
885 } else if (a->find_uid) { /* then account */
886 *should_free = 1;
887 users = find_users(m);
888 } else if (a->users != NULL) {
889 *should_free = 0;
890 users = a->users;
891 }
892 if (users == NULL) {
893 *should_free = 1;
894 users = xmalloc(sizeof *users);
895 ARRAY_INIT(users);
896 ARRAY_ADD(users, conf.def_user, uid_t);
897 }
898
899 return (users);
900 }
901
902 int
903 start_action(struct io *io, struct deliver_ctx *dctx)
904 {
905 struct account *a = dctx->account;
906 struct action *t = dctx->action;
907 struct mail *m = dctx->mail;
908 struct mail *md = &dctx->wr_mail;
909 struct msg msg;
910 u_int lines;
911
912 dctx->tim = get_time();
913 if (t->deliver->deliver == NULL)
914 return (0);
915
916 log_debug2("%s: message %u, running action %s as user %lu",
917 a->name, m->idx, t->name, (u_long) dctx->uid);
918 add_tag(&m->tags, "action", "%s", t->name);
919
920 /* just deliver now for in-child delivery */
921 if (t->deliver->type == DELIVER_INCHILD) {
922 dctx->blocked = 0;
923 if (t->deliver->deliver(dctx, t) != DELIVER_SUCCESS)
924 return (1);
925 return (0);
926 }
927
928 #if 0
929 /* if the current user is the same as the deliver user, don't bother
930 passing up either */
931 if (t->deliver->type == DELIVER_ASUSER && dctx->uid == geteuid()) {
932 dctx->blocked = 0;
933 if (t->deliver->deliver(dctx, t) != DELIVER_SUCCESS)
934 return (1);
935 return (0);
936 }
937 if (t->deliver->type == DELIVER_WRBACK && dctx->uid == geteuid()) {
938 dctx->blocked = 0;
939
940 mail_open(md, IO_BLOCKSIZE);
941 md->decision = m->decision;
942
943 if (t->deliver->deliver(dctx, t) != DELIVER_SUCCESS) {
944 mail_destroy(md);
945 return (1);
946 }
947
948 memcpy(&msg.data.mail, md, sizeof msg.data.mail);
949 cleanup_deregister(md->shm.name);
950 strb_destroy(&md->tags);
951
952 mail_receive(m, &msg);
953 log_debug2("%s: received modified mail: size %zu, body %zd",
954 a->name, m->size, m->body);
955
956 /* trim from line */
957 trim_from(m);
958
959 /* and recreate the wrapped array */
960 lines = fill_wrapped(m);
961 log_debug2("%s: found %u wrapped lines", a->name, lines);
962
963 return (0);
964 }
965 #endif
966
967 memset(&msg, 0, sizeof msg);
968 msg.type = MSG_ACTION;
969
970 msg.data.account = a;
971 msg.data.action = t;
972 msg.data.uid = dctx->uid;
973
974 mail_send(m, &msg);
975
976 log_debug3("%s: sending action to parent", a->name);
977 if (privsep_send(io, &msg, m->tags, STRB_SIZE(m->tags)) != 0)
978 fatalx("child: privsep_send error");
979 dctx->blocked = 1;
980
981 return (0);
982 }
983
984 int
985 finish_action(struct deliver_ctx *dctx, struct msg *msg, void *buf, size_t len)
986 {
987 struct account *a = dctx->account;
988 struct action *t = dctx->action;
989 struct mail *m = dctx->mail;
990 u_int lines;
991
992 if (buf == NULL || len == 0)
993 fatalx("child: bad tags");
994 strb_destroy(&m->tags);
995 m->tags = buf;
996 update_tags(&m->tags);
997
998 if (msg->data.error != 0)
999 return (1);
1000
1001 if (t->deliver->type != DELIVER_WRBACK)
1002 return (0);
1003
1004 mail_receive(m, msg);
1005 log_debug2("%s: message %u, received modified mail: size %zu, body %zd",
1006 a->name, m->idx, m->size, m->body);
1007
1008 /* trim from line */
1009 trim_from(m);
1010
1011 /* and recreate the wrapped array */
1012 lines = fill_wrapped(m);
1013 log_debug2("%s: found %u wrapped lines", a->name, lines);
1014
1015 return (0);
1016 }
7474
7575 struct child *
7676 child_start(struct children *children, uid_t uid, int (*start)(struct child *,
77 struct io *), int (*msg)(struct child *, struct msg *, void *, size_t),
77 struct io *), int (*msg)(struct child *, struct msg *, struct msgbuf *),
7878 void *data)
7979 {
8080 struct child *child, *childp;
2424
2525 /* Deliver context. */
2626 struct deliver_ctx {
27 double tim;
27 double tim;
2828
29 struct action *action;
30 struct rule *rule;
29 struct action *action;
30 struct rule *rule;
3131
32 struct account *account;
33 struct mail *mail;
32 struct account *account;
33 struct mail *mail;
3434
35 uid_t uid;
35 uid_t uid;
3636
37 struct mail wr_mail;
37 struct mail wr_mail;
3838
39 int blocked; /* blocked waiting for parent */
40 TAILQ_ENTRY(deliver_ctx) entry;
39 TAILQ_ENTRY(deliver_ctx) entry;
4140 };
42 TAILQ_HEAD(deliver_queue, deliver_ctx);
4341
4442 /* Delivery types. */
4543 enum delivertype {
277277 pid_t pid;
278278 struct children children, dead_children;
279279 struct child *child;
280 void *buf;
281 size_t len;
282280 struct io **ios, *io;
283281 double tim;
284282 struct sigaction act;
285283 struct msg msg;
284 struct msgbuf msgbuf;
286285 size_t off;
287286 struct macro *macro;
288287 struct child_fetch_data *cfd;
734733 break;
735734
736735 /* and handle them if necessary */
737 if (privsep_recv(child->io, &msg, &buf, &len) != 0)
736 if (privsep_recv(child->io, &msg, &msgbuf) != 0)
738737 fatalx("parent: privsep_recv error");
739 if (child->msg(child, &msg, buf, len) == 0)
738 log_debug3("parent: got message type %d, id %u from "
739 "child %ld", msg.type, msg.id, (long) child->pid);
740
741 if (child->msg(child, &msg, &msgbuf) == 0)
740742 continue;
741743
742744 /* child has said it is ready to exit, tell it to */
743745 memset(&msg, 0, sizeof msg);
744746 msg.type = MSG_EXIT;
745 if (privsep_send(child->io, &msg, NULL, 0) != 0)
747 if (privsep_send(child->io, &msg, NULL) != 0)
746748 fatalx("parent: privsep_send error");
747749
748 /* wait for the child */
750 /* wait for the child */
749751 if (waitpid(child->pid, &status, 0) == -1)
750752 fatal("waitpid");
751753 if (WIFSIGNALED(status)) {
+63
-15
fdm.h less more
354354
355355 /* A single mail. */
356356 struct mail {
357 u_int idx;
357358 double tim;
358 u_int idx;
359359
360360 struct strb *tags;
361361
379379 /* XXX move below into special struct and just cp it in mail_*? */
380380 struct rmlist rml; /* regexp matches */
381381
382 int done; /* mail is finished with */
383382 enum decision decision; /* final deliver decision */
384383
385384 void (*auxfree)(void *);
386385 void *auxdata;
387386 };
387
388 /* Mail fetch/delivery return codes. */
389 #define MAIL_CONTINUE 0
390 #define MAIL_DELIVER 1
391 #define MAIL_MATCH 2
392 #define MAIL_ERROR 3
393 #define MAIL_BLOCKED 4
394 #define MAIL_DONE 5
395
396 /* Mail fetch/delivery context. */
397 struct mail_ctx {
398 int done;
399 u_int msgid;
400
401 struct account *account;
402 struct io *io;
403 struct mail *mail;
404
405 struct rule *rule;
406 ARRAY_DECL(, struct rule *) stack;
407 struct expritem *expritem;
408 int result;
409 int matched;
410
411 TAILQ_HEAD(, deliver_ctx) dqueue;
412
413 TAILQ_ENTRY(mail_ctx) entry;
414 };
415 TAILQ_HEAD(mail_queue, mail_ctx);
416 extern struct mail_queue mail_queue;
388417
389418 /* An attachment. */
390419 struct attach {
424453 uid_t uid;
425454 };
426455
456 /* Privsep message buffer. */
457 struct msgbuf {
458 void *buf;
459 size_t len;
460 };
461
427462 /* Privsep message. */
428463 struct msg {
464 u_int id;
429465 enum msgtype type;
430466 size_t size;
431467
438474 struct io *io;
439475
440476 void *data;
441 int (*msg)(struct child *, struct msg *, void *, size_t);
477 int (*msg)(struct child *, struct msg *, struct msgbuf *);
478
479 void *buf;
480 size_t len;
442481 };
443482
444483 /* List of children. */
455494 struct child_deliver_data {
456495 void (*hook)(int, struct account *, struct msg *,
457496 struct child_deliver_data *, int *);
497
458498 struct child *child; /* the source of the request */
499
459500 u_int msgid;
460501 const char *name;
502
461503 struct account *account;
504 struct mail *mail;
462505 struct action *action;
506
463507 struct deliver_ctx *dctx;
464 struct mail *mail;
465 struct match_ctx *mctx;
508 struct mail_ctx *mctx;
509
466510 struct match_command_data *cmddata;
467511 };
468512
779823 void attach_free(struct attach *);
780824
781825 /* privsep.c */
782 int privsep_send(struct io *, struct msg *, void *,
783 size_t);
826 int privsep_send(struct io *, struct msg *,
827 struct msgbuf *);
784828 int privsep_check(struct io *);
785 int privsep_recv(struct io *, struct msg *, void **,
786 size_t *);
829 int privsep_recv(struct io *, struct msg *,
830 struct msgbuf *);
787831
788832 /* command.c */
789833 struct cmd *cmd_start(const char *, int, int, char *, size_t,
797841 __dead void child_exit(int);
798842 struct child *child_start(struct children *, uid_t,
799843 int (*)(struct child *, struct io *),
800 int (*)(struct child *, struct msg *, void *,
801 size_t), void *);
844 int (*)(struct child *, struct msg *,
845 struct msgbuf *), void *);
802846
803847 /* child-fetch.c */
804848 int child_fetch(struct child *, struct io *);
811855 struct msg *, struct child_deliver_data *, int *);
812856
813857 /* parent-fetch.c */
814 int parent_fetch(struct child *, struct msg *, void *,
815 size_t);
858 int parent_fetch(struct child *, struct msg *,
859 struct msgbuf *);
816860
817861 /* parent-deliver.c */
818 int parent_deliver(struct child *, struct msg *, void *,
819 size_t);
862 int parent_deliver(struct child *, struct msg *,
863 struct msgbuf *);
820864
821865 /* connect.c */
822866 struct proxy *getproxy(const char *);
851895 u_int fill_wrapped(struct mail *);
852896 void set_wrapped(struct mail *, char);
853897
898 /* mail-state.c */
899 int mail_match(struct mail_ctx *, struct msg *, struct msgbuf *);
900 int mail_deliver(struct mail_ctx *, struct msg *, struct msgbuf *);
901
854902 /* cleanup.c */
855903 void cleanup_check(void);
856904 void cleanup_flush(void);
2828
2929 int fetch_pop3_start(struct account *);
3030 void fetch_pop3_fill(struct account *, struct io **, u_int *);
31 int fetch_pop3_finish(struct account *);
31 int fetch_pop3_finish(struct account *, int);
3232 int fetch_pop3_poll(struct account *, u_int *);
3333 int fetch_pop3_fetch(struct account *, struct mail *);
3434 int fetch_pop3_purge(struct account *);
3838 void fetch_pop3_free(void *);
3939
4040 int fetch_pop3_connect(struct account *);
41 int fetch_pop3_disconnect(struct account *);
41 int fetch_pop3_disconnect(struct account *, int);
4242
4343 int fetch_pop3_line(struct account *, char **);
4444 int fetch_pop3_okay(char *);
136136 }
137137
138138 int
139 fetch_pop3_finish(struct account *a)
139 fetch_pop3_finish(struct account *a, int aborted)
140140 {
141141 struct fetch_pop3_data *data = a->data;
142142 u_int i;
143143
144144 if (data->io != NULL)
145 fetch_pop3_disconnect(a);
145 fetch_pop3_disconnect(a, aborted);
146146
147147 if (data->uid != NULL)
148148 xfree(data->uid);
199199 }
200200
201201 int
202 fetch_pop3_disconnect(struct account *a)
202 fetch_pop3_disconnect(struct account *a, int aborted)
203203 {
204204 struct fetch_pop3_data *data = a->data;
205205
206206 io_writeline(data->io, "QUIT");
207 if (fetch_pop3_check(a) == NULL)
207 if (!aborted && fetch_pop3_check(a) == NULL)
208208 goto error;
209209
210210 io_close(data->io);
391391 int
392392 fetch_pop3_purge(struct account *a)
393393 {
394 if (fetch_pop3_disconnect(a) != 0)
394 if (fetch_pop3_disconnect(a, 0) != 0)
395395 return (FETCH_ERROR);
396396 return (fetch_pop3_connect(a));
397397 }
2525 #define FETCH_EMPTY 3
2626 #define FETCH_COMPLETE 4
2727 #define FETCH_AGAIN 5
28 #define FETCH_NONE 6
2829
2930 /* Fetch functions. */
3031 struct fetch {
4041 int (*fetch)(struct account *, struct mail *);
4142 int (*purge)(struct account *);
4243 int (*done)(struct account *, struct mail *);
43 int (*finish)(struct account *);
44 int (*finish)(struct account *, int);
4445 void (*desc)(struct account *, char *, size_t);
4546 };
4647
0 /* $Id$ */
1
2 /*
3 * Copyright (c) 2006 Nicholas Marriott <nicm@users.sourceforge.net>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
14 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
15 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19
20 #include <fnmatch.h>
21 #include <string.h>
22
23 #include "fdm.h"
24 #include "fetch.h"
25 #include "match.h"
26
27 struct strings *find_delivery_users(struct mail_ctx *, struct action *, int *);
28 int fill_delivery_queue(struct mail_ctx *, struct rule *);
29
30 int start_action(struct mail_ctx *, struct deliver_ctx *);
31 int finish_action(struct deliver_ctx *, struct msg *,
32 struct msgbuf *);
33
34 #define ACTION_DONE 0
35 #define ACTION_ERROR 1
36 #define ACTION_PARENT 2
37
38 int
39 mail_match(struct mail_ctx *mctx, struct msg *msg, struct msgbuf *msgbuf)
40 {
41 struct account *a = mctx->account;
42 struct mail *m = mctx->mail;
43 struct strings *aa;
44 struct expritem *ei;
45 u_int i;
46 int error = MAIL_CONTINUE;
47 char *an, *tkey, *tvalue;
48
49 /*
50 * If blocked, check for msgs from parent.
51 */
52 if (mctx->msgid != 0) {
53 if (msg == NULL || msg->id != mctx->msgid)
54 return (MAIL_BLOCKED);
55 mctx->msgid = 0;
56
57 if (msg->type != MSG_DONE)
58 fatalx("child: unexpected message");
59 if (msgbuf->buf == NULL || msgbuf->len == 0)
60 fatalx("child: bad tags");
61 strb_destroy(&m->tags);
62 m->tags = msgbuf->buf;
63
64 ei = mctx->expritem;
65 switch (msg->data.error) {
66 case MATCH_ERROR:
67 return (MAIL_ERROR);
68 case MATCH_TRUE:
69 if (ei->op == OP_NONE || ei->op == OP_OR)
70 mctx->result = 1;
71 break;
72 case MATCH_FALSE:
73 if (ei->op == OP_AND)
74 mctx->result = 0;
75 break;
76 default:
77 fatalx("child: unexpected response");
78 }
79
80 goto next_expritem;
81 }
82
83 /*
84 * Check for completion and end of ruleset.
85 */
86 if (mctx->done)
87 return (MAIL_DONE);
88 if (mctx->rule == NULL) {
89 switch (conf.impl_act) {
90 case DECISION_NONE:
91 log_warnx("%s: reached end of ruleset. no "
92 "unmatched-mail option; keeping mail", a->name);
93 m->decision = DECISION_KEEP;
94 break;
95 case DECISION_KEEP:
96 log_debug2("%s: reached end of ruleset. keeping mail",
97 a->name);
98 m->decision = DECISION_KEEP;
99 break;
100 case DECISION_DROP:
101 log_debug2("%s: reached end of ruleset. dropping mail",
102 a->name);
103 m->decision = DECISION_DROP;
104 break;
105 }
106 return (MAIL_DONE);
107 }
108
109 /*
110 * Expression not started. Start it.
111 */
112 if (mctx->expritem == NULL) {
113 /*
114 * Check rule account list.
115 */
116 aa = mctx->rule->accounts;
117 if (aa != NULL && !ARRAY_EMPTY(aa)) {
118 for (i = 0; i < ARRAY_LENGTH(aa); i++) {
119 an = ARRAY_ITEM(aa, i, char *);
120 if (name_match(an, a->name))
121 break;
122 }
123 if (i == ARRAY_LENGTH(aa)) {
124 mctx->result = 0;
125 goto skip;
126 }
127 }
128
129 /*
130 * No expression. Must be an "all" rule, treat it as always
131 * true.
132 */
133 if (mctx->rule->expr == NULL || TAILQ_EMPTY(mctx->rule->expr)) {
134 mctx->result = 1;
135 goto skip;
136 }
137
138 /*
139 * Start the expression.
140 */
141 mctx->result = 0;
142 mctx->expritem = TAILQ_FIRST(mctx->rule->expr);
143 }
144
145 /*
146 * Check this expression item and adjust the result.
147 */
148 ei = mctx->expritem;
149 switch (ei->match->match(mctx, ei)) {
150 case MATCH_ERROR:
151 return (MAIL_ERROR);
152 case MATCH_PARENT:
153 return (MAIL_BLOCKED);
154 case MATCH_TRUE:
155 if (ei->op == OP_NONE || ei->op == OP_OR)
156 mctx->result = 1;
157 break;
158 case MATCH_FALSE:
159 if (ei->op == OP_AND)
160 mctx->result = 0;
161 break;
162 }
163
164 next_expritem:
165 /*
166 * Move to the next item. If there is one, then return.
167 */
168 mctx->expritem = TAILQ_NEXT(mctx->expritem, entry);
169 if (mctx->expritem != NULL)
170 return (MAIL_CONTINUE);
171
172 skip:
173 /*
174 * If the result was false, skip to find the next rule.
175 */
176 if (!mctx->result)
177 goto next_rule;
178 mctx->matched = 1;
179 log_debug2("%s: matched to rule %u", a->name, mctx->rule->idx);
180
181 /*
182 * If this rule is stop, mark the context so when we get back after
183 * delivery we know to stop.
184 */
185 if (mctx->rule->stop)
186 mctx->done = 1;
187
188 /*
189 * Handle nested rules.
190 */
191 if (!TAILQ_EMPTY(&mctx->rule->rules)) {
192 log_debug2("%s: entering nested rules", a->name);
193
194 /*
195 * Stack the current rule (we are at the end of it so the
196 * the expritem must be NULL already).
197 */
198 ARRAY_ADD(&mctx->stack, mctx->rule, struct rule *);
199
200 /*
201 * Continue with the first rule of the nested list.
202 */
203 mctx->rule = TAILQ_FIRST(&mctx->rule->rules);
204 return (MAIL_CONTINUE);
205 }
206
207 /*
208 * Tag mail if necessary.
209 */
210 if (mctx->rule->key.str != NULL) {
211 tkey = replacestr(&mctx->rule->key, m->tags, m, &m->rml);
212 tvalue = replacestr(&mctx->rule->value, m->tags, m, &m->rml);
213
214 if (tkey != NULL && *tkey != '\0' && tvalue != NULL) {
215 log_debug2("%s: tagging message: %s (%s)", a->name,
216 tkey, tvalue);
217 add_tag(&m->tags, tkey, "%s", tvalue);
218 }
219
220 if (tkey != NULL)
221 xfree(tkey);
222 if (tvalue != NULL)
223 xfree(tvalue);
224 }
225
226 /*
227 * Fill the delivery action queue.
228 */
229 if (!ARRAY_EMPTY(mctx->rule->actions)) {
230 if (fill_delivery_queue(mctx, mctx->rule) != 0)
231 return (MAIL_ERROR);
232 error = MAIL_DELIVER;
233 }
234
235 next_rule:
236 /*
237 * Move to the next rule.
238 */
239 mctx->rule = TAILQ_NEXT(mctx->rule, entry);
240
241 /*
242 * If no more rules, try to move up the stack.
243 */
244 while (mctx->rule == NULL) {
245 if (ARRAY_EMPTY(&mctx->stack))
246 break;
247 mctx->rule = ARRAY_LAST(&mctx->stack, struct rule *);
248 mctx->rule = TAILQ_NEXT(mctx->rule, entry);
249 ARRAY_TRUNC(&mctx->stack, 1, struct rule *);
250 }
251
252 return (error);
253 }
254
255 int
256 mail_deliver(struct mail_ctx *mctx, struct msg *msg, struct msgbuf *msgbuf)
257 {
258 struct account *a = mctx->account;
259 struct mail *m = mctx->mail;
260 struct deliver_ctx *dctx;
261
262 /*
263 * If blocked, check for msgs from parent.
264 */
265 if (mctx->msgid != 0) {
266 if (msg == NULL || msg->id != mctx->msgid)
267 return (MAIL_BLOCKED);
268 mctx->msgid = 0;
269
270 /*
271 * Got message. Finish delivery.
272 */
273 dctx = TAILQ_FIRST(&mctx->dqueue);
274 if (finish_action(dctx, msg, msgbuf) == ACTION_ERROR)
275 return (MAIL_ERROR);
276
277 /*
278 * Move on to dequeue this delivery action.
279 */
280 goto done;
281 }
282
283 /*
284 * Check if delivery is complete.
285 */
286 if (TAILQ_EMPTY(&mctx->dqueue))
287 return (MAIL_MATCH);
288
289 /*
290 * Get the first delivery action and start it.
291 */
292 dctx = TAILQ_FIRST(&mctx->dqueue);
293 switch (start_action(mctx, dctx)) {
294 case ACTION_ERROR:
295 return (MAIL_ERROR);
296 case ACTION_PARENT:
297 return (MAIL_BLOCKED);
298 }
299
300 done:
301 /*
302 * Remove completed action from queue.
303 */
304 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
305 log_debug("%s: message %u delivered (rule %u, %s) after %.3f seconds",
306 a->name, m->idx, dctx->rule->idx,
307 dctx->action->deliver->name, get_time() - dctx->tim);
308 xfree(dctx);
309 return (MAIL_CONTINUE);
310 }
311
312 struct strings *
313 find_delivery_users(struct mail_ctx *mctx, struct action *t, int *should_free)
314 {
315 struct account *a = mctx->account;
316 struct mail *m = mctx->mail;
317 struct rule *r = mctx->rule;
318 struct strings *users;
319
320 *should_free = 0;
321 users = NULL;
322 if (r->find_uid) { /* rule comes first */
323 *should_free = 1;
324 users = find_users(m);
325 } else if (r->users != NULL) {
326 *should_free = 0;
327 users = r->users;
328 } else if (t->find_uid) { /* then action */
329 *should_free = 1;
330 users = find_users(m);
331 } else if (t->users != NULL) {
332 *should_free = 0;
333 users = t->users;
334 } else if (a->find_uid) { /* then account */
335 *should_free = 1;
336 users = find_users(m);
337 } else if (a->users != NULL) {
338 *should_free = 0;
339 users = a->users;
340 }
341 if (users == NULL) {
342 *should_free = 1;
343 users = xmalloc(sizeof *users);
344 ARRAY_INIT(users);
345 ARRAY_ADD(users, conf.def_user, uid_t);
346 }
347
348 return (users);
349 }
350
351 int
352 fill_delivery_queue(struct mail_ctx *mctx, struct rule *r)
353 {
354 struct account *a = mctx->account;
355 struct mail *m = mctx->mail;
356 struct action *t;
357 struct actions *ta;
358 u_int i, j, k;
359 char *s;
360 struct replstr *rs;
361 struct deliver_ctx *dctx;
362 struct strings *users;
363 int should_free;
364
365 for (i = 0; i < ARRAY_LENGTH(r->actions); i++) {
366 rs = &ARRAY_ITEM(r->actions, i, struct replstr);
367 s = replacestr(rs, m->tags, m, &m->rml);
368
369 log_debug2("%s: looking for actions matching: %s", a->name, s);
370 ta = match_actions(s);
371 if (ARRAY_EMPTY(ta))
372 goto empty;
373 xfree(s);
374
375 log_debug2("%s: found %u actions", a->name, ARRAY_LENGTH(ta));
376 for (j = 0; j < ARRAY_LENGTH(ta); j++) {
377 t = ARRAY_ITEM(ta, j, struct action *);
378 users = find_delivery_users(mctx, t, &should_free);
379
380 for (k = 0; k < ARRAY_LENGTH(users); k++) {
381 dctx = xcalloc(1, sizeof *dctx);
382 dctx->action = t;
383 dctx->account = a;
384 dctx->rule = r;
385 dctx->mail = m;
386 dctx->uid = ARRAY_ITEM(users, k, uid_t);
387
388 log_debug3("%s: action %s, uid %lu", a->name,
389 t->name, (u_long) dctx->uid);
390 TAILQ_INSERT_TAIL(&mctx->dqueue, dctx, entry);
391 }
392
393 if (should_free)
394 ARRAY_FREEALL(users);
395 }
396
397 ARRAY_FREEALL(ta);
398 }
399
400 return (0);
401
402 empty:
403 xfree(s);
404 ARRAY_FREEALL(ta);
405 log_warnx("%s: no actions matching: %s (%s)", a->name, s, rs->str);
406 return (1);
407
408 }
409
410 int
411 start_action(struct mail_ctx *mctx, struct deliver_ctx *dctx)
412 {
413 struct account *a = dctx->account;
414 struct action *t = dctx->action;
415 struct mail *m = dctx->mail;
416 struct mail *md = &dctx->wr_mail;
417 struct msg msg;
418 struct msgbuf msgbuf;
419 u_int lines;
420
421 dctx->tim = get_time();
422 if (t->deliver->deliver == NULL)
423 return (0);
424
425 log_debug2("%s: message %u, running action %s as user %lu",
426 a->name, m->idx, t->name, (u_long) dctx->uid);
427 add_tag(&m->tags, "action", "%s", t->name);
428
429 /* just deliver now for in-child delivery */
430 if (t->deliver->type == DELIVER_INCHILD) {
431 if (t->deliver->deliver(dctx, t) != DELIVER_SUCCESS)
432 return (ACTION_ERROR);
433 return (ACTION_DONE);
434 }
435
436 #if 0
437 /* if the current user is the same as the deliver user, don't bother
438 passing up either */
439 if (t->deliver->type == DELIVER_ASUSER && dctx->uid == geteuid()) {
440 dctx->blocked = 0;
441 if (t->deliver->deliver(dctx, t) != DELIVER_SUCCESS)
442 return (ACTION_ERROR);
443 return (ACTION_DONE);
444 }
445 if (t->deliver->type == DELIVER_WRBACK && dctx->uid == geteuid()) {
446 dctx->blocked = 0;
447
448 mail_open(md, IO_BLOCKSIZE);
449 md->decision = m->decision;
450
451 if (t->deliver->deliver(dctx, t) != DELIVER_SUCCESS) {
452 mail_destroy(md);
453 return (ACTION_ERROR);
454 }
455
456 memcpy(&msg.data.mail, md, sizeof msg.data.mail);
457 cleanup_deregister(md->shm.name);
458 strb_destroy(&md->tags);
459
460 mail_receive(m, &msg);
461 log_debug2("%s: received modified mail: size %zu, body %zd",
462 a->name, m->size, m->body);
463
464 /* trim from line */
465 trim_from(m);
466
467 /* and recreate the wrapped array */
468 lines = fill_wrapped(m);
469 log_debug2("%s: found %u wrapped lines", a->name, lines);
470
471 return (ACTION_DONE);
472 }
473 #endif
474
475 memset(&msg, 0, sizeof msg);
476 msg.type = MSG_ACTION;
477 msg.id = m->idx;
478
479 msg.data.account = a;
480 msg.data.action = t;
481 msg.data.uid = dctx->uid;
482
483 msgbuf.buf = m->tags;
484 msgbuf.len = STRB_SIZE(m->tags);
485
486 mail_send(m, &msg);
487
488 log_debug3("%s: sending action to parent", a->name);
489 if (privsep_send(mctx->io, &msg, &msgbuf) != 0)
490 fatalx("child: privsep_send error");
491
492 mctx->msgid = msg.id;
493 return (ACTION_PARENT);
494 }
495
496 int
497 finish_action(struct deliver_ctx *dctx, struct msg *msg, struct msgbuf *msgbuf)
498 {
499 struct account *a = dctx->account;
500 struct action *t = dctx->action;
501 struct mail *m = dctx->mail;
502 u_int lines;
503
504 if (msgbuf->buf == NULL || msgbuf->len == 0)
505 fatalx("child: bad tags");
506 strb_destroy(&m->tags);
507 m->tags = msgbuf->buf;
508 update_tags(&m->tags);
509
510 if (msg->data.error != 0)
511 return (ACTION_ERROR);
512
513 if (t->deliver->type != DELIVER_WRBACK)
514 return (ACTION_DONE);
515
516 mail_receive(m, msg);
517 log_debug2("%s: message %u, received modified mail: size %zu, body %zd",
518 a->name, m->idx, m->size, m->body);
519
520 /* trim from line */
521 trim_from(m);
522
523 /* and recreate the wrapped array */
524 lines = fill_wrapped(m);
525 log_debug2("%s: found %u wrapped lines", a->name, lines);
526
527 return (ACTION_DONE);
528 }
529
530 /* -------------------------------------------------------------------------- */
531 #if 0
532 int
533 run_match(struct account *a, const char **cause)
534 {
535 switch (fetch_rule(mctx, cause)) {
536 case FETCH_ERROR:
537 return (1);
538 case FETCH_AGAIN:
539 /* delivering mail, queue for delivery */
540 log_debug3("%s: %u, adding to deliver queue", a->name, m->idx);
541 TAILQ_REMOVE(&matchq, mctx, entry);
542 TAILQ_INSERT_TAIL(&deliverq, mctx, entry);
543 break;
544 case FETCH_COMPLETE:
545 /* finished with mail, queue on done queue */
546 log_debug3("%s: %u, adding to done queue", a->name, m->idx);
547 TAILQ_REMOVE(&matchq, mctx, entry);
548 TAILQ_INSERT_TAIL(&doneq, mctx, entry);
549
550 /*
551 * Destroy mail data now it is finished, just keep the mail
552 * structure.
553 */
554 shm_destroy(&mctx->mail->shm);
555 break;
556 }
557
558 return (0);
559 }
560
561 int
562 run_done(struct account *a, const char **cause)
563 {
564 struct match_ctx *mctx;
565 struct mail *m;
566 int error = 0;
567 const char *type;
568
569 if (TAILQ_EMPTY(&doneq))
570 return (0);
571
572 mctx = TAILQ_FIRST(&doneq);
573 m = mctx->mail;
574 log_debug3("%s: running done queue", a->name);
575
576 TAILQ_REMOVE(&doneq, mctx, entry);
577 ARRAY_FREE(&mctx->stack);
578 log_debug("%s: message %u done after %.3f seconds", a->name, m->idx,
579 get_time() - mctx->tim);
580 xfree(mctx);
581
582 if (a->fetch->done != NULL) {
583 switch (m->decision) {
584 case DECISION_DROP:
585 type = "deleting";
586 dropped++;
587 break;
588 case DECISION_KEEP:
589 type = "keeping";
590 kept++;
591 break;
592 default:
593 fatalx("invalid decision");
594 }
595 log_debug("%s: %s message %u", a->name, type, m->idx);
596
597 if (a->fetch->done(a, m) != FETCH_SUCCESS) {
598 *cause = type;
599 error = 1;
600 }
601 }
602
603 mail_destroy(m);
604 xfree(m);
605
606 return (error);
607 }
608
609 void
610 flush_queue(struct match_queue *mq)
611 {
612 struct match_ctx *mctx;
613 struct deliver_ctx *dctx;
614 struct mail *m;
615
616 while (!TAILQ_EMPTY(mq)) {
617 mctx = TAILQ_FIRST(mq);
618 m = mctx->mail;
619
620 TAILQ_REMOVE(mq, mctx, entry);
621 while (!TAILQ_EMPTY(&mctx->dqueue)) {
622 dctx = TAILQ_FIRST(&mctx->dqueue);
623 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
624 xfree(dctx);
625 }
626 ARRAY_FREE(&mctx->stack);
627 xfree(mctx);
628
629 mail_destroy(m);
630 xfree(m);
631 }
632 }
633
634 int
635 run_deliver(struct account *a, const char **cause)
636 {
637 struct match_ctx *mctx;
638 struct mail *m;
639 struct deliver_ctx *dctx;
640
641 if (TAILQ_EMPTY(&deliverq))
642 return (0);
643
644 mctx = TAILQ_FIRST(&deliverq);
645 m = mctx->mail;
646
647 if (TAILQ_EMPTY(&mctx->dqueue)) {
648 /* delivery done. return to match queue */
649 log_debug3("%s: %u, returning to match queue", a->name, m->idx);
650 TAILQ_REMOVE(&deliverq, mctx, entry);
651 TAILQ_INSERT_HEAD(&matchq, mctx, entry);
652 return (0);
653 }
654
655 /* start the first action */
656 log_debug3("%s: running deliver queue", a->name);
657 dctx = TAILQ_FIRST(&mctx->dqueue);
658
659 switch (start_action(mctx, dctx)) {
660 case ACTION_ERROR:
661 *cause = "delivery";
662 return (1);
663 case ACTION_PARENT:
664 log_debug3("%s: %u, adding to blocked queue", a->name, m->idx);
665 TAILQ_REMOVE(&deliverq, mctx, entry);
666 TAILQ_INSERT_HEAD(&blockedq, mctx, entry);
667 return (0);
668 }
669
670 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
671 log_debug("%s: message %u delivered (rule %u, %s) after %.3f seconds",
672 a->name, mctx->mail->idx, dctx->rule->idx,
673 dctx->action->deliver->name, get_time() - dctx->tim);
674 xfree(dctx);
675 return (0);
676 }
677
678 int
679 recvd_deliver(struct msg *msg, struct msgbuf *msgbuf, void *data,
680 const char **cause)
681 {
682 struct match_ctx *mctx = data;
683 struct account *a = mctx->account;
684 struct mail *m = mctx->mail;
685 struct deliver_ctx *dctx;
686
687 if (msg->type != MSG_DONE)
688 fatalx("child: unexpected message");
689
690 log_debug3("%s: %u, returning to deliver queue", a->name, m->idx);
691 TAILQ_REMOVE(&blockedq, mctx, entry);
692 TAILQ_INSERT_HEAD(&deliverq, mctx, entry);
693
694 dctx = TAILQ_FIRST(&mctx->dqueue);
695 if (finish_action(dctx, msg, msgbuf) != ACTION_DONE) {
696 *cause = "delivery";
697 return (1);
698 }
699
700 TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
701 log_debug("%s: message %u delivered (rule %u, %s) after %.3f seconds",
702 a->name, mctx->mail->idx, dctx->rule->idx,
703 dctx->action->deliver->name, get_time() - dctx->tim);
704 xfree(dctx);
705 return (0);
706 }
707
708 int
709 fetch_rule(struct match_ctx *mctx, const char **cause)
710 {
711 struct account *a = mctx->account;
712 struct strings *aa;
713 struct mail *m = mctx->mail;
714 struct rule *r = mctx->rule;
715 u_int i;
716 int error;
717 char *tkey, *tvalue;
718
719 /* matching finished */
720 if (m->done) {
721 if (conf.keep_all || a->keep)
722 m->decision = DECISION_KEEP;
723 return (FETCH_COMPLETE);
724 }
725
726 /* end of ruleset reached */
727 if (r == NULL) {
728 switch (conf.impl_act) {
729 case DECISION_NONE:
730 log_warnx("%s: reached end of ruleset. no "
731 "unmatched-mail option; keeping mail", a->name);
732 m->decision = DECISION_KEEP;
733 break;
734 case DECISION_KEEP:
735 log_debug2("%s: reached end of ruleset. keeping mail",
736 a->name);
737 m->decision = DECISION_KEEP;
738 break;
739 case DECISION_DROP:
740 log_debug2("%s: reached end of ruleset. dropping mail",
741 a->name);
742 m->decision = DECISION_DROP;
743 break;
744 }
745 m->done = 1;
746 return (FETCH_SUCCESS);
747 }
748
749 mctx->rule = TAILQ_NEXT(mctx->rule, entry);
750 while (mctx->rule == NULL) {
751 if (ARRAY_EMPTY(&mctx->stack))
752 break;
753 mctx->rule = ARRAY_LAST(&mctx->stack, struct rule *);
754 mctx->rule = TAILQ_NEXT(mctx->rule, entry);
755 ARRAY_TRUNC(&mctx->stack, 1, struct rule *);
756 }
757
758 aa = r->accounts;
759 if (!ARRAY_EMPTY(aa)) {
760 for (i = 0; i < ARRAY_LENGTH(aa); i++) {
761 if (name_match(ARRAY_ITEM(aa, i, char *), a->name))
762 break;
763 }
764 if (i == ARRAY_LENGTH(aa))
765 return (FETCH_SUCCESS);
766 }
767
768 /* match all the regexps */
769 switch (r->type) {
770 case RULE_EXPRESSION:
771 /* combine wrapped lines */
772 set_wrapped(m, ' ');
773
774 /* perform the expression */
775 if ((error = do_expr(r, mctx)) == -1) {
776 *cause = "matching";
777 return (FETCH_ERROR);
778 }
779
780 /* continue if no match */
781 if (!error)
782 return (FETCH_SUCCESS);
783 break;
784 case RULE_ALL:
785 break;
786 }
787
788 /* reset wrapped lines */
789 set_wrapped(m, '\n');
790
791 /* report rule number */
792 if (TAILQ_EMPTY(&r->rules))
793 log_debug2("%s: matched to rule %u", a->name, r->idx);
794 else
795 log_debug2("%s: matched to rule %u (nested)", a->name, r->idx);
796
797 /* deal with nested rules */
798 if (!TAILQ_EMPTY(&r->rules)) {
799 log_debug2("%s: entering nested rules", a->name);
800 ARRAY_ADD(&mctx->stack, r, struct rule *);
801 mctx->rule = TAILQ_FIRST(&r->rules);
802 return (FETCH_SUCCESS);
803 }
804
805 /* tag mail if needed */
806 if (r->key.str != NULL) {
807 tkey = replacestr(&r->key, m->tags, m, &m->rml);
808 tvalue = replacestr(&r->value, m->tags, m, &m->rml);
809
810 if (tkey != NULL && *tkey != '\0' && tvalue != NULL) {
811 log_debug2("%s: tagging message: %s (%s)",
812 a->name, tkey, tvalue);
813 add_tag(&m->tags, tkey, "%s", tvalue);
814 }
815
816 if (tkey != NULL)
817 xfree(tkey);
818 if (tvalue != NULL)
819 xfree(tvalue);
820 }
821 1 /* if this rule is marked as stop, mark the mail as done */
822 if (r->stop)
823 m->done = 1;
824
825 /* handle delivery */
826 if (r->actions != NULL) {
827 log_debug2("%s: delivering message", a->name);
828 mctx->matched = 1;
829 if (do_deliver(r, mctx) != 0) {
830 *cause = "delivery";
831 return (FETCH_ERROR);
832 }
833 return (FETCH_AGAIN);
834 }
835
836 return (FETCH_SUCCESS);
837 }
838
839 int
840 do_expr(struct rule *r, struct match_ctx *mctx)
841 {
842 int fres, cres;
843 struct expritem *ei;
844 char desc[DESCBUFSIZE];
845
846 fres = 0;
847 TAILQ_FOREACH(ei, r->expr, entry) {
848 cres = ei->match->match(mctx, ei);
849 if (cres == MATCH_ERROR)
850 return (-1);
851 cres = cres == MATCH_TRUE;
852 if (ei->inverted)
853 cres = !cres;
854 switch (ei->op) {
855 case OP_NONE:
856 case OP_OR:
857 fres = fres || cres;
858 break;
859 case OP_AND:
860 fres = fres && cres;
861 break;
862 }
863
864 ei->match->desc(ei, desc, sizeof desc);
865 log_debug2("%s: tried %s%s, got %d", mctx->account->name,
866 ei->inverted ? "not " : "", desc, cres);
867 }
868
869 return (fres);
870 }
871
872 int
873 do_deliver(struct rule *r, struct match_ctx *mctx)
874 {
875 struct account *a = mctx->account;
876 struct mail *m = mctx->mail;
877 struct action *t;
878 struct actions *ta;
879 u_int i, j, k;
880 char *s;
881 struct replstr *rs;
882 struct deliver_ctx *dctx;
883 struct strings *users;
884 int should_free;
885
886 for (i = 0; i < ARRAY_LENGTH(r->actions); i++) {
887 rs = &ARRAY_ITEM(r->actions, i, struct replstr);
888 s = replacestr(rs, m->tags, m, &m->rml);
889
890 log_debug2("%s: looking for actions matching: %s", a->name, s);
891 ta = match_actions(s);
892 if (ARRAY_EMPTY(ta))
893 goto empty;
894 xfree(s);
895
896 log_debug2("%s: found %u actions", a->name, ARRAY_LENGTH(ta));
897 for (j = 0; j < ARRAY_LENGTH(ta); j++) {
898 t = ARRAY_ITEM(ta, j, struct action *);
899 users = get_users(mctx, r, t, &should_free);
900
901 for (k = 0; k < ARRAY_LENGTH(users); k++) {
902 dctx = xmalloc(sizeof *dctx);
903 dctx->action = t;
904 dctx->account = a;
905 dctx->rule = r;
906 dctx->mail = m;
907 dctx->uid = ARRAY_ITEM(users, k, uid_t);
908
909 TAILQ_INSERT_TAIL(&mctx->dqueue, dctx, entry);
910 }
911
912 if (should_free)
913 ARRAY_FREEALL(users);
914 }
915
916 ARRAY_FREEALL(ta);
917 }
918
919 return (0);
920
921 empty:
922 xfree(s);
923 ARRAY_FREEALL(ta);
924 log_warnx("%s: no actions matching: %s (%s)", a->name, s, rs->str);
925 return (1);
926 }
927 #endif
6767 {
6868 struct mail *mm = &msg->data.mail;
6969
70 mm->done = m->done;
7170 mm->idx = m->idx;
7271
7372 mm->tags = m->tags;
2424 #include "fdm.h"
2525 #include "match.h"
2626
27 int match_age_match(struct match_ctx *, struct expritem *);
27 int match_age_match(struct mail_ctx *, struct expritem *);
2828 void match_age_desc(struct expritem *, char *, size_t);
2929
3030 int match_age_tzlookup(const char *, int *);
7979 }
8080
8181 int
82 match_age_match(struct match_ctx *mctx, struct expritem *ei)
82 match_age_match(struct mail_ctx *mctx, struct expritem *ei)
8383 {
8484 struct match_age_data *data = ei->data;
8585 struct account *a = mctx->account;
2222 #include "fdm.h"
2323 #include "match.h"
2424
25 int match_attachment_match(struct match_ctx *, struct expritem *);
25 int match_attachment_match(struct mail_ctx *, struct expritem *);
2626 void match_attachment_desc(struct expritem *, char *, size_t);
2727
2828 struct match match_attachment = {
3232 };
3333
3434 int
35 match_attachment_match(struct match_ctx *mctx, struct expritem *ei)
35 match_attachment_match(struct mail_ctx *mctx, struct expritem *ei)
3636 {
3737 struct match_attachment_data *data = ei->data;
3838 struct account *a = mctx->account;
2222 #include "fdm.h"
2323 #include "match.h"
2424
25 int match_command_match(struct match_ctx *, struct expritem *);
25 int match_command_match(struct mail_ctx *, struct expritem *);
2626 void match_command_desc(struct expritem *, char *, size_t);
2727
2828 struct match match_command = {
3232 };
3333
3434 int
35 match_command_match(struct match_ctx *mctx, struct expritem *ei)
35 match_command_match(struct mail_ctx *mctx, struct expritem *ei)
3636 {
3737 struct match_command_data *data = ei->data;
3838 struct account *a = mctx->account;
3939 struct mail *m = mctx->mail;
4040 struct io *io = mctx->io;
4141 struct msg msg;
42 void *buf;
43 size_t len;
42 struct msgbuf msgbuf;
4443
4544 /*
4645 * We are called as the child so to change uid this needs to be done
4847 */
4948 memset(&msg, 0, sizeof msg);
5049 msg.type = MSG_COMMAND;
50 msg.id = m->idx;
51
5152 msg.data.account = a;
5253 msg.data.cmddata = data;
5354 msg.data.uid = data->uid;
5455
56 msgbuf.buf = m->tags;
57 msgbuf.len = STRB_SIZE(m->tags);
58
5559 mail_send(m, &msg);
5660
57 if (privsep_send(io, &msg, m->tags, STRB_SIZE(m->tags)) != 0)
61 if (privsep_send(io, &msg, &msgbuf) != 0)
5862 fatalx("child: privsep_send error");
5963
60 if (privsep_recv(io, &msg, &buf, &len) != 0)
61 fatalx("child: privsep_recv error");
62 if (msg.type != MSG_DONE)
63 fatalx("child: unexpected message");
64
65 if (buf == NULL || len == 0)
66 fatalx("child: bad tags");
67 strb_destroy(&m->tags);
68 m->tags = buf;
69
70 return (msg.data.error);
64 mctx->msgid = msg.id;
65 return (MATCH_PARENT);
7166 }
7267
7368 void
2222 #include "fdm.h"
2323 #include "match.h"
2424
25 int match_matched_match(struct match_ctx *, struct expritem *);
25 int match_matched_match(struct mail_ctx *, struct expritem *);
2626 void match_matched_desc(struct expritem *, char *, size_t);
2727
2828 struct match match_matched = {
3232 };
3333
3434 int
35 match_matched_match(struct match_ctx *mctx, unused struct expritem *ei)
35 match_matched_match(struct mail_ctx *mctx, unused struct expritem *ei)
3636 {
3737 if (mctx->matched)
3838 return (MATCH_TRUE);
2222 #include "fdm.h"
2323 #include "match.h"
2424
25 int match_regexp_match(struct match_ctx *, struct expritem *);
25 int match_regexp_match(struct mail_ctx *, struct expritem *);
2626 void match_regexp_desc(struct expritem *, char *, size_t);
2727
2828 struct match match_regexp = {
3232 };
3333
3434 int
35 match_regexp_match(struct match_ctx *mctx, struct expritem *ei)
35 match_regexp_match(struct mail_ctx *mctx, struct expritem *ei)
3636 {
3737 struct match_regexp_data *data = ei->data;
3838 struct account *a = mctx->account;
2222 #include "fdm.h"
2323 #include "match.h"
2424
25 int match_size_match(struct match_ctx *, struct expritem *);
25 int match_size_match(struct mail_ctx *, struct expritem *);
2626 void match_size_desc(struct expritem *, char *, size_t);
2727
2828 struct match match_size = {
3232 };
3333
3434 int
35 match_size_match(struct match_ctx *mctx, struct expritem *ei)
35 match_size_match(struct mail_ctx *mctx, struct expritem *ei)
3636 {
3737 struct match_size_data *data = ei->data;
3838 struct mail *m = mctx->mail;
2323 #include "fdm.h"
2424 #include "match.h"
2525
26 int match_string_match(struct match_ctx *, struct expritem *);
26 int match_string_match(struct mail_ctx *, struct expritem *);
2727 void match_string_desc(struct expritem *, char *, size_t);
2828
2929 struct match match_string = {
3333 };
3434
3535 int
36 match_string_match(struct match_ctx *mctx, struct expritem *ei)
36 match_string_match(struct mail_ctx *mctx, struct expritem *ei)
3737 {
3838 struct match_string_data *data = ei->data;
3939 struct account *a = mctx->account;
2323 #include "fdm.h"
2424 #include "match.h"
2525
26 int match_tagged_match(struct match_ctx *, struct expritem *);
26 int match_tagged_match(struct mail_ctx *, struct expritem *);
2727 void match_tagged_desc(struct expritem *, char *, size_t);
2828
2929 struct match match_tagged = {
3333 };
3434
3535 int
36 match_tagged_match(struct match_ctx *mctx, struct expritem *ei)
36 match_tagged_match(struct mail_ctx *mctx, struct expritem *ei)
3737 {
3838 struct match_tagged_data *data = ei->data;
3939 struct mail *m = mctx->mail;
2222 #include "fdm.h"
2323 #include "match.h"
2424
25 int match_unmatched_match(struct match_ctx *, struct expritem *);
25 int match_unmatched_match(struct mail_ctx *, struct expritem *);
2626 void match_unmatched_desc(struct expritem *, char *, size_t);
2727
2828 struct match match_unmatched = {
3232 };
3333
3434 int
35 match_unmatched_match(struct match_ctx *mctx, unused struct expritem *ei)
35 match_unmatched_match(struct mail_ctx *mctx, unused struct expritem *ei)
3636 {
3737 if (mctx->matched)
3838 return (MATCH_FALSE);
2424 #define MATCH_FALSE 0
2525 #define MATCH_TRUE 1
2626 #define MATCH_ERROR 2
27
28 /* Match context. */
29 struct match_ctx {
30 double tim;
31
32 struct io *io;
33 struct account *account;
34 struct mail *mail;
35
36 int matched;
37 int stopped;
38
39 struct rule *rule;
40 ARRAY_DECL(, struct rule *) stack;
41
42 struct deliver_queue dqueue;
43
44 TAILQ_ENTRY(match_ctx) entry;
45 };
46 /* XXX should this be an array since we need to know the length? */
47 TAILQ_HEAD(match_queue, match_ctx);
27 #define MATCH_PARENT 3
4828
4929 /* Match functions. */
5030 struct match {
5131 const char *name;
5232
53 int (*match)(struct match_ctx *, struct expritem *);
33 int (*match)(struct mail_ctx *, struct expritem *);
5434 void (*desc)(struct expritem *, char *, size_t);
5535 };
5636
2929 #include "match.h"
3030
3131 int
32 parent_deliver(struct child *child, struct msg *msg, void *buf, size_t len)
32 parent_deliver(struct child *child, struct msg *msg, struct msgbuf *msgbuf)
3333 {
3434 struct child_deliver_data *data = child->data;
3535 struct account *a = data->account;
3636 struct mail *m = data->mail;
37
38 log_debug3("parent_deliver: got message type %d from child %ld",
39 msg->type, (long) child->pid);
4037
4138 switch (msg->type) {
4239 case MSG_DONE:
4542 fatalx("parent_deliver: unexpected message");
4643 }
4744
48 if (buf == NULL || len == 0)
45 if (msgbuf->buf == NULL || msgbuf->len == 0)
4946 fatalx("parent_deliver: bad tags");
5047 strb_destroy(&m->tags);
51 m->tags = buf;
48 m->tags = msgbuf->buf;
5249
5350 /* call the hook */
5451 data->hook(1, a, msg, data, &msg->data.error);
5552
5653 msg->type = MSG_DONE;
54 msg->id = data->msgid;
55
56 msgbuf->buf = m->tags;
57 msgbuf->len = STRB_SIZE(m->tags);
5758
5859 mail_send(m, msg);
5960
6061 child = data->child;
61 if (privsep_send(child->io, msg, m->tags, STRB_SIZE(m->tags)) != 0)
62 if (privsep_send(child->io, msg, msgbuf) != 0)
6263 fatalx("parent_deliver: privsep_send error");
6364
6465 mail_close(m);
3030
3131 void parent_fetch_action(struct child *, struct children *,
3232 struct deliver_ctx *, struct msg *);
33 void parent_fetch_cmd(struct child *, struct children *, struct match_ctx *,
33 void parent_fetch_cmd(struct child *, struct children *, struct mail_ctx *,
3434 struct msg *);
3535
3636 int
37 parent_fetch(struct child *child, struct msg *msg, void *buf, size_t len)
37 parent_fetch(struct child *child, struct msg *msg, struct msgbuf *msgbuf)
3838 {
3939 struct child_fetch_data *data = child->data;
4040 struct children *children = data->children;
4141 struct deliver_ctx *dctx;
42 struct match_ctx *mctx;
42 struct mail_ctx *mctx;
4343 struct mail *m;
44
45 log_debug3("parent_fetch: got message type %d from child %ld",
46 msg->type, (long) child->pid);
4744
4845 switch (msg->type) {
4946 case MSG_ACTION:
50 if (buf == NULL || len == 0)
47 if (msgbuf->buf == NULL || msgbuf->len == 0)
5148 fatalx("parent_fetch: bad tags");
5249 m = xcalloc(1, sizeof *m);
5350 mail_receive(m, msg);
54 m->tags = buf;
51 m->tags = msgbuf->buf;
5552
5653 dctx = xcalloc(1, sizeof *dctx);
5754 dctx->account = msg->data.account;
6057 parent_fetch_action(child, children, dctx, msg);
6158 break;
6259 case MSG_COMMAND:
63 if (buf == NULL || len == 0)
60 if (msgbuf->buf == NULL || msgbuf->len == 0)
6461 fatalx("parent_fetch: bad tags");
6562 m = xcalloc(1, sizeof *m);
6663 mail_receive(m, msg);
67 m->tags = buf;
64 m->tags = msgbuf->buf;
6865
6966 mctx = xcalloc(1, sizeof *mctx);
7067 mctx->account = msg->data.account;
106103
107104 data = xmalloc(sizeof *data);
108105 data->child = child;
106 data->msgid = msg->id;
109107 data->account = dctx->account;
110108 data->hook = child_deliver_action_hook;
111109 data->action = t;
118116
119117 void
120118 parent_fetch_cmd(struct child *child, struct children *children,
121 struct match_ctx *mctx, struct msg *msg)
119 struct mail_ctx *mctx, struct msg *msg)
122120 {
123121 uid_t uid = msg->data.uid;
124122 struct mail *m = mctx->mail;
126124
127125 data = xmalloc(sizeof *data);
128126 data->child = child;
127 data->msgid = msg->id;
129128 data->account = mctx->account;
130129 data->hook = child_deliver_cmd_hook;
131130 data->mctx = mctx;
2020 #include "fdm.h"
2121
2222 int
23 privsep_send(struct io *io, struct msg *msg, void *buf, size_t len)
23 privsep_send(struct io *io, struct msg *msg, struct msgbuf *msgbuf)
2424 {
2525 char *cause;
2626
27 if (buf != NULL && len > 0)
28 msg->size = len;
29 else
30 msg->size = 0;
27 msg->size = 0;
28 if (msgbuf != NULL && msgbuf->buf != NULL && msgbuf->len > 0)
29 msg->size = msgbuf->len;
3130
3231 io_write(io, msg, sizeof *msg);
3332 if (io_flush(io, &cause) != 0)
3433 return (1);
3534
36 if (buf != NULL && len > 0) {
37 io_write(io, buf, len);
35 if (msg->size != 0) {
36 io_write(io, msgbuf->buf, msgbuf->len);
3837 if (io_flush(io, &cause) != 0)
3938 return (1);
4039 }
4948 }
5049
5150 int
52 privsep_recv(struct io *io, struct msg *msg, void **buf, size_t *len)
51 privsep_recv(struct io *io, struct msg *msg, struct msgbuf *msgbuf)
5352 {
54 if (len != NULL)
55 *len = 0;
56 if (buf != NULL)
57 *buf = NULL;
58
5953 if (io_wait(io, sizeof *msg, NULL) != 0)
6054 return (1);
6155 if (io_read2(io, msg, sizeof *msg) != 0)
6357
6458 if (msg->size == 0)
6559 return (0);
66 if (buf == NULL || len == NULL)
60 if (msgbuf == NULL)
6761 return (1);
6862
69 *len = msg->size;
70 if (*len == 0) {
71 *buf = NULL;
63 msgbuf->len = msg->size;
64 if (msgbuf->len == 0) {
65 msgbuf->buf = NULL;
7266 return (0);
7367 }
74 if (io_wait(io, *len, NULL) != 0)
68 if (io_wait(io, msgbuf->len, NULL) != 0)
7569 return (1);
76 if ((*buf = io_read(io, *len)) == NULL)
70 if ((msgbuf->buf = io_read(io, msgbuf->len)) == NULL)
7771 return (1);
7872
7973 return (0);