]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
mailqueue: factorize the code opening a file in the queue
authorBaptiste Daroussin <bapt@FreeBSD.org>
Wed, 5 Jan 2022 10:00:27 +0000 (11:00 +0100)
committerBaptiste Daroussin <bapt@FreeBSD.org>
Wed, 5 Jan 2022 10:09:13 +0000 (11:09 +0100)
include/mlmmj.h
include/prepstdreply.h
src/mlmmj-process.c
src/mlmmj.c
src/prepstdreply.c
src/send_digest.c

index 82655d4c2267dd4507945e505d22ba106614e7f6..3c1dd4da40f99313d914b9cda64a95396a698e35 100644 (file)
@@ -122,7 +122,7 @@ void mlmmj_list_init(struct mlmmj_list *list);
 bool mlmmj_list_open(struct mlmmj_list *list);
 void mlmmj_list_close(struct mlmmj_list *list);
 void queuedmail_free(struct queuedmail *q);
-struct queuedmail *queuedmail_new(void);
+struct queuedmail *queuedmail_new(struct mlmmj_list *list);
 
 #define MY_ASSERT(expression) if (!(expression)) { \
                        errno = 0; \
index 7c6153fd3b64d103947d061a0d4b4d41b232c41f..4f58c2e66da70478d27e11fac23c2a3d5de3edfe 100644 (file)
@@ -58,7 +58,7 @@ text *open_text_file(struct mlmmj_list *list, const char *filename);
 text *open_text(struct mlmmj_list *list, const char *purpose, const char *action,
                   const char *reason, const char *type, const char *compat);
 void register_unformatted(text *txt, const char *token, const char *subst);
-void register_originalmail(text *txt, const char *mailname);
+void register_originalmail(text *txt, int fd);
 void register_formatted(text *txt, const char *token,
                rewind_function rew, get_function get, void * state);
 char *get_processed_text_line(text *txt, int headers, struct mlmmj_list *list);
