/****************************************************************************/
/*                               RXControl.c                                */
/*                        Control features of ARexx                         */
/*                    Copyright © 1994 MIchael Letowski                     */
/****************************************************************************/

#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/execbase.h>
#include <dos/rdargs.h>
#include <dos/dos.h>
#include <rexx/rxslib.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>

#include <support/types.h>
#include <support/exec.h>
#include <support/dos.h>

#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/rexxsyslib.h>
#include <proto/intuition.h>
#include <proto/icon.h>

#include "rxcontrol.rev.h"

#define DOS_NAME				"dos.library"
#define REXX_NAME				"rexxsyslib.library"
#define INTUI_NAME			"intuition.library"
#define ICON_NAME				"icon.library"
#define DOS_VERN				37L
#define REXX_VERN				36L
#define INTUI_VERN			37L
#define ICON_VERN				37L

#define RXPORT_NAME			"REXX"

#define RXCONTROL_NAME	"RXControl"

#define TEMPLATE				"CANCEL=RXC/S,HALT=HI/S,SUSPEND/S,RESUME/S,"\
												"TRACESTART=TS/S,TRACEEND=TE/S,"\
												"CONOPEN=TCO/S,CONCLOSE=TCC/S,"\
												"QUIET/S"

#define OPT_RXC					0
#define OPT_HI					1
#define OPT_SUSPEND			2
#define OPT_RESUME			3
#define OPT_TS					4
#define OPT_TE					5
#define OPT_TCO					6
#define OPT_TCC					7
#define OPT_QUIET				8
#define OPT_COUNT				9

/* Messages */
#define UNABLE_OPEN			"Unable to open '%s'\n"
#define NOT_ACTIVE			"ARexx server not active\n"
#define IS_SUSPENDED		"Execution is suspended\n"
#define WILL_CLOSE			"RexxMaster will close\n"
/* Other texts */
#define OK							"OK"
#define ON							"ON"
#define OFF							"OFF"
#define OPEN						"open"
#define CLOSED					"closed"
#define REQUEST_MSG			" Request"
#define INFO_MSG				" Information"
#define SPC_TAB					"  "

STATIC CONST TEXT VersionString[]=
	VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);

struct Switch
{
	STRPTR sw_Name;
	ULONG sw_Index;
};

ULONG CLIMode(struct ExecBase *SysBase, struct DosLibrary *DOSBase);
ULONG WBMode(struct ExecBase *SysBase, struct DosLibrary *DOSBase);

ULONG RXControl(VOID)
{
	struct ExecBase *SysBase=*((struct ExecBase **)4);
	struct DosLibrary *DOSBase;

	ULONG RC=RETURN_FAIL;

	unless(DOSBase=(struct DosLibrary *)OpenLibrary(DOS_NAME,DOS_VERN))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidDOS;
	}

	RC=FromWB ? WBMode(SysBase,DOSBase) : CLIMode(SysBase,DOSBase);

	CloseLibrary((struct Library *)DOSBase);
InvalidDOS:
	return(RC);
}

