/*
**	termMain.c
**
**	Program main routines and event loop
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Argument vectors offsets. */

enum	{	ARG_SETTINGS,ARG_DEVICE,ARG_UNIT,ARG_KEEPIO,ARG_DONTPOP,ARG_COUNT };

	/* Argument template. */

#define ARGTEMPLATE "SETTINGS/K,DEVICE/K,UNIT/K/N,K=KEEPIO/S,D=DONTPOP/S"

	/* Some global variables for starters. */

STATIC BYTE	DoIconify = FALSE;

	/* Local config path variable. */

STATIC STRPTR	ConfigPath;
STATIC UBYTE	ThePath[256];

	/* Segment split routine, has to be local. */

STATIC struct Process * SegmentSplit(STRPTR Name,BYTE Pri,LONG StackSize,APTR Function);
STATIC VOID		CloseLibs(VOID);

	/* main():
	 *
	 *	This is our main entry point, check for the right
	 *	Kickstart version and fire off the background task
	 *	if approritate.
	 */

LONG
main()
{
	STRPTR Result;

		/* Are we running as a child of Workbench? */

	ThisProcess = (struct Process *)SysBase -> ThisTask;

	if(!ThisProcess -> pr_CLI)
	{
		WaitPort(&ThisProcess -> pr_MsgPort);

		WBenchMsg = (struct WBStartup *)GetMsg(&ThisProcess -> pr_MsgPort);
	}
	else
		WBenchMsg = NULL;

		/* Now try to open dos.library and utility.library and go on examining
		 * our calling parameters.
		 */

	if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0)))
	{
		CloseLibs();

		return(RETURN_FAIL);
	}

	if(!(UtilityBase = OpenLibrary("utility.library",0)))
	{
		CloseLibs();

		return(RETURN_FAIL);
	}

		/* We were called from Shell. */

	if(ThisProcess -> pr_CLI)
	{
		STRPTR *ArgArray;

			/* Use the cute ReadArgs parser, allocate the
			 * argument vectors...
			 */

		if(ArgArray = (STRPTR *)AllocVec(sizeof(STRPTR) * (ARG_COUNT),MEMF_ANY|MEMF_CLEAR))
		{
			struct RDArgs *ArgsPtr;

			if(ArgsPtr = (struct RDArgs *)AllocDosObject(DOS_RDARGS,TAG_DONE))
			{
				ArgsPtr -> RDA_ExtHelp = "\nUsage: \33[1mterm\33[0m [Settings <Path name>] [Device <Device name>] [Unit <Unit number>]\n            [KeepIO] [DontPop]\n\n       Settings = Path to search for settings files.\n         Device = Serial device driver to use.\n           Unit = Serial device driver unit to use.\n         KeepIO = Keep links to the current Shell window.\n        DontPop = Do not pop an already running `term' to the front.\n\n";

					/* Parse the args (if any). */

				if(ReadArgs(ARGTEMPLATE,(LONG *)ArgArray,ArgsPtr))
				{
						/* Pop a running `term' to the front? */

					if((TermPort = (struct TermPort *)FindPort("term Port")) && !ArgArray[ARG_DONTPOP])
					{
						if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
						{
							if(TermPort -> TopWindow)
								BumpWindow(TermPort -> TopWindow);
						}

						TermPort = NULL;

						FreeArgs(ArgsPtr);
						FreeDosObject(DOS_RDARGS,ArgsPtr);
						FreeVec(ArgArray);

						CloseLibs();

						return(RETURN_OK);
					}

						/* Are we to use a special settings path? */

					if(ArgArray[ARG_SETTINGS])
					{
						ConfigPath = ThePath;

						strcpy(ThePath,ArgArray[ARG_SETTINGS]);
					}

						/* Are we to use a special device? */

					if(ArgArray[ARG_DEVICE])
					{
						if(ArgArray[ARG_DEVICE][0])
						{
							strcpy(NewDevice,ArgArray[ARG_DEVICE]);

							UseNewDevice = TRUE;
						}
					}

						/* Are we to use a special unit number? */

					if(ArgArray[ARG_UNIT])
					{
						NewUnit = *(LONG *)ArgArray[ARG_UNIT];

						UseNewUnit = TRUE;
					}

						/* We are to keep our links to
						 * the Shell.
						 */

					if(ArgArray[ARG_KEEPIO])
					{
						BYTE OldPri = ThisProcess -> pr_Task . tc_Node . ln_Pri;

							/* Do we have enough stack space available? */

						if(((struct CommandLineInterface *)BADDR(ThisProcess -> pr_CLI)) -> cli_DefaultStack < 4096)
						{
							Printf("\33[1mterm:\33[0m %s.\a\n","Sorry, the Shell stack must be at least 16384 bytes large");

							FreeArgs(ArgsPtr);
							FreeDosObject(DOS_RDARGS,ArgsPtr);
							FreeVec(ArgArray);

							CloseLibs();

							return(RETURN_FAIL);
						}

							/* Open our resources and
							 * squeak on failure.
							 */

						if(Result = OpenAll(ConfigPath))
						{
							if(Result[0])
								Printf("\33[1mterm:\33[0m %s!\a\n",Result);

							FreeArgs(ArgsPtr);
							FreeDosObject(DOS_RDARGS,ArgsPtr);
							FreeVec(ArgArray);

							CloseAll(TRUE);

							return(RETURN_FAIL);
						}

							/* Go into main input
							 * loop.
							 */

						HandleInput();

							/* Does anybody understand
							 * this joke?
							 */

						Printf("You quit with 0 gold pieces\nTo play again, just type \"term\"\n");

							/* Free the argument
							 * data.
							 */

						FreeArgs(ArgsPtr);
						FreeDosObject(DOS_RDARGS,ArgsPtr);
						FreeVec(ArgArray);

							/* Restore old priority. */

						SetTaskPri(ThisProcess,(LONG)OldPri);

							/* Terminate execution. */

						CloseAll(TRUE);

						return(RETURN_OK);
					}

					FreeArgs(ArgsPtr);
				}
				else
				{
					PrintFault(IoErr(),"term");

					FreeDosObject(DOS_RDARGS,ArgsPtr);
					FreeVec(ArgArray);

					return(RETURN_ERROR);
				}

				FreeDosObject(DOS_RDARGS,ArgsPtr);
			}

			FreeVec(ArgArray);

				/* Create a new process from our code. */

			if(!SegmentSplit("term main process",0,16384,HandleInput))
			{
				Printf("\33[1mterm:\33[0m Failed to create new process!\a\n");

				CloseLibs();

				return(RETURN_FAIL);
			}
		}
		else
		{
			Printf("\33[1mterm:\33[0m Failed to allocate argument vectors!\a\n");

			CloseLibs();

			return(RETURN_FAIL);
		}
	}
	else
	{
		LONG StackSize;

		StackSize = (LONG)SysBase -> ThisTask -> tc_SPUpper - (LONG)SysBase -> ThisTask -> tc_SPLower;

		if(StackSize < 16384)
		{
			if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37))
				MyEasyRequest(NULL,"`term' has a problem:\nThe current stack size of %ld bytes is too low,\nplease edit the icon file to use at least\n16384 bytes and restart the proram.","Continue",StackSize);

			CloseLibs();

			return(RETURN_FAIL);
		}
		else
		{
			CurrentDir(WBenchMsg -> sm_ArgList -> wa_Lock);

				/* Open icon.library, we want to take a
				 * look at the icon.
				 */

			if(IconBase = OpenLibrary("icon.library",0))
			{
				struct DiskObject *Icon;

					/* Try to read the icon file. */

				if(Icon = GetDiskObject(WBenchMsg -> sm_ArgList -> wa_Name))
				{
					STRPTR Type;

						/* Look for a `Settings' tooltype. */

					if(ConfigPath = FindToolType(Icon -> do_ToolTypes,"SETTINGS"))
					{
							/* Remember the path and continue. */

						strcpy(ThePath,ConfigPath);

						ConfigPath = ThePath;
					}

						/* Look for a `Device' tooltype. */

					if(Type = FindToolType(Icon -> do_ToolTypes,"DEVICE"))
					{
						if(Type[0])
						{
							strcpy(NewDevice,Type);

							UseNewDevice = TRUE;
						}
					}

						/* Look for a `Unit' tooltype. */

					if(Type = FindToolType(Icon -> do_ToolTypes,"UNIT"))
					{
						if(Type[0])
						{
							NewUnit = Atol(Type);

							UseNewUnit = TRUE;
						}
					}

						/* Free the icon. */

					FreeDiskObject(Icon);
				}

					/* Close the library. */

				CloseLibrary(IconBase);

				IconBase = NULL;
			}

				/* Initialize this, so OpenAll will work with
				 * correct data.
				 */

			TermPort = (struct TermPort *)FindPort("term Port");

				/* We were called from Workbench. */

			if(Result = OpenAll(ConfigPath))
			{
				if(IntuitionBase && Result[0])
					MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Result);

				CloseAll(TRUE);
			}
			else
				HandleInput();
		}
	}

	return(RETURN_OK);
}

	/* CloseLibs():
	 *
	 *	Plain and simple: close two libraries and clean up.
	 */

