diff --git a/contrib/dma/mail.c b/contrib/dma/mail.c
index 9e00c22d71db..9641818b8814 100644
--- a/contrib/dma/mail.c
+++ b/contrib/dma/mail.c
@@ -1,518 +1,516 @@
 /*
  * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>.
  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Simon Schubert <2@0x2c.org>.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
  * 3. Neither the name of The DragonFly Project nor the names of its
  *    contributors may be used to endorse or promote products derived
  *    from this software without specific, prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <errno.h>
 #include <inttypes.h>
 #include <signal.h>
 #include <strings.h>
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>
 
 #include "dma.h"
 
 #define MAX_LINE_RFC822	999 /* 998 characters plus \n */
 
 void
 bounce(struct qitem *it, const char *reason)
 {
 	struct queue bounceq;
 	char line[1000];
 	size_t pos;
 	int error;
 
 	/* Don't bounce bounced mails */
 	if (it->sender[0] == 0) {
 		syslog(LOG_INFO, "can not bounce a bounce message, discarding");
 		exit(EX_SOFTWARE);
 	}
 
 	bzero(&bounceq, sizeof(bounceq));
 	LIST_INIT(&bounceq.queue);
 	bounceq.sender = "";
 	if (add_recp(&bounceq, it->sender, EXPAND_WILDCARD) != 0)
 		goto fail;
 
 	if (newspoolf(&bounceq) != 0)
 		goto fail;
 
 	syslog(LOG_ERR, "delivery failed, bouncing as %s", bounceq.id);
 	setlogident("%s", bounceq.id);
 
 	error = fprintf(bounceq.mailf,
 		"Received: from MAILER-DAEMON\n"
 		"\tid %s\n"
 		"\tby %s (%s on %s);\n"
 		"\t%s\n"
 		"X-Original-To: <%s>\n"
 		"From: MAILER-DAEMON <>\n"
 		"To: %s\n"
 		"Subject: Mail delivery failed\n"
 		"Message-Id: <%s@%s>\n"
 		"Date: %s\n"
 		"\n"
 		"This is the %s at %s.\n"
 		"\n"
 		"There was an error delivering your mail to <%s>.\n"
 		"\n"
 		"%s\n"
 		"\n"
 		"%s\n"
 		"\n",
 		bounceq.id,
 		hostname(), VERSION, systemhostname(),
 		rfc822date(),
 		it->addr,
 		it->sender,
 		bounceq.id, hostname(),
 		rfc822date(),
 		VERSION, hostname(),
 		it->addr,
 		reason,
 		config.features & FULLBOUNCE ?
 		    "Original message follows." :
 		    "Message headers follow.");
 	if (error < 0)
 		goto fail;
 
 	if (fseek(it->mailf, 0, SEEK_SET) != 0)
 		goto fail;
 	if (config.features & FULLBOUNCE) {
 		while ((pos = fread(line, 1, sizeof(line), it->mailf)) > 0) {
 			if (fwrite(line, 1, pos, bounceq.mailf) != pos)
 				goto fail;
 		}
 	} else {
 		while (!feof(it->mailf)) {
 			if (fgets(line, sizeof(line), it->mailf) == NULL)
 				break;
 			if (line[0] == '\n')
 				break;
 			if (fwrite(line, strlen(line), 1, bounceq.mailf) != 1)
 				goto fail;
 		}
 	}
 
 	if (linkspool(&bounceq) != 0)
 		goto fail;
 	/* bounce is safe */
 
 	delqueue(it);
 
 	run_queue(&bounceq);
 	/* NOTREACHED */
 
 fail:
 	syslog(LOG_CRIT, "error creating bounce: %m");
 	delqueue(it);
 	exit(EX_IOERR);
 }
 
 struct parse_state {
 	char addr[1000];
 	int pos;
 
 	enum {
 		NONE = 0,
 		START,
 		MAIN,
 		EOL,
 		QUIT
 	} state;
 	int comment;
 	int quote;
 	int brackets;
 	int esc;
 };
 
 /*
  * Simplified RFC2822 header/address parsing.
  * We copy escapes and quoted strings directly, since
  * we have to pass them like this to the mail server anyways.
  * XXX local addresses will need treatment
  */
 static int
 parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
 {
 	char *addr;
 
 again:
 	switch (ps->state) {
 	case NONE:
 		return (-1);
 
 	case START:
 		/* init our data */
 		bzero(ps, sizeof(*ps));
 
 		/* skip over header name */
 		while (*s != ':')
 			s++;
 		s++;
 		ps->state = MAIN;
 		break;
 
 	case MAIN:
 		/* all fine */
 		break;
 
 	case EOL:
 		switch (*s) {
 		case ' ':
 		case '\t':
 			ps->state = MAIN;
 			break;
 
 		default:
 			ps->state = QUIT;
 			if (ps->pos != 0)
 				goto newaddr;
 			return (0);
 		}
 		break;
 
 	case QUIT:
 		return (0);
 	}
 
 	for (; *s != 0; s++) {
 		if (ps->esc) {
 			ps->esc = 0;
 
 			switch (*s) {
 			case '\r':
 			case '\n':
 				goto err;
 
 			default:
 				goto copy;
 			}
 		}
 
 		if (ps->quote) {
 			switch (*s) {
 			case '"':
 				ps->quote = 0;
 				goto copy;
 
 			case '\\':
 				ps->esc = 1;
 				goto copy;
 
 			case '\r':
 			case '\n':
 				goto eol;
 
 			default:
 				goto copy;
 			}
 		}
 
 		switch (*s) {
 		case '(':
 			ps->comment++;
 			break;
 
 		case ')':
 			if (ps->comment)
 				ps->comment--;
 			else
 				goto err;
 			goto skip;
 
 		case '"':
 			ps->quote = 1;
 			goto copy;
 
 		case '\\':
 			ps->esc = 1;
 			goto copy;
 
 		case '\r':
 		case '\n':
 			goto eol;
 		}
 
 		if (ps->comment)
 			goto skip;
 
 		switch (*s) {
 		case ' ':
 		case '\t':
 			/* ignore whitespace */
 			goto skip;
 
 		case '<':
 			/* this is the real address now */
 			ps->brackets = 1;
 			ps->pos = 0;
 			goto skip;
 
 		case '>':
 			if (!ps->brackets)
 				goto err;
 			ps->brackets = 0;
 
 			s++;
 			goto newaddr;
 
 		case ':':
 			/* group - ignore */
 			ps->pos = 0;
 			goto skip;
 
 		case ',':
 		case ';':
 			/*
 			 * Next address, copy previous one.
 			 * However, we might be directly after
 			 * a <address>, or have two consecutive
 			 * commas.
 			 * Skip the comma unless there is
 			 * really something to copy.
 			 */
 			if (ps->pos == 0)
 				goto skip;
 			s++;
 			goto newaddr;
 
 		default:
 			goto copy;
 		}
 
 copy:
 		if (ps->comment)
 			goto skip;
 
 		if (ps->pos + 1 == sizeof(ps->addr))
 			goto err;
 		ps->addr[ps->pos++] = *s;
 
 skip:
 		;
 	}
 
 eol:
 	ps->state = EOL;
 	return (0);
 
 err:
 	ps->state = QUIT;
 	return (-1);
 
 newaddr:
 	ps->addr[ps->pos] = 0;
 	ps->pos = 0;
 	addr = strdup(ps->addr);
 	if (addr == NULL)
 		errlog(EX_SOFTWARE, "strdup");
 
 	if (add_recp(queue, addr, EXPAND_WILDCARD) != 0)
 		errlogx(EX_DATAERR, "invalid recipient `%s'", addr);
 
 	goto again;
 }
 
 static int
 writeline(struct queue *queue, const char *line, ssize_t linelen)
 {
 	ssize_t len;
 
 	while (linelen > 0) {
 		len = linelen;
 		if (linelen > MAX_LINE_RFC822) {
 			len = MAX_LINE_RFC822 - 10;
 		}
 
 		if (fwrite(line, len, 1, queue->mailf) != 1)
 			return (-1);
 
 		if (linelen <= MAX_LINE_RFC822)
 			break;
 
 		if (fwrite("\n", 1, 1, queue->mailf) != 1)
 			return (-1);
 
 		line += MAX_LINE_RFC822 - 10;
 		linelen = strlen(line);
 	}
 	return (0);
 }
 
 int
 readmail(struct queue *queue, int nodot, int recp_from_header)
 {
 	struct parse_state parse_state;
 	char *line = NULL;
 	ssize_t linelen;
 	size_t linecap = 0;
 	char newline[MAX_LINE_RFC822 + 1];
 	size_t error;
 	int had_headers = 0;
 	int had_from = 0;
 	int had_messagid = 0;
 	int had_date = 0;
 	int had_first_line = 0;
 	int had_last_line = 0;
 	int nocopy = 0;
 	int ret = -1;
 
 	parse_state.state = NONE;
 
 	error = fprintf(queue->mailf,
 		"Received: from %s (uid %d)\n"
 		"\t(envelope-from %s)\n"
 		"\tid %s\n"
 		"\tby %s (%s on %s);\n"
 		"\t%s\n",
 		username, useruid,
 		queue->sender,
 		queue->id,
 		hostname(), VERSION, systemhostname(),
 		rfc822date());
 	if ((ssize_t)error < 0)
 		return (-1);
 
-	while (!feof(stdin)) {
+	while ((linelen = getline(&line, &linecap, stdin)) > 0) {
 		newline[0] = '\0';
-		if ((linelen = getline(&line, &linecap, stdin)) <= 0)
-			break;
 		if (had_last_line)
 			errlogx(EX_DATAERR, "bad mail input format:"
 				" from %s (uid %d) (envelope-from %s)",
 				username, useruid, queue->sender);
 		linelen = strlen(line);
 		if (linelen == 0 || line[linelen - 1] != '\n') {
 			/*
 			 * This line did not end with a newline character.
 			 * If we fix it, it better be the last line of
 			 * the file.
 			 */
 			line[linelen] = '\n';
 			line[linelen + 1] = 0;
 			had_last_line = 1;
 		}
 		if (!had_first_line) {
 			/*
 			 * Ignore a leading RFC-976 From_ or >From_ line mistakenly
 			 * inserted by some programs.
 			 */
 			if (strprefixcmp(line, "From ") == 0 || strprefixcmp(line, ">From ") == 0)
 				continue;
 			had_first_line = 1;
 		}
 		if (!had_headers) {
 			if (linelen > MAX_LINE_RFC822) {
 				/* XXX also split headers */
 				errlogx(EX_DATAERR, "bad mail input format:"
 				    " from %s (uid %d) (envelope-from %s)",
 				    username, useruid, queue->sender);
 			}
 			/*
 			 * Unless this is a continuation, switch of
 			 * the Bcc: nocopy flag.
 			 */
 			if (!(line[0] == ' ' || line[0] == '\t'))
 				nocopy = 0;
 
 			if (strprefixcmp(line, "Date:") == 0)
 				had_date = 1;
 			else if (strprefixcmp(line, "Message-Id:") == 0)
 				had_messagid = 1;
 			else if (strprefixcmp(line, "From:") == 0)
 				had_from = 1;
 			else if (strprefixcmp(line, "Bcc:") == 0)
 				nocopy = 1;
 
 			if (parse_state.state != NONE) {
 				if (parse_addrs(&parse_state, line, queue) < 0) {
 					errlogx(EX_DATAERR, "invalid address in header\n");
 					/* NOTREACHED */
 				}
 			}
 
 			if (recp_from_header && (
 					strprefixcmp(line, "To:") == 0 ||
 					strprefixcmp(line, "Cc:") == 0 ||
 					strprefixcmp(line, "Bcc:") == 0)) {
 				parse_state.state = START;
 				if (parse_addrs(&parse_state, line, queue) < 0) {
 					errlogx(EX_DATAERR, "invalid address in header\n");
 					/* NOTREACHED */
 				}
 			}
 		}
 
 		if (strcmp(line, "\n") == 0 && !had_headers) {
 			had_headers = 1;
 			while (!had_date || !had_messagid || !had_from) {
 				if (!had_date) {
 					had_date = 1;
 					snprintf(newline, sizeof(newline), "Date: %s\n", rfc822date());
 				} else if (!had_messagid) {
 					/* XXX msgid, assign earlier and log? */
 					had_messagid = 1;
 					snprintf(newline, sizeof(newline), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
 						 (uintmax_t)time(NULL),
 						 queue->id,
 						 (uintmax_t)random(),
 						 hostname());
 				} else if (!had_from) {
 					had_from = 1;
 					snprintf(newline, sizeof(newline), "From: <%s>\n", queue->sender);
 				}
 				if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)
 					goto fail;
 			}
 			strlcpy(newline, "\n", sizeof(newline));
 		}
 		if (!nodot && linelen == 2 && line[0] == '.')
 			break;
 		if (!nocopy) {
 			if (newline[0]) {
 				if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)
 					goto fail;
 			} else {
 				if (writeline(queue, line, linelen) != 0)
 					goto fail;
 			}
 		}
 	}
-
-	ret = 0;
+	if (ferror(stdin) == 0)
+		ret = 0;
 fail:
 	free(line);
 	return (ret);
 }