/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1991 by Olaf 'Olsen' Barthel & MXM
 *
 *	Name .....: TermRexx.c
 *	Created ..: Monday 21-Jan-91 20:12
 *	Revision .: 2
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	24-Mar-91       Olsen           Added some more commands.
 *	26-Jan-91       Olsen           Added asynchronous RexxMsg parsing.
 *	21-Jan-91       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

#include "TermGlobal.h"

	/* This module contains the ARexx support code I had adapted some
	 * time ago for rexxhost.library.
	 */

struct RexxMsg	*CreateRexxMsg(struct MsgPort *,STRPTR,STRPTR);
VOID		 DeleteRexxMsg(struct RexxMsg *);
STRPTR		 CreateArgstring(STRPTR,LONG);
VOID		 DeleteArgstring(STRPTR);

#pragma libcall RexxSysBase CreateArgstring 7e 802
#pragma libcall RexxSysBase DeleteArgstring 84 801
#pragma libcall RexxSysBase CreateRexxMsg 90 9803
#pragma libcall RexxSysBase DeleteRexxMsg 96 801

	/* The rexx server commands are contained in lists in which
	 * each command name and the approriate routine is
	 * stored. The following three structure definitions
	 * are required to set up the list properly.
	 */

struct QueryStruct
{
	UBYTE	*String;
	UBYTE *	(*Routine)(VOID);
};

struct ASyncCommandStruct
{
	UBYTE	*String;
	VOID	(*Routine)(VOID);
};

struct CommandStruct
{
	UBYTE	*String;
	UBYTE *	(*Routine)(UBYTE *);
};

	/* Global rexx output buffer. */

STATIC UBYTE RexxTextBuffer[256];

	/* This structure defines a relation between a time unit
	 * (microseconds, seconds, minutes) and a string key.
	 */

struct TimeRel
{
	UBYTE	*Key;
	LONG	 Multi;
};

	/* Relations between qualifying keywords and time multipliers. */

#define NUMTIMEREL 9

STATIC struct TimeRel TimeRelations[NUMTIMEREL] =
{
	"MIC",		1,
	"SEC",		MILLION,
	"MIN",		MILLION * 60,

	"MICROSECONDS",	1,
	"SECONDS",	MILLION,
	"MINUTES",	MILLION * 60,

	"MICROS",	1,
	"SECS",		MILLION,
	"MINS",		MILLION * 60
};

	/* Asynchronous commands which can be executed by the
	 * rexx server process itself and do not require the
	 * term main process to take any action.
	 */

#define NUMASYNCS 9

STATIC struct ASyncCommandStruct ASyncCommands[NUMASYNCS] =
{
	"TERM2FRONT",		(APTR)Term2Front,
	"DEFAULT2FRONT",	(APTR)BumpDefault,
	"WB2FRONT",		(APTR)WBenchToFront,
	"REXX2FRONT",		(APTR)Rexx2Front,
	"DISPLAY2FRONT",	(APTR)Display2Front,
	"CLOSEDISPLAY",		(APTR)CloseDisplay,
	"CLEARDISPLAY",		(APTR)ClearBuffer,
	"CLEARDOWNLOADLIST",	(APTR)ClearDownloadObjects,
	"QUIETEXIT",		(APTR)QuietExit
};

	/* Query commands which return miscellaneous system
	 * information (these routines are handled asynchronously
	 * as well).
	 */

#define NUMQUERIES 81

STATIC struct QueryStruct QueryCommands[NUMQUERIES] =
{
	"BAUDRATE",		(APTR)QueryBaud,
	"BITSPERCHAR",		(APTR)QueryDataBits,
	"PARITY",		(APTR)QueryParity,
	"STOPBITS",		(APTR)QueryStopBits,
	"HANDSHAKING",		(APTR)QueryHandshaking,
	"DUPLEX",		(APTR)QueryDuplex,
	"HIGHSPEED",		(APTR)QueryHighspeed,
	"BREAKLENGTH",		(APTR)QueryBreakLength,
	"SERIALDEVICE",		(APTR)QuerySerialDevice,
	"UNITNUMBER",		(APTR)QueryUnitNumber,
	"MODEMINIT",		(APTR)QueryModemInit,
	"MODEMEXIT",		(APTR)QueryModemExit,
	"DIALPREFIX",		(APTR)QueryDialPrefix,
	"REDIALDELAY",		(APTR)QueryRedialDelay,
	"DIALRETRIES",		(APTR)QueryDialRetries,
	"DIALTIMEOUT",		(APTR)QueryDialTimeout,
	"CONNECTAUTOBAUD",	(APTR)QueryConnectAutoBaud,
	"NOCARRIER",		(APTR)QueryNoCarrier,
	"CONNECT",		(APTR)QueryConnect,
	"VOICE",		(APTR)QueryVoice,
	"RING",			(APTR)QueryRing,
	"BUSY",			(APTR)QueryBusy,
	"PROTOCOL",		(APTR)QueryProtocol,
	"PROTOCOLOPTIONS",	(APTR)QueryProtocolOptions,
	"MACROFILE",		(APTR)QueryMacroFile,
	"DISPLAYMODE",		(APTR)QueryDisplay,
	"PUBLICSCREEN",		(APTR)QueryPublicScreen,
	"SHANGHAI",		(APTR)QueryShanghai,
	"CAPTUREFILTER",	(APTR)QueryCaptureFilter,
	"DSBACKSPACE",		(APTR)QueryDSBackSpace,
	"AUDBELL",		(APTR)QueryAudBell,
	"VISBELL",		(APTR)QueryVisBell,
	"EIGHTYCOLUMNS",	(APTR)QueryEightyColumns,
	"SENDCR",		(APTR)QuerySendCR,
	"SENDLF",		(APTR)QuerySendLF,
	"COLOURMODE",		(APTR)QueryColourMode,
	"COLORMODE",		(APTR)QueryColourMode,
	"EMULATION",		(APTR)QueryEmulation,
	"FONT",			(APTR)QueryFont,
	"STATUS",		(APTR)QueryStatus,
	"SERIAL",		(APTR)QuerySerial,
	"STARTUP",		(APTR)QueryStartup,
	"REQUESTERS",		(APTR)QueryRequesters,
	"TIMEOUT",		(APTR)QueryTimeout,
	"LINE",			(APTR)QueryLine,
	"COLUMNS",		(APTR)QueryColumns,
	"LINES",		(APTR)QueryLines,
	"CURSOR",		(APTR)QueryCursor,

	/* Added in revision 1.6 */

	"MODEMHANGUP",		(APTR)QueryModemHangup,
	"AUTOCAPTURE",		(APTR)QueryAutoCapture,
	"LOGACTIONS",		(APTR)QueryLogActions,
	"BLINKING",		(APTR)QueryBlinking,
	"CURSORMODE",		(APTR)QueryCursorMode,
	"FONTSCALE",		(APTR)QueryFontScale,
	"SMOOTHSCROLL",		(APTR)QueryJumpScroll,
	"CHARACTERWRAP",	(APTR)QueryCharacterWrap,
	"CURSORWRAP",		(APTR)QueryCursorWrap,
	"NEWLINEMODE",		(APTR)QueryNewLine,
	"INSERTMODE",		(APTR)QueryInsert,
	"NUMERICMODE",		(APTR)QueryNumeric,
	"DEFAULTSTORE",		(APTR)QueryDefaultStore,
	"TUPLOADPATH",		(APTR)QueryTUploadPath,
	"TDOWNLOADPATH",	(APTR)QueryTDownloadPath,
	"AUPLOADPATH",		(APTR)QueryAUploadPath,
	"ADOWNLOADPATH",	(APTR)QueryADownloadPath,
	"BUPLOADPATH",		(APTR)QueryBUploadPath,
	"BDOWNLOADPATH",	(APTR)QueryBDownloadPath,
	"CAPTUREPATH",		(APTR)QueryCapturePath,
	"LOGFILE",		(APTR)QueryLogFile,
	"EDITOR",		(APTR)QueryEditor,
	"BEEPSOUND",		(APTR)QueryBeepSound,
	"CAPTURESTATE",		(APTR)QueryCaptureState,
	"DOWNLOADS",		(APTR)QueryDownloads,

	/* Added in revision 1.8b */

	"SPEECHFILE",		(APTR)QuerySpeechFile,
	"SCREENADDRESS",	(APTR)QueryScreenAddress,
	"SPEECHRATE",		(APTR)QuerySpeechRate,
	"SPEECHPITCH",		(APTR)QuerySpeechPitch,
	"SPEECHFREQUENCY",	(APTR)QuerySpeechFrequency,
	"SPEECHVOLUME",		(APTR)QuerySpeechVolume,
	"SPEECHSEX",		(APTR)QuerySpeechSex,
	"SPEECH",		(APTR)QuerySpeech
};

	/* Any options which are to be set using the `SET' command
	 * are stored in the following list (these commands are
	 * handled synchronously).
	 */

#define NUMSETS		71

	/* How many set commands require more parameters? */

#define SETMOREPARAMS	6

