/*
**	termARexxCommands.c
**
**	ARexx interface command support routines
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#include "termARexxGlobal.h"

	/* Number of bytes already processed by ScanNodeFilter(). */

STATIC LONG WaitCount = 0;

	/* Cheapo shortcuts ;-) */

#define Args	Pkt -> Array
#define Results	Pkt -> Results

	/* ScanNodeFilter():
	 *
	 *	Scan memory for a certain sequence.
	 */

STATIC STRPTR __regargs
ScanNodeFilter(register STRPTR Data,register LONG Size,register struct WaitNode *Node,LONG *Position)
{
	register UBYTE c,Mask;

	*Position = 0;

	if(Config -> SerialConfig -> StripBit8)
		Mask = 0x7F;
	else
		Mask = 0xFF;

	if(Node)
	{
		do
		{
			(*Position)++;

			if(c = ToUpper((*Data++) & Mask))
			{
				register BYTE MatchMade;

				do
				{
					MatchMade = FALSE;

					if(Node -> Count == WaitCount)
					{
						if(c == (Node -> Node . ln_Name[WaitCount] & Mask))
						{
							MatchMade = TRUE;

							if(!Node -> Node . ln_Name[++Node -> Count])
							{
								if(Node -> ResponseLen)
								{
									SerWriteVerbatim(Node -> Response,Node -> ResponseLen,FALSE);

									Node -> Count = 0;
								}
								else
									return(Node -> Node . ln_Name);
							}
						}
					}

					if(MatchMade)
						WaitCount++;
					else
					{
						if(WaitCount)
						{
							WaitCount = 0;

							Node -> Count = 0;
						}
						else
							break;
					}
				}
				while(!WaitCount);
			}
		}
		while(--Size);
	}
	else
	{
		do
		{
			(*Position)++;

			if(c = ToUpper((*Data++) & Mask))
			{
				register BYTE MatchMade;

				do
				{
					MatchMade = FALSE;

					Node = (struct WaitNode *)GenericListTable[GLIST_WAIT] -> ListHeader . mlh_Head;

					while(Node -> Node . ln_Succ)
					{
						if(Node -> Count == WaitCount)
						{
							if(c == (Node -> Node . ln_Name[WaitCount] & Mask))
							{
								Node -> Count++;

								MatchMade = TRUE;

								if(!Node -> Node . ln_Name[Node -> Count])
								{
									if(Node -> ResponseLen)
									{
										SerWriteVerbatim(Node -> Response,Node -> ResponseLen,FALSE);

										Node -> Count = 0;
									}
									else
										return(Node -> Node . ln_Name);
								}
							}
						}

						Node = (struct WaitNode *)Node -> Node . ln_Succ;
					}

					if(MatchMade)
						WaitCount++;
					else
					{
						if(WaitCount)
						{
							WaitCount = 0;

							Node = (struct WaitNode *)GenericListTable[GLIST_WAIT] -> ListHeader . mlh_Head;

							while(Node -> Node . ln_Succ)
							{
								Node -> Count = 0;

								Node = (struct WaitNode *)Node -> Node . ln_Succ;
							}
						}
						else
							break;
					}
				}
				while(!WaitCount);
			}
		}
		while(--Size);
	}

	return(NULL);
}

STRPTR
RexxActivate(struct RexxPkt *Pkt)
{
	if(Window)
		BumpWindow(Window);
	else
		Signal(ThisProcess,SIGBREAKF_CTRL_F);

	return(NULL);
}

STRPTR
RexxAdd(struct RexxPkt *Pkt)
{
	enum	{	ARG_ADD_FROM,ARG_ADD_BEFORE,ARG_ADD_AFTER,ARG_ADD_RESPONSE,
			ARG_ADD_COMMAND,ARG_ADD_PHONEENTRY,ARG_ADD_NAME };

	WORD ListIndex;

	if((ListIndex = ToList(Args[ARG_ADD_FROM])) != -1)
	{
		struct GenericList	*List = GenericListTable[ListIndex];
		BYTE			 AddMode;

		if(Args[ARG_ADD_BEFORE])
			AddMode = ADD_GLIST_BEFORE;
		else
		{
			if(Args[ARG_ADD_AFTER])
				AddMode = ADD_GLIST_BEHIND;
			else
				AddMode = ADD_GLIST_BOTTOM;
		}

		if(ListIndex == GLIST_DIAL)
		{
			if(Args[ARG_ADD_PHONEENTRY])
			{
				if(!IsNumeric(Args[ARG_ADD_PHONEENTRY]))
				{
					STRPTR Buffer;

					if(Buffer = CreateMatchBuffer(Args[ARG_ADD_PHONEENTRY]))
					{
						struct DialNode	*Node;
						LONG		 i;
						BOOL		 GotIt = FALSE;

						for(i = 0 ; i < NumPhoneEntries ; i++)
						{
							if(MatchBuffer(Buffer,Phonebook[i] -> Header -> Name))
							{
								if(Node = (struct DialNode *)CreateGenericListNode(sizeof(struct DialNode),""))
								{
									Node -> Entry = Phonebook[i];

									AddGenericListNode(List,(struct Node *)Node,AddMode);

									GotIt = TRUE;
								}
								else
								{
									Results[0] = RC_ERROR;
									Results[1] = ERROR_NO_FREE_STORE;

									break;
								}
							}
						}

						if(!GotIt && Results[0] != RC_ERROR)
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_OBJECT_NOT_FOUND;
						}

						DeleteMatchBuffer(Buffer);
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_NO_FREE_STORE;
					}
				}
				else
				{
					LONG Index = Atol(Args[ARG_ADD_PHONEENTRY]);

					if(Index < 0 || Index > NumPhoneEntries)
					{
						Results[0] = RC_ERROR;
						Results[1] = TERMERROR_INDEX_OUT_OF_RANGE;
					}
					else
					{
						struct DialNode	*Node;

						if(Node = (struct DialNode *)CreateGenericListNode(sizeof(struct DialNode),""))
						{
							Node -> Entry = Phonebook[Index];

							AddGenericListNode(List,(struct Node *)Node,AddMode);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}
					}
				}
			}
			else
			{
				if(Args[ARG_ADD_NAME])
				{
					struct Node *Node;

					if(Node = CreateGenericListNode(sizeof(struct DialNode),Args[ARG_ADD_NAME]))
						AddGenericListNode(List,Node,AddMode);
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_NO_FREE_STORE;
					}
				}
			}
		}
		else
		{
			if(ListIndex == GLIST_WAIT)
			{
				STRPTR	Response;
				LONG	ResponseLen;

				if(Args[ARG_ADD_RESPONSE])
				{
					Response	= Args[ARG_ADD_RESPONSE];
					ResponseLen	= strlen(Response);
				}
				else
				{
					Response	= NULL;
					ResponseLen	= 0;
				}

				if(Args[ARG_ADD_NAME])
				{
					struct WaitNode *Node;

					if(Node = (struct WaitNode *)CreateGenericListNode(sizeof(struct WaitNode) + ResponseLen + 1,Args[ARG_ADD_NAME]))
					{
						WORD i,Len;

						Len = TranslateString(Node -> Node . ln_Name,Node -> Node . ln_Name);

						Node -> Node . ln_Name[Len] = 0;

						for(i = 0 ; i < Len ; i++)
							Node -> Node . ln_Name[i] = ToUpper(Node -> Node . ln_Name[i]);

						if(Response && ResponseLen)
						{
							Node -> Response = &Node -> Node . ln_Name[Len + 1];

							strcpy(Node -> Response,Response);

							Node -> ResponseLen = TranslateString(Node -> Response,Node -> Response);
						}
						else
							Node -> ResponseLen = 0;

						AddGenericListNode(List,Node,AddMode);
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_NO_FREE_STORE;
					}
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_REQUIRED_ARG_MISSING;
				}
			}
			else
			{
				if(ListIndex == GLIST_TRAP)
				{
					if(!Args[ARG_ADD_NAME] || !Args[ARG_ADD_COMMAND])
					{
						struct TrapNode	*Node;
						UBYTE		 LocalBuffer[256];
						LONG		 NameLen;

						if(strlen(Args[ARG_ADD_NAME]) > 255)
							Args[ARG_ADD_NAME][255] = 0;

						NameLen = TranslateString(Args[ARG_ADD_NAME],LocalBuffer);

						if(Node = (struct TrapNode *)AllocVecPooled(sizeof(struct TrapNode) + strlen(Args[ARG_ADD_NAME]) + 1 + NameLen + strlen(Args[ARG_ADD_COMMAND]) + 1,MEMF_ANY))
						{
							STRPTR String = Node -> Node . ln_Name = (STRPTR)(Node + 1);

							strcpy(String,Args[ARG_ADD_NAME]);

							String += strlen(String) + 1;

							Node -> Sequence = String;

							CopyMem(LocalBuffer,String,NameLen);

							String += NameLen;

							Node -> Command = String;

							strcpy(String,Args[ARG_ADD_COMMAND]);

							Node -> SequenceLen = NameLen;
							Node -> Count = 0;

							AddGenericListNode(List,Node,AddMode);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_REQUIRED_ARG_MISSING;
					}
				}
				else
				{
					if(Args[ARG_ADD_NAME])
					{
						struct Node *Node;

						if(Node = CreateGenericListNode(sizeof(struct DialNode),Args[ARG_ADD_NAME]))
							AddGenericListNode(List,Node,AddMode);
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = TERMERROR_WRONG_LIST;
					}
				}
			}
		}
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_UNKNOWN_LIST;
	}

	return(NULL);
}

STRPTR
RexxBaud(struct RexxPkt *Pkt)
{
	enum	{	ARG_BAUD_RATE };

	LONG Rate = *(LONG *)Args[ARG_BAUD_RATE],Min = MILLION,Diff,Index;
	WORD i;

	for(i = 0 ; i < NumBaudRates ; i++)
	{
		Diff = Rate - BaudRates[i];

		if(Diff >= 0 && Diff < Min)
		{
			Min	= Diff;
			Index	= i;
		}
	}

	if(BaudRates[Index] != Config -> SerialConfig -> BaudRate)
	{
		Config -> SerialConfig -> BaudRate = BaudRates[Index];

		ConfigChanged = TRUE;

		UpdateRequired = TRUE;
	}

	return(NULL);
}

STRPTR
RexxBeepScreen(struct RexxPkt *Pkt)
{
	BellSignal();

	return(NULL);
}

STRPTR
RexxCallMenu(struct RexxPkt *Pkt)
{
	enum	{	ARG_CALLMENU_TITLE };

	STRPTR Buffer;

	if(Buffer = CreateMatchBuffer(Args[ARG_CALLMENU_TITLE]))
	{
		WORD i;

		Results[0] = RC_WARN;

			/* Scan the menu list... */

		for(i = 0 ; TermMenu[i] . nm_Type != NM_END ; i++)
		{
				/* Did we get a valid name string? */

			if(TermMenu[i] . nm_Label != NM_BARLABEL)
			{
					/* Does the name match our template? */

				if(MatchBuffer(Buffer,TermMenu[i] . nm_Label))
				{
					HandleMenuCode((ULONG)TermMenu[i] . nm_UserData,NULL);

					Results[0] = RC_OK;

					break;
				}
			}
		}

		DeleteMatchBuffer(Buffer);
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_NO_FREE_STORE;
	}

	return(NULL);
}

STRPTR
RexxCapture(struct RexxPkt *Pkt)
{
	enum	{	ARG_CAPTURE_TO,ARG_CAPTURE_NAME };

	if(!Stricmp(Args[ARG_CAPTURE_TO],"PRINTER"))
	{
		if(!PrinterCapture)
			OpenPrinterCapture(FALSE);
	}
	else
	{
		if(!Stricmp(Args[ARG_CAPTURE_TO],"FILE"))
		{
			if(FileCapture)
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_OBJECT_IN_USE;
			}
			else
			{
				if(Args[ARG_CAPTURE_NAME])
				{
					if(FileCapture = BufferOpen(Args[ARG_CAPTURE_NAME],"a"))
						strcpy(CaptureName,Args[ARG_CAPTURE_NAME]);
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
				}
				else
				{
					UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH],
								*DummyChar;
					struct FileRequester	*FileRequest;

					if(!CaptureName[0])
					{
						strcpy(CaptureName,Config -> CaptureConfig -> CapturePath);

						if(!AddPart(CaptureName,LocaleString(MSG_DIALPANEL_CAPTURE_NAME_TXT),MAX_FILENAME_LENGTH))
							CaptureName[0] = 0;
					}

					strcpy(DummyBuffer,CaptureName);

					DummyChar = PathPart(DummyBuffer);

					*DummyChar = 0;

					BlockWindows();

					if(FileRequest = GetFile(Window,LocaleString(MSG_TERMMAIN_CAPTURE_TO_DISK_TXT),DummyBuffer,FilePart(CaptureName),DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_OPEN_TXT),FALSE))
					{
						BYTE Continue;

						if(GetFileSize(DummyBuffer))
						{
							Continue = TRUE;

							switch(MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FILE_ALREADY_EXISTS_TXT),LocaleString(MSG_GLOBAL_CREATE_APPEND_CANCEL_TXT),DummyBuffer))
							{
								case 1:

									FileCapture = BufferOpen(DummyBuffer,"w");
									break;

								case 2:

									FileCapture = BufferOpen(DummyBuffer,"a");
									break;

								case 0:

									Results[0] = RC_WARN;
									Continue = FALSE;
									break;
							}
						}
						else
						{
							Continue = TRUE;

							FileCapture = BufferOpen(DummyBuffer,"w");
						}

						if(Continue)
						{
							if(!FileCapture)
							{
								MyEasyRequest(Window,LocaleString(MSG_GLOBAL_ERROR_OPENING_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),DummyBuffer);

								Results[0] = RC_ERROR;
								Results[1] = IoErr();
							}
							else
							{
								strcpy(CaptureName,DummyBuffer);

								CheckItem(MEN_CAPTURE_TO_FILE,TRUE);
							}
						}

						FreeAslRequest(FileRequest);
					}

					ReleaseWindows();
				}
			}
		}
		else
		{
			Results[0] = RC_ERROR;
			Results[1] = ERROR_REQUIRED_ARG_MISSING;
		}
	}

	ConOutputUpdate();

	Forbid();

	CheckItem(MEN_CAPTURE_TO_FILE,		FileCapture != NULL);
	CheckItem(MEN_CAPTURE_TO_PRINTER,	PrinterCapture != NULL);

	Permit();

	return(NULL);
}

