When listing the queue, show all messages, even those that are
currently locked for delivery.  Indicate the lock with a '*' after
the queue ID.

--- a/dma.c
+++ b/dma.c
@@ -73,6 +73,7 @@
 struct authusers authusers = LIST_HEAD_INITIALIZER(authusers);
 static int daemonize = 1;
 struct config *config;
+static struct strlist seenmsg[16][16];
 
 static int open_locked(const char *, int);
 
@@ -666,8 +667,66 @@
 	/* NOTREACHED */
 }
 
+static int
+c2x(char c)
+{
+	if (c <= '9')
+		return (c - '0');
+	else if (c <= 'F')
+		return (c - 'A' + 10);
+	else
+		return (c - 'a' + 10);
+}
+
 static void
-load_queue(struct queue *queue)
+seen_init(void)
+{
+	int i, j;
+
+	for (i = 0; i < 16; i++)
+		for (j = 0; j < 16; j++)
+			SLIST_INIT(&seenmsg[i][j]);
+}
+
+static int
+seen(const char *msgid)
+{
+	const char *p;
+	size_t len;
+	int i, j;
+	struct stritem *t;
+
+	p = strchr(msgid, '.');
+	if (p == NULL)
+		return (0);
+	len = p - msgid;
+	if (len >= 2) {
+		i = c2x(msgid[len - 2]);
+		j = c2x(msgid[len - 1]);
+	} else if (len == 1) {
+		i = c2x(msgid[0]);
+		j = 0;
+	} else {
+		i = j = 0;
+	}
+	if (i < 0 || i >= 16 || j < 0 || j >= 16)
+		errx(1, "INTERNAL ERROR: bad seen code for msgid %s", msgid);
+	SLIST_FOREACH(t, &seenmsg[i][j], next)
+		if (!strncmp(t->str, msgid, len))
+			return (1);
+	t = malloc(sizeof(*t));
+	if (t == NULL)
+		errx(1, "Could not allocate %lu bytes",
+		    (unsigned long)(sizeof(*t)));
+	t->str = strdup(msgid);
+	if (t->str == NULL)
+		errx(1, "Could not duplicate msgid %s", msgid);
+	SLIST_INSERT_HEAD(&seenmsg[i][j], t, next);
+	return (0);
+}
+
+static void
+load_queue(struct queue *queue, int nolock)
 {
 	struct stat st;
 	struct qitem *it;
@@ -683,7 +742,7 @@
 	char *queueid;
 	char *queuefn;
 	off_t hdrlen;
-	int fd;
+	int fd, locked, seenit;
 
 	LIST_INIT(&queue->queue);
 
@@ -691,6 +750,7 @@
 	if (spooldir == NULL)
 		err(1, "reading queue");
 
+	seen_init();
 	while ((de = readdir(spooldir)) != NULL) {
 		sender = NULL;
 		queuef = NULL;
@@ -705,12 +765,19 @@
 			continue;
 		if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0)
 			goto fail;
+		seenit = seen(de->d_name);
+		locked = 0;
 		fd = open_locked(queuefn, O_RDONLY|O_NONBLOCK);
 		if (fd < 0) {
 			/* Ignore locked files */
-			if (errno == EWOULDBLOCK)
+			if (errno != EWOULDBLOCK)
+				goto skip_item;
+			if (!nolock || seenit)
 				continue;
-			goto skip_item;
+			fd = open(queuefn, O_RDONLY);
+			if (fd < 0)
+				goto skip_item;
+			locked = 1;
 		}
 
 		queuef = fdopen(fd, "r");
@@ -751,6 +818,7 @@
 			it->queuef = queuef;
 			it->queueid = queueid;
 			it->queuefn = fn;
+			it->locked = locked;
 			fn = NULL;
 		}
 		if (LIST_EMPTY(&itmqueue.queue)) {
@@ -810,9 +878,9 @@
 
 	LIST_FOREACH(it, &queue->queue, next) {
 		printf("\
-ID\t: %s\n\
+ID\t: %s%s\n\
 From\t: %s\n\
-To\t: %s\n--\n", it->queueid, it->sender, it->addr);
+To\t: %s\n--\n", it->queueid, it->locked? "*": "", it->sender, it->addr);
 	}
 }
 
@@ -914,7 +982,7 @@
 		if (argc != 0)
 			errx(1, "sending mail and displaying queue is"
 				" mutually exclusive");
-		load_queue(&lqueue);
+		load_queue(&lqueue, 1);
 		show_queue(&lqueue);
 		return (0);
 	}
@@ -922,7 +990,7 @@
 	if (doqueue) {
 		if (argc != 0)
 			errx(1, "sending mail and queue pickup is mutually exclusive");
-		load_queue(&lqueue);
+		load_queue(&lqueue, 0);
 		run_queue(&lqueue);
 		return (0);
 	}
--- a/dma.h
+++ b/dma.h
@@ -97,6 +97,7 @@
 	FILE *queuef;
 	off_t hdrlen;
 	int remote;
+	int locked;
 };
 LIST_HEAD(queueh, qitem);
 
