/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.0   JRR     02-Apr-1992     Initial version.
*	V01.1	JRR	26-May-1992	Remove unnecessary definition.
*					Shorten date in message.
*					Add header.
*	V01.2	JRR	03-Nov-1992	Check for .nqs-domain in user's home
*					directory.
*	V01.3
*	V01.4	JRR	23-Feb-1993	Added Boeing enhancement for Mids.
*			08-Apr-1993	Ensure broadcast at least to
*					original host.
*	V01.5	JRR	18-Aug-1993	Miniscule change to includes.
*	V01.6	JRR	22-Oct-1993	Establish own session and do not
*					wait for broadcast child.
*	V01.7	JRR	28-Feb-1994	Added support for SOLARIS.
*/
/*++ nqs_broadcast.c - Network Queueing System
 *
 *
 * DESCRIPTION:
 *
 *	This module contains the function:
 *
 *		nqs_broadcast()
 *
 *	which delivers a broadcast message either at the start of execution
 *	of an NQS job or the completion.
 *
 *
 *	Author:
 *	-------
 *	John Roman, Monsanto Company.
 *	April 2, 1992.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 */
#include "nqs.h"			/* NQS types and defns */
#include <errno.h>
#include <unistd.h>			/* For getuid() */
#include <pwd.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
#include "nqsmail.h"			/* NQS mail definitions */
#include "requestcc.h"			/* NQS request completion codes */
#include "nqsxvars.h"			/* Global vars */


/*** nqs_broadcast
 *
 *
 *	int nqs_broadcast()
 *
 *	Broadcast message regarding a specific NQS request and WAIT for
 *	the broadcast process to exit.
 *
 *	Similarities with nqs_mai are not a figment of your imagination.
 *	I started with that file to create this one.
 *
 *	WARNING:
 *		Nqs_broadcast() must NEVER be called at any time
 *		by the NQS daemon after the rebuild operation
 *		is complete, since this broadcast procedure waits
 *		for the spawned broadcast process to exit, which
 *		could result in the waiting for an exited
 *		request shepherd process, rather than the
 *		broadcast process.
 *
 *	Returns:
 *		0: if broadcast sent (does not guarantee delivery);
 *	       -1: if unsuccessful (diagnostic text is written
 *		   to the logfile).
 */
int nqs_broadcast (rawreq, requestlog, suffixcode)
register struct rawreq *rawreq;		/* Raw request structure for req */
register struct requestlog *requestlog;	/* Mail request log structure */
					/* (Can be NIL if suffixcode is */
					/*  one of MSX_BEGINNING or */
					/*  MSX_RESTARTING) */