STRPTR
RexxClear(struct RexxPkt *Pkt)
{
	enum	{	ARG_CLEAR_FROM,ARG_CLEAR_FORCE };

	if(!Stricmp(Args[ARG_CLEAR_FROM],"BUFFER"))
	{
		if(Lines)
		{
			if(Args[ARG_CLEAR_FORCE])
			{
				FreeBuffer();

				TerminateBuffer();
			}
			else
			{
				BlockWindows();

				if(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
				{
					FreeBuffer();

					TerminateBuffer();
				}
				else
					Results[0] = RC_WARN;

				ReleaseWindows();
			}
		}
	}
	else
	{
		WORD ListIndex;

		if((ListIndex = ToList(Args[ARG_CLEAR_FROM])) != -1)
			ClearGenericList(GenericListTable[ListIndex]);
		else
		{
			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_UNKNOWN_LIST;
		}
	}

	return(NULL);
}

STRPTR
RexxClearScreen(struct RexxPkt *Pkt)
{
	if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
		XEmulatorClearConsole(XEM_IO);
	else
	{
		DropMarker();

		ConBypass("\033[2J\033[H",-1);
	}

	return(NULL);
}

STRPTR
RexxClose(struct RexxPkt *Pkt)
{
	enum	{	ARG_CLOSE_FROM };

	STATIC STRPTR ValidArgs[3] =
	{
		"PRINTER",
		"FILE",
		"ALL"
	};

	WORD i;

	for(i = 0 ; i < 3 ; i++)
	{
		if(!Stricmp(Args[ARG_CLOSE_FROM],ValidArgs[i]))
		{
			if(i == 0 || i == 2)
			{
				if(PrinterCapture)
					ClosePrinterCapture(TRUE);
			}

			if(i == 1 || i == 2)
			{
				if(FileCapture)
				{
					BufferClose(FileCapture);

					CheckItem(MEN_CAPTURE_TO_FILE,FALSE);

					FileCapture = NULL;

					if(!GetFileSize(CaptureName))
						DeleteFile(CaptureName);
					else
					{
						AddProtection(CaptureName,FIBF_EXECUTE);

						if(Config -> MiscConfig -> CreateIcons)
							AddIcon(CaptureName,FILETYPE_TEXT,TRUE);
					}

					ConOutputUpdate();
				}
			}

			return(NULL);
		}
	}

	Results[0] = RC_ERROR;
	Results[1] = ERROR_TOO_MANY_ARGS;

	return(NULL);
}

STRPTR
RexxCloseDevice(struct RexxPkt *Pkt)
{
	ClearSerial();

	DeleteSerial();

	return(NULL);
}

STRPTR
RexxCloseRequester(struct RexxPkt *Pkt)
{
	if(ThisProcess)
		Signal(ThisProcess,SIG_BREAK);
	else
		Results[0] = RC_WARN;

	return(NULL);
}

STRPTR
RexxDeactivate(struct RexxPkt *Pkt)
{
	Forbid();

	if(Window)
		DoIconify = TRUE;

	Permit();

	return(NULL);
}

STRPTR
RexxDial(struct RexxPkt *Pkt)
{
	enum	{	ARG_SYNC,ARG_DIAL_NUM };

	struct PhoneNode	*DialNode;
	struct GenericList	*List;

	if(Args[ARG_DIAL_NUM])
	{
		struct List *LocalList;

		if(LocalList = (struct List *)AllocVecPooled(sizeof(struct List),MEMF_ANY))
		{
			LONG Len = strlen(Args[ARG_DIAL_NUM]);

			NewList(LocalList);

			if(DialNode = (struct PhoneNode *)AllocVecPooled(sizeof(struct PhoneNode) + Len + 1,MEMF_ANY | MEMF_CLEAR))
			{
				DialNode -> VanillaNode . ln_Name = (STRPTR)(DialNode + 1);

				strcpy(DialNode -> VanillaNode . ln_Name,Args[ARG_DIAL_NUM]);

				AddTail(LocalList,&DialNode -> VanillaNode);

				FreeDialList(TRUE);

				DialList = LocalList;
			}
			else
			{
				FreeVecPooled(LocalList);

				Results[0] = RC_ERROR;
				Results[1] = ERROR_NO_FREE_STORE;

				return(NULL);
			}
		}
	}
	else
	{
		if(GenericListCount(List = GenericListTable[GLIST_DIAL]))
		{
			struct DialNode *Node = (struct DialNode *)FirstGenericListNode(List);

			if(Node)
			{
				LONG Len;

				if(!DialList)
				{
					if(DialList = (struct List *)AllocVecPooled(sizeof(struct List),MEMF_ANY | MEMF_CLEAR))
						NewList(DialList);
				}

				if(DialList)
				{
					while(Node)
					{
						if(Node -> Entry)
							Len = 0;
						else
							Len = strlen(Node -> Node . ln_Name) + 1;

						if(DialNode = (struct PhoneNode *)AllocVecPooled(sizeof(struct PhoneNode) + Len,MEMF_ANY | MEMF_CLEAR))
						{
							if(Node -> Entry)
								DialNode -> Entry = Node -> Entry;
							else
							{
								DialNode -> VanillaNode . ln_Name = (STRPTR)(DialNode + 1);

								strcpy(DialNode -> VanillaNode . ln_Name,Node -> Node . ln_Name);
							}

							AddTail(DialList,&DialNode -> VanillaNode);
						}
						else
						{
							FreeDialList(FALSE);

							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;

							return(NULL);
						}

						Node = (struct DialNode *)NextGenericListNode(List);
					}
				}
			}
		}
	}

	if(DialList)
	{
		if(DialList -> lh_Head -> ln_Succ)
		{
			DoDial = DIAL_LIST;

			Forbid();

			if(!DialMsg && Args[ARG_SYNC])
			{
				DialMsg = Pkt -> RexxMsg;

				Pkt -> RexxMsg = NULL;
			}

			Permit();
		}
		else
		{
			FreeDialList(FALSE);

			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_LIST_IS_ALREADY_EMPTY;
		}
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_NO_FREE_STORE;
	}

	return(NULL);
}

STRPTR
RexxDelay(struct RexxPkt *Pkt)
{
	enum	{	ARG_DELAY_MICROSECONDS,ARG_DELAY_SECONDS,ARG_DELAY_MINUTES,ARG_DELAY_QUIET };

	LONG	Seconds = 0,
		Micros;
	ULONG	Signals;
	BYTE	Quiet;

	if(Args[ARG_DELAY_QUIET] || !ReadRequest || !WriteRequest)
		Quiet = TRUE;
	else
		Quiet = FALSE;

	if(Args[ARG_DELAY_MINUTES])
		Seconds += 60 * (*(LONG *)Args[ARG_DELAY_MINUTES]);

	if(Args[ARG_DELAY_SECONDS])
		Seconds += *(LONG *)Args[ARG_DELAY_SECONDS];

	if(Args[ARG_DELAY_MICROSECONDS])
		Micros = *(LONG *)Args[ARG_DELAY_MICROSECONDS];
	else
		Micros = 0;

	if(Seconds || Micros)
	{
		StartTime(Seconds,Micros);

		BlockWindows();

		if(Marking)
			DropMarker();

		if(Quiet)
			Signals = NULL;
		else
		{
			if(DataHold)
			{
				ConProcess(DataHold,DataSize);

				Status = STATUS_READY;

				DataHold = NULL;

				RestartSerial(TRUE);
			}

			Signals = CheckSignal(SIG_SERIAL);
		}

		FOREVER
		{
			if(Signals & SIG_SERIAL)
			{
				if(!WaitSerialRead())
				{
					LONG Length;

					BytesIn++;

					if(Translate_CR_LF)
						Length = (* Translate_CR_LF)(ReadBuffer,1);
					else
						Length = 1;

					if(Length)
					{
						ConProcess(ReadBuffer,Length);

						Status = STATUS_READY;
					}

						/* Check how many bytes are still in
						 * the serial buffer.
						 */

					if(Length = GetSerialWaiting())
					{
						if(Length > SerialBufferSize)
							Length = SerialBufferSize;

						if(Length > Config -> SerialConfig -> Quantum)
							Length = Config -> SerialConfig -> Quantum;

						if(!DoSerialRead(ReadBuffer,Length))
						{
							BytesIn += Length;

							if(Translate_CR_LF)
								Length = (* Translate_CR_LF)(ReadBuffer,Length);

								/* Send the data to the console. */

							if(Length)
								ConProcess(ReadBuffer,Length);

							Status = STATUS_READY;
						}
					}
				}

				RestartSerial(TRUE);
			}

			if(Signals & SIG_BREAK)
			{
				StopTime();

				Results[0] = RC_WARN;

				break;
			}

			if(Signals & SIG_TIMER)
			{
				WaitIO(TimeRequest);

				break;
			}

			if(Quiet)
				Signals = Wait(SIG_TIMER | SIG_BREAK);
			else
				Signals = Wait(SIG_TIMER | SIG_BREAK | SIG_SERIAL);
		}

		ReleaseWindows();
	}

	return(NULL);
}

STRPTR
RexxDuplex(struct RexxPkt *Pkt)
{
	enum	{	ARG_DUPLEX_FULL,ARG_DUPLEX_HALF };

	BYTE Mode;

	if(Args[ARG_DUPLEX_FULL])
		Mode = DUPLEX_FULL;

	if(Args[ARG_DUPLEX_HALF])
		Mode = DUPLEX_HALF;

	if(Config -> SerialConfig -> Duplex != Mode)
	{
		Config -> SerialConfig -> Duplex = Mode;

		UpdateRequired = TRUE;

		ConfigChanged = TRUE;
	}

	return(NULL);
}

STRPTR
RexxFault(struct RexxPkt *Pkt)
{
	enum	{	ARG_FAULT_CODE };

	LONG	Code = *(LONG *)Args[ARG_FAULT_CODE];
	UBYTE	RexxResultString[256];
	STRPTR	Result;

	if(Code >= ERR10_001 && Code <= ERR10_048)
		Result = LocaleString(MSG_AREXX_SYSERR10_001_TXT + Code - ERR10_001);
	else
	{
		if(Code >= TERMERROR_NO_DATA_TO_PROCESS && Code <= TERMERROR_WRONG_LIST)
			Result = LocaleString(MSG_AREXX_HOSTERR_000_TXT + Code - TERMERROR_NO_DATA_TO_PROCESS);
		else
		{
			Fault(Code,"",RexxResultString,256);

			Result = &RexxResultString[2];
		}
	}

	return(CreateResult(Result,Results));
}

STRPTR
RexxGetClip(struct RexxPkt *Pkt)
{
	enum	{	ARG_GETCLIP_UNIT };

	struct IFFHandle	*Handle;
	STRPTR			 ResultBuffer = NULL;

	if(Handle = AllocIFF())
	{
		if(Args[ARG_GETCLIP_UNIT])
			Handle -> iff_Stream = (ULONG)OpenClipboard(*(LONG *)Args[ARG_GETCLIP_UNIT]);
		else
			Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit);

		if(Handle -> iff_Stream)
		{
			InitIFFasClip(Handle);

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunk(Handle,ID_FTXT,ID_CHRS))
				{
					if(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						struct ContextNode *ContextNode;

						ContextNode = CurrentChunk(Handle);

						if(ContextNode -> cn_Type == ID_FTXT && ContextNode -> cn_Size > 0)
						{
							STRPTR Result;

							if(Result = (STRPTR)AllocVecPooled(ContextNode -> cn_Size,MEMF_ANY))
							{
								if(ReadChunkBytes(Handle,Result,ContextNode -> cn_Size) == ContextNode -> cn_Size)
									ResultBuffer = CreateArgstring(Result,ContextNode -> cn_Size);

								FreeVecPooled(Result);
							}
							else
							{
								Results[0] = RC_ERROR;
								Results[1] = ERROR_NO_FREE_STORE;
							}
						}
						else
							Results[0] = RC_WARN;
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_OBJECT_NOT_FOUND;
					}
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_OBJECT_NOT_FOUND;
				}

				CloseIFF(Handle);
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_OBJECT_NOT_FOUND;
			}

			CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
		}
		else
		{
			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_UNIT_NOT_AVAILABLE;
		}

		FreeIFF(Handle);
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_OBJECT_NOT_FOUND;
	}

	return(ResultBuffer);
}

STRPTR
RexxGoOnline(struct RexxPkt *Pkt)
{
	if(!Online)
	{
		ObtainSemaphore(&OnlineSemaphore);

		WasOnline		= Online;
		Online			= TRUE;

		ReleaseSemaphore(&OnlineSemaphore);

		BaudCount		= 0;
		BaudBuffer[0]		= 0;
		BaudPending		= FALSE;
		CurrentPay		= 0;

		ObtainSemaphore(&PatternSemaphore);

		ChosenEntry		= NULL;
		ChosenPattern		= NULL;

		ReleaseSemaphore(&PatternSemaphore);

		Password[0]		= 0;
		UserName[0]		= 0;
		SendStartup		= FALSE;
		LimitCount		= -1;
		CurrentBBSName[0]	= 0;
		CurrentBBSComment[0]	= 0;
		CurrentBBSNumber[0]	= 0;

		Forbid();

		SetDialMenu(FALSE);

		Permit();
	}

	return(NULL);
}

STRPTR
RexxHangup(struct RexxPkt *Pkt)
{
	if(!WriteRequest)
	{
		Results[0] = RC_WARN;

		return(NULL);
	}

	BlockWindows();

	HangUp();

		/* We are no longer online. */

	ObtainSemaphore(&OnlineSemaphore);

	WasOnline	= Online;
	Online		= FALSE;

	ReleaseSemaphore(&OnlineSemaphore);

		/* Reset time limit. */

	LimitCount = -1;

		/* Clear the password. */

	Password[0]		= 0;
	UserName[0]		= 0;

	CurrentBBSName[0]	= 0;
	CurrentBBSComment[0]	= 0;
	CurrentBBSNumber[0]	= 0;

		/* Note the  last action. */

	LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_HANG_UP_TXT));

	ReleaseWindows();

		/* Execute logoff macro. */

	if(WasOnline && Config -> CommandConfig -> LogoffMacro[0])
		SerialCommand(Config -> CommandConfig -> LogoffMacro);

		/* Update the logfile. */

	StopCall(FALSE);

		/* Don't execute the logoff macro twice. */

	ObtainSemaphore(&OnlineSemaphore);

	WasOnline = FALSE;

	ReleaseSemaphore(&OnlineSemaphore);

		/* Enable the dialing functions. */

	SetDialMenu(TRUE);

	if(Config -> ModemConfig -> RedialAfterHangup)
	{
		if(DialList)
		{
			if(DialList -> lh_Head -> ln_Succ)
				DoDial = DIAL_REDIAL;
		}
	}

	ObtainSemaphore(&PatternSemaphore);

	ChosenEntry	= NULL;
	ChosenPattern	= NULL;

	ReleaseSemaphore(&PatternSemaphore);

	return(NULL);
}

STRPTR
RexxHelp(struct RexxPkt *Pkt)
{
	enum	{	ARG_HELP_COMMAND,ARG_HELP_PROMPT };

	if(Args[ARG_HELP_PROMPT])
		GuideSetup();
	else
	{
		WORD i;

		for(i = 0 ; i < CommandTableSize ; i++)
		{
			if(!Stricmp(Args[ARG_HELP_COMMAND],CommandTable[i] . Name))
			{
				if(CommandTable[i] . Arguments)
					return(CreateResult(CommandTable[i] . Arguments,Results));
				else
					return(CreateResult(",",Results));
			}
		}

		Results[0] = RC_ERROR;
		Results[1] = ERROR_OBJECT_NOT_FOUND;
	}

	return(NULL);
}

