/****************************************************************************/
/*            clickstart.c - enable/disbale features of AmigaDOS            */
/*                    Copyright © 1994 Michael Letowski                     */
/****************************************************************************/

#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/execbase.h>
#include <dos/rdargs.h>
#include <dos/dosextens.h>
#include <dos/var.h>
#include <devices/trackdisk.h>
#include <support/types.h>
#include <support/exec.h>

#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>

#include "clickstart.rev.h"

#define DOS_NAME		"dos.library"
#define DOS_VERN		37L
#define TRACK_NAME	"trackdisk.device"

#define TEMPLATE		"CLICK/S,NOCLICK/S,STAR/S,NOSTAR/S,PIPE/K,NOPIPE/S,"\
										"MULTI/K,NOMULTI/S,ALERT/K/N,QUIET/S"

#define OPT_CLICK		0
#define OPT_NOCLICK	1
#define OPT_STAR		2
#define OPT_NOSTAR	3
#define OPT_PIPE		4
#define OPT_NOPIPE	5
#define OPT_MULTI		6
#define OPT_NOMULTI	7
#define OPT_ALERT		8
#define OPT_QUIET		9
#define OPT_COUNT		10

#define STATE_CLICK	0
#define STATE_STAR	1
#define STATE_PIPE	2
#define STATE_MULTI	3
#define STATE_ALERT	4
#define STATE_COUNT	5

/* Pipe enable/disable */
#define PIPE_VAR_NAME		"_pchar"

/* Multi command enable/disable */
#define MULTI_VAR_NAME	"_mchar"

#define VAR_PIPE				0
#define VAR_MULTI				1
#define VAR_COUNT				2

#define VAR_LEN					1
#define VAR_FLAGS				(LV_VAR | GVF_LOCAL_ONLY)
#define VAR_SIZE				(VAR_LEN+3)

#define QUOTES					(('\''<<24) | ('\''<<8))

/* Default pipe and multi characters */
#define DEF_PIPE				"|"
#define DEF_MULTI				"\\"

/* On/off texts */
#define ON							"ON"
#define OFF							"OFF"
#define UNKNOWN					"?"

#define PStr(arg,def)		(*(arg)=='\0' ? (def) : (arg))
#define AlTime(time)		((time)>0 ? (time) : 0)

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

STATIC LONG HandleVar(STRPTR varName, STRPTR varVal, STRPTR defVal, LONG off,
											BOOL *error, STRPTR result, struct DosLibrary *DOSBase);

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

	struct RDArgs *Args;
	struct MsgPort *Port;
	struct IOExtTD *IO;
	UBYTE *PubFlags;
	LONG *DOSFlags;
	LONG Options[OPT_COUNT];
	ULONG Unit,RC=RETURN_FAIL;
	STRPTR States[STATE_COUNT];
	CHAR PipeVal[VAR_SIZE],MultiVal[VAR_SIZE];
	BOOL ErrOccured=TRUE;

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

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

	/* Handle clicking */
	States[STATE_CLICK]=UNKNOWN;
	if(Port=CreateMsgPort())
	{
		if(IO=CreateIORequest(Port,sizeof(struct IOExtTD)))
		{
			ErrOccured=FALSE;								/* Everything OK so far */
			for(Unit=0; Unit<4; Unit++)
			{
				if(OpenDevice(TRACK_NAME,Unit,(struct IORequest *)IO,0)==0)
				{
					PubFlags=&((struct TDU_PublicUnit *)IO->iotd_Req.io_Unit)->tdu_PubFlags;
					if(Options[OPT_CLICK])
						fclr(*PubFlags,TDPF_NOCLICK);
					if(Options[OPT_NOCLICK])
						fset(*PubFlags,TDPF_NOCLICK);
					States[STATE_CLICK]=ftst(*PubFlags,TDPF_NOCLICK) ? OFF : ON;
					CloseDevice((struct IORequest *)IO);
				}
			}
			DeleteIORequest(IO);
		}
		DeleteMsgPort(Port);
	}

	/* Wildstar */
	DOSFlags=&DOSBase->dl_Root->rn_Flags;
	if(Options[OPT_STAR])														/* Enable */
		fset(*DOSFlags,RNF_WILDSTAR);
	if(Options[OPT_NOSTAR])													/* Disable */
		fclr(*DOSFlags,RNF_WILDSTAR);
	if(ftst(*DOSFlags,RNF_WILDSTAR))
		States[STATE_STAR]=ON;
	else
		States[STATE_STAR]=OFF;

	/* Piping */
	if(HandleVar(PIPE_VAR_NAME,(STRPTR)Options[OPT_PIPE],DEF_PIPE,
								Options[OPT_NOPIPE],&ErrOccured,PipeVal,DOSBase))
		States[STATE_PIPE]=PipeVal;
	else
		States[STATE_PIPE]=OFF;

	/* Multi command execution */
	if(HandleVar(MULTI_VAR_NAME,(STRPTR)Options[OPT_MULTI],DEF_MULTI,
								Options[OPT_NOMULTI],&ErrOccured,MultiVal,DOSBase))
		States[STATE_MULTI]=MultiVal;
	else
		States[STATE_MULTI]=OFF;

	/* Alerts timing */
	if(Options[OPT_ALERT])
		SysBase->LastAlert[3]=AlTime(*((LONG *)Options[OPT_ALERT]));
	States[STATE_ALERT]=(STRPTR)SysBase->LastAlert[3];

	unless(Options[OPT_QUIET])
		VPrintf("System state:\n"
						"\tDrive click is %s\n"
						"\tStar is %s\n"
						"\tPipe char is %s\n"
						"\tMulti command char is %s\n"
						"\tAlert lasts %lu frames\n",(LONG *)States);

	RC=(ErrOccured ? RETURN_ERROR : RETURN_OK);

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

STATIC LONG HandleVar(STRPTR varName, STRPTR varVal, STRPTR defVal, LONG off,
											BOOL *error, STRPTR result, struct DosLibrary *DOSBase)
{
	struct LocalVar *Var;

	if(varVal)
		unless(SetVar(varName,PStr(varVal,defVal),VAR_LEN,VAR_FLAGS))
		{
			PrintFault(IoErr(),varName);
			*error=TRUE;
		}
	if(off)
		unless(DeleteVar(varName,VAR_FLAGS))
		{
			PrintFault(IoErr(),varName);
			*error=TRUE;
		}
	if(Var=FindVar(varName,VAR_FLAGS))
	{
		result[0]='\'';
		result[1]=*(Var->lv_Value);
		result[2]='\'';
		result[3]='\0';
	}
	return((LONG)Var);															/* Check current state */
}