/* CLI mode work */
ULONG CLIMode(struct ExecBase *SysBase, struct DosLibrary *DOSBase)
{
	struct RxsLib *RexxSysBase;

	struct RDArgs *Args;
	struct MsgPort *Port;
	struct RexxMsg *RXMsg;
	LONG Options[OPT_COUNT];
	ULONG RC=RETURN_FAIL;
	BOOL ErrOccured=FALSE;

	unless(RexxSysBase=(struct RxsLib *)OpenLibrary(REXX_NAME,REXX_VERN))
	{
		CauseIoErr(ERROR_INVALID_RESIDENT_LIBRARY,NULL);
		goto InvalidREXX;
	}

	/* Read options */
	clear(&Options);										/* Clear options buffer */
	unless(Args=ReadArgs(TEMPLATE,Options,NULL))
	{
		PrintFault(IoErr(),NULL);				/* Inform user */
		goto NoArgs;
	}

	/* Check for REXX port */
	Forbid();
	unless(Port=FindPort(RXPORT_NAME))
	{
		Permit();
		PutStr(NOT_ACTIVE);
		goto NotActive;
	}
	/* RXC */
	if(Options[OPT_RXC])
	{
		if(RXMsg=CreateRexxMsg(NULL,NULL,NULL))
		{
			RXMsg->rm_Action=RXCLOSE | RXFF_NONRET;
			PutMsg(Port,(struct Message *)RXMsg);
		}
		else
		{
			CauseIoErr(ERROR_NO_FREE_STORE,NULL);
			ErrOccured=TRUE;
		}
	}
	/* HI */
	if(Options[OPT_HI])
	{
		bset(RexxSysBase->rl_Flags,RLFB_HALT);
		Signal(Port->mp_SigTask,flag(Port->mp_SigBit));
	}
	/* Suspend/Resume */
	if(Options[OPT_SUSPEND])
	{
		bset(RexxSysBase->rl_Flags,RLFB_SUSP);
		Signal(Port->mp_SigTask,flag(Port->mp_SigBit));
	}
	if(Options[OPT_RESUME])
	{
		bclr(RexxSysBase->rl_Flags,RLFB_SUSP);
		Signal(Port->mp_SigTask,flag(Port->mp_SigBit));
	}
	/* TE/TS */
	if(Options[OPT_TE])
		bclr(RexxSysBase->rl_Flags,RLFB_TRACE);
	if(Options[OPT_TS])
		bset(RexxSysBase->rl_Flags,RLFB_TRACE);
	/* TCO/TCC */
	if(Options[OPT_TCO])
	{
		if(RXMsg=CreateRexxMsg(NULL,NULL,NULL))
		{
			RXMsg->rm_Action=RXTCOPN | RXFF_NONRET;
			PutMsg(Port,(struct Message *)RXMsg);
		}
		else
		{
			CauseIoErr(ERROR_NO_FREE_STORE,NULL);
			ErrOccured=TRUE;
		}
	}
	if(Options[OPT_TCC])
	{
		if(RXMsg=CreateRexxMsg(NULL,NULL,NULL))
		{
			RXMsg->rm_Action=RXTCCLS | RXFF_NONRET;
			PutMsg(Port,(struct Message *)RXMsg);
		}
		else
		{
			CauseIoErr(ERROR_NO_FREE_STORE,NULL);
			ErrOccured=TRUE;
		}
	}
	Permit();

	unless(Options[OPT_QUIET])
	{
		Printf("ARexx state:\n"
						"\tTracing is %s\n"
						"\tTrace console is %s\n%s%s",
						btst(RexxSysBase->rl_Flags,RLFB_TRACE) ? ON : OFF,
						RexxSysBase->rl_TraceFH ? OPEN : CLOSED,
						btst(RexxSysBase->rl_Flags,RLFB_SUSP) ?
							"\t" IS_SUSPENDED : NULL,
						btst(RexxSysBase->rl_Flags,RLFB_CLOSE) ?
							"\t" WILL_CLOSE : NULL);
	}

	RC=(ErrOccured ? RETURN_ERROR : RETURN_OK);

NotActive:
	FreeArgs(Args);
NoArgs:
	CloseLibrary((struct Library *)RexxSysBase);
InvalidREXX:
	return(RC);
}