STRPTR
RexxOpen(struct RexxPkt *Pkt)
{
	enum	{	ARG_OPEN_NAME,ARG_OPEN_TO };

	WORD Index = ToConfig(Args[ARG_OPEN_TO]);

	if(Index == -1 || Index > DATATYPE_PHONEBOOK)
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_OBJECT_NOT_FOUND;
	}
	else
	{
		UBYTE	DummyBuffer[MAX_FILENAME_LENGTH];
		STRPTR	FileName;

		if(Args[ARG_OPEN_NAME])
			FileName = Args[ARG_OPEN_NAME];
		else
		{
			STRPTR			 Title;
			struct FileRequester	*FileRequest;

			FileName = NULL;

			switch(Index)
			{
				case DATATYPE_TRANSLATIONS:

					Title = LocaleString(MSG_PHONEPANEL_SELECT_TRANSLATION_TXT);
					break;

				case DATATYPE_FUNCTIONKEYS:

					Title = LocaleString(MSG_PHONEPANEL_SELECT_KEYBOARD_MACROS_TXT);
					break;

				case DATATYPE_CURSORKEYS:

					Title = LocaleString(MSG_PHONEPANEL_SELECT_CURSOR_KEYS_TXT);
					break;

				case DATATYPE_FASTMACROS:

					Title = LocaleString(MSG_PHONEPANEL_SELECT_FAST_MACROS_TXT);
					break;

				case DATATYPE_HOTKEYS:

					Title = LocaleString(MSG_HOTKEYPANEL_LOAD_HOTKEYS_TXT);
					break;

				case DATATYPE_SPEECH:

					Title = LocaleString(MSG_SPEECHPANEL_LOAD_SPEECH_SETTINGS_TXT);
					break;

				case DATATYPE_SOUND:

					Title = LocaleString(MSG_SOUNDPANEL_LOAD_SOUNDS_TXT);
					break;

				case DATATYPE_BUFFER:

					Title = LocaleString(MSG_TERMMAIN_LOAD_BUFFER_TXT);
					break;

				case DATATYPE_CONFIGURATION:

					Title = LocaleString(MSG_TERMMAIN_OPEN_PREFERENCES_TXT);
					break;

				case DATATYPE_PHONEBOOK:

					Title = LocaleString(MSG_PHONEPANEL_LOAD_PHONEBOOK_TXT);
					break;
			}

			BlockWindows();

			if(FileRequest = GetFile(Window,Title,"","",DummyBuffer,NULL,FALSE,FALSE,FALSE,"Ok",TRUE))
			{
				FileName = DummyBuffer;

				FreeAslRequest(FileRequest);
			}
			else
				Results[0] = RC_WARN;

			ReleaseWindows();
		}

		if(FileName)
		{
			if(!GetFileSize(FileName))
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_OBJECT_NOT_FOUND;

				return(NULL);
			}

			BlockWindows();

			switch(Index)
			{
				case DATATYPE_TRANSLATIONS:
				{
					struct TranslationEntry	**Send,
								**Receive = NULL;
					BYTE			Success = FALSE;

					if(Send = AllocTranslationTable())
					{
						if(Receive = AllocTranslationTable())
						{
							if(!(Success = LoadTranslationTables(FileName,Send,Receive)))
							{
								Results[0] = RC_ERROR;
								Results[1] = IoErr();
							}
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_NO_FREE_STORE;
					}

					if(!Success)
					{
						if(Send)
							FreeTranslationTable(Send);

						if(Receive)
							FreeTranslationTable(Receive);
					}
					else
					{
						strcpy(Config -> FileConfig -> TranslationFileName,FileName);

						strcpy(LastTranslation,FileName);

						FreeTranslationTable(SendTable);
						FreeTranslationTable(ReceiveTable);

						SendTable	= Send;
						ReceiveTable	= Receive;
					}
				}

				break;

				case DATATYPE_FUNCTIONKEYS:
				{
					if(!LoadMacros(FileName,MacroKeys))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						MacroChanged = FALSE;

						strcpy(Config -> FileConfig -> MacroFileName,FileName);

						strcpy(LastMacros,FileName);
					}
				}

				break;

				case DATATYPE_CURSORKEYS:
				{
					if(!ReadIFFData(FileName,CursorKeys,sizeof(struct CursorKeys),ID_KEYS))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						CursorKeysChanged = FALSE;

						strcpy(Config -> FileConfig -> CursorFileName,FileName);

						strcpy(LastCursorKeys,FileName);
					}
				}

				break;

				case DATATYPE_FASTMACROS:
				{
					if(!LoadFastMacros(FileName,&FastMacroList))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(Config -> FileConfig -> FastMacroFileName,FileName);

						strcpy(LastFastMacros,FileName);

						FastMacrosChanged = FALSE;
					}

					RefreshFastWindow(TRUE);
				}

				break;

				case DATATYPE_HOTKEYS:
				{
					if(!LoadHotkeys(FileName,&Hotkeys))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastKeys,FileName);

						HotkeysChanged = FALSE;

						SetupCx();
					}
				}

				break;

				case DATATYPE_SPEECH:
				{
					if(!ReadIFFData(FileName,&SpeechConfig,sizeof(struct SpeechConfig),ID_SPEK))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastSpeech,FileName);

						SpeechSetup();

						SpeechChanged = FALSE;
					}
				}

				break;

				case DATATYPE_SOUND:
				{
					if(!ReadIFFData(FileName,&SoundConfig,sizeof(struct SoundConfig),ID_SOUN))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastSound,FileName);

						SoundInit();

						SoundChanged = FALSE;
					}
				}

				break;

				case DATATYPE_BUFFER:
				{
					BPTR SomeFile;

					if(SomeFile = Open(FileName,MODE_OLDFILE))
					{
						LONG Len;

						LineRead(NULL,NULL,NULL);

						while((Len = LineRead(SomeFile,FileName,80)) > 0)
							CaptureParser(FileName,Len,AddLine);

						Close(SomeFile);

						BufferChanged = TRUE;
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
				}

				break;

				case DATATYPE_CONFIGURATION:
				{
					if(ReadConfig(FileName,PrivateConfig))
					{
						SwapConfig(PrivateConfig,Config);

						strcpy(FileName,LastConfig);

						ConfigSetup();

						ConfigChanged = FALSE;
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
				}

				break;

				case DATATYPE_PHONEBOOK:
				{
					if(ChosenEntry)
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_OBJECT_IN_USE;
					}
					else
					{
						if(!LoadPhonebook(FileName))
						{
							Results[0] = RC_ERROR;
							Results[1] = IoErr();
						}
						else
						{
							strcpy(LastPhone,FileName);

							PhonebookChanged = FALSE;

							RebuildMenu = TRUE;
						}
					}
				}

				break;
			}

			ReleaseWindows();
		}
		else
			Results[0] = RC_WARN;
	}

	return(NULL);
}

STRPTR
RexxOpenDevice(struct RexxPkt *Pkt)
{
	enum	{	ARG_OPENDEVICE_NAME,ARG_OPENDEVICE_UNIT };

	if(ReadRequest)
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_DEVICE_DRIVER_STILL_OPEN;
	}
	else
	{
		if(Args[ARG_OPENDEVICE_NAME])
		{
			strcpy(Config -> SerialConfig -> SerialDevice,Args[ARG_OPENDEVICE_NAME]);

			ConfigChanged = TRUE;
		}

		if(Args[ARG_OPENDEVICE_UNIT])
		{
			Config -> SerialConfig -> UnitNumber = *(LONG *)Args[ARG_OPENDEVICE_UNIT];

			ConfigChanged = TRUE;
		}

		BlockWindows();

		ReopenSerial();

		ReleaseWindows();
	}

	return(NULL);
}

STRPTR
RexxOpenRequester(struct RexxPkt *Pkt)
{
	enum	{	ARG_OPENREQUESTER_REQUESTER };

	WORD Index;

	if((Index = ToRequester(Args[ARG_OPENREQUESTER_REQUESTER])) == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_OBJECT_NOT_FOUND;
	}
	else
	{
		ULONG	Code;
		WORD	i;

		switch(Index)
		{
			case REQUESTER_SERIAL:

				Code = MEN_SERIAL;
				break;

			case REQUESTER_MODEM:

				Code = MEN_MODEM;
				break;

			case REQUESTER_SCREEN:

				Code = MEN_SCREEN;
				break;

			case REQUESTER_TERMINAL:

				Code = MEN_TERMINAL;
				break;

			case REQUESTER_EMULATION:

				Code = MEN_SET_EMULATION;
				break;

			case REQUESTER_CLIPBOARD:

				Code = MEN_CLIPBOARD;
				break;

			case REQUESTER_CAPTURE:

				Code = MEN_CAPTURE;
				break;

			case REQUESTER_COMMANDS:

				Code = MEN_COMMANDS;
				break;

			case REQUESTER_MISC:

				Code = MEN_MISC;
				break;

			case REQUESTER_PATH:

				Code = MEN_PATH;
				break;

			case REQUESTER_TRANSFER:

				Code = MEN_TRANSFER;
				break;

			case REQUESTER_TRANSLATIONS:

				Code = MEN_TRANSLATION;
				break;

			case REQUESTER_FUNCTIONKEYS:

				Code = MEN_MACROS;
				break;

			case REQUESTER_CURSORKEYS:

				Code = MEN_CURSORKEYS;
				break;

			case REQUESTER_FASTMACROS:

				Code = MEN_FAST_MACROS;
				break;

			case REQUESTER_HOTKEYS:

				Code = MEN_HOTKEYS;
				break;

			case REQUESTER_SPEECH:

				Code = MEN_SPEECH;
				break;

			case REQUESTER_SOUND:

				Code = MEN_SOUND;
				break;


			case REQUESTER_PHONE:

				Code = MEN_PHONEBOOK;
				break;
		}

			/* Scan the menu list... */

		for(i = 0 ; TermMenu[i] . nm_Type != NM_END ; i++)
		{
				/* Did we get a valid name string? */

			if(TermMenu[i] . nm_Label != NM_BARLABEL)
			{
				if((ULONG)TermMenu[i] . nm_UserData == Code)
				{
					HandleMenuCode((ULONG)TermMenu[i] . nm_UserData,NULL);

					break;
				}
			}
		}
	}

	return(NULL);
}

STRPTR
RexxParity(struct RexxPkt *Pkt)
{
	enum	{	ARG_PARITY_EVEN,ARG_PARITY_ODD,ARG_PARITY_NONE,ARG_PARITY_MARK,ARG_PARITY_SPACE };

	BYTE Mode;

	if(Args[ARG_PARITY_EVEN])
		Mode = PARITY_EVEN;

	if(Args[ARG_PARITY_ODD])
		Mode = PARITY_ODD;

	if(Args[ARG_PARITY_NONE])
		Mode = PARITY_NONE;

	if(Args[ARG_PARITY_MARK])
		Mode = PARITY_MARK;

	if(Args[ARG_PARITY_SPACE])
		Mode = PARITY_SPACE;

	if(Config -> SerialConfig -> Parity != Mode)
	{
		Config -> SerialConfig -> Parity = Mode;

		UpdateRequired = TRUE;

		ConfigChanged = TRUE;
	}

	return(NULL);
}

STRPTR
RexxPasteClip(struct RexxPkt *Pkt)
{
	enum	{	ARG_PASTECLIP_UNIT };

	struct DataMsg	*Msg;
	LONG		 Unit;

	if(Args[ARG_PASTECLIP_UNIT])
		Unit = *(LONG *)Args[ARG_PASTECLIP_UNIT];
	else
		Unit = Config -> ClipConfig -> ClipboardUnit;

	if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg)))
	{
		Msg -> Type = DATAMSGTYPE_WRITECLIP;
		Msg -> Size = Unit;

		PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_NO_FREE_STORE;
	}

	return(NULL);
}

STRPTR
RexxPrint(struct RexxPkt *Pkt)
{
	enum	{	ARG_PRINT_FROM,ARG_PRINT_TO,ARG_PRINT_SERIAL,ARG_PRINT_MODEM,ARG_PRINT_SCREEN,
			ARG_PRINT_TERMINAL,ARG_PRINT_USER,ARG_PRINT_COMMENT,ARG_PRINT_SIZE,
			ARG_PRINT_DATE,ARG_PRINT_BITS };

	WORD	Index,Mode = -1;
	ULONG	Flags = NULL;

	if(Args[ARG_PRINT_SERIAL])
		Flags |= PRINT_SERIAL;

	if(Args[ARG_PRINT_MODEM])
		Flags |= PRINT_MODEM;

	if(Args[ARG_PRINT_SCREEN])
		Flags |= PRINT_SCREEN;

	if(Args[ARG_PRINT_TERMINAL])
		Flags |= PRINT_TERMINAL;

	if(Args[ARG_PRINT_USER])
		Flags |= PRINT_USERNAME;

	if(Args[ARG_PRINT_COMMENT])
		Flags |= PRINT_COMMENT;

	if(Args[ARG_PRINT_SIZE])
		Flags |= PRINT_SIZE;

	if(Args[ARG_PRINT_DATE])
		Flags |= PRINT_DATE;

	if(Args[ARG_PRINT_BITS])
		Flags |= PRINT_BITS;

	if((Index = ToList(Args[ARG_PRINT_FROM])) == -1)
	{
		if(!Stricmp(Args[ARG_PRINT_FROM],"SCREENTEXT"))
		{
			if(!RasterEnabled)
			{
				Results[0] = RC_ERROR;
				Results[1] = TERMERROR_NO_DATA_TO_PROCESS;

				return(NULL);
			}
			else
				Mode = 0;
		}

		if(!Stricmp(Args[ARG_PRINT_FROM],"CLIPBOARD"))
			Mode = 1;

		if(!Stricmp(Args[ARG_PRINT_FROM],"BUFFER"))
			Mode = 2;
	}

	if(Index == -1 && Mode == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_UNKNOWN_LIST;
	}
	else
	{
		BYTE	Continue = TRUE;
		LONG	Error = 0;
		BPTR	File;
		STRPTR	Name;

		if(Args[ARG_PRINT_TO])
			Name = Args[ARG_PRINT_TO];
		else
			Name = "PRT:";

		if(File = Open(Name,MODE_NEWFILE))
		{
			struct Window		*ReqWindow;
			struct EasyStruct	 Easy;

			Easy . es_StructSize	= sizeof(struct EasyStruct);
			Easy . es_Flags		= NULL;
			Easy . es_Title		= (UBYTE *)LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);
			Easy . es_GadgetFormat	= (UBYTE *)LocaleString(MSG_PRINT_STOP_TXT);
			Easy . es_TextFormat	= (UBYTE *)LocaleString(MSG_GLOBAL_PRINTING_TXT);

			BlockWindows();

			if(ReqWindow = BuildEasyRequest(Window,&Easy,NULL))
			{
				switch(Index)
				{
					case GLIST_DIAL:
					{
						struct GenericList *List = GenericListTable[Index];

						ObtainSemaphore(&List -> ListSemaphore);

						if(List -> ListHeader . mlh_Head -> mln_Succ)
						{
							struct DialNode *TempNode;

							for(TempNode = (struct DialNode *)List -> ListHeader . mlh_Head ; Continue && TempNode -> Node . ln_Succ ; TempNode = (struct DialNode *)TempNode -> Node . ln_Succ)
							{
								if(TempNode -> Entry)
									Continue = PrintEntry(File,ReqWindow,TRUE,&Error,TempNode -> Entry,Flags);
								else
									Continue = PrintText(File,ReqWindow,&Error,"\n\"???\" (%s)",TempNode -> Node . ln_Name);
							}
						}

						ReleaseSemaphore(&List -> ListSemaphore);
					}

					break;

					case GLIST_UPLOAD:
					case GLIST_DOWNLOAD:
					{
						struct GenericList *List = GenericListTable[Index];

						ObtainSemaphore(&List -> ListSemaphore);

						if(List -> ListHeader . mlh_Head -> mln_Succ)
						{
							struct Node *TempNode;

							for(TempNode = (struct Node *)List -> ListHeader . mlh_Head ; Continue && TempNode -> ln_Succ ; TempNode = TempNode -> ln_Succ)
								Continue = PrintFileInformation(File,ReqWindow,&Error,TempNode -> ln_Name,Flags);
						}

						ReleaseSemaphore(&List -> ListSemaphore);
					}

					break;

					case GLIST_WAIT:
					{
						struct GenericList *List = GenericListTable[Index];

						ObtainSemaphore(&List -> ListSemaphore);

						if(List -> ListHeader . mlh_Head -> mln_Succ)
						{
							struct Node *TempNode;

							for(TempNode = (struct Node *)List -> ListHeader . mlh_Head ; Continue && TempNode -> ln_Succ ; TempNode = TempNode -> ln_Succ)
								Continue = PrintText(File,ReqWindow,&Error,"%s\n",TempNode -> ln_Name);
						}

						ReleaseSemaphore(&List -> ListSemaphore);
					}

					break;

					default:
					{
						switch(Mode)
						{
							case 0:

								Continue = PrintScreen(File,ReqWindow,&Error);
								break;

							case 1:

								Continue = PrintClip(File,ReqWindow,&Error);
								break;

							case 2:

								Continue = PrintBuffer(File,ReqWindow,&Error);
								break;
						}

						break;
					}

					break;
				}

				FreeSysRequest(ReqWindow);
			}

			ReleaseWindows();

			Close(File);
		}
		else
			Error = IoErr();

		if(Error)
		{
			Results[0] = RC_ERROR;
			Results[1] = Error;
		}
		else
		{
			if(!Continue)
				Results[0] = RC_WARN;
		}
	}

	return(NULL);
}

