/*
**	$Id: termMain.c,v 1.16 92/08/18 16:12:39 olsen Sta Locker: olsen $
**	$Revision: 1.16 $
**	$Date: 92/08/18 16:12:39 $
**
**	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_KEEPIO,ARG_DONTPOP,ARG_SETTINGS,ARG_COUNT };

	/* Argument template. */

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

	/* Some global variables for starters. */

STATIC BYTE	DoIconify = FALSE;

	/* Local config path variable. */

STATIC STRPTR	ConfigPath;
STATIC UBYTE	ThePath[256];

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

LONG __saveds
main()
{
	UBYTE *Result;

		/* Set up SysBase. */

	SysBase = *(struct ExecBase **)4;

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

		/* Kickstart 2.0 or higher required, do you hear me? */

	if(SysBase -> LibNode . lib_Version < 36)
	{
		if(ThisProcess -> pr_CLI)
		{
			if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0))
			{
				Write(ThisProcess -> pr_COS,"Kickstart 2.0 or higher required.\a\n",35);

				ThisProcess -> pr_Result2 = ERROR_INVALID_RESIDENT_LIBRARY;

				CloseLibrary(DOSBase);
			}
		}
		else
		{
			if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
			{
				STATIC struct IntuiText BodyText =  {0,1,JAM1,5,3,&DefaultFont,(UBYTE *)"Kickstart 2.0 or higher required.", NULL};
				STATIC struct IntuiText SorryText = {0,1,JAM1,6,3,&DefaultFont,(UBYTE *)"Sorry",NULL};

				struct Window *Window;

				if(Window = (struct Window *)BuildSysRequest(NULL,&BodyText,NULL,&SorryText,GADGETUP,301,46))
				{
					struct IntuiMessage *Message;

					ScreenToFront(Window -> WScreen);

					DisplayBeep(Window -> WScreen);

					WaitPort(Window -> UserPort);

					if(Message = (struct IntuiMessage *)GetMsg(Window -> UserPort))
						ReplyMsg(Message);

					FreeSysRequest(Window);
				}

				CloseLibrary(IntuitionBase);
			}
		}

		if(WBenchMsg)
		{
			Forbid();

			ReplyMsg((struct Message *)WBenchMsg);
		}

		return(RETURN_FAIL);
	}

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

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

		return(RETURN_FAIL);
	}

		/* We were called from Shell. */

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

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

		if(ArgArray = (UBYTE **)AllocVec(sizeof(UBYTE *) * (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 [KeepIO] [DontPop] [Settings <Path name>]\n\n         KeepIO = Keep links to the current Shell window.\n        DontPop = Do not pop an already running `term' to the front.\n       Settings = Path to search for settings files.\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);

							CloseLibrary(IntuitionBase);
						}

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

						CloseLibrary(DOSBase);

						return(RETURN_OK);
					}

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

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

						strcpy(ThePath,ArgArray[ARG_SETTINGS]);
					}

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

							CloseLibrary(DOSBase);

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

							CloseAll();

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

							CloseLibrary(DOSBase);

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

						CloseLibrary(DOSBase);

						return(RETURN_OK);
					}

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

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

					CloseLibrary(DOSBase);

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

				CloseAll();

				CloseLibrary(DOSBase);

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

			CloseLibrary(DOSBase);

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

				CloseLibrary(IntuitionBase);
			}

			if(DOSBase)
				CloseLibrary(DOSBase);

			Forbid();

			ReplyMsg((struct Message *)WBenchMsg);

			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))
				{
						/* Look for a `Settings' tooltype. */

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

						strcpy(ThePath,ConfigPath);

						ConfigPath = ThePath;
					}

						/* 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();
			}
			else
				HandleInput();
		}
	}

	return(RETURN_OK);
}

	/* 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)
	{
		UBYTE *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();

			return;
		}
	}

	BumpWindow(Window);

		/* Set up the public screen data. */

	PubScreenStuff();

		/* Change program priority. */

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

	BlockWindows();

		/* Load the phone book. */

	LoadPhonebook(LastPhone);

		/* Show our business card. */

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

	ReleaseWindows();

		/* Initialize the modem. */

	SerialCommand(Config . ModemInit);

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

	if(Config . StartupMacro[0])
		SerialCommand(Config . 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 . LogoffMacro[0])
					SerialCommand(Config . 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))
			while(HandleWindow() || HandleSerial() || HandlePacket() || HandleReview());

			/* Remove audio request. */

		if(SignalSet & SIG_AUDIO)
			ClearAudio();

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

		if(UsesZModem)
		{
			if(FlowInfo . ZModemUpload && XProtocolBase)
			{
				FlowInit();

				if(Config . 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();
				}
			}
		}

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

		if(FlowInfo . Changed && (FlowInfo . Voice || FlowInfo . Ring || FlowInfo . Connect))
		{
			if(!Online)
			{
				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);
				}
			}

			FlowInit();
		}

			/* 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;
								BYTE			 HadBuffer = BufferProcess ? TRUE : FALSE;
								UBYTE			*String,*Error;

									/* Release the window. */

								Released = TRUE;

								ReleaseWindows();

									/* Remove the display buffer. */

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

									Wait(SIGBREAKF_CTRL_C);
								}

									/* Reset and release the serial driver. */

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

									/* The buffer process was running before we
									 * went into iconified state, so let's try to
									 * conjure it up again.
									 */

								if(HadBuffer)
									LaunchBuffer();

									/* Open the serial driver. */

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

				CloseLibrary(WorkbenchBase);
			}
			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)
		{
			UBYTE *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 . SerialDevice,Config . UnitNumber))
			{
				UBYTE *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;
		}

		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. */

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

	ClearSerial();

	LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_PROGRAM_TERMINATED_TXT));

	Say(LocaleString(MSG_TERMMAIN_BYE_BYE_TXT));

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

	/* 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)
			{
				switch(Config . SendCR)
				{
					case CR_IGNORE:	break;

					case CR_ASCR:	SerWrite("\r",1);
							break;

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

			ClipXerox = FALSE;
		}
		else
		{
			if(Len > 0)
			{
					/* Is a send-delay enabled? */

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

						/* Run down the buffer... */

					for(i = 0 ; i < Len ; i++)
					{
							/* What kind of delay
							 * are we to provide?
							 */

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

									break;

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

									break;
						}

						SerWrite(&InputBuffer[i],1);
					}
				}
				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;

		Gadget		= (struct Gadget *)Massage -> IAddress;

		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
			 * originate 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 = FALSE;
			}

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

			if(Qualifier & IEQUALIFIER_NUMERICPAD)
			{
				if(HandleCursor(Char))
					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 . 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 . SendLF)
							{
								case LF_IGNORE:	break;

								case LF_ASLF:	goto SendIt;

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

							continue;
						}

						if(c == '\r')
						{
							switch(Config . 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 . PassThrough)
							{
								SerWrite(&c,1);

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

							/* Restart in/output. */

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

								continue;
							}
						}

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