STATIC VOID
CloseLibs()
{
	if(UtilityBase)
	{
		CloseLibrary(UtilityBase);

		UtilityBase = NULL;
	}

	if(DOSBase)
	{
		CloseLibrary(DOSBase);

		DOSBase = NULL;
	}

	if(WBenchMsg)
	{
		Forbid();

		ReplyMsg((struct Message *)WBenchMsg);
	}
}

	/* ProcessCleanup(register __d1 BPTR SegList):
	 *
	 *	Frees all resource the main process has allocated when
	 *	it exits.
	 */

STATIC VOID __saveds __asm
ProcessCleanup(register __d1 BPTR SegList)
{
	CloseAll(FALSE);

	Forbid();

	UnLoadSeg(SegList);

	CloseLibrary(DOSBase);

	DOSBase = NULL;
}

	/* SegmentSplit(STRPTR Name,BYTE Pri,LONG StackSize,APTR Function):
	 *
	 *	Create a new process from the current one.
	 */

STATIC struct Process *
SegmentSplit(STRPTR Name,BYTE Pri,LONG StackSize,APTR Function)
{
	struct Process			*Child;
	struct CommandLineInterface	*CLI;

	CLI = (struct CommandLineInterface *)BADDR(((struct Process *)SysBase -> ThisTask) -> pr_CLI);

	if(Child = CreateNewProcTags(
		NP_CommandName,	"term",
		NP_Name,	Name,
		NP_Priority,	Pri,
		NP_StackSize,	StackSize,
		NP_Entry,	Function,
		NP_Cli,		TRUE,
		NP_ExitCode,	ProcessCleanup,
		NP_ExitData,	CLI -> cli_Module,
	TAG_DONE))
	{
		CLI -> cli_Module = NULL;

		return(Child);
	}
	else
		return(NULL);
}

	/* HandleInput():
	 *
	 *	This is our main input loop (check window & serial).
	 */

VOID __saveds
HandleInput()
{
	ULONG SignalSet = NULL,SavageSignals = NULL;

	ThisProcess = (struct Process *)SysBase -> ThisTask;

		/* Open the resources we need. */

	if(!IntuitionBase)
	{
		STRPTR Result;

		if(Result = OpenAll(ConfigPath))
		{
			if(IntuitionBase && Result[0])
				MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Result);

			CloseAll(TRUE);

			return;
		}
	}

	BumpWindow(Window);

		/* Set up the public screen data. */

	PubScreenStuff();

		/* Change program priority. */

	SetTaskPri(ThisProcess,(LONG)Config . MiscConfig . Priority);

	BlockWindows();

		/* Load the phone book. */

	LoadPhonebook(LastPhone);

		/* Show our business card. */

	if(ShowInfo(TRUE))
		SignalSet |= SIG_REXX;

	ReleaseWindows();

		/* Initialize the modem. */

	SerialCommand(Config . ModemConfig . ModemInit);

		/* Execute the startup macro (if any). */

	if(Config . CommandConfig . StartupMacro[0])
		SerialCommand(Config . CommandConfig . StartupMacro);

	LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_PROGRAM_STARTED_TXT),TermName,TermDate);

		/* Go into input loop... */

