/*
** distsbr.c -- routines to do additional "dist-style" processing
**
** This code is Copyright (c) 2002, by the authors of nmh.  See the
** COPYRIGHT file in the root directory of the nmh distribution for
** complete copyright information.
*/

#include <h/mh.h>
#include <fcntl.h>
#include <h/utils.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/stat.h>

static int  hdrfd = NOTOK;
static int  txtfd = NOTOK;

/*
** static prototypes
*/
static int ready_msg(char *);

int
distout(char *drft, char *msgnam, char *backup)
{
	enum state state;
	struct field f = {{0}};
	unsigned char *dp;
	int resent = 0;
	FILE *ifp, *ofp;

	strcpy(backup, m_mktemp(toabsdir(invo_name), NULL, NULL));
	if (rename(drft, backup) == NOTOK) {
		advise(backup, "unable to rename %s to",drft);
		return NOTOK;
	}

	if (ready_msg(msgnam) != OK) {
		return NOTOK;
	}

	if (!(ifp = fopen(backup, "r"))) {
		advise(backup, "unable to read");
		return NOTOK;
	}

	if (!(ofp = fopen(drft, "w"))) {
		fclose(ifp);
		advise(drft, "unable to create temporary file");
		return NOTOK;
	}
	chmod(drft, m_gmprot());

	lseek(hdrfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */
	cpydata(hdrfd, fileno(ofp), msgnam, drft);

	state = FLD2;
	while (1) {
		switch (state = m_getfld2(state, &f, ifp)) {
		case FLD2:
			if (!uprf(f.name, "resent")) {
				advise(NULL, "Please re-edit draft to remove the ``%s'' header.", f.name);
				goto leave_bad;
			}
			resent = 1;
			fprintf(ofp, "%s: %s", f.name, f.value);
			break;

		case BODY2:
			for (dp = f.value; *dp; dp++) {
				if (!isspace(*dp)) {
					advise(NULL, "Please re-edit draft to consist of headers only.");
					goto leave_bad;
				}
			}

		case FILEEOF2:
			goto process;

		case LENERR2:
		case FMTERR2:
		case IOERR2:
			advise(NULL, "Please re-edit draft and fix that header.");
leave_bad: ;
			fclose(ifp);
			fclose(ofp);
			unlink(drft);
			if (rename(backup, drft) == NOTOK) {
				advise(drft, "unable to rename %s to", backup);
			}
			return NOTOK;

		default:
			advise(NULL, "getfld() returned %d", state);
			return NOTOK;
		}
	}

process: ;
	fclose(ifp);
	fflush(ofp);

	if (!resent) {
		advise(NULL, "Please re-edit draft to include a ``Resent-To:'' header.");
		fclose(ofp);
		unlink(drft);
		if (rename(backup, drft) == NOTOK) {
			advise(drft, "unable to rename %s to", backup);
		}
		return NOTOK;
	}

	if (txtfd != NOTOK) {
		lseek(txtfd, (off_t) 0, SEEK_SET);  /* msgnam not accurate */
		cpydata(txtfd, fileno(ofp), msgnam, drft);
	}

	fclose(ofp);

	return OK;
}


static int
ready_msg(char *msgnam)
{
	enum state state;
	struct field f = {{0}};
	char tmpfil[BUFSIZ];
	int out;
	FILE *ifp, *ofp;
	char *cp = NULL;

	if (hdrfd != NOTOK) {
		close(hdrfd);
		hdrfd = NOTOK;
	}
	if (txtfd != NOTOK) {
		close(txtfd);
		txtfd = NOTOK;
	}
	if (!(ifp = fopen(msgnam, "r"))) {
		advise(msgnam, "unable to open message");
		return NOTOK;
	}

	cp = m_mktemp2(NULL, "dist", &hdrfd, NULL);
	if (!cp) {
		fclose(ifp);
		advise("distsbr", "unable to create temporary file");
		return NOTOK;
	}
	fchmod(hdrfd, 0600);
	strncpy(tmpfil, cp, sizeof(tmpfil));
	if ((out = dup(hdrfd)) == NOTOK || !(ofp = fdopen(out, "w"))) {
		fclose(ifp);
		advise(NULL, "no file descriptors -- you lose big");
		return NOTOK;
	}
	unlink(tmpfil);

	state = FLD2;
	while (1) {
		state = m_getfld2(state, &f, ifp);
		switch (state) {
		case FLD2:
			if (uprf(f.name, "resent")) {
				fprintf(ofp, "Prev-");
			}
			fprintf(ofp, "%s: %s", f.name, f.value);
			break;

		case BODY2:
			fclose(ofp);

			cp = m_mktemp2(NULL, "dist", &txtfd, NULL);
			if (!cp) {
				advise("distsbr", "unable to create temp file");
				return NOTOK;
			}
			fchmod(txtfd, 0600);
			strncpy(tmpfil, cp, sizeof(tmpfil));
			if ((out = dup(txtfd)) == NOTOK ||
					!(ofp = fdopen(out, "w"))) {
				advise(NULL, "no file descriptors -- you lose");
				return NOTOK;
			}
			unlink(tmpfil);
			fputs("\n", ofp);
			while (state == BODY2) {
				fputs(f.value, ofp);
				state = m_getfld2(state, &f, ifp);
			}
			/* FALL */

		case FILEEOF2:
			goto process;

		case LENERR2:
		case FMTERR2:
		case IOERR2:
			advise(NULL, "format error in message %s", msgnam);
			return NOTOK;

		default:
			advise(NULL, "getfld() returned %d", state);
			return NOTOK;
		}
	}
process: ;
	fclose(ifp);
	fclose(ofp);
	return OK;
}
