dma: convert to more extensible queue file format
authorSimon Schubert <corecode@dragonflybsd.org>
Thu, 27 Aug 2009 16:24:50 +0000 (18:24 +0200)
committerSimon Schubert <corecode@dragonflybsd.org>
Thu, 27 Aug 2009 21:12:55 +0000 (23:12 +0200)
libexec/dma/dma.h
libexec/dma/local.c
libexec/dma/mail.c
libexec/dma/net.c
libexec/dma/spool.c

index 96fd9bd..17b9437 100644 (file)
@@ -94,7 +94,6 @@ struct qitem {
        char *queueid;
        FILE *queuef;
        FILE *mailf;
-       off_t hdrlen;
        int remote;
 };
 LIST_HEAD(queueh, qitem);
index 109bd2b..9ce4928 100644 (file)
@@ -46,7 +46,7 @@ deliver_local(struct qitem *it, const char **errmsg)
        if (strcmp(sender, "") == 0)
                sender = "MAILER-DAEMON";
 
-       if (fseek(it->mailf, it->hdrlen, SEEK_SET) != 0) {
+       if (fseek(it->mailf, 0, SEEK_SET) != 0) {
                syslog(LOG_NOTICE, "local delivery deferred: can not seek: %m");
                return (1);
        }
index dd317e5..547990b 100644 (file)
@@ -100,7 +100,7 @@ bounce(struct qitem *it, const char *reason)
        if (error < 0)
                goto fail;
 
-       if (fseek(it->mailf, it->hdrlen, SEEK_SET) != 0)
+       if (fseek(it->mailf, 0, SEEK_SET) != 0)
                goto fail;
        if (config->features & FULLBOUNCE) {
                while ((pos = fread(line, 1, sizeof(line), it->mailf)) > 0) {
index 9be00f2..38d8614 100644 (file)
@@ -349,7 +349,7 @@ deliver_remote(struct qitem *it, const char **errmsg)
        /* asprintf can't take const */
        void *errmsgc = __DECONST(char **, errmsg);
 
-       if (fseek(it->mailf, it->hdrlen, SEEK_SET) != 0) {
+       if (fseek(it->mailf, 0, SEEK_SET) != 0) {
                asprintf(errmsgc, "can not seek: %s", strerror(errno));
                return (-1);
        }
index 21818b2..efe7c18 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <sys/stat.h>
 
+#include <ctype.h>
 #include <dirent.h>
 #include <err.h>
 #include <errno.h>
  * Spool file format:
  *
  * 'Q'id files (queue):
- *   id envelope-to
+ *   Organized like an RFC822 header, field: value.  Ignores unknown fields.
+ *   ID: id
+ *   Sender: envelope-from
+ *   Recipient: envelope-to
  *
  * 'M'id files (data):
- *   envelope-from
  *   mail data
  *
  * Each queue file needs to have a corresponding data file.
@@ -67,8 +70,6 @@ newspoolf(struct queue *queue)
        char fn[PATH_MAX+1];
        struct stat st;
        struct stritem *t;
-       struct qitem *it;
-       off_t hdrlen;
        int fd;
 
        if (snprintf(fn, sizeof(fn), "%s/%s", config->spooldir, "tmp_XXXXXXXXXX") <= 0)
@@ -95,15 +96,6 @@ newspoolf(struct queue *queue)
        if (queue->mailf == NULL)
                goto fail;
 
-       if (fprintf(queue->mailf, "%s\n", queue->sender) < 0)
-               goto fail;
-
-       hdrlen = ftello(queue->mailf);
-
-       LIST_FOREACH(it, &queue->queue, next) {
-               it->hdrlen = hdrlen;
-       }
-
        t = malloc(sizeof(*t));
        if (t != NULL) {
                t->str = queue->tmpf;
@@ -119,13 +111,117 @@ fail:
        return (-1);
 }
 
+static int
+writequeuef(struct qitem *it)
+{
+       int error;
+       int queuefd;
+
+       queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0600);
+       if (queuefd == -1)
+               return (-1);
+       it->queuef = fdopen(queuefd, "w+");
+       if (it->queuef == NULL)
+               return (-1);
+
+       error = fprintf(it->queuef,
+                       "ID: %s\n"
+                       "Sender: %s\n"
+                       "Recipient: %s\n",
+                        it->queueid,
+                        it->sender,
+                        it->addr);
+
+       if (error <= 0)
+               return (-1);
+
+       if (fflush(it->queuef) != 0 || fsync(fileno(it->queuef)) != 0)
+               return (-1);
+
+       return (0);
+}
+
+static struct qitem *
+readqueuef(struct queue *queue, char *queuefn)
+{
+       char line[1000];
+       struct queue itmqueue;
+       FILE *queuef = NULL;
+       char *s;
+       char *queueid = NULL, *sender = NULL, *addr = NULL;
+       struct qitem *it = NULL;
+
+       bzero(&itmqueue, sizeof(itmqueue));
+       LIST_INIT(&itmqueue.queue);
+
+       queuef = fopen(queuefn, "r");
+       if (queuef == NULL)
+               goto out;
+
+       while (!feof(queuef)) {
+               if (fgets(line, sizeof(line), queuef) == NULL || line[0] == 0)
+                       break;
+               line[strlen(line) - 1] = 0;     /* chop newline */
+
+               s = strchr(line, ':');
+               if (s == NULL)
+                       goto malformed;
+               *s = 0;
+
+               s++;
+               while (isspace(*s))
+                       s++;
+
+               s = strdup(s);
+               if (s == NULL || s[0] == 0)
+                       goto malformed;
+
+               if (strcmp(line, "ID") == 0) {
+                       queueid = s;
+               } else if (strcmp(line, "Sender") == 0) {
+                       sender = s;
+               } else if (strcmp(line, "Recipient") == 0) {
+                       addr = s;
+               } else {
+                       syslog(LOG_DEBUG, "ignoring unknown queue info `%s' in `%s'",
+                              line, queuefn);
+                       free(s);
+               }
+       }
+
+       if (queueid == NULL || sender == NULL || addr == NULL) {
+malformed:
+               errno = EINVAL;
+               syslog(LOG_ERR, "malformed queue file `%s'", queuefn);
+               goto out;
+       }
+
+       if (add_recp(&itmqueue, addr, 0) != 0)
+               goto out;
+
+       it = LIST_FIRST(&itmqueue.queue);
+       it->sender = sender; sender = NULL;
+       it->queueid = queueid; queueid = NULL;
+       it->queuefn = queuefn; queuefn = NULL;
+       LIST_INSERT_HEAD(&queue->queue, it, next);
+
+out:
+       if (sender != NULL)
+               free(sender);
+       if (queueid != NULL)
+               free(queueid);
+       if (addr != NULL)
+               free(addr);
+       if (queuef != NULL)
+               fclose(queuef);
+
+       return (it);
+}
+
 int
 linkspool(struct queue *queue)
 {
-       char line[1000];        /* by RFC2822 */
        struct stat st;
-       size_t error;
-       int queuefd;
        struct qitem *it;
 
        if (fflush(queue->mailf) != 0 || fsync(fileno(queue->mailf)) != 0)
@@ -146,20 +242,7 @@ linkspool(struct queue *queue)
                if (stat(it->queuefn, &st) == 0 || stat(it->mailfn, &st) == 0)
                        goto delfiles;
 
-               error = snprintf(line, sizeof(line), "%s %s\n", it->queueid, it->addr);
-               if ((ssize_t)error < 0 || error >= sizeof(line))
-                       goto delfiles;
-
-               queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0600);
-               if (queuefd == -1)
-                       goto delfiles;
-               it->queuef = fdopen(queuefd, "w+");
-               if (it->queuef == NULL)
-                       goto delfiles;
-
-               if (fwrite(line, strlen(line), 1, it->queuef) != 1)
-                       goto delfiles;
-               if (fflush(it->queuef) != 0 || fsync(fileno(it->queuef)) != 0)
+               if (writequeuef(it) != 0)
                        goto delfiles;
 
                if (link(queue->tmpf, it->mailfn) != 0)
@@ -185,20 +268,12 @@ delfiles:
 int
 load_queue(struct queue *queue)
 {
+       struct stat sb;
        struct qitem *it;
-       //struct queue queue, itmqueue;
-       struct queue itmqueue;
        DIR *spooldir;
        struct dirent *de;
-       char line[1000];
-       FILE *queuef;
-       FILE *mailf;
-       char *sender;
-       char *addr;
-       char *queueid;
        char *queuefn;
        char *mailfn;
-       off_t hdrlen;
 
        bzero(queue, sizeof(queue));
        LIST_INIT(&queue->queue);
@@ -208,12 +283,8 @@ load_queue(struct queue *queue)
                err(1, "reading queue");
 
        while ((de = readdir(spooldir)) != NULL) {
-               sender = NULL;
-               queuef = NULL;
-               mailf = NULL;
-               queueid = NULL;
                queuefn = NULL;
-               LIST_INIT(&itmqueue.queue);
+               mailfn = NULL;
 
                /* ignore temp files */
                if (strncmp(de->d_name, "tmp_", 4) == 0 || de->d_type != DT_REG)
@@ -225,64 +296,22 @@ load_queue(struct queue *queue)
                if (asprintf(&mailfn, "%s/M%s", config->spooldir, de->d_name + 1) < 0)
                        goto fail;
 
-               mailf = fopen(mailfn, "r");
-               if (mailf == NULL)
-                       goto skip_item;
-               if (fgets(line, sizeof(line), mailf) == NULL || line[0] == 0)
-                       goto skip_item;
-               line[strlen(line) - 1] = 0;     /* chop newline */
-               sender = strdup(line);
-               if (sender == NULL)
-                       goto skip_item;
-
-               hdrlen = ftell(mailf);
-
-               queuef = fopen(queuefn, "r");
-               if (queuef == NULL)
+               if (stat(mailfn, &sb) != 0)
                        goto skip_item;
 
-               if (fgets(line, sizeof(line), queuef) == NULL || line[0] == 0)
-                       goto skip_item;
-               line[strlen(line) - 1] = 0;
-               queueid = strdup(line);
-               if (queueid == NULL)
-                       goto skip_item;
-               addr = strchr(queueid, ' ');
-               if (addr == NULL)
+               it = readqueuef(queue, queuefn);
+               if (it == NULL)
                        goto skip_item;
-               *addr++ = 0;
 
-               if (add_recp(&itmqueue, addr, 0) != 0)
-                       goto skip_item;
-
-               it = LIST_FIRST(&itmqueue.queue);
-               it->sender = sender;
-               it->queueid = queueid;
-               it->queuefn = queuefn;
                it->mailfn = mailfn;
-               it->hdrlen = hdrlen;
-               LIST_INSERT_HEAD(&queue->queue, it, next);
-
-               if (queuef != NULL)
-                       fclose(queuef);
-               if (mailf != NULL)
-                       fclose(mailf);
                continue;
 
 skip_item:
                syslog(LOG_INFO, "could not pick up queue file: `%s'/`%s': %m", queuefn, mailfn);
-               if (sender != NULL)
-                       free(sender);
                if (queuefn != NULL)
                        free(queuefn);
                if (mailfn != NULL)
                        free(queuefn);
-               if (queueid != NULL)
-                       free(queueid);
-               if (queuef != NULL)
-                       fclose(queuef);
-               if (mailf != NULL)
-                       fclose(mailf);
        }
        closedir(spooldir);
        return (0);