Loop:	while(!MainTerminated)
	{
			/* Is the serial write request available? */

		if((SignalSet & SIG_CHECK) && WriteRequest)
		{
				/* Query serial status. */

			WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

			DoIO(WriteRequest);

				/* Is the carrier detect signal
				 * still present?
				 */

			if(WriteRequest -> io_Status & (1 << 5))
			{
				WasOnline	= TRUE;
				Online		= FALSE;
			}
		}

			/* If no longer online, get back to the
			 * previous configuration.
			 */

		if(!Online)
		{
			BYTE ShowRate = TRUE;

			if(WasOnline)
			{
				StopCall(FALSE);

				SetDialMenu(TRUE);

					/* Execute logoff macro. */

				if(Config . CommandConfig . LogoffMacro[0])
					SerialCommand(Config . CommandConfig . LogoffMacro);

					/* Clear the password. */

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

				WasOnline = FALSE;
			}

			ChosenEntry = NULL;

				/* Previous configuration available? */

			if(BackupConfig)
			{
					/* Remember old configuration. */

				PrivateConfig = Config;

					/* Copy configuration. */

				memcpy(&Config,BackupConfig,sizeof(struct Configuration));

					/* Set up new configuration. */

				ConfigSetup();

					/* Free old configuration. */

				FreeVec(BackupConfig);

				BackupConfig = NULL;

					/* Don't show the rate yet. */

				ShowRate = FALSE;
			}

			if(CurrentPay && ShowRate)
			{
				/* Display how much we expect
				 * the user will have to pay for
				 * this call.
				 */

				ConWrites(LocaleString(MSG_TERMMAIN_THIS_CALL_WILL_COST_YOU_TXT),CreateSum(CurrentPay,TRUE));

				CurrentPay = 0;
			}
		}

			/* Take care of external terminal emulation library. */

		if(SignalSet & XEM_Signal)
		{
			if(!XEmulatorSignal(XEM_IO,SignalSet))
			{
				CloseEmulator();

				ResetDisplay = TRUE;
			}
		}

			/* A SIG_CLIP will cause us to transmit the current contents of
			 * the clipboard...
			 */

		if(SignalSet & SIG_CLIP)
		{
			if(!ClipInput)
			{
				if(!OpenClip())
					ClipInput = ClipXerox = TRUE;
				else
					ClipInput = ClipXerox = FALSE;
			}
		}

			/* Loop & check until the dust has settled. */

		if((SignalSet & (SIG_WINDOW | SavageSignals | SIG_CLIP)) || HostReadBuffer)
			while(HandleWindow() || HandleSerial() || HandlePacket() || HandleReview());

			/* Remove audio request. */

		if(SignalSet & SIG_AUDIO)
			ClearAudio();

			/* Make the user notice not too obvious events. */

		if(FlowInfo . Changed)
		{
			if(!Online && (FlowInfo . Voice || FlowInfo . Ring || FlowInfo . Connect))
			{
				WakeUp(Window);

				if(FlowInfo . Voice)
				{
					ConWrites(LocaleString(MSG_TERMMAIN_INCOMING_VOIC_CALL_TXT));

					Say(LocaleString(MSG_TERMMAIN_SAY_INCOMING_VOICE_CALL_TXT));
				}

				if(FlowInfo . Ring)
				{
					ConWrites(LocaleString(MSG_TERMMAIN_INCOMING_CALL_TXT));

					Say(LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));
				}

				if(FlowInfo . Connect)
				{
					Online		= TRUE;
					BaudPending	= FALSE;

					SetDialMenu(FALSE);
				}
			}

				/* Check if we are to prompt the user for
				 * ZModem upload type.
				 */

			if(UsesZModem && FlowInfo . ZModemUpload && XProtocolBase)
			{
				if(Config . MiscConfig . AutoUpload)
				{
					BlockWindows();

					switch(UploadPanel())
					{
						case UPLOAD_TEXT:	BinaryTransfer = FALSE;

									if(!StartXprSend(TRANSFER_TEXT))
										SerWrite(ZModemCancel,20);

									break;

						case UPLOAD_BINARY:	BinaryTransfer = TRUE;

									if(!StartXprSend(TRANSFER_BINARY))
										SerWrite(ZModemCancel,20);

									break;

						case UPLOAD_IGNORE:	break;

						case UPLOAD_ABORT:	SerWrite(ZModemCancel,20);
									break;
					}

					ReleaseWindows();
				}
			}

			FlowInit(TRUE);
		}

			/* Check for rexx messages to be processed. */

		if(SignalSet & SIG_REXX)
		{
			HandleRexx();

			if(MainTerminated)
				break;
		}

			/* Iconify the program? */

		if(DoIconify)
		{
			BYTE Released = FALSE;

				/* Set the wait mouse pointer... */

			BlockWindows();

				/* Open workbench.library. */

			if(WorkbenchBase = OpenLibrary("workbench.library",0))
			{
					/* Open icon.library. */

				if(IconBase = OpenLibrary("icon.library",0))
				{
					struct DiskObject *Icon = NULL;

						/* Get the program icon. */

					if(WBenchMsg)
					{
						if(WBenchMsg -> sm_ArgList)
						{
							if(WBenchMsg -> sm_ArgList -> wa_Name)
								Icon = GetDiskObjectNew(WBenchMsg -> sm_ArgList -> wa_Name);
						}
					}

						/* No icon? Use the default name. */

					if(!Icon)
						Icon = GetDiskObjectNew("term");

						/* Did we get any icon? */

					if(Icon)
					{
							/* Not a tool icon? */

						if(Icon -> do_Type != WBTOOL)
						{
								/* Get rid of it... */

							FreeDiskObject(Icon);

								/* Get the default tool icon. */

							Icon = GetDefDiskObject(WBTOOL);
						}
					}
					else
					{
							/* Get the default tool icon. */

						Icon = GetDefDiskObject(WBTOOL);
					}

						/* Did we get an icon? */

					if(Icon)
					{
						struct MsgPort *IconPort;

							/* Default icon position. */

						Icon -> do_CurrentX = NO_ICON_POSITION;
						Icon -> do_CurrentY = NO_ICON_POSITION;

							/* Create the Workbench reply port. */

						if(IconPort = CreateMsgPort())
						{
							struct AppIcon *AppIcon;

								/* Add the application icon. */

							if(AppIcon = AddAppIcon(0,0,TermIDString,IconPort,NULL,Icon,NULL))
							{
								BYTE			 IconTerminated = FALSE;
								struct AppMessage	*AppMessage;
								UBYTE			*String,*Error;

									/* Release the window. */

								Released = TRUE;

								ReleaseWindows();

									/* Reset and release the serial driver. */

								if(Config . MiscConfig . ReleaseDevice)
								{
									ClearSerial();

									DeleteSerial();
								}

									/* Close the display. full stop. */

								DeleteDisplay();

									/* Wait for double-click. */

IconLoop:							while(!IconTerminated)
								{
									ULONG SignalSet = Wait((1 << IconPort -> mp_SigBit) | SIG_REXX);

									if(SignalSet & (1 << IconPort -> mp_SigBit))
									{
											/* Pick up application messages. */

										while(AppMessage = (struct AppMessage *)GetMsg(IconPort))
										{
												/* Received a double-click? */

											IconTerminated = TRUE;

											ReplyMsg(AppMessage);
										}
									}

										/* Wake up if ARexx command received. */

									if(SignalSet & SIG_REXX)
										IconTerminated = TRUE;
								}

									/* Open the serial driver. */

								if(Config . MiscConfig . ReleaseDevice)
								{
									if(Error = CreateSerial())
									{
										DeleteSerial();

										switch(MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_ICONIFY_IGNORE_QUIT_TXT),Error))
										{
											case 1:		goto IconLoop;
											case 2:		break;
											case 0:		MainTerminated = TRUE;
										}
									}
									else
									{
										if(SerialMessage)
										{
											MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SerialMessage);

											SerialMessage = NULL;
										}
									}
								}

									/* Create the display. */

								if(String = CreateDisplay(FALSE))
								{
									if(MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_ICONIFY_QUIT_TXT),String))
									{
										ClearSerial();

										DeleteSerial();

										IconTerminated = FALSE;

										goto IconLoop;
									}
									else
										MainTerminated = FALSE;
								}
								else
								{
									BumpWindow(Window);

									PubScreenStuff();
								}

									/* Remove the application icon. */

								RemoveAppIcon(AppIcon);

									/* Reply pending messages. */

								while(AppMessage = (struct AppMessage *)GetMsg(IconPort))
									ReplyMsg(AppMessage);
							}
							else
								MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_ADD_APPLICATION_ICON_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

							DeleteMsgPort(IconPort);
						}
						else
							MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FAILED_TO_CREATE_MSGPORT_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

						FreeDiskObject(Icon);
					}
					else
						MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_TOOL_ICON_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

					CloseLibrary(IconBase);

					IconBase = NULL;
				}
				else
					MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_ICON_LIBRARY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

				CloseLibrary(WorkbenchBase);

				WorkbenchBase = NULL;
			}
			else
				MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_WORKBENCH_LIBRARY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

			if(!Released)
				ReleaseWindows();

				/* Finished! */

			DoIconify = FALSE;

				/* Just a check for safety. */

			HandleRexx();
		}

			/* Reset the serial driver? */

		if(ResetSerial)
		{
			STRPTR Error;

			ClearSerial();

			DeleteSerial();

			BlockWindows();

OpenLoop:		if(Error = CreateSerial())
			{
				APTR OldPtr = ThisProcess -> pr_WindowPtr;

				DeleteSerial();

				ThisProcess -> pr_WindowPtr = (APTR)Window;

				switch(MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_RETRY_IGNORE_QUIT_TXT),Error))
				{
					case 1:		goto OpenLoop;
					case 2:		break;
					case 0:		MainTerminated = TRUE;
				}

				ThisProcess -> pr_WindowPtr = OldPtr;
			}
			else
			{
				if(SerialMessage)
				{
					MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SerialMessage);

					SerialMessage = NULL;
				}

				ResetSerial = FALSE;
			}

			ReleaseWindows();
		}

			/* We are to release the serial.device (or
			 * whatever we are using) for some reason.
			 */

		if(ReleaseSerial)
		{
			APTR OldPtr = ThisProcess -> pr_WindowPtr;

			ThisProcess -> pr_WindowPtr = (APTR)Window;

				/* This might happen if an ARexx user
				 * released the serial device and
				 * failed to reopen it.
				 */

			if(!ReadPort)
				goto OpenIt;

			ClearSerial();

			DeleteSerial();

			BlockWindows();

			if(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_UNIT_RESET_AND_RELEASED_TXT),LocaleString(MSG_TERMMAIN_RETURN_QUIT_TXT),Config . SerialConfig . SerialDevice,Config . SerialConfig . UnitNumber))
			{
				STRPTR Error;

OpenIt:				if(Error = CreateSerial())
				{
					DeleteSerial();

					switch(MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_RETRY_IGNORE_QUIT_TXT),Error))
					{
						case 1:		goto OpenIt;
						case 2:		break;
						case 0:		MainTerminated = TRUE;
					}
				}
				else
				{
					if(SerialMessage)
					{
						MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SerialMessage);

						SerialMessage = NULL;
					}
				}
			}
			else
				MainTerminated = TRUE;

			ReleaseSerial = FALSE;

			ThisProcess -> pr_WindowPtr = OldPtr;

			ReleaseWindows();
		}

			/* Somebody told us to re-open the display
			 * (changed the terminal emulation/colour
			 * mode).
			 */

		if(ResetDisplay)
		{
			if(!DisplayReset())
				MainTerminated = TRUE;
		}

			/* Now for public screen mode changes. */

		if(FixPubScreenMode)
			PubScreenStuff();

			/* Now for window size changes. */

		if(FixScreenSize)
			ScreenSizeStuff();

		if(Blocking && !MainTerminated)
		{
			Blocking = FALSE;

			continue;
		}

			/* Set up the signal bits to wait for. */

		SavageSignals = XEM_Signal;

			/* The serial line is active. */

		if(Status != STATUS_HOLDING && ReadPort)
			SavageSignals |= SIG_SERIAL;

			/* The packet window is still open. */

		if(PacketWindow)
			SavageSignals |= SIG_PACKET;

			/* The review buffer window is open. */

		if(ReviewPort)
			SavageSignals |= SIG_REVIEW;

			/* Wait for input events to occur. */

		if(HostReadBuffer)
			SignalSet = CheckSignal(SIG_WINDOW | SIG_REXX | SIG_AUDIO | SIG_CLIP | SIG_CHECK | SavageSignals);
		else
			SignalSet = Wait(SIG_WINDOW | SIG_REXX | SIG_AUDIO | SIG_CLIP | SIG_CHECK | SavageSignals);
	}

		/* Shut down the transfer panel if any. */

	if(TransferWindow)
	{
		if(DidTransfer)
		{
			if(SendAbort && UsesZModem)
				SerWrite(ZModemCancel,20);
		}

		DeleteTransferPanel();
	}

		/* User wants to quit term, so let's try to close
		 * our magnificient screen and exit.
		 */

	if(Screen)
	{
		struct List		*PubScreenList;
		struct PubScreenNode	*ScreenNode;

			/* Lock the list of public screens. */

		PubScreenList = LockPubScreenList();

			/* Scan the list and try to find our
			 * private node.
			 */

		for(ScreenNode = (struct PubScreenNode *)PubScreenList -> lh_Head ; ScreenNode -> psn_Node . ln_Succ ; ScreenNode = (struct PubScreenNode *)ScreenNode -> psn_Node . ln_Succ)
		{
			if(ScreenNode -> psn_Screen == Screen)
				break;
		}

		if(ScreenNode)
		{
				/* Okay, we know who and where we are,
				 * check the number of visitor windows
				 * currently open on our screen.
				 */

			if(ScreenNode -> psn_VisitorCount)
			{
					/* No chance, don't close
					 * the screen now.
					 */

				UnlockPubScreenList();

				BlockWindows();

				MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_TERMMAIN_CANNOT_CLOSE_SCREEN_YET_TXT));

				ReleaseWindows();

				MainTerminated = FALSE;

				goto Loop;
			}
		}

		UnlockPubScreenList();
	}

		/* Send the modem exit command, shut down the
		 * serial.device and close all resources.
		 */

	SerialCommand(Config . ModemConfig . ModemExit);

	ClearSerial();

	LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_PROGRAM_TERMINATED_TXT));

	Say(LocaleString(MSG_TERMMAIN_BYE_BYE_TXT));

	if(Phonebook && PhoneSize)
		DeletePhonebook(Phonebook,PhoneSize,TRUE);

	if(!ThisProcess -> pr_CLI)
		CloseAll(TRUE);
}

	/* HandleWindow():
	 *
	 *	This funny part checks the window(s) for incoming
	 *	user input. Menus are handled elsewhere.
	 */

