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

#include "termGlobal.h"

	/* Argument vectors offsets. */

enum	{	ARG_WINDOW,ARG_PUBSCREEN,ARG_STARTUP,ARG_PORTNAME,ARG_SETTINGS,ARG_UNIT,ARG_DEVICE,
		ARG_NEW,ARG_SYNC,ARG_QUIET,ARG_COUNT };

	/* Argument template. */

#define ARGTEMPLATE "WINDOW/K,PUBSCREEN/K,STARTUP/K,PORTNAME/K,SETTINGS/K,UNIT/K/N,DEVICE/K,NEW/S,SYNC/S,QUIET/S"

	/* Local config path variable. */

STATIC STRPTR		ConfigPath;
STATIC UBYTE		ThePath[MAX_FILENAME_LENGTH];

	/* Local dialing list. */

STATIC struct List	*LocalDialList;
STATIC LONG		 LocalCount = -1;

	/* Startup file name. */

STATIC UBYTE		StartupFile[MAX_FILENAME_LENGTH];

	/* 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: term [WINDOW <Name>] [PUBSCREEN <Name>] [STARTUP <File name>]\n            [SETTINGS <File or path name>] [UNIT <Number>] [DEVICE <Name>]\n            [NEW] [SYNC]\n\n     Window = Output window specifier\n  PubScreen = Name of public screen to open window upon\n    Startup = ARexx script file to run on startup\n   Settings = Main configuration file name or path name to search for it\n       Unit = Serial device driver unit number\n     Device = Serial device driver name\n        New = Spawn a new `term' process\n       Sync = Keep links to Shell environment\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_NEW])
					{
						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 ARexx host port name? */

					if(ArgArray[ARG_PORTNAME])
						strcpy(RexxPortName,ArgArray[ARG_PORTNAME]);

						/* Are we to use a special output window name? */

					if(ArgArray[ARG_WINDOW])
						strcpy(WindowName,ArgArray[ARG_WINDOW]);

						/* Are we to run an ARexx script on startup? */

					if(ArgArray[ARG_STARTUP])
						strcpy(StartupFile,ArgArray[ARG_STARTUP]);

						/* Are we to open a window on a public screen? */

					if(ArgArray[ARG_PUBSCREEN])
						strcpy(SomePubScreenName,ArgArray[ARG_PUBSCREEN]);

						/* 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;
					}

						/* Are we to start up iconified? */

					if(ArgArray[ARG_QUIET])
					{
						if(!StartupFile[0])
							DoIconify = TRUE;
					}

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

					if(ArgArray[ARG_SYNC])
					{
						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();

							/* 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 tool icon to use at least\n16384 bytes and restart the proram.","Continue",StackSize);

			CloseLibs();

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

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

			if(IconBase)
			{
				struct DiskObject *Icon;

					/* Try to read the icon file. */

				if(Icon = GetProgramIcon())
				{
					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 `Portname' tooltype. */

					if(Type = FindToolType(Icon -> do_ToolTypes,"PORTNAME"))
						strcpy(RexxPortName,Type);
					else
						RexxPortName[0] = 0;

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

					if(Type = FindToolType(Icon -> do_ToolTypes,"WINDOW"))
						strcpy(WindowName,Type);
					else
						WindowName[0] = 0;

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

					if(Type = FindToolType(Icon -> do_ToolTypes,"PUBSCREEN"))
						strcpy(SomePubScreenName,Type);
					else
						SomePubScreenName[0] = 0;

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

					if(Type = FindToolType(Icon -> do_ToolTypes,"STARTUP"))
						strcpy(StartupFile,Type);
					else
						StartupFile[0] = 0;

						/* 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;
						}
					}

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

					if(FindToolType(Icon -> do_ToolTypes,"QUIET"))
					{
						if(!StartupFile[0])
							DoIconify = TRUE;
					}

						/* Free the icon. */

					FreeDiskObject(Icon);
				}
			}

				/* 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(WBenchMsg)
		CurrentDir(WBenchLock);

	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);

	Forbid();

	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);

	if(Child)
		CLI -> cli_Module = NULL;

	Permit();

	return(Child);
}

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

VOID __saveds
HandleInput()
{
	STRPTR Error;

	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;
		}
	}

	if(DoIconify)
	{
		HandleIconify();

		DoIconify = FALSE;

		if(MainTerminated)
			goto Stop;
	}

	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);

		/* Build new menu strip. */

	if(Error = BuildMenu())
	{
		if(IntuitionBase)
			MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Error);

		CloseAll(TRUE);

		return;
	}

		/* Show our business card. */

	if(!StartupFile[0])
	{
		if(ShowInfo(TRUE))
			while(HandleRexx());
	}

	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)
	{
			/* Handle the signal responses. */

		HandleResponse();

		if(RebuildMenu)
		{
			if(Error = BuildMenu())
			{
				if(IntuitionBase)
					MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Error);

				MainTerminated = TRUE;

				break;
			}

			RebuildMenu = FALSE;
		}

			/* Are we to run an ARexx script file? */

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

			SendARexxCommand(StartupFile);

			ReleaseWindows();

			StartupFile[0] = 0;
		}

			/* Are we to leave the main loop? */

		if(MainTerminated)
			break;

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

		if(FlowInfo . Changed)
			HandleFlowChange();

			/* Are we no longer online? */

		if(!Online && WasOnline)
			HandleOnlineCleanup();

			/* Now for public screen mode changes. */

		if(FixPubScreenMode)
			PubScreenStuff();

			/* Now for window size changes. */

		if(FixScreenSize)
			ScreenSizeStuff();

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

		if(ResetDisplay)
		{
			if(!DisplayReset())
				break;
		}

			/* Display the online cost. */

		if(!Online && CurrentPay)
		{
				/* Reset the text rendering styles, font, etc. in
				 * order to keep the following text from getting
				 * illegible.
				 */

			SoftReset();

				/* 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;
		}

			/* Iconify the program? */

		if(DoIconify)
		{
			HandleIconify();

			if(MainTerminated)
				break;
		}

			/* Reset the serial driver? */

		if(ResetSerial)
		{
			HandleSerialReset();

			if(MainTerminated)
				break;
		}

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

		if(ReleaseSerial)
		{
			HandleSerialRelease();

			if(MainTerminated)
				break;
		}

			/* Invoke the dialing function? */

		if(DoDial != DIAL_IGNORE)
		{
			if(DoDial == DIAL_LIST)
			{
				BYTE OldStatus = Status;

				DoDial = DIAL_IGNORE;

				BlockWindows();

				DialPanel();

				FreeDialList(FALSE);

				Status = OldStatus;

				SetRedialMenu();

				ReleaseWindows();
			}
			else
			{
				DoDial = DIAL_IGNORE;

				HandleMenuCode(MEN_REDIAL,NULL);
			}
		}
	}

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

Stop:	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	*Message;
	ULONG			 IClass,Code,Qualifier;
	LONG			 MouseX,MouseY,Len,GadgetID;
	struct Gadget		*Gadget;
	UBYTE			 Char,InputBuffer[257];
	struct Window		*IDCMPWindow;
	BYTE			 Result = FALSE;

		/* Are we reading input from the clipboard? */

	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)
				(*SendLine)(InputBuffer,Len);

			Result = TRUE;
		}
	}

		/* Any news in the mail? */

	if(Message = (struct IntuiMessage *)GetMsg(Window -> UserPort))
	{
		if(Message -> IDCMPWindow == InfoWindow)
		{
			struct IntuiMessage *GT_Message;

				/* Translate the message. */

			if(GT_Message = GT_FilterIMsg(Message))
			{
					/* Pick up the pieces. */

				IClass		= GT_Message -> Class;
				Code		= GT_Message -> Code;
				Qualifier	= GT_Message -> Qualifier;

				MouseX		= GT_Message -> MouseX;
				MouseY		= GT_Message -> MouseY;

				IDCMPWindow	= GT_Message -> IDCMPWindow;

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

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

				Message = GT_PostFilterIMsg(GT_Message);
			}
			else
				IClass = NULL;
		}
		else
		{
				/* Pick up the pieces. */

			IClass		= Message -> Class;
			Code		= Message -> Code;
			Qualifier	= Message -> Qualifier;
			Gadget		= (struct Gadget *)Message -> IAddress;

			MouseX		= Message -> MouseX;
			MouseY		= Message -> MouseY;

			IDCMPWindow	= Message -> IDCMPWindow;

			if(IClass == IDCMP_IDCMPUPDATE)
				GadgetID = GetTagData(GA_ID,0,(struct TagItem *)Gadget);

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

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

		ReplyMsg(Message);
	}
	else
		IClass = NULL;

		/* Did we get any information? */

	if(IClass)
	{
			/* The following messages probably
			 * originated from the fast! macro
			 * panel.
			 */

		if(IDCMPWindow == FastWindow)
		{
			switch(IClass)
			{
					/* Close the window. */

				case IDCMP_CLOSEWINDOW:

					CloseFastWindow();

					return(TRUE);

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

				case IDCMP_NEWSIZE:

					RefreshFastWindow(FALSE);

					return(TRUE);

					/* Some gadget was invoked. */

				case IDCMP_GADGETUP:
				case IDCMP_GADGETDOWN:

					GadgetID = Gadget -> GadgetID;

				case IDCMP_MOUSEMOVE:
				case IDCMP_IDCMPUPDATE:

					HandleFastWindowGadget(IClass,Code,GadgetID);

					return(TRUE);
			}
		}

				/* Clicked inside the status window? */

		if(IDCMPWindow == InfoWindow)
		{
			switch(IClass)
			{
				case IDCMP_CLOSEWINDOW:

					CloseInfoWindow();

					return(TRUE);

				case IDCMP_MOUSEBUTTONS:

					if(!(Code & IECODE_UP_PREFIX))
						RefreshInfoWindow();

					return(TRUE);
			}
		}

			/* Status window activated? */

		if(IDCMPWindow == StatusWindow && IClass == IDCMP_ACTIVEWINDOW)
			NormalCursor();

			/* Main window message? */

		if(IDCMPWindow == Window)
		{
			switch(IClass)
			{
				case IDCMP_INACTIVEWINDOW:

					HoldClick = FALSE;

					GhostCursor();

					break;

				case IDCMP_ACTIVEWINDOW:

					NormalCursor();

					break;

				case IDCMP_NEWSIZE:

						/* Is a window clipping region installed? */

					if(ClipRegion)
					{
						struct Rectangle RegionRectangle;

							/* Install old region. */

						InstallClipRegion(Window -> WLayer,OldRegion);

							/* Fill in the clipping rectangle. */

						RegionRectangle . MinX = Window -> BorderLeft;
						RegionRectangle . MinY = Window -> BorderTop;
						RegionRectangle . MaxX = Window -> Width - (Window -> BorderRight + 1);
						RegionRectangle . MaxY = Window -> Height - (Window -> BorderBottom + 1);

							/* Clear previous clipping region. */

						ClearRegion(ClipRegion);

							/* Set new clipping region. */

						OrRectRegion(ClipRegion,&RegionRectangle);

							/* Install new clipping region. */

						OldRegion = InstallClipRegion(Window -> WLayer,ClipRegion);
					}

					HandleMenuCode(MEN_RESET_TERMINAL,Qualifier);
					break;

				case IDCMP_CLOSEWINDOW:

					HandleMenuCode(MEN_QUIT,Qualifier);
					break;

				case IDCMP_MOUSEMOVE:

					if(HoldClick)
					{
						if(!Marking)
							SetMarker(ClickX,ClickY);
						else
						{
							MouseX -= WindowLeft;

							if(MouseX < 0)
								MouseX = 0;

							if(MouseX > WindowWidth - 1)
								MouseX = WindowWidth - 1;

							MouseY -= WindowTop;

							if(MouseY < 0)
								MouseY = 0;

							if(MouseY > WindowHeight - 1)
								MouseY = WindowHeight - 1;

							MoveMarker(MouseX,MouseY);
						}
					}

					break;

				case IDCMP_MOUSEBUTTONS:

					if(!XEmulatorBase || Config -> TerminalConfig -> EmulationMode != EMULATION_EXTERNAL)
					{
						if(Code == SELECTUP)
							HoldClick = FALSE;

						if(Code == SELECTDOWN)
						{
							MouseX -= WindowLeft;

							if(MouseX < 0)
								MouseX = 0;

							if(MouseX > WindowWidth - 1)
								MouseX = WindowWidth - 1;

							MouseY -= WindowTop;

							if(MouseY < 0)
								MouseY = 0;

							if(MouseY > WindowHeight - 1)
								MouseY = WindowHeight - 1;

							HoldClick = TRUE;

							if(Qualifier & IEQUALIFIER_CONTROL)
							{
								WORD FirstX,FirstY;

								FirstX = MouseX / TextFontWidth;
								FirstY = MouseY / TextFontHeight;

								if(FirstX <= LastColumn && FirstY <= LastLine)
								{
									UBYTE Char;

									ObtainSemaphore(RasterSemaphore);

									Char = Raster[FirstY * RasterWidth + FirstX];

									ReleaseSemaphore(RasterSemaphore);

									if(Char && Char != ' ')
									{
										SerWrite(&Char,1);

										if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
										{
											switch(Config -> TerminalConfig -> SendCR)
											{
												case CR_ASCR:

													SerWrite("\r",1);
													break;

												case CR_ASCRLF:

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

								return(TRUE);
							}

							if((Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT)) && (Qualifier & IEQUALIFIER_LEFTBUTTON))
							{
								WORD DeltaX,DeltaY;

								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);
									}
								}

								return(TRUE);
							}

							ReportMouse(TRUE,Window);

							if(!FirstClick)
							{
								ULONG CurrentSecs,CurrentMicros;

								CurrentTime(&CurrentSecs,&CurrentMicros);

								FirstClick = TRUE;

								if(ABS(ClickX - MouseX) <= TextFontWidth && ABS(ClickY - MouseY) <= TextFontHeight && DoubleClick(ClickSecs,ClickMicros,CurrentSecs,CurrentMicros))
								{
									MarkWord(ClickX,ClickY);

									return(TRUE);
								}
								else
								{
									CurrentTime(&ClickSecs,&ClickMicros);

									FirstClick	= FALSE;

									ClickX		= MouseX;
									ClickY		= MouseY;
								}
							}
							else
							{
								CurrentTime(&ClickSecs,&ClickMicros);

								FirstClick	= FALSE;

								ClickX		= MouseX;
								ClickY		= MouseY;
							}

							if(Marking)
							{
								if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
									MoveMarker(MouseX,MouseY);
								else
								{
									DropMarker();

									CurrentTime(&ClickSecs,&ClickMicros);

									FirstClick	= FALSE;

									ClickX		= MouseX;
									ClickY		= MouseY;

									ReportMouse(TRUE,Window);
								}
							}
						}
					}

					break;
			}
		}

			/* Now for general information. */

		switch(IClass)
		{
			case IDCMP_RAWKEY:

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

				if(Len)
				{
					switch(CharType[Char])
					{
						case CHAR_HELP:

							GuideDisplay(CONTEXT_MAIN);

							Len = 0;

							break;

						case CHAR_CURSOR:

							if(ClipInput)
							{
								CloseClip();

								ClipInput = ClipXerox = ClipPrefix = FALSE;
							}

								/* If in cursor key applications mode,
								 * send the corresponding string.
								 */

							if(Config -> EmulationConfig -> CursorMode == KEYMODE_APPLICATION)
							{
								STATIC STRPTR CursorTable[4] =
								{
									"\033OA",
									"\033OB",
									"\033OC",
									"\033OD"
								};

								SerWrite(CursorTable[Char - CUP],3);
							}
							else
							{
								WORD QualType;

									/* Find the approriate qualifier. */

								if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
									QualType = 1;
								else
								{
									if(Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
										QualType = 2;
									else
									{
										if(Qualifier & IEQUALIFIER_CONTROL)
											QualType = 3;
										else
											QualType = 0;
									}
								}

									/* Send the corresponding string. */

								SerialCommand(CursorKeys -> Keys[QualType][Char - CUP]);
							}

							Len = 0;

							break;

							/* Any function key pressed? */

						case CHAR_FUNCTION:

							if(ClipInput)
							{
								CloseClip();

								ClipInput = ClipXerox = ClipPrefix = FALSE;
							}

							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]);
								}
							}

							Len = 0;

							break;

							/* Anything else? */

						default:

							if(Len == 1 && (Qualifier & IEQUALIFIER_NUMERICPAD) && (Config -> EmulationConfig -> NumericMode == KEYMODE_APPLICATION))
							{
								STATIC STRPTR ApplicationTable[20][2] =
								{
									"0",	"\033Op",
									"1",	"\033Oq",
									"2",	"\033Or",
									"3",	"\033Os",
									"4",	"\033Ot",
									"5",	"\033Ou",
									"6",	"\033Ov",
									"7",	"\033Ow",
									"8",	"\033Ox",
									"9",	"\033Oy",
									"-",	"\033Om",
									"+",	"\033Ol",	/* This should really be a comma */
									".",	"\033On",

									"[",	"\033OP",
									"{",	"\033OP",
									"]",	"\033OQ",
									"}",	"\033OQ",
									"/",	"\033OR",
									"*",	"\033OS",

									"\r",	"\033OM"
								};

								WORD i;

								for(i = 0 ; i < 20 ; i++)
								{
									if(Char == ApplicationTable[i][0][0])
									{
										if(ClipInput)
										{
											CloseClip();

											ClipInput = ClipXerox = ClipPrefix = FALSE;
										}

										SerWrite(ApplicationTable[i][1],strlen(ApplicationTable[i][1]));

										Len = 0;

										break;
									}
								}
							}

							break;
					}

						/* Any characters to send? */

					if(Len)
					{
						STRPTR	Buffer = InputBuffer;
						UBYTE	Mask,
							c;

							/* Strip the high order bit? */

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

						if(ClipInput)
						{
							CloseClip();

							ClipInput = ClipXerox = ClipPrefix = FALSE;
						}

						while(Len--)
						{
							switch(CharType[c = (*Buffer++) & Mask])
							{
								case CHAR_ENTER:

									if(Status == STATUS_HOLDING)
										DoBeep();
									else
									{
										switch(Config -> TerminalConfig -> SendLF)
										{
											case LF_ASLF:

												SerWrite("\n",1);
												break;

											case LF_ASLFCR:

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

									break;

								case CHAR_RETURN:

									if(Status == STATUS_HOLDING)
										DoBeep();
									else
									{
										switch(Config -> TerminalConfig -> SendCR)
										{
											case CR_ASCR:

												SerWrite("\r",1);
												break;

											case CR_ASCRLF:

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

									break;

									/* Stop in/output. */

								case CHAR_XON:

									if(Status == STATUS_HOLDING)
										DoBeep();
									else
									{
										if(Config -> SerialConfig -> xONxOFF)
											Status = STATUS_HOLDING;

										if(Config -> SerialConfig -> PassThrough)
											SerWrite(&c,1);
									}

									break;

									/* Restart in/output. */

								case CHAR_XOFF:

									if(Status == STATUS_HOLDING)
										Status = STATUS_READY;

									if(Config -> SerialConfig -> PassThrough)
										SerWrite(&c,1);

									break;

									/* Any other character. */

								case CHAR_VANILLA:

									if(Status == STATUS_HOLDING)
										DoBeep();
									else
									{
										if(Config -> TerminalConfig -> FontMode == FONT_IBM)
										{
												/* Convert special
												 * Amiga characters into
												 * alien IBM dialect.
												 */

											if(IBMConversion[c])
												SerWrite(&IBMConversion[c],1);
											else
												SerWrite(&c,1);
										}
										else
											SerWrite(&c,1);
									}

									break;
							}
						}
					}
				}

				break;

				/* A menu item was selected. */

			case IDCMP_MENUPICK:

				HandleMenu(Code,Qualifier);
				break;
		}

		return(TRUE);
	}

	return(Result);
}

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

VOID
HandleMenuCode(ULONG Code,ULONG Qualifier)
{
	struct FileRequester	*FileRequest;
	UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH],
				*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),TRUE))
			{
				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),FALSE))
			{
				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)
					{
						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))
									break;
							}

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

						Close(SomeFile);

						AddProtection(DummyBuffer,FIBF_EXECUTE);

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

				FreeAslRequest(FileRequest);
			}

			ReleaseWindows();

			break;

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

		case MEN_PRINT_SCREEN:

			BlockWindows();

			if(RasterEnabled)
				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)
				CloseFileCapture();
			else
				OpenFileCapture();

			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;

				if(SoundChanged)
					Len += strlen(LocaleString(MSG_WAIT_SOUND_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(Config -> ClipConfig -> ClipboardUnit))
			{
				ClipInput = TRUE;

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

			break;

		case MEN_COPY:

			if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
				ClipMarker(TRUE);
			else
				ClipMarker(FALSE);

			break;

		case MEN_CLEAR:

			DropMarker();
			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. */
#ifdef USE_AREXX

		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;

#endif	/* USE_AREXX */

			/* 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;
			}

			SetRedialMenu();

			ReleaseWindows();

			break;

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

		case MEN_REDIAL:

			BlockWindows();

			do
			{
				if(!DialPanel())
				{
					Status = OldStatus;

					break;
				}

				Status = OldStatus;
			}
			while(PhonePanel());

			SetRedialMenu();

			ReleaseWindows();

			break;

			/* Dial a single number. */

		case MEN_DIAL_NUMBER:

			BlockWindows();

			DummyBuffer[0] = 0;

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

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

						NewList(LocalList);

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

							strcpy(DialNode -> VanillaNode . ln_Name,DummyBuffer);

							AddTail(LocalList,&DialNode -> VanillaNode);

							FreeDialList(TRUE);

							DialList = LocalList;

							DialPanel();

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

			SetRedialMenu();

			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;
			UserName[0]		= 0;

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

				/* Reset time limit. */

			LimitCount = -1;

				/* Note the  last action. */

			LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_HANG_UP_TXT));

			SoundPlay(SOUND_DISCONNECT);

			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;

			ChosenEntry = NULL;

				/* Enable the dialing functions. */

			SetDialMenu(TRUE);

				/* Previous configuration available? */

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

				SaveConfig(Config,PrivateConfig);

					/* Copy configuration. */

				SaveConfig(BackupConfig,Config);

					/* Set up new configuration. */

				ConfigSetup();

					/* Free old configuration. */

				DeleteConfiguration(BackupConfig);

				BackupConfig = NULL;
			}

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

			break;

			/* Wait a bit... */

		case MEN_WAIT:
		{
			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_GLOBAL_CONTINUE_TXT);
			Easy . es_TextFormat	= (UBYTE *)LocaleString(MSG_TERMMAIN_WAITING_TXT);

			BlockWindows();

			if(ReqWindow = BuildEasyRequest(Window,&Easy,NULL))
			{
				ULONG	Signals;
				BYTE	Done = FALSE;

					/* Don't echo serial output. */

				Quiet = TRUE;

				do
				{
					SerWrite(" \b",2);

					HandleSerial();

					StartTime(1,0);

					Signals = Wait(SIG_TIMER | PORTMASK(ReqWindow -> UserPort));

					if(Signals & SIG_TIMER)
						WaitIO(TimeRequest);

					if(Signals & PORTMASK(ReqWindow -> UserPort))
					{
						if(!SysReqHandler(ReqWindow,NULL,FALSE))
						{
							Done = TRUE;

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

							WaitIO(TimeRequest);
						}
					}
				}
				while(!Done);

				Quiet = FALSE;

				FreeSysRequest(ReqWindow);
			}

			ReleaseWindows();
		}

		break;

			/* Flush the serial buffers. */

		case MEN_FLUSH_BUFFER:

			ClearSerial();

			RestartSerial();

			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,TRUE);

				ASCIIShutdown();
			}

			ReleaseWindows();

			break;

		case MEN_DOWNLOAD_ASCII:

			BlockWindows();

			if(ASCIISetup())
			{
				StartXprReceive(TRANSFER_ASCII,NULL,TRUE);

				ASCIIShutdown();
			}

			ReleaseWindows();

			break;

		case MEN_UPLOAD_TEXT:

			BlockWindows();

			BinaryTransfer = FALSE;

			StartXprSend(TRANSFER_TEXT,TRUE);

			BinaryTransfer = TRUE;

			ReleaseWindows();

			break;

		case MEN_DOWNLOAD_TEXT:

			BlockWindows();

			BinaryTransfer = FALSE;

			StartXprReceive(TRANSFER_TEXT,NULL,TRUE);

			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),TRUE))
				{
					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,TRUE);

			ReleaseWindows();

			break;

			/* Download some files. */

		case MEN_DOWNLOAD_BINARY:

			BlockWindows();

			BinaryTransfer = TRUE;

			StartXprReceive(TRANSFER_BINARY,NULL,TRUE);

			ReleaseWindows();

			break;

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

		case MEN_CLEAR_BUFFER:

			if(Lines)
			{
				BlockWindows();

				if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
				{
					FreeBuffer();

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

						TerminateBuffer();
					}
				}

				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)
			{
				Forbid();

				Signal(BufferProcess,SIG_KILL);

				ClrSignal(SIG_HANDSHAKE);

				Wait(SIG_HANDSHAKE);

				Permit();
			}

			break;

			/* Is the buffer to be frozen? */

		case MEN_FREEZE_BUFFER:

			BufferFrozen ^= TRUE;

			CheckItem(MEN_FREEZE_BUFFER,BufferFrozen);

			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),FALSE))
			{
				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:	FreeBuffer();
									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 || !BufferLines)
				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),Config -> CaptureConfig -> BufferPath,"",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT),FALSE))
				{
					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 = BufferLines[i][-1];

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

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

						ReleaseSemaphore(BufferSemaphore);

						Close(SomeFile);

						AddProtection(DummyBuffer,FIBF_EXECUTE);

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

						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
			{
				DropMarker();

				ClearCursor();

				EraseScreen("2J");
				SetAbsolutePosition("H");

				DrawCursor();
			}

			break;

			/* Reset the current text rendering font. */

		case MEN_RESET_FONT:

			if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
				XEmulatorResetCharset(XEM_IO);
			else
			{
				DropMarker();

				CurrentFont = TextFont;

				SetFont(RPort,CurrentFont);

				ConOutputUpdate();
			}

			break;

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

		case MEN_RESET_STYLES:

			if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
				XEmulatorResetTextStyles(XEM_IO);
			else
			{
				DropMarker();

				ClearCursor();

				SetAttributes("0m");

				Config -> EmulationConfig -> FontScale = SCALE_NORMAL;

				FgPen = GetPenIndex(SafeTextPen);
				BgPen = 0;

				if(ReadAPen(RPort) != MappedPens[0][FgPen])
					SetAPen(RPort,MappedPens[0][FgPen]);

				if(ReadBPen(RPort) != MappedPens[0][BgPen])
					SetBPen(RPort,MappedPens[0][BgPen]);

				SetWrMsk(RPort,DepthMask);

				ConFontScaleUpdate();

				DrawCursor();
			}

			break;

			/* Reset the whole terminal. */

		case MEN_RESET_TERMINAL:

			if(XEmulatorBase && Config -> TerminalConfig -> EmulationMode == EMULATION_EXTERNAL)
				XEmulatorResetConsole(XEM_IO);
			else
			{
				FreeMarker();

				DoCancel();

				ClearCursor();

				Reset();

				DrawCursor();
			}

			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,NULL);

			ReleaseWindows();

			break;

			/* Set the serial preferences. */

		case MEN_SERIAL:

			BlockWindows();

			if(SerialPanel(Config,NULL))
			{
				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the modem preferences. */

		case MEN_MODEM:

			BlockWindows();

			if(ModemPanel(Config,NULL))
			{
				FlowInit(TRUE);

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the screen preferences. */

		case MEN_SCREEN:

			BlockWindows();

			if(ScreenPanel(Config,NULL))
			{
				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,NULL))
			{
				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the clipboard preferences. */

		case MEN_CLIPBOARD:

			BlockWindows();

			if(ClipPanel(Config,NULL))
			{
				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the capture preferences. */

		case MEN_CAPTURE:

			BlockWindows();

			if(CapturePanel(Config,NULL))
			{
				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the command preferences. */

		case MEN_COMMANDS:

			BlockWindows();

			if(CommandPanel(Config,NULL))
				ConfigChanged = TRUE;

			ReleaseWindows();

			break;

			/* Set the miscellaneous preferences. */

		case MEN_MISC:

			BlockWindows();

			if(MiscPanel(Config,NULL))
			{
				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the path settings. */

		case MEN_PATH:

			BlockWindows();

			if(PathPanel(Config,NULL))
				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(FALSE))
					strcpy(Config -> FileConfig -> ProtocolFileName,LastXprLibrary);
				else
				{
					strcpy(LastXprLibrary,Config -> FileConfig -> ProtocolFileName);

					ProtocolSetup(FALSE);
				}

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

			ReleaseWindows();

			break;

			/* Set the translation tables. */

		case MEN_TRANSLATION:

			BlockWindows();

			TranslationChanged |= TranslationPanel();

				/* Choose the right console write routine. */

			ConOutputUpdate();

			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;

			/* Set the sound preferences. */

		case MEN_SOUND:

			BlockWindows();

			if(SoundPanel(&SoundConfig))
				SoundInit();

			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,TRUE))
			{
				if(ReadConfig(DummyBuffer,PrivateConfig))
				{
					SwapConfig(PrivateConfig,Config);

					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(!WriteConfig(LastConfig,Config))
					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,TRUE))
			{
				if(WriteConfig(DummyBuffer,Config))
				{
					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);

				CheckItem(MEN_PACKET_WINDOW,TRUE);
			}

			break;

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

		case MEN_FAST_MACROS_WINDOW:

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

			break;

		default:if(Code >= DIAL_MENU_LIMIT)
			{
				if(!LocalDialList && !Online)
				{
					if(LocalDialList = (struct List *)AllocVec(sizeof(struct List),MEMF_ANY))
						NewList(LocalDialList);
				}

				if(LocalDialList)
				{
					LONG Index = Code - DIAL_MENU_LIMIT;

					struct PhoneNode *NewNode;

						/* Create a new node to be added to the dial list. */

					if(NewNode = (struct PhoneNode *)AllocVec(sizeof(struct PhoneNode),MEMF_ANY | MEMF_CLEAR))
					{
							/* Take care of the name and the corresponding phone book entry. */

						NewNode -> VanillaNode . ln_Name	= NewNode -> LocalName;
						NewNode -> Entry			= Phonebook[Index];

						Phonebook[Index] -> Count = ++LocalCount;

						strcpy(NewNode -> LocalName,Phonebook[Index] -> Header -> Name);

							/* Install back-link. */

						NewNode -> Entry -> Node = NewNode;

						AddTail(LocalDialList,&NewNode -> VanillaNode);
					}
				}
			}

			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))
		{
			HandleMenuCode((ULONG)GTMENUITEM_USERDATA(MenuItem),Qualifier);

			if(DisplayReopened)
			{
				DisplayReopened = FALSE;

				return;
			}

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

	if(LocalDialList)
	{
		if(LocalDialList -> lh_Head -> ln_Succ && !Online)
		{
			FreeDialList(TRUE);

			DialList = LocalDialList;

			LocalDialList = NULL;

			LocalCount = -1;

			SetRedialMenu();

			HandleMenuCode(MEN_REDIAL,NULL);
		}
		else
		{
			struct Node *Node,*NextNode;

			Node = LocalDialList -> lh_Head;

			while(NextNode = Node -> ln_Succ)
			{
				FreeVec(Node);

				Node = NextNode;
			}

			FreeVec(LocalDialList);

			LocalDialList = NULL;

			LocalCount = -1;
		}
	}
}

	/* HandleWorkbenchWindow():
	 *
	 *	Handle input coming from the Workbench window.
	 */

VOID
HandleWorkbenchWindow()
{
	struct FileInfoBlock	*FileInfo;
	struct AppMessage	*AppMessage;

	if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
	{
		struct FileTransferInfo *Info;

		if(Info = AllocFileTransferInfo())
		{
			LONG FilesFound = 0,i;
			BYTE Success = TRUE;

			while(AppMessage = (struct AppMessage *)GetMsg(WorkbenchPort))
			{
				if(Success && AppMessage -> am_Type == MTYPE_APPWINDOW)
				{
					for(i = 0 ; Success && i < AppMessage -> am_NumArgs ; i++)
					{
						if(AppMessage -> am_ArgList[i] . wa_Lock && AppMessage -> am_ArgList[i] . wa_Name)
						{
							BPTR OldLock;

							if(OldLock = CurrentDir(AppMessage -> am_ArgList[i] . wa_Lock))
							{
								BPTR FileLock;

								if(FileLock = Lock(AppMessage -> am_ArgList[i] . wa_Name,ACCESS_READ))
								{
									if(Examine(FileLock,FileInfo))
									{
										if(FileInfo -> fib_DirEntryType < 0)
										{
											if(NameFromLock(FileLock,SharedBuffer,512))
											{
												if(!AddFileTransferNode(Info,SharedBuffer,FileInfo -> fib_Size))
													Success = FALSE;
												else
												{
													FilesFound++;

													if(Config -> MiscConfig -> TransferIcons)
													{
														BPTR InfoLock;

														strcat(SharedBuffer,".info");

														if(InfoLock = Lock(SharedBuffer,ACCESS_READ))
														{
															if(Examine(InfoLock,FileInfo))
															{
																if(FileInfo -> fib_DirEntryType < 0)
																{
																	if(!AddFileTransferNode(Info,SharedBuffer,FileInfo -> fib_Size))
																		Success = FALSE;
																	else
																		FilesFound++;
																}
															}

															UnLock(InfoLock);
														}
													}
												}
											}
										}
									}

									UnLock(FileLock);
								}

								CurrentDir(OldLock);
							}
						}
					}
				}

				ReplyMsg((struct Message *)AppMessage);
			}

			if(FilesFound)
			{
				SortFileTransferInfo(Info);

				BlockWindows();

				switch(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_TRANSFER_FILES_AS_TXT),LocaleString(MSG_TERMMAIN_BINARY_UPLOAD_CANCEL_TXT)))
				{
					case 1:	BinaryTransfer		= FALSE;
						FileTransferInfo	= Info;

						StartXprSendFromList(TRANSFER_TEXT,TRUE);

						break;

					case 2:	BinaryTransfer		= TRUE;
						FileTransferInfo	= Info;

						StartXprSendFromList(TRANSFER_BINARY,TRUE);

						break;

					case 0:	FreeFileTransferInfo(Info);
						break;
				}

				ReleaseWindows();
			}
		}

		FreeDosObject(DOS_FIB,FileInfo);
	}

	while(AppMessage = (struct AppMessage *)GetMsg(WorkbenchPort))
		ReplyMsg((struct Message *)AppMessage);
}

	/* HandleIconify():
	 *
	 *	Handle program iconification.
	 */

VOID
HandleIconify()
{
	BYTE Released = FALSE;

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

	BlockWindows();

		/* Open workbench.library. */

	if(WorkbenchBase)
	{
			/* Open icon.library. */

		if(IconBase)
		{
			struct DiskObject *Icon;

			if(!(Icon = GetProgramIcon()))
				Icon = GetDefDiskObject(WBTOOL);

				/* Did we get an icon? */

			if(Icon)
			{
				struct MsgPort *IconPort;

					/* Reset the icon type. */

				Icon -> do_Type		= NULL;

					/* 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,TAG_DONE))
					{
						struct AppMessage	*AppMessage;
						UBYTE			*String,*Error;

							/* Reset the guardian. */

						IconTerminated = FALSE;

							/* Release the window. */

						Released = TRUE;

						ReleaseWindows();

							/* Close the display. full stop. */

						if(DeleteDisplay())
						{
								/* Reset and release the serial driver. */

							if(Config -> MiscConfig -> ReleaseDevice)
							{
								ClearSerial();

								DeleteSerial();
							}

								/* Wait for double-click. */

IconLoop:						while(!IconTerminated)
							{
								ULONG SignalSet = Wait(PORTMASK(IconPort) | SIG_REXX);

								if(SignalSet & PORTMASK(IconPort))
								{
										/* 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)
									while(HandleRexx());
							}

								/* 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 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(!MainTerminated)
							{
								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();
								}
							}
						}
						else
						{
							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();
						}

							/* 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));
		}
		else
			MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_ICON_LIBRARY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
	}
	else
		MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_WORKBENCH_LIBRARY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

	if(!Released)
		ReleaseWindows();

		/* Finished! */

	DoIconify = FALSE;
}

	/* HandleOnlineCleanup():
	 *
	 *	Perform offline cleanup tasks.
	 */

VOID
HandleOnlineCleanup()
{
	SoundPlay(SOUND_DISCONNECT);

	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;

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

	WasOnline = FALSE;

	ChosenEntry = NULL;

	LimitCount = -1;

		/* Previous configuration available? */

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

		SaveConfig(Config,PrivateConfig);

			/* Copy configuration. */

		SaveConfig(BackupConfig,Config);

			/* Set up new configuration. */

		ConfigSetup();

			/* Free old configuration. */

		DeleteConfiguration(BackupConfig);

		BackupConfig = NULL;
	}

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

	/* HandleFlowChange():
	 *
	 *	Handle data flow scanner information.
	 */

VOID
HandleFlowChange()
{
	if(!Online && (FlowInfo . Voice || FlowInfo . Ring || FlowInfo . Connect))
	{
		if(FlowInfo . Voice)
		{
			WakeUp(Window,SOUND_VOICE);

			ConWrites(LocaleString(MSG_TERMMAIN_INCOMING_VOIC_CALL_TXT));

			Say(LocaleString(MSG_TERMMAIN_SAY_INCOMING_VOICE_CALL_TXT));
		}

		if(FlowInfo . Ring)
		{
			WakeUp(Window,SOUND_RING);

			ConWrites(LocaleString(MSG_TERMMAIN_INCOMING_CALL_TXT));

			Say(LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));
		}

		if(FlowInfo . Connect)
		{
			WakeUp(Window,SOUND_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,TRUE))
						SerWrite(ZModemCancel,20);

					break;

				case UPLOAD_BINARY:

					BinaryTransfer = TRUE;

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

					break;

				case UPLOAD_ABORT:

					SerWrite(ZModemCancel,20);
					break;
			}

			ReleaseWindows();
		}
	}

	FlowInit(TRUE);
}

	/* HandleSerialReset():
	 *
	 *	Handle serial device reset.
	 */

VOID
HandleSerialReset()
{
	ClearSerial();

	DeleteSerial();

	BlockWindows();

	ReopenSerial();

	ReleaseWindows();
}

	/* HandleSerialRelease():
	 *
	 *	Release the serial device driver, then reopen it again.
	 */

VOID
HandleSerialRelease()
{
	APTR	OldPtr = ThisProcess -> pr_WindowPtr;
	BYTE	Continue,SerialClosed;

	ThisProcess -> pr_WindowPtr = (APTR)Window;

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

	if(ReadPort)
		SerialClosed = FALSE;
	else
		SerialClosed = TRUE;

	BlockWindows();

		/* Prevent catastrophes! */

	if(Online && !SerialClosed)
	{
		if(!MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_YOU_ARE_STILL_ONLINE_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
			Continue = FALSE;
		else
			Continue = TRUE;
	}
	else
		Continue = TRUE;

	if(Continue)
	{
		if(SerialClosed)
			ReopenSerial();
		else
		{
			ClearSerial();

			DeleteSerial();

			if(MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_UNIT_RESET_AND_RELEASED_TXT),LocaleString(MSG_TERMMAIN_RETURN_QUIT_TXT),Config -> SerialConfig -> SerialDevice,Config -> SerialConfig -> UnitNumber))
				ReopenSerial();
			else
				MainTerminated = TRUE;
		}
	}

	ReleaseSerial = FALSE;

	ThisProcess -> pr_WindowPtr = OldPtr;

	ReleaseWindows();
}

	/* HandleExternalEmulation():
	 *
	 *	Handle external emulation event.
	 */

VOID
HandleExternalEmulation()
{
	if(!XEmulatorSignal(XEM_IO,XEM_Signal))
	{
		CloseEmulator();

		ResetDisplay = TRUE;
	}
}

	/* HandleClipboard():
	 *
	 *	Handle clipboard input processing.
	 */

VOID
HandleClipboard()
{
	if(!ClipInput)
	{
		if(!OpenClip(Config -> ClipConfig -> ClipboardUnit))
			ClipInput = ClipXerox = TRUE;
		else
			ClipInput = ClipXerox = FALSE;
	}
}

	/* HandleSerialCheck():
	 *
	 *	Query the state of the serial line.
	 */

VOID
HandleSerialCheck()
{
		/* Query serial status. */

	WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

	DoIO(WriteRequest);

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

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

		/* Check online time limit. */

	if(!LimitCount)
	{
		LimitCount = -1;

		BlockWindows();

		SendARexxCommand(LimitMacro);

		ReleaseWindows();
	}
}
