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

/*
 * Common routine to produce a diagnostic message for the scheduler to read
 */

#include "hostenv.h"
#include <stdio.h>
#include <sysexits.h>
#ifdef HAVE_STDARG_H
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "mail.h"
#include "ta.h"


extern char *strdup();
extern void *emalloc();
extern void *erealloc();

char *notarybuf = NULL;
time_t retryat_time = 0; /* Used at SMTP to avoid trying same host too soon.. */

char *
notaryacct(rc,okstr)
int rc;
char *okstr;
{
	static char msgbuf[20];
	switch (rc) {
	  case EX_OK:
	      return okstr; /* "delivered" or "relayed" ..  Depends.. */
	  case EX_TEMPFAIL:
	  case EX_IOERR:
	  case EX_OSERR:
	  case EX_CANTCREAT:
	  case EX_SOFTWARE:
	      return "delayed";
	  case EX_NOUSER:
	  case EX_NOHOST:
	  case EX_UNAVAILABLE:
	      return "failed";
	  case EX_NOPERM:
	  case EX_PROTOCOL:
	  case EX_USAGE:
	  default:
	      sprintf(msgbuf,"*SW-ERROR*not-act-rc=%d*",rc);
	      return msgbuf;
	}
}

static char *arg5 = NULL; /* NOTARY arg5: 'While-Talking-To -host' */
void notary_setwtt(host)
char *host;
{
	if (arg5) free(arg5);
	if (host)
	  arg5 = strdup(host);
	else
	  arg5 = NULL;
}

void
notaryreport(arg1,arg2,arg3,arg4)
     const char *arg1, *arg2, *arg3, *arg4;
{
	char *fmt = "%s\001%s\001%s\001%s\001%s";
	int len;
	static char *A1 = NULL, *A2 = NULL, *A3 = NULL, *A4 = NULL;

	if (arg1) { if (A1) free(A1); A1 = strdup(arg1); }
	if (arg2) { if (A2) free(A2); A2 = strdup(arg2); }
	if (arg3) { if (A3) free(A3); A3 = strdup(arg3); }
	if (arg4) { if (A4) free(A4); A4 = strdup(arg4); }

	len = 5; /* "\001\001\001\001" */
	if (A1) len += strlen(A1);
	if (A2) len += strlen(A2);
	if (A3) len += strlen(A3);
	if (A4) len += strlen(A4);
	if (arg5) len += strlen(arg5);

	if (!notarybuf)
	  notarybuf = (char*) emalloc(len);
	else
	  notarybuf = (char*) erealloc(notarybuf,len);
	sprintf(notarybuf,fmt,
		A1?A1:"",A2?A2:"",A3?A3:"",A4?A4:"",
		arg5?arg5:"");
}

#ifdef HAVE_STDARG_H
void
diagnostic(struct rcpt *rp, int rc, int timeout, char *fmt, ...)
#else
/*VARARGS*/
void
diagnostic(rp, rc, timeout, fmt, va_alist) /* (rp, rc, timeout, "fmtstr", remotemsg) */
	struct rcpt *rp;
	int rc, timeout;
	char *fmt;
	va_dcl
#endif
{
	char	mark, message[8192];
	register char *s, *es, *s2;
	va_list	ap;
	int report_notary = 1;

	rp->status = rc;

#ifdef HAVE_STDARG_H
	va_start(ap,fmt);
#else
	va_start(ap);
#endif
	es = &message[sizeof message - 2];
	for (s = message; fmt != NULL && *fmt != '\0'; ++fmt) {
		if (s >= es)
			break;
		if (*fmt != '%') {
			*s++ = *fmt;
			continue;
		}
		switch (*++fmt) {
		case 's':	/* string */
			for (s2 = va_arg(ap, char *); *s2 != 0; ++s2) {
				*s++ = *s2;
				if (s >= es)
					break;
			}
			break;
		case 'd':	/* integer */
			if (s >= es - 10)
				break;
			sprintf(s, "%d", va_arg(ap, int));
			while (*s != '\0') ++s;
			break;
		case '%':	/* percent */
			*s++ = '%';
			break;
		case '\0':
			--fmt;	/* exit soonest */
			break;
		}
	}
	*s = '\0';
	va_end(ap);

	retryat_time = 0;

	/* XX: Following needs changes if we are to do positive
	   delivery acknowledgements! */
	if (rp->status == EX_OK)
	  report_notary = 0;

	printf("%d/%ld\t%s\t",
	       rp->desc->ctlid, rp->id,
	       (notarybuf && report_notary) ? notarybuf : "");
	switch (rp->status) {
	case EX_OK:
		printf("ok");
		mark = _CFTAG_OK;
		break;
	case EX_TEMPFAIL:
	case EX_IOERR:
	case EX_OSERR:
	case EX_CANTCREAT:
	case EX_SOFTWARE:
		if (timeout > 0) {
		  printf("retryat +%d",timeout);
		  time(&retryat_time);
		  retryat_time += timeout;
		}
		else
		  printf("deferred");
		mark = _CFTAG_DEFER;
		break;
	case EX_NOPERM:
	case EX_PROTOCOL:
	case EX_USAGE:
		strncat(message,
			" (this is abnormal, investigate!)", es - s);
		s += strlen(s);
		/* fall through */
	case EX_NOUSER:
	case EX_NOHOST:
	case EX_UNAVAILABLE:
		printf("error");
		mark = _CFTAG_NOTOK;
		break;
	default:
		printf("error Unknown sysexits error code %d!",
		       rp->status);
		mark = _CFTAG_NOTOK;
		break;
	}
	if (message[0] != '\0')
		printf(" %s", message);
	printf("\n");
	if (!lockaddr(rp->desc->ctlfd, rp->desc->ctlmap,
		      rp->lockoffset, _CFTAG_LOCK, mark)) {
	  /* something went wrong in unlocking it, concurrency problem? */
	}
	rp->lockoffset = 0;	/* mark this recipient unlocked */
	fflush(stdout);
}