STATIC struct CommandStruct SetCommands[NUMSETS] =
{
	/* The first five commands require more than
	 * one calling parameter and are handled
	 * differently (as compared to the other
	 * set commands).
	 */

	"MACRO",		(APTR)RexxSetMacro,
	"COLOUR",		(APTR)RexxSetColour,
	"COLOR",		(APTR)RexxSetColour,
	"SCREEN",		(APTR)RexxSetScreen,
	"BELL",			(APTR)RexxSetBell,
	"TIMEOUT",		(APTR)RexxSetTimeout,

	"BAUDRATE",		(APTR)RexxSetBaud,
	"BITSPERCHAR",		(APTR)RexxSetDataBits,
	"PARITY",		(APTR)RexxSetParity,
	"STOPBITS",		(APTR)RexxSetStopBits,
	"HANDSHAKING",		(APTR)RexxSetHandshaking,
	"DUPLEX",		(APTR)RexxSetDuplex,
	"HIGHSPEED",		(APTR)RexxSetHighSpeed,
	"BREAKLENGTH",		(APTR)RexxSetBreakLength,
	"SERIALDEVICE",		(APTR)RexxSetSerialDevice,
	"UNITNUMBER",		(APTR)RexxSetUnitNumber,
	"MODEMINIT",		(APTR)RexxSetModemInit,
	"MODEMEXIT",		(APTR)RexxSetModemExit,
	"DIALPREFIX",		(APTR)RexxSetDialPrefix,
	"REDIALDELAY",		(APTR)RexxSetRedialDelay,
	"DIALRETRIES",		(APTR)RexxSetDialRetries,
	"DIALTIMEOUT",		(APTR)RexxSetDialTimeout,
	"CONNECTAUTOBAUD",	(APTR)RexxSetConnectAutoBaud,
	"NOCARRIER",		(APTR)RexxSetNoCarrier,
	"CONNECT",		(APTR)RexxSetConnect,
	"VOICE",		(APTR)RexxSetVoice,
	"RING",			(APTR)RexxSetRing,
	"BUSY",			(APTR)RexxSetBusy,
	"SCREENMODE",		(APTR)RexxSetScreenMode,
	"FILTER",		(APTR)RexxSetFilter,
	"BACKSPACE",		(APTR)RexxSetBackspace,
	"CR",			(APTR)RexxSetCR,
	"LF",			(APTR)RexxSetLF,
	"EIGHTYCOLUMNS",	(APTR)RexxSet80Columns,
	"COLOURMODE",		(APTR)RexxSetColourMode,
	"COLORMODE",		(APTR)RexxSetColourMode,
	"EMULATION",		(APTR)RexxSetEmulation,
	"FONT",			(APTR)RexxSetFont,
	"STARTUP",		(APTR)RexxSetStartup,
	"PROTOCOL",		(APTR)RexxSetProtocol,
	"PROTOCOLOPTIONS",	(APTR)RexxSetProtocolOptions,
	"REQUESTERS",		(APTR)RexxSetRequesters,
	"SERIAL",		(APTR)RexxSetSerial,

	/* Added in revision 1.6 */

	"MODEMHANGUP",		(APTR)RexxSetModemHangup,
	"AUTOCAPTURE",		(APTR)RexxSetAutoCapture,
	"LOGACTIONS",		(APTR)RexxSetLogActions,
	"BLINKING",		(APTR)RexxSetBlinking,
	"CURSORMODE",		(APTR)RexxSetCursorMode,
	"FONTSCALE",		(APTR)RexxSetFontScale,
	"SMOOTHSCROLL",		(APTR)RexxSetJumpScroll,
	"CHARACTERWRAP",	(APTR)RexxSetCharacterWrap,
	"CURSORWRAP",		(APTR)RexxSetCursorWrap,
	"NEWLINEMODE",		(APTR)RexxSetNewLine,
	"INSERTMODE",		(APTR)RexxSetInsert,
	"NUMERICMODE",		(APTR)RexxSetNumeric,
	"DEFAULTSTORE",		(APTR)RexxSetDefaultStore,
	"TUPLOADPATH",		(APTR)RexxSetTUploadPath,
	"TDOWNLOADPATH",	(APTR)RexxSetTDownloadPath,
	"AUPLOADPATH",		(APTR)RexxSetAUploadPath,
	"ADOWNLOADPATH",	(APTR)RexxSetADownloadPath,
	"BUPLOADPATH",		(APTR)RexxSetBUploadPath,
	"BDOWNLOADPATH",	(APTR)RexxSetBDownloadPath,
	"CAPTUREPATH",		(APTR)RexxSetCapturePath,
	"LOGFILE",		(APTR)RexxSetLogFile,
	"EDITOR",		(APTR)RexxSetEditor,

	/* Added in revision 1.8b */

	"SPEECHRATE",		(APTR)RexxSetSpeechRate,
	"SPEECHPITCH",		(APTR)RexxSetSpeechPitch,
	"SPEECHFREQUENCY",	(APTR)RexxSetSpeechFrequency,
	"SPEECHVOLUME",		(APTR)RexxSetSpeechVolume,
	"SPEECHSEX",		(APTR)RexxSetSpeechSex,
	"SPEECH",		(APTR)RexxSetSpeech
};

	/* The following list contains only synchronous commands
	 * the rexx server passes to the term main process.
	 */

#define NUMREXX		35

	/* How many commands require more parameters. */

#define REXXMOREPARAMS	8

struct CommandStruct RexxCommands[NUMREXX] =
{
	/* The first five commands require more than
	 * one calling parameter.
	 */

	"BUFFER",		(APTR)RexxBuffer,
	"CAPTURE",		(APTR)RexxCapture,
	"CONFIG",		(APTR)RexxConfig,
	"MACROS",		(APTR)RexxMacros,
	"SPEECH",		(APTR)RexxSpeech,
	"PHONE",		(APTR)RexxPhone,
	"DELAY",		(APTR)RexxDelay,
	"WAITSTRING",		(APTR)RexxWaitString,

	"PRINTER",		(APTR)RexxPrinter,
	"BEEP",			(APTR)DoSomeBeep,
	"BREAK",		(APTR)RexxBreak,
	"BUPLOAD",		(APTR)RexxBUpload,
	"BDOWNLOAD",		(APTR)RexxBDownload,
	"CLEARSCREEN",		(APTR)RexxClearScreen,
	"COMMAND",		(APTR)RexxCommand,
	"DIAL",			(APTR)RexxDial,
	"GETSTRING",		(APTR)RexxGetString,
	"HANGUP",		(APTR)RexxHangUp,
	"INPUT",		(APTR)RexxInput,
	"MESSAGE",		(APTR)RexxMessage,
	"RESETSTYLES",		(APTR)RexxResetStyles,
	"SAVEILBM",		(APTR)RexxSaveILBM,
	"TUPLOAD",		(APTR)RexxTUpload,
	"TDOWNLOAD",		(APTR)RexxTDownload,
	"WRITE",		(APTR)RexxWrite,
	"PUTCLIP",		(APTR)RexxPutClip,
	"GETCLIP",		(APTR)RexxGetClip,

	/* Added in revision 1.6 */

	"FIRSTDOWNLOAD",	(APTR)RexxFirstDownload,
	"NEXTDOWNLOAD",		(APTR)RexxNextDownload,
	"LASTDOWNLOAD",		(APTR)RexxLastDownload,

	/* Added in revision 1.8a */

	"TONEDIAL",		(APTR)RexxToneDial,

	/* Added in revision 1.8b */

	"SIMPLEREQUEST",	(APTR)RexxSimpleRequest,
	"TWOGADREQUEST",	(APTR)RexxTwoGadRequest,
	"FILEREQUEST",		(APTR)RexxFileRequest,

	"SPEAK",		(APTR)RexxSpeak
};

	/* A global error code and a global input timeout. */

STATIC LONG RexxRes1,RexxGlobalTimeout;

	/* The names of the 16 display mode IDs in abbreviated
	 * form.
	 */

STATIC UBYTE *ConfigDisplayNames[16] =
{
	"HIRES",
	"HIRESLACE",
	"SUPERHIRES",
	"SUPERHIRESLACE",
	"PRODUCT",
	"PRODUCTLACE",

	"PALHIRES",
	"PALHIRESLACE",
	"PALSUPERHIRES",
	"PALSUPERHIRESLACE",

	"NTSCHIRES",
	"NTSCHIRESLACE",
	"NTSCSUPERHIRES",
	"NTSCSUPERHIRESLACE",

	"A2024TENHZ",
	"A2024FIFTEENHZ"
};

	/* The global duplex modes in abbreviated form. */

STATIC UBYTE *ConfigDuplex[2] =
{
	"FULL",
	"HALF"
};

	/* The global handshake modes in abbreviated form. */

STATIC UBYTE *ConfigHandshaking[3] =
{
	"XONOFF",
	"RTSCTS",
	"NONE"
};

	/* The global fonts in abbreviated form. */

STATIC UBYTE *ConfigFont[2] =
{
	"TOPAZ",
	"IBM"
};

	/* The global colour modes in abbreviated form. */

STATIC UBYTE *ConfigColour[4] =
{
	"AMIGA",
	"EIGHT",
	"SIXTEEN",
	"MONO"
};

	/* The emulation types in abbreviated form. */

STATIC UBYTE *ConfigEmulation[3] =
{
	"ANSIVT",
	"ATOMIC",
	"TTY"
};

	/* The global parity settings in abbreviated form. */

STATIC UBYTE *ConfigParity[5] =
{
	"NONE",
	"EVEN",
	"ODD",
	"MARK",
	"SPACE"
};

	/* The global term status modes in abbreviated form. */

STATIC UBYTE *ConfigStatus[7] =
{
	"READY",
	"HOLDING",
	"DIALING",
	"UPLOAD",
	"DOWNLOAD",
	"BREAKING",
	"HANGUP"
};

	/* Two boolean identifiers. */

STATIC UBYTE *Booleans[2] =
{
	"OFF",
	"ON"
};

STATIC UBYTE *KeyModes[2] =
{
	"STANDARD",
	"APPLICATION"
};

STATIC UBYTE *FontSizes[5] =
{
	"NORMAL",
	"HIGHTOP",
	"HIGHBOTTOM",
	"WIDE",
	"HALF"
};

STATIC UBYTE *Qualifiers[4] =
{
	"NONE",
	"SHIFT",
	"ALTERNATE",
	"CONTROL"
};

	/* SendRexxCommand():
	 *
	 *	Post a command to an ARexx port.
	 */

