1*a9e8641dSBaptiste Daroussin /* 2*a9e8641dSBaptiste Daroussin * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3*a9e8641dSBaptiste Daroussin * 4*a9e8641dSBaptiste Daroussin * This code is derived from software contributed to The DragonFly Project 5*a9e8641dSBaptiste Daroussin * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>. 6*a9e8641dSBaptiste Daroussin * 7*a9e8641dSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 8*a9e8641dSBaptiste Daroussin * modification, are permitted provided that the following conditions 9*a9e8641dSBaptiste Daroussin * are met: 10*a9e8641dSBaptiste Daroussin * 11*a9e8641dSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 12*a9e8641dSBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 13*a9e8641dSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 14*a9e8641dSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in 15*a9e8641dSBaptiste Daroussin * the documentation and/or other materials provided with the 16*a9e8641dSBaptiste Daroussin * distribution. 17*a9e8641dSBaptiste Daroussin * 3. Neither the name of The DragonFly Project nor the names of its 18*a9e8641dSBaptiste Daroussin * contributors may be used to endorse or promote products derived 19*a9e8641dSBaptiste Daroussin * from this software without specific, prior written permission. 20*a9e8641dSBaptiste Daroussin * 21*a9e8641dSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*a9e8641dSBaptiste Daroussin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*a9e8641dSBaptiste Daroussin * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24*a9e8641dSBaptiste Daroussin * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25*a9e8641dSBaptiste Daroussin * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26*a9e8641dSBaptiste Daroussin * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27*a9e8641dSBaptiste Daroussin * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28*a9e8641dSBaptiste Daroussin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29*a9e8641dSBaptiste Daroussin * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30*a9e8641dSBaptiste Daroussin * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31*a9e8641dSBaptiste Daroussin * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*a9e8641dSBaptiste Daroussin * SUCH DAMAGE. 33*a9e8641dSBaptiste Daroussin */ 34*a9e8641dSBaptiste Daroussin 35*a9e8641dSBaptiste Daroussin #include "dfcompat.h" 36*a9e8641dSBaptiste Daroussin 37*a9e8641dSBaptiste Daroussin #include <sys/file.h> 38*a9e8641dSBaptiste Daroussin #include <sys/stat.h> 39*a9e8641dSBaptiste Daroussin 40*a9e8641dSBaptiste Daroussin #include <ctype.h> 41*a9e8641dSBaptiste Daroussin #include <dirent.h> 42*a9e8641dSBaptiste Daroussin #include <err.h> 43*a9e8641dSBaptiste Daroussin #include <errno.h> 44*a9e8641dSBaptiste Daroussin #include <fcntl.h> 45*a9e8641dSBaptiste Daroussin #include <inttypes.h> 46*a9e8641dSBaptiste Daroussin #include <unistd.h> 47*a9e8641dSBaptiste Daroussin #include <syslog.h> 48*a9e8641dSBaptiste Daroussin 49*a9e8641dSBaptiste Daroussin #include "dma.h" 50*a9e8641dSBaptiste Daroussin 51*a9e8641dSBaptiste Daroussin /* 52*a9e8641dSBaptiste Daroussin * Spool file format: 53*a9e8641dSBaptiste Daroussin * 54*a9e8641dSBaptiste Daroussin * 'Q'id files (queue): 55*a9e8641dSBaptiste Daroussin * Organized like an RFC822 header, field: value. Ignores unknown fields. 56*a9e8641dSBaptiste Daroussin * ID: id 57*a9e8641dSBaptiste Daroussin * Sender: envelope-from 58*a9e8641dSBaptiste Daroussin * Recipient: envelope-to 59*a9e8641dSBaptiste Daroussin * 60*a9e8641dSBaptiste Daroussin * 'M'id files (data): 61*a9e8641dSBaptiste Daroussin * mail data 62*a9e8641dSBaptiste Daroussin * 63*a9e8641dSBaptiste Daroussin * Each queue file needs to have a corresponding data file. 64*a9e8641dSBaptiste Daroussin * One data file might be shared by linking it several times. 65*a9e8641dSBaptiste Daroussin * 66*a9e8641dSBaptiste Daroussin * Queue ids are unique, formed from the inode of the data file 67*a9e8641dSBaptiste Daroussin * and a unique identifier. 68*a9e8641dSBaptiste Daroussin */ 69*a9e8641dSBaptiste Daroussin 70*a9e8641dSBaptiste Daroussin int 71*a9e8641dSBaptiste Daroussin newspoolf(struct queue *queue) 72*a9e8641dSBaptiste Daroussin { 73*a9e8641dSBaptiste Daroussin char fn[PATH_MAX+1]; 74*a9e8641dSBaptiste Daroussin struct stat st; 75*a9e8641dSBaptiste Daroussin struct stritem *t; 76*a9e8641dSBaptiste Daroussin int fd; 77*a9e8641dSBaptiste Daroussin 78*a9e8641dSBaptiste Daroussin if (snprintf(fn, sizeof(fn), "%s/%s", config.spooldir, "tmp_XXXXXXXXXX") <= 0) 79*a9e8641dSBaptiste Daroussin return (-1); 80*a9e8641dSBaptiste Daroussin 81*a9e8641dSBaptiste Daroussin fd = mkstemp(fn); 82*a9e8641dSBaptiste Daroussin if (fd < 0) 83*a9e8641dSBaptiste Daroussin return (-1); 84*a9e8641dSBaptiste Daroussin /* XXX group rights */ 85*a9e8641dSBaptiste Daroussin if (fchmod(fd, 0660) < 0) 86*a9e8641dSBaptiste Daroussin goto fail; 87*a9e8641dSBaptiste Daroussin if (flock(fd, LOCK_EX) == -1) 88*a9e8641dSBaptiste Daroussin goto fail; 89*a9e8641dSBaptiste Daroussin queue->tmpf = strdup(fn); 90*a9e8641dSBaptiste Daroussin if (queue->tmpf == NULL) 91*a9e8641dSBaptiste Daroussin goto fail; 92*a9e8641dSBaptiste Daroussin 93*a9e8641dSBaptiste Daroussin /* 94*a9e8641dSBaptiste Daroussin * Assign queue id 95*a9e8641dSBaptiste Daroussin */ 96*a9e8641dSBaptiste Daroussin if (fstat(fd, &st) != 0) 97*a9e8641dSBaptiste Daroussin goto fail; 98*a9e8641dSBaptiste Daroussin if (asprintf(&queue->id, "%"PRIxMAX, (uintmax_t)st.st_ino) < 0) 99*a9e8641dSBaptiste Daroussin goto fail; 100*a9e8641dSBaptiste Daroussin 101*a9e8641dSBaptiste Daroussin queue->mailf = fdopen(fd, "r+"); 102*a9e8641dSBaptiste Daroussin if (queue->mailf == NULL) 103*a9e8641dSBaptiste Daroussin goto fail; 104*a9e8641dSBaptiste Daroussin 105*a9e8641dSBaptiste Daroussin t = malloc(sizeof(*t)); 106*a9e8641dSBaptiste Daroussin if (t != NULL) { 107*a9e8641dSBaptiste Daroussin t->str = queue->tmpf; 108*a9e8641dSBaptiste Daroussin SLIST_INSERT_HEAD(&tmpfs, t, next); 109*a9e8641dSBaptiste Daroussin } 110*a9e8641dSBaptiste Daroussin return (0); 111*a9e8641dSBaptiste Daroussin 112*a9e8641dSBaptiste Daroussin fail: 113*a9e8641dSBaptiste Daroussin if (queue->mailf != NULL) 114*a9e8641dSBaptiste Daroussin fclose(queue->mailf); 115*a9e8641dSBaptiste Daroussin close(fd); 116*a9e8641dSBaptiste Daroussin unlink(fn); 117*a9e8641dSBaptiste Daroussin return (-1); 118*a9e8641dSBaptiste Daroussin } 119*a9e8641dSBaptiste Daroussin 120*a9e8641dSBaptiste Daroussin static int 121*a9e8641dSBaptiste Daroussin writequeuef(struct qitem *it) 122*a9e8641dSBaptiste Daroussin { 123*a9e8641dSBaptiste Daroussin int error; 124*a9e8641dSBaptiste Daroussin int queuefd; 125*a9e8641dSBaptiste Daroussin 126*a9e8641dSBaptiste Daroussin queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0660); 127*a9e8641dSBaptiste Daroussin if (queuefd == -1) 128*a9e8641dSBaptiste Daroussin return (-1); 129*a9e8641dSBaptiste Daroussin if (fchmod(queuefd, 0660) < 0) 130*a9e8641dSBaptiste Daroussin return (-1); 131*a9e8641dSBaptiste Daroussin it->queuef = fdopen(queuefd, "w+"); 132*a9e8641dSBaptiste Daroussin if (it->queuef == NULL) 133*a9e8641dSBaptiste Daroussin return (-1); 134*a9e8641dSBaptiste Daroussin 135*a9e8641dSBaptiste Daroussin error = fprintf(it->queuef, 136*a9e8641dSBaptiste Daroussin "ID: %s\n" 137*a9e8641dSBaptiste Daroussin "Sender: %s\n" 138*a9e8641dSBaptiste Daroussin "Recipient: %s\n", 139*a9e8641dSBaptiste Daroussin it->queueid, 140*a9e8641dSBaptiste Daroussin it->sender, 141*a9e8641dSBaptiste Daroussin it->addr); 142*a9e8641dSBaptiste Daroussin 143*a9e8641dSBaptiste Daroussin if (error <= 0) 144*a9e8641dSBaptiste Daroussin return (-1); 145*a9e8641dSBaptiste Daroussin 146*a9e8641dSBaptiste Daroussin if (fflush(it->queuef) != 0 || fsync(fileno(it->queuef)) != 0) 147*a9e8641dSBaptiste Daroussin return (-1); 148*a9e8641dSBaptiste Daroussin 149*a9e8641dSBaptiste Daroussin return (0); 150*a9e8641dSBaptiste Daroussin } 151*a9e8641dSBaptiste Daroussin 152*a9e8641dSBaptiste Daroussin static struct qitem * 153*a9e8641dSBaptiste Daroussin readqueuef(struct queue *queue, char *queuefn) 154*a9e8641dSBaptiste Daroussin { 155*a9e8641dSBaptiste Daroussin char line[1000]; 156*a9e8641dSBaptiste Daroussin struct queue itmqueue; 157*a9e8641dSBaptiste Daroussin FILE *queuef = NULL; 158*a9e8641dSBaptiste Daroussin char *s; 159*a9e8641dSBaptiste Daroussin char *queueid = NULL, *sender = NULL, *addr = NULL; 160*a9e8641dSBaptiste Daroussin struct qitem *it = NULL; 161*a9e8641dSBaptiste Daroussin 162*a9e8641dSBaptiste Daroussin bzero(&itmqueue, sizeof(itmqueue)); 163*a9e8641dSBaptiste Daroussin LIST_INIT(&itmqueue.queue); 164*a9e8641dSBaptiste Daroussin 165*a9e8641dSBaptiste Daroussin queuef = fopen(queuefn, "r"); 166*a9e8641dSBaptiste Daroussin if (queuef == NULL) 167*a9e8641dSBaptiste Daroussin goto out; 168*a9e8641dSBaptiste Daroussin 169*a9e8641dSBaptiste Daroussin while (!feof(queuef)) { 170*a9e8641dSBaptiste Daroussin if (fgets(line, sizeof(line), queuef) == NULL || line[0] == 0) 171*a9e8641dSBaptiste Daroussin break; 172*a9e8641dSBaptiste Daroussin line[strlen(line) - 1] = 0; /* chop newline */ 173*a9e8641dSBaptiste Daroussin 174*a9e8641dSBaptiste Daroussin s = strchr(line, ':'); 175*a9e8641dSBaptiste Daroussin if (s == NULL) 176*a9e8641dSBaptiste Daroussin goto malformed; 177*a9e8641dSBaptiste Daroussin *s = 0; 178*a9e8641dSBaptiste Daroussin 179*a9e8641dSBaptiste Daroussin s++; 180*a9e8641dSBaptiste Daroussin while (isspace(*s)) 181*a9e8641dSBaptiste Daroussin s++; 182*a9e8641dSBaptiste Daroussin 183*a9e8641dSBaptiste Daroussin s = strdup(s); 184*a9e8641dSBaptiste Daroussin if (s == NULL) 185*a9e8641dSBaptiste Daroussin goto malformed; 186*a9e8641dSBaptiste Daroussin 187*a9e8641dSBaptiste Daroussin if (strcmp(line, "ID") == 0) { 188*a9e8641dSBaptiste Daroussin queueid = s; 189*a9e8641dSBaptiste Daroussin } else if (strcmp(line, "Sender") == 0) { 190*a9e8641dSBaptiste Daroussin sender = s; 191*a9e8641dSBaptiste Daroussin } else if (strcmp(line, "Recipient") == 0) { 192*a9e8641dSBaptiste Daroussin addr = s; 193*a9e8641dSBaptiste Daroussin } else { 194*a9e8641dSBaptiste Daroussin syslog(LOG_DEBUG, "ignoring unknown queue info `%s' in `%s'", 195*a9e8641dSBaptiste Daroussin line, queuefn); 196*a9e8641dSBaptiste Daroussin free(s); 197*a9e8641dSBaptiste Daroussin } 198*a9e8641dSBaptiste Daroussin } 199*a9e8641dSBaptiste Daroussin 200*a9e8641dSBaptiste Daroussin if (queueid == NULL || sender == NULL || addr == NULL || 201*a9e8641dSBaptiste Daroussin *queueid == 0 || *addr == 0) { 202*a9e8641dSBaptiste Daroussin malformed: 203*a9e8641dSBaptiste Daroussin errno = EINVAL; 204*a9e8641dSBaptiste Daroussin syslog(LOG_ERR, "malformed queue file `%s'", queuefn); 205*a9e8641dSBaptiste Daroussin goto out; 206*a9e8641dSBaptiste Daroussin } 207*a9e8641dSBaptiste Daroussin 208*a9e8641dSBaptiste Daroussin if (add_recp(&itmqueue, addr, 0) != 0) 209*a9e8641dSBaptiste Daroussin goto out; 210*a9e8641dSBaptiste Daroussin 211*a9e8641dSBaptiste Daroussin it = LIST_FIRST(&itmqueue.queue); 212*a9e8641dSBaptiste Daroussin it->sender = sender; sender = NULL; 213*a9e8641dSBaptiste Daroussin it->queueid = queueid; queueid = NULL; 214*a9e8641dSBaptiste Daroussin it->queuefn = queuefn; queuefn = NULL; 215*a9e8641dSBaptiste Daroussin LIST_INSERT_HEAD(&queue->queue, it, next); 216*a9e8641dSBaptiste Daroussin 217*a9e8641dSBaptiste Daroussin out: 218*a9e8641dSBaptiste Daroussin if (sender != NULL) 219*a9e8641dSBaptiste Daroussin free(sender); 220*a9e8641dSBaptiste Daroussin if (queueid != NULL) 221*a9e8641dSBaptiste Daroussin free(queueid); 222*a9e8641dSBaptiste Daroussin if (addr != NULL) 223*a9e8641dSBaptiste Daroussin free(addr); 224*a9e8641dSBaptiste Daroussin if (queuef != NULL) 225*a9e8641dSBaptiste Daroussin fclose(queuef); 226*a9e8641dSBaptiste Daroussin 227*a9e8641dSBaptiste Daroussin return (it); 228*a9e8641dSBaptiste Daroussin } 229*a9e8641dSBaptiste Daroussin 230*a9e8641dSBaptiste Daroussin int 231*a9e8641dSBaptiste Daroussin linkspool(struct queue *queue) 232*a9e8641dSBaptiste Daroussin { 233*a9e8641dSBaptiste Daroussin struct stat st; 234*a9e8641dSBaptiste Daroussin struct qitem *it; 235*a9e8641dSBaptiste Daroussin 236*a9e8641dSBaptiste Daroussin if (fflush(queue->mailf) != 0 || fsync(fileno(queue->mailf)) != 0) 237*a9e8641dSBaptiste Daroussin goto delfiles; 238*a9e8641dSBaptiste Daroussin 239*a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "new mail from user=%s uid=%d envelope_from=<%s>", 240*a9e8641dSBaptiste Daroussin username, getuid(), queue->sender); 241*a9e8641dSBaptiste Daroussin 242*a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 243*a9e8641dSBaptiste Daroussin if (asprintf(&it->queueid, "%s.%"PRIxPTR, queue->id, (uintptr_t)it) <= 0) 244*a9e8641dSBaptiste Daroussin goto delfiles; 245*a9e8641dSBaptiste Daroussin if (asprintf(&it->queuefn, "%s/Q%s", config.spooldir, it->queueid) <= 0) 246*a9e8641dSBaptiste Daroussin goto delfiles; 247*a9e8641dSBaptiste Daroussin if (asprintf(&it->mailfn, "%s/M%s", config.spooldir, it->queueid) <= 0) 248*a9e8641dSBaptiste Daroussin goto delfiles; 249*a9e8641dSBaptiste Daroussin 250*a9e8641dSBaptiste Daroussin /* Neither file may not exist yet */ 251*a9e8641dSBaptiste Daroussin if (stat(it->queuefn, &st) == 0 || stat(it->mailfn, &st) == 0) 252*a9e8641dSBaptiste Daroussin goto delfiles; 253*a9e8641dSBaptiste Daroussin 254*a9e8641dSBaptiste Daroussin if (writequeuef(it) != 0) 255*a9e8641dSBaptiste Daroussin goto delfiles; 256*a9e8641dSBaptiste Daroussin 257*a9e8641dSBaptiste Daroussin if (link(queue->tmpf, it->mailfn) != 0) 258*a9e8641dSBaptiste Daroussin goto delfiles; 259*a9e8641dSBaptiste Daroussin } 260*a9e8641dSBaptiste Daroussin 261*a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 262*a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "mail to=<%s> queued as %s", 263*a9e8641dSBaptiste Daroussin it->addr, it->queueid); 264*a9e8641dSBaptiste Daroussin } 265*a9e8641dSBaptiste Daroussin 266*a9e8641dSBaptiste Daroussin unlink(queue->tmpf); 267*a9e8641dSBaptiste Daroussin return (0); 268*a9e8641dSBaptiste Daroussin 269*a9e8641dSBaptiste Daroussin delfiles: 270*a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 271*a9e8641dSBaptiste Daroussin unlink(it->mailfn); 272*a9e8641dSBaptiste Daroussin unlink(it->queuefn); 273*a9e8641dSBaptiste Daroussin } 274*a9e8641dSBaptiste Daroussin return (-1); 275*a9e8641dSBaptiste Daroussin } 276*a9e8641dSBaptiste Daroussin 277*a9e8641dSBaptiste Daroussin int 278*a9e8641dSBaptiste Daroussin load_queue(struct queue *queue) 279*a9e8641dSBaptiste Daroussin { 280*a9e8641dSBaptiste Daroussin struct stat sb; 281*a9e8641dSBaptiste Daroussin struct qitem *it; 282*a9e8641dSBaptiste Daroussin DIR *spooldir; 283*a9e8641dSBaptiste Daroussin struct dirent *de; 284*a9e8641dSBaptiste Daroussin char *queuefn; 285*a9e8641dSBaptiste Daroussin char *mailfn; 286*a9e8641dSBaptiste Daroussin 287*a9e8641dSBaptiste Daroussin bzero(queue, sizeof(*queue)); 288*a9e8641dSBaptiste Daroussin LIST_INIT(&queue->queue); 289*a9e8641dSBaptiste Daroussin 290*a9e8641dSBaptiste Daroussin spooldir = opendir(config.spooldir); 291*a9e8641dSBaptiste Daroussin if (spooldir == NULL) 292*a9e8641dSBaptiste Daroussin err(1, "reading queue"); 293*a9e8641dSBaptiste Daroussin 294*a9e8641dSBaptiste Daroussin while ((de = readdir(spooldir)) != NULL) { 295*a9e8641dSBaptiste Daroussin queuefn = NULL; 296*a9e8641dSBaptiste Daroussin mailfn = NULL; 297*a9e8641dSBaptiste Daroussin 298*a9e8641dSBaptiste Daroussin /* ignore non-queue files */ 299*a9e8641dSBaptiste Daroussin if (de->d_name[0] != 'Q') 300*a9e8641dSBaptiste Daroussin continue; 301*a9e8641dSBaptiste Daroussin if (asprintf(&queuefn, "%s/Q%s", config.spooldir, de->d_name + 1) < 0) 302*a9e8641dSBaptiste Daroussin goto fail; 303*a9e8641dSBaptiste Daroussin if (asprintf(&mailfn, "%s/M%s", config.spooldir, de->d_name + 1) < 0) 304*a9e8641dSBaptiste Daroussin goto fail; 305*a9e8641dSBaptiste Daroussin 306*a9e8641dSBaptiste Daroussin /* 307*a9e8641dSBaptiste Daroussin * Some file systems don't provide a de->d_type, so we have to 308*a9e8641dSBaptiste Daroussin * do an explicit stat on the queue file. 309*a9e8641dSBaptiste Daroussin * Move on if it turns out to be something else than a file. 310*a9e8641dSBaptiste Daroussin */ 311*a9e8641dSBaptiste Daroussin if (stat(queuefn, &sb) != 0) 312*a9e8641dSBaptiste Daroussin goto skip_item; 313*a9e8641dSBaptiste Daroussin if (!S_ISREG(sb.st_mode)) { 314*a9e8641dSBaptiste Daroussin errno = EINVAL; 315*a9e8641dSBaptiste Daroussin goto skip_item; 316*a9e8641dSBaptiste Daroussin } 317*a9e8641dSBaptiste Daroussin 318*a9e8641dSBaptiste Daroussin if (stat(mailfn, &sb) != 0) 319*a9e8641dSBaptiste Daroussin goto skip_item; 320*a9e8641dSBaptiste Daroussin 321*a9e8641dSBaptiste Daroussin it = readqueuef(queue, queuefn); 322*a9e8641dSBaptiste Daroussin if (it == NULL) 323*a9e8641dSBaptiste Daroussin goto skip_item; 324*a9e8641dSBaptiste Daroussin 325*a9e8641dSBaptiste Daroussin it->mailfn = mailfn; 326*a9e8641dSBaptiste Daroussin continue; 327*a9e8641dSBaptiste Daroussin 328*a9e8641dSBaptiste Daroussin skip_item: 329*a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "could not pick up queue file: `%s'/`%s': %m", queuefn, mailfn); 330*a9e8641dSBaptiste Daroussin if (queuefn != NULL) 331*a9e8641dSBaptiste Daroussin free(queuefn); 332*a9e8641dSBaptiste Daroussin if (mailfn != NULL) 333*a9e8641dSBaptiste Daroussin free(mailfn); 334*a9e8641dSBaptiste Daroussin } 335*a9e8641dSBaptiste Daroussin closedir(spooldir); 336*a9e8641dSBaptiste Daroussin return (0); 337*a9e8641dSBaptiste Daroussin 338*a9e8641dSBaptiste Daroussin fail: 339*a9e8641dSBaptiste Daroussin return (-1); 340*a9e8641dSBaptiste Daroussin } 341*a9e8641dSBaptiste Daroussin 342*a9e8641dSBaptiste Daroussin void 343*a9e8641dSBaptiste Daroussin delqueue(struct qitem *it) 344*a9e8641dSBaptiste Daroussin { 345*a9e8641dSBaptiste Daroussin unlink(it->mailfn); 346*a9e8641dSBaptiste Daroussin unlink(it->queuefn); 347*a9e8641dSBaptiste Daroussin if (it->queuef != NULL) 348*a9e8641dSBaptiste Daroussin fclose(it->queuef); 349*a9e8641dSBaptiste Daroussin if (it->mailf != NULL) 350*a9e8641dSBaptiste Daroussin fclose(it->mailf); 351*a9e8641dSBaptiste Daroussin free(it); 352*a9e8641dSBaptiste Daroussin } 353*a9e8641dSBaptiste Daroussin 354*a9e8641dSBaptiste Daroussin int 355*a9e8641dSBaptiste Daroussin acquirespool(struct qitem *it) 356*a9e8641dSBaptiste Daroussin { 357*a9e8641dSBaptiste Daroussin int queuefd; 358*a9e8641dSBaptiste Daroussin 359*a9e8641dSBaptiste Daroussin if (it->queuef == NULL) { 360*a9e8641dSBaptiste Daroussin queuefd = open_locked(it->queuefn, O_RDWR|O_NONBLOCK); 361*a9e8641dSBaptiste Daroussin if (queuefd < 0) 362*a9e8641dSBaptiste Daroussin goto fail; 363*a9e8641dSBaptiste Daroussin it->queuef = fdopen(queuefd, "r+"); 364*a9e8641dSBaptiste Daroussin if (it->queuef == NULL) 365*a9e8641dSBaptiste Daroussin goto fail; 366*a9e8641dSBaptiste Daroussin } 367*a9e8641dSBaptiste Daroussin 368*a9e8641dSBaptiste Daroussin if (it->mailf == NULL) { 369*a9e8641dSBaptiste Daroussin it->mailf = fopen(it->mailfn, "r"); 370*a9e8641dSBaptiste Daroussin if (it->mailf == NULL) 371*a9e8641dSBaptiste Daroussin goto fail; 372*a9e8641dSBaptiste Daroussin } 373*a9e8641dSBaptiste Daroussin 374*a9e8641dSBaptiste Daroussin return (0); 375*a9e8641dSBaptiste Daroussin 376*a9e8641dSBaptiste Daroussin fail: 377*a9e8641dSBaptiste Daroussin if (errno == EWOULDBLOCK) 378*a9e8641dSBaptiste Daroussin return (1); 379*a9e8641dSBaptiste Daroussin syslog(LOG_INFO, "could not acquire queue file: %m"); 380*a9e8641dSBaptiste Daroussin return (-1); 381*a9e8641dSBaptiste Daroussin } 382*a9e8641dSBaptiste Daroussin 383*a9e8641dSBaptiste Daroussin void 384*a9e8641dSBaptiste Daroussin dropspool(struct queue *queue, struct qitem *keep) 385*a9e8641dSBaptiste Daroussin { 386*a9e8641dSBaptiste Daroussin struct qitem *it; 387*a9e8641dSBaptiste Daroussin 388*a9e8641dSBaptiste Daroussin LIST_FOREACH(it, &queue->queue, next) { 389*a9e8641dSBaptiste Daroussin if (it == keep) 390*a9e8641dSBaptiste Daroussin continue; 391*a9e8641dSBaptiste Daroussin 392*a9e8641dSBaptiste Daroussin if (it->queuef != NULL) 393*a9e8641dSBaptiste Daroussin fclose(it->queuef); 394*a9e8641dSBaptiste Daroussin if (it->mailf != NULL) 395*a9e8641dSBaptiste Daroussin fclose(it->mailf); 396*a9e8641dSBaptiste Daroussin } 397*a9e8641dSBaptiste Daroussin } 398*a9e8641dSBaptiste Daroussin 399*a9e8641dSBaptiste Daroussin int 400*a9e8641dSBaptiste Daroussin flushqueue_since(unsigned int period) 401*a9e8641dSBaptiste Daroussin { 402*a9e8641dSBaptiste Daroussin struct stat st; 403*a9e8641dSBaptiste Daroussin struct timeval now; 404*a9e8641dSBaptiste Daroussin char *flushfn = NULL; 405*a9e8641dSBaptiste Daroussin 406*a9e8641dSBaptiste Daroussin if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) 407*a9e8641dSBaptiste Daroussin return (0); 408*a9e8641dSBaptiste Daroussin if (stat(flushfn, &st) < 0) { 409*a9e8641dSBaptiste Daroussin free(flushfn); 410*a9e8641dSBaptiste Daroussin return (0); 411*a9e8641dSBaptiste Daroussin } 412*a9e8641dSBaptiste Daroussin free(flushfn); 413*a9e8641dSBaptiste Daroussin flushfn = NULL; 414*a9e8641dSBaptiste Daroussin if (gettimeofday(&now, 0) != 0) 415*a9e8641dSBaptiste Daroussin return (0); 416*a9e8641dSBaptiste Daroussin 417*a9e8641dSBaptiste Daroussin /* Did the flush file get touched within the last period seconds? */ 418*a9e8641dSBaptiste Daroussin if (st.st_mtim.tv_sec + period >= now.tv_sec) 419*a9e8641dSBaptiste Daroussin return (1); 420*a9e8641dSBaptiste Daroussin else 421*a9e8641dSBaptiste Daroussin return (0); 422*a9e8641dSBaptiste Daroussin } 423*a9e8641dSBaptiste Daroussin 424*a9e8641dSBaptiste Daroussin int 425*a9e8641dSBaptiste Daroussin flushqueue_signal(void) 426*a9e8641dSBaptiste Daroussin { 427*a9e8641dSBaptiste Daroussin char *flushfn = NULL; 428*a9e8641dSBaptiste Daroussin int fd; 429*a9e8641dSBaptiste Daroussin 430*a9e8641dSBaptiste Daroussin if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) 431*a9e8641dSBaptiste Daroussin return (-1); 432*a9e8641dSBaptiste Daroussin fd = open(flushfn, O_CREAT|O_WRONLY|O_TRUNC, 0660); 433*a9e8641dSBaptiste Daroussin free(flushfn); 434*a9e8641dSBaptiste Daroussin if (fd < 0) { 435*a9e8641dSBaptiste Daroussin syslog(LOG_ERR, "could not open flush file: %m"); 436*a9e8641dSBaptiste Daroussin return (-1); 437*a9e8641dSBaptiste Daroussin } 438*a9e8641dSBaptiste Daroussin close(fd); 439*a9e8641dSBaptiste Daroussin return (0); 440*a9e8641dSBaptiste Daroussin } 441