BYTE
HandleWindow()
{
	struct IntuiMessage	*Massage;
	ULONG			 Class,Code,Qualifier;
	LONG			 MouseX,MouseY,Len;
	struct Gadget		*Gadget;
	UBYTE			 Char,InputBuffer[257];
	struct Window		*IDCMPWindow;
	BYTE			 Result = FALSE;

	if(ClipInput)
	{
		WORD Len = GetClip(InputBuffer,256,FALSE);

		if(Len < 0)
		{
			CloseClip();

			ClipInput = FALSE;

			if(ClipXerox)
			{
				if(Config . ClipConfig . InsertSuffix[0])
					SerialCommand(Config . ClipConfig . InsertSuffix);

				ClipXerox = FALSE;
			}

			ClipPrefix = FALSE;
		}
		else
		{
			if(!ClipPrefix && ClipXerox)
			{
				if(Config . ClipConfig . InsertPrefix[0])
					SerialCommand(Config . ClipConfig . InsertPrefix);

				ClipPrefix = TRUE;
			}

			if(Len > 0)
			{
					/* Is a send-delay enabled? */

				if(Config . ClipConfig . CharDelay || Config . ClipConfig . LineDelay)
				{
					WORD i;

						/* Run down the buffer... */

					for(i = 0 ; i < Len ; i++)
					{
						SerWrite(&InputBuffer[i],1);

							/* What kind of delay
							 * are we to provide?
							 */

						switch(InputBuffer[i])
						{
							case '\r':	if(Config . ClipConfig . LineDelay)
										WaitTime(Config . ClipConfig . LineDelay / 100,(Config . ClipConfig . LineDelay % 100) * 10000);

									break;

							default:	if(Config . ClipConfig . CharDelay)
										WaitTime(Config . ClipConfig . CharDelay / 100,(Config . ClipConfig . CharDelay % 100) * 10000);

									break;
						}
					}
				}
				else
					SerWrite(InputBuffer,Len);
			}

			Result = TRUE;
		}
	}

		/* Any news in the mail? */

	if(Massage = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort))
	{
			/* Pick up the pieces. */

		Class		= Massage -> Class;
		Code		= Massage -> Code;
		Qualifier	= Massage -> Qualifier;

		MouseX		= Massage -> MouseX;
		MouseY		= Massage -> MouseY;

		IDCMPWindow	= Massage -> IDCMPWindow;

		if(Class == IDCMP_RAWKEY)
		{
				/* Perform key conversion. */

			if(XEmulatorBase)
			{
				if(Len = XEmulatorUserMon(XEM_IO,InputBuffer,256,Massage))
					Char = InputBuffer[0];
			}
			else
				Char = KeyConvert(Massage,InputBuffer,&Len);
		}

		GT_ReplyIMsg(Massage);

		if(IDCMPWindow == InfoWindow)
		{
			switch(Class)
			{
				case IDCMP_CLOSEWINDOW:	CloseInfoWindow();

							return(Result);

				case IDCMP_MOUSEBUTTONS:if(!(Code & IECODE_UP_PREFIX))
								RefreshInfoWindow();

							return(Result);

				default:		break;
			}
		}

			/* The following messages probably
			 * originated from the fast! macro
			 * panel.
			 */

		if(IDCMPWindow == FastWindow)
		{
			struct MacroNode *Node;

			switch(Class)
			{
							/* Close the window. */

				case IDCMP_CLOSEWINDOW:	CloseFastWindow();

							return(Result);

							/* Window size has changed for some reason. */

				case IDCMP_NEWSIZE:	if(FastWindow -> Height != Screen -> WBorTop + Screen -> Font -> ta_YSize + 1)
							{
								RefreshFastWindow(FastWindow -> Height);

								RefreshWindowFrame(FastWindow);
							}

							return(Result);

				case IDCMP_GADGETUP:	if(Node = GetFastMacro(Code))
							{
								if(Node -> mn_Code[0])
									SerialCommand(Node -> mn_Code);
							}

							return(Result);

				case IDCMP_MOUSEBUTTONS:return(Result);

				default:		break;
			}
		}

			/* This looks like a raw, or better, now cooked key. */

		if(Class == IDCMP_RAWKEY && Len)
		{
			if(ClipInput)
			{
				CloseClip();

				ClipInput = ClipXerox = ClipPrefix = FALSE;
			}

				/* VT100 prefers to handle
				 * the numeric keypad differently
				 * in applications mode.
				 */

			if(Qualifier & IEQUALIFIER_NUMERICPAD)
			{
				if(HandleCursor(Char,Qualifier))
					goto SkipIt;
			}

				/* If input is not a control
				 * character, such as F-keys,
				 * cursor keys, etc. process
				 * it as usual.
				 */

			if(!IsBlank(Char))
			{
				WORD	i;
				UBYTE	c;

					/* Run down the contents of
					 * the key result string.
					 */

				for(i = 0 ; i < Len ; i++)
				{
					if(Config . SerialConfig . StripBit8)
						c = InputBuffer[i] & 0x7F;
					else
						c = InputBuffer[i];

						/* Restart serial line
						 * after XON.
						 */

					if(Status == STATUS_HOLDING)
					{
						if(c == XOF)
						{
							SerWrite(&c,1);

							Status = STATUS_READY;
						}
						else
							DoBeep();
					}
					else
					{
							/* Convert chars
							 * as approriate.
							 */

						if(c == '\n')
						{
							switch(Config . TerminalConfig . SendLF)
							{
								case LF_IGNORE:	break;

								case LF_ASLF:	goto SendIt;

								case LF_ASLFCR:	SerWrite("\n\r",2);
										break;
							}

							continue;
						}

						if(c == '\r')
						{
							switch(Config . TerminalConfig . SendCR)
							{
								case CR_IGNORE:	break;

								case CR_ASCR:	goto SendIt;

								case CR_ASCRLF:	SerWrite("\r\n",2);
										break;
							}

							continue;
						}

							/* Stop in/output. */

						if(c == XON)
						{
							if(Config . SerialConfig . PassThrough)
							{
								SerWrite(&c,1);

								continue;
							}
							else
							{
								if(Config . SerialConfig . xONxOFF)
									Status = STATUS_HOLDING;
							}
						}

							/* Restart in/output. */

						if(c == XOF)
						{
							if(Config . SerialConfig . PassThrough)
							{
								SerWrite(&c,1);

								continue;
							}
						}

							/* Convert special
							 * Amiga characters into
							 * alien IBM dialect.
							 */

SendIt:						if(Config . TerminalConfig . FontMode == FONT_IBM)
						{
							if(IBMConversion[c])
								SerWrite(&IBMConversion[c],1);
							else
								SerWrite(&c,1);
						}
						else
							SerWrite(&c,1);
					}
				}
			}
			else
			{
					/* Send keyboard macro commands
					 * or perform cursor functions.
					 */

				if(Char >= FN1 && Char <= F10)
				{
					if(Qualifier & IEQUALIFIER_CONTROL)
						SerialCommand(MacroKeys -> Keys[3][Char - FN1]);
					else
					{
						if(Qualifier & (IEQUALIFIER_LALT|IEQUALIFIER_RALT))
							SerialCommand(MacroKeys -> Keys[2][Char - FN1]);
						else
						{
							if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
								SerialCommand(MacroKeys -> Keys[1][Char - FN1]);
							else
								SerialCommand(MacroKeys -> Keys[0][Char - FN1]);
						}
					}
				}
				else
					HandleCursor(Char,Qualifier);
			}
		}

			/* Capture characters from the main
			 * screen.
			 */

		if(Class == IDCMP_MOUSEBUTTONS && !(Code & IECODE_UP_PREFIX) && IDCMPWindow == Window)
		{
			if(Code == SELECTDOWN && (Qualifier & (IEQUALIFIER_LALT|IEQUALIFIER_RALT)) && (Qualifier & IEQUALIFIER_LEFTBUTTON))
			{
				WORD	DeltaX = MouseX / TextFontWidth  - CursorX,
					DeltaY = MouseY / TextFontHeight - CursorY;

				if(DeltaX || DeltaY)
				{
					if(DeltaX > 0)
					{
						DeltaX++;

						while(DeltaX--)
							SerWrite("\33[C",3);
					}

					if(DeltaX < 0)
					{
						while(DeltaX++)
							SerWrite("\33[D",3);
					}

					if(DeltaY > 0)
					{
						DeltaY++;

						while(DeltaY--)
							SerWrite("\33[B",3);
					}

					if(DeltaY < 0)
					{
						while(DeltaY++)
							SerWrite("\33[A",3);
					}
				}
			}
			else
			{
				if(!XEmulatorBase || Config . TerminalConfig . EmulationMode != EMULATION_EXTERNAL)
				{
					BYTE SingleChar,Xerox;

					Marking = TRUE;

						/* We want to know where the mouse
						 * moves...
						 */

					ReportMouse(TRUE,Window);

						/* Pick a single character. */

					if(Qualifier & IEQUALIFIER_CONTROL)
						SingleChar = TRUE;
					else
						SingleChar = FALSE;

						/* Xerox style snapping (feed into
						 * input stream after selection).
						 */

					if(Code == MIDDLEDOWN || (Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)))
						Xerox = TRUE;
					else
						Xerox = FALSE;

					MarkClip(SingleChar,Xerox);

					ReportMouse(FALSE,Window);

					while(Massage = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort))
						GT_ReplyIMsg(Massage);

					Marking = FALSE;

					return(Result);
				}
			}
		}

			/* A menu item was selected. */

SkipIt:		if(Class == IDCMP_MENUPICK)
			HandleMenu(Code,Qualifier);

		return(TRUE);
	}

	return(Result);
}

	/* TransferCleanup():
	 *
	 * We did a file transfer (auto-download?) and
	 * will need to close the transfer window.
	 */