BYTE
SendRexxCommand(struct MsgPort *HostPort,STRPTR CommandString,STRPTR FileExtension,STRPTR HostName)
{
	struct MsgPort	*RexxPort = (struct MsgPort *)FindPort(RXSDIR);
	struct RexxMsg	*HostMessage;

	if(RexxPort)
	{
		if(!HostName)
			HostName = (STRPTR)"";

		if(!FileExtension)
			FileExtension = (STRPTR)"";

		if(HostMessage = CreateRexxMsg((struct MsgPort *)HostPort,FileExtension,HostName))
		{
			if(HostMessage -> rm_Args[0] = CreateArgstring(CommandString,strlen(CommandString)))
			{
				HostMessage -> rm_Action = RXCOMM;

				PutMsg(RexxPort,HostMessage);

				return(TRUE);
			}

			DeleteRexxMsg(HostMessage);
		}

		MyEasyRequest(Window,"`term' has a problem:\nCouldn't send rexx message!","Continue");

		return(FALSE);
	}
	else
		MyEasyRequest(Window,"`term' has a problem:\nThe ARexx server isn't running!","Continue");
}

	/* FreeRexxCommand(struct RexxMsg *RexxMessage):
	 *
	 *	Free the contents of a RexxMsg.
	 */

VOID
FreeRexxCommand(struct RexxMsg *RexxMessage)
{
	if(RexxMessage -> rm_Args[0])
		DeleteArgstring(RexxMessage -> rm_Args[0]);

	DeleteRexxMsg(RexxMessage);
}

	/* ReplyRexxCommand():
	 *
	 *	Reply a command request the rexx server - or someone else -
	 *	has passed to us.
	 */

VOID
ReplyRexxCommand(struct RexxMsg *RexxMessage,LONG Primary,LONG Secondary,STRPTR Result)
{
	if(Secondary == NULL && (RexxMessage -> rm_Action & RXFF_RESULT))
	{
		if(Result)
		{
			if(Result[0])
				Secondary = (LONG)CreateArgstring(Result,strlen(Result));
		}
	}

	RexxMessage -> rm_Result1 = Primary;
	RexxMessage -> rm_Result2 = Secondary;

	ReplyMsg(RexxMessage);
}

	/* IsSpace(UBYTE c):
	 *
	 *	Return if the character passed to this routine is some
	 *	kind of blank space.
	 */

STATIC BYTE
IsSpace(UBYTE c)
{
	if((c >= 13 && c <= 17) || c == 32)
		return(TRUE);
	else
		return(FALSE);
}

	/* GetToken():
	 *
	 *	Parse a string for a token (typically used for
	 *	rexx message parsing).
	 */

STRPTR
GetToken(STRPTR String,LONG *StartChar,STRPTR AuxBuff,LONG MaxLength)
{
	WORD	i,StrEnd = 0,MaxPos = strlen(String);
	BYTE	Filter = FALSE;
	UBYTE	Brace = 0;

	if(MaxPos >= MaxLength + *StartChar)
		MaxPos = MaxLength + *StartChar - 1;

	if(*StartChar <= strlen(String) - 1 && String && String[0] && AuxBuff && MaxLength)
	{
		for(i = *StartChar ; i <= MaxPos ; i++)
		{
			if(!Filter)
			{
				if(!StrEnd && IsSpace(String[i]))
				{
					while(IsSpace(String[i]) && i < MaxPos)
					{
						i++;

						(*StartChar)++;
					}
				}
			}

			if((!Filter && IsSpace(String[i])) || String[i] == 0)
			{
				strncpy(AuxBuff,(String + *StartChar),StrEnd);
				AuxBuff[StrEnd] = 0;

				(*StartChar) += StrEnd;

				return(AuxBuff);
			}

			if(String[i] == '\'' || String[i] == '\"')
			{
				if(!Filter)
				{
					Brace = String[i];

					Filter = TRUE;
				}
				else
				{
					if(String[i] == Brace)
						Filter = FALSE;
				}
			}

			StrEnd++;
		}
	}

	return(NULL);
}

	/* A bunch of single rexx server routines is to follow.
	 * Since there are pretty much of subroutines, I didn't
	 * necessarily make a comment on any (figure out yourself
	 * how they work :-)
	 */

UBYTE *
QueryBaud()
{
	SPrintf(RexxTextBuffer,"%ld",Config . BaudRate);

	return(RexxTextBuffer);
}

UBYTE *
QueryDataBits()
{
	SPrintf(RexxTextBuffer,"%ld",Config . BitsPerChar);

	return(RexxTextBuffer);
}

UBYTE *
QueryParity()
{
	return(ConfigParity[Config . Parity]);
}

UBYTE *
QueryStopBits()
{
	SPrintf(RexxTextBuffer,"%ld",Config . StopBits);

	return(RexxTextBuffer);
}

UBYTE *
QueryHandshaking()
{
	return(ConfigHandshaking[Config . Handshaking]);
}

UBYTE *
QueryDuplex()
{
	return(ConfigDuplex[Config . Duplex]);
}

UBYTE *
QueryHighspeed()
{
	return(Booleans[Config . HighSpeed]);
}

UBYTE *
QueryBreakLength()
{
	SPrintf(RexxTextBuffer,"%ld",Config . BreakLength);

	return(RexxTextBuffer);
}

UBYTE *
QuerySerialDevice()
{
	return(Config . SerialDevice);
}

UBYTE *
QueryUnitNumber()
{
	SPrintf(RexxTextBuffer,"%ld",Config . UnitNumber);

	return(RexxTextBuffer);
}

UBYTE *
QueryModemInit()
{
	return(Config . ModemInit);
}

UBYTE *
QueryModemExit()
{
	return(Config . ModemExit);
}

UBYTE *
QueryDialPrefix()
{
	return(Config . DialPrefix);
}

UBYTE *
QueryRedialDelay()
{
	SPrintf(RexxTextBuffer,"%ld",Config . RedialDelay);

	return(RexxTextBuffer);
}

UBYTE *
QueryDialRetries()
{
	SPrintf(RexxTextBuffer,"%ld",Config . DialRetries);

	return(RexxTextBuffer);
}

UBYTE *
QueryDialTimeout()
{
	SPrintf(RexxTextBuffer,"%ld",Config . DialTimeout);

	return(RexxTextBuffer);
}

UBYTE *
QueryConnectAutoBaud()
{
	return(Booleans[Config . ConnectAutoBaud]);
}

UBYTE *
QueryNoCarrier()
{
	return(Config . NoCarrier);
}

UBYTE *
QueryConnect()
{
	return(Config . Connect);
}

UBYTE *
QueryVoice()
{
	return(Config . Voice);
}

UBYTE *
QueryRing()
{
	return(Config . Ring);
}

UBYTE *
QueryBusy()
{
	return(Config . Busy);
}

UBYTE *
QueryProtocol()
{
	return(Config . Protocol);
}

UBYTE *
QueryProtocolOptions()
{
	return(ProtocolOptsBuffer);
}

UBYTE *
QueryMacroFile()
{
	return(Config . MacroFile);
}

UBYTE *
QueryDisplay()
{
	WORD i;

	for(i = 0 ; i < 16 ; i++)
		if(Config . DisplayMode == ModeID[i])
			return(ConfigDisplayNames[i]);
}

UBYTE *
QueryPublicScreen()
{
	return(Booleans[Config . MakeScreenPublic]);
}

UBYTE *
QueryShanghai()
{
	return(Booleans[Config . ShanghaiWindows]);
}

UBYTE *
QueryCaptureFilter()
{
	return(Booleans[Config . HighSpeed]);
}

UBYTE *
QueryDSBackSpace()
{
	return(Booleans[Config . DestructiveBackspace]);
}

UBYTE *
QueryAudBell()
{
	return(Booleans[Config . AudibleBell]);
}

UBYTE *
QueryVisBell()
{
	return(Booleans[Config . VisibleBell]);
}

UBYTE *
QueryEightyColumns()
{
	return(Booleans[Config . EightyColumns != 0]);
}

UBYTE *
QuerySendCR()
{
	switch(Config . SendCR)
	{
		case CR_IGNORE:		return("IGNORE");
		case CR_ASCR:		return("CR");
		case CR_ASCRLF:		return("CRLF");
	}
}

UBYTE *
QuerySendLF()
{
	switch(Config . SendLF)
	{
		case LF_IGNORE:		return("IGNORE");
		case LF_ASLF:		return("LF");
		case LF_ASLFCR:		return("LFCR");
	}
}

UBYTE *
QueryColourMode()
{
	return(ConfigColour[Config . ColourMode]);
}

UBYTE *
QueryEmulation()
{
	return(ConfigEmulation[Config . Emulation]);
}

UBYTE *
QueryFont()
{
	return(ConfigFont[Config . Font]);
}

UBYTE *
QueryStatus()
{
	return(ConfigStatus[Status]);
}

UBYTE *
QuerySerial()
{
	return(Booleans[ReadPort ? 1 : 0]);
}

UBYTE *
QueryStartup()
{
	return(Config . StartupMacro);
}

UBYTE *
QueryRequesters()
{
	return((LONG)ThisProcess -> pr_WindowPtr == -1 ? Booleans[0] : Booleans[1]);
}

UBYTE *
QueryTimeout()
{
	SPrintf(RexxTextBuffer,"%ld",RexxGlobalTimeout);

	return(RexxTextBuffer);
}

UBYTE *
QueryLine()
{
	return(Booleans[Online]);
}

UBYTE *
QueryLines()
{
		/* Note: LastLine is the last accessible line (i.e. for a
		 *       24 line display, LastLine will be 23).
		 */

	SPrintf(RexxTextBuffer,"%ld",LastLine + 1);

	return(RexxTextBuffer);
}

UBYTE *
QueryColumns()
{
	SPrintf(RexxTextBuffer,"%ld",LastColumn);

	return(RexxTextBuffer);
}

UBYTE *
QueryCursor()
{
	SPrintf(RexxTextBuffer,"%ld %ld",CursorX,CursorY);

	return(RexxTextBuffer);
}

UBYTE *
QueryModemHangup()
{
	return(Config . ModemHangup);
}

UBYTE *
QueryAutoCapture()
{
	return(Booleans[Config . ConnectAutoCapture]);
}

UBYTE *
QueryLogActions()
{
	return(Booleans[Config . LogActions]);
}