STRPTR
RexxProcessIO(struct RexxPkt *Pkt)
{
	enum	{	ARG_PROCESSIO_ON,ARG_PROCESSIO_OFF };

	Forbid();

	if(Args[ARG_PROCESSIO_ON])
		ProcessIO = TRUE;

	if(Args[ARG_PROCESSIO_OFF])
		ProcessIO = FALSE;

	Permit();

	return(NULL);
}

STRPTR
RexxProtocol(struct RexxPkt *Pkt)
{
	enum	{	ARG_PROTOCOL_NONE,ARG_PROTOCOL_RTSCTS,ARG_PROTOCOL_RTSCTSDTR };

	BYTE Mode;

	if(Args[ARG_PROTOCOL_NONE])
		Mode = HANDSHAKING_NONE;

	if(Args[ARG_PROTOCOL_RTSCTS])
		Mode = HANDSHAKING_RTSCTS;

	if(Args[ARG_PROTOCOL_RTSCTSDTR])
		Mode = HANDSHAKING_RTSCTS_DSR;

	if(Config -> SerialConfig -> HandshakingProtocol != Mode)
	{
		Config -> SerialConfig -> HandshakingProtocol = Mode;

		UpdateRequired = TRUE;

		ConfigChanged = TRUE;
	}

	return(NULL);
}

STRPTR
RexxPutClip(struct RexxPkt *Pkt)
{
	enum	{	ARG_PUTCLIP_UNIT,ARG_PUTCLIP_TEXT };

	struct IFFHandle	*Handle;
	LONG			 Unit;
	BYTE			 Success = FALSE;

	if(Args[ARG_PUTCLIP_UNIT])
		Unit = *(LONG *)Args[ARG_PUTCLIP_UNIT];
	else
		Unit = Config -> ClipConfig -> ClipboardUnit;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = (ULONG)OpenClipboard(Unit))
		{
			InitIFFasClip(Handle);

			if(!OpenIFF(Handle,IFFF_WRITE))
			{
				if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
				{
					if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
					{
						LONG Len = strlen(Args[ARG_PUTCLIP_TEXT]);

						if(WriteChunkBytes(Handle,Args[ARG_PUTCLIP_TEXT],Len) == Len)
						{
							if(!PopChunk(Handle))
								Success = TRUE;
						}
					}
				}

				if(PopChunk(Handle))
					Success = FALSE;

				CloseIFF(Handle);
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_NO_FREE_STORE;
			}

			CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
		}
		else
		{
			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_UNIT_NOT_AVAILABLE;
		}

		FreeIFF(Handle);
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_NO_FREE_STORE;
	}

	if(!Success && !Results[0])
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_CLIPBOARD_ERROR;
	}

	return(NULL);
}

STRPTR
RexxQuit(struct RexxPkt *Pkt)
{
	enum	{	ARG_QUIT_FORCE };

	struct DataMsg *Msg;

	if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg)))
	{
		Pkt -> RexxMsg -> rm_Result1 = RC_WARN;
		Pkt -> RexxMsg -> rm_Result2 = 0;

		ReplyMsg(Pkt -> RexxMsg);

		Pkt -> RexxMsg = NULL;

		Msg -> Type = DATAMSGTYPE_MENU;
		Msg -> Size = MEN_QUIT;

		if(Args[ARG_QUIT_FORCE])
			Msg -> Data = (APTR)(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT);
		else
			Msg -> Data = NULL;

		PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_NO_FREE_STORE;
	}

	return(NULL);
}

STATIC STRPTR	RexxReadBuffer;
STATIC LONG	RexxReadIndex,
		RexxReadLen;
STATIC BYTE	RexxReadDone,
		RexxReadEcho;

STATIC BOOLEAN
RexxReadBypassVerbatim(STRPTR Buffer,LONG Size)
{
	while(Size-- > 0)
	{
		switch(*Buffer)
		{
			case '\n':

				break;

			case '\r':

				RexxReadDone = TRUE;
				break;

			case '\b':
			case '\30':

				while(RexxReadIndex > 0)
				{
					if(RexxReadEcho)
						SerWriteVerbatim("\b",1,FALSE);

					RexxReadIndex--;
				}

				break;

			default:

				if(RexxReadIndex < RexxReadLen && ((*Buffer >= ' ' && *Buffer < 127) || *Buffer >= 160 || Config -> TerminalConfig -> FontMode == FONT_IBM))
				{
					RexxReadBuffer[RexxReadIndex++] = *Buffer;

					if(RexxReadEcho)
						SerWriteVerbatim(Buffer,1,FALSE);
				}

				break;
		}

		Buffer++;
	}

	return(FALSE);
}

STATIC BOOLEAN
RexxReadBypassTranslate(STRPTR Buffer,LONG Size)
{
	struct TranslationHandle	Handle;
	UBYTE				Temp;

	while(Size-- > 0)
	{
		TranslateSetup(&Handle,Buffer,1,&Temp,1,ReceiveTable);

		while(!RexxReadDone && TranslateBuffer(&Handle))
		{
			switch(Temp)
			{
				case '\n':

					break;

				case '\r':

					RexxReadDone = TRUE;

					break;

				case '\b':
				case '\30':

					while(RexxReadIndex > 0)
					{
						if(RexxReadEcho)
							SerWriteVerbatim("\b",1,FALSE);

						RexxReadIndex--;
					}

					break;

				default:

					if(RexxReadIndex < RexxReadLen && ((Temp >= ' ' && Temp < 127) || Temp >= 160 || Config -> TerminalConfig -> FontMode == FONT_IBM))
					{
						RexxReadBuffer[RexxReadIndex++] = Temp;

						if(RexxReadEcho)
							SerWriteVerbatim(&Temp,1,FALSE);
					}

					break;
			}
		}

		Buffer++;
	}

	return(FALSE);
}

STRPTR
RexxRead(struct RexxPkt *Pkt)
{
	enum	{	ARG_READ_NUM,ARG_READ_CR,ARG_READ_NOECHO,ARG_READ_VERBATIM,ARG_READ_PROMPT };

	LONG Len,BytesRead = 0;

	if(!ReadRequest || !WriteRequest)
	{
		Results[0] = RC_WARN;

		return(NULL);
	}

	if(Args[ARG_READ_NUM])
	{
		Len = *(LONG *)Args[ARG_READ_NUM] + 1;

		if(Len < 1)
		{
			Results[0] = RC_ERROR;
			Results[1] = ERROR_BAD_NUMBER;

			return(NULL);
		}

		if(Len > MAX_RESULT_LEN + 1)
			Len = MAX_RESULT_LEN + 1;
	}
	else
		Len = MAX_RESULT_LEN + 1;

	if(Args[ARG_READ_PROMPT])
		SerialCommand(Args[ARG_READ_PROMPT]);

	if(Marking)
		DropMarker();

	BlockWindows();

	if(Args[ARG_READ_CR])
	{
		Forbid();

		LT_UnlockWindow(Window);

		Window -> Flags |= WFLG_RMBTRAP;

		Permit();

		NormalCursor();
	}

	Status = STATUS_READY;

	if(Args[ARG_READ_VERBATIM] || !ReceiveTable)
	{
		if(Args[ARG_READ_CR])
		{
			ULONG	 Signals,SignalMask = SIG_SERIAL | SIG_TIMER | SIG_BREAK;
			UBYTE	*Char = ReadBuffer;
			BYTE	 Echo,Done = FALSE;
			LONG	 Index = 0;
			STRPTR	 Buffer;

			if(Buffer = (STRPTR)AllocVecPooled(Len,MEMF_ANY))
			{
				if(Args[ARG_READ_NOECHO])
					Echo = FALSE;
				else
					Echo = TRUE;

				RexxReadEcho = Echo;

				if(RexxTimeoutVal)
					StartTime(RexxTimeoutVal,0);

				if(DataHold)
				{
					while(DataSize-- > 0)
					{
						Char = DataHold++;

						switch(*Char)
						{
							case '\n':

								break;

							case '\r':

								Done = TRUE;

								if(Echo)
									SerWrite(ReadBuffer,1);

								break;

							case '\b':

								if(Index > 0)
								{
									Index--;

									if(Echo)
										SerWrite(ReadBuffer,1);
								}

								break;

							case '\30':

								if(Echo)
								{
									while(Index > 0)
									{
										Index--;

										SerWrite("\b",1);
									}
								}
								else
									Index = 0;

								break;

							default:

								if(Index < Len && ((*Char >= ' ' && *Char < 127) || *Char >= 160 || Config -> TerminalConfig -> FontMode == FONT_IBM))
								{
									Buffer[Index++] = *Char;

									if(Echo)
										SerWrite(ReadBuffer,1);
								}

								break;
						}
					}

					DataHold = NULL;

					RestartSerial(TRUE);
				}

				if(CheckSerialRead())
					Signals = SIG_SERIAL;
				else
					Signals = NULL;

				do
				{
					if(Signals & SIG_WINDOW)
					{
						SerWriteBypass = RexxReadBypassVerbatim;

						RexxReadBuffer	= Buffer;
						RexxReadIndex	= Index;
						RexxReadLen	= Len;
						RexxReadDone	= Done;

						while(HandleWindow());

						Buffer	= RexxReadBuffer;
						Index	= RexxReadIndex;
						Len	= RexxReadLen;
						Done	= RexxReadDone;

						SerWriteBypass = NULL;
					}

					if(Signals & SIG_SERIAL)
					{
						if(!WaitSerialRead())
						{
							LONG Length;

							BytesIn++;

							if(Translate_CR_LF)
								Length = (* Translate_CR_LF)(ReadBuffer,1);
							else
								Length = 1;

							while(Length--)
							{
								switch(*Char)
								{
									case '\n':

										break;

									case '\r':

										Done = TRUE;

										if(Echo)
											SerWrite(ReadBuffer,1);

										break;

									case '\b':

										if(Index > 0)
										{
											Index--;

											if(Echo)
												SerWrite(ReadBuffer,1);
										}

										break;

									case '\30':

										if(Echo)
										{
											while(Index > 0)
											{
												Index--;

												SerWrite("\b",1);
											}
										}
										else
											Index = 0;

									default:

										if(Index < Len && ((*Char >= ' ' && *Char < 127) || *Char >= 160 || Config -> TerminalConfig -> FontMode == FONT_IBM))
										{
											Buffer[Index++] = *Char;

											if(Echo)
												SerWrite(ReadBuffer,1);
										}

										break;
								}

								Char++;
							}
						}

						RestartSerial(TRUE);
					}

					if(Signals & (SIG_BREAK | SIG_TIMER))
					{
						Results[0] = RC_WARN;

						break;
					}

					if(!Done)
						Signals = Wait(SignalMask | SIG_WINDOW);
				}
				while(!Done);

				if(RexxTimeoutVal)
					StopTime();

				if(Index)
				{
					STRPTR Result;

					Buffer[Index] = 0;

					Result = CreateResult(Buffer,Results);

					if(Args[ARG_READ_CR])
					{
						Forbid();

						Window -> Flags &= ~WFLG_RMBTRAP;

						LT_LockWindow(Window);

						Permit();
					}

					ReleaseWindows();

					FreeVecPooled(Buffer);

					return(Result);
				}
				else
					Results[0] = RC_WARN;

				FreeVecPooled(Buffer);
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_NO_FREE_STORE;
			}
		}
		else
		{
			STRPTR Buffer;

			if(Buffer = (STRPTR)AllocVecPooled(Len,MEMF_ANY))
			{
				STRPTR Result;

				if(DataHold && DataSize >= Len - 1)
				{
					CopyMem(DataHold,Buffer,Len - 1);

					BytesRead = Len - 1;

					if(DataSize == Len - 1)
					{
						DataHold = NULL;

						RestartSerial(TRUE);
					}
					else
					{
						DataHold += Len - 1;
						DataSize -= Len - 1;
					}
				}
				else
				{
					ULONG Signals,SignalMask = SIG_SERIAL | SIG_TIMER | SIG_BREAK;

					ClearSerial();

					ClrSignal(SignalMask);

					if(RexxTimeoutVal)
						StartTime(RexxTimeoutVal,0);

					if(DataHold)
					{
						CopyMem(DataHold,Buffer,DataSize);

						StartSerialRead(Buffer + DataSize,Len - 1 - DataSize);

						BytesRead = DataSize;

						DataHold = NULL;
					}
					else
						StartSerialRead(Buffer,Len - 1);

					FOREVER
					{
						Signals = Wait(SignalMask);

						if(Signals & SIG_SERIAL)
						{
							if(RexxTimeoutVal)
								StopTime();

								/* Did the request terminate gracefully? */

							if(!WaitSerialRead())
							{
								BytesIn += ReadRequest -> IOSer . io_Actual;

								BytesRead = ReadRequest -> IOSer . io_Actual;
							}
							else
								Results[0] = RC_ERROR;

							break;
						}

						if(Signals & SIG_BREAK)
						{
							StopSerialRead();

							if(RexxTimeoutVal)
								StopTime();

							Results[0] = RC_WARN;

							break;
						}

						if(Signals & SIG_TIMER)
						{
							StopSerialRead();

							WaitIO(TimeRequest);

							if(ReadRequest -> IOSer . io_Actual)
							{
								BytesIn += ReadRequest -> IOSer . io_Actual;

								BytesRead = ReadRequest -> IOSer . io_Actual;
							}
							else
							{
								ULONG Waiting = GetSerialWaiting();

								if(Waiting)
								{
										/* Don't read more than actually wanted. */

									if(!DoSerialRead(Buffer,MIN(Len - 1,Waiting)))
									{
										BytesIn += ReadRequest -> IOSer . io_Actual;

										BytesRead = ReadRequest -> IOSer . io_Actual;
									}
								}
							}

							break;
						}
					}
				}

				if(BytesRead)
					Result = CreateResultLen(Buffer,Results,BytesRead);
				else
				{
					Results[0] = RC_WARN;

					Result = NULL;
				}

				FreeVecPooled(Buffer);

				RestartSerial(TRUE);

				if(Args[ARG_READ_CR])
				{
					Forbid();

					Window -> Flags &= ~WFLG_RMBTRAP;

					LT_LockWindow(Window);

					Permit();
				}

				ReleaseWindows();

				return(Result);
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_NO_FREE_STORE;
			}

			RestartSerial(TRUE);
		}
	}
	else
	{
		if(Args[ARG_READ_CR])
		{
			ULONG				 Signals,SignalMask = SIG_SERIAL | SIG_TIMER | SIG_BREAK;
			UBYTE				*Char,Temp;
			BYTE				 Echo,Done = FALSE;
			LONG				 Index = 0;
			struct TranslationHandle	 Handle;
			STRPTR				 Buffer;

			if(Buffer = (STRPTR)AllocVecPooled(Len,MEMF_ANY))
			{
				if(Args[ARG_READ_NOECHO])
					Echo = FALSE;
				else
					Echo = TRUE;

				RexxReadEcho = Echo;

				if(RexxTimeoutVal)
					StartTime(RexxTimeoutVal,0);

				if(DataHold)
				{
					while(DataSize-- > 0)
					{
						Char = DataHold++;

						TranslateSetup(&Handle,Char,1,&Temp,1,ReceiveTable);

						while(!Done && TranslateBuffer(&Handle))
						{
							switch(Temp)
							{
								case '\n':

									break;

								case '\r':

									Done = TRUE;

									if(Echo)
										SerWrite(&Temp,1);

									break;

								case '\b':

									if(Index > 0)
									{
										Index--;

										if(Echo)
											SerWrite(&Temp,1);
									}

									break;

								case '\30':

									if(Echo)
									{
										while(Index > 0)
										{
											Index--;

											SerWrite("\b",1);
										}
									}
									else
										Index = 0;

									break;

								default:

									if(Index < Len && ((Temp >= ' ' && Temp < 127) || Temp >= 160 || Config -> TerminalConfig -> FontMode == FONT_IBM))
									{
										Buffer[Index++] = Temp;

										if(Echo)
											SerWrite(&Temp,1);
									}

									break;
							}
						}
					}

					DataHold = NULL;

					RestartSerial(TRUE);
				}

				if(CheckSerialRead())
					Signals = SIG_SERIAL;
				else
					Signals = NULL;

				do
				{
					if(Signals & SIG_WINDOW)
					{
						SerWriteBypass = RexxReadBypassTranslate;

						RexxReadBuffer	= Buffer;
						RexxReadIndex	= Index;
						RexxReadLen	= Len;
						RexxReadDone	= Done;

						while(HandleWindow());

						Buffer	= RexxReadBuffer;
						Index	= RexxReadIndex;
						Len	= RexxReadLen;
						Done	= RexxReadDone;

						SerWriteBypass = NULL;
					}

					if(Signals & SIG_SERIAL)
					{
						if(!WaitSerialRead())
						{
							LONG Length;

							BytesIn++;

							if(Translate_CR_LF)
								Length = (* Translate_CR_LF)(ReadBuffer,1);
							else
								Length = 1;

							if(Length)
							{
								TranslateSetup(&Handle,ReadBuffer,Length,&Temp,1,ReceiveTable);

								while(!Done && TranslateBuffer(&Handle))
								{
									switch(Temp)
									{
										case '\n':

											break;

										case '\r':

											Done = TRUE;

											if(Echo)
												SerWrite(&Temp,1);

											break;

										case '\b':

											if(Index > 0)
											{
												Index--;

												if(Echo)
													SerWrite(&Temp,1);
											}

											break;

										case '\30':

											if(Echo)
											{
												while(Index > 0)
												{
													Index--;

													SerWrite("\b",1);
												}
											}
											else
												Index = 0;

										default:

											if(Index < Len && ((Temp >= ' ' && Temp < 127) || Temp >= 160 || Config -> TerminalConfig -> FontMode == FONT_IBM))
											{
												Buffer[Index++] = Temp;

												if(Echo)
													SerWrite(&Temp,1);
											}

											break;
									}
								}
							}
						}

						RestartSerial(TRUE);
					}

					if(Signals & (SIG_BREAK | SIG_TIMER))
					{
						Results[0] = RC_WARN;

						break;
					}

					if(!Done)
						Signals = Wait(SignalMask | SIG_WINDOW);
				}
				while(!Done);

				if(RexxTimeoutVal)
					StopTime();

				if(Index)
				{
					STRPTR Result;

					Buffer[Index] = 0;

					Result = CreateResult(Buffer,Results);

					if(Args[ARG_READ_CR])
					{
						Forbid();

						Window -> Flags &= ~WFLG_RMBTRAP;

						LT_LockWindow(Window);

						Permit();
					}

					ReleaseWindows();

					FreeVecPooled(Buffer);

					return(Result);
				}
				else
					Results[0] = RC_WARN;

				FreeVecPooled(Buffer);
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_NO_FREE_STORE;
			}
		}
		else
		{
			STRPTR Buffer;

			if(Buffer = (STRPTR)AllocVecPooled(Len,MEMF_ANY))
			{
				STRPTR Result;

				if(DataHold && DataSize >= Len - 1)
				{
					CopyMem(DataHold,Buffer,Len - 1);

					BytesRead = Len - 1;

					if(DataSize == Len - 1)
					{
						DataHold = NULL;

						RestartSerial(TRUE);
					}
					else
					{
						DataHold += Len - 1;
						DataSize -= Len - 1;
					}
				}
				else
				{
					ULONG Signals,SignalMask = SIG_SERIAL | SIG_TIMER | SIG_BREAK;

					ClearSerial();

					ClrSignal(SignalMask);

					if(RexxTimeoutVal)
						StartTime(RexxTimeoutVal,0);

					if(DataHold)
					{
						CopyMem(DataHold,Buffer,DataSize);

						StartSerialRead(Buffer + DataSize,Len - 1 - DataSize);

						BytesRead = DataSize;

						DataHold = NULL;
					}
					else
						StartSerialRead(Buffer,Len - 1);

					FOREVER
					{
						Signals = Wait(SignalMask);

						if(Signals & SIG_SERIAL)
						{
							if(RexxTimeoutVal)
								StopTime();

								/* Did the request terminate gracefully? */

							if(!WaitSerialRead())
							{
								BytesIn += ReadRequest -> IOSer . io_Actual;

								BytesRead = ReadRequest -> IOSer . io_Actual;
							}
							else
								Results[0] = RC_ERROR;

							break;
						}

						if(Signals & SIG_BREAK)
						{
							StopSerialRead();

							if(RexxTimeoutVal)
								StopTime();

							Results[0] = RC_WARN;

							break;
						}

						if(Signals & SIG_TIMER)
						{
							StopSerialRead();

							WaitIO(TimeRequest);

							if(ReadRequest -> IOSer . io_Actual)
							{
								BytesIn += ReadRequest -> IOSer . io_Actual;

								BytesRead = ReadRequest -> IOSer . io_Actual;
							}
							else
							{
								ULONG Waiting = GetSerialWaiting();

								if(Waiting)
								{
										/* Don't read more than actually wanted. */

									if(!DoSerialRead(Buffer,MIN(Len - 1,Waiting)))
									{
										BytesIn += ReadRequest -> IOSer . io_Actual;

										BytesRead = ReadRequest -> IOSer . io_Actual;
									}
								}
							}

							break;
						}
					}
				}

				if(BytesRead)
				{
					STRPTR MetaBuffer;

					if(MetaBuffer = AllocVecPooled(Len,MEMF_ANY))
					{
						struct TranslationHandle	Handle;
						LONG				Bytes;

						TranslateSetup(&Handle,Buffer,BytesRead,MetaBuffer,Len - 1,ReceiveTable);

						Bytes = TranslateBuffer(&Handle);

						Result = CreateResultLen(MetaBuffer,Results,Bytes);

						FreeVecPooled(MetaBuffer);
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = ERROR_NO_FREE_STORE;

						Result = NULL;
					}
				}
				else
				{
					Results[0] = RC_WARN;

					Result = NULL;
				}

				FreeVecPooled(Buffer);

				RestartSerial(TRUE);

				if(Args[ARG_READ_CR])
				{
					Forbid();

					Window -> Flags &= ~WFLG_RMBTRAP;

					LT_LockWindow(Window);

					Permit();
				}

				ReleaseWindows();

				return(Result);
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_NO_FREE_STORE;
			}

			RestartSerial(TRUE);
		}
	}

	if(Args[ARG_READ_CR])
	{
		Forbid();

		Window -> Flags &= ~WFLG_RMBTRAP;

		LT_LockWindow(Window);

		Permit();
	}

	ReleaseWindows();

	return(NULL);
}