STATIC VOID
TransferCleanup(VOID)
{
	if(DidTransfer)
	{
		WakeUp(TransferWindow);

		WaitTime(2,0);

		DeleteTransferPanel();

		if(SendAbort && UsesZModem)
			SerWrite(ZModemCancel,20);

		SendAbort = FALSE;

		if(Config . CommandConfig . DownloadMacro[0])
			SerialCommand(Config . CommandConfig . DownloadMacro);

		Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

		DidTransfer = FALSE;
	}
	else
	{
		WaitTime(3,0);

		DeleteTransferPanel();
	}

	ReleaseWindows();
}

	/* HandleSerial():
	 *
	 *	Handle the data coming in from the serial line.
	 */

BYTE
HandleSerial()
{
	if(ReadPort && !ReleaseSerial && !MainTerminated)
	{
		BYTE Return = FALSE;

		if(HostReadBuffer)
		{
			LONG Length;

			if(Length = XProtocolHostMon(XprIO,HostReadBuffer,0,Config . SerialConfig . SerialBufferSize))
			{
				ConProcess(HostReadBuffer,Length);

				Return = TRUE;
			}
		}

			/* We are XON'ed or the serial line was shut down. */

		if(Status != STATUS_HOLDING && !Blocking)
		{
			register ULONG MaxReadSize = Config . SerialConfig . SerialBufferSize;

			if(MaxReadSize > ReadRequest -> io_Baud / 4)
				MaxReadSize = ReadRequest -> io_Baud / 4;

				/* Any news? */

			if(CheckIO(ReadRequest))
			{
				LONG Length;

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

					SetSignal(0,SIG_SERIAL);

					SendIO(ReadRequest);

					return(Return);
				}

				BytesIn++;

					/* Process the data if necessary (XPR-function). */

				if(XProtocolBase && (TransferBits & XPRS_HOSTMON))
				{
					LONG Result = XProtocolHostMon(XprIO,ReadBuffer,1,Config . SerialConfig . SerialBufferSize);

					if(TransferWindow)
						TransferCleanup();

					if(Result)
						ConProcess(ReadBuffer,Result);
				}
				else
					ConProcess(ReadBuffer,1);

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

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

					WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

					DoIO(WriteRequest);

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

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

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

								/* Process the serial data if
								 * necessary (XPR-stuff).
								 */

							if(XProtocolBase && (TransferBits & XPRS_HOSTMON))
							{
								Length = XProtocolHostMon(XprIO,ReadBuffer,Length,Config . SerialConfig . SerialBufferSize);

								if(TransferWindow)
									TransferCleanup();

								if(Length)
									ConProcess(ReadBuffer,Length);
							}
							else
								ConProcess(ReadBuffer,Length);
						}
					}
				}
				while(Length);

					/* Ask for another byte. */

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

				SetSignal(0,SIG_SERIAL);

				SendIO(ReadRequest);

				return(TRUE);
			}
		}

		return(Return);
	}

	return(FALSE);
}

	/* HandleCode(ULONG Code,ULONG Qualifier,struct MenuItem *MenuItem):
	 *
	 *	Handle each function associated with a menu code.
	 */

VOID
HandleCode(ULONG Code,ULONG Qualifier,struct MenuItem *MenuItem)
{
	STATIC UBYTE		 NumberBuffer[256];

	struct FileRequester	*FileRequest;
	UBYTE			 DummyBuffer[256],
				*DummyChar;
	BYTE			 OldStatus = Status;

	BPTR			 SomeFile;
	APTR			 OldPtr;

	switch(Code)
	{
			/* Save screen as IFF-ILBM file. */

		case MEN_SAVE_AS_PICTURE:

					BlockWindows();

					if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_SAVE_SCREEN_IFF_TXT),"","",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT)))
					{
						if(!SaveWindow(DummyBuffer,Window))
							MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FAILED_TO_SAVE_SCREEN_TO_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),DummyBuffer);

						FreeAslRequest(FileRequest);
					}

					ReleaseWindows();

					break;

			/* Save screen as ASCII file. */

		case MEN_SAVE_AS_TEXT:

					BlockWindows();

					if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_SAVE_SCREEN_ASCII_TXT),"","",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT)))
					{
						if(GetFileSize(DummyBuffer))
						{
							switch(MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FILE_ALREADY_EXISTS_TXT),LocaleString(MSG_GLOBAL_CREATE_APPEND_CANCEL_TXT),DummyBuffer))
							{
								case 1:	SomeFile = Open(DummyBuffer,MODE_NEWFILE);
									break;

								case 2:	if(SomeFile = Open(DummyBuffer,MODE_READWRITE))
									{
										if(Seek(SomeFile,0,OFFSET_END) == -1)
										{
											Close(SomeFile);

											SomeFile = NULL;
										}
									}

									break;

								case 0:	SomeFile = ~0;
									break;
							}
						}
						else
							SomeFile = Open(DummyBuffer,MODE_NEWFILE);

						if(!SomeFile)
							MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FAILED_TO_SAVE_SCREEN_TO_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),DummyBuffer);
						else
						{
							if(SomeFile != ~0)
							{
								WORD	 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))
											break;
									}

									if(!FWrite(SomeFile,"\n",1,1))
										break;
								}

								Close(SomeFile);

								SetProtection(DummyBuffer,FIBF_EXECUTE);
							}
						}

						FreeAslRequest(FileRequest);
					}

					ReleaseWindows();

					break;

			/* Print the screen (pure ASCII). */

		case MEN_PRINT_SCREEN:

					BlockWindows();

					if(!XEmulatorBase || Config . TerminalConfig . EmulationMode != EMULATION_EXTERNAL)
						PrintSomething(PRINT_SCREEN);
					else
						MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_NO_DATA_TO_PRINT_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

					ReleaseWindows();

					break;

			/* Print the clipboard contents. */

		case MEN_PRINT_CLIP:

					BlockWindows();

					PrintSomething(PRINT_CLIP);

					ReleaseWindows();

					break;

			/* Open/close the terminal capture file. */

		case MEN_CAPTURE_TO_FILE:

					if(FileCapture)
					{
						BufferClose(FileCapture);

						MenuItem -> Flags &= ~CHECKED;

						FileCapture = NULL;

						if(!GetFileSize(CaptureName))
							DeleteFile(CaptureName);
						else
							SetProtection(CaptureName,FIBF_EXECUTE);
					}
					else
					{
						BlockWindows();

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

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

						strcpy(DummyBuffer,CaptureName);

						DummyChar = PathPart(DummyBuffer);

						*DummyChar = 0;

						if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_CAPTURE_TO_DISK_TXT),DummyBuffer,FilePart(CaptureName),DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_OPEN_TXT)))
						{
							if(GetFileSize(DummyBuffer))
							{
								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:	MenuItem -> Flags &= ~CHECKED;
										goto CapSkip;
								}
							}
							else
								FileCapture = BufferOpen(DummyBuffer,"w");

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

								MenuItem -> Flags &= ~CHECKED;
							}
							else
							{
								strcpy(CaptureName,DummyBuffer);

								MenuItem -> Flags |= CHECKED;
							}

							FreeAslRequest(FileRequest);
						}
						else
							MenuItem -> Flags &= ~CHECKED;