UBYTE *
QueryBlinking()
{
	return(Booleans[Config . DisableBlinking ^ TRUE]);
}

UBYTE *
QueryCursorMode()
{
	return(KeyModes[Config . CursorApp]);
}

UBYTE *
QueryFontScale()
{
	return(FontSizes[Config . FontScale]);
}

UBYTE *
QueryJumpScroll()
{
	return(Booleans[Config . JumpScroll ^ TRUE]);
}

UBYTE *
QueryCharacterWrap()
{
	return(Booleans[Config . AutoWrap]);
}

UBYTE *
QueryCursorWrap()
{
	return(Booleans[Config . CursorWrap]);
}

UBYTE *
QueryNewLine()
{
	return(Booleans[Config . NewLine]);
}

UBYTE *
QueryInsert()
{
	return(Booleans[Config . InsertChar]);
}

UBYTE *
QueryNumeric()
{
	return(KeyModes[Config . NumApp]);
}

UBYTE *
QueryDefaultStore()
{
	return(Config . DefaultStorage);
}

UBYTE *
QueryTUploadPath()
{
	return(Config . TextUploadPath);
}

UBYTE *
QueryTDownloadPath()
{
	return(Config . TextDownloadPath);
}

UBYTE *
QueryAUploadPath()
{
	return(Config . ASCIIUploadPath);
}

UBYTE *
QueryADownloadPath()
{
	return(Config . ASCIIDownloadPath);
}

UBYTE *
QueryBUploadPath()
{
	return(Config . BinaryUploadPath);
}

UBYTE *
QueryBDownloadPath()
{
	return(Config . BinaryDownloadPath);
}

UBYTE *
QueryCapturePath()
{
	return(Config . CapturePath);
}

UBYTE *
QueryLogFile()
{
	return(Config . LogFile);
}

UBYTE *
QueryEditor()
{
	return(Config . Editor);
}

UBYTE *
QueryBeepSound()
{
	return(Config . BeepSound);
}

UBYTE *
QueryCaptureState()
{
	RexxTextBuffer[0] = 0;

	if(PrinterCapture)
	{
		strcat(RexxTextBuffer,"PRINTER");

		if(FileCapture)
			strcat(RexxTextBuffer," FILE");
	}
	else
	{
		if(FileCapture)
			strcat(RexxTextBuffer,"FILE");
		else
			strcat(RexxTextBuffer,Booleans[0]);
	}		

	return(RexxTextBuffer);
}

UBYTE *
QueryDownloads()
{
	SPrintf(RexxTextBuffer,"%ld",DownloadLineCount);

	return(RexxTextBuffer);
}

UBYTE *
QueryScreenAddress()
{
	SPrintf(RexxTextBuffer,"%ld",Screen);

	return(RexxTextBuffer);
}

UBYTE *
QuerySpeechFile()
{
	return(LastSpeech);
}

UBYTE *
QuerySpeechRate()
{
	SPrintf(RexxTextBuffer,"%ld",SpeechConfig . Rate);

	return(RexxTextBuffer);
}

UBYTE *
QuerySpeechPitch()
{
	SPrintf(RexxTextBuffer,"%ld",SpeechConfig . Pitch);

	return(RexxTextBuffer);
}

UBYTE *
QuerySpeechFrequency()
{
	SPrintf(RexxTextBuffer,"%ld",SpeechConfig . Frequency);

	return(RexxTextBuffer);
}

UBYTE *
QuerySpeechVolume()
{
	SPrintf(RexxTextBuffer,"%ld",SpeechConfig . Volume);

	return(RexxTextBuffer);
}

UBYTE *
QuerySpeechSex()
{
	return(SpeechConfig . Sex ? "FEMALE" : "MALE");
}

UBYTE *
QuerySpeech()
{
	return(Booleans[SpeechConfig . Enabled]);
}

VOID
RexxSetBaud(UBYTE *String)
{
	LONG Value = atol(String);

	if(Config . BaudRate != Value)
	{
		Config . BaudRate = Value;

		ResetSerial = TRUE;
	}
}

VOID
RexxSetDataBits(UBYTE *String)
{
	LONG Bits = atol(String);

	if(Bits == 7 || Bits == 8)
	{
		if(Config . BitsPerChar != Bits)
		{
			Config . BitsPerChar = Bits;

			ResetSerial = TRUE;
		}
	}
	else
		RexxRes1 = RC_ERROR;
}

VOID
RexxSetParity(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 5 ; i++)
	{
		if(!Stricmp(String,ConfigParity[i]))
		{
			if(Config . Parity != i)
			{
				Config . Parity = i;

				ResetSerial = TRUE;
			}

			break;
		}
	}
}

VOID
RexxSetStopBits(UBYTE *String)
{
	LONG Bits = atol(String);

	if(Bits == 1 || Bits == 2)
	{
		if(Config . StopBits != Bits)
		{
			Config . StopBits = Bits;

			ResetSerial = TRUE;
		}
	}
	else
		RexxRes1 = RC_ERROR;
}

VOID
RexxSetHandshaking(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 3 ; i++)
	{
		if(!Stricmp(String,ConfigHandshaking[i]))
		{
			if(Config . Handshaking != i)
			{
				Config . Handshaking = i;

				ResetSerial = TRUE;
			}

			break;
		}
	}
}

VOID
RexxSetDuplex(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,ConfigDuplex[i]))
		{
			Config . Duplex = i;

			break;
		}
	}
}

VOID
RexxSetHighSpeed(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			if(Config . HighSpeed != i)
			{
				Config . HighSpeed = i;

				ResetSerial = TRUE;
			}

			break;
		}
	}
}

VOID
RexxSetBreakLength(UBYTE *String)
{
	LONG Value = atol(String);

	if(Config . BreakLength != Value)
	{
		Config . BreakLength = Value;

		ResetSerial = TRUE;
	}
}

VOID
RexxSetSerialDevice(UBYTE *String)
{
	if(strcmp(Config . SerialDevice,String))
	{
		strcpy(Config . SerialDevice,String);

		ResetSerial = TRUE;
	}
}

VOID
RexxSetUnitNumber(UBYTE *String)
{
	LONG Value = atol(String);

	if(Config . UnitNumber != Value)
	{
		Config . UnitNumber = Value;

		ResetSerial = TRUE;
	}
}

VOID
RexxSetModemInit(UBYTE *String)
{
	strcpy(Config . ModemInit,String);
}

VOID
RexxSetModemExit(UBYTE *String)
{
	strcpy(Config . ModemExit,String);
}

VOID
RexxSetDialPrefix(UBYTE *String)
{
	strcpy(Config . DialPrefix,String);
}

VOID
RexxSetRedialDelay(UBYTE *String)
{
	Config . RedialDelay = atol(String);
}

VOID
RexxSetDialRetries(UBYTE *String)
{
	Config . DialRetries = atol(String);
}

VOID
RexxSetDialTimeout(UBYTE *String)
{
	Config . DialTimeout = atol(String);
}

VOID
RexxSetConnectAutoBaud(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . ConnectAutoBaud = i;

			break;
		}
	}
}

VOID
RexxSetNoCarrier(UBYTE *String)
{
	strcpy(Config . NoCarrier,String);
}

VOID
RexxSetConnect(UBYTE *String)
{
	strcpy(Config . Connect,String);
}

VOID
RexxSetVoice(UBYTE *String)
{
	strcpy(Config . Voice,String);
}

VOID
RexxSetRing(UBYTE *String)
{
	strcpy(Config . Ring,String);
}

VOID
RexxSetBusy(UBYTE *String)
{
	strcpy(Config . Busy,String);
}

VOID
RexxSetScreenMode(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 16 ; i++)
	{
		if(!Stricmp(ConfigDisplayNames[i],String))
		{
			if(!ModeNotAvailable(ModeID[i]))
			{
				if(Config . DisplayMode != ModeID[i])
				{
					BYTE Limited;

					if(Config . ColourMode == COLOUR_EIGHT || Config . ColourMode == COLOUR_SIXTEEN)
						Limited = TRUE;
					else
						Limited = FALSE;

					if(!Limited && ((ModeID[i] & ~MONITOR_ID_MASK) != HIRES_KEY) && ((ModeID[i] & ~MONITOR_ID_MASK) != HIRESLACE_KEY))
					{
						Config . DisplayMode = ModeID[i];

						ResetDisplay = TRUE;
					}
				}
			}

			break;
		}
	}
}

VOID
RexxSetFilter(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . CaptureFilter = i;

			break;
		}
	}
}

VOID
RexxSetBackspace(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . DestructiveBackspace = i;

			break;
		}
	}
}

VOID
RexxSetCR(UBYTE *String)
{
	if(!Stricmp(String,"IGNORE"))
		Config . SendCR = CR_IGNORE;

	if(!Stricmp(String,"CR"))
		Config . SendCR = CR_ASCR;

	if(!Stricmp(String,"CRLF"))
		Config . SendCR = CR_ASCRLF;
}

VOID
RexxSetLF(UBYTE *String)
{
	if(!Stricmp(String,"IGNORE"))
		Config . SendLF = LF_IGNORE;

	if(!Stricmp(String,"LF"))
		Config . SendLF = LF_ASLF;

	if(!Stricmp(String,"LFCR"))
		Config . SendLF = LF_ASLFCR;
}

VOID
RexxSet80Columns(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . EightyColumns = i;

			ConfigSetup();

			break;
		}
	}
}

VOID
RexxSetColourMode(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 4 ; i++)
	{
		if(!Stricmp(ConfigColour[i],String))
		{
			if(i != Config . ColourMode)
			{
				BYTE Limited;

				switch(Config . DisplayMode & ~MONITOR_ID_MASK)
				{
					case HIRES_KEY:
					case HIRESLACE_KEY:	Limited = FALSE;
								break;

					default:		Limited = TRUE;
								break;
				}

				if(Config . Emulation == EMULATION_ATOMIC && i > COLOUR_AMIGA && i < COLOUR_MONO)
					Config . Emulation = EMULATION_ANSIVT100;

				if(Limited && i != COLOUR_AMIGA && i != COLOUR_MONO)
				{
					if(Config . DisplayMode & LACE)
						Config . DisplayMode = DEFAULT_MONITOR_ID|HIRESLACE_KEY;
					else
						Config . DisplayMode = DEFAULT_MONITOR_ID|HIRES_KEY;
				}

				Config . ColourMode = i;

				ResetDisplay = TRUE;
			}

			break;
		}
	}
}

