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