static void queue_msg_dispatch(void) { uint64_t evpid; uint32_t msgid, version; size_t n; char buffer[8192], path[SMTPD_MAXPATHLEN]; int r, fd; FILE *ifile, *ofile; switch (imsg.hdr.type) { case PROC_QUEUE_INIT: queue_msg_get(&version, sizeof(version)); queue_msg_end(); if (version != PROC_QUEUE_API_VERSION) { log_warnx("warn: queue-api: bad API version"); fatalx("queue-api: exiting"); } imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, NULL, 0); break; case PROC_QUEUE_MESSAGE_CREATE: queue_msg_end(); r = handler_message_create(&msgid); queue_msg_add(&r, sizeof(r)); if (r == 1) queue_msg_add(&msgid, sizeof(msgid)); queue_msg_close(); break; case PROC_QUEUE_MESSAGE_DELETE: queue_msg_get(&msgid, sizeof(msgid)); queue_msg_end(); r = handler_message_delete(msgid); imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, &r, sizeof(r)); break; case PROC_QUEUE_MESSAGE_COMMIT: queue_msg_get(&msgid, sizeof(msgid)); queue_msg_end(); /* XXX needs more love */ r = -1; fd = mkstemp(path); if (fd == -1) { log_warn("warn: queue-api: mkstemp"); } else { ifile = fdopen(imsg.fd, "r"); ofile = fdopen(fd, "w"); if (ifile && ofile) { while (!feof(ifile)) { n = fread(buffer, 1, sizeof(buffer), ifile); fwrite(buffer, 1, n, ofile); } r = handler_message_commit(msgid, path); } if (ifile) fclose(ifile); if (ofile) fclose(ofile); } imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, &r, sizeof(r)); break; case PROC_QUEUE_MESSAGE_FD_R: queue_msg_get(&msgid, sizeof(msgid)); queue_msg_end(); fd = handler_message_fd_r(msgid); imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, fd, NULL, 0); break; case PROC_QUEUE_MESSAGE_CORRUPT: queue_msg_get(&msgid, sizeof(msgid)); queue_msg_end(); r = handler_message_corrupt(msgid); imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, &r, sizeof(r)); break; case PROC_QUEUE_ENVELOPE_CREATE: queue_msg_get(&msgid, sizeof(msgid)); r = handler_envelope_create(msgid, rdata, rlen, &evpid); queue_msg_get(NULL, rlen); queue_msg_end(); queue_msg_add(&r, sizeof(r)); if (r == 1) queue_msg_add(&evpid, sizeof(evpid)); queue_msg_close(); break; case PROC_QUEUE_ENVELOPE_DELETE: queue_msg_get(&evpid, sizeof(evpid)); queue_msg_end(); r = handler_envelope_delete(evpid); imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, &r, sizeof(r)); break; case PROC_QUEUE_ENVELOPE_LOAD: queue_msg_get(&evpid, sizeof(evpid)); queue_msg_end(); r = handler_envelope_load(evpid, buffer, sizeof(buffer)); imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, buffer, r); break; case PROC_QUEUE_ENVELOPE_UPDATE: queue_msg_get(&evpid, sizeof(evpid)); r = handler_envelope_update(evpid, rdata, rlen); queue_msg_get(NULL, rlen); queue_msg_end(); imsg_compose(&ibuf, PROC_QUEUE_OK, 0, 0, -1, &r, sizeof(r)); break; case PROC_QUEUE_ENVELOPE_WALK: queue_msg_end(); r = handler_envelope_walk(&evpid, buffer, sizeof(buffer)); queue_msg_add(&r, sizeof(r)); if (r > 0) { queue_msg_add(&evpid, sizeof(evpid)); queue_msg_add(buffer, r); } queue_msg_close(); default: log_warnx("warn: queue-api: bad message %i", imsg.hdr.type); fatalx("queue-api: exiting"); } }
int queue_message_commit(uint32_t msgid) { int r; char msgpath[PATH_MAX]; char tmppath[PATH_MAX]; FILE *ifp = NULL; FILE *ofp = NULL; profile_enter("queue_message_commit"); queue_message_path(msgid, msgpath, sizeof(msgpath)); if (env->sc_queue_flags & QUEUE_COMPRESSION) { bsnprintf(tmppath, sizeof tmppath, "%s.comp", msgpath); ifp = fopen(msgpath, "r"); ofp = fopen(tmppath, "w+"); if (ifp == NULL || ofp == NULL) goto err; if (! compress_file(ifp, ofp)) goto err; fclose(ifp); fclose(ofp); ifp = NULL; ofp = NULL; if (rename(tmppath, msgpath) == -1) { if (errno == ENOSPC) return (0); unlink(tmppath); log_warn("rename"); return (0); } } if (env->sc_queue_flags & QUEUE_ENCRYPTION) { bsnprintf(tmppath, sizeof tmppath, "%s.enc", msgpath); ifp = fopen(msgpath, "r"); ofp = fopen(tmppath, "w+"); if (ifp == NULL || ofp == NULL) goto err; if (! crypto_encrypt_file(ifp, ofp)) goto err; fclose(ifp); fclose(ofp); ifp = NULL; ofp = NULL; if (rename(tmppath, msgpath) == -1) { if (errno == ENOSPC) return (0); unlink(tmppath); log_warn("rename"); return (0); } } r = handler_message_commit(msgid, msgpath); profile_leave(); /* in case it's not done by the backend */ unlink(msgpath); log_trace(TRACE_QUEUE, "queue-backend: queue_message_commit(%08"PRIx32") -> %d", msgid, r); return (r); err: if (ifp) fclose(ifp); if (ofp) fclose(ofp); return 0; }