/*
 *	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 <sys/param.h>
#include <fcntl.h>
#include <mail.h>
#include "scheduler.h"
#ifdef	USE_SYSLOG
#include <syslog.h>
#endif	/* USE_SYSLOG */

/*
 * There has to be some way of collecting the error messages produced during
 * delivery, and this is it. Each message is appended to the control file.
 * Just before the control file is to be unlinked (or at other times by
 * external programs), we check to see if we had any diagnostic messages.
 * If so, we need to submit a message to the router using the standard
 * routines. This scheme is ugly in that it modifies the control file rather
 * drastically (at least its forced-appends), but elegant in most every other
 * respect (knock wood).
 */

/* deposit the error message */

void
msgerror(vp, offset, message)
	struct vertex *vp;
	long offset;
	char *message;
{
	char path[MAXPATHLEN];
	FILE *fp;

	(void) sprintf(path, "../%s/%s", TRANSPORTDIR, vp->cfp->mid);
	/* exclusive access required, but we're the only scheduler... */
	if ((fp = fopen(path, "a")) == NULL) {
		(void) fprintf(stderr,
			       "Cannot open control file %s to deposit", path);
		(void) fprintf(stderr,
			       " error message for offset %ld:\n", offset);
		(void) fprintf(stderr, "\t%s\n", message);
		return;
	}
	vp->cfp->haderror = 1;
	fprintf(fp, "%c%c%ld %s\n",
		    _CF_DIAGNOSTIC, _CFTAG_NORMAL, offset, message);
	(void) fclose(fp);
}

/* called to process errors at sensible intervals */

void
reporterrs(cfp)
	struct ctlfile *cfp;
{
	int i, n, wroteheader, byteidx, fd;
	long *lp;
	char path[MAXPATHLEN], buf[BUFSIZ], *midbuf, *cp, *s, *eaddr;
	FILE *errfp, *fp;
	extern struct ctlfile *slurp();
	extern char *mailshare, *progname;
	extern int lockaddr();

	if (cfp->haderror == 0)
		return;
	if (cfp->erroraddr == NULL)
		return;
	eaddr = cfp->erroraddr;
	/* re-read the control file to get some unstashed information */
	midbuf = cfp->mid;
	(void) sprintf(path, "../%s/%s", TRANSPORTDIR, cfp->mid);
	/* we don't need cfp any more... reuse the variable */
	/* exclusive access required, but we're the only scheduler... */
	if ((fd = open(path, O_RDWR, 0)) < 0 || (cfp = slurp(fd)) == NULL) {
		(void) fprintf(stderr,
			"%s: unexpected absence of control file %s for error processing!\n",
			progname, path);
		if (fd >= 0)
			(void) close(fd);
		return;
	}
	lp = &cfp->offset[0];
	if ((errfp = mail_open(MSG_RFC822)) == NULL) {
		(void) fprintf(stderr,
			"%s: cannot open mail file to return diagnostics!\n",
			progname);
		(void) close(cfp->fd);
		free(cfp->contents);
		if (cfp->logident != NULL)
			free(cfp->logident);
		free((char *)cfp);
		return;
	}
	cfp->mid = midbuf;
	wroteheader = 0;
	for (i = 0; i < cfp->nlines; ++i, ++lp) {
		cp = cfp->contents + *lp;
		if (!(*cp == _CF_DIAGNOSTIC && *++cp == _CFTAG_NORMAL))
			continue;
		if (!wroteheader) {
			(void) fprintf(errfp, "channel error\n");
			(void) fprintf(errfp, "To: %s\n", eaddr);
			(void) sprintf(path, "%s/%s/delivery",
				      mailshare, FORMSDIR);
			if ((fp = fopen(path, "r")) != NULL) {
				while ((n = fread(buf, sizeof buf[0], sizeof buf, fp)) > 0)
					(void) fwrite(buf, sizeof buf[0], n, errfp);
				(void) fclose(fp);
			}
			(void) fprintf(errfp, "\n");
			wroteheader = 1;
		}
		cp = cfp->contents + *lp + 2;
		byteidx = atoi(cp);
		while (isascii(*cp) && isdigit(*cp))
			++cp;
		while (isascii(*cp) && isspace(*cp))
			++cp;
		(void) fprintf(errfp, "<%s>: ", cfp->contents + byteidx + 2);
		if (strchr(cp, '\r')) {
			(void) fprintf(errfp, "...\\\n\t");
			for (s = cp; *s != '\0'; ++s) {
				if (*s == '\r')
					(void) putc('\n', errfp), putc('\t', errfp);
				else
					(void) putc(*s, errfp);
			}
			(void) putc('\n', errfp);
		} else
			(void) fprintf(errfp, "%s\n", cp);
		(void) lockaddr(cfp->fd, *lp + 1, _CFTAG_NORMAL, _CFTAG_OK);
#ifdef	LOG_INFO
		syslog(LOG_INFO, "%s: <%s>: %s",
				 cfp->mid, cfp->contents + byteidx + 2, cp);
#endif	/* LOG_INFO */
	}
	fprintf(errfp, "\n----------  Original Message  ----------\n");
	sprintf(path, "../%s/%s", QUEUEDIR, cfp->mid);
	if ((fp = fopen(path, "r")) != NULL) {
		while ((n = fread(buf, sizeof buf[0], sizeof buf, fp)) > 0)
			fwrite(buf, sizeof buf[0], n, errfp);
		(void) fclose(fp);
	}
	(void) mail_close(errfp);	/* XX: check for error */
	(void) close(cfp->fd);
	(void) free(cfp->contents);
	if (cfp->erroraddr != NULL)
		(void) free(cfp->erroraddr);
	if (cfp->logident != NULL)
		(void) free(cfp->logident);
	(void) free((char *)cfp);
}

char *
mail_alloc(n)
	u_int n;
{
	return emalloc(n);
}

void
mail_free(s)
	char *s;
{
	free(s);
}

