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");
	}
}
Exemple #2
0
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;
}