1 /* $Id$ */
2 
3 /*
4  * Copyright (c) 2006 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <sys/wait.h>
23 
24 #include <fcntl.h>
25 #include <fnmatch.h>
26 #include <limits.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30 
31 #include "fdm.h"
32 #include "deliver.h"
33 #include "fetch.h"
34 #include "match.h"
35 
36 void	fetch_status(struct account *, double);
37 int	fetch_account(struct account *, struct io *, int, double);
38 int	fetch_match(struct account *, struct msg *, struct msgbuf *);
39 int	fetch_deliver(struct account *, struct msg *, struct msgbuf *);
40 int	fetch_poll(struct account *, struct iolist *, struct io *, int);
41 int	fetch_purge(struct account *);
42 void	fetch_free(void);
43 void	fetch_free1(struct mail_ctx *);
44 
45 int	fetch_enqueue(struct account *, struct io *, struct mail *);
46 int	fetch_dequeue(struct account *, struct mail_ctx *);
47 
48 const char *account_get_method(struct account *);
49 
50 struct mail_queue	 fetch_matchq;
51 struct mail_queue	 fetch_deliverq;
52 
53 u_int			 fetch_dropped;
54 u_int			 fetch_kept;
55 
56 u_int			 fetch_queued;	 /* number of mails queued */
57 u_int			 fetch_blocked;	 /* blocked for parent */
58 
59 int
open_cache(struct account * a,struct cache * cache)60 open_cache(struct account *a, struct cache *cache)
61 {
62 	int	n;
63 
64 	if (cache->db != NULL)
65 		return (0);
66 
67 	if ((cache->db = db_open(cache->path)) == NULL) {
68 		log_warn("%s: %s", a->name, cache->path);
69 		return (-1);
70 	}
71 
72 	n = db_size(cache->db);
73 	log_debug3("%s: opened cache %s: %d keys", a->name, cache->path, n);
74 
75 	if (cache->expire == 0)
76 		return (0);
77 	if (db_expire(cache->db, cache->expire) != 0) {
78 		log_warnx("%s: %s: expiry failed", a->name, cache->path);
79 		return (-1);
80 	}
81 
82 	n -= db_size(cache->db);
83 	if (n < 0)
84 		n = 0;
85 	log_debug3("%s: cache %s: expired %d keys", a->name, cache->path, n);
86 
87 	return (0);
88 }
89 
90 int
child_fetch(struct child * child,struct io * pio)91 child_fetch(struct child *child, struct io *pio)
92 {
93 	struct child_fetch_data	*data = child->data;
94 	enum fdmop		 op = data->op;
95 	struct account		*a = data->account;
96 	struct msg		 msg;
97 	int			 error, flags;
98 	double			 tim;
99 
100 	log_debug2("%s: fetch started, pid %ld", a->name, (long) getpid());
101 
102 #ifdef HAVE_SETPROCTITLE
103 	setproctitle("child: %s", a->name);
104 #endif
105 
106 	log_debug2("%s: user is %lu", a->name, (u_long) geteuid());
107 	tim = get_time();
108 
109 	/* Process fetch or poll. */
110 	log_debug2("%s: started processing", a->name);
111 	flags = 0;
112 	if (op == FDMOP_POLL)
113 		flags |= FETCH_POLL;
114 	error = fetch_account(a, pio, flags, tim);
115 	log_debug2("%s: finished processing. exiting", a->name);
116 
117 	memset(&msg, 0, sizeof msg);
118 	msg.type = MSG_EXIT;
119 	log_debug3("%s: sending exit message to parent", a->name);
120 	if (privsep_send(pio, &msg, NULL) != 0)
121 		fatalx("privsep_send error");
122 	do {
123 		log_debug3("%s: waiting for exit message from parent", a->name);
124 		if (privsep_recv(pio, &msg, NULL) != 0)
125 			fatalx("privsep_recv error");
126 	} while (msg.type != MSG_EXIT);
127 
128 	return (error);
129 }
130 
131 int
fetch_poll(struct account * a,struct iolist * iol,struct io * pio,int timeout)132 fetch_poll(struct account *a, struct iolist *iol, struct io *pio, int timeout)
133 {
134 	struct io	*rio;
135 	char		*cause;
136 	double		 tim;
137 
138 	log_debug3(
139 	    "%s: polling: %u, timeout=%d", a->name, ARRAY_LENGTH(iol), timeout);
140 	tim = get_time();
141 	switch (io_polln(
142 	    ARRAY_DATA(iol), ARRAY_LENGTH(iol), &rio, timeout, &cause)) {
143 	case 0:
144 		if (rio == pio)
145 			fatalx("parent socket closed");
146 		log_warnx("%s: connection closed", a->name);
147 		return (-1);
148 	case -1:
149 		if (errno == EAGAIN)
150 			break;
151 		if (rio == pio)
152 			fatalx("parent socket error");
153 		log_warnx("%s: %s", a->name, cause);
154 		xfree(cause);
155 		return (-1);
156 	}
157 	tim = get_time() - tim;
158 
159 	return (0);
160 }
161 
162 int
fetch_match(struct account * a,struct msg * msg,struct msgbuf * msgbuf)163 fetch_match(struct account *a, struct msg *msg, struct msgbuf *msgbuf)
164 {
165 	struct mail_ctx	*mctx, *this;
166 
167 	if (TAILQ_EMPTY(&fetch_matchq))
168 		return (0);
169 
170 	mctx = TAILQ_FIRST(&fetch_matchq);
171 	while (mctx != NULL) {
172 		this = mctx;
173 		mctx = TAILQ_NEXT(this, entry);
174 
175 		log_debug3("%s: "
176 		    "trying (match) message %u", a->name, this->mail->idx);
177 		switch (mail_match(this, msg, msgbuf)) {
178 		case MAIL_ERROR:
179 			log_debug3("%s: match"
180 			    " message %u, error", a->name, this->mail->idx);
181 			return (-1);
182 		case MAIL_DELIVER:
183 			log_debug3("%s: match"
184 			    " message %u, deliver", a->name, this->mail->idx);
185 			TAILQ_REMOVE(&fetch_matchq, this, entry);
186 			TAILQ_INSERT_TAIL(&fetch_deliverq, this, entry);
187 			break;
188 		case MAIL_DONE:
189 			log_debug3("%s: match"
190 			    " message %u, done", a->name, this->mail->idx);
191 			if (fetch_dequeue(a, this) != 0)
192 				return (-1);
193 			break;
194 		case MAIL_BLOCKED:
195 			log_debug3("%s: match"
196 			    " message %u, blocked", a->name, this->mail->idx);
197 			fetch_blocked++;
198 			break;
199 		}
200 	}
201 
202 	return (0);
203 }
204 
205 int
fetch_deliver(struct account * a,struct msg * msg,struct msgbuf * msgbuf)206 fetch_deliver(struct account *a, struct msg *msg, struct msgbuf *msgbuf)
207 {
208 	struct mail_ctx	*mctx, *this;
209 
210 	if (TAILQ_EMPTY(&fetch_deliverq))
211 		return (0);
212 
213 	mctx = TAILQ_FIRST(&fetch_deliverq);
214 	while (mctx != NULL) {
215 		this = mctx;
216 		mctx = TAILQ_NEXT(this, entry);
217 
218 		log_debug3("%s:"
219 		    " trying (deliver) message %u", a->name, this->mail->idx);
220 		switch (mail_deliver(this, msg, msgbuf)) {
221 		case MAIL_ERROR:
222 			log_debug3("%s: deliver"
223 			    " message %u, error", a->name, this->mail->idx);
224 
225 			if (conf.ignore_errors) {
226 				log_warnx("%s: fetching error. ignored",
227 				    a->name);
228 
229 				TAILQ_REMOVE(&fetch_deliverq, this, entry);
230 				TAILQ_INSERT_TAIL(&fetch_matchq, this, entry);
231 
232 				this->mail->decision = DECISION_KEEP;
233 				if (fetch_dequeue(a, this) != 0)
234 					return (-1);
235 				break;
236 			}
237 
238 			return (-1);
239 		case MAIL_MATCH:
240 			log_debug3("%s: deliver"
241 			    " message %u, match", a->name, this->mail->idx);
242 			TAILQ_REMOVE(&fetch_deliverq, this, entry);
243 			TAILQ_INSERT_TAIL(&fetch_matchq, this, entry);
244 			break;
245 		case MAIL_BLOCKED:
246 			log_debug3("%s: deliver"
247 			    " message %u, blocked", a->name, this->mail->idx);
248 			fetch_blocked++;
249 			break;
250 		}
251 	}
252 
253 	return (0);
254 }
255 
256 void
fetch_free1(struct mail_ctx * mctx)257 fetch_free1(struct mail_ctx *mctx)
258 {
259 	struct deliver_ctx	*dctx;
260 
261 	while (!TAILQ_EMPTY(&mctx->dqueue)) {
262 		dctx = TAILQ_FIRST(&mctx->dqueue);
263 		TAILQ_REMOVE(&mctx->dqueue, dctx, entry);
264 		user_free(dctx->udata);
265 		xfree(dctx);
266 	}
267 
268 	ARRAY_FREE(&mctx->stack);
269 	mail_destroy(mctx->mail);
270 	xfree(mctx->mail);
271 	xfree(mctx);
272 }
273 
274 void
fetch_free(void)275 fetch_free(void)
276 {
277 	struct mail_ctx	*mctx;
278 
279 	while (!TAILQ_EMPTY(&fetch_matchq)) {
280 		mctx = TAILQ_FIRST(&fetch_matchq);
281 		TAILQ_REMOVE(&fetch_matchq, mctx, entry);
282 		fetch_free1(mctx);
283 	}
284 
285 	while (!TAILQ_EMPTY(&fetch_deliverq)) {
286 		mctx = TAILQ_FIRST(&fetch_deliverq);
287 		TAILQ_REMOVE(&fetch_deliverq, mctx, entry);
288 		fetch_free1(mctx);
289 	}
290 }
291 
292 int
fetch_purge(struct account * a)293 fetch_purge(struct account *a)
294 {
295 	static u_int	last_total = 0, last_dropped = 0;
296 	u_int		n;
297 
298 	if (conf.purge_after == 0)
299 		return (0);
300 
301 	n = fetch_dropped + fetch_kept;
302 	if (n == last_total || n % conf.purge_after != 0)
303 		return (0);
304 	last_total = n;
305 
306 	if (last_dropped == fetch_dropped) {
307 		log_debug("%s: not purging, no mails dropped", a->name);
308 		return (0);
309 	}
310 	last_dropped = fetch_dropped;
311 
312 	log_debug("%s: purging after %u mails", a->name, n);
313 	return (1);
314 }
315 
316 void
fetch_status(struct account * a,double tim)317 fetch_status(struct account *a, double tim)
318 {
319 	u_int	n;
320 
321 	tim = get_time() - tim;
322 	n = fetch_dropped + fetch_kept;
323 	if (n > 0) {
324 		log_info("%s: %u messages processed (%u kept) in %.3f seconds "
325 		    "(average %.3f)", a->name, n, fetch_kept, tim, tim / n);
326 	} else {
327 		log_info("%s: 0 messages processed in %.3f seconds",
328 		    a->name, tim);
329 	}
330 }
331 
332 int
fetch_account(struct account * a,struct io * pio,int nflags,double tim)333 fetch_account(struct account *a, struct io *pio, int nflags, double tim)
334 {
335 	struct msg	 msg, *msgp;
336 	struct msgbuf	 msgbuf;
337 	struct fetch_ctx fctx;
338 	struct cache	*cache;
339 	struct iolist	 iol;
340 	int		 aborted, complete, holding, timeout;
341 
342 	log_debug2("%s: fetching", a->name);
343 
344 	TAILQ_INIT(&fetch_matchq);
345 	TAILQ_INIT(&fetch_deliverq);
346 	fetch_queued = fetch_dropped = fetch_kept = 0;
347 
348 	if (nflags & FETCH_POLL && a->fetch->total == NULL) {
349 		log_info("%s: polling not supported", a->name);
350 		return (0);
351 	}
352 
353 	fctx.llen = IO_LINESIZE;
354 	fctx.lbuf = xmalloc(fctx.llen);
355 	fctx.flags = nflags;
356 
357 	fctx.mail = xcalloc(1, sizeof *fctx.mail);
358 	fctx.state = a->fetch->first;
359 
360 	ARRAY_INIT(&iol);
361 
362 	aborted = complete = holding = 0;
363 	for (;;) {
364 		log_debug3("%s: fetch loop start", a->name);
365 
366 		if (sigusr1) {
367 			log_debug("%s: caught SIGUSR1", a->name);
368 			if (!(nflags & FETCH_POLL))
369 				fetch_status(a, tim);
370 			sigusr1 = 0;
371 		}
372 
373 		fetch_blocked = 0;
374 
375 		/* Check for new privsep messages. */
376 		msgp = NULL;
377 		if (privsep_check(pio)) {
378 			if (privsep_recv(pio, &msg, &msgbuf) != 0)
379 				fatalx("privsep_recv error");
380 			log_debug3("%s: got message type %d, id %u", a->name,
381 			    msg.type, msg.id);
382 			msgp = &msg;
383 		}
384 
385 		/* Match and deliver mail. */
386 		if (fetch_match(a, msgp, &msgbuf) != 0)
387 			goto abort;
388 		if (fetch_deliver(a, msgp, &msgbuf) != 0)
389 			goto abort;
390 
391 		/* Check for purge and set flag if necessary. */
392 		if (fetch_purge(a))
393 			fctx.flags |= FETCH_PURGE;
394 
395 		/* Update the holding flag. */
396 		if (fetch_queued <= (u_int) conf.queue_low)
397 			holding = 0;
398 		if (fetch_queued >= (u_int) conf.queue_high)
399 			holding = 1;
400 
401 		/* If not holding and not finished, call the fetch handler. */
402 		if (!holding && !complete) {
403 			/*
404 			 * Set the empty flag if queues are empty. Purging
405 			 * shouldn't happen if this is clear.
406 			 */
407 			fctx.flags &= ~FETCH_EMPTY;
408 			if (fetch_queued == 0)
409 				fctx.flags |= FETCH_EMPTY;
410 
411 			/* Call the fetch function. */
412 			log_debug3("%s: calling fetch state (%p, flags 0x%02x)",
413 			    a->name, fctx.state, fctx.flags);
414 			switch (fctx.state(a, &fctx)) {
415 			case FETCH_ERROR:
416 				/* Fetch error. */
417 				log_debug3("%s: fetch, error", a->name);
418 				goto abort;
419 			case FETCH_EXIT:
420 				/* Fetch completed. */
421 				log_debug3("%s: fetch, exit", a->name);
422 				complete = 1;
423 				break;
424 			case FETCH_AGAIN:
425 				/* Fetch again - no blocking. */
426 				log_debug3("%s: fetch, again", a->name);
427 				continue;
428 			case FETCH_BLOCK:
429 				/* Fetch again - allow blocking. */
430 				log_debug3("%s: fetch, block", a->name);
431 				break;
432 			case FETCH_MAIL:
433 				/* Mail ready. */
434 				log_debug3("%s: fetch, mail", a->name);
435 				if (fetch_enqueue(a, pio, fctx.mail) != 0)
436 					goto abort;
437 				fctx.mail = xcalloc(1, sizeof *fctx.mail);
438 				continue;
439 			default:
440 				fatalx("unexpected fetch return");
441 			}
442 		}
443 
444 		/* If fetch finished and no more mails queued, exit. */
445 		if (complete && fetch_queued == 0)
446 			goto finished;
447 
448 		/* Prepare for poll. */
449 		ARRAY_CLEAR(&iol);
450 		ARRAY_ADD(&iol, pio);
451 		if (a->fetch->fill != NULL)
452 			a->fetch->fill(a, &iol);
453 
454 		/*
455 		 * Work out timeout. If the queues are empty, we can block,
456 		 * unless this fetch type doesn't have any sockets to poll -
457 		 * then we would block forever. Otherwise, if the queues are
458 		 * non-empty, we can block unless there are mails that aren't
459 		 * blocked (these mails can continue to be processed).
460 		 */
461 		timeout = conf.timeout;
462 		if (fetch_queued == 0 && ARRAY_LENGTH(&iol) == 1)
463 			timeout = 0;
464 		else if (fetch_queued != 0 && fetch_blocked != fetch_queued)
465 			timeout = 0;
466 
467 		/* Poll for fetch data or privsep messages. */
468 		log_debug3("%s: queued %u; blocked %u; flags 0x%02x", a->name,
469 		    fetch_queued, fetch_blocked, fctx.flags);
470 		if (fetch_poll(a, &iol, pio, timeout) != 0)
471 			goto abort;
472 	}
473 
474 abort:
475 	a->fetch->abort(a);
476 
477 	if (nflags & FETCH_POLL)
478 		log_warnx("%s: polling error. aborted", a->name);
479 	else
480 		log_warnx("%s: fetching error. aborted", a->name);
481 
482 	aborted = 1;
483 
484 finished:
485 	if (fctx.mail != NULL) {
486 		mail_destroy(fctx.mail);
487 		xfree(fctx.mail);
488 	}
489 
490 	xfree(fctx.lbuf);
491 	fetch_free();
492 	ARRAY_FREE(&iol);
493 
494 	/* Close caches. */
495 	TAILQ_FOREACH(cache, &conf.caches, entry) {
496 		if (cache->db != NULL)
497 			db_close(cache->db);
498 	}
499 
500 	/* Print results. */
501 	if (nflags & FETCH_POLL)
502 		log_info("%s: %u messages found", a->name, a->fetch->total(a));
503 	else
504 		fetch_status(a, tim);
505 	return (aborted);
506 }
507 
508 /*
509  * Returns a string describing the connection method, including cipher used (if
510  * any).
511  */
512 const char *
account_get_method(struct account * a)513 account_get_method(struct account *a)
514 {
515 	struct fetch_imap_data	*idata;
516 	struct fetch_pop3_data	*pdata;
517 	const SSL_CIPHER	*cipher = NULL;
518 	static char		 s[128];
519 	char			 tmp[128];
520 
521 	if (a->fetch == &fetch_imap) {
522 		idata = a->data;
523 		if (idata->io->ssl != NULL)
524 			cipher = SSL_get_current_cipher(idata->io->ssl);
525 	} else if (a->fetch == &fetch_pop3) {
526 		pdata = a->data;
527 		if (pdata->io->ssl != NULL)
528 			cipher = SSL_get_current_cipher(pdata->io->ssl);
529 	}
530 	if (cipher != NULL) {
531 		snprintf(tmp, sizeof tmp, "version=%s %s %d bits",
532 		    SSL_CIPHER_get_version(cipher),
533 		    SSL_CIPHER_get_name(cipher),
534 		    SSL_CIPHER_get_bits(cipher, NULL));
535 	} else
536 		snprintf(tmp, sizeof tmp, "unencrypted");
537 
538 	snprintf(s, sizeof s, "with %s (%s)", a->fetch->name, tmp);
539 	return (s);
540 }
541 
542 /*
543  * Check mail for various problems, add headers and fill tags, then create an
544  * mctx and enqueue it onto the fetch queue.
545  */
546 int
fetch_enqueue(struct account * a,struct io * pio,struct mail * m)547 fetch_enqueue(struct account *a, struct io *pio, struct mail *m)
548 {
549 	struct mail_ctx		*mctx;
550 	char			*hdr, rtime[128], *rhost, total[16];
551 	u_int			 n, b;
552 	size_t			 size;
553 	int			 error;
554 	struct tm		*tm;
555 	time_t			 t;
556 	const char		*tptr;
557 
558 	/*
559 	 * Check for oversize mails. This must be first since there is no
560 	 * guarantee anything other than size is valid if oversize.
561 	 */
562 	if (m->size > conf.max_size) {
563 		log_warnx("%s: message too big: %zu bytes", a->name, m->size);
564 		if (!conf.del_big)
565 			return (-1);
566 
567 		/* Delete the mail. */
568 		m->decision = DECISION_DROP;
569 		if (a->fetch->commit != NULL &&
570 		    a->fetch->commit(a, m) == FETCH_ERROR)
571 			return (-1);
572 
573 		mail_destroy(m);
574 		xfree(m);
575 		return (0);
576 	}
577 
578 	/*
579 	 * Find the mail body (needed by trim_from). This is probably slower
580 	 * than doing it during fetching but it guarantees consistency.
581 	 */
582 	m->body = find_body(m);
583 
584 	/* Trim "From" line, if any. */
585 	trim_from(m);
586 
587 	/* Check for empty mails. */
588 	if (m->size == 0) {
589 		log_warnx("%s: empty message", a->name);
590 		return (-1);
591 	}
592 
593 	/* Fill in standard mail attributes. */
594 	m->decision = DECISION_DROP;
595 	m->idx = ++a->idx;
596 	m->tim = get_time();
597 
598 	/* Add account name tag. */
599 	add_tag(&m->tags, "account", "%s", a->name);
600 
601 	/* Add mail time tags. */
602 	if (mailtime(m, &t) != 0) {
603 		log_debug2("%s: bad date header, using current time", a->name);
604 		t = time(NULL);
605 	}
606 	if ((tm = localtime(&t)) != NULL) {
607 		add_tag(&m->tags, "mail_hour", "%.2d", tm->tm_hour);
608 		add_tag(&m->tags, "mail_minute", "%.2d", tm->tm_min);
609 		add_tag(&m->tags, "mail_second", "%.2d", tm->tm_sec);
610 		add_tag(&m->tags, "mail_day", "%.2d", tm->tm_mday);
611 		add_tag(&m->tags, "mail_month", "%.2d", tm->tm_mon + 1);
612 		add_tag(&m->tags, "mail_year", "%.4d", 1900 + tm->tm_year);
613 		add_tag(&m->tags, "mail_year2", "%.2d", tm->tm_year % 100);
614 		add_tag(&m->tags, "mail_dayofweek", "%d", tm->tm_wday);
615 		add_tag(&m->tags, "mail_dayofyear", "%.2d", tm->tm_yday + 1);
616 		add_tag(&m->tags,
617 		    "mail_quarter", "%d", tm->tm_mon / 3 + 1);
618 	}
619 	if (rfc822time(t, rtime, sizeof rtime) != NULL)
620 		add_tag(&m->tags, "mail_rfc822date", "%s", rtime);
621 
622 	/* Fill in lines tags. */
623 	count_lines(m, &n, &b);
624 	log_debug2("%s: found %u lines, %u in body", a->name, n, b);
625 	add_tag(&m->tags, "lines", "%u", n);
626 	add_tag(&m->tags, "body_lines", "%u", b);
627 	if (n - b != 0)
628 		b++;	/* don't include the separator */
629 	add_tag(&m->tags, "header_lines", "%u", n - b);
630 
631 	/* Insert message-id tag. */
632 	hdr = find_header(m, "message-id", &size, 1);
633 	if (hdr == NULL || size == 0 || size > INT_MAX)
634 		log_debug2("%s: message-id not found", a->name);
635 	else {
636 		log_debug2("%s: message-id is: %.*s", a->name, (int) size, hdr);
637 		add_tag(&m->tags, "message_id", "%.*s", (int) size, hdr);
638 	}
639 
640 	/*
641 	 * Insert received header.
642 	 *
643 	 * No header line must exceed 998 bytes. Limiting the user-supplied
644 	 * stuff to 900 bytes gives plenty of space for the other stuff, and if
645 	 * it gets truncated, who cares?
646 	 */
647 	if (!conf.no_received) {
648 		error = 1;
649 		if (rfc822time(time(NULL), rtime, sizeof rtime) != NULL) {
650 			rhost = conf.host_fqdn;
651 			if (rhost == NULL)
652 				rhost = conf.host_name;
653 
654 			error = insert_header(m, "received", "Received: by "
655 			    "%.350s (%s " VERSION ", account \"%.350s\") \n\t%s\n\t%s",
656 			    rhost, __progname, a->name, account_get_method(a), rtime);
657 		}
658 		if (error != 0)
659 			log_debug3("%s: couldn't add received header", a->name);
660 	}
661 
662 	/* Insert Gmail-specific headers. */
663 	if ((tptr = find_tag(m->tags, "gmail_msgid")) != NULL &&
664 	    insert_header(m, "message-id", "X-GM-MSGID: %s", tptr) != 0)
665 		log_warnx("%s: failed to add header X-GM-MSGID", a->name);
666 	if ((tptr = find_tag(m->tags, "gmail_thrid")) != NULL &&
667 	    insert_header(m, "message-id", "X-GM-THRID: %s", tptr) != 0)
668 		log_warnx("%s: failed to add header X-GM-THRID", a->name);
669 	if ((tptr = find_tag(m->tags, "gmail_labels")) != NULL &&
670 	    insert_header(m, "message-id", "X-GM-LABELS: %s", tptr) != 0)
671 		log_warnx("%s: failed to add header X-GM-LABELS", a->name);
672 
673 	/* Fill wrapped line list. */
674 	n = fill_wrapped(m);
675 	log_debug2("%s: found %u wrapped lines", a->name, n);
676 
677 	/* Create the mctx. */
678 	mctx = xcalloc(1, sizeof *mctx);
679 	mctx->account = a;
680 	mctx->io = pio;
681 	mctx->mail = m;
682 	mctx->msgid = 0;
683 	mctx->done = 0;
684 
685 	mctx->matched = 0;
686 
687 	mctx->rule = TAILQ_FIRST(&conf.rules);
688 	TAILQ_INIT(&mctx->dqueue);
689 	ARRAY_INIT(&mctx->stack);
690 
691 	/* And enqueue it. */
692 	TAILQ_INSERT_TAIL(&fetch_matchq, mctx, entry);
693 	fetch_queued++;
694 
695 	*total = '\0';
696 	if (a->fetch->total != NULL && a->fetch->total(a) != 0)
697 		xsnprintf(total, sizeof total, " of %u", a->fetch->total(a));
698 	log_debug("%s: got message %u%s: size %zu, body %zu", a->name, m->idx,
699 	    total, m->size, m->body);
700 	return (0);
701 }
702 
703 /* Resolve final decision and dequeue mail. */
704 int
fetch_dequeue(struct account * a,struct mail_ctx * mctx)705 fetch_dequeue(struct account *a, struct mail_ctx *mctx)
706 {
707 	struct mail	*m = mctx->mail;
708 
709 	if (conf.keep_all || a->keep)
710 		m->decision = DECISION_KEEP;
711 
712 	switch (m->decision) {
713 	case DECISION_DROP:
714 		fetch_dropped++;
715 		log_debug("%s: deleting message %u", a->name, m->idx);
716 		break;
717 	case DECISION_KEEP:
718 		fetch_kept++;
719 		log_debug("%s: keeping message %u", a->name, m->idx);
720 		break;
721 	default:
722 		fatalx("invalid decision");
723 	}
724 
725 	if (a->fetch->commit != NULL && a->fetch->commit(a, m) == FETCH_ERROR)
726 		return (-1);
727 
728 	TAILQ_REMOVE(&fetch_matchq, mctx, entry);
729 	fetch_queued--;
730 
731 	fetch_free1(mctx);
732 
733 	return (0);
734 }
735