/* launch.c */

/*		Copyright © 1989 by Donald T. Meyer, Stormgate Software
 *		All Rights Reserved
 */



#include "rxil.h"

#include <string.h>



/* NAME
 *		RxilLaunch
 *
 * SYNOPSIS
 *		result = RxilLaunch( rxi )
 *
 *		LONG result;
 *
 *		struct RxilInvocation *rxi;
 *
 * FUNCTION
 *		Launch an ARexx program by sending an invocation message
 *		to the RexxMaster process.  The RxilInvocation structure
 *		which is allocated prior to this call via RxilCreateRxi()
 *		contains the information neccessary to launch the program.
 *
 * INPUTS
 *		rxi		A pointer to an initialized RxilInvocation structure.
 *
 * RESULT
 *		Zero if the launch was successful, non-zero otherwise.
 *
 * SIDES
 *
 * HISTORY
 *		01-Aug-89	Creation.
 *
 * BUGS
 *
 * SEE ALSO
 *		RxilCreateRxi(), RxilDeleteRxi()
 */

LONG RxilLaunch( struct RxilInvocation *rxi )
{
	struct RexxArg *arg;
	struct MsgPort *rmast, *replyport;
	struct RexxMsg *rexxmsg;
	int i;
	int ac=0;
	UWORD len;


	/* Make call "safe" even if RxilInit() failed */
	if( global_rdef == NULL )
	{
		return( -1 );
	}


	/* Replys can come in at either port. */
	replyport = global_rdef->SecretPort ?
		global_rdef->SecretPort : global_rdef->PublicPort;


	if( rxi->State != RXIL_STATE_AVAILABLE )
	{
		/* A command is already launched, (using this structure),
		 * or the reply has not yet been dealt with.
		 */
		return( -1 );
	}


	/* Allocate a packet to send to rexxmaster */
	rexxmsg = CreateRexxMsg( replyport, rxi->FileExt, rxi->CommAddr );
	if( rexxmsg == NULL )
	{
		return( -1 );
	}

	/* Allocate an argument string for the command name and args */
	arg = CreateArgstring(  rxi->Name, strlen( rxi->Name )  );
	if( arg == NULL )
	{
		DeleteRexxMsg( rexxmsg );
		return( -1 );
	}
 
	ARG0(rexxmsg) = (STRPTR)arg;


	if( rxi->Type == RXFUNC )
	{
		/* This is a Function invocation. */

		/* Turn the arguments into Rexx Argstrings and place in the
		 * RexxMsg packet.
		 */
		for( i=1; i<=MAXRMARG; i++ )
		{
			if( rxi->FuncArg[i] == NULL )
			{
				/* Empty argument slot, consider it the last */
				break;
			}

			/* We can either determine the argument length, or the client
			 * can pre-set a count.
			 */
			len = rxi->CountArgs ?
				rxi->ArgLen[i] : strlen(rxi->FuncArg[i]);

			rexxmsg->rm_Args[i] =
				(STRPTR)CreateArgstring( rxi->FuncArg[i], len );

			ac++;

			if( rexxmsg->rm_Args[i] == NULL )
			{
				/* Unable to create this argstring.  Cleanup and return
				 * a failure code.
				 */
				for( i=0; i<=MAXRMARG; i++ )
				{
					if( rexxmsg->rm_Args[i] != NULL )
					{
						DeleteArgstring( (struct RexxArg *)
							(rexxmsg->rm_Args[i]) );
					}
				}

				DeleteRexxMsg( rexxmsg );
				return( -1 );
			}
		}

		rexxmsg->rm_Action = RXFUNC | rxi->ActionFlags | ac;
	}
	else
	{
		/* This is a Command invocation */
 		rexxmsg->rm_Action = RXCOMM | rxi->ActionFlags;
	}


	/* Set up the I/O streams for the macro */

	if( rxi->Parent == NULL )
	{
		/* This is an original launch from the application */
		if( rxi->Console )
		{
			/* And there is a console spec.  Use it. */
			RxilOpenConsole( rxi->Console, rexxmsg );
		}
	}
	else
	{
		/* This is a loopback child of a macro.  Use the I/O fields
		 * from the parent message.
		 */
		rexxmsg->rm_Stdin = rxi->Parent->rm_Stdin;
		rexxmsg->rm_Stdout = rxi->Parent->rm_Stdout;
	}
 
 
	Forbid();
	if(   (  rmast = FindPort( rxi->IHostPort )  ) != NULL   )
	{
		PutMsg( rmast, (struct message *)rexxmsg );
	}
	Permit();
 
	if( rmast == NULL )
	{
		/* we could not find the REXX port, this failed!
		 * Cleanup and return a failure code.
		 */
		for( i=0; i<=MAXRMARG; i++ )
		{
			if( rexxmsg->rm_Args[i] != NULL )
			{
				DeleteArgstring( (struct RexxArg *)
					(rexxmsg->rm_Args[i]) );
			}
		}

		if( rxi->Console )
		{
			RxilCloseConsole( rexxmsg );
		}

		DeleteRexxMsg( rexxmsg );
		return( -1 );
	}


	/* If we make it here, we have hopefully launched. */
 
	/* Set this so we can recognize the reply, and to let us know that
	 * we have a command pending.
	 */
	rxi->RexxMsg = rexxmsg;
	rxi->State = RXIL_STATE_PENDING;
 

	if( rxi->CommAddr == global_rdef->SecretPortName )
	{
#if 0
		if( global_rdef->Locked  )
		{
			/* Since we are locked, we should not be launching any macros
			 * which have the secret port as their initial host address.
			 */
			return( -1 );
		}
#endif

		/* Increment the locked count.
		 */
		global_rdef->LockCount++;
	}


	if( rxi->Parent == NULL )
	{
		/* This is a launch originated within the application. */
		if(  FlagIsClear( global_rdef->Flags, RXIL_NO_ABORT )  )
		{
			/* Post the macro cancel requester */
			RxilPostCancel();
		}
	}


	return( 0 );
}

