/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1991 by Olaf 'Olsen' Barthel & MXM
 *
 *	Name .....: TermMain.c
 *	Created ..: Monday 21-Jan-91 20:12
 *	Revision .: 0
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	21-Jan-91       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

#include "TermGlobal.h"

	/* Argument vectors offsets. */

enum	{	ARG_KEEPIO,ARG_DONTPOP };

	/* Argument template. */

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

	/* Some global variables for starters. */

STATIC BYTE	Terminated	= FALSE,
		DoIconify	= FALSE;

	/* 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_DONTPOP + 1),MEMF_PUBLIC | MEMF_CLEAR))
		{
			struct RDArgs *ArgsPtr;

			if(ArgsPtr = (struct RDArgs *)AllocVec(sizeof(struct RDArgs),MEMF_PUBLIC|MEMF_CLEAR))
			{
				ArgsPtr -> RDA_ExtHelp = "\nUsage: \33[1mterm\33[0m [KeepIO] [DontPop]\n\n       KeepIO ....: Keep links to the current Shell window.\n       DontPop ...: Don't pop an already running `term' to the front.\n\n";

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

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

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

							CloseLibrary(IntuitionBase);
						}

						FreeArgs(ArgsPtr);
						FreeVec(ArgsPtr);
						FreeVec(ArgArray);

						return(RETURN_OK);
					}

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

					if(ArgArray[ARG_KEEPIO])
					{
							/* Open our resources and
							 * squeak after failure.
							 */

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

							CloseAll();

							FreeArgs(ArgsPtr);
							FreeVec(ArgsPtr);
							FreeVec(ArgArray);

							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);
						FreeVec(ArgsPtr);
						FreeVec(ArgArray);

							/* Mega-glitch: term used to
							 * bolt and lock the door
							 * before the last dos.library
							 * functions were called!
							 */

						CloseAll();

						return(RETURN_OK);
					}

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

					FreeVec(ArgsPtr);
					FreeVec(ArgArray);

					return(RETURN_ERROR);
				}

				FreeVec(ArgsPtr);
			}

			FreeVec(ArgArray);

				/* Clone the current directory of our
				 * process before we detach ourselves
				 * from the starting Shell.
				 */

			CurrentDir(RemoteCurrentDir = CurrentDir(NULL));
			RemoteCurrentDir = DupLock(RemoteCurrentDir);

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

			if(!Res("term Main Process",0,HandleInput,16384,FALSE))
			{
				UnLock(RemoteCurrentDir);

				Printf("\33[1mterm:\33[0m Failed to create new process!\a\n");

				CloseAll();

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

			CloseLibrary(DOSBase);

			return(RETURN_FAIL);
		}
	}
	else
	{
			/* Initialize this, so OpenAll will work with
			 * correct data.
			 */

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

			/* We were called from Workbench. */

		if(Result = OpenAll())
		{
			if(IntuitionBase && Result[0])
				MyEasyRequest(NULL,"`term' has a problem:\n%s!","Continue",Result);

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

			HandleInput();
		}
	}

	return(RETURN_OK);
}

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