VOID
RexxSetEmulation(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 3 ; i++)
	{
		if(!Stricmp(String,ConfigEmulation[i]))
		{
			if(Config . Emulation != i)
			{
				Config . Emulation = i;

				ResetDisplay = TRUE;
			}

			break;
		}
	}
}

VOID
RexxSetStartup(UBYTE *String)
{
	strcpy(Config . StartupMacro,String);
}

VOID
RexxSetFont(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,ConfigFont[i]))
		{
			if(Config . Font != i)
			{
				Config . Font = i;

				if(Config . Font == FONT_TOPAZ)
					SetFont(RPort,Topaz);
				else
				{
					if(IBM)
						SetFont(RPort,IBM);
				}
			}

			break;
		}
	}
}

VOID
RexxSetProtocol(UBYTE *String)
{
	if(Stricmp(LastXprLibrary,String))
	{
		UBYTE Name[80];

		WORD i;

		for(i = 0 ; i < strlen(String) ; i++)
			Name[i] = ToLower(String[i]);

		strcpy(LastXprLibrary,Name);

		strcpy(Config . Protocol,LastXprLibrary);

		ProtocolSetup();
	}
}

VOID
RexxSetProtocolOptions(UBYTE *String)
{
	if(XProtocolBase)
	{
		if(Stricmp(ProtocolOptsBuffer,String))
		{
			strcpy(ProtocolOptsBuffer,String);

			XprIO -> xpr_filename = ProtocolOptsBuffer;

			TransferBits = XProtocolSetup(XprIO);

			if(!(TransferBits & XPRS_SUCCESS))
			{
				CloseLibrary(XProtocolBase);

				XProtocolBase = NULL;

				LastXprLibrary[0] = 0;

				TransferBits = 0;

				RexxRes1 = RC_ERROR;
			}
		}
	}
}

VOID
RexxSetMacro(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[40],Arg3[256];
	LONG ArgCount,i,Qualifier = -1;

	Arg1[0] = Arg2[0] = Arg3[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,40);
	GetToken(String,&ArgCount,Arg3,256);

	for(i = 0 ; i < 4 ; i++)
	{
		if(!Stricmp(Qualifiers[i],Arg1))
		{
			Qualifier = i;
			break;
		}
	}

	if(Qualifier != -1)
	{
		if(Arg2[0] >= '0' && Arg2[0] <= '9')
			strcpy(MacroKeys -> Keys[Qualifier][Arg2[0] - '0'],Arg3);
		else
			RexxRes1 = RC_ERROR;
	}
	else
		RexxRes1 = RC_ERROR;
}

VOID
RexxSetColour(UBYTE *String)
{
	UBYTE Arg1[20],Arg2[20];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,20);
	GetToken(String,&ArgCount,Arg2,20);

	if(Arg1[0] && Arg2[0])
	{
		LONG Colour,Value;

		Colour	= atol(Arg1);
		Value	= ahtoi(Arg2);

		if(Colour >= 0 && Colour < (1 << (Config . ColourMode == COLOUR_EIGHT ? 3 : Screen -> RastPort . BitMap -> Depth)))
		{
			Config . Colours[Colour] = Value;

			if(Config . ColourMode == COLOUR_AMIGA && Config . Emulation == EMULATION_ANSIVT100)
			{
				if(Colour == 0)
					BlinkColours[3] = Value;

				if(Colour != 3)
					BlinkColours[Colour] = Value;
			}
			else
			{
				if(Colour == 0 && Config . ColourMode == COLOUR_EIGHT && Config . Emulation == EMULATION_ANSIVT100)
				{
					WORD i;

					for(i = 8 ; i < 16 ; i++)
						BlinkColours[i] = Value;
				}
				else
					BlinkColours[Colour] = Value;
			}

			LoadRGB4(VPort,&Config . Colours[0],(1 << Screen -> RastPort . BitMap -> Depth));
		}
		else
			RexxRes1 = RC_ERROR;
	}
	else
		RexxRes1 = RC_ERROR;
}

VOID
RexxSetScreen(UBYTE *String)
{
	UBYTE Arg1[20],Arg2[20];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,20);
	GetToken(String,&ArgCount,Arg2,20);

	Config . MakeScreenPublic	= FALSE;
	Config . ShanghaiWindows	= FALSE;

	if(!Stricmp(Arg1,"PUBLIC") || !Stricmp(Arg2,"PUBLIC"))
		Config . MakeScreenPublic = TRUE;

	if(!Stricmp(Arg1,"SHANGHAI") || !Stricmp(Arg2,"SHANGHAI"))
		Config . ShanghaiWindows = TRUE;

	PubScreenStuff();
}

VOID
RexxSetBell(UBYTE *String)
{
	UBYTE Arg1[20],Arg2[20];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,20);
	GetToken(String,&ArgCount,Arg2,20);

	Config . AudibleBell	= FALSE;
	Config . VisibleBell	= FALSE;

	if(!Stricmp(Arg1,"VISIBLE") || !Stricmp(Arg2,"VISIBLE"))
		Config . VisibleBell = TRUE;

	if(!Stricmp(Arg1,"AUDIBLE") || !Stricmp(Arg2,"AUDIBLE"))
		Config . AudibleBell = TRUE;
}

VOID
RexxSetRequesters(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			ThisProcess -> pr_WindowPtr = (APTR)(i ? Window : -1);

			break;
		}
	}
}

VOID
RexxSetSerial(UBYTE *String)
{
	if(!Stricmp(String,Booleans[0]) && ReadPort)
		DeleteSerial();

	if(!Stricmp(String,Booleans[1]) && !ReadPort)
	{
		if(!CreateSerial())
			RexxRes1 = RC_ERROR;
	}
}

VOID
RexxSetTimeout(UBYTE *String)
{
	UBYTE	Arg1[40],Arg2[40];
	LONG	ArgCount;

	ULONG	Time = 0;
	WORD	i;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,40);

	for(i = 0 ; i < NUMTIMEREL ; i++)
	{
		if(!Stricmp(Arg2,TimeRelations[i] . Key))
		{
			Time = atol(String) * TimeRelations[i] . Multi;
			break;
		}
	}

	if(Time > 0)
		RexxGlobalTimeout = Time;
	else
		RexxRes1 = RC_ERROR;
}

VOID
RexxSetModemHangup(UBYTE *String)
{
	strcpy(Config . ModemHangup,String);
}

VOID
RexxSetAutoCapture(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . ConnectAutoCapture = i;
			break;
		}
	}
}

VOID
RexxSetLogActions(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . LogActions = i;
			break;
		}
	}
}

VOID
RexxSetBlinking(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . DisableBlinking = TRUE ^ i;
			break;
		}
	}
}

VOID
RexxSetCursorMode(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,KeyModes[i]))
		{
			Config . CursorApp = i;
			break;
		}
	}
}

VOID
RexxSetFontScale(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 5 ; i++)
	{
		if(!Stricmp(String,FontSizes[i]))
		{
			if(i != SCALE_HALF && Config . FontScale == SCALE_HALF)
			{
				CursorX >>= 1;
				SetCursor();

				if(Config . EightyColumns)
					LastColumn = 79;
				else
					LastColumn = (Window -> Width >> 3) - 1;
			}

			if(i == SCALE_HALF && Config . FontScale != SCALE_HALF)
			{
				if(Config . EightyColumns)
					LastColumn = 131;
				else
					LastColumn = (Window -> Width >> 2) - 1;
			}

			Config . FontScale = i;
			break;
		}
	}
}

VOID
RexxSetJumpScroll(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . JumpScroll = TRUE ^ i;
			break;
		}
	}
}

VOID
RexxSetCharacterWrap(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . AutoWrap = i;
			break;
		}
	}
}

VOID
RexxSetCursorWrap(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . CursorWrap = i;
			break;
		}
	}
}

VOID
RexxSetNewLine(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . NewLine = i;
			break;
		}
	}
}

VOID
RexxSetInsert(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			Config . InsertChar = i;
			break;
		}
	}
}

VOID
RexxSetNumeric(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,KeyModes[i]))
		{
			Config . NumApp = i;
			break;
		}
	}
}

VOID
RexxSetDefaultStore(UBYTE *String)
{
	strcpy(Config . DefaultStorage,String);
}

VOID
RexxSetTUploadPath(UBYTE *String)
{
	strcpy(Config . TextUploadPath,String);
}

VOID
RexxSetTDownloadPath(UBYTE *String)
{
	strcpy(Config . TextDownloadPath,String);
}

VOID
RexxSetAUploadPath(UBYTE *String)
{
	strcpy(Config . ASCIIUploadPath,String);
}

VOID
RexxSetADownloadPath(UBYTE *String)
{
	strcpy(Config . ASCIIDownloadPath,String);
}

VOID
RexxSetBUploadPath(UBYTE *String)
{
	strcpy(Config . BinaryUploadPath,String);
}

VOID
RexxSetBDownloadPath(UBYTE *String)
{
	strcpy(Config . BinaryDownloadPath,String);
}

VOID
RexxSetCapturePath(UBYTE *String)
{
	strcpy(Config . CapturePath,String);
}

VOID
RexxSetLogFile(UBYTE *String)
{
	strcpy(Config . LogFile,String);
}

VOID
RexxSetEditor(UBYTE *String)
{
	strcpy(Config . Editor,String);
}

VOID
RexxSetSpeechRate(UBYTE *String)
{
	SpeechConfig . Rate = atol(String);

	SpeechSetup();
}

