/* sc_sound.c
   gopher item subclass procedures for sound */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.3     08 April 1993                  */
     /*                version 1.2     20 November 1992               */
     /*                version 1.1     20 April 1992                  */
     /*                version 1.0     04 March 1992                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing and Communications Services Office   */
     /* Copyright 1992, 1993 by                                       */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/

#include "conf.h"
#include "globals.h"
#include "gopher.h"
#include "appres.h"
#include "util.h"
#include "status.h"
#include "jobs.h"
#include "misc.h"
#include "subst.h"
#include "sc_sound.h"
#include "sc_soundP.h"

#include "osdep.h"

extern	 errno;



/* getSound
   get a sound file and play it.  Since sound will not conflict with
   visuals, this can be done asynchronously as a new process.

   X is run in a distributed environment.  As such, we take some pains
   to ensure that the requestor of the sound is the one who will actually
   hear the sound.  To wit, we strive to determine that the Xgopher
   client host and X display host are one and the same.  

   Note that this does not eliminate mischief, as the sound command
   specified in the resources can still be an "rsh" type of command. */

static BOOLEAN
getSound(gi)
gopherItemP	gi;
{
	static BOOLEAN	firstTime = TRUE;
	static BOOLEAN	soundCommandOK = TRUE;
	static char	*soundCmd;
	char		message[MESSAGE_STRING_LEN];
	FILE		*soundCmdFile;
	PID_TYPE	soundPID = (PID_TYPE) 0;
	int		s;


	/* see if sound command is an executable file */

	if (firstTime) {
		firstTime = FALSE;
		soundCmd = editCommand(gi, cmdPath(appResources->soundCommand),
				(char *) NULL, (char *) NULL);
		if (soundCmd == NULL) {
			soundCommandOK = FALSE;
		}

		/* check here for X display (later) */
	}

	if (! soundCommandOK) {
		sprintf (message,
			"Unable to execute the sound play command: \'%s\'\n",
			soundCmd);
		showError(message);
		return FALSE;
				
	}

	if (findJobType(gi->type) != NO_JOB) {
		/* sound may still be active */
		PID_TYPE	pid;

		waitOnChildren();
		pid = findJobType(gi->type);
		if (pid != NO_JOB) {
		    showError(
		    "Another sound file is still executing.  Try again later."
		        );
		    return FALSE;
		} 
	}


	if ((soundPID = fork()) < 0) {
		soundCommandOK = FALSE;
		sprintf(message,
		    "Unable to start playing the sound (error %d)\n",
		    errno);
		showError(message);
		return FALSE;

	} else if (soundPID == 0) {

		/* we should immediately do a 
		      close (ConnectionNumber(XtDisplay(widget)));
		   here.  */

		/* DO NOT use status panel or any X requests including error
		   popups in this block.  This is the CHILD process and has
		   no business using the parent's X connection. */

		s = connectToSocket(gi->host, gi->port);
		if (s < 0) {
			/* networkError(s, gi->host, gi->port); */
			fprintf (stderr, "Cannot connect to %s at port %d\n",
					gi->host, gi->port);
			return FALSE;
		}

		writeString(s, vStringValue(&(gi->selector)));
		writeString(s, EOL_STRING);

		soundCmdFile = popen(soundCmd, "w");

		if (soundCmdFile == NULL) {
			close (s);
			sprintf(message,
			    "Unable to start the sound command (\'%s\')",
				soundCmd);
			/* showError(message); */
			fprintf(stderr, "%s\n", message);
			exit(-1);
		}

		GI_copyNetUntilEOF(s, soundCmdFile);

		close(s);
		pclose(soundCmdFile);
		exit(0);
	}

	/* parent */

	showStatus("trying to start playing a sound file from",
					STAT_TEMP_MESSAGE,
					gi->host, gi->port);
	addJob(gi->type, soundPID);
	return TRUE;
}


/* GISound_restart
   kill a sound command process if possible. */

void
GISound_restart()
{
	killAllItemType(A_SOUND);
}


/* GISound_init
   initialize sound class - host access list and prefix. */

void
GISound_init()
{
	GU_makePrefix(prefixSound,  appResources->prefixSound);
	soundHostList = GU_createAccessList(appResources->soundServers);
	GU_registerNewType(A_SOUND, &soundSubclass);

	/* as a mater of security, in public mode, if there are no
	   restrictions, sounds should be banned.  It is easy to
	   overcome these restrictions by creating a list such as
	   ".edu .com .mil .gov .net" etc.  */

	if (appResources->publicMode  &&  soundHostList == NULL) {
		appResources->hasSound	= False;
	}

	return;
}


/* GISound_access
   check the accessability of a sound file selection */

BOOLEAN
GISound_access(gi)
gopherItemP	gi;
{
	BOOLEAN	result;

	if (appResources->hasSound  &&
	    (soundHostList == NULL  ||
				GU_checkAccess(gi->host, soundHostList))) {
		result = TRUE;
	}else {
		result = FALSE;
	}

	return result;
}


/* GISound_process
   process a sound file selection */

BOOLEAN
GISound_process(gi)
gopherItemP	gi;
{
	BOOLEAN	result;

	result = getSound(gi);

	return result;
}