STRPTR
RexxReceiveFile(struct RexxPkt *Pkt)
{
	enum	{	ARG_RECEIVEFILE_MODE,ARG_RECEIVEFILE_NAME };

	WORD Mode = TRANSFER_BINARY;

	if(Args[ARG_RECEIVEFILE_MODE])
		Mode = ToMode(Args[ARG_RECEIVEFILE_MODE]);

	if(Mode == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_ACTION_NOT_KNOWN;
	}
	else
	{
		BlockWindows();

		switch(Mode)
		{
			case TRANSFER_ASCII:

				if(ChangeProtocol(Config -> TransferConfig -> ASCIIDownloadLibrary))
				{
					BinaryTransfer = FALSE;

					StartXprReceive(TRANSFER_ASCII,NULL,FALSE);

					BinaryTransfer = TRUE;

					SerialCommand(Config -> CommandConfig -> DownloadMacro);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}

				ResetProtocol();

				break;

			case TRANSFER_TEXT:

				if(ChangeProtocol(Config -> TransferConfig -> TextDownloadLibrary))
				{
					BinaryTransfer = FALSE;

					StartXprReceive(TRANSFER_TEXT,NULL,FALSE);

					BinaryTransfer = TRUE;

					SerialCommand(Config -> CommandConfig -> DownloadMacro);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}

				ResetProtocol();

				break;

			case TRANSFER_BINARY:

				if(ChangeProtocol(Config -> TransferConfig -> BinaryDownloadLibrary))
				{
					BinaryTransfer = TRUE;

					StartXprReceive(TRANSFER_BINARY,NULL,FALSE);

					SerialCommand(Config -> CommandConfig -> DownloadMacro);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}

				ResetProtocol();

				break;
		}

		if(TransferFailed)
			Results[0] = RC_ERROR;

		if(TransferAborted)
			Results[0] = RC_WARN;

		ReleaseWindows();
	}

	return(NULL);
}

STRPTR
RexxRedial(struct RexxPkt *Pkt)
{
	if(DialList)
	{
		if(DialList -> lh_Head -> ln_Succ)
			DoDial = DIAL_REDIAL;
		else
			Results[0] = RC_WARN;
	}
	else
		Results[0] = RC_WARN;

	return(NULL);
}

STRPTR
RexxRemove(struct RexxPkt *Pkt)
{
	enum	{	ARG_REMOVE_FROM,ARG_REMOVE_NAME };

	WORD Index;

	if((Index = ToList(Args[ARG_REMOVE_FROM])) == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_UNKNOWN_LIST;
	}
	else
	{
		if(Args[ARG_REMOVE_NAME] && Index == GLIST_DIAL)
		{
			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_DATA_TYPES_INCOMPATIBLE;
		}
		else
		{
			struct GenericList *List;

			List = GenericListTable[Index];

			if(Args[ARG_REMOVE_NAME])
			{
				STRPTR Buffer;

				if(Buffer = CreateMatchBuffer(Args[ARG_REMOVE_NAME]))
				{
					struct Node *Node,*NextNode;

					ObtainSemaphore(&List -> ListSemaphore);

					Node = (struct Node *)List -> ListHeader . mlh_Head;

					while(NextNode = Node -> ln_Succ)
					{
						if(MatchBuffer(Buffer,Node -> ln_Name))
						{
							Forbid();

							ReleaseSemaphore(&List -> ListSemaphore);

							DeleteGenericListNode(List,Node);

							ObtainSemaphore(&List -> ListSemaphore);

							Permit();
						}

						Node = NextNode;
					}

					ReleaseSemaphore(&List -> ListSemaphore);

					DeleteMatchBuffer(Buffer);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}
			}
			else
				DeleteGenericListNode(List,NULL);

			if(!GenericListCount(List))
				Results[0] = RC_WARN;
		}
	}

	return(NULL);
}

STRPTR
RexxRequestFile(struct RexxPkt *Pkt)
{
	enum	{	ARG_REQUESTFILE_TITLE,ARG_REQUESTFILE_PATH,ARG_REQUESTFILE_FILE,
			ARG_REQUESTFILE_PATTERN,ARG_REQUESTFILE_MULTI,ARG_REQUESTFILE_NAME };

	if(Args[ARG_REQUESTFILE_MULTI] && !Args[ARG_REQUESTFILE_NAME])
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_RESULT_VARIABLE_REQUIRED;
	}
	else
	{
		struct FileRequester	*FileRequester;
		UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH],
					*DummyChar;
		STRPTR			 FileName,
					 PathName;

		if(Args[ARG_REQUESTFILE_PATH])
		{
			PathName = Args[ARG_REQUESTFILE_PATH];

			if(Args[ARG_REQUESTFILE_FILE])
				FileName = Args[ARG_REQUESTFILE_FILE];
			else
				FileName = "";
		}
		else
		{
			PathName = "";

			if(Args[ARG_REQUESTFILE_FILE])
			{
				strcpy(DummyBuffer,Args[ARG_REQUESTFILE_FILE]);

				DummyChar = PathPart(DummyBuffer);

				*DummyChar = 0;

				PathName = DummyBuffer;
				FileName = FilePart(Args[ARG_REQUESTFILE_FILE]);
			}
			else
				FileName = "";
		}

		BlockWindows();

		if(FileRequester = GetFile(Window,Args[ARG_REQUESTFILE_TITLE],PathName,FileName,DummyBuffer,Args[ARG_REQUESTFILE_PATTERN],FALSE,Args[ARG_REQUESTFILE_MULTI] != NULL,FALSE,"Ok",TRUE))
		{
			if(Args[ARG_REQUESTFILE_NAME])
			{
				if(Args[ARG_REQUESTFILE_MULTI])
				{
					UBYTE		 DummyBuffer[MAX_FILENAME_LENGTH];
					struct WBArg	*ArgList = FileRequester -> rf_ArgList;
					LONG		 i,Counted = 0;

					for(i = 0 ; i < FileRequester -> rf_NumArgs ; i++)
					{
						if(ArgList[i] . wa_Name)
						{
							if(ArgList[i] . wa_Lock)
							{
								if(!NameFromLock(ArgList[i] . wa_Lock,DummyBuffer,MAX_FILENAME_LENGTH))
								{
									Results[0] = RC_ERROR;
									Results[1] = IoErr();

									break;
								}
							}
							else
								strcpy(DummyBuffer,FileRequester -> rf_Dir);

							if(AddPart(DummyBuffer,ArgList[i] . wa_Name,MAX_FILENAME_LENGTH))
							{
								if(CreateVarArgs(DummyBuffer,Pkt,"%s.%ld",Args[ARG_REQUESTFILE_NAME],i))
									Counted++;
								else
									break;
							}
							else
							{
								Results[0] = RC_ERROR;
								Results[1] = IoErr();

								break;
							}
						}
					}

					if(Counted)
					{
						SPrintf(DummyBuffer,"%ld",Counted);

						CreateVarArgs(DummyBuffer,Pkt,"%s.COUNT",Args[ARG_REQUESTFILE_NAME]);
					}

					FreeAslRequest(FileRequester);
				}
				else
				{
					FreeAslRequest(FileRequester);

					ReleaseWindows();

					return(CreateVar(DummyBuffer,Pkt,Args[ARG_REQUESTFILE_NAME]));
				}
			}
			else
			{
				FreeAslRequest(FileRequester);

				ReleaseWindows();

				return(CreateResult(DummyBuffer,Results));
			}
		}
		else
			Results[0] = RC_WARN;

		ReleaseWindows();
	}

	return(NULL);
}