VOID
RexxSetSpeechPitch(UBYTE *String)
{
	SpeechConfig . Pitch = atol(String);

	SpeechSetup();
}

VOID
RexxSetSpeechFrequency(UBYTE *String)
{
	SpeechConfig . Frequency = atol(String);

	SpeechSetup();
}

VOID
RexxSetSpeechVolume(UBYTE *String)
{
	SpeechConfig . Volume = atol(String);

	SpeechSetup();
}

VOID
RexxSetSpeechSex(UBYTE *String)
{
	if(!Stricmp(String,"MALE"))
	{
		SpeechConfig . Sex = 0;

		SpeechSetup();
	}
	else
	{
		if(!Stricmp(String,"FEMALE"))
		{
			SpeechConfig . Sex = 1;

			SpeechSetup();
		}
		else
			RexxRes1 = RC_ERROR;
	}
}

VOID
RexxSetSpeech(UBYTE *String)
{
	WORD i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(!Stricmp(String,Booleans[i]))
		{
			SpeechConfig . Enabled = i;

			SpeechSetup();

			break;
		}
	}
}

UBYTE *
RexxBreak()
{
	BYTE OldStatus = Status;

	if(WriteRequest)
	{
		Status = STATUS_BREAKING;

		WriteRequest -> IOSer . io_Command = SDCMD_BREAK;
		DoIO(WriteRequest);

		Status = OldStatus;
	}

	return(NULL);
}

UBYTE *
RexxTUpload(UBYTE *String)
{
	BinaryTransfer = FALSE;

	RexxBUpload(String);

	return(NULL);
}

UBYTE *
RexxTDownload(UBYTE *String)
{
	BinaryTransfer = FALSE;

	RexxBDownload(String);

	return(NULL);
}

UBYTE *
RexxBDownload(UBYTE *String)
{
	BYTE OldStatus = Status;

	if(XProtocolBase)
	{
		if(!(TransferBits & XPRS_NORECREQ))
			XprIO -> xpr_filename = String;

		if(TransferPanel(BinaryTransfer ? "Download File(s)" : "Download Text"))
		{
			Status = STATUS_DOWNLOAD;

			ClearSerial();

			XProtocolReceive(XprIO);

			Status = OldStatus;

			if(ReadRequest)
			{
				ReadRequest -> IOSer . io_Command	= CMD_READ;
				ReadRequest -> IOSer . io_Data		= ReadBuffer;
				ReadRequest -> IOSer . io_Length	= 1;

				SendIO(ReadRequest);
			}

			DeleteTransferPanel();
		}
	}

	BinaryTransfer = TRUE;

	return(NULL);
}

UBYTE *
RexxBUpload(UBYTE *String)
{
	BYTE OldStatus = Status;

	if(XProtocolBase)
	{
		if(!(TransferBits & XPRS_NOSNDREQ))
			XprIO -> xpr_filename = String;

		if(TransferPanel(BinaryTransfer ? "Upload File(s)" : "Upload Text"))
		{
			Status = STATUS_UPLOAD;

			ClearSerial();

			XProtocolSend(XprIO);

			Status = OldStatus;

			DeleteTransferPanel();

			if(ReadRequest)
			{
				ReadRequest -> IOSer . io_Command	= CMD_READ;
				ReadRequest -> IOSer . io_Data		= ReadBuffer;
				ReadRequest -> IOSer . io_Length	= 1;

				SendIO(ReadRequest);
			}
		}
	}

	BinaryTransfer = TRUE;

	return(NULL);
}

UBYTE *
RexxWrite(UBYTE *String)
{
	if(String[0])
		SerWrite(String,strlen(String));
	else
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxResetStyles()
{
	Escape = TRUE;

	ConProcess("\033[m",3);

	switch(Config . ColourMode)
	{
		case COLOUR_EIGHT:	FgPen = 7;
					break;

		case COLOUR_SIXTEEN:	FgPen = 15;
					break;

		case COLOUR_AMIGA:
		default:		FgPen = 1;
					break;
	}

	BgPen = 0;

	if(RPort -> FgPen != FgPen)
		SetAPen(RPort,FgPen);

	if(RPort -> BgPen != BgPen)
		SetBPen(RPort,BgPen);

	Config . FontScale = SCALE_NORMAL;

	Escape = FALSE;

	return(NULL);
}

UBYTE *
RexxClearScreen()
{
	Escape = TRUE;

	ConProcess("\033[2J\033[H",7);

	Escape = FALSE;

	return(NULL);
}

UBYTE *
RexxSaveILBM(UBYTE *String)
{
	if(!SaveRPort(&Screen -> RastPort,VPort,0,Window -> TopEdge,Window -> Width,Window -> Height,Screen -> Width,Screen -> Height,FALSE,String))
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxHangUp()
{
	BYTE OldStatus = Status;

	Status = STATUS_HANGUP;

	SerialCommand(Config . ModemHangup);

	Status = OldStatus;

	Online = FALSE;

	Password[0] = 0;

	return(NULL);
}

UBYTE *
RexxGetString(UBYTE *String)
{
	RexxTextBuffer[0] = 0;

	if(xpr_gets(String[0] ? String : "Get String For Rexx",RexxTextBuffer))
		return(RexxTextBuffer);
	else
		return(NULL);
}

UBYTE *
RexxCommand(UBYTE *String)
{
	if(String[0])
		SerialCommand(String);
	else
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxMessage(UBYTE *String)
{
	if(String[0])
		ConProcess(String,strlen(String));
	else
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxPutClip(UBYTE *String)
{
	if(String[0])
		SaveClip(String,strlen(String));
	else
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxGetClip()
{
	LONG Size;

	if(Size = LoadClip(RexxTextBuffer,255))
	{
		RexxTextBuffer[Size] = 0;

		return(RexxTextBuffer);
	}
	else
		return(NULL);
}

UBYTE *
RexxDelay(UBYTE *String)
{
	UBYTE	Arg1[40],Arg2[40];
	LONG	ArgCount;

	ULONG	Time = 0;
	WORD	i;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,40);

	for(i = 0 ; i < NUMTIMEREL ; i++)
	{
		if(!Stricmp(Arg2,TimeRelations[i] . Key))
		{
			Time = atol(String) * TimeRelations[i] . Multi;
			break;
		}
	}

	if(Time)
	{
		ULONG SignalSet;

		TimeRequest -> tr_node . io_Command	= TR_ADDREQUEST;
		TimeRequest -> tr_time . tv_secs	= Time / MILLION;
		TimeRequest -> tr_time . tv_micro	= Time % MILLION;

		SendIO(TimeRequest);

		SignalSet = Wait(SIGBREAKF_CTRL_D | (1 << TimeRequest -> tr_node . io_Message . mn_ReplyPort -> mp_SigBit));

		if(SignalSet & SIGBREAKF_CTRL_D)
		{
			if(!CheckIO(TimeRequest))
				AbortIO(TimeRequest);

			WaitIO(TimeRequest);

			return(NULL);
		}

		WaitIO(TimeRequest);
	}
	else
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxDial(UBYTE *String)
{
	LONG i;

	strcpy(RexxTextBuffer,Config . DialPrefix);

	for(i = 0 ; i < NumPhoneEntries ; i++)
	{
		if(!Stricmp(Phonebook[i] -> Name,String))
		{
			strcat(RexxTextBuffer,Phonebook[i] -> Number);

			goto DialIt;
		}
	}

	strcat(RexxTextBuffer,String);

DialIt:	strcat(RexxTextBuffer,"\\r");

	SerialCommand(RexxTextBuffer);

	return(NULL);
}

UBYTE *
RexxInput(UBYTE *String)
{
	LONG Length = atol(String);

	if(Length > 255)
		Length = 255;

	ClearSerial();

	if(Length = xpr_sread(RexxTextBuffer,Length,RexxGlobalTimeout))
	{
		RexxTextBuffer[Length] = 0;

		if(ReadRequest)
		{
			ReadRequest -> IOSer . io_Command	= CMD_READ;
			ReadRequest -> IOSer . io_Data		= ReadBuffer;
			ReadRequest -> IOSer . io_Length	= 1;

			SendIO(ReadRequest);
		}

		return(RexxTextBuffer);
	}

	if(ReadRequest)
	{
		ReadRequest -> IOSer . io_Command	= CMD_READ;
		ReadRequest -> IOSer . io_Data		= ReadBuffer;
		ReadRequest -> IOSer . io_Length	= 1;

		SendIO(ReadRequest);
	}

	return(NULL);
}

UBYTE *
RexxPrinter(UBYTE *String)
{
	struct MenuItem *SomeItem;

	SomeItem = FindThisItem(MEN_CAPTUREPRINTER);

	if(!Stricmp(String,Booleans[0]) && PrinterCapture)
	{
		Close(PrinterCapture);

		SomeItem -> Flags &= ~CHECKED;

		PrinterCapture = NULL;
	}

	if(!Stricmp(String,Booleans[1]) && !PrinterCapture)
	{
		if(PrinterCapture = Open("PRT:",MODE_NEWFILE))
			SomeItem -> Flags |= CHECKED;
		else
		{
			SomeItem -> Flags &= ~CHECKED;
			RexxRes1 = RC_ERROR;
		}
	}

	return(NULL);
}

UBYTE *
RexxMacros(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[256];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,256);

	if(!Stricmp(Arg1,"SAVE"))
	{
		if(Arg2[0])
		{
			if(WriteIFFData(Arg2,MacroKeys,sizeof(struct MacroKeys),'KEYS'))
				strcpy(LastMacros,Arg2);
			else
				RexxRes1 = RC_ERROR;
		}
	}

	if(!Stricmp(Arg1,"LOAD"))
	{
		if(Arg2[0])
		{
			if(LoadMacros(Arg2,MacroKeys))
				strcpy(LastMacros,Arg2);
			else
				RexxRes1 = RC_ERROR;
		}
	}

	return(NULL);
}

UBYTE *
RexxSpeech(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[256];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,256);

	if(!Stricmp(Arg1,"SAVE"))
	{
		if(Arg2[0])
		{
			if(!WriteIFFData(Arg2,&SpeechConfig,sizeof(struct SpeechConfig),'SPEK'))
				RexxRes1 = RC_ERROR;
			else
				strcpy(LastSpeech,Arg2);
		}
	}

	if(!Stricmp(Arg1,"LOAD"))
	{
		if(Arg2[0])
		{
			if(!ReadIFFData(Arg2,&SpeechConfig,sizeof(struct SpeechConfig),'SPEK'))
				RexxRes1 = RC_ERROR;
			else
			{
				strcpy(LastSpeech,Arg2);

				SpeechSetup();
			}
		}
	}

	return(NULL);
}

UBYTE *
RexxConfig(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[256];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,256);

	if(!Stricmp(Arg1,"SAVE"))
	{
		if(Arg2[0])
		{
			if(WriteIFFData(Arg2,&Config,sizeof(struct Configuration),'PREF'))
				strcpy(LastConfig,Arg2);
			else
				RexxRes1 = RC_ERROR;
		}
	}

	if(!Stricmp(Arg1,"LOAD"))
	{
		if(Arg2[0])
		{
			struct Configuration PrivateConfig;

			if(ReadIFFData(Arg2,&PrivateConfig,sizeof(struct Configuration),'PREF'))
			{
				Config = PrivateConfig;

				ConfigSetup();

				strcpy(LastConfig,Arg2);
			}
			else
				RexxRes1 = RC_ERROR;
		}
	}

	return(NULL);
}

UBYTE *
RexxPhone(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[256];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,256);

	if(!Stricmp(Arg1,"SAVE"))
	{
		if(Arg2[0])
		{
			if(SavePhonebook(Arg2))
				strcpy(LastPhone,Arg2);
			else
				RexxRes1 = RC_ERROR;
		}
	}

	if(!Stricmp(Arg1,"LOAD"))
	{
		if(Arg2[0])
		{
			if(LoadPhonebook(Arg2))
				strcpy(LastPhone,Arg2);
			else
				RexxRes1 = RC_ERROR;
		}
	}

	return(NULL);
}

UBYTE *
RexxCapture(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[256];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,256);

	if(!Stricmp(Arg1,"CLOSE") && FileCapture)
	{
		struct MenuItem *SomeItem;

		SomeItem = FindThisItem(MEN_CAPTUREDISK);

		BufferClose(FileCapture);

		SomeItem -> Flags &= ~CHECKED;

		FileCapture = NULL;

		if(!GetFileSize(CaptureName))
			DeleteFile(CaptureName);
		else
			SetProtection(CaptureName,FIBF_EXECUTE);
	}
	else
	{
		if(!Stricmp(Arg1,"NEW") && Arg2[0])
			FileCapture = BufferOpen(Arg2,"w");
		else
		{
			if(!Stricmp(Arg1,"APPEND") && Arg2[0])
				FileCapture = BufferOpen(Arg2,"a");
		}

		if(FileCapture)
		{
			struct MenuItem *SomeItem;

			strcpy(CaptureName,Arg2);

			SomeItem = FindThisItem(MEN_CAPTUREDISK);

			SomeItem -> Flags |= CHECKED;
		}
		else
			RexxRes1 = RC_ERROR;
	}

	return(NULL);
}