int suffixcode;				/* Subject suffix code */
{
	static char *suffixtab []= {
		"aborted",		/* MSX_ABORTED */
		"aborted for NQS shutdown",
					/* MSX_ABORTSHUTDN */
		"beginning",		/* MSX_BEGINNING */
		"deleted",		/* MSX_DELETED */
		"delivered",		/* MSX_DELIVERED */
		"ended",		/* MSX_ENDED */
		"failed",		/* MSX_FAILED */
		"requeued",		/* MSX_REQUEUED */
		"restarting",		/* MSX_RESTARTING */
		"status"		/* Bad MSX value maps to here */
	};
        FILE *domainfile;      		/* Domain file */
	char domainfile_name[64];	/* Name of the domain file */
        char hostname [256];          	/* Domain file line buffer */
	int found_orig_host;		/* Flag make sure broadcast */
					/* to original host */

	char message [128];	/* Message to broadcast */
	int i;			/* Work var */
	struct tm *tp;		/* Break down time into parts */
	char *machinename;	/* Machine name */
	struct passwd *my_passwd;
	char *cp;
	int pid;		/* Process-id of child */
	time_t timeofday;	/* Time of day */
	char orig_host[64];     /* Name of original host */
	char *argv [100];	/* Arguments to shell */
	char *envp [5];		/* Environment variables for process that */
				/* will be used to send NQS mail */
	char home [64];		/* HOME=........................ */
#if	HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
	char logname [30];	/* LOGNAME=..................... */
#else
#if	BSD43 | ULTRIX | DECOSF
	char user [30];		/* USER=........................ */
#else
BAD SYSTEM TYPE
#endif
#endif


	/*
	 *  Build message line.
	 */
	if (suffixcode < 0 || suffixcode > MSX_MAXMSX) {
		suffixcode = MSX_MAXMSX+1;
	}
	time (&timeofday);
	strcpy(orig_host, fmtmidname(rawreq->orig_mid) );
	tp = localtime(&timeofday);
	sprintf (message, "NQS request: %s (%1ld.%s) %s at %d:%2.2d on %s",
		rawreq->reqname,
		(long) rawreq->orig_seqno, 
		orig_host,
		suffixtab [suffixcode],
		tp->tm_hour, tp->tm_min, 
      		fmtmidname (Locmid));
	if (Debug > 2) {
	    printf("D$nqs_broadcast: mid is %u\n", rawreq->orig_mid);
	    printf("D$nqs_broadcast: message is %s\n", message);
	}
	fflush (stdout);	/* Purge any diagnostic messages prior to */
	fflush (stderr);	/* fork */
	if ((pid = fork()) == 0) {
		setsid();	/* set our own session */
		/*
		 *  We are child process.
		 *
		 *  Simulate enough of a login account to cause the
		 *  msg  program to operate in the necessary fashion.
		 */
		sprintf (home, "HOME=/" );
		envp [0] = home;	/* Record the home directory */
		envp [1] = "SHELL=/bin/sh";
					/* Default shell */
#if		HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
		envp [2] = "PATH=:/bin:/usr/bin:/usr/local/bin";
		sprintf (logname, "LOGNAME=%s", rawreq->username);
		envp [3] = logname;
		envp [4] = (char *) 0;	/* No more environment variables */
#else
#if		BSD43 | ULTRIX | DECOSF
		envp [2] = "PATH=:/usr/ucb:/bin:/usr/bin:/usr/local/bin";
		sprintf (user, "USER=%s", rawreq->username);
		envp [3] = user;
		envp [4] = (char *) 0;	/* No more environment variables */
#else
BAD SYSTEM TYPE
#endif
#endif
		argv [0] = "msg";
		argv [1] = "-s";               /* silently, silently */
		argv [2] = "-m";
		argv [3] = message;
		domainfile == (FILE *) 0;
                my_passwd = fetchpwnam(rawreq->username);
		if ( my_passwd == NULL ) {
		    printf("E$nqs_broadcast: unable to get passwd for %s\n", 
			    rawreq->username);
		    fflush(stdout);
		} else {
                    sprintf(domainfile_name,  "%s/.nqs-domain", my_passwd->pw_dir);
                    domainfile = fopen (domainfile_name, "r");
                }
		if (domainfile == (FILE *) 0) {
		    sprintf(domainfile_name, "%s/nqs-domain", NQS_LIBEXE);
		    domainfile = fopen (domainfile_name, "r");
		}
        	if (domainfile != (FILE *) 0) {
		     i = 4;
		     while ( (fgets(hostname, sizeof(hostname), domainfile) ) != 
			(char *) 0 ) { 
		        cp = strchr(hostname, '\n');
		        if (cp != (char *) 0 ) *cp = '\0';
		        if (hostname[0] == '#') continue;
			if ( !strcmp(hostname,  orig_host)) found_orig_host++;
		        cp = malloc(strlen(rawreq->username)+strlen(hostname)+2);
		        if (cp == NULL) {
			    printf("E$nqs_broadcast:  malloc failed.\n");
		    	    fflush(stdout);
			    _exit (1);
		        }
		        sprintf(cp, "%s@%s", rawreq->username, hostname);
		        if (Debug > 4) {
			    printf("D$nqs_broadcast: sending to %s\n", cp);
			    fflush(stdout);
		        }
		        argv [i] = cp;
		        i++;
		    }
		    fclose (domainfile);
		}
		/*
		 * If we did not find the original host, add it to list.
		 */
		if (!found_orig_host) {
		    cp = malloc(strlen(rawreq->username)+strlen(orig_host)+2);
		    if (cp == NULL) {
			printf("E$nqs_broadcast:  malloc failed.\n");
		        fflush(stdout);
		        _exit (1);
		    }
		    sprintf(cp, "%s@%s", rawreq->username, orig_host);
		    if (Debug > 4) {
			printf("D$nqs_broadcast: sending to %s\n", cp);
			fflush(stdout);
		    }
		    argv [i] = cp;
		    i++;
      		}
		argv [i] = (char *) 0;
		if (Debug > 4) {
		    printf("D$nqs_broadcast: here are the arguments:\n");
		    for (i = 0; argv[i] != '\0'; i++) {
		        printf("D$nqs_broadcast: argv[%d] is %s\n", i, argv[i]);
		    }
		    fflush(stdout);
		}
		execve ("/usr/local/bin/msg", argv, envp);
					/* Execve() broadcast program */
		_exit (1);
	}
	else if (pid == -1) return (-1);	/* Fork failed */
	/*
	 *  The broadcast process was successfully created.
         *  Don't wait for the broadcast program to exit.
         */
        /*  while (wait ((int *)0) == -1 && errno == EINTR) 
         *       ;
	 */
	return (0);				/* Success */
}