/* Workbench mode work */
ULONG WBMode(struct ExecBase *SysBase, struct DosLibrary *DOSBase)
{
	struct IntuitionBase *IntuitionBase;
	struct RxsLib *RexxSysBase;
	struct Library *IconBase;

	STATIC CONST struct EasyStruct NoLibReq=
	{
		sizeof(struct EasyStruct),0,
		RXCONTROL_NAME REQUEST_MSG,
		UNABLE_OPEN,
		OK
	};
	STATIC CONST struct EasyStruct NotActiveReq=
	{
		sizeof(struct EasyStruct),0,
		RXCONTROL_NAME REQUEST_MSG,
		NOT_ACTIVE,
		OK
	};
	STATIC CONST struct EasyStruct InfoReq=
	{
		sizeof(struct EasyStruct),0,
		RXCONTROL_NAME INFO_MSG,
		"ARexx state:\n"
			SPC_TAB "Tracing is %s\n"
			SPC_TAB "Trace console is %s\n%s%s",
		OK
	};
	STATIC CONST struct Switch Switches[]=
	{
		{"CANCEL",OPT_RXC},			{"RXC",OPT_RXC},
		{"HALT",OPT_HI},				{"HI",OPT_HI},
		{"SUSPEND",OPT_SUSPEND},
		{"RESUME",OPT_RESUME},
		{"TRACESTART",OPT_TS},	{"TS",OPT_TS},
		{"TRACEEND",OPT_TE},		{"TE",OPT_TE},
		{"CONOPEN",OPT_TCO},		{"TCO",OPT_TCO},
		{"CONCLOSE",OPT_TCC},		{"TCC",OPT_TCC},
		{"QUIET",OPT_QUIET}
	};

	struct WBArg *Args;
	struct MsgPort *Port;
	struct RexxMsg *RXMsg;
	struct WBStartup *WBMsg;
	struct DiskObject *Object;
	STRPTR *ToolArray;
	BPTR OldDir;
	LONG Options[OPT_COUNT];
	ULONG I,J,RC=RETURN_FAIL;
	BOOL ErrOccured=FALSE;

	WaitPort(&ThisProcessS->pr_MsgPort);
	WBMsg=(struct WBStartup *)GetMsg(&ThisProcessS->pr_MsgPort);
	unless(IntuitionBase=
					(struct IntuitionBase *)OpenLibrary(INTUI_NAME,INTUI_VERN))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidIntuition;
	}
	unless(IconBase=OpenLibrary(ICON_NAME,ICON_VERN))
	{
		EasyRequest(NULL,&NoLibReq,NULL,ICON_NAME);
		goto InvalidIcon;
	}
	unless(RexxSysBase=(struct RxsLib *)OpenLibrary(REXX_NAME,REXX_VERN))
	{
		EasyRequest(NULL,&NoLibReq,NULL,REXX_NAME);
		goto InvalidREXX;
	}

	clear(&Options);										/* Clear options buffer */
	for(I=0, Args=WBMsg->sm_ArgList; I<WBMsg->sm_NumArgs; I++, Args++)
	{
		if(Args->wa_Lock && *Args->wa_Name)
		{
			OldDir=CurrentDir(Args->wa_Lock);
			if(*Args->wa_Name && (Object=GetDiskObject(Args->wa_Name)))
			{
				ToolArray=(STRPTR *)Object->do_ToolTypes;
				for(J=0; J<sizeof(Switches)/sizeof(struct Switch); J++)
					if(FindToolType(ToolArray,Switches[J].sw_Name))
						Options[Switches[J].sw_Index]=TRUE;
				FreeDiskObject(Object);
			}
			CurrentDir(OldDir);							/* CD back */
		}
	}

	/* Check for REXX port */
	Forbid();
	unless(Port=FindPort(RXPORT_NAME))
	{
		Permit();
		EasyRequest(NULL,&NotActiveReq,NULL);
		goto NotActive;
	}
	/* RXC */
	if(Options[OPT_RXC])
	{
		if(RXMsg=CreateRexxMsg(NULL,NULL,NULL))
		{
			RXMsg->rm_Action=RXCLOSE | RXFF_NONRET;
			PutMsg(Port,(struct Message *)RXMsg);
		}
		else
			ErrOccured=TRUE;
	}
	/* HI */
	if(Options[OPT_HI])
	{
		bset(RexxSysBase->rl_Flags,RLFB_HALT);
		Signal(Port->mp_SigTask,flag(Port->mp_SigBit));
	}
	/* Suspend/Resume */
	if(Options[OPT_SUSPEND])
	{
		bset(RexxSysBase->rl_Flags,RLFB_SUSP);
		Signal(Port->mp_SigTask,flag(Port->mp_SigBit));
	}
	if(Options[OPT_RESUME])
	{
		bclr(RexxSysBase->rl_Flags,RLFB_SUSP);
		Signal(Port->mp_SigTask,flag(Port->mp_SigBit));
	}
	/* TE/TS */
	if(Options[OPT_TE])
		bclr(RexxSysBase->rl_Flags,RLFB_TRACE);
	if(Options[OPT_TS])
		bset(RexxSysBase->rl_Flags,RLFB_TRACE);
	/* TCO/TCC */
	if(Options[OPT_TCO])
	{
		if(RXMsg=CreateRexxMsg(NULL,NULL,NULL))
		{
			RXMsg->rm_Action=RXTCOPN | RXFF_NONRET;
			PutMsg(Port,(struct Message *)RXMsg);
		}
		else
			ErrOccured=TRUE;
	}
	if(Options[OPT_TCC])
	{
		if(RXMsg=CreateRexxMsg(NULL,NULL,NULL))
		{
			RXMsg->rm_Action=RXTCCLS | RXFF_NONRET;
			PutMsg(Port,(struct Message *)RXMsg);
		}
		else
			ErrOccured=TRUE;
	}
	Permit();

	unless(Options[OPT_QUIET])
	{
		EasyRequest(NULL,&InfoReq,NULL,
								btst(RexxSysBase->rl_Flags,RLFB_TRACE) ? ON : OFF,
								RexxSysBase->rl_TraceFH ? OPEN : CLOSED,
								btst(RexxSysBase->rl_Flags,RLFB_SUSP) ?
									SPC_TAB IS_SUSPENDED : NULL,
								btst(RexxSysBase->rl_Flags,RLFB_CLOSE) ?
									SPC_TAB WILL_CLOSE : NULL);
	}

	RC=(ErrOccured ? RETURN_ERROR : RETURN_OK);

NotActive:
NoArgs:
	CloseLibrary((struct Library *)RexxSysBase);
InvalidREXX:
	CloseLibrary(IconBase);
InvalidIcon:
	CloseLibrary((struct Library *)IntuitionBase);
InvalidIntuition:
	ReplyMsg((struct Message *)WBMsg);
	return(RC);
}