STRPTR
RexxRequestNotify(struct RexxPkt *Pkt)
{
	enum	{	ARG_REQUESTNOTIFY_TITLE,ARG_REQUESTNOTIFY_PROMPT };

	struct EasyStruct	Easy;
	ULONG			IDCMP = NULL;

	Easy . es_StructSize	= sizeof(struct EasyStruct);
	Easy . es_Flags		= NULL;
	Easy . es_TextFormat	= Args[ARG_REQUESTNOTIFY_PROMPT];
	Easy . es_GadgetFormat	= LocaleString(MSG_GLOBAL_CONTINUE_TXT);

	if(Args[ARG_REQUESTNOTIFY_TITLE])
		Easy . es_Title	= Args[ARG_REQUESTNOTIFY_TITLE];
	else
		Easy . es_Title	= LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);

	BlockWindows();

	EasyRequestArgs(Window,&Easy,&IDCMP,NULL);

	ReleaseWindows();

	return(NULL);
}

STRPTR
RexxRequestNumber(struct RexxPkt *Pkt)
{
	enum	{	ARG_REQUESTNUMBER_DEFAULT,ARG_REQUESTNUMBER_PROMPT };

	UBYTE DummyBuffer[256];

	if(Args[ARG_REQUESTNUMBER_DEFAULT])
		SPrintf(DummyBuffer,"%ld",*(LONG *)Args[ARG_REQUESTNUMBER_DEFAULT]);
	else
		DummyBuffer[0] = 0;

	BlockWindows();

	if(GetString(FALSE,FALSE,255,Args[ARG_REQUESTNUMBER_PROMPT],DummyBuffer))
	{
		STRPTR Index = DummyBuffer;

		while(*Index == ' ' || *Index == '\t')
			Index++;

		if(*Index)
		{
			LONG Value;

			if(StrToLong(DummyBuffer,&Value) == -1)
			{
				Results[0] = RC_ERROR;
				Results[1] = ERROR_BAD_NUMBER;
			}
			else
			{
				ReleaseWindows();

				SPrintf(DummyBuffer,"%ld",Value);

				return(CreateResult(DummyBuffer,Results));
			}
		}
		else
			Results[0] = RC_WARN;
	}
	else
		Results[0] = RC_WARN;

	ReleaseWindows();

	return(NULL);
}

STRPTR
RexxRequestResponse(struct RexxPkt *Pkt)
{
	enum	{	ARG_REQUESTRESPONSE_TITLE,ARG_REQUESTRESPONSE_OPTIONS,
			ARG_REQUESTRESPONSE_PROMPT };

	struct EasyStruct	Easy;
	ULONG			IDCMP = NULL;
	WORD			Result;

	Easy . es_StructSize	= sizeof(struct EasyStruct);
	Easy . es_Flags		= NULL;
	Easy . es_TextFormat	= Args[ARG_REQUESTRESPONSE_PROMPT];

	if(Args[ARG_REQUESTRESPONSE_OPTIONS])
		Easy . es_GadgetFormat = Args[ARG_REQUESTRESPONSE_OPTIONS];
	else
		Easy . es_GadgetFormat = LocaleString(MSG_GLOBAL_YES_NO_TXT);

	if(Args[ARG_REQUESTRESPONSE_TITLE])
		Easy . es_Title	= Args[ARG_REQUESTRESPONSE_TITLE];
	else
		Easy . es_Title	= LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);

	BlockWindows();

	Result = EasyRequestArgs(Window,&Easy,&IDCMP,NULL);

	ReleaseWindows();

	if(Result)
	{
		UBYTE DummyBuffer[20];

		SPrintf(DummyBuffer,"%ld",Result);

		return(CreateResult(DummyBuffer,Results));
	}
	else
	{
		Results[0] = RC_WARN;

		return(NULL);
	}
}

STRPTR
RexxRequestString(struct RexxPkt *Pkt)
{
	enum	{	ARG_REQUESTSTRING_SECRET,ARG_REQUESTSTRING_DEFAULT,ARG_REQUESTSTRING_PROMPT };

	UBYTE DummyBuffer[256];

	if(Args[ARG_REQUESTSTRING_DEFAULT])
		strcpy(DummyBuffer,Args[ARG_REQUESTSTRING_DEFAULT]);
	else
		DummyBuffer[0] = 0;

	BlockWindows();

	if(GetString(FALSE,Args[ARG_REQUESTSTRING_SECRET] != NULL,255,Args[ARG_REQUESTSTRING_PROMPT],DummyBuffer))
	{
		ReleaseWindows();

		return(CreateResult(DummyBuffer,Results));
	}
	else
		Results[0] = RC_WARN;

	ReleaseWindows();

	return(NULL);
}

STRPTR
RexxResetScreen(struct RexxPkt *Pkt)
{
	if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
		XEmulatorResetConsole(XEM_IO);
	else
	{
		FreeMarker();

		ObtainSemaphore(&TerminalSemaphore);

		ClearCursor();

		Reset();

		DrawCursor();

		ReleaseSemaphore(&TerminalSemaphore);
	}

	return(NULL);
}

STRPTR
RexxResetStyles(struct RexxPkt *Pkt)
{
	if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
		XEmulatorResetTextStyles(XEM_IO);
	else
	{
		DropMarker();

		ConBypass("\033[0m",-1);

		ObtainSemaphore(&TerminalSemaphore);

		ClearCursor();

		Config -> EmulationConfig -> FontScale = SCALE_NORMAL;

		ForegroundPen = GetPenIndex(SafeTextPen);
		BackgroundPen = 0;

		UpdatePens();

		SetMask(RPort,DepthMask);

		ConFontScaleUpdate();

		DrawCursor();

		ReleaseSemaphore(&TerminalSemaphore);
	}

	return(NULL);
}

STRPTR
RexxResetText(struct RexxPkt *Pkt)
{
	if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
		XEmulatorResetCharset(XEM_IO);
	else
	{
		DropMarker();

		CurrentFont = TextFont;

		SetFont(RPort,CurrentFont);

		ConOutputUpdate();
	}

	return(NULL);
}

STRPTR
RexxResetTimer(struct RexxPkt *Pkt)
{
	Forbid();

	if(StatusProcess)
		Signal(StatusProcess,SIG_RESETTIME);

	Permit();

	return(NULL);
}

STRPTR
RexxSaveAs(struct RexxPkt *Pkt)
{
	enum	{	ARG_SAVEAS_NAME,ARG_SAVEAS_FROM };

	WORD Index = ToConfig(Args[ARG_SAVEAS_FROM]);

	if(Index == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_OBJECT_NOT_FOUND;
	}
	else
	{
		UBYTE	DummyBuffer[MAX_FILENAME_LENGTH];
		STRPTR	FileName;

		if(Args[ARG_SAVEAS_NAME])
			FileName = Args[ARG_SAVEAS_NAME];
		else
		{
			STRPTR			 Title;
			struct FileRequester	*FileRequest;

			FileName = NULL;

			switch(Index)
			{
				case DATATYPE_TRANSLATIONS:

					Title = LocaleString(MSG_TRANSLATIONPANEL_SAVE_TRANSLATION_TABLES_TXT);
					break;

				case DATATYPE_FUNCTIONKEYS:

					Title = LocaleString(MSG_MACROPANEL_SAVE_MACRO_KEYS_TXT);
					break;

				case DATATYPE_CURSORKEYS:

					Title = LocaleString(MSG_CURSORPANEL_SAVE_CURSOR_KEYS_TXT);
					break;

				case DATATYPE_FASTMACROS:

					Title = LocaleString(MSG_FASTMACROPANEL_SAVE_FAST_MACRO_SETTINGS_TXT);
					break;

				case DATATYPE_HOTKEYS:

					Title = LocaleString(MSG_HOTKEYPANEL_SAVE_HOTKEYS_TXT);
					break;

				case DATATYPE_SPEECH:

					Title = LocaleString(MSG_SPEECHPANEL_SAVE_SPEECH_SETTINGS_TXT);
					break;

				case DATATYPE_SOUND:

					Title = LocaleString(MSG_SOUNDPANEL_SAVE_SOUNDS_TXT);
					break;

				case DATATYPE_BUFFER:

					Title = LocaleString(MSG_TERMMAIN_SAVE_BUFFER_TXT);
					break;

				case DATATYPE_CONFIGURATION:

					Title = LocaleString(MSG_TERMMAIN_SAVE_PREFERENCES_AS_TXT);
					break;

				case DATATYPE_PHONEBOOK:

					Title = LocaleString(MSG_PHONEPANEL_SAVE_PHONEBOOK_TXT);
					break;

				case DATATYPE_SCREENTEXT:

					Title = LocaleString(MSG_TERMMAIN_SAVE_SCREEN_ASCII_TXT);
					break;

				case DATATYPE_SCREENIMAGE:

					Title = LocaleString(MSG_TERMMAIN_SAVE_SCREEN_IFF_TXT);
					break;
			}

			BlockWindows();

			if(FileRequest = GetFile(Window,Title,"","",DummyBuffer,NULL,TRUE,FALSE,FALSE,NULL,TRUE))
			{
				FileName = DummyBuffer;

				FreeAslRequest(FileRequest);
			}

			ReleaseWindows();
		}

		if(FileName)
		{
			switch(Index)
			{
				case DATATYPE_TRANSLATIONS:
				{
					if(SendTable && ReceiveTable)
					{
						if(!SaveTranslationTables(FileName,SendTable,ReceiveTable))
						{
							Results[0] = RC_ERROR;
							Results[1] = IoErr();
						}
						else
						{
							strcpy(LastTranslation,FileName);

							TranslationChanged = FALSE;
						}
					}
					else
						Results[0] = RC_WARN;
				}

				break;

				case DATATYPE_FUNCTIONKEYS:
				{
					if(!WriteIFFData(FileName,MacroKeys,sizeof(struct MacroKeys),ID_KEYS))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastMacros,FileName);

						MacroChanged = FALSE;
					}
				}

				break;

				case DATATYPE_CURSORKEYS:
				{
					if(!WriteIFFData(FileName,CursorKeys,sizeof(struct CursorKeys),ID_KEYS))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastCursorKeys,FileName);

						CursorKeysChanged = FALSE;
					}
				}

				break;

				case DATATYPE_FASTMACROS:
				{
					if(!SaveFastMacros(FileName,&FastMacroList))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastFastMacros,FileName);

						FastMacrosChanged = FALSE;
					}
				}

				break;

				case DATATYPE_HOTKEYS:
				{
					if(!WriteIFFData(FileName,&Hotkeys,sizeof(struct Hotkeys),ID_HOTK))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastKeys,FileName);

						HotkeysChanged = FALSE;
					}
				}

				break;

				case DATATYPE_SPEECH:
				{
					if(!WriteIFFData(FileName,&SpeechConfig,sizeof(struct SpeechConfig),ID_SPEK))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastSpeech,FileName);

						SpeechChanged = FALSE;
					}
				}

				break;

				case DATATYPE_SOUND:
				{
					if(!WriteIFFData(FileName,&SoundConfig,sizeof(struct SoundConfig),ID_SOUN))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastSound,FileName);

						SoundChanged = FALSE;
					}
				}

				break;

				case DATATYPE_BUFFER:
				{
					if(BufferLines && Lines)
					{
						BPTR SomeFile;

						if(GetFileSize(FileName))
						{
							if(SomeFile = Open(FileName,MODE_READWRITE))
							{
								if(Seek(SomeFile,0,OFFSET_END) == -1)
								{
									Close(SomeFile);

									SomeFile = NULL;

									SetIoErr(ERROR_SEEK_ERROR);
								}
							}
						}
						else
							SomeFile = Open(FileName,MODE_NEWFILE);

						if(SomeFile)
						{
							LONG i,Len;

								/* Obtain the semaphore required
								 * to gain access to the line buffer
								 */

							ObtainSemaphore(BufferSemaphore);

							for(i = 0 ; i < Lines ; i++)
							{
								Len = BufferLines[i][-1];

								if(Len)
								{
									if(FWrite(SomeFile,BufferLines[i],Len,1) != 1)
									{
										Results[0] = RC_ERROR;
										Results[1] = IoErr();

										break;
									}
								}

								if(FPrintf(SomeFile,"\n") < 1)
								{
									Results[0] = RC_ERROR;
									Results[1] = IoErr();

									break;
								}
							}

							ReleaseSemaphore(BufferSemaphore);

							Close(SomeFile);

							AddProtection(FileName,FIBF_EXECUTE);

							if(Config -> MiscConfig -> CreateIcons)
								AddIcon(FileName,FILETYPE_TEXT,TRUE);

							BufferChanged = FALSE;
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = IoErr();
						}
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = TERMERROR_NO_DATA_TO_PROCESS;
					}
				}

				break;

				case DATATYPE_CONFIGURATION:
				{
					if(!WriteConfig(FileName,Config))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastConfig,FileName);

						ConfigChanged = FALSE;
					}
				}

				break;

				case DATATYPE_PHONEBOOK:
				{
					if(!SavePhonebook(FileName))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
					else
					{
						strcpy(LastPhone,FileName);

						PhonebookChanged = FALSE;
					}
				}

				break;

				case DATATYPE_SCREENTEXT:
				{
					if(RasterEnabled)
					{
						BPTR SomeFile;

						if(GetFileSize(FileName))
						{
							if(SomeFile = Open(FileName,MODE_READWRITE))
							{
								if(Seek(SomeFile,0,OFFSET_END) == -1)
								{
									Close(SomeFile);

									SomeFile = NULL;

									SetIoErr(ERROR_SEEK_ERROR);
								}
							}
						}
						else
							SomeFile = Open(FileName,MODE_NEWFILE);

						if(SomeFile)
						{
							LONG	 i,j;
							UBYTE	*Buffer;

							for(i = 0 ; i < RasterHeight ; i++)
							{
								Buffer = &Raster[i * RasterWidth];

								j = LastColumn;

								while(j >= 0 && Buffer[j] == ' ')
									j--;

								if(j >= 0)
								{
									if(!FWrite(SomeFile,Buffer,j + 1,1))
									{
										Results[0] = RC_ERROR;
										Results[1] = IoErr();

										break;
									}
								}

								if(!FWrite(SomeFile,"\n",1,1))
								{
									Results[0] = RC_ERROR;
									Results[1] = IoErr();

									break;
								}
							}

							Close(SomeFile);

							AddProtection(FileName,FIBF_EXECUTE);

							if(Config -> MiscConfig -> CreateIcons)
								AddIcon(FileName,FILETYPE_TEXT,TRUE);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = IoErr();
						}
					}
					else
					{
						Results[0] = RC_ERROR;
						Results[1] = TERMERROR_NO_DATA_TO_PROCESS;
					}
				}

				break;

				case DATATYPE_SCREENIMAGE:
				{
					if(!SaveWindow(FileName,Window))
					{
						Results[0] = RC_ERROR;
						Results[1] = IoErr();
					}
				}

				break;
			}
		}
		else
			Results[0] = RC_WARN;
	}

	return(NULL);
}

STRPTR
RexxSave(struct RexxPkt *Pkt)
{
	enum	{	ARG_SAVE_FROM };

	Args[1] = Args[ARG_SAVE_FROM];
	Args[0] = NULL;

	return(RexxSaveAs(Pkt));
}