CapSkip:					ReleaseWindows();
					}

					break;

			/* Start/terminate the printer
			 * capture.
			 */

		case MEN_CAPTURE_TO_PRINTER:

					if(PrinterCapture)
						ClosePrinterCapture(TRUE);
					else
						OpenPrinterCapture(FALSE);

					break;

			/* Iconify the program. */

		case MEN_ICONIFY:

					DoIconify = TRUE;

					break;

			/* Say who we are. */

		case MEN_ABOUT:

					BlockWindows();

					ShowInfo(FALSE);

					ReleaseWindows();

					break;

			/* Terminate the program. */

		case MEN_QUIT:		if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
						MainTerminated = TRUE;
					else
					{
						STRPTR	Buffer;
						LONG	OldLen,Len = strlen(LocaleString(MSG_TERMMAIN_REALLY_QUIT_TXT)) + 3;

						OldLen = Len;

						if(Online)
							Len += strlen(LocaleString(MSG_WAIT_PROGRAM_IS_STILL_ONLINE_TXT)) + 4;

						if(BufferChanged)
							Len += strlen(LocaleString(MSG_WAIT_REVIEW_BUFFER_NOT_SAVED_TXT)) + 4;

						if(ConfigChanged)
							Len += strlen(LocaleString(MSG_WAIT_CONFIGURATION_HAS_BEEN_CHANGED_TXT)) + 4;

						if(PhonebookChanged)
							Len += strlen(LocaleString(MSG_WAIT_PHONEBOOK_NOT_SAVED_TXT)) + 4;

						if(TranslationChanged)
							Len += strlen(LocaleString(MSG_WAIT_TRANSLATION_TABLES_CHANGED_TXT)) + 4;

						if(MacroChanged)
							Len += strlen(LocaleString(MSG_WAIT_MACRO_KEYS_CHANGED_TXT)) + 4;

						if(CursorKeysChanged)
							Len += strlen(LocaleString(MSG_WAIT_CURSOR_KEYS_CHANGED_TXT)) + 4;

						if(FastMacrosChanged)
							Len += strlen(LocaleString(MSG_WAIT_FAST_MACROS_CHANGED_TXT)) + 4;

						if(HotkeysChanged)
							Len += strlen(LocaleString(MSG_WAIT_HOTKEYS_CHANGED_TXT)) + 4;

						if(SpeechChanged)
							Len += strlen(LocaleString(MSG_WAIT_SPEECH_SETTINGS_CHANGED_TXT)) + 4;

						BlockWindows();

						OldPtr = ThisProcess -> pr_WindowPtr;

						ThisProcess -> pr_WindowPtr = (APTR)Window;

						if(OldLen != Len)
						{
							if(Buffer = (STRPTR)AllocVec(Len,MEMF_ANY))
							{
								SPrintf(Buffer,"%s\n\n",LocaleString(MSG_TERMMAIN_REALLY_QUIT_TXT));

								if(Online)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_PROGRAM_IS_STILL_ONLINE_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(BufferChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_REVIEW_BUFFER_NOT_SAVED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(ConfigChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_CONFIGURATION_HAS_BEEN_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(PhonebookChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_PHONEBOOK_NOT_SAVED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(TranslationChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_TRANSLATION_TABLES_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(MacroChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_MACRO_KEYS_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(CursorKeysChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_CURSOR_KEYS_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(FastMacrosChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_FAST_MACROS_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(HotkeysChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_HOTKEYS_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(SpeechChanged)
								{
									SPrintf(SharedBuffer," · %s\n",LocaleString(MSG_WAIT_SPEECH_SETTINGS_CHANGED_TXT));

									strcat(Buffer,SharedBuffer);
								}

								if(MyEasyRequest(Window,Buffer,LocaleString(MSG_GLOBAL_YES_NO_TXT)))
									MainTerminated = TRUE;

								FreeVec(Buffer);
							}
							else
							{
								if(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_REALLY_QUIT_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
									MainTerminated = TRUE;
							}
						}
						else
						{
							if(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_REALLY_QUIT_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
								MainTerminated = TRUE;
						}

						ThisProcess -> pr_WindowPtr = OldPtr;

						ReleaseWindows();
					}

					break;

			/* Feed the contents of the clipboard
			 * into the input stream.
			 */

		case MEN_PASTE:

					if(!OpenClip())
					{
						ClipInput = TRUE;

						if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
							ClipXerox = TRUE;
					}
					else
						ClipInput = FALSE;

					break;

			/* Execute an AmigaDOS command. */

		case MEN_EXECUTE_DOS_COMMAND:

					BlockWindows();

					DummyBuffer[0] = 0;

						/* Enter the name of the command. */

					if(GetString(TRUE,FALSE,0,LocaleString(MSG_TERMMAIN_ENTER_AMIGADOS_COMMAND_TXT),DummyBuffer))
						SendAmigaDOSCommand(DummyBuffer);

					ReleaseWindows();

					break;

			/* Execute an ARexx script command. */

		case MEN_EXECUTE_REXX_COMMAND:

					BlockWindows();

					DummyBuffer[0] = 0;

						/* Get the rexx file name/program. */

					if(GetString(TRUE,FALSE,0,LocaleString(MSG_TERMMAIN_ENTER_AREXX_COMMAND_TXT),DummyBuffer))
						SendARexxCommand(DummyBuffer);

					ReleaseWindows();

					break;

			/* Set the name we will use to open the
			 * default console output window for
			 * AmigaDOS commands and ARexx scripts.
			 */

		case MEN_SET_CONSOLE:

					BlockWindows();

					if(GetString(FALSE,FALSE,0,LocaleString(MSG_TERMMAIN_SET_CONSOLE_WINDOW_TXT),WindowName))
						SetEnvDOS("TERMWINDOW",WindowName);

					ReleaseWindows();

					break;

			/* Open the phonebook and dial the
			 * list of entries the user will select.
			 */

		case MEN_PHONEBOOK:

					BlockWindows();

					while(PhonePanel())
					{
						if(!DialPanel())
						{
							Status = OldStatus;

							break;
						}

						Status = OldStatus;
					}

					ReleaseWindows();

					break;

			/* Redial those dial list entries which
			 * we were unable to connect.
			 */

		case MEN_REDIAL:

					BlockWindows();

					if(DialList)
					{
						if(DialList -> lh_Head -> ln_Succ)
						{
							do
							{
								if(!DialPanel())
								{
									Status = OldStatus;

									break;
								}

								Status = OldStatus;
							}
							while(PhonePanel());
						}
						else
							MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_CURRENT_DIALING_LIST_IS_EMPTY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
					}
					else
						MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_CURRENT_DIALING_LIST_IS_EMPTY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

					ReleaseWindows();

					break;

			/* Dial a single number. */

		case MEN_DIAL_NUMBER:

					BlockWindows();

					if(GetString(FALSE,FALSE,0,LocaleString(MSG_TERMMAIN_ENTER_PHONE_NUMBER_TXT),NumberBuffer))
					{
						if(NumberBuffer[0])
						{
							struct List *LocalList;

							if(LocalList = (struct List *)AllocVec(sizeof(struct List),MEMF_ANY|MEMF_CLEAR))
							{
								struct PhoneNode *DialNode;

								NewList(LocalList);

								if(DialNode = (struct PhoneNode *)AllocVec(sizeof(struct PhoneNode),MEMF_ANY|MEMF_CLEAR))
								{
									DialNode -> VanillaNode . ln_Name = (STRPTR)NumberBuffer;

									AddTail(LocalList,&DialNode -> VanillaNode);

									FreeDialList();

									DialList = LocalList;

									DialPanel();

									Status = OldStatus;
								}
								else
									FreeVec(LocalList);
							}
						}
					}

					ReleaseWindows();

					break;


			/* Send a break across the serial line. */

		case MEN_SEND_BREAK:

					if(WriteRequest)
					{
						Status = STATUS_BREAKING;

						WriteRequest -> IOSer . io_Command = SDCMD_BREAK;

						DoIO(WriteRequest);

						Status = OldStatus;
					}

					break;

			/* Hang up the phone line. */

		case MEN_HANG_UP:

					BlockWindows();

					Status = STATUS_HANGUP;

						/* Are we to drop the DTR line
						 * before sending the hangup
						 * string?
						 */

					if(Config . ModemConfig . DropDTR)
					{
						/* Let's be nice and try to transmit the
						 * `drop the line' command before
						 * trying to close and reopen the driver.
						 */

						WriteRequest -> IOSer . io_Command	= SIOCMD_SETCTRLLINES;
						WriteRequest -> IOSer . io_Offset	= SIOB_DTRF;
						WriteRequest -> IOSer . io_Length	= 0;

						/* Transmit the command. */

						if(!DoIO(WriteRequest))
						{
							/* Wait a bit... */

							WaitTime(1,0);

							/* Raise the line again. */

							WriteRequest -> IOSer . io_Command	= SIOCMD_SETCTRLLINES;
							WriteRequest -> IOSer . io_Offset	= SIOB_DTRF;
							WriteRequest -> IOSer . io_Length	= SIOB_DTRF;

							DoIO(WriteRequest);
						}
						else
						{
							/* Do it the standard way: close and reopen
							 * the serial driver (the serial.device is
							 * supposed to drop the DTR line when closed).
							 */

							if(!DropDTR())
							{
								if(!MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_REOPEN_UNIT_TXT),LocaleString(MSG_TERMMAIN_IGNORE_QUIT_TXT),Config . SerialConfig . SerialDevice,Config . SerialConfig . UnitNumber))
									MainTerminated = TRUE;
							}
						}
					}

						/* Transmit the hangup command. */

					if(Config . ModemConfig . ModemHangup[0])
						SerialCommand(Config . ModemConfig . ModemHangup);

						/* Reset to old status. */

					Status = OldStatus;

						/* We are no longer online. */

					Online = FALSE;

						/* Clear the password. */

					Password[0] = 0;

						/* Clear the user name as well. */

					UserName[0] = 0;

						/* Note the  last action. */

					LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_HANG_UP_TXT));

					ReleaseWindows();

						/* Execute logoff macro. */

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

						/* Update the logfile. */

					StopCall(FALSE);

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

					WasOnline = FALSE;

						/* Enable the dialing functions. */

					SetDialMenu(TRUE);

					break;

			/* Flush the serial buffers. */

		case MEN_FLUSH_BUFFER:

					ClearSerial();

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

						SetSignal(0,SIG_SERIAL);

						SendIO(ReadRequest);
					}

					break;

			/* Release the serial device for other
			 * applications.
			 */

		case MEN_RELEASE_DEVICE:

					ReleaseSerial = TRUE;
					break;

		case MEN_UPLOAD_ASCII:

					BlockWindows();

					if(ASCIISetup())
					{
						StartXprSend(TRANSFER_ASCII);

						ASCIIShutdown();
					}

					ReleaseWindows();

					break;

		case MEN_DOWNLOAD_ASCII:

					BlockWindows();

					if(ASCIISetup())
					{
						StartXprReceive(TRANSFER_ASCII);

						ASCIIShutdown();
					}

					ReleaseWindows();

					break;

		case MEN_UPLOAD_TEXT:

					BlockWindows();

					BinaryTransfer = FALSE;

					StartXprSend(TRANSFER_TEXT);

					BinaryTransfer = TRUE;

					ReleaseWindows();

					break;

		case MEN_DOWNLOAD_TEXT:
					BlockWindows();

					BinaryTransfer = FALSE;

					StartXprReceive(TRANSFER_TEXT);

					BinaryTransfer = TRUE;

					ReleaseWindows();

					break;

			/* Edit and transfer a file. */

		case MEN_EDIT_AND_UPLOAD_TEXT:

					BlockWindows();

					if(!Config . PathConfig . Editor[0])
						GetString(TRUE,FALSE,0,LocaleString(MSG_TERMMAIN_ENTER_NAME_OF_EDITOR_TO_USE_TXT),Config . PathConfig . Editor);

					if(Config . PathConfig . Editor[0])
					{
						if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_EDIT_AND_TRANSFER_FILE_TXT),"","",DummyBuffer,NULL,FALSE,FALSE,FALSE,LocaleString(MSG_TERMMAIN_EDIT_TXT)))
						{
							UBYTE CompoundName[512];

							strcpy(CompoundName,Config . PathConfig . Editor);
							strcat(CompoundName," ");
							strcat(CompoundName,DummyBuffer);

							SystemTags(CompoundName,TAG_DONE);

							BumpWindow(Window);

							FreeAslRequest(FileRequest);

							if(GetFileSize(DummyBuffer))
							{
								BinaryTransfer = FALSE;

								switch(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_TRANSFER_FILE_AS_TXT),LocaleString(MSG_TERMMAIN_ASCII_UPLOAD_CANCEL_TXT),FilePart(DummyBuffer)))
								{
									case 1:	if(ASCIISetup())
										{
											SendTextFile(DummyBuffer);

											ASCIIShutdown();
										}

										break;

									case 2:	SendTextFile(DummyBuffer);

										break;

									case 0:	break;
								}

								BinaryTransfer = TRUE;
							}
						}
					}

					ReleaseWindows();
					break;

		case MEN_UPLOAD_BINARY:

					BlockWindows();

					BinaryTransfer = TRUE;

					StartXprSend(TRANSFER_BINARY);

					ReleaseWindows();

					break;

			/* Download some files. */

		case MEN_DOWNLOAD_BINARY:

					BlockWindows();

					BinaryTransfer = TRUE;

					StartXprReceive(TRANSFER_BINARY);

					ReleaseWindows();

					break;

			/* Clear the contents of the scrollback
			 * buffer.
			 */

		case MEN_CLEAR_BUFFER:

					if(Lines)
					{
						BlockWindows();

						if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
							ClearBuffer();
						else
						{
							if(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
								ClearBuffer();
						}

						UpdateReview(TRUE);

						ReleaseWindows();
					}

					break;

			/* Display the scrollback buffer.
			 * Notify the scrollback task or
			 * fire it off if approriate.
			 */

		case MEN_DISPLAY_BUFFER:

					if(!LaunchBuffer())
					{
						BlockWindows();

						MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_UNABLE_TO_CREATE_BUFFER_TASK_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

						ReleaseWindows();
					}

					break;


			/* Close the buffer display. */

		case MEN_CLOSE_BUFFER:

					if(BufferProcess)
					{
						Signal(BufferProcess,SIGBREAKF_CTRL_C);

						Wait(SIGBREAKF_CTRL_C);
					}

					break;

			/* Is the buffer to be frozen? */

		case MEN_FREEZE_BUFFER:

					if(MenuItem -> Flags & CHECKED)
						BufferFrozen = TRUE;
					else
						BufferFrozen = FALSE;

					break;

			/* Load the buffer contents from a file. */

		case MEN_OPEN_BUFFER:

					BlockWindows();

					if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_LOAD_BUFFER_TXT),"","",DummyBuffer,NULL,FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_LOAD_TXT)))
					{
						if(GetFileSize(DummyBuffer))
						{
							if(SomeFile = Open(DummyBuffer,MODE_OLDFILE))
							{
								if(Lines)
								{
									switch(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_TERMMAIN_DISCARD_APPPEND_CANCEL_TXT),Lines))
									{
										case 1:	ClearBuffer();
											break;

										case 2:	break;

										case 0:	Close(SomeFile);
											SomeFile = NULL;
											break;
									}
								}

								if(SomeFile)
								{
									LONG Len;

									LineRead(NULL,NULL,NULL);

									while((Len = LineRead(SomeFile,DummyBuffer,80)) > 0)
										StoreBuffer(DummyBuffer,Len);

									Close(SomeFile);

									BufferChanged = TRUE;
								}
							}
						}

						FreeAslRequest(FileRequest);
					}

					ReleaseWindows();
					break;

			/* Save the contents of the scrollback
			 * buffer to a file (line by line).
			 */

		case MEN_SAVE_BUFFER_AS:

					BlockWindows();

					if(!Lines)
						MyEasyRequest(Window,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
					else
					{
						if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_SAVE_BUFFER_TXT),"","",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT)))
						{
							SomeFile = NULL;

								/* If the file we are about
								 * to create already exists,
								 * ask the user whether we are
								 * to create, append or skip
								 * the file.
								 */

							if(GetFileSize(DummyBuffer))
							{
								switch(MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FILE_ALREADY_EXISTS_TXT),LocaleString(MSG_GLOBAL_CREATE_APPEND_CANCEL_TXT),DummyBuffer))
								{
									case 1:	SomeFile = Open(DummyBuffer,MODE_NEWFILE);
										break;

									case 2:	if(SomeFile = Open(DummyBuffer,MODE_READWRITE))
										{
											if(Seek(SomeFile,0,OFFSET_END) == -1)
											{
												Close(SomeFile);

												SomeFile = NULL;
											}
										}

										break;
								}
							}
							else
								SomeFile = Open(DummyBuffer,MODE_NEWFILE);

							if(!SomeFile)
								MyEasyRequest(Window,LocaleString(MSG_GLOBAL_ERROR_OPENING_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),DummyBuffer);
							else
							{
								LONG i,Len;

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

								ObtainSemaphore(BufferSemaphore);

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

									if(Len)
									{
										if(FWrite(SomeFile,BufferLines[i],Len,1) != 1)
											break;
									}

									if(FPrintf(SomeFile,"\n") < 1)
										break;
								}

								ReleaseSemaphore(BufferSemaphore);

								Close(SomeFile);

								SetProtection(DummyBuffer,FIBF_EXECUTE);

								BufferChanged = FALSE;
							}

							FreeAslRequest(FileRequest);
						}
					}

					ReleaseWindows();

					break;

			/* Simply clear the screen and move the
			 * cursor to its home position.
			 */

		case MEN_CLEAR_SCREEN:

					if(XEmulatorBase && Config . TerminalConfig . EmulationMode == EMULATION_EXTERNAL)
						XEmulatorClearConsole(XEM_IO);
					else
					{
						EraseScreen("2J");
						SetAbsolutePosition("H");
					}

					break;

			/* Reset the current text rendering font. */

		case MEN_RESET_FONT:

					if(XEmulatorBase && Config . TerminalConfig . EmulationMode == EMULATION_EXTERNAL)
						XEmulatorResetCharset(XEM_IO);
					else
					{
						CurrentFont = TextFont;

						SetFont(RPort,CurrentFont);
					}

					break;

			/* Reset the display styles and restore
			 * the colours.
			 */

		case MEN_RESET_STYLES:

					if(XEmulatorBase && Config . TerminalConfig . EmulationMode == EMULATION_EXTERNAL)
						XEmulatorResetTextStyles(XEM_IO);
					else
					{
						SetAttributes("0m");

						Config . EmulationConfig . FontScale = SCALE_NORMAL;

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

							case COLOUR_SIXTEEN:	FgPen = 15;
										break;

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

						BgPen = 0;

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

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

						SetWrMsk(RPort,0xFF);
					}

					break;

			/* Reset the whole terminal. */

		case MEN_RESET_TERMINAL:

					if(XEmulatorBase && Config . TerminalConfig . EmulationMode == EMULATION_EXTERNAL)
						XEmulatorResetConsole(XEM_IO);
					else
					{
						DoCancel();

						Reset();
					}

					break;

		case MEN_SET_EMULATION:

					BlockWindows();

					if(XEmulatorBase && Config . TerminalConfig . EmulationMode == EMULATION_EXTERNAL)
					{
						OptionTitle = LocaleString(MSG_TERMMAIN_EMULATION_PREFERENCES_TXT);

						XEmulatorOptions(XEM_IO);

						if(NewOptions)
						{
							SetEmulatorOptions(XEM_PREFS_SAVE);

							NewOptions = FALSE;
						}

						OptionTitle = NULL;
					}
					else
						EmulationPanel(&Config);

					ReleaseWindows();

					break;

			/* Set the serial preferences. */

		case MEN_SERIAL:

					BlockWindows();

					if(SerialPanel(&Config))
					{
						ConfigSetup();

						ConfigChanged = TRUE;
					}

					ReleaseWindows();

					break;

			/* Set the modem preferences. */

		case MEN_MODEM:

					BlockWindows();

					if(ModemPanel(&Config))
					{
						FlowInit(TRUE);

						ConfigChanged = TRUE;
					}

					ReleaseWindows();

					break;

			/* Set the screen preferences. */

		case MEN_SCREEN:

					BlockWindows();

					if(ScreenPanel(&Config))
					{
						if(memcmp(PrivateConfig . ScreenConfig . Colours,Config . ScreenConfig . Colours,sizeof(UWORD) * 16))
						{
							switch(Config . ScreenConfig . ColourMode)
							{
								case COLOUR_EIGHT:	CopyMem(Config . ScreenConfig . Colours,ANSIColours,16 * sizeof(UWORD));
											break;

								case COLOUR_SIXTEEN:	CopyMem(Config . ScreenConfig . Colours,EGAColours,16 * sizeof(UWORD));
											break;

								case COLOUR_AMIGA:	CopyMem(Config . ScreenConfig . Colours,DefaultColours,16 * sizeof(UWORD));
											break;

								case COLOUR_MONO:	CopyMem(Config . ScreenConfig . Colours,AtomicColours,16 * sizeof(UWORD));
											break;
							}
						}

						ConfigSetup();

						ConfigChanged = TRUE;
					}
					else
					{
						if(memcmp(PrivateConfig . ScreenConfig . Colours,Config . ScreenConfig . Colours,sizeof(UWORD) * 16))
						{
							switch(Config . ScreenConfig . ColourMode)
							{
								case COLOUR_EIGHT:	CopyMem(Config . ScreenConfig . Colours,ANSIColours,16 * sizeof(UWORD));
											break;

								case COLOUR_SIXTEEN:	CopyMem(Config . ScreenConfig . Colours,EGAColours,16 * sizeof(UWORD));
											break;

								case COLOUR_AMIGA:	CopyMem(Config . ScreenConfig . Colours,DefaultColours,16 * sizeof(UWORD));
											break;

								case COLOUR_MONO:	CopyMem(Config . ScreenConfig . Colours,AtomicColours,16 * sizeof(UWORD));
											break;
							}

							ConfigChanged = TRUE;
						}
					}

					ReleaseWindows();

					break;

			/* Set the terminal preferences. */

		case MEN_TERMINAL:

					BlockWindows();

					if(TerminalPanel(&Config))
					{
						ConfigSetup();

						ConfigChanged = TRUE;
					}

					ReleaseWindows();

					break;

			/* Set the clipboard preferences. */

		case MEN_CLIPBOARD:
					BlockWindows();

					if(ClipPanel(&Config))
					{
						ConfigSetup();

						ConfigChanged = TRUE;
					}

					ReleaseWindows();

					break;

			/* Set the capture preferences. */

		case MEN_CAPTURE:
					BlockWindows();

					if(CapturePanel(&Config))
					{
						ConfigSetup();

						ConfigChanged = TRUE;
					}

					ReleaseWindows();

					break;

			/* Set the command preferences. */

		case MEN_COMMANDS:

					BlockWindows();

					if(CommandPanel(&Config))
						ConfigChanged = TRUE;

					ReleaseWindows();

					break;

			/* Set the miscellaneous preferences. */

		case MEN_MISC:

					BlockWindows();

					if(MiscPanel(&Config))
					{
						ConfigSetup();

						ConfigChanged = TRUE;
					}

					ReleaseWindows();

					break;

			/* Set the path settings. */

		case MEN_PATH:

					BlockWindows();

					if(PathPanel(&Config))
						ConfigChanged = TRUE;

					ReleaseWindows();

					break;

			/* Set the file transfer options. */

		case MEN_TRANSFER:

					BlockWindows();

					XprIO -> xpr_filename = NULL;

						/* Set up the library options. */

					if(XProtocolBase)
					{
						TransferBits = XProtocolSetup(XprIO);

							/* Successful? */

						if(!(TransferBits & XPRS_SUCCESS))
						{
							MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FAILED_TO_SET_UP_PROTOCOL_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LastXprLibrary);

							CloseLibrary(XProtocolBase);

							XProtocolBase = NULL;

							LastXprLibrary[0] = 0;

							TransferBits = 0;
						}
						else
							SaveProtocolOpts();
					}

					ReleaseWindows();

					break;

			/* Select the transfer protocol; I had hoped
			 * to get rid of this option but xprascii and
			 * the older pre-2.0 standard xpr-libraries
			 * forced it back in.
			 */

		case MEN_TRANSFER_PROTOCOL:

					BlockWindows();

					if(SelectProtocol(LastXprLibrary,Window))
					{
						if(ProtocolSetup())
							strcpy(Config . FileConfig . ProtocolFileName,LastXprLibrary);
						else
						{
							strcpy(LastXprLibrary,Config . FileConfig . ProtocolFileName);

							ProtocolSetup();
						}

						if(!XProtocolBase)
							SetTransferMenu(FALSE);
						else
							SetTransferMenu(TRUE);
					}

					ReleaseWindows();

					break;

			/* Set the translation tables. */

		case MEN_TRANSLATION:
					BlockWindows();

					TranslationChanged |= TranslationPanel();

					ReleaseWindows();

					break;

			/* Set the keyboard macros. */

		case MEN_MACROS:
					BlockWindows();

					if(XEmulatorBase && Config . TerminalConfig . EmulationMode == EMULATION_EXTERNAL)
					{
						XEmulatorMacroKeyFilter(XEM_IO,NULL);

						MacroPanel(MacroKeys);

						SetupXEM_MacroKeys(MacroKeys);
					}
					else
						MacroPanel(MacroKeys);

					ReleaseWindows();

					break;

			/* Set the cursor keys. */

		case MEN_CURSORKEYS:
					BlockWindows();

					CursorPanel(CursorKeys);

					ReleaseWindows();

					break;

			/* Set the fast macros. */

		case MEN_FAST_MACROS:

					BlockWindows();

					FastMacroPanel();

					ReleaseWindows();

					break;

			/* Set the hotkey preferences. */

		case MEN_HOTKEYS:

					BlockWindows();

					if(HotkeyPanel(&Hotkeys))
					{
						if(!SetupCx())
							MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_SET_UP_HOTKEYS_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
					}

					ReleaseWindows();

					break;

			/* Set the speech preferences. */

		case MEN_SPEECH:

					BlockWindows();

					SpeechPanel();

					ReleaseWindows();

					break;

			/* Open the preferences settings. */

		case MEN_OPEN_SETTINGS:

					BlockWindows();

					strcpy(DummyBuffer,LastConfig);

					DummyChar = PathPart(DummyBuffer);

					*DummyChar = 0;

					if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_OPEN_PREFERENCES_TXT),DummyBuffer,FilePart(LastConfig),DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,NULL))
					{
						if(ReadConfig(DummyBuffer,&PrivateConfig))
						{
							swmem(&PrivateConfig,&Config,sizeof(struct Configuration));

							strcpy(DummyBuffer,LastConfig);

							ConfigSetup();

							ConfigChanged = FALSE;
						}
						else
							MyEasyRequest(Window,LocaleString(MSG_GLOBAL_ERROR_OPENING_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),DummyBuffer);

						FreeAslRequest(FileRequest);
					}

					ReleaseWindows();

					break;

			/* Save the terminal preferences. */

		case MEN_SAVE_SETTINGS:

					if(LastConfig[0])
					{
						BlockWindows();

						if(!WriteIFFData(LastConfig,&Config,sizeof(struct Configuration),ID_PREF))
							MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_ERROR_WRITING_PREFERENCES_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LastConfig);
						else
							ConfigChanged = FALSE;

						ReleaseWindows();

						break;
					}

			/* Save the terminal preferences to a
			 * given file name.
			 */

		case MEN_SAVE_SETTINGS_AS:

					BlockWindows();

					strcpy(DummyBuffer,LastConfig);

					DummyChar = PathPart(DummyBuffer);

					*DummyChar = 0;

					if(FileRequest = GetFile(LocaleString(MSG_TERMMAIN_SAVE_PREFERENCES_AS_TXT),DummyBuffer,FilePart(LastConfig),DummyBuffer,"#?.prefs",TRUE,FALSE,FALSE,NULL))
					{
						if(WriteIFFData(DummyBuffer,&Config,sizeof(struct Configuration),ID_PREF))
						{
							strcpy(LastConfig,DummyBuffer);

							ConfigChanged = FALSE;
						}
						else
							MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_ERROR_WRITING_PREFERENCES_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),DummyBuffer);

						FreeAslRequest(FileRequest);
					}

					ReleaseWindows();

					break;

			/* Show terminal information window. */

		case MEN_STATUS_WINDOW:

					if(InfoWindow)
						CloseInfoWindow();
					else
						OpenInfoWindow();

					break;

		case MEN_REVIEW_WINDOW:

					if(ReviewWindow)
						DeleteReview();
					else
						CreateReview();

					break;

			/* Open the packet window if necessary, else
			 * just activate it.
			 */

		case MEN_PACKET_WINDOW:

					if(!PacketWindow)
						CreatePacketWindow();
					else
					{
						ActivateWindow(PacketWindow);

						MenuItem -> Flags |= CHECKED;
					}

					break;

			/* Toggle the presence of the fast! macro panel. */

		case MEN_FAST_MACROS_WINDOW:

					if(FastWindow)
						CloseFastWindow();
					else
						OpenFastWindow();

					break;

			/* Ignore the rest. */

		default:		break;
	}
}

	/* HandleMenu(ULONG Code,ULONG Qualifier):
	 *
	 *	Skip along the number of selected menu items and
	 *	handle the associated functions.
	 */

VOID
HandleMenu(ULONG Code,ULONG Qualifier)
{
	struct MenuItem *MenuItem;

	DisplayReopened = FALSE;

		/* Check until the last menuitem has been
		 * processed.
		 */

	while(Code != MENUNULL)
	{
			/* Pick up the associated menu item. */

		if(MenuItem = ItemAddress(Menu,Code))
		{
			HandleCode((ULONG)GTMENUITEM_USERDATA(MenuItem),Qualifier,MenuItem);

			if(DisplayReopened)
			{
				DisplayReopened = FALSE;

				break;
			}

			Code = MenuItem -> NextSelect;
		}
		else
			break;
	}
}
