/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

#include "hostenv.h"
#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <signal.h>
#include <sysexits.h>
#include <varargs.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <mail.h>
#include "ta.h"


#define	PROGNAME	"errormail"
#define	CHANNEL		"error"	/* the default channel name we deliver for */

char *dfltform[] = {
		"From: The Post Office <postmaster>",
		"Subject: Delivery problems with your mail",
		"Cc: The Post Office <postoffice>",
		"Precedence: junk",
		"",
		"Processing your mail message caused the following errors:",
		NULL
};

char *progname;

extern void warning();
extern char *emalloc();

#ifndef	MAXPATHLEN
#define	MAXPATHLEN 1024
#endif	/* MAXPATHLEN */

int
main(argc, argv)
	int argc;
	char *argv[];
{
	char *channel, file[MAXPATHLEN+1];
	int errflg, c;
	struct ctldesc *dp;
	extern char *optarg;
	extern int optind;
	extern int emptyline();
	extern void prversion(), process();

	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		(void) signal(SIGINT, wantout);
	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		(void) signal(SIGHUP, wantout);
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		(void) signal(SIGTERM, wantout);
	(void) signal(SIGPIPE, SIG_IGN);

	if ((progname = strrchr(argv[0], '/')) == NULL)
		progname = argv[0];
	else
		++progname;
	errflg = 0;
	channel = CHANNEL;
	while ((c = getopt(argc, argv, "c:V")) != EOF) {
		switch (c) {
		case 'c':	/* specify channel scanned for */
			channel = optarg;
			break;
		case 'V':
			prversion(PROGNAME);
			exit(EX_OK);
			break;
		default:
			++errflg;
			break;
		}
	}
	if (errflg || optind != argc) {
		(void) fprintf(stderr, "Usage: %s [-V] [-c channel]\n",
				argv[0]);
		exit(EX_USAGE);
	}

	while (!getout && fgets(file, sizeof file, stdin)) {
		if (emptyline(file, sizeof file))
			break;
		dp = ctlopen(file, channel, (char *)NULL, &getout, ctlsticky);
		if (dp == NULL)
			continue;
		process(dp);
		ctlclose(dp);
	}
	exit(0);
	/* NOTREACHED */
	return 0;
}

char *
tmalloc(n)
	int n;
{
	extern char *emalloc();

	return emalloc((u_int)n);
}

void
process(dp)
	struct ctldesc *dp;
{
	char buf[BUFSIZ];
	char **cpp, *mailshare, *mfpath;
	FILE *mfp, *efp;
	int n;
	struct rcpt *rp;

	/* recipient host field is the error message file name in FORMSDIR */
	/* recipient user field is the address causing the error */

	if (dp->senders == NULL) {
		/*
		 * If there was no error return address
		 * it might be because this message was
		 * an error message being bounced back.
		 * We do NOT want to bounce this, but
		 * instead just drop it on the floor.
		 */
		for (rp = dp->recipients; rp != NULL; rp = rp->next)
			diagnostic(rp, EX_OK, "error bounce dropped");
		return;
	}

	if ((mfp = mail_open(MSG_RFC822)) == NULL) {
		for (rp = dp->recipients; rp != NULL; rp = rp->next)
			diagnostic(rp, EX_TEMPFAIL, "mail_open failure");
		warning("Cannot open mail file!");
		return;
	}

	rp = dp->recipients;

	/* copy To: from error return address */
	(void) fprintf(mfp, "To: %s\n", rp->addr->link->user);

	/* copy error message file itself */
	if ((mailshare = getzenv("MAILSHARE")) == NULL)
		mailshare = MAILSHARE;

	mfpath = emalloc(3+strlen(mailshare)+strlen(FORMSDIR)
				 +strlen(rp->addr->host));
	(void) sprintf(mfpath, "%s/%s/%s", mailshare, FORMSDIR, rp->addr->host);

	if ((efp = fopen(mfpath, "r")) != NULL) {
		while ((n = fread(buf, sizeof buf[0], sizeof buf, efp)) > 0)
			(void) fwrite(buf, sizeof buf[0], n, mfp);
		(void) fclose(efp);
	} else {
		for (cpp = &dfltform[0]; *cpp != NULL; ++cpp)
			(void) fprintf(mfp, "%s\n", *cpp);
	}
	/* print out errors in standard format */
	(void) fputc('\n', mfp);
	for (rp = dp->recipients; rp != NULL; rp = rp->next) {
		(void) fprintf(mfp, "error: %s: %s\n",
				    rp->addr->host, rp->addr->user);
	}
	(void) fprintf(mfp,
		"\n------- Original Message follows -------\n");
	/* copy original message file */
	while ((n = read(dp->msgfd, buf, sizeof buf)) > 0)
		(void) fwrite(buf, sizeof buf[0], n, mfp);
	if (ferror(mfp)) {
		(void) mail_abort(mfp);
		n = EX_IOERR;
	} else if (mail_close(mfp) == EOF)
		n = EX_IOERR;
	else
		n = EX_OK;
	for (rp = dp->recipients; rp != NULL; rp = rp->next)
		diagnostic(rp, n, (char *)NULL);
}