VOID
HandleInput()
{
	ULONG SignalSet,SavageSignals;

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

		/* Return to the previous current directory
		 * (so that file requesters and the like
		 * will know where to start).
		 */

	if(RemoteCurrentDir)
	{
		CurrentDir(RemoteCurrentDir);

		/* Oops, some data still remains and needs to
		 * be cleared.
		 */

		ThisProcess -> pr_CIS		= NULL;
		ThisProcess -> pr_COS		= NULL;

		ThisProcess -> pr_ConsoleTask	= NULL;
		ThisProcess -> pr_CLI		= NULL;
	}

		/* Open the resources we need. */

	if(!ThisProcess -> pr_CLI && !WBenchMsg)
	{
		UBYTE *Result;

		if(Result = OpenAll())
		{
			if(IntuitionBase && Result[0])
				MyEasyRequest(NULL,"`term' has a problem:\n%s!","Continue",Result);

			CloseAll();

			return;
		}
	}

	BumpWindow(Window);

		/* Set up the public screen data. */

	PubScreenStuff();

		/* Show our business card. */

	BlockWindows();

	ShowInfo(TRUE);

	ReleaseWindows();

		/* Initialize the modem. */

	SerialCommand(Config . ModemInit);

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

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

	LogAction("Program started (%s %s).",TermName,TermDate);

		/* Go into input loop... */

Loop:	while(!Terminated)
	{
			/* We did a file transfer (auto-download?) and
			 * will need to close the transfer window.
			 */

		if(TransferWindow)
		{
			WakeUp(TransferWindow);

			DeleteTransferPanel();

			ReleaseWindows();

			Say("Transfer completed.");
		}

		SavageSignals = NULL;

			/* The serial line is active. */

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

			/* The packet window is still open. */

		if(PacketWindow)
			SavageSignals |= SIG_PACKET;

			/* Wait for input events to occur. */

		SignalSet = Wait(SIG_WINDOW | SIG_REXX | SIG_AUDIO | SavageSignals);

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

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

			/* Remove audio request. */

		if(SignalSet & SIG_AUDIO)
			WaitIO(AudioBlock);

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

		if(UsesZModem)
		{
			if(FlowInfo . ZModemUpload && XProtocolBase)
			{
					/* The standard ZModem cancel sequence
					 * (ten CAN chars followed by ten
					 * BS chars).
					 */

				STATIC UBYTE ZModemCancel[] =
				{
					24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8
				};

				FlowInit();

				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 . Voice || FlowInfo . Ring)
		{
			if(!Online)
			{
				BumpWindow(Window);

				if(FlowInfo . Voice)
				{
					ConWrites("\r\nIncoming call!\r\n\r\n");

					Say("Incoming call.");
				}
				else
				{
					ConWrites("\r\nIncoming voice call!\r\n\r\n");

					Say("Incoming voice call.");
				}
			}

			FlowInit();
		}

			/* Bring the screen to the front if a `CONNECT'
			 * message arrives.
			 */

		if(FlowInfo . Connect && !Online)
		{
			BumpWindow(Window);

			FlowInit();
		}

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

		if(SignalSet & SIG_REXX)
			HandleRexx();

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

			ConWrites("\r\nThis call will cost you %ld.%02ld.\r\n\r\n",CurrentPay / 100,CurrentPay % 100);

			CurrentPay = 0;
		}

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

		if(TransferWindow)
		{
			WakeUp(TransferWindow);

			DeleteTransferPanel();

			ReleaseWindows();

			Say("Transfer completed.");
		}

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

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

									/* Release the window. */

								Released = TRUE;

								ReleaseWindows();

									/* Remove the display buffer. */

								if(BufferProcess)
									Signal(BufferProcess,SIGBREAKF_CTRL_C);

									/* Reset and release the serial driver. */

								ClearSerial();

								DeleteSerial();

									/* Close the display. full stop. */

								DeleteDisplay();

									/* Wait for double-click. */

IconLoop:							while(!IconTerminated)
								{
									WaitPort(IconPort);

										/* Pick up application messages. */

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

										if(!AppMessage -> am_NumArgs && !AppMessage -> am_ArgList)
											IconTerminated = TRUE;

										ReplyMsg(AppMessage);
									}
								}

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

								if(HadBuffer)
								{
									if(BufferProcess = (struct Process *)CreateNewProcTags(
										NP_Entry,	BufferServer,
										NP_Name,	"term Buffer Process",
										NP_Priority,	0,
										NP_StackSize,	8192,
										NP_WindowPtr,	-1,
									TAG_END))
										Wait(SIGBREAKF_CTRL_C);
								}

									/* Open the serial driver. */

								if(!CreateSerial())
								{
									DeleteSerial();

									switch(MyEasyRequest(NULL,"`term' has a problem:\nFailed to open %s!","Iconify|Ignore|Quit `term'",Config . SerialDevice))
									{
										case 1:		goto IconLoop;
										case 2:		break;
										case 0:		Terminated = TRUE;
									}
								}

									/* Create the display. */

								if(String = CreateDisplay(FALSE))
								{
									if(MyEasyRequest(NULL,"`term' has a problem:\n%s!","Iconify|Quit",String))
									{
										ClearSerial();

										DeleteSerial();

										IconTerminated = FALSE;

										goto IconLoop;
									}
									else
										Terminated = 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,"Failed to add application icon\n(is Workbench running?).","Continue");

							DeleteMsgPort(IconPort);
						}
						else
							MyEasyRequest(Window,"Failed to create MsgPort.","Continue");

						FreeDiskObject(Icon);
					}
					else
						MyEasyRequest(Window,"Failed to open tool icon.","Continue");

					CloseLibrary(IconBase);
				}
				else
					MyEasyRequest(Window,"Failed to open icon.library.","Continue");

				CloseLibrary(WorkbenchBase);
			}
			else
				MyEasyRequest(Window,"Failed to open workbench.library.","Continue");

			if(!Released)
				ReleaseWindows();

				/* Finished! */

			DoIconify = FALSE;
		}

			/* Set up a new emulator? */

		if(NewEmulatorPlease)
		{
			BlockWindows();

			if(!CreateEmulator(Config . EmulationName,TRUE))
			{
				Config . Emulation = EMULATION_ANSIVT100;

				if(Config . Font == FONT_IBM && IBM)
					CurrentFont = IBM;
				else
					CurrentFont = Topaz;

				SetFont(RPort,CurrentFont);
			}
			else
			{
				Config . RasterEnabled = FALSE;

				EraseScreen("2");
			}

			NewEmulatorPlease = FALSE;

			ReleaseWindows();
		}

			/* Encountered any trouble during emulation
			 * setup procedure?
			 */

		if(EmulationSetupError)
		{
			BlockWindows();

			MyEasyRequest(Window,"Could not set up terminal emulation `%s':\n%s.\n\nResetting to built-in terminal emulation.","Continue",FilePart(Config . EmulationName),EmulationErrorStrings[EmulationSetupError - 1]);

			EmulationSetupError = 0;

			ReleaseWindows();
		}

			/* Reset the serial driver? */

		if(ResetSerial)
		{
			ClearSerial();

			DeleteSerial();

			BlockWindows();

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

				DeleteSerial();

				ThisProcess -> pr_WindowPtr = (APTR)Window;

				switch(MyEasyRequest(Window,"`term' has a problem:\nFailed to open %s!","Retry|Ignore|Quit `term'",Config . SerialDevice))
				{
					case 1:		goto OpenLoop;
					case 2:		break;
					case 0:		Terminated = TRUE;
				}

				ThisProcess -> pr_WindowPtr = OldPtr;
			}
			else
				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,"`%s' unit Nš %ld has been reset and released.","Return To `term'|Quit `term'",Config . SerialDevice,Config . UnitNumber))
			{
OpenIt:				if(!CreateSerial())
				{
					DeleteSerial();

					switch(MyEasyRequest(Window,"`term' has a problem:\nFailed to open %s!","Retry|Ignore|Quit `term'",Config . SerialDevice))
					{
						case 1:		goto OpenIt;
						case 2:		break;
						case 0:		Terminated = TRUE;
					}
				}
			}
			else
				Terminated = TRUE;

			ReleaseSerial = FALSE;

			ThisProcess -> pr_WindowPtr = OldPtr;

			ReleaseWindows();
		}

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

		if(ResetDisplay)
		{
			UBYTE *Result;

				/* Delete the display (if possible).
				 * This will go wrong if there
				 * are any visitor windows on our
				 * screen.
				 */

			if(DeleteDisplay())
			{
				if(Result = CreateDisplay(FALSE))
				{
					ThisProcess -> pr_WindowPtr = (APTR)Window;

					MyEasyRequest(NULL,"`term' has a problem:\n%s!","Continue",Result);

					Terminated = TRUE;
				}

				BumpWindow(Window);

				PubScreenStuff();
			}
			else
			{
				CopyMem(&PrivateConfig,&Config,sizeof(struct Configuration));

				BlockWindows();

				MyEasyRequest(Window,"`term' has a problem:\nCannot close screen yet!","Continue");

				ReleaseWindows();
			}

			ResetDisplay = FALSE;
		}

		if(SendStartup && Online)
		{
			if(Config . StartupMacro[0])
				SerialCommand(Config . StartupMacro);

			SendStartup = FALSE;
		}
	}

		/* 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,"`term' has a problem:\nCannot close screen yet!","Continue");

				ReleaseWindows();

				Terminated = FALSE;

				goto Loop;
			}
		}

		UnlockPubScreenList();
	}

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

	SerialCommand(Config . ModemExit);

	ClearSerial();

	LogAction("Program terminated.");

	Say("Bye bye.");

	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;
	struct Gadget		*Gadget;
	UBYTE			 Char,InputBuffer[257];

		/* Any news in the mail? */

	if(Massage = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort))
	{
			/* Perform key conversion. */

		Char = KeyConvert(Massage,InputBuffer);

			/* Pick up the pieces. */

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

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

		GT_ReplyIMsg(Massage);

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

		if(FastWindow)
		{
				/* Close the window. */

			if(Class == IDCMP_CLOSEWINDOW)
				CloseFastWindow();

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

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

					RefreshWindowFrame(FastWindow);
				}
			}

				/* User has selected an item. */

			if(Class == IDCMP_GADGETUP)
			{
				struct MacroNode *Node = GetFastMacro(Code);

				if(Node)
				{
					if(Node -> mn_Code[0])
						SerialCommand(Node -> mn_Code);
				}
			}
		}

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

		if(Class == IDCMP_RAWKEY)
		{
			if(Char)
			{
					/* 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(!IsControl(Char))
				{
					WORD	i;
					UBYTE	c;

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

					for(i = 0 ; i < strlen(InputBuffer) ; 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
								DoSomeBeep();
						}
						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 . Handshaking == HANDSHAKING_XONXOFF)
									Status = STATUS_HOLDING;
							}

								/* 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
					{
							/* The Help-key toggles
							 * the fast! macro panel.
							 */

						if(Char == HLP)
						{
							if(FastWindow)
								CloseFastWindow();
							else
								OpenFastWindow();
						}

						HandleCursor(Char);
					}
				}
			}
		}

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

		if(Class == IDCMP_MOUSEBUTTONS && Code == SELECTDOWN && Config . RasterEnabled)
		{
			BYTE SingleChar,Xerox;

				/* 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(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
				Xerox = TRUE;
			else
				Xerox = FALSE;

			RasterClip(SingleChar,Xerox);

			ReportMouse(FALSE,Window);
		}

			/* A menu item was selected. */

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

		return(TRUE);
	}

	return(FALSE);
}

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