STRPTR
RexxSelect(struct RexxPkt *Pkt)
{
	enum	{	ARG_SELECT_NAME,ARG_SELECT_FROM,ARG_SELECT_NEXT,ARG_SELECT_PREVIOUS,
			ARG_SELECT_TOP,ARG_SELECT_BOTTOM };

	WORD Index;

	if((Index = ToList(Args[ARG_SELECT_FROM])) == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = TERMERROR_UNKNOWN_LIST;
	}
	else
	{
		if(Args[ARG_SELECT_NAME] && Index == GLIST_DIAL)
		{
			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_DATA_TYPES_INCOMPATIBLE;
		}
		else
		{
			struct GenericList *List;

			List = GenericListTable[Index];

			if(Args[ARG_SELECT_NAME])
			{
				STRPTR Buffer;

				if(Buffer = CreateMatchBuffer(Args[ARG_SELECT_NAME]))
				{
					struct Node *Node,*NextNode;

					ObtainSemaphore(&List -> ListSemaphore);

					Node = (struct Node *)List -> ListHeader . mlh_Head;

					while(NextNode = Node -> ln_Succ)
					{
						if(MatchBuffer(Buffer,Node -> ln_Name))
						{
							List -> ListNode = Node;

							Node = NULL;

							break;
						}

						Node = NextNode;
					}

					if(Node)
						Results[0] = RC_WARN;

					ReleaseSemaphore(&List -> ListSemaphore);

					DeleteMatchBuffer(Buffer);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}
			}
			else
			{
				if(Args[ARG_SELECT_NEXT])
				{
					if(!NextGenericListNode(List))
					{
						Results[0] = RC_WARN;

						return(NULL);
					}
				}

				if(Args[ARG_SELECT_PREVIOUS])
				{
					if(!PrevGenericListNode(List))
					{
						Results[0] = RC_WARN;

						return(NULL);
					}
				}

				if(Args[ARG_SELECT_TOP])
				{
					if(!FirstGenericListNode(List))
					{
						Results[0] = RC_WARN;

						return(NULL);
					}
				}

				if(Args[ARG_SELECT_BOTTOM])
				{
					if(!LastGenericListNode(List))
					{
						Results[0] = RC_WARN;

						return(NULL);
					}
				}
			}

			ObtainSemaphore(&List -> ListSemaphore);

			if(List -> ListNode)
			{
				if(Index != GLIST_DIAL)
				{
					struct Node	*Node = (struct Node *)List -> ListNode;
					STRPTR		 Result;

					Result = CreateResult(Node -> ln_Name,Results);

					ReleaseSemaphore(&List -> ListSemaphore);

					return(Result);
				}
			}
			else
				Results[0] = RC_WARN;

			ReleaseSemaphore(&List -> ListSemaphore);
		}
	}

	return(NULL);
}

STRPTR
RexxSend(struct RexxPkt *Pkt)
{
	enum	{	ARG_SEND_NOECHO,ARG_SEND_LOCAL,ARG_SEND_BYTE,ARG_SEND_TEXT };

	if(Args[ARG_SEND_LOCAL])
	{
		if(!Args[ARG_SEND_NOECHO])
		{
			if(Marking)
				DropMarker();

			if(Args[ARG_SEND_TEXT])
				ConsoleCommand(Args[ARG_SEND_TEXT]);
			else
			{
				UBYTE Byte = *(LONG *)Args[ARG_SEND_BYTE];

				ConProcess(&Byte,1);
			}
		}
	}
	else
	{
		if(Args[ARG_SEND_NOECHO])
			Quiet = TRUE;

		if(Args[ARG_SEND_TEXT])
			SerialCommand(Args[ARG_SEND_TEXT]);
		else
		{
			UBYTE Byte = *(LONG *)Args[ARG_SEND_BYTE];

			SerWrite(&Byte,1);
		}

		Quiet = FALSE;
	}

	return(NULL);
}

STRPTR
RexxSendBreak(struct RexxPkt *Pkt)
{
	if(WriteRequest)
		SendBreak();
	else
		Results[0] = RC_WARN;

	return(NULL);
}

STRPTR
RexxSendFile(struct RexxPkt *Pkt)
{
	enum	{	ARG_SENDFILE_MODE,ARG_SENDFILE_NAMES };

	WORD Mode = TRANSFER_BINARY;

	if(Args[ARG_SENDFILE_MODE])
		Mode = ToMode(Args[ARG_SENDFILE_MODE]);

	if(Mode == -1)
	{
		Results[0] = RC_ERROR;
		Results[1] = ERROR_ACTION_NOT_KNOWN;
	}
	else
	{
		struct FileTransferInfo	*Info;
		LONG			 FilesFound = 0;

		if(Info = AllocFileTransferInfo())
		{
			struct GenericList *List = GenericListTable[GLIST_UPLOAD];

			if(Args[ARG_SENDFILE_NAMES])
			{
				struct FileInfoBlock *FileInfo;

				if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
				{
					STRPTR	*Names = (STRPTR *)Args[ARG_SENDFILE_NAMES];
					BPTR	 FileLock,NewDir,OldDir;

					NewDir = NULL;

					switch(Mode)
					{
						case TRANSFER_BINARY:

							if(Config -> PathConfig -> BinaryUploadPath[0])
								NewDir = Lock(Config -> PathConfig -> BinaryUploadPath,ACCESS_READ);

							break;

						case TRANSFER_TEXT:

							if(Config -> PathConfig -> TextUploadPath[0])
								NewDir = Lock(Config -> PathConfig -> TextUploadPath,ACCESS_READ);

							break;

						case TRANSFER_ASCII:

							if(Config -> PathConfig -> ASCIIUploadPath[0])
								NewDir = Lock(Config -> PathConfig -> ASCIIUploadPath,ACCESS_READ);

							break;
					}

					if(NewDir)
						OldDir = CurrentDir(NewDir);
					else
						OldDir = NULL;

					while(*Names && Results[0] == RC_OK)
					{
						if(FileLock = Lock(*Names,ACCESS_READ))
						{
							if(Examine(FileLock,FileInfo))
							{
								if(FileInfo -> fib_DirEntryType < 0)
								{
									if(NameFromLock(FileLock,SharedBuffer,512))
									{
										if(AddFileTransferNode(Info,SharedBuffer,FileInfo -> fib_Size))
											FilesFound++;
										else
										{
											Results[0] = RC_ERROR;
											Results[1] = ERROR_NO_FREE_STORE;
										}
									}
									else
									{
										Results[0] = RC_ERROR;
										Results[1] = IoErr();
									}
								}
								else
								{
									Results[0] = RC_ERROR;
									Results[1] = ERROR_OBJECT_WRONG_TYPE;
								}
							}
							else
							{
								Results[0] = RC_ERROR;
								Results[1] = IoErr();
							}

							UnLock(FileLock);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = IoErr();
						}

						Names++;
					}

					if(OldDir)
						CurrentDir(OldDir);

					if(NewDir)
						UnLock(NewDir);

					FreeDosObject(DOS_FIB,FileInfo);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}
			}

			ObtainSemaphore(&List -> ListSemaphore);

			if(List -> ListHeader . mlh_Head -> mln_Succ)
			{
				struct Node		*Node = (struct Node *)List -> ListHeader . mlh_Head;
				struct FileInfoBlock	*FileInfo;
				BPTR			 NewDir,OldDir;

				NewDir = NULL;

				switch(Mode)
				{
					case TRANSFER_BINARY:

						if(Config -> PathConfig -> BinaryUploadPath[0])
							NewDir = Lock(Config -> PathConfig -> BinaryUploadPath,ACCESS_READ);

						break;

					case TRANSFER_TEXT:

						if(Config -> PathConfig -> TextUploadPath[0])
							NewDir = Lock(Config -> PathConfig -> TextUploadPath,ACCESS_READ);

						break;

					case TRANSFER_ASCII:

						if(Config -> PathConfig -> ASCIIUploadPath[0])
							NewDir = Lock(Config -> PathConfig -> ASCIIUploadPath,ACCESS_READ);

						break;
				}

				if(NewDir)
					OldDir = CurrentDir(NewDir);
				else
					OldDir = NULL;

				if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
				{
					BPTR FileLock;

					while(Node -> ln_Succ && Results[0] == RC_OK)
					{
						if(FileLock = Lock(Node -> ln_Name,ACCESS_READ))
						{
							if(Examine(FileLock,FileInfo))
							{
								if(FileInfo -> fib_DirEntryType < 0)
								{
									if(NameFromLock(FileLock,SharedBuffer,512))
									{
										if(AddFileTransferNode(Info,SharedBuffer,FileInfo -> fib_Size))
											FilesFound++;
										else
										{
											Results[0] = RC_ERROR;
											Results[1] = ERROR_NO_FREE_STORE;
										}
									}
									else
									{
										Results[0] = RC_ERROR;
										Results[1] = IoErr();
									}
								}
								else
								{
									Results[0] = RC_ERROR;
									Results[1] = ERROR_OBJECT_WRONG_TYPE;
								}
							}
							else
							{
								Results[0] = RC_ERROR;
								Results[1] = IoErr();
							}

							UnLock(FileLock);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = IoErr();
						}

						Node = Node -> ln_Succ;
					}

					if(OldDir)
						CurrentDir(OldDir);

					if(NewDir)
						UnLock(NewDir);

					FreeDosObject(DOS_FIB,FileInfo);
				}
				else
				{
					Results[0] = RC_ERROR;
					Results[1] = ERROR_NO_FREE_STORE;
				}
			}

			ReleaseSemaphore(&List -> ListSemaphore);

			if(Results[0] == RC_OK)
			{
				BlockWindows();

				if(FilesFound)
				{
					SortFileTransferInfo(Info);

					FileTransferInfo = Info;
				}

				switch(Mode)
				{
					case TRANSFER_ASCII:

						if(ChangeProtocol(Config -> TransferConfig -> ASCIIUploadLibrary))
						{
							BinaryTransfer = FALSE;

							if(FilesFound)
								StartXprSendFromList(TRANSFER_ASCII,FALSE);
							else
								StartXprSend(TRANSFER_ASCII,FALSE);

							BinaryTransfer = TRUE;

							SerialCommand(Config -> CommandConfig -> UploadMacro);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}

						ResetProtocol();

						break;

					case TRANSFER_TEXT:

						if(ChangeProtocol(Config -> TransferConfig -> TextUploadLibrary))
						{
							BinaryTransfer = FALSE;

							if(FilesFound)
								StartXprSendFromList(TRANSFER_TEXT,FALSE);
							else
								StartXprSend(TRANSFER_TEXT,FALSE);

							BinaryTransfer = TRUE;

							SerialCommand(Config -> CommandConfig -> UploadMacro);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}

						ResetProtocol();

						break;

					case TRANSFER_BINARY:

						if(ChangeProtocol(Config -> TransferConfig -> BinaryUploadLibrary))
						{
							BinaryTransfer = TRUE;

							if(FilesFound)
								StartXprSendFromList(TRANSFER_BINARY,FALSE);
							else
								StartXprSend(TRANSFER_BINARY,FALSE);

							SerialCommand(Config -> CommandConfig -> UploadMacro);
						}
						else
						{
							Results[0] = RC_ERROR;
							Results[1] = ERROR_NO_FREE_STORE;
						}

						ResetProtocol();

						break;
				}

				if(TransferFailed)
					Results[0] = RC_ERROR;

				if(TransferAborted)
					Results[0] = RC_WARN;

				ReleaseWindows();
			}
			else
				FreeFileTransferInfo(Info);
		}
		else
		{
			Results[0] = RC_ERROR;
			Results[1] = ERROR_NO_FREE_STORE;
		}
	}

	return(NULL);
}

STRPTR
RexxSpeak(struct RexxPkt *Pkt)
{
	enum	{	ARG_SPEAK_TEXT };

	if(SpeechConfig . Enabled && English)
		Say(Args[ARG_SPEAK_TEXT]);
	else
		Results[0] = RC_WARN;

	return(NULL);
}

STRPTR
RexxStopBits(struct RexxPkt *Pkt)
{
	enum	{	ARG_STOPBITS_0,ARG_STOPBITS_1 };

	BYTE Bits;

	if(Args[ARG_STOPBITS_0])
		Bits = 0;

	if(Args[ARG_STOPBITS_1])
		Bits = 1;

	if(Config -> SerialConfig -> StopBits != Bits)
	{
		Config -> SerialConfig -> StopBits = Bits;

		UpdateRequired = TRUE;

		ConfigChanged = TRUE;
	}

	return(NULL);
}

STRPTR
RexxTextBuffer(struct RexxPkt *Pkt)
{
	enum	{	ARG_TEXTBUFFER_LOCK,ARG_TEXTBUFFER_UNLOCK };

	Forbid();

	if(Args[ARG_TEXTBUFFER_LOCK])
		BufferFrozen = TRUE;

	if(Args[ARG_TEXTBUFFER_UNLOCK])
		BufferFrozen = FALSE;

	CheckItem(MEN_FREEZE_BUFFER,BufferFrozen);

	ConOutputUpdate();

	Permit();

	return(NULL);
}

STRPTR
RexxTimeout(struct RexxPkt *Pkt)
{
	enum	{	ARG_TIMEOUT_SECONDS,ARG_TIMEOUT_OFF };

	if(Args[ARG_TIMEOUT_OFF])
		RexxTimeoutVal = 0;
	else
		RexxTimeoutVal = *(LONG *)Args[ARG_TIMEOUT_SECONDS];

	return(NULL);

}

STRPTR
RexxTrap(struct RexxPkt *Pkt)
{
	enum	{	ARG_TRAP_ON,ARG_TRAP_OFF };

	BOOLEAN Enabled;

	Forbid();

	if(Args[ARG_TRAP_ON])
		Enabled = TRUE;

	if(Args[ARG_TRAP_OFF])
		Enabled = FALSE;

	CheckItem(MEN_DISABLE_TRAPS,Enabled ^ TRUE);

	Permit();

	ObtainSemaphore(&GenericListTable[GLIST_TRAP] -> ListSemaphore);

	if(GenericListTable[GLIST_TRAP] -> ListHeader . mlh_Head -> mln_Succ && Enabled)
		WatchTraps = TRUE;
	else
		WatchTraps = FALSE;

	ReleaseSemaphore(&GenericListTable[GLIST_TRAP] -> ListSemaphore);

	return(NULL);
}

STATIC STRPTR		 RexxWaitResult;
STATIC struct WaitNode	*RexxWaitNode;

STATIC BOOLEAN
RexxWaitBypass(STRPTR Buffer,LONG Size)
{
	LONG Position;

	RexxWaitResult = ScanNodeFilter(Buffer,Size,RexxWaitNode,&Position);

	SerWriteVerbatim(Buffer,Size,FALSE);

	return(FALSE);
}