SendIt:						if(Config . Font == 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);
			}
		}

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

		if(Class == IDCMP_MOUSEBUTTONS && !(Code & IECODE_UP_PREFIX))
		{
			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 . Emulation != 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.
	 */

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

		WaitTime(2,0);

		DeleteTransferPanel();

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

		SendAbort = FALSE;

		if(Config . DownloadMacro[0])
			SerialCommand(Config . 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 . SerBuffSize))
			{
				ConProcess(ReadBuffer,Length);

				Return = TRUE;
			}
		}

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

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

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

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

					if(TransferBits & XPRS_HOSTMON)
					{
						LONG Result = XProtocolHostMon(XprIO,ReadBuffer,1,1);

						if(TransferWindow)
							TransferCleanup();

						if(!Result)
							goto Loop;
					}
				}

					/* Send the byte to the console. */

				ConProcess(ReadBuffer,1);

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

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

					WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

					DoIO(WriteRequest);

					if(Length = WriteRequest -> IOSer . io_Actual)
					{
						if(Length > 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;

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

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

									if(TransferWindow)
										TransferCleanup();

									if(!Length)
									{
										Length = 1;

										continue;
									}
								}
							}

								/* Send the data to the console. */

							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(!SaveRPort(&Screen -> RastPort,VPort,0,Window -> TopEdge,Window -> Width,Window -> Height,Screen -> Width,Screen -> Height,FALSE,DummyBuffer))
							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 . Emulation != 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 . 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
					{
						BlockWindows();

						OldPtr = ThisProcess -> pr_WindowPtr;

						ThisProcess -> pr_WindowPtr = (APTR)Window;

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

							Status = OldStatus;
						}
						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(xpr_gets(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 = (UBYTE *)NumberBuffer;

									AddTail(LocalList,&DialNode -> VanillaNode);

									FreeDialList();

									DialList = LocalList;

									DialPanel();

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

					ReleaseWindows();

					break;

			/* Play a touch-tone phone number. */

		case MEN_PLAY_NUMBER:

					BlockWindows();

					if(xpr_gets(LocaleString(MSG_TERMMAIN_ENTER_PHONE_NUMBER_TO_PLAY_TXT),NumberBuffer))
					{
						if(!ToneDial(NumberBuffer))
							MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_GLOBAL_FAILED_TO_ALLOCATE_RESOURCES_FOR_PLAYING_TXT));
						else
							DeleteTone();
					}

					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 . 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 . SerialDevice,Config . UnitNumber))
									MainTerminated = TRUE;
							}
						}
					}

						/* Transmit the hangup command. */

					SerialCommand(Config . 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 . LogoffMacro[0] && WasOnline)
						SerialCommand(Config . 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 . Editor[0])
						GetString(LocaleString(MSG_TERMMAIN_ENTER_NAME_OF_EDITOR_TO_USE_TXT),&Config . Editor[0]);

					if(Config . 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 . 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))
										StoreBuffer(DummyBuffer,Len);

									Close(SomeFile);
								}
							}
						}

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

							FreeAslRequest(FileRequest);
						}
					}

					ReleaseWindows();

					break;

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

		case MEN_CLEAR_SCREEN:

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

					break;

			/* Reset the current text rendering font. */

		case MEN_RESET_FONT:

					if(XEmulatorBase && Config . Emulation == 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 . Emulation == EMULATION_EXTERNAL)
						XEmulatorResetTextStyles(XEM_IO);
					else
					{
						SetAttributes("0m");

						Config . FontScale = SCALE_NORMAL;

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

							case COLOUR_SIXTEEN:	FgPen = 15;
										break;

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

						BgPen = 0;

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

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

						SetWrMsk(RPort,0xFF);
					}

					break;

			/* Reset the whole terminal. */

		case MEN_RESET_TERMINAL:

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

						Reset();
					}

					break;

		case MEN_SET_EMULATION:

					BlockWindows();

					if(XEmulatorBase && Config . Emulation == 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();

					ReleaseWindows();

					break;

			/* Set the modem preferences. */

		case MEN_MODEM:

					BlockWindows();

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

					ReleaseWindows();

					break;

			/* Set the screen preferences. */

		case MEN_SCREEN:

					BlockWindows();

					if(ScreenPanel(&Config))
						ResetDisplay = TRUE;
					else
						PubScreenStuff();

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

							case COLOUR_SIXTEEN:	CopyMem(&Config . Colours[0],&EGAColours[0],16 * sizeof(UWORD));
										break;

							case COLOUR_AMIGA:	CopyMem(&Config . Colours[0],&DefaultColours[0],16 * sizeof(UWORD));
										break;

							case COLOUR_MONO:	CopyMem(&Config . Colours[0],&AtomicColours[0],16 * sizeof(UWORD));
										break;
						}
					}

					ReleaseWindows();

					break;

			/* Set the terminal preferences. */

		case MEN_TERMINAL:

					BlockWindows();

					TerminalPanel(&Config);

					ConfigSetup();

					ReleaseWindows();

					break;

		case MEN_COMMANDS:

					BlockWindows();

					CommandPanel(&Config);

					ReleaseWindows();

					break;

		case MEN_MISC:

					BlockWindows();

					MiscPanel(&Config);

					ConfigSetup();

					ReleaseWindows();

					break;

		case MEN_PATH:

					BlockWindows();

					if(PathPanel(&Config))
					{
						DeleteBeep();

						if(Config . BeepSound[0])
						{
							if(!OpenSound(Config . BeepSound))
								MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_SOUND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Config . BeepSound);
						}

						CreateBeep();
					}

					ReleaseWindows();

					break;

			/* Set the file transfer options. */

		case MEN_TRANSFER:

					BlockWindows();

					for(;;)
					{
						XprIO -> xpr_filename = NULL;

						NewLibrary = FALSE;

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

								break;
							}
						}
						else
							xpr_options(0,NULL);

							/* Save the options if necessary. */

						SaveProtocolOpts();

						if(NewLibrary)
						{
							if(!ProtocolSetup())
								SetTransferMenu(FALSE);
							else
								SetTransferMenu(TRUE);

							if(strlen(LastXprLibrary) > 39)
							{
								MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_NAME_TOO_LONG_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

								strcpy(Config . Protocol,FilePart(LastXprLibrary));
							}
							else
								strcpy(Config . Protocol,LastXprLibrary);
						}
						else
							break;
					}

					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())
						{
							if(strlen(LastXprLibrary) > 39)
							{
								MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_NAME_TOO_LONG_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

								strcpy(Config . Protocol,FilePart(LastXprLibrary));
							}
							else
								strcpy(Config . Protocol,LastXprLibrary);
						}
						else
						{
							strcpy(LastXprLibrary,Config . Protocol);

							ProtocolSetup();
						}

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

					ReleaseWindows();

					break;

			/* Set the keyboard macros. */

		case MEN_MACROS:

					BlockWindows();

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

						MacroPanel(MacroKeys);

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

					ReleaseWindows();

					break;

			/* Set the fast macros. */

		case MEN_FAST_MACROS:

					BlockWindows();

					FastMacroPanel();

					ReleaseWindows();

					break;

		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;

		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(ReadIFFData(DummyBuffer,&PrivateConfig,sizeof(struct Configuration),'PREF'))
						{
							swmem(&PrivateConfig,&Config,sizeof(struct Configuration));

							strcpy(DummyBuffer,LastConfig);

							UpdatePrefs(&Config);

							ConfigSetup();
						}
						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),'PREF'))
							MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_ERROR_WRITING_PREFERENCES_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LastConfig);

						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),'PREF'))
							strcpy(LastConfig,DummyBuffer);
						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;
	}
}