index 5b557b8361a03cfb3184ce9dab5ba5dc19455bfa..de41f5c76d7e7c2833a2d646adc5b9aa1ab7310c 100644 (file)
@@ -170,7 +170,9 @@ static void newmoderated(struct mlmmj_list *list, const char *mailfilename,
        register_unformatted(txt, "moderators", "%moderators%"); /* DEPRECATED */
        register_formatted(txt, "moderators",
                        rewind_memory_lines, get_memory_line, mls);
-       register_originalmail(txt, mailfilename);
+       int fd = open(mailfilename, O_RDONLY);
+       register_originalmail(txt, fd);
+       close(fd);
        queuefilename = prepstdreply(txt, list, "$listowner$", to, replyto, false);
        MY_ASSERT(queuefilename);
        close_text(txt);
@@ -226,7 +228,9 @@ static void newmoderated(struct mlmmj_list *list, const char *mailfilename,
        register_unformatted(txt, "moderators", "%moderators%"); /* DEPRECATED */
        register_formatted(txt, "moderators",
                        rewind_memory_lines, get_memory_line, mls);
-       register_originalmail(txt, mailfilename);
+       int fd2 = open(mailfilename, O_RDONLY);
+       register_originalmail(txt, fd2);
+       close(fd2);
        q = prepqstdreply(txt, list, "$listowner$", efromsender, NULL);
        MY_ASSERT(q);
        close_text(txt);
@@ -439,7 +443,7 @@ static void print_help(const char *prg)
 static void
 send_denymail(struct mlmmj_list *list, const char *cause, const char *subcause,
     char *causestr, const char *posteraddr, const char *subject,
-    char *donemailname, const char *mailfile)
+    struct queuedmail *done, const char *mailfile)
 {
        char *fromaddr;
        text *txt;
@@ -453,13 +457,13 @@ send_denymail(struct mlmmj_list *list, const char *cause, const char *subcause,
        register_unformatted(txt, "posteraddr", posteraddr);
        if (causestr != NULL)
                register_unformatted(txt, cause, causestr);
-       register_originalmail(txt, donemailname);
+       register_originalmail(txt, done->fd);
        q = prepqstdreply(txt, list, "$listowner$", posteraddr, NULL);
        MY_ASSERT(q);
        close_text(txt);
-       unlink(donemailname);
+       unlinkat(list->queuefd, done->name, 0);
        unlink(mailfile);
-       free(donemailname);
+       queuedmail_free(q);
        free(causestr);
        memset(&mh, 0, sizeof(mh));
        mh.to = posteraddr;
@@ -473,12 +477,12 @@ int main(int argc, char **argv)
 {
        int i, j, opt, noprocess = 0, moderated = 0, send = 0;
        enum modreason modreason;
-       int hdrfd, footfd, rawmailfd, donemailfd, omitfd;
+       int hdrfd, footfd, rawmailfd, omitfd;
        int addrtocc, intocc = 0, findaddress = 0;
        int maxmailsize = 0;
        int notmetoo = 0;
        int subonlypost = 0, modonlypost = 0, modnonsubposts = 0, foundaddr = 0;
-       char *mailfile = NULL, *donemailname = NULL;
+       char *mailfile = NULL, *donemailname;
        char *randomstr = NULL, *mqueuename, *omitfilename;
        char *mlmmjsend, *mlmmjsub, *mlmmjunsub, *mlmmjbounce;
        char *bindir, *subjectprefix, *discardname;
@@ -498,6 +502,7 @@ int main(int argc, char **argv)
        struct strlist *delheaders = NULL;
        struct strlist allheaders;
        struct strlist *listaddrs = NULL;
+       struct queuedmail *q;
        struct mailhdr readhdrs[] = {
                { "From:", 0, NULL },
                { "To:", 0, NULL },
@@ -565,28 +570,16 @@ int main(int argc, char **argv)
                }
        }
 
-        do {
-                free(donemailname);
-                free(randomstr);
-                randomstr = random_str();
-               xasprintf(&donemailname, "%s/queue/%s", list.dir, randomstr);
-
-                donemailfd = open(donemailname, O_RDWR|O_CREAT|O_EXCL,
-                                               S_IRUSR|S_IWUSR);
-
-        } while ((donemailfd < 0) && (errno == EEXIST));
-
-       if(donemailfd < 0) {
-               log_error(LOG_ARGS, "could not create %s", donemailname);
-               free(donemailname);
+       q = queuedmail_new(&list);
+       if (q == NULL) {
+               log_error(LOG_ARGS, "could not create queued mail");
                exit(EXIT_FAILURE);
        }
 #if 0
        log_error(LOG_ARGS, "donemailname = [%s]\n", donemailname);
 #endif
        if((rawmailfd = open(mailfile, O_RDONLY)) < 0) {
-               unlink(donemailname);
-               free(donemailname);
+               unlinkat(list.queuefd, q->name, 0);
                log_error(LOG_ARGS, "could not open() input mail file");
                exit(EXIT_FAILURE);
        }
@@ -612,7 +605,7 @@ int main(int argc, char **argv)
 
        subjectprefix = ctrlvalue(&list, "prefix");
 
-       if(do_all_the_voodoo_here(rawmailfd, donemailfd, hdrfd, footfd,
+       if(do_all_the_voodoo_here(rawmailfd, q->fd, hdrfd, footfd,
                                delheaders, readhdrs,
                                &allheaders, subjectprefix) < 0) {
                log_error(LOG_ARGS, "Error in do_all_the_voodoo_here");
@@ -624,7 +617,7 @@ int main(int argc, char **argv)
        free(delheaders->strs);
 
        close(rawmailfd);
-       close(donemailfd);
+       queuedmail_free(q);
 
        if(hdrfd >= 0)
                close(hdrfd);
@@ -725,8 +718,7 @@ int main(int argc, char **argv)
                        log_error(LOG_ARGS, "fromemails.emaillist[%d] = %s\n",
                                        i, fromemails.emaillist[i]);
                rename(mailfile, discardname);
-               unlink(donemailname);
-               free(donemailname);
+               unlinkat(list.queuefd, q->name, 0);
                free(discardname);
                free(randomstr);
                /* TODO: free emailstructs */
@@ -760,6 +752,8 @@ int main(int argc, char **argv)
        if (!subject) subject = xstrdup("");
 
        if(recipextra) {
+               char *donemailname;
+               xasprintf(&donemailname, "%s/queue/%s", list.dir, q->name);
                xasprintf(&owner, "%s/control/owner", list.dir);
                if(owner && strcmp(recipextra, "owner") == 0) {
                        /* Why is this here, and not in listcontrol() ?
@@ -778,13 +772,7 @@ int main(int argc, char **argv)
                                                    "input mail file");
                                exit(EXIT_FAILURE);
                        }
-                       if((donemailfd = open(donemailname,
-                                               O_WRONLY|O_TRUNC)) < 0) {
-                               log_error(LOG_ARGS, "could not open() "
-                                                   "output mail file");
-                               exit(EXIT_FAILURE);
-                       }
-                       if(do_all_the_voodoo_here(rawmailfd, donemailfd, -1,
+                       if(do_all_the_voodoo_here(rawmailfd, q->fd, -1,
                                        -1, delheaders,
                                        NULL, &allheaders, NULL) < 0) {
                                log_error(LOG_ARGS, "do_all_the_voodoo_here");
@@ -794,7 +782,7 @@ int main(int argc, char **argv)
                                free(delheaders->strs[i]);
                        free(delheaders->strs);
                        close(rawmailfd);
-                       close(donemailfd);
+                       queuedmail_free(q);
                        unlink(mailfile);
                        log_oper(list.dir, OPLOGFNAME, "mlmmj-process: sending"
                                        " mail from %s to owner",
@@ -825,8 +813,9 @@ int main(int argc, char **argv)
        maxmailsizestr = ctrlvalue(&list, "maxmailsize");
        if(maxmailsizestr) {
                maxmailsize = atol(maxmailsizestr);
-               if(stat(donemailname, &st) < 0) {
-                       log_error(LOG_ARGS, "stat(%s,..) failed", donemailname);
+               if(fstat(q->fd, &st) < 0) {
+                       log_error(LOG_ARGS, "stat(%s/queue/%s,..) failed",
+                           list.dir, q->name);
                        exit(EXIT_FAILURE);
                }
 
@@ -834,17 +823,16 @@ int main(int argc, char **argv)
 
                        if (statctrl(&list, "nomaxmailsizedenymails")) {
                                errno = 0;
-                               log_error(LOG_ARGS, "Discarding %s due to"
+                               log_error(LOG_ARGS, "Discarding %s/queue/%s due to"
                                                " size limit (%d bytes too big)",
-                                               donemailname, (st.st_size - maxmailsize));
-                               unlink(donemailname);
+                                               list.dir, q->name, (st.st_size - maxmailsize));
+                               unlinkat(list.queuefd, q->name, 0);
                                unlink(mailfile);
-                               free(donemailname);
                                free(maxmailsizestr);
                                exit(EXIT_SUCCESS);
                        }
                        send_denymail(&list, "maxmailsize", "maxmailsize",
-                           maxmailsizestr, posteraddr, subject, donemailname, mailfile);
+                           maxmailsizestr, posteraddr, subject, q, mailfile);
                }
        }
 
@@ -858,8 +846,8 @@ int main(int argc, char **argv)
                log_error(LOG_ARGS, "Discarding %s due to missing envelope"
                                " from address", mailfile);
                rename(mailfile, discardname);
-               unlink(donemailname);
-               free(donemailname);
+               unlinkat(list.queuefd, q->name, 0);
+               queuedmail_free(q);
                free(discardname);
                free(randomstr);
                /* TODO: free emailstructs */
@@ -879,12 +867,12 @@ int main(int argc, char **argv)
                                        " and From: was the list or"
                                        " notoccdenymails was set",
                                        mailfile);
-                       unlink(donemailname);
-                       free(donemailname);
+                       unlinkat(list.queuefd, q->name, 0);
+                       queuedmail_free(q);
                        exit(EXIT_SUCCESS);
                }
                send_denymail(&list, "tocc", "notintocc", NULL,
-                   posteraddr, subject, donemailname, mailfile);
+                   posteraddr, subject, q, mailfile);
        }
 
        access_rules = ctrlvalues(&list, "access");
@@ -903,27 +891,27 @@ int main(int argc, char **argv)
                                        " address or noaccessdenymails"
                                        " was set",
                                        mailfile);
-                               unlink(donemailname);
-                               free(donemailname);
+                               unlinkat(list.queuefd, q->name, 0);
+                               queuedmail_free(q);
                                exit(EXIT_SUCCESS);
                        }
                        send_denymail(&list, "access", "access",
-                           NULL, posteraddr, subject, donemailname, mailfile);
+                           NULL, posteraddr, subject, q, mailfile);
                } else if (accret == MODERATE) {
                        moderated = 1;
                        modreason = ACCESS;
                } else if (accret == DISCARD) {
-                       xasprintf(&discardname, "%s/queue/discarded/%s",
-                           list.dir, randomstr);
+                       xasprintf(&discardname, "/discarded/%s", randomstr);
                        free(randomstr);
-                       if(rename(donemailname, discardname) < 0) {
+                       if(renameat(list.queuefd, q->name,
+                           list.queuefd, discardname) < 0) {
                                log_error(LOG_ARGS, "could not rename(%s,%s)",
-                                           donemailname, discardname);
-                               free(donemailname);
+                                           q->name, discardname);
+                               queuedmail_free(q);
                                free(discardname);
                                exit(EXIT_FAILURE);
                        }
-                       free(donemailname);
+                       queuedmail_free(q);
                        free(discardname);
                        exit(EXIT_SUCCESS);
                } else if (accret == SEND) {
@@ -947,8 +935,8 @@ int main(int argc, char **argv)
                                        " there are sender restrictions but"
                                        " From: was the list address",
                                        mailfile);
-                       unlink(donemailname);
-                       free(donemailname);
+                       unlinkat(list.queuefd, q->name, 0);
+                       queuedmail_free(q);
                        exit(EXIT_SUCCESS);
                }
                if(subonlypost) {
@@ -972,17 +960,17 @@ int main(int argc, char **argv)
                                log_error(LOG_ARGS, "Discarding %s because"
                                        " no{sub|mod}onlydenymails was set",
                                        mailfile);
-                               unlink(donemailname);
-                               free(donemailname);
+                               unlinkat(list.queuefd, q->name, 0);
+                               queuedmail_free(q);
                                exit(EXIT_SUCCESS);
                            }
                            if (subonlypost) {
                                send_denymail(&list, "subonlypost",
-                                   "subonlypost", NULL, posteraddr, subject, donemailname,
+                                   "subonlypost", NULL, posteraddr, subject, q,
                                    mailfile);
                            } else if (modonlypost) {
                                send_denymail(&list, "modonlypost",
-                                   NULL, NULL, posteraddr, subject, donemailname,
+                                   NULL, NULL, posteraddr, subject, q,
                                    mailfile);
                            }
                        }