STRPTR
RexxWait(struct RexxPkt *Pkt)
{
	enum	{	ARG_WAIT_NOECHO,ARG_WAIT_TEXT };

	ULONG		 Signals;
	STRPTR		 Result = NULL;
	BYTE		 Echo;
	struct WaitNode	*WaitNode,
			 Node;
	UBYTE		 DummyBuffer[256];
	LONG		 Position;
	struct List	 DummyList;

	if(!ReadRequest || !WriteRequest)
	{
		Results[0] = RC_WARN;

		return(NULL);
	}

	if(Args[ARG_WAIT_NOECHO])
		Echo = FALSE;
	else
		Echo = TRUE;

	if(Args[ARG_WAIT_TEXT])
	{
		WORD i,Len;

		NewList(&DummyList);

		memcpy(DummyBuffer,Args[ARG_WAIT_TEXT],255);

		DummyBuffer[255] = 0;

		for(i = 0 ; i < strlen(DummyBuffer) ; i++)
			DummyBuffer[i] = ToUpper(DummyBuffer[i]);

		Len = TranslateString(DummyBuffer,DummyBuffer);

		DummyBuffer[Len] = 0;

		memset(&Node,0,sizeof(struct WaitNode));

		Node . Node . ln_Name	= DummyBuffer;
		Node . Count		= 0;

		WaitNode = &Node;

		AddTail(&DummyList,(struct Node *)WaitNode);
	}
	else
	{
		if(!GenericListCount(GenericListTable[GLIST_WAIT]))
		{
			Results[0] = RC_ERROR;
			Results[1] = TERMERROR_LIST_IS_ALREADY_EMPTY;

			return(NULL);
		}
		else
		{
			WaitNode = (struct WaitNode *)GenericListTable[GLIST_WAIT] -> ListHeader . mlh_Head;

			while(WaitNode -> Node . ln_Succ)
			{
				WaitNode -> Count = 0;

				WaitNode = (struct WaitNode *)WaitNode -> Node . ln_Succ;
			}

			WaitNode = NULL;
		}
	}

	if(RexxTimeoutVal)
		StartTime(RexxTimeoutVal,0);

	WaitCount = 0;

	BlockWindows();

	Forbid();

	LT_UnlockWindow(Window);

	Window -> Flags |= WFLG_RMBTRAP;

	Permit();

	if(Marking)
		DropMarker();

	NormalCursor();

	if(DataHold)
	{
		if(Echo)
		{
			ConProcess(DataHold,DataSize);

			Status = STATUS_READY;
		}

		if(Result = ScanNodeFilter(DataHold,DataSize,WaitNode,&Position))
		{
			if(Position < DataSize)
			{
				DataHold += Position;
				DataSize -= Position;
			}
			else
			{
				DataHold = NULL;

				RestartSerial(TRUE);
			}
		}
		else
		{
			DataHold = NULL;

			RestartSerial(TRUE);
		}
	}

	if(!Result)
	{
		if(CheckSerialRead())
			Signals = SIG_SERIAL;
		else
			Signals = NULL;

		do
		{
			if(Signals & SIG_WINDOW)
			{
				if(!Result)
				{
					SerWriteBypass = RexxWaitBypass;

					RexxWaitResult	= Result;
					RexxWaitNode	= WaitNode;

					while(HandleWindow());

					Result = RexxWaitResult;

					SerWriteBypass = NULL;
				}
			}

			if(Signals & SIG_SERIAL)
			{
				BOOLEAN Restart = TRUE;

				if(!WaitSerialRead())
				{
					LONG Length;

					BytesIn++;

					if(Translate_CR_LF)
						Length = (*Translate_CR_LF)(ReadBuffer,1);
					else
						Length = 1;

					if(Echo && Length)
					{
						ConProcess(ReadBuffer,Length);

						Status = STATUS_READY;
					}

					if(!Result && Length)
						Result = ScanNodeFilter(ReadBuffer,Length,WaitNode,&Position);

					if(!Result)
					{
							/* Check how many bytes are still in
							 * the serial buffer.
							 */

						if(Length = GetSerialWaiting())
						{
							if(Length > SerialBufferSize)
								Length = SerialBufferSize;

							if(Length > Config -> SerialConfig -> Quantum)
								Length = Config -> SerialConfig -> Quantum;

							if(!DoSerialRead(ReadBuffer,Length))
							{
								BytesIn += Length;

								if(Translate_CR_LF)
									Length = (* Translate_CR_LF)(ReadBuffer,Length);

								if(Length)
								{
										/* Send the data to the console. */

									if(Echo)
									{
										ConProcess(ReadBuffer,Length);

										Status = STATUS_READY;
									}

									if(Result = ScanNodeFilter(ReadBuffer,Length,WaitNode,&Position))
									{
										if(Position < Length)
										{
											DataHold = (UBYTE *)ReadBuffer	+ Position;
											DataSize = Length		- Position;

											Restart = FALSE;
										}
										else
											DataHold = NULL;
									}
								}
							}
						}
					}
				}

				if(Restart)
					RestartSerial(TRUE);
			}

			if(Signals & (SIG_BREAK | SIG_TIMER))
			{
				if(!Result)
					Results[0] = RC_WARN;

				break;
			}

			if(!Result)
				Signals = Wait(SIG_SERIAL | SIG_TIMER | SIG_BREAK | SIG_WINDOW);
		}
		while(!Result);
	}

	Forbid();

	Window -> Flags &= ~WFLG_RMBTRAP;

	LT_LockWindow(Window);

	Permit();

	ReleaseWindows();

	if(RexxTimeoutVal)
		StopTime();

	if(Result)
		return(CreateResult(Result,Results));
	else
		return(NULL);
}

STRPTR
RexxWindow(struct RexxPkt *Pkt)
{
	enum	{	ARG_WINDOW_NAMES,ARG_WINDOW_OPEN,ARG_WINDOW_CLOSE,ARG_WINDOW_ACTIVATE,
			ARG_WINDOW_MIN,ARG_WINDOW_MAX,ARG_WINDOW_FRONT,ARG_WINDOW_BACK,
			ARG_WINDOW_TOP,ARG_WINDOW_BOTTOM,ARG_WINDOW_UP,ARG_WINDOW_DOWN };

	STRPTR	*Names = (STRPTR *)Args[ARG_WINDOW_NAMES];
	WORD	 Index;

	while(*Names)
	{
		if((Index = ToWindow(*Names++)) != -1)
		{
			if(Args[ARG_WINDOW_OPEN])
			{
				Forbid();

				switch(Index)
				{
					case WINDOWID_BUFFER:

						ObtainSemaphore(&BufferTaskSemaphore);

						if(!BufferTask)
						{
							ReleaseSemaphore(&BufferTaskSemaphore);

							LaunchBuffer();
						}
						else
							ReleaseSemaphore(&BufferTaskSemaphore);

						break;

					case WINDOWID_UPLOAD_QUEUE:

						CreateQueueProcess();

						break;

					case WINDOWID_REVIEW:

						if(!ReviewWindow)
							CreateReview();

						break;

					case WINDOWID_PACKET:

						if(!PacketWindow)
							CreatePacketWindow();

						break;

					case WINDOWID_FASTMACROS:

						if(!FastWindow)
							OpenFastWindow();

						break;

					case WINDOWID_STATUS:

						if(!InfoWindow)
							OpenInfoWindow();

						break;

					case WINDOWID_MAIN:

						if(!IconTerminated)
							IconTerminated = TRUE;

						break;
				}

				Permit();
			}

			if(Args[ARG_WINDOW_CLOSE])
			{
				Forbid();

				switch(Index)
				{
					case WINDOWID_UPLOAD_QUEUE:

						CloseQueueWindow();
						break;

					case WINDOWID_BUFFER:

						ObtainSemaphore(&BufferTaskSemaphore);

						if(BufferTask)
						{
							Signal(BufferTask,SIG_KILL);

							ReleaseSemaphore(&BufferTaskSemaphore);

							ClrSignal(SIG_HANDSHAKE);

							Wait(SIG_HANDSHAKE);
						}
						else
							ReleaseSemaphore(&BufferTaskSemaphore);

						break;

					case WINDOWID_REVIEW:

						if(ReviewWindow)
							DeleteReview();

						break;

					case WINDOWID_PACKET:

						if(PacketWindow)
							DeletePacketWindow(FALSE);

						break;

					case WINDOWID_FASTMACROS:

						if(FastWindow)
							CloseFastWindow();

						break;

					case WINDOWID_STATUS:

						if(InfoWindow)
							CloseInfoWindow();

						break;

					case WINDOWID_MAIN:

						if(Window)
							DoIconify = TRUE;

						break;
				}

				Permit();
			}

			if(Args[ARG_WINDOW_ACTIVATE])
			{
				Forbid();

				switch(Index)
				{
					case WINDOWID_UPLOAD_QUEUE:

						CreateQueueProcess();

						break;

					case WINDOWID_BUFFER:

						ObtainSemaphore(&BufferTaskSemaphore);

						if(BufferTask)
						{
							ReleaseSemaphore(&BufferTaskSemaphore);

							LaunchBuffer();
						}
						else
							ReleaseSemaphore(&BufferTaskSemaphore);

						break;

					case WINDOWID_REVIEW:

						if(ReviewWindow)
							BumpWindow(ReviewWindow);

						break;

					case WINDOWID_PACKET:

						if(PacketWindow)
							BumpWindow(PacketWindow);

						break;

					case WINDOWID_FASTMACROS:

						if(FastWindow)
							BumpWindow(FastWindow);

						break;

					case WINDOWID_STATUS:

						if(InfoWindow)
							BumpWindow(InfoWindow);

						break;

					case WINDOWID_MAIN:

						if(Window)
							BumpWindow(Window);

						break;
				}

				Permit();
			}

			if(Args[ARG_WINDOW_MIN])
			{
				struct Window *SomeWindow = NULL;

				Forbid();

				switch(Index)
				{
					case WINDOWID_REVIEW:

						SomeWindow = ReviewWindow;
						break;

					case WINDOWID_PACKET:

						SomeWindow = PacketWindow;
						break;

					case WINDOWID_FASTMACROS:

						SomeWindow = FastWindow;
						break;

					case WINDOWID_STATUS:

						SomeWindow = InfoWindow;
						break;
				}

				if(SomeWindow)
					ChangeWindowBox(SomeWindow,SomeWindow -> LeftEdge,SomeWindow -> TopEdge,SomeWindow -> MinWidth,SomeWindow -> MinHeight);

				Permit();
			}

			if(Args[ARG_WINDOW_MAX])
			{
				struct Window *SomeWindow = NULL;

				Forbid();

				switch(Index)
				{
					case WINDOWID_REVIEW:

						SomeWindow = ReviewWindow;
						break;

					case WINDOWID_PACKET:

						SomeWindow = PacketWindow;
						break;

					case WINDOWID_FASTMACROS:

						SomeWindow = FastWindow;
						break;

					case WINDOWID_STATUS:

						SomeWindow = InfoWindow;
						break;
				}

				if(SomeWindow)
					ChangeWindowBox(SomeWindow,0,0,SomeWindow -> MaxWidth,SomeWindow -> MaxHeight);

				Permit();
			}

			if(Args[ARG_WINDOW_FRONT])
			{
				Forbid();

				switch(Index)
				{
					case WINDOWID_UPLOAD_QUEUE:

						CreateQueueProcess();

						break;

					case WINDOWID_BUFFER:

						ObtainSemaphore(&BufferTaskSemaphore);

						if(BufferTask)
						{
							ReleaseSemaphore(&BufferTaskSemaphore);

							LaunchBuffer();
						}
						else
							ReleaseSemaphore(&BufferTaskSemaphore);

						break;

					case WINDOWID_REVIEW:

						if(ReviewWindow)
							WindowToFront(ReviewWindow);

						break;

					case WINDOWID_PACKET:

						if(PacketWindow)
							WindowToFront(PacketWindow);

						break;

					case WINDOWID_FASTMACROS:

						if(FastWindow)
							WindowToFront(FastWindow);

						break;

					case WINDOWID_STATUS:

						if(InfoWindow)
							WindowToFront(InfoWindow);

						break;

					case WINDOWID_MAIN:

						if(Window)
							WindowToFront(Window);

						break;
				}

				Permit();
			}

			if(Args[ARG_WINDOW_BACK])
			{
				Forbid();

				switch(Index)
				{
					case WINDOWID_REVIEW:

						if(ReviewWindow)
							WindowToBack(ReviewWindow);

						break;

					case WINDOWID_PACKET:

						if(PacketWindow)
							WindowToBack(PacketWindow);

						break;

					case WINDOWID_FASTMACROS:

						if(FastWindow)
							WindowToBack(FastWindow);

						break;

					case WINDOWID_STATUS:

						if(InfoWindow)
							WindowToBack(InfoWindow);

						break;

					case WINDOWID_MAIN:

						if(Window)
							WindowToBack(Window);

						break;
				}

				Permit();
			}

			Forbid();

			if(Index == WINDOW_REVIEW && ReviewWindow)
			{
				if(Args[ARG_WINDOW_TOP])
					MoveReview(REVIEW_MOVE_TOP);

				if(Args[ARG_WINDOW_BOTTOM])
					MoveReview(REVIEW_MOVE_BOTTOM);

				if(Args[ARG_WINDOW_UP])
					MoveReview(REVIEW_MOVE_UP);

				if(Args[ARG_WINDOW_DOWN])
					MoveReview(REVIEW_MOVE_DOWN);
			}

			Permit();
		}
	}

	return(NULL);
}

STRPTR
RexxRX(struct RexxPkt *Pkt)
{
	enum	{	ARG_RX_CONSOLE,ARG_RX_ASYNC,ARG_RX_COMMAND };

	struct MsgPort	*RexxPort;
	BYTE		 Eaten = FALSE;

	if(RexxPort = FindPort(RXSDIR))
	{
		struct MsgPort __aligned	 SinglePort;
		struct RexxMsg			*HostMessage;

		InitSinglePort(&SinglePort);

		if(HostMessage = CreateRexxMsg(&SinglePort,"term",RexxPortName))
		{
			if(HostMessage -> rm_Args[0] = CreateArgstring(Args[ARG_RX_COMMAND],strlen(Args[ARG_RX_COMMAND])))
			{
				HostMessage -> rm_Action = RXCOMM;

				if(!GoodStream(NULL))
					HostMessage -> rm_Action |= RXFF_NOIO;

				if(Args[ARG_RX_ASYNC])
				{
					RexxPktCleanup(Pkt,NULL);

					Eaten = TRUE;
				}

				Forbid();

				PutMsg(RexxPort,HostMessage);

				ClrSignal(SIGF_SINGLE);

				WaitPort(&SinglePort);

				Permit();

				GetMsg(&SinglePort);

				if(!Eaten)
				{
					Results[0] = HostMessage -> rm_Result1;
					Results[1] = HostMessage -> rm_Result2;
				}
			}
			else
			{
				Results[0] = RC_ERROR;
				Results[1] = ERR10_003;
			}

			DeleteRexxMsg(HostMessage);
		}
		else
		{
			Results[0] = RC_ERROR;
			Results[1] = ERR10_003;
		}
	}
	else
	{
		Results[0] = RC_ERROR;
		Results[1] = ERR10_013;
	}

	if(!Eaten)
		RexxPktCleanup(Pkt,NULL);

	return(NULL);
}

STRPTR
RexxExecTool(struct RexxPkt *Pkt)
{
	enum	{	ARG_EXECTOOL_CONSOLE,ARG_EXECTOOL_ASYNC,ARG_EXECTOOL_PORT,ARG_EXECTOOL_COMMAND };

	LONG	 Error;
	UBYTE	 CommandName[256],
		 CommandArgs[256],
		*Index = Args[ARG_EXECTOOL_COMMAND];
	WORD	 i;
	BYTE	 Eaten = FALSE;

	while(*Index == ' ' || *Index == '\t')
		Index++;

	for(i = 0 ; Index[i] != ' ' && Index[i] != '\t' ; i++)
		CommandName[i] = Index[i];

	CommandName[i] = 0;

	Index += i;

	while(*Index == ' ' || *Index == '\t')
		Index++;

	if(Args[ARG_EXECTOOL_PORT])
		SPrintf(CommandArgs,"%s %s\n",Index,RexxPortName);
	else
		SPrintf(CommandArgs,"%s\n",Index);

	if(Args[ARG_EXECTOOL_ASYNC])
	{
		RexxPktCleanup(Pkt,NULL);

		Eaten = TRUE;
	}

	Error = SystemTags(CommandName,
		NP_Arguments,	CommandArgs,
		SYS_UserShell,	TRUE,
	TAG_DONE);

	if(!Eaten)
	{
		if(Error)
		{
			Results[0] = RC_ERROR;
			Results[1] = Error;
		}

		RexxPktCleanup(Pkt,NULL);
	}

	return(NULL);
}