UBYTE *
RexxBuffer(UBYTE *String)
{
	UBYTE Arg1[40],Arg2[256];
	LONG ArgCount;

	Arg1[0] = Arg2[0] = 0;
	ArgCount = 0;

	GetToken(String,&ArgCount,Arg1,40);
	GetToken(String,&ArgCount,Arg2,256);

	if(!Stricmp(Arg1,"NEW") || !Stricmp(Arg1,"APPEND"))
	{
		if(GetFileSize(Arg2))
		{
			BPTR SomeFile;

			if(SomeFile = Open(Arg2,MODE_OLDFILE))
			{
				if(Lines)
				{
					if(!Stricmp(Arg1,"NEW"))
						ClearBuffer();
				}

				LineRead(NULL,NULL,NULL);

				while(LineRead(SomeFile,Arg2,80))
					StoreBuffer(Arg2,strlen(Arg2));

				Close(SomeFile);
			}
			else
				RexxRes1 = RC_ERROR;
		}
		else
			RexxRes1 = RC_ERROR;
	}
	else
	{
		if(!Stricmp(Arg1,"DISPLAY"))
		{
			if(BufferProcess)
				Signal(BufferProcess,SIGBREAKF_CTRL_D);
			else
			{
				if(BufferProcess = (struct Process *)CreateNewProcTags(
					NP_Entry,	BufferServer,
					NP_Name,	"term Buffer Process",
					NP_Priority,	0,
					NP_StackSize,	8192,
					NP_WindowPtr,	-1,
				TAG_END))
					Wait(SIGBREAKF_CTRL_C);
			}
		}
	}

	return(NULL);
}

UBYTE *
RexxFirstDownload()
{
	ObtainSemaphore(DownloadSemaphore);

	if(DownloadLineCount)
	{
		DownloadNode = DownloadList . lh_Head;

		if(DownloadNode -> ln_Succ)
		{
			strcpy(RexxTextBuffer,DownloadNode -> ln_Name);

			ReleaseSemaphore(DownloadSemaphore);

			return(RexxTextBuffer);
		}
	}

	ReleaseSemaphore(DownloadSemaphore);

	return("");
}

UBYTE *
RexxNextDownload()
{
	ObtainSemaphore(DownloadSemaphore);

	if(!DownloadNode)
		DownloadNode = DownloadList . lh_Head;
	else
		DownloadNode = DownloadNode -> ln_Succ;

	if(DownloadNode -> ln_Succ)
	{
		strcpy(RexxTextBuffer,DownloadNode -> ln_Name);

		ReleaseSemaphore(DownloadSemaphore);

		return(RexxTextBuffer);
	}
	else
		DownloadNode = NULL;

	ReleaseSemaphore(DownloadSemaphore);

	return("");
}

UBYTE *
RexxLastDownload()
{
	ObtainSemaphore(DownloadSemaphore);

	if(DownloadLineCount)
	{
		DownloadNode = DownloadList . lh_TailPred;

		strcpy(RexxTextBuffer,DownloadNode -> ln_Name);

		ReleaseSemaphore(DownloadSemaphore);

		return(RexxTextBuffer);
	}

	ReleaseSemaphore(DownloadSemaphore);

	return("");
}

UBYTE *
RexxWaitString(UBYTE *String)
{
	UBYTE		 Arg1[40];
	LONG		 ArgCount;

	struct ScanNode	*Matching = NULL;

	ULONG		 SignalSet;
	WORD		 i;

	ULONG		 Timeout = RexxGlobalTimeout;

	if(ReadPort)
	{
		Arg1[0] = 0;

		ArgCount = 0;

			/* Parse the argument looking for sequences
			 * to wait for.
			 */

		while(GetToken(String,&ArgCount,Arg1,40))
			AddSequenceObject(Arg1);

			/* If no timeout is set this routine becomes
			 * a real trap: suppose the string to wait for
			 * never happens to arrive -> we'll wait
			 * forever. For this reason the default timeout
			 * is set to five seconds.
			 */

		if(Timeout < 1)
			Timeout = 5 * MILLION;

		TimeRequest -> tr_node . io_Command	= TR_ADDREQUEST;
		TimeRequest -> tr_time . tv_secs	= Timeout >= MILLION ? Timeout / MILLION : 0;
		TimeRequest -> tr_time . tv_micro	= Timeout % MILLION;

		SetSignal(0,SIG_TIMER);

		SendIO(TimeRequest);

		FOREVER
		{
			SignalSet = Wait(SIG_TIMER | SIG_SERIAL | SIGBREAKF_CTRL_D);

				/* We are to abort the job. */

			if(SignalSet & SIGBREAKF_CTRL_D)
			{
				Matching = NULL;
				break;
			}

				/* Serial data came in... */

			if(SignalSet & SIG_SERIAL)
			{
				if(Status == STATUS_HOLDING)
					Status = STATUS_READY;

				/* Any news? */

				if(CheckIO(ReadRequest))
				{
					LONG Length;

					if(!WaitIO(ReadRequest))
					{
						/* Send the byte to the console. */

						ConProcess(ReadBuffer,1);

						if(Matching == NULL)
							Matching = SequenceFilter(((UBYTE *)ReadBuffer)[0]);

						/* Loop until all data has been processed. */

Loop:						do
						{
							/* Check how many bytes are still in
							 * the serial buffer.
							 */

							WriteRequest -> IOSer . io_Command = SDCMD_QUERY;
							DoIO(WriteRequest);

							if(Length = WriteRequest -> IOSer . io_Actual)
							{
								if(Length > SERBUFF_SIZE)
									Length = SERBUFF_SIZE;

								ReadRequest -> IOSer . io_Command	= CMD_READ;
								ReadRequest -> IOSer . io_Data		= ReadBuffer;
								ReadRequest -> IOSer . io_Length	= Length;

								DoIO(ReadRequest);

								/* Send the data to the console. */

								ConProcess(ReadBuffer,Length);

								if(Matching == NULL)
								{
									for(i = 0 ; i < Length ; i++)
									{
										if(Matching = SequenceFilter(((UBYTE *)ReadBuffer)[i]))
											break;
									}
								}
							}
						}
						while(Length);

						/* Ask for another byte. */

						ReadRequest -> IOSer . io_Command	= CMD_READ;
						ReadRequest -> IOSer . io_Data		= ReadBuffer;
						ReadRequest -> IOSer . io_Length 	= 1;

						SendIO(ReadRequest);
					}
				}
			}

				/* Timeout has occured. */

			if(SignalSet & SIG_TIMER)
				break;

				/* We've made a match! */

			if(Matching)
				break;
		}

			/* Is the timer still active? If so, cancel it. */

		if(!CheckIO(TimeRequest))
			AbortIO(TimeRequest);

			/* Wait for timer to return. */

		WaitIO(TimeRequest);

			/* Determine the result code if a match has been
			 * made.
			 */

		if(Matching)
			strcpy(RexxTextBuffer,Matching -> Sequence);
		else
			RexxTextBuffer[0] = 0;
	}

		/* Clear the list of sequences to check. */

	ClearSequenceObjects();

	return(RexxTextBuffer);
}

