/*

 #    #   ####    ####            ####
 ##  ##  #       #    #          #    #
 # ## #   ####   #               #
 #    #       #  #  ###   ###    #
 #    #  #    #  #    #   ###    #    #
 #    #   ####    ####    ###     ####

	Fatal messages.
*/

/*
 * $Id: msg.c,v 3.0.1.5 1999/01/13 18:08:06 ram Exp $
 *
 *  Copyright (c) 1990-1993, Raphael Manfredi
 *  
 *  You may redistribute only under the terms of the Artistic License,
 *  as specified in the README file that comes with the distribution.
 *  You may reuse parts of this distribution only within the terms of
 *  that same Artistic License; a copy of which may be found at the root
 *  of the source tree for mailagent 3.0.
 *
 * $Log: msg.c,v $
 * Revision 3.0.1.5  1999/01/13 18:08:06  ram
 * patch64: added tag-checking heuristic to say()
 *
 * Revision 3.0.1.4  1996/12/24  13:59:31  ram
 * patch45: call my_exit() instead of exit()
 *
 * Revision 3.0.1.3  1995/08/31  16:22:00  ram
 * patch42: new routine say() to print messages onto stderr
 * patch42: all messages on stderr now also include the filter pid
 * patch42: fatal() now prefixes its supplied reason with FATAL
 *
 * Revision 3.0.1.2  1995/08/07  16:10:55  ram
 * patch37: commented and re-organized fatal code for emergency saving
 *
 * Revision 3.0.1.1  1994/09/22  13:46:01  ram
 * patch12: made fatal() arguments long rather than int for 64-bit machines
 *
 * Revision 3.0  1993/11/29  13:48:17  ram
 * Baseline for mailagent 3.0 netwide release.
 *
 */

#include "config.h"
#include "portable.h"
#include <stdio.h>
#include <sys/types.h>
#include <ctype.h>
#include "sysexits.h"
#include "logfile.h"
#include "lock.h"
#include "io.h"
#include "confmagic.h"

#define MAX_STRING	1024		/* Maximum length for error string */

extern Pid_t progpid;			/* Program PID */

/* VARARGS2 */
public void say(msg, arg1, arg2, arg3, arg4, arg5)
char *msg;
long arg1, arg2, arg3, arg4, arg5;	/* Use longs, hope (char *) fits in it! */
{
	/* Write important message to stderr */

	fprintf(stderr, "%s[%d]: ", progname, progpid);
	fprintf(stderr, msg, arg1, arg2, arg3, arg4, arg5);
	fputc('\n', stderr);

	/*
	 * A little heuristic here...
	 *
	 * If the message begins with an upper-cased don't prepend
	 * the ERROR tag, assuming a tag was already specified.
	 */

	if (isupper(msg[0]))
		add_log(2, msg, arg1, arg2, arg3, arg4, arg5);
	else {
		char buffer[MAX_STRING];
		sprintf(buffer, "ERROR %s", msg);
		add_log(2, buffer, arg1, arg2, arg3, arg4, arg5);
	}
}

/* VARARGS2 */
public void fatal(reason, arg1, arg2, arg3, arg4, arg5)
char *reason;
long arg1, arg2, arg3, arg4, arg5;	/* Use longs, hope (char *) fits in it! */
{
	/* Fatal error -- die with a meaningful error status for sendmail. If the
	 * logfile has been opened, the reason will also be logged there.
	 */
	char buffer[MAX_STRING];
	int status;						/* Status from emergency_save() */
	
	/*
	 * Attempt a save as early as possible, since we might not recover
	 * from a fprintf() if we came here on a SIGSEGV or a SIGBUS.
	 */

	status = emergency_save();		/* Attempt emergency saving */

	fprintf(stderr, "%s[%d]: FATAL ", progname, progpid);
	fprintf(stderr, reason, arg1, arg2, arg3, arg4, arg5);
	fputc('\n', stderr);

	sprintf(buffer, "FATAL %s", reason);
	add_log(1, buffer, arg1, arg2, arg3, arg4, arg5);

	release_lock();		/* We're about to exit, free grabbed resources */

	/*
	 * If the emergency saving failed, then the message is not queued
	 * anywhere. We're about to leave the message in the MTA queue in
	 * that case, but we must warn them since we have no guarantee the
	 * MTA will do as we think it will.
	 */

	if (status == -1)
		add_log(5, "WARNING no saving was ever done");

	if (!was_queued()) {
		/*
		 * Exit with a meaningful exit code for the MTA (sendmail usually) so
		 * that it leaves the message in its own queue for later delivery when
		 * conditions * are better (hopefully), or it will bounce to the sender
		 * after some delay.
		 */

		add_log(6, "NOTICE leaving mail in MTA's queue");
		my_exit(EX_TEMPFAIL);
	}

	/*
	 * Message was saved somewhere where mailagent will find it (either in
	 * its queue, or listed in the agent.wait file). There's no need for
	 * the MTA to worry, hence the following...
	 */

	my_exit(EX_OK);
}