BYTE
HandleSerial()
{
		/* We are XON'ed or the serial line was shut down. */

	if(Status != STATUS_HOLDING && ReadPort && !ReleaseSerial && !Terminated)
	{
			/* Any news? */

		if(CheckIO(ReadRequest))
		{
			LONG Length;

			if(WaitIO(ReadRequest))
				return(FALSE);

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

				if(TransferBits & XPRS_HOSTMON)
					if(!XProtocolHostMon(XprIO,ReadBuffer,1,1))
						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 > SERBUFF_SIZE)
						Length = SERBUFF_SIZE;

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

					DoIO(ReadRequest);

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

						if(TransferBits & XPRS_HOSTMON)
						{
							if(!(Length = XProtocolHostMon(XprIO,ReadBuffer,Length,SERBUFF_SIZE)))
							{
								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;

			SendIO(ReadRequest);

			return(TRUE);
		}
	}

	return(FALSE);
}

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

VOID
HandleMenu(ULONG Code)
{
	STATIC UBYTE		 NumberBuffer[256];

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

	struct List		*DialList;

	LONG			 Size;
	BPTR			 SomeFile;
	APTR			 OldPtr;

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

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

		if(!(MenuItem = ItemAddress(Menu,Code)))
			break;

		OldStatus = Status;

			/* Now call the approriate routine. */

		switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
		{
				/* Say who we are. */

			case MEN_ABOUT:		BlockWindows();

						ShowInfo(FALSE);

						ReleaseWindows();

						break;

			case MEN_ICONIFY:	DoIconify = TRUE;

						break;

				/* Open the preferences settings. */

			case MEN_OPEN:		BlockWindows();

						strcpy(DummyBuffer,LastConfig);

						DummyChar = PathPart(DummyBuffer);

						*DummyChar = 0;

						if(FileRequest = GetFile("Open Preferences",DummyBuffer,FilePart(LastConfig),DummyBuffer,"#?.term",FALSE,FALSE,FALSE,NULL))
						{
							if(ReadIFFData(DummyBuffer,&PrivateConfig,sizeof(struct Configuration),'PREF'))
							{
								swmem(&PrivateConfig,&Config,sizeof(struct Configuration));

								strcpy(DummyBuffer,LastConfig);

								ConfigSetup();
							}
							else
								MyEasyRequest(Window,"Error opening file\n%s!","Continue",DummyBuffer);

							FreeAslRequest(FileRequest);
						}

						ReleaseWindows();

						break;

				/* Save the terminal preferences. */

			case MEN_SAVE:		if(LastConfig[0])
						{
							BlockWindows();

							if(!WriteIFFData(LastConfig,&Config,sizeof(struct Configuration),'PREF'))
								MyEasyRequest(Window,"Error writing preferences to\nfile %s!","Continue",LastConfig);

							ReleaseWindows();
						}

						break;

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

			case MEN_SAVEAS:	BlockWindows();

						strcpy(DummyBuffer,LastConfig);

						DummyChar = PathPart(DummyBuffer);

						*DummyChar = 0;

						if(FileRequest = GetFile("Save Preferences As",DummyBuffer,FilePart(LastConfig),DummyBuffer,"#?.term",TRUE,FALSE,FALSE,NULL))
						{
							if(WriteIFFData(DummyBuffer,&Config,sizeof(struct Configuration),'PREF'))
								strcpy(LastConfig,DummyBuffer);
							else
								MyEasyRequest(Window,"Error writing preferences to\nfile %s!","Continue",DummyBuffer);

							FreeAslRequest(FileRequest);
						}

						ReleaseWindows();

						break;

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

			case MEN_PRINTSCREEN:	BlockWindows();

						if(SomeFile = Open("PRT:",MODE_NEWFILE))
						{
							WORD	 i,j;
							UBYTE	*Buffer;

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

								j = LastColumn;

								if(RasterAttr[i] != SCALE_ATTR_NORMAL)
									j >>= 1;

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

								j++;

								if(!FWrite(SomeFile,Buffer,j,1))
									break;

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

							Close(SomeFile);
						}
						else
							MyEasyRequest(Window,"Failed to open device PRT:!","Continue");

						ReleaseWindows();

						break;

				/* Terminate the program. */

			case MEN_QUIT:		BlockWindows();

						OldPtr = ThisProcess -> pr_WindowPtr;

						ThisProcess -> pr_WindowPtr = (APTR)Window;

						if(MyEasyRequest(Window,"Do you really want to quit `term'?","Yes|No"))
							Terminated = TRUE;

						ThisProcess -> pr_WindowPtr = OldPtr;

						ReleaseWindows();

						break;

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

			case MEN_SETCONSOLE:	BlockWindows();

						if(xpr_gets("Set Console Window",WindowName))
							SetEnvDOS("TERMWINDOW",WindowName);

						ReleaseWindows();

						break;

				/* Execute an AmigaDOS command. */

			case MEN_DOSCOMMAND:	BlockWindows();

						DummyBuffer[0] = 0;

							/* Enter the name of the command. */

						if(GetString("Enter AmigaDOS Command",DummyBuffer))
							SendAmigaDOSCommand(DummyBuffer);

						ReleaseWindows();

						break;

				/* Execute an ARexx script command. */

			case MEN_REXXCOMMAND:	BlockWindows();

						DummyBuffer[0] = 0;

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

						if(GetString("Enter ARexx Command",DummyBuffer))
							SendARexxCommand(DummyBuffer);

						ReleaseWindows();

						break;

				/* Edit a file. */

			case MEN_EDIT:		BlockWindows();

						if(!Config . Editor[0])
							GetString("Enter Name Of Editor To Use",&Config . Editor[0]);

						if(Config . Editor[0])
						{
							if(FileRequest = GetFile("Edit File","","",DummyBuffer,NULL,FALSE,FALSE,FALSE,"Edit"))
							{
								UBYTE CompoundName[512];
								ULONG TagEnd = TAG_END;

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

								System(CompoundName,(APTR)&TagEnd);

								BumpWindow(Window);

								FreeAslRequest(FileRequest);
							}
						}

						ReleaseWindows();
						break;

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

			case MEN_PASTE:		if(Size = LoadClip(SharedBuffer,256))
							SerWrite(SharedBuffer,Size);

						break;

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

			case MEN_PACKET:	if(!PacketWindow)
							CreatePacketWindow();
						else
							ActivateWindow(PacketWindow);

						break;

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

			case MEN_CLEARBUFFER:	if(Lines)
						{
							BlockWindows();

							if(MyEasyRequest(Window,"The buffer still holds %ld lines,\ndo you wish to discard them?","Yes|No",Lines))
								ClearBuffer();

							ReleaseWindows();
						}

						break;

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

			case MEN_DISPLAYBUFFER:	if(BufferProcess)
							Signal(BufferProcess,SIGBREAKF_CTRL_D);
						else
						{
							if(BufferProcess = (struct Process *)CreateNewProcTags(
								NP_Entry,	BufferServer,
								NP_Name,	"term Buffer Process",
								NP_Priority,	0,
								NP_StackSize,	8192,
								NP_WindowPtr,	-1,
							TAG_END))
								Wait(SIGBREAKF_CTRL_C);

							if(!BufferProcess)
							{
								BlockWindows();

								MyEasyRequest(Window,"Unable to create buffer task!","Continue");

								ReleaseWindows();
							}
						}

						break;


			case MEN_CLOSEBUFFER:	if(BufferProcess)
							Signal(BufferProcess,SIGBREAKF_CTRL_C);

						break;

			case MEN_LOADBUFFER:	BlockWindows();

						if(FileRequest = GetFile("Load Buffer","","",DummyBuffer,NULL,FALSE,FALSE,FALSE,"Load"))
						{
							if(GetFileSize(DummyBuffer))
							{
								if(SomeFile = Open(DummyBuffer,MODE_OLDFILE))
								{
									if(Lines)
									{
										switch(MyEasyRequest(Window,"The display buffer still holds %ld\nlines, do you wish to continue?","Discard Buffer|Append Buffer|Cancel",Lines))
										{
											case 1:	ClearBuffer();
												break;

											case 2:	break;

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

									if(SomeFile)
									{
										LineRead(NULL,NULL,NULL);

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

										Close(SomeFile);
									}
								}
							}

							FreeAslRequest(FileRequest);
						}

						ReleaseWindows();
						break;

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

			case MEN_SAVEBUFFER:	BlockWindows();

						if(!Lines)
							MyEasyRequest(Window,"There isn't anything in the\nbuffer right now.","Continue");
						else
						{
							if(FileRequest = GetFile("Save Buffer","","",DummyBuffer,NULL,TRUE,FALSE,FALSE,"Save"))
							{
								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,"File %s already exists!","Create New File|Append Data|Cancel",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,"Error opening file %s!","Continue",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;

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

			case MEN_CAPTUREDISK:	if(FileCapture)
						{
							BufferClose(FileCapture);

							MenuItem -> Flags &= ~CHECKED;

							FileCapture = NULL;

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

							strcpy(DummyBuffer,CaptureName);

							DummyChar = PathPart(DummyBuffer);

							*DummyChar = 0;

							if(FileRequest = GetFile("Capture To Disk",DummyBuffer,FilePart(CaptureName),DummyBuffer,NULL,TRUE,FALSE,FALSE,"Open"))
							{
								if(GetFileSize(DummyBuffer))
								{
									switch(MyEasyRequest(Window,"File %s already exists!","Create New File|Append Data|Cancel",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,"Error opening file %s!","Continue",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_CAPTUREPRINTER:if(PrinterCapture)
						{
							Close(PrinterCapture);

							MenuItem -> Flags &= ~CHECKED;

							PrinterCapture = NULL;
						}
						else
						{
							if(PrinterCapture = Open("PRT:",MODE_NEWFILE))
								MenuItem -> Flags |= CHECKED;
							else
							{
								MenuItem -> Flags &= ~CHECKED;

								BlockWindows();

								MyEasyRequest(Window,"Error opening PRT: device!","Continue");

								ReleaseWindows();
							}
						}

						break;

				/* This follows the upload routines.
				 * Text upload makes the xpr_finfo function
				 * identify any file as being a text
				 * file (no voodoo magic yet).
				 */

			case MEN_UPLOADTEXT:	BinaryTransfer = FALSE;

				/* The rest of the upload routines. */

			case MEN_UPLOAD:	BlockWindows();

						StartXprSend(BinaryTransfer ? TRANSFER_BINARY : TRANSFER_TEXT);

						BinaryTransfer = TRUE;

						ReleaseWindows();

						break;

			case MEN_DOWNLOADTEXT:	BinaryTransfer = FALSE;

				/* Download some files. */

			case MEN_DOWNLOAD:	BlockWindows();

						StartXprReceive(BinaryTransfer ? TRANSFER_BINARY : TRANSFER_TEXT);

						BinaryTransfer = TRUE;

						ReleaseWindows();

						break;

				/* Set the file transfer options. */

			case MEN_XFERPROTOCOL:	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,"Failed to set up protocol\n\"%s\"!","Continue",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())
									break;

								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_SELECTXFER:	BlockWindows();

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

								ProtocolSetup();
							}
						}

						ReleaseWindows();

						break;

				/* These routines simply switch the
				 * transfer library (to xprascii.library)
				 * and perform up/download. To lessen the
				 * confusion both routines have been
				 * implemented as single routines.
				 * After the transfer the control is
				 * returned to the previously selected
				 * transfer library.
				 */

			case MEN_SEND:		BlockWindows();

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

							ASCIIShutdown();
						}

						ReleaseWindows();

						break;

			case MEN_RECEIVE:	BlockWindows();

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

							ASCIIShutdown();
						}

						ReleaseWindows();

						break;

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

			case MEN_PHONEBOOK:	BlockWindows();

						if(PhonePanel())
						{
							DialPanel();

							Status = OldStatus;
						}

						ReleaseWindows();

						break;

				/* Dial a single number. */

			case MEN_DIAL:		BlockWindows();

						if(xpr_gets("Enter Phone Number",NumberBuffer))
						{
							if(DialList = (struct List *)AllocVec(sizeof(struct List),MEMF_PUBLIC | MEMF_CLEAR))
							{
								struct PhoneNode *DialNode;

								NewList(DialList);

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

									AddTail(DialList,&DialNode -> VanillaNode);

									FreeSubList();

									SubList		= DialList;
									SubListNum	= 1;

									DialPanel();

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

						ReleaseWindows();

						break;

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

			case MEN_REDIAL:	BlockWindows();

						if(SubList)
						{
							DialPanel();

							Status = OldStatus;
						}
						else
							MyEasyRequest(Window,"Current dialing list is empty.","Continue");

						ReleaseWindows();

						break;

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

			case MEN_PLAY:		BlockWindows();

						if(xpr_gets("Enter Phone Number To Play",NumberBuffer))
						{
							if(!ToneDial(NumberBuffer))
								MyEasyRequest(NULL,"`term' has a problem:\n%s!","Continue","Failed to allocate resources for playing.");
							else
								DeleteTone();
						}

						ReleaseWindows();
						break;

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

			case MEN_SENDBREAK:	if(WriteRequest)
						{
							Status = STATUS_BREAKING;

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

							Status = OldStatus;
						}

						break;

				/* Hang up the phone line. */

			case MEN_HANGUP:	Status = STATUS_HANGUP;

						SerialCommand(Config . ModemHangup);

						Status = OldStatus;

						Online = FALSE;

						Password[0] = 0;

						LogAction("Hang up line.");

						break;

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

			case MEN_RELEASE:	ReleaseSerial = TRUE;
						break;

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

			case MEN_RESETSTYLES:	if(Console && Config . Emulation == EMULATION_EXTERNAL)
							Console -> reset_style((APTR)Console);
						else
						{
							Escape = TRUE;

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

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

							Escape = FALSE;
						}

						break;

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

			case MEN_CLEARSCREEN:	if(Console && Config . Emulation == EMULATION_EXTERNAL)
							Console -> clear_term((APTR)Console);
						else
						{
							Escape = TRUE;

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

							Escape = FALSE;
						}

						break;

				/* Reset the whole terminal. */

			case MEN_RESETTERMINAL:	if(Console && Config . Emulation == EMULATION_EXTERNAL)
							Console -> reset_term((APTR)Console);
						else
						{
							Escape = TRUE;

							ConProcess("\033c",2);

							Escape = FALSE;
						}

						break;

				/* Save screen as IFF-ILBM file. */

			case MEN_SAVEILBM:	BlockWindows();

						if(FileRequest = GetFile("Save Screen (IFF-ILBM)","","",DummyBuffer,NULL,TRUE,FALSE,FALSE,"Save"))
						{
							if(!SaveRPort(&Screen -> RastPort,VPort,0,Window -> TopEdge,Window -> Width,Window -> Height,Screen -> Width,Screen -> Height,FALSE,DummyBuffer))
								MyEasyRequest(Window,"Failed to save screen to\nfile %s!","Continue",DummyBuffer);

							FreeAslRequest(FileRequest);
						}

						ReleaseWindows();

						break;

				/* Save screen as ASCII file. */

			case MEN_SAVEASCII:	BlockWindows();

						if(FileRequest = GetFile("Save Screen (ASCII)","","",DummyBuffer,NULL,TRUE,FALSE,FALSE,"Save"))
						{
							if(GetFileSize(DummyBuffer))
							{
								switch(MyEasyRequest(Window,"File %s already exists!","Create New File|Append Data|Cancel",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,"Failed to save screen to\nfile %s!","Continue",DummyBuffer);
							else
							{
								if(SomeFile != ~0)
								{
									WORD	 i,j;
									UBYTE	*Buffer;

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

										j = LastColumn;

										if(RasterAttr[i] != SCALE_ATTR_NORMAL)
											j >>= 1;

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

										j++;

										if(!FWrite(SomeFile,Buffer,j,1))
											break;

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

									Close(SomeFile);

									SetProtection(DummyBuffer,FIBF_EXECUTE);
								}
							}

							FreeAslRequest(FileRequest);
						}

						ReleaseWindows();

						break;

				/* Set the serial preferences. */

			case MEN_SERIAL:	BlockWindows();

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

							DeleteSerial();

							if(!CreateSerial())
							{
								OldPtr = ThisProcess -> pr_WindowPtr;

								DeleteSerial();

								ThisProcess -> pr_WindowPtr = (APTR)Window;

								if(!MyEasyRequest(Window,"`term' has a problem:\nFailed to open %s!","Continue|Quit `term'",Config . SerialDevice))
								{
									ThisProcess -> pr_WindowPtr = OldPtr;

									Terminated = TRUE;

									break;
								}

								ThisProcess -> pr_WindowPtr = OldPtr;
							}
						}

						ReleaseWindows();

						break;

				/* Set the modem preferences. */

			case MEN_MODEM:		BlockWindows();

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

						ReleaseWindows();

						break;

				/* Set the fast macros. */

			case MEN_FASTMACROS:	BlockWindows();

						FastMacroPanel();

						ReleaseWindows();

						break;

				/* Set the keyboard macros. */

			case MEN_MACROS:	BlockWindows();

						MacroPanel(MacroKeys);

						ReleaseWindows();

						break;

				/* Set the screen preferences. */

			case MEN_SCREEN:	BlockWindows();

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

						ReleaseWindows();

						break;

				/* Set the terminal preferences. */

			case MEN_TERMINAL:	BlockWindows();

						TerminalPanel(&Config);

						ConfigSetup();

						ReleaseWindows();

						break;

			case MEN_STARTUP:	BlockWindows();

						GetString("Enter Startup Macro",&Config . StartupMacro[0]);

						ReleaseWindows();

						break;

			case MEN_EMULATION:	BlockWindows();

						if(Console && Config . Emulation == EMULATION_EXTERNAL)
						{
							OptionTitle = "Emulation Preferences";

							Console -> parameters((APTR)Console);

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

						ReleaseWindows();

						break;

			case MEN_PATH:		BlockWindows();

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

							if(!OpenSound(Config . BeepSound))
								MyEasyRequest(Window,"Failed to open sound \"%s\"!","Continue",Config . BeepSound);

							CreateBeep();
						}

						ReleaseWindows();

						break;

			case MEN_HOTKEYS:	BlockWindows();

						if(HotkeyPanel(&Hotkeys))
						{
							if(!SetupCx())
								MyEasyRequest(Window,"Failed to set up hotkeys (spelling mistake?).","Continue");
						}

						ReleaseWindows();

						break;

			case MEN_SPEECH:	BlockWindows();

						SpeechPanel();

						ReleaseWindows();

						break;

				/* Ignore the rest. */

			default:		break;
		}

		Code = MenuItem -> NextSelect;
	}
}