@@ -999,22 +987,22 @@ int main(int argc, char **argv)
        notmetoo = statctrl(&list, "notmetoo");
 
        if(moderated) {
-               xasprintf(&mqueuename, "%s/moderation/%s", list.dir, randomstr);
+               xasprintf(&mqueuename, "moderation/%s", randomstr);
                free(randomstr);
-               if(rename(donemailname, mqueuename) < 0) {
+               if(renameat(list.queuefd, q->name, list.fd, mqueuename) < 0) {
                        log_error(LOG_ARGS, "could not rename(%s,%s)",
-                                           donemailname, mqueuename);
-                       free(donemailname);
+                                           q->name, mqueuename);
+                       queuedmail_free(q);
                        free(mqueuename);
                        exit(EXIT_FAILURE);
                }
-               free(donemailname);
+               queuedmail_free(q);
                if (notmetoo) {
                        xasprintf(&omitfilename, "%s.omit", mqueuename);
-                       omitfd = open(omitfilename, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
+                       omitfd = openat(list.fd, omitfilename, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
                        if (omitfd < 0) {
                                log_error(LOG_ARGS, "could not open %s",
-                                                   omitfilename);
+                                               omitfilename);
                                free(mqueuename);
                                free(omitfilename);
                                exit(EXIT_FAILURE);
@@ -1038,20 +1026,23 @@ int main(int argc, char **argv)
        free(randomstr);
 
        if(noprocess) {
-               free(donemailname);
+               queuedmail_free(q);
                /* XXX: toemails and ccemails etc. have to be free() */
                exit(EXIT_SUCCESS);
        }
 
-       if (notmetoo)
+       xasprintf(&donemailname, "%s/queue/%s", list.dir, q->name);
+
+       if (notmetoo) {
                execlp(mlmmjsend, mlmmjsend,
                                "-L", list.dir,
                                "-o", posteraddr,
                                "-m", donemailname, (char *)NULL);
-       else
+       } else {
                execlp(mlmmjsend, mlmmjsend,
                                "-L", list.dir,
                                "-m", donemailname, (char *)NULL);
+       }
        log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
 
        return EXIT_FAILURE;
index 4d012fa880e907a5f60d2badf78072b015c00c4d..38679a641ca80f544c4d952fcef6960abc20c805 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 Baptiste Daroussin <bapt@FreeBSD.org>
+ * Copyright (C) 2021-2022 Baptiste Daroussin <bapt@FreeBSD.org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
  * IN THE SOFTWARE.
  */
 
+#include <sys/stat.h>
+
 #include <unistd.h>
 #include <err.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include "xmalloc.h"
 #include "strgen.h"
 #include "mlmmj.h"
 #include "controls.h"
+#include "log_error.h"
 
 void
 mlmmj_list_init(struct mlmmj_list *list)
@@ -93,6 +97,7 @@ mlmmj_list_open(struct mlmmj_list *list)
                mlmmj_list_close(list);
                return (false);
        }
+
        return (true);
 }
 
@@ -108,9 +113,24 @@ queuedmail_free(struct queuedmail *q)
 }
 
 struct queuedmail *
-queuedmail_new(void)
+queuedmail_new(struct mlmmj_list *list)
 {
        struct queuedmail *q = xcalloc(1, sizeof(struct queuedmail));
        q->fd = -1;
+
+       do {
+               if (list->queuefd == -1)
+                       list->queuefd = openat(list->fd, "queue", O_DIRECTORY);
+               free(q->name);
+               q->name = random_str();
+               q->fd = openat(list->queuefd, q->name, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
+       } while (q->fd < 0 && (errno == EEXIST));
+
+       if(q->fd < 0) {
+               log_error(LOG_ARGS, "Could not open std mail %s", q->name);
+               queuedmail_free(q);
+               return NULL;
+       }
+
        return (q);
 }
index a3b1925939d3b9266f0c43086f3322ae015a8282..2c76bd188cc76897e5d80e21d7a61ef54ce214d4 100644 (file)
@@ -119,7 +119,7 @@ struct text {
        char *type;
        source *src;
        substitution *substs;
-       char *mailname;
+       int mailfd;
        formatted *fmts;
        int wrapindent;
        int wrapwidth;
@@ -495,7 +495,7 @@ text *open_text_file(struct mlmmj_list *list, const char *filename)
        txt->reason = NULL;
        txt->type = NULL;
        txt->substs = NULL;
-       txt->mailname = NULL;
+       txt->mailfd = -1;
        txt->fmts = NULL;
        txt->wrapindent = 0;
        txt->wrapwidth = 0;
@@ -589,9 +589,9 @@ void register_unformatted(text *txt, const char *token, const char *replacement)
 }
 
 
-void register_originalmail(text *txt, const char *mailname)
+void register_originalmail(text *txt, int fd)
 {
-       txt->mailname = xstrdup(mailname);
+       txt->mailfd = dup(fd);
 }
 
 
@@ -1037,8 +1037,7 @@ static int handle_directive(text *txt, char **line_p, char **pos_p,
                        begin_new_source_file(txt, line_p, pos_p, width_p, fd, 0);
                        return 0;
                }
-       } else if(strncmp(token, "originalmail", 12) == 0 &&
-                       txt->mailname != NULL) {
+       } else if(strncmp(token, "originalmail", 12) == 0 && txt->mailfd != -1) {
                token += 12;
                limit = 0;
                if (*token == '\0') {
@@ -1051,9 +1050,9 @@ static int handle_directive(text *txt, char **line_p, char **pos_p,
                        if (token != NULL) limit = atol(token);
                }
                if (limit != 0) {
-                       int fd = open(txt->mailname, O_RDONLY);
+                       lseek(txt->mailfd, 0, SEEK_SET);
                        begin_new_source_file(txt, line_p, pos_p, width_p,
-                                       fd, 1);
+                                       txt->mailfd, 1);
                        if (limit == -1) txt->src->limit = -1;
                        else txt->src->limit = limit - 1;
                        return 0;
@@ -1566,7 +1565,7 @@ void close_text(text *txt)
                txt->substs = txt->substs->next;
                free(subst);
        }
-       if (txt->mailname != NULL) free(txt->mailname);
+       if (txt->mailfd != -1) close(txt->mailfd);
        while (txt->fmts != NULL) {
                fmt = txt->fmts;
                free(fmt->token);
@@ -1764,21 +1763,9 @@ struct queuedmail *prepqstdreply(text *txt, struct mlmmj_list *list,
        char *str;
        char *tmp;
        char *headers[10] = { NULL }; /* relies on NULL to flag end */
-       struct queuedmail *q = xcalloc(1, sizeof(struct queuedmail));
-
-       do {
-               if (list->queuefd == -1)
-                       list->queuefd = openat(list->fd, "queue", O_DIRECTORY);
-               free(q->name);
-               q->name = random_str();
-               q->fd = openat(list->queuefd, q->name, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
-       } while ((q->fd < 0) && (errno == EEXIST));
-
-       if(q->fd < 0) {
-               log_error(LOG_ARGS, "Could not open std mail %s", q->name);
-               queuedmail_free(q);
-               return NULL;
-       }
+       struct queuedmail *q = queuedmail_new(list);
+       if (q == NULL)
+               return (NULL);
 
        for (i=0; i<6; i++) {
                tmp = xstrdup("randomN");
index 69e0c6402fc2df8badfba292ca38a54bce9ffdd0..728b2b9ccf7a4d79f5990da5290eac48d2c59d2b 100644 (file)
@@ -233,14 +233,15 @@ static void finish_thread_list(thread_list_state * s)
 int send_digest(struct mlmmj_list *list, int firstindex, int lastindex,
                int issue, const char *addr, const char *mlmmjsend)
 {
-       int i, fd, archivefd, status, hdrfd, r;
+       int i, archivefd, status, hdrfd, r;
        size_t len;
        text * txt;
        char buf[100];
-       char *tmp, *queuename = NULL, *archivename, *subject = NULL, *line = NULL;
+       char *tmp, *archivename, *subject = NULL, *line = NULL;
        char *boundary;
        pid_t childpid, pid;
        thread_list_state * tls;
+       struct queuedmail *q;
 
        if (addr) {
                errno = 0;
@@ -251,19 +252,10 @@ int send_digest(struct mlmmj_list *list, int firstindex, int lastindex,
 
        if (firstindex > lastindex)
                return -1;
-       
-       do {
-               tmp = random_str();
-               free(queuename);
-               xasprintf(&queuename, "queue/%s", tmp);
-               free(tmp);
-               fd = openat(list->fd, queuename, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
-       } while ((fd < 0) && (errno == EEXIST));
 
-       if (fd < 0) {
-               log_error(LOG_ARGS, "Could not open digest queue file '%s'",
-                               queuename);
-               free(queuename);
+       q = queuedmail_new(list);
+       if (q == NULL) {
+               log_error(LOG_ARGS, "Could not open digest queue file");
                return -1;
        }
 
@@ -354,7 +346,7 @@ fallback_subject:
                free(tmp);
        }
 
-       r = dprintf(fd, "From: %s%shelp@%s"
+       r = dprintf(q->fd, "From: %s%shelp@%s"
                           "\nMIME-Version: 1.0"
                           "\nContent-Type: multipart/" DIGESTMIMETYPE "; "
                           "boundary=%s"
@@ -365,21 +357,20 @@ fallback_subject:
        if (r < 0)
                goto errdighdrs;
 
-       if(hdrfd >= 0 && dumpfd2fd(hdrfd, fd) < 0) {
+       if(hdrfd >= 0 && dumpfd2fd(hdrfd, q->fd) < 0) {
                goto errdighdrs;
        }
 
        close(hdrfd);
        hdrfd = -1;
 
-       if (dprintf(fd, "\n") < 0) {
+       if (dprintf(q->fd, "\n") < 0) {
 errdighdrs:
-               log_error(LOG_ARGS, "Could not write digest headers to '%s'",
-                               queuename);
-               close(fd);
-               unlink(queuename);
+               log_error(LOG_ARGS, "Could not write digest headers to "
+                   "'%s/queue%s'", list->dir, q->name);
+               unlinkat(list->queuefd, q->name, 0);
+               queuedmail_free(q);
                free(boundary);
-               free(queuename);
                if (txt != NULL) {
                        close_text(txt);
                        free(line);
@@ -392,16 +383,16 @@ errdighdrs:
 
        if ((txt != NULL) && !statctrl(list, "nodigesttext")) {
 
-               if (dprintf(fd, "\n--%s"
+               if (dprintf(q->fd, "\n--%s"
                        "\nContent-Type: text/plain; charset=UTF-8"
                        "\nContent-Transfer-Encoding: 8bit"
                        "\n\n", boundary) == -1) {
                        log_error(LOG_ARGS, "Could not write digest text/plain"
-                                       " part headers to '%s'", queuename);
-                       close(fd);
-                       unlink(queuename);
+                                       " part headers to '%s/queue/%s'",
+                                       list->dir, q->name);
+                       unlinkat(list->queuefd, q->name, 0);
+                       queuedmail_free(q);
                        free(boundary);
-                       free(queuename);
                        if (txt != NULL) {
                                close_text(txt);
                                free(line);
@@ -414,7 +405,7 @@ errdighdrs:
                        if (line == NULL) break;
                        len = strlen(line);
                        line[len] = '\n';
-                       if(dprintf(fd, "%s", line) < 0) {
+                       if(dprintf(q->fd, "%s", line) < 0) {
                                free(line);
                                log_error(LOG_ARGS, "Could not write"
                                                " std mail");
@@ -440,47 +431,46 @@ errdighdrs:
                if (archivefd < 0)
                        continue;
                
-               if (dprintf(fd, "\n--%s"
+               if (dprintf(q->fd, "\n--%s"
                        "\nContent-Type: message/rfc822"
                        "\nContent-Disposition: inline; filename=\"%s_%d.eml\"",
                        boundary, list->name, i) == -1) {
                        log_error(LOG_ARGS, "Could not write digest part "
                                        "headers for archive index %d to "
-                                       "'%s'", i, queuename);
-                       close(fd);
+                                       "'%s/%s'", i, list->dir, q->name);
+                       unlinkat(list->queuefd, q->name, 0);
+                       queuedmail_free(q);
                        close(archivefd);
-                       unlink(queuename);
                        free(boundary);
-                       free(queuename);
                        return -1;
                }
 
-               if (dumpfd2fd(archivefd, fd) < 0) {
+               if (dumpfd2fd(archivefd, q->fd) < 0) {
                        log_error(LOG_ARGS, "Could not write digest part %d "
-                                       "to '%s'", i,
-                                       queuename);
-                       close(fd);
+                                       "to '%s/queue/%s'", i, list->dir,
+                                       q->name);
+                       unlinkat(list->queuefd, q->name, 0);
+                       queuedmail_free(q);
                        close(archivefd);
-                       unlink(queuename);
                        free(boundary);
-                       free(queuename);
                        return -1;
                }
                
                close(archivefd);
        }
 
-       if (dprintf(fd, "\n--%s--\n", boundary) == -1) {
-               log_error(LOG_ARGS, "Could not write digest end to '%s'",
-                               queuename);
-               close(fd);
-               unlink(queuename);
+       if (dprintf(q->fd, "\n--%s--\n", boundary) == -1) {
+               log_error(LOG_ARGS, "Could not write digest end to '%s/queue/%s'",
+                   list->dir, q->name);
+               unlinkat(list->queuefd, q->name, 0);
+               queuedmail_free(q);
                free(boundary);
-               free(queuename);
                return -1;
        }
 
-       close(fd);
+       char *queuename;
+       xasprintf(&queuename, "%s/queue/%s", list->dir, q->name);
+       queuedmail_free(q);
        free(boundary);
 
        childpid = fork();