UBYTE *
RexxToneDial(UBYTE *String)
{
	if(ToneDial(String))
		DeleteTone();
	else
		RexxRes1 = RC_ERROR;

	return(NULL);
}

UBYTE *
RexxSimpleRequest(UBYTE *String)
{
	BlockWindows();

	MyEasyRequest(Window,String,"Continue");

	ReleaseWindows();

	return(NULL);
}

UBYTE *
RexxTwoGadRequest(UBYTE *String)
{
	BYTE Result;

	BlockWindows();

	Result = MyEasyRequest(Window,String,"Yes|No");

	ReleaseWindows();

	if(Result)
		return("YES");
	else
		return("NO");
}

UBYTE *
RexxFileRequest(UBYTE *String)
{
	struct AslFileRequest *FileRequest;

	BlockWindows();

	MoveScreen(Screen,0,-Screen -> TopEdge);

	ScreenToFront(Screen);

	if(FileRequest = GetFile(String,"","",RexxTextBuffer,NULL,FALSE,FALSE,FALSE,NULL))
	{
		if(RexxTextBuffer[0])
		{
			FreeAslRequest(FileRequest);

			ReleaseWindows();

			return(RexxTextBuffer);
		}
		else
		{
			FreeAslRequest(FileRequest);

			ReleaseWindows();

			return(NULL);
		}
	}
	else
	{
		ReleaseWindows();

		return(NULL);
	}
}

UBYTE *
RexxSpeak(UBYTE *String)
{
	Say(String);

	return(NULL);
}

VOID
Rexx2Front()
{
	if(RexxWindow)
		BumpWindow(RexxWindow);
}

VOID
Term2Front()
{
	BumpWindow(Window);
}

VOID
Display2Front()
{
	if(BufferProcess)
		Signal(BufferProcess,SIGBREAKF_CTRL_D);
}

VOID
CloseDisplay()
{
	if(BufferProcess)
		Signal(BufferProcess,SIGBREAKF_CTRL_C);
}

VOID
QuietExit()
{
	ExitQuietly = TRUE;
}

	/* RexxASyncCommand(struct RexxMsg *RexxMsg):
	 *
	 *	This routine handles the asynchronous Rexx
	 *	commands and complains if the command passed
	 *	to it cannot be executed asynchronously.
	 */

BYTE
RexxASyncCommand(struct RexxMsg *RexxMsg,UBYTE *Arg1,UBYTE *Arg2)
{
	LONG	ArgCount = 0;
	STRPTR	StringResult = NULL;
	WORD	i;
	LONG	RexxRes1 = RC_OK;

	GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg1,80);
	GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg2,80);

	if(!Stricmp(Arg1,"QUERY"))
	{
		if(!Stricmp(Arg2,"COLOUR"))
		{
			LONG Colour;

			GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg1,80);

			Colour = atol(Arg1);

			if(Colour >= 0 && Colour < (1 << (Config . ColourMode == COLOUR_EIGHT ? 3 : Screen -> RastPort . BitMap -> Depth)))
			{
				SPrintf(RexxTextBuffer,"%03lx",Config . Colours[Colour]);

				StringResult = RexxTextBuffer;
			}
			else
				RexxRes1 = RC_ERROR;
		}
		else
		{
			if(!Stricmp(Arg2,"MACRO"))
			{
				LONG Value,Qualifier = -1;

				GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg2,80);

				for(i = 0 ; i < 4 ; i++)
				{
					if(!Stricmp(Qualifiers[i],Arg2))
					{
						Qualifier = i;
						break;
					}
				}

				if(Qualifier != -1)
				{
					GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg2,80);

					Value = atol(Arg2);

					if(Value >= 0 && Value <= 9)
						StringResult = MacroKeys -> Keys[Qualifier][Value];
					else
						RexxRes1 = RC_ERROR;
				}
				else
					RexxRes1 = RC_ERROR;
			}
			else
			{
				for(i = 0 ; i < NUMQUERIES ; i++)
				{
					if(!Stricmp(Arg2,QueryCommands[i] . String))
						StringResult = QueryCommands[i] . Routine();
				}
			}
		}
	}
	else
	{
		for(i = 0 ; i < NUMASYNCS ; i++)
		{
			if(!Stricmp(Arg1,ASyncCommands[i] . String))
			{
				ASyncCommands[i] . Routine();

				i = -1;

				break;
			}
		}

		if(i != -1)
			return(FALSE);
	}

	ReplyRexxCommand(RexxMsg,RexxRes1,0,StringResult);

	return(TRUE);
}

	/* RexxSyncCommand(struct RexxMsg *RexxMsg):
	 *
	 *	Handles the synchronous Rexx commands and returns the
	 *	message if no matching command is found.
	 */

VOID
RexxSyncCommand(struct RexxMsg *RexxMsg,UBYTE *Arg1,UBYTE *Arg2)
{
	LONG	ArgCount = 0,Count2;
	STRPTR	StringResult = NULL;
	WORD	i;

	GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg1,80);

		/* Save position of second argument for the
		 * Rexx commands.
		 */

	Count2 = ArgCount;

	GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg2,80);

	RexxRes1 = RC_OK;

		/* Look if it's a `set' command. */

	if(!Stricmp(Arg1,"SET"))
	{
		for(i = 0 ; i < SETMOREPARAMS ; i++)
		{
			if(!Stricmp(Arg2,SetCommands[i] . String))
			{
				SetCommands[i] . Routine(&RexxMsg -> rm_Args[0][ArgCount]);

				ReplyRexxCommand(RexxMsg,RexxRes1,0,NULL);

				return;
			}
		}

		for(i = SETMOREPARAMS ; i < NUMSETS ; i++)
		{
			if(!Stricmp(Arg2,SetCommands[i] . String))
			{
				GetToken(RexxMsg -> rm_Args[0],&ArgCount,Arg2,80);

				SetCommands[i] . Routine(Arg2);

				ReplyRexxCommand(RexxMsg,RexxRes1,0,NULL);

				return;
			}
		}
	}

	for(i = 0 ; i < REXXMOREPARAMS ; i++)
	{
		if(!Stricmp(Arg1,RexxCommands[i] . String))
		{
			StringResult = RexxCommands[i] . Routine(&RexxMsg -> rm_Args[0][Count2]);

			ReplyRexxCommand(RexxMsg,RexxRes1,0,StringResult);

			return;
		}
	}

	for(i = REXXMOREPARAMS ; i < NUMREXX ; i++)
	{
		if(!Stricmp(Arg1,RexxCommands[i] . String))
		{
			StringResult = RexxCommands[i] . Routine(Arg2);

			ReplyRexxCommand(RexxMsg,RexxRes1,0,StringResult);

			return;
		}
	}

	ReplyRexxCommand(RexxMsg,RC_ERROR,0,NULL);
}

	/* RexxServer(VOID):
	 *
	 *	Asynchronous ARexx host server.
	 */

VOID __saveds
RexxServer(VOID)
{
	UBYTE		 Arg1[80],Arg2[80];

	struct MsgPort	*RexxPort;
	struct RexxMsg	*RexxMsg;

	ULONG		 SignalSet;

	BYTE		 Terminated = FALSE;

		/* Create the public host port. */

	if(RexxPort = (struct MsgPort *)CreateMsgPort())
	{
		RexxPort -> mp_Node . ln_Name	= TermIDString;
		RexxPort -> mp_Node . ln_Pri	= 1;

			/* Make it a public port. */

		AddPort(RexxPort);

			/* Signal our father that we're running. */

		Signal(ThisProcess,SIGBREAKF_CTRL_C);

			/* Go into loop and wait for input. */

		while(!Terminated)
		{
			SignalSet = Wait(SIGBREAKF_CTRL_C | (1 << RexxPort -> mp_SigBit));

				/* This is probably a Rexx command. */

			if(SignalSet & (1 << RexxPort -> mp_SigBit))
			{
					/* Pick up all the messages. */

				while(RexxMsg = (struct RexxMsg *)GetMsg(RexxPort))
				{
					Arg1[0] = Arg2[0] = 0;

						/* At first try to run the
						 * command asynchronously.
						 * If this turns out to be
						 * somewhat `impossible' pass
						 * it to the `term' main process
						 * or - if in batch mode - try
						 * to deal with the message
						 * on our own.
						 */

					if(!RexxASyncCommand(RexxMsg,Arg1,Arg2))
					{
						if(!BatchMode)
							PutMsg(TermRexxPort,RexxMsg);
						else
							ReplyRexxCommand(RexxMsg,-1,0,NULL);
					}
				}
			}

			if(SignalSet & SIGBREAKF_CTRL_C)
				Terminated = TRUE;
		}

		Forbid();

		while(RexxMsg = (struct RexxMsg *)GetMsg(RexxPort))
			ReplyRexxCommand(RexxMsg,-1,0,NULL);

		RemPort(RexxPort);

		DeleteMsgPort(RexxPort);
	}

	Forbid();

	RexxProcess = NULL;

	Signal(ThisProcess,SIGBREAKF_CTRL_C);
}

	/* HandleRexx():
	 *
	 *	Tiny & simple subroutine to read and examine all
	 *	messages coming in to be processed synchronously
	 *	by the `term' main process.
	 */

VOID
HandleRexx()
{
	struct RexxMsg	*RexxMsg;
	UBYTE		 Arg1[80],Arg2[256];

	while(RexxMsg = (struct RexxMsg *)GetMsg(TermRexxPort))
	{
		Arg1[0] = Arg2[0] = 0;

		RexxSyncCommand(RexxMsg,Arg1,Arg2);
	}
}
