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

#include "termGlobal.h"

	/* Argument vectors offsets. */

enum	{	ARG_WINDOW,ARG_PUBSCREEN,ARG_STARTUP,ARG_PORTNAME,ARG_SETTINGS,ARG_UNIT,ARG_DEVICE,
		ARG_NEW,ARG_SYNC,ARG_QUIET,ARG_BEHIND,ARG_DEBUG,

		ARG_COUNT
	};

	/* Argument template. */

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

	/* Local config path variable. */

STATIC STRPTR		ConfigPath;
STATIC UBYTE __far	ThePath[MAX_FILENAME_LENGTH];

	/* Local dialing list. */

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

	/* Startup file name. */

STATIC UBYTE __far	StartupFile[MAX_FILENAME_LENGTH];

	/* Did we hang up the line? */

STATIC BOOLEAN		HungUp = FALSE;

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

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

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

LONG
main()
{
	STRPTR Result;

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

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

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

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

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

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

		return(RETURN_FAIL);
	}

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

		return(RETURN_FAIL);
	}

		/* We were called from Shell. */

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

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

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

			if(ArgsPtr = (struct RDArgs *)AllocDosObject(DOS_RDARGS,TAG_DONE))
			{
				ArgsPtr -> RDA_ExtHelp =	"\nUsage: term [WINDOW <Name>] [PUBSCREEN <Name>] [STARTUP <File name>]\n"
								"            [SETTINGS <File or path name>] [UNIT <Number>] [DEVICE <Name>]\n"
								"            [NEW] [SYNC] [QUIET] [BEHIND]\n\n"
								"     Window = Output window specifier\n"
								"  PubScreen = Name of public screen to open window upon\n"
								"    Startup = ARexx script file to run on startup\n"
								"   Settings = Main configuration file name or path name to search for it\n"
								"       Unit = Serial device driver unit number\n"
								"     Device = Serial device driver name\n"
								"        New = Spawn a new `term' process\n"
								"       Sync = Keep links to Shell environment\n"
								"      Quiet = Start iconified\n"
								"     Behind = Open screen behind all other screens, don't activate the window\n\n";

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

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

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

						TermPort = NULL;

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

						CloseLibs();

						return(RETURN_OK);
					}

					if(ArgArray[ARG_DEBUG])
						DebugFlag = TRUE;

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

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

						strcpy(ThePath,ArgArray[ARG_SETTINGS]);
					}

						/* Are we to use a special ARexx host port name? */

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

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

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

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

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

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

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

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

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

						UseNewDevice = TRUE;
					}

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

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

						UseNewUnit = TRUE;
					}

						/* Are we to start up iconified? */

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

						/* Hide the screen and don't activate the window? */

					if(ArgArray[ARG_BEHIND])
						KeepQuiet = TRUE;

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

					if(ArgArray[ARG_SYNC] || !ThisProcess -> pr_HomeDir)
					{
						BYTE OldPri = ThisProcess -> pr_Task . tc_Node . ln_Pri;

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

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

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

							CloseLibs();

							return(RETURN_FAIL);
						}

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

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

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

							CloseAll(TRUE);

							return(RETURN_FAIL);
						}

							/* Go into main input
							 * loop.
							 */

						HandleInput();

							/* Free the argument
							 * data.
							 */

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

							/* Restore old priority. */

						SetTaskPri(ThisProcess,(LONG)OldPri);

							/* Terminate execution. */

						CloseAll(TRUE);

						return(RETURN_OK);
					}

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

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

					CloseLibs();

					return(RETURN_ERROR);
				}

				FreeDosObject(DOS_RDARGS,ArgsPtr);
			}

			FreeVec(ArgArray);

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

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

				CloseLibs();

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

			CloseLibs();

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

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

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

			CloseLibs();

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

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

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

					/* Try to read the icon file. */

				if(Icon = GetProgramIcon())
				{
					STRPTR Type;

					if(FindToolType(Icon -> do_ToolTypes,"DEBUG"))
						DebugFlag = TRUE;

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

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

						strcpy(ThePath,ConfigPath);

						ConfigPath = ThePath;
					}

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

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

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

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

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

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

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

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

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

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

							UseNewDevice = TRUE;
						}
					}

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

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

							UseNewUnit = TRUE;
						}
					}

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

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

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

					if(FindToolType(Icon -> do_ToolTypes,"BEHIND"))
						KeepQuiet = TRUE;

						/* Free the icon. */

					FreeDiskObject(Icon);
				}

				CloseLibrary(IconBase);

				IconBase = NULL;
			}

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

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

				/* We were called from Workbench. */

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

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

	return(RETURN_OK);
}

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

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

		UtilityBase = NULL;
	}

	if(WBenchMsg)
		CurrentDir(WBenchLock);

	if(DOSBase)
	{
		CloseLibrary(DOSBase);

		DOSBase = NULL;
	}

#ifdef BETA
	StopBetaTask();
#endif	/* BETA */

	if(WBenchMsg)
	{
		Forbid();

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

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

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

	Forbid();

	UnLoadSeg(SegList);

	CloseLibrary(DOSBase);

	DOSBase = NULL;
}

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

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

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

	Forbid();

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

	if(Child)
		CLI -> cli_Module = NULL;

	Permit();

	return(Child);
}

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

VOID __saveds
HandleInput()
{
	STRPTR	Error;
	BOOLEAN	AlmostFinished = FALSE;

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

		/* Open the resources we need. */

	if(!IntuitionBase)
	{
		STRPTR Result;

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

			if(WBenchMsg)
				CloseAll(TRUE);

			return;
		}
	}

		/* Start the online timer if a carrier is present? */

	if(Config -> SerialConfig -> CheckCarrier)
	{
			/* Is the carrier signal present? */

		if(!(GetSerialStatus() & CIAF_COMCD))
		{
				/* Go into online state. */

			ObtainSemaphore(&OnlineSemaphore);

			WasOnline		= FALSE;
			Online			= TRUE;

			ReleaseSemaphore(&OnlineSemaphore);

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

			CurrentPay		= 0;

			ObtainSemaphore(&PatternSemaphore);

			ChosenEntry		= NULL;
			ChosenPattern		= NULL;

			ReleaseSemaphore(&PatternSemaphore);

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

			SendStartup		= FALSE;

			LimitCount		= -1;

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

			SetDialMenu(FALSE);
		}
	}

		/* Start up iconified? */

	if(DoIconify)
	{
		HandleIconify();

		DoIconify = FALSE;

		if(MainTerminated)
			goto Stop;
	}

#ifndef BETA
	if(!KeepQuiet)
		BumpWindow(Window);
#endif	/* BETA */

		/* Set up the public screen data. */

	PubScreenStuff();

		/* Change program priority. */

	SetTaskPri(ThisProcess,(LONG)Config -> MiscConfig -> Priority);

	BlockWindows();

		/* Load the phone book. */

	LoadPhonebook(LastPhone);

		/* Build new menu strip. */

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

		CloseAll(TRUE);

		return;
	}

#ifdef BETA
	StopBetaTask();

	if(!KeepQuiet)
		BumpWindow(Window);
#endif	/* BETA */

		/* Show our business card. */

	if(!StartupFile[0] && !Config -> CommandConfig -> StartupMacro[0] && !KeepQuiet)
	{
		if(ShowAbout(TRUE))
			while(HandleRexx());
	}

	ReleaseWindows();

		/* Don't do anything silly. */

	KeepQuiet = FALSE;

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

		/* Initialize the modem. */

	SerialCommand(Config -> ModemConfig -> ModemInit);

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

	if(Config -> CommandConfig -> StartupMacro[0])
		SerialCommand(Config -> CommandConfig -> StartupMacro);

		/* Go into input loop... */

Loop:	while(!MainTerminated)
	{
		if(Recording)
		{
			if(RecordingLine)
				Status = STATUS_RECORDING_LINE;
			else
				Status = STATUS_RECORDING;
		}

			/* Handle the signal responses. */

		HandleResponse();

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

				MainTerminated = TRUE;

				break;
			}

			RebuildMenu = FALSE;
		}

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

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

			SendARexxCommand(StartupFile);

			ReleaseWindows();

			StartupFile[0] = 0;
		}

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

		if(MainTerminated)
			break;

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

		if(FlowInfo . Changed)
			HandleFlowChange();

			/* Are we no longer online? */

		if(!Online)
		{
			if(WasOnline)
			{
				HandleOnlineCleanup(HungUp);

				WasOnline = FALSE;

				HungUp = FALSE;
			}
		}

			/* Now for public screen mode changes. */

		if(FixPubScreenMode)
			PubScreenStuff();

			/* Now for window size changes. */

		if(FixScreenSize)
			ScreenSizeStuff();

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

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

			/* Let's see if we still have to display the
			 * online cost.
			 */

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

			SoftReset();

				/* Display how much we expect
				 * the user will have to pay for
				 * this call.
				 */

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

			CurrentPay = 0;
		}

			/* Iconify the program? */

		if(DoIconify)
		{
			HandleIconify();

			if(MainTerminated)
				break;
		}

			/* Reset the serial driver? */

		if(ResetSerial)
		{
			HandleSerialReset();

			if(MainTerminated)
				break;
		}

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

		if(ReleaseSerial)
		{
			HandleSerialRelease();

			if(MainTerminated)
				break;
		}

			/* Invoke the dialing function? */

		if(DoDial != DIAL_IGNORE)
		{
			if(Online)
			{
				FreeDialList(FALSE);

				DoDial = DIAL_IGNORE;

				Forbid();

				if(DialMsg)
				{
					DialMsg -> rm_Result1 = RC_WARN;
					DialMsg -> rm_Result2 = 0;

					ReplyMsg(DialMsg);

					DialMsg = NULL;
				}

				Permit();
			}
			else
			{
				if(DoDial == DIAL_LIST)
				{
					BYTE OldStatus = Status;

					DoDial = DIAL_IGNORE;

					BlockWindows();

					DialPanel();

					FreeDialList(FALSE);

					Status = OldStatus;

					SetRedialMenu();

					ReleaseWindows();
				}
				else
				{
					DoDial = DIAL_IGNORE;

					HandleMenuCode(MEN_REDIAL,NULL);
				}
			}
		}

			/* Can we quit now? */

		if(AlmostFinished && !CantQuit)
			break;
	}

		/* Don't exit until all background processes
		 * have terminated.
		 */

	if(MainTerminated && CantQuit)
	{
		MainTerminated = FALSE;
		AlmostFinished = TRUE;

		goto Loop;
	}

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

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

			/* Lock the list of public screens. */

		PubScreenList = LockPubScreenList();

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

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

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

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

				UnlockPubScreenList();

				BlockWindows();

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

				ReleaseWindows();

				AlmostFinished = MainTerminated = FALSE;

				goto Loop;
			}
		}

		UnlockPubScreenList();
	}

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

	SerialCommand(Config -> ModemConfig -> ModemExit);

	ClearSerial();

	LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_PROGRAM_TERMINATED_TXT));

	Say(LocaleString(MSG_TERMMAIN_BYE_BYE_TXT));

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

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

	/* SendInputTextBuffer(STRPTR Buffer,LONG Len,BOOL Bell):
	 *
	 *	Transmit text the user typed or pasted via the
	 *	clipboard.
	 */

STATIC VOID __regargs
SendInputTextBuffer(STRPTR Buffer,LONG Len,BOOL Bell)
{
	UBYTE Mask,c;

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

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

				if(Status == STATUS_HOLDING)
				{
					if(Bell)
						BellSignal();
				}
				else
				{
					switch(Config -> TerminalConfig -> SendLF)
					{
						case EOL_LF:

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

						case EOL_CR:

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

						case EOL_LFCR:

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

						case EOL_CRLF:

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

				break;

			case CHAR_RETURN:

				if(Status == STATUS_HOLDING)
				{
					if(Bell)
						BellSignal();
				}
				else
				{
					switch(Config -> TerminalConfig -> SendCR)
					{
						case EOL_LF:

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

						case EOL_CR:

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

						case EOL_LFCR:

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

						case EOL_CRLF:

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

				break;

				/* Stop in/output. */

			case CHAR_XON:

				if(Status == STATUS_HOLDING)
				{
					if(Bell)
						BellSignal();
				}
				else
				{
					if(Config -> SerialConfig -> xONxOFF)
						Status = STATUS_HOLDING;

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

				break;

				/* Restart in/output. */

			case CHAR_XOFF:

				if(Status == STATUS_HOLDING)
					Status = STATUS_READY;

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

				break;

				/* Any other character. */

			case CHAR_VANILLA:

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

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

				break;
		}
	}
}

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

BYTE
HandleWindow()
{
	STATIC ULONG		 LastSeconds,LastMicros;

	struct IntuiMessage	*Message;
	ULONG			 IClass,Code,Qualifier,Seconds,Micros;
	LONG			 MouseX,MouseY,Len,GadgetID;
	struct Gadget		*Gadget;
	UBYTE			 Char,InputBuffer[257];
	struct Window		*IDCMPWindow;
	BOOLEAN			 Result = FALSE,ClickAndActivate = FALSE;

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

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

		if(Len < 0)
		{
			CloseClip();

			ClipInput = FALSE;

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

				ClipXerox = FALSE;
			}

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

				ClipPrefix = TRUE;
			}

			if(Len > 0)
				SendInputTextBuffer(InputBuffer,Len,FALSE);

			Result = TRUE;
		}
	}

		/* Any news in the mail? */

	if(Message = (struct IntuiMessage *)GetMsg(Window -> UserPort))
	{
			/* A click into the window should activate it, but
			 * we don't want to have the character snapping activated
			 * under these conditions. In this case we rely upon
			 * Intuition sending the IDCMP_ACTIVEWINDOW and
			 * IDCMP_MOUSEBUTTONS event marked with the same
			 * creation time stamp. Even if the Intuition
			 * implementation should change no harm should
			 * be done.
			 */

		Seconds	= Message -> Seconds;
		Micros	= Message -> Micros;

		if(Seconds == LastSeconds && Micros == LastMicros && Message -> IDCMPWindow == Window)
		{
			if(Message -> Class == IDCMP_ACTIVEWINDOW || Message -> Class == IDCMP_MOUSEBUTTONS)
				ClickAndActivate = TRUE;
		}

		LastSeconds	= Seconds;
		LastMicros	= Micros;

			/* Pick up the pieces. */

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

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

		IDCMPWindow	= Message -> IDCMPWindow;

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

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

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

		ReplyMsg(Message);
	}
	else
		IClass = NULL;

		/* Did we get any information? */

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

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

				case IDCMP_CLOSEWINDOW:

					CloseFastWindow();

					return(TRUE);

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

				case IDCMP_NEWSIZE:

					RefreshFastWindow(FALSE);

					return(TRUE);

					/* Some gadget was invoked. */

				case IDCMP_GADGETUP:
				case IDCMP_GADGETDOWN:

					GadgetID = Gadget -> GadgetID;

				case IDCMP_MOUSEMOVE:
				case IDCMP_IDCMPUPDATE:

					HandleFastWindowGadget(IClass,Code,GadgetID);

					return(TRUE);
			}
		}

			/* Status window activated? */

		if(IDCMPWindow == StatusWindow)
		{
			if(IClass == IDCMP_ACTIVEWINDOW && !Config -> ScreenConfig -> SplitStatus)
				NormalCursor();

			if(IClass == IDCMP_CLOSEWINDOW)
			{
				Forbid();

				ClrSignal(SIG_HANDSHAKE);

				Signal(StatusProcess,SIG_CLOSEWINDOW);

				Wait(SIG_HANDSHAKE);

				Permit();

				ClearMenuStrip(StatusWindow);
				CloseWindowSafely(StatusWindow);

				StatusWindow = NULL;
			}
		}

			/* Main window message? */

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

					HoldClick = FALSE;

					GhostCursor();

					break;

				case IDCMP_ACTIVEWINDOW:

					NormalCursor();

					break;

				case IDCMP_NEWSIZE:

						/* Is a window clipping region installed? */

					if(ClipRegion)
					{
						struct Rectangle RegionRectangle;

							/* Install old region. */

						InstallClipRegion(Window -> WLayer,OldRegion);

							/* Fill in the clipping rectangle. */

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

							/* Clear previous clipping region. */

						ClearRegion(ClipRegion);

							/* Set new clipping region. */

						OrRectRegion(ClipRegion,&RegionRectangle);

							/* Install new clipping region. */

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

					HandleMenuCode(MEN_RESET_TERMINAL,Qualifier);
					break;

				case IDCMP_CLOSEWINDOW:

					HandleMenuCode(MEN_QUIT,Qualifier);
					break;

				case IDCMP_MOUSEMOVE:

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

							if(MouseX < 0)
								MouseX = 0;

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

							MouseY -= WindowTop;

							if(MouseY < 0)
								MouseY = 0;

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

							MoveMarker(MouseX,MouseY);
						}
					}

					break;

				case IDCMP_MOUSEBUTTONS:

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

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

							if(MouseX < 0)
								MouseX = 0;

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

							MouseY -= WindowTop;

							if(MouseY < 0)
								MouseY = 0;

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

							HoldClick = TRUE;

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

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

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

									ObtainSemaphore(RasterSemaphore);

									Char = Raster[FirstY * RasterWidth + FirstX];

									ReleaseSemaphore(RasterSemaphore);

									if(Char)
									{
										SerWrite(&Char,1);

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

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

												case EOL_CR:

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

												case EOL_LFCR:

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

												case EOL_CRLF:

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

								return(TRUE);
							}

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

								ObtainSemaphore(&TerminalSemaphore);

								DeltaX = MouseX / TextFontWidth  - CursorX;
								DeltaY = MouseY / TextFontHeight - CursorY;

								ReleaseSemaphore(&TerminalSemaphore);

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

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

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

									if(DeltaY > 0)
									{
										DeltaY++;

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

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

								return(TRUE);
							}

							ReportMouse(TRUE,Window);

							if(!FirstClick)
							{
								ULONG CurrentSecs,CurrentMicros;

								CurrentTime(&CurrentSecs,&CurrentMicros);

								FirstClick = TRUE;

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

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

									FirstClick	= FALSE;

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

								FirstClick	= FALSE;

								ClickX		= MouseX;
								ClickY		= MouseY;
							}

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

									CurrentTime(&ClickSecs,&ClickMicros);

									FirstClick	= FALSE;

									ClickX		= MouseX;
									ClickY		= MouseY;

									ReportMouse(TRUE,Window);
								}
							}
						}
					}

					break;
			}
		}

			/* Now for general information. */

		switch(IClass)
		{
			case IDCMP_RAWKEY:

					/* Take care of the numeric keypad. */

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

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

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

					STATIC struct { UBYTE Code; STRPTR String; } CodeTable[18] =
					{
						0x0F,	"\033Op",	// "0"
						0x1D,	"\033Oq",	// "1"
						0x1E,	"\033Or",	// "2"
						0x1F,	"\033Os",	// "3"
						0x2D,	"\033Ot",	// "4"
						0x2E,	"\033Ou",	// "5"
						0x2F,	"\033Ov",	// "6"
						0x3D,	"\033Ow",	// "7"
						0x3E,	"\033Ox",	// "8"
						0x3F,	"\033Oy",	// "9"
						0x4A,	"\033Om",	// "-"
						0x5E,	"\033Ol",	// "+", but this should really be a comma
						0x3C,	"\033On",	// "."

						0x5A,	"\033OP",	// "["
						0x5B,	"\033OQ",	// "]"
						0x5C,	"\033OR",	// "/"
						0x5D,	"\033OS",	// "*"

						0x43,	"\033OM"	// <cr>
					};

					STRPTR	String = NULL;
					WORD	i;

					for(i = 0 ; i < 22 ; i++)
					{
						if(Char == StringTable[i][0][0])
						{
							String = StringTable[i][1];

							break;
						}
					}

					if(!String)
					{
						for(i = 0 ; i < 18 ; i++)
						{
							if(Code == CodeTable[i] . Code)
							{
								String = CodeTable[i] . String;

								break;
							}
						}
					}

					if(String)
					{
						if(ClipInput)
						{
							CloseClip();

							ClipInput = ClipXerox = ClipPrefix = FALSE;
						}

						SerWrite(String,strlen(String));

						Len = 0;
					}
				}

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

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

							GuideDisplay(CONTEXT_MAIN);

							Len = 0;

							break;

						case CHAR_CURSOR:

							if(ClipInput)
							{
								CloseClip();

								ClipInput = ClipXerox = ClipPrefix = FALSE;
							}

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

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

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

									/* Find the approriate qualifier. */

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

									/* Send the corresponding string. */

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

							Len = 0;

							break;

							/* Any function key pressed? */

						case CHAR_FUNCTION:

							if(ClipInput)
							{
								CloseClip();

								ClipInput = ClipXerox = ClipPrefix = FALSE;
							}

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

							Len = 0;

							break;

							/* Anything else? */

						default:

							if(Len == 1 && Char == '\r' && Recording && !RecordingLine && (Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
							{
								RememberInputText("\r",1);

								Len = 0;

								RecordingLine = TRUE;

								RememberResetInput();

								RememberOutput = FALSE;
								RememberInput = TRUE;

								CheckItem(MEN_RECORD_LINE,TRUE);
							}

							break;
					}

						/* Any characters to send? */

					if(Len)
						SendInputTextBuffer(InputBuffer,Len,TRUE);
				}

				break;

				/* A menu item was selected. */

			case IDCMP_MENUPICK:

				HandleMenu(Code,Qualifier);
				break;

				/* Menu help is required. */

			case IDCMP_MENUHELP:

				if(MENUNUM(Code) == NOMENU || MENUNUM(Code) > 9 || ITEMNUM(Code) == NOITEM)
					GuideDisplay(CONTEXT_MAIN_MENU);
				else
					GuideDisplay(CONTEXT_PROJECT_MEN + MENUNUM(Code));

				break;
		}

		return(TRUE);
	}

	return(Result);
}

	/* HandleLocalDialList(BYTE ClearIt):
	 *
	 *	Invoke the local dialing list or clear it.
	 */

STATIC VOID __regargs
HandleLocalDialList(BYTE ClearIt)
{
	if(Menu)
	{
		struct MenuItem *DialItem;

		if(DialItem = FindThisItem(Menu,FirstDialMenu))
		{
			if(Window)
				ClearMenuStrip(Window);

			if(StatusWindow)
				ClearMenuStrip(StatusWindow);

			if(FastWindow)
				ClearMenuStrip(FastWindow);

			do
				DialItem -> Flags &= ~CHECKED;
			while(DialItem = DialItem -> NextItem);

			if(Window)
				ResetMenuStrip(Window,Menu);

			if(StatusWindow)
				ResetMenuStrip(StatusWindow,Menu);

			if(FastWindow)
				ResetMenuStrip(FastWindow,Menu);
		}
	}

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

			DialList = LocalDialList;

			LocalDialList = NULL;

			LocalCount = -1;

			SetRedialMenu();

			HandleMenuCode(MEN_REDIAL,NULL);
		}
		else
		{
			FreeList(LocalDialList);

			FreeVecPooled(LocalDialList);

			LocalDialList = NULL;

			LocalCount = -1;
		}
	}
}

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

VOID __regargs
HandleMenuCode(ULONG Code,ULONG Qualifier)
{
	struct FileRequester	*FileRequest;
	UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH],
				*DummyChar;
	BYTE			 OldStatus = Status;

	BPTR			 SomeFile;
	APTR			 OldPtr;

	struct MenuItem		*Item;

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

		case MEN_SAVE_AS_PICTURE:

			BlockWindows();

			if(FileRequest = GetFile(Window,LocaleString(MSG_TERMMAIN_SAVE_SCREEN_IFF_TXT),"","",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT),TRUE))
			{
				if(!SaveWindow(DummyBuffer,Window))
					ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);

				FreeAslRequest(FileRequest);
			}

			ReleaseWindows();

			break;

			/* Save screen as ASCII file. */

		case MEN_SAVE_AS_TEXT:

			BlockWindows();

			if(FileRequest = GetFile(Window,LocaleString(MSG_TERMMAIN_SAVE_SCREEN_ASCII_TXT),"","",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT),FALSE))
			{
				LONG Error = 0;

				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)
				{
					if(SomeFile != ~0)
					{
						LONG	 i,j;
						UBYTE	*Buffer;

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

							j = LastColumn;

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

							if(j >= 0)
							{
								SetIoErr(0);

								if(FWrite(SomeFile,Buffer,j + 1,1) < 1)
								{
									Error = IoErr();

									break;
								}
							}

							SetIoErr(0);

							if(FWrite(SomeFile,"\n",1,1) < 1)
							{
								Error = IoErr();

								break;
							}
						}

						Close(SomeFile);

						AddProtection(DummyBuffer,FIBF_EXECUTE);

						if(Config -> MiscConfig -> CreateIcons)
							AddIcon(DummyBuffer,FILETYPE_TEXT,TRUE);
					}
				}
				else
					Error = IoErr();

				if(Error)
					ShowError(Window,ERR_SAVE_ERROR,Error,DummyBuffer);

				FreeAslRequest(FileRequest);
			}

			ReleaseWindows();

			break;

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

		case MEN_PRINT_SCREEN:

			BlockWindows();

			if(RasterEnabled)
				PrintSomething(PRINT_SCREEN);
			else
				MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_NO_DATA_TO_PRINT_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

			ReleaseWindows();

			break;

			/* Print the screen (graphics). */

		case MEN_PRINT_SCREEN_AS_GFX:

			BlockWindows();

			PrintScreenGfx();

			ReleaseWindows();

			break;

			/* Print the clipboard contents. */

		case MEN_PRINT_CLIP:

			BlockWindows();

			PrintSomething(PRINT_CLIP);

			ReleaseWindows();

			break;

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

		case MEN_CAPTURE_TO_FILE:

			if(FileCapture)
				CloseFileCapture();
			else
				OpenFileCapture();

			CheckItem(MEN_CAPTURE_TO_FILE,FileCapture != NULL);

			break;

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

		case MEN_CAPTURE_TO_PRINTER:

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

			CheckItem(MEN_CAPTURE_TO_PRINTER,PrinterCapture != NULL);

			break;

			/* Iconify the program. */

		case MEN_ICONIFY:

			if(Online && Config -> MiscConfig -> ReleaseDevice && !(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
			{
				if(!MyEasyRequest(Window,LocaleString(MSG_TERMMAIN_YOU_ARE_STILL_ONLINE_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
					break;
			}

			DoIconify = TRUE;

			break;

			/* Say who we are. */

		case MEN_ABOUT:

			BlockWindows();
#ifdef DATAFEED
			if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
			{
				STATIC UBYTE LastFile[40],LastPath[256];

				extern BPTR DataFeed;

				if(DataFeed)
				{
					Close(DataFeed);

					DataFeed = NULL;
				}

				if(FileRequest = GetFile(Window,"Select terminal test file",LastPath,LastFile,DummyBuffer,NULL,FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SELECT_TXT),FALSE))
				{
					if(GetFileSize(DummyBuffer))
					{
						if(DataFeed = Open(DummyBuffer,MODE_OLDFILE))
						{
							strcpy(LastFile,FileRequest -> fr_File);
							strcpy(LastPath,FileRequest -> fr_Drawer);

							if(Kick30)
								SetVBuf(DataFeed,NULL,2,8192);
						}
					}

					FreeAslRequest(FileRequest);
				}
			}
			else
#endif	/* DATAFEED */

			ShowAbout(FALSE);

			ReleaseWindows();

			break;

			/* Terminate the program. */

		case MEN_QUIT:

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

				OldLen = Len;

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

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

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

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

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

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

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

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

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

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

				if(SoundChanged)
					Len += strlen(LocaleString(MSG_WAIT_SOUND_SETTINGS_CHANGED_TXT)) + 4;

				BlockWindows();

				OldPtr = ThisProcess -> pr_WindowPtr;

				ThisProcess -> pr_WindowPtr = (APTR)Window;

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

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

							strcat(Buffer,SharedBuffer);
						}

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

						FreeVecPooled(Buffer);
					}
					else
						MainTerminated = TRUE;
				}
				else
					MainTerminated = TRUE;

				ThisProcess -> pr_WindowPtr = OldPtr;

				ReleaseWindows();
			}

			break;

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

		case MEN_PASTE:

			if(!OpenClip(Config -> ClipConfig -> ClipboardUnit))
			{
				ClipInput = TRUE;

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

			break;

		case MEN_COPY:

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

			break;

		case MEN_CLEAR:

			DropMarker();
			break;

			/* Execute an AmigaDOS command. */

		case MEN_EXECUTE_DOS_COMMAND:

			BlockWindows();

				/* Enter the name of the command. */

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

			ReleaseWindows();

			break;

			/* Execute an ARexx script command. */

		case MEN_EXECUTE_REXX_COMMAND:

			BlockWindows();

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

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

			ReleaseWindows();

			break;

			/* Turn recording on/off. */

		case MEN_RECORD:

			if(GetItem(MEN_RECORD))
			{
				if(!Recording)
				{
					if(CreateRecord(CurrentBBSName[0] ? CurrentBBSName : LocaleString(MSG_SCREENPANEL_UNKNOWN_TXT)))
					{
						RememberResetOutput();
						RememberResetInput();

						RememberOutput = TRUE;

						Recording = TRUE;
						RecordingLine = FALSE;

						OnItem(MEN_RECORD_LINE);
					}
				}
			}
			else
			{
				if(Recording)
				{
					FinishRecord();

					RememberOutput = FALSE;
					RememberInput = FALSE;

					Recording = FALSE;
					RecordingLine = FALSE;

					OffItem(MEN_RECORD_LINE);

					Status = STATUS_READY;
				}
			}

			break;

		case MEN_RECORD_LINE:

			if(Recording)
			{
				if(GetItem(MEN_RECORD))
				{
					if(!RecordingLine)
					{
						RecordingLine = TRUE;

						RememberResetInput();

						RememberOutput = FALSE;
						RememberInput = TRUE;
					}
				}
				else
				{
					if(RecordingLine)
					{
						RememberSpill();

						RecordingLine = FALSE;

						RememberOutput = TRUE;
						RememberInput = FALSE;
					}
				}
			}

			break;

		case MEN_DISABLE_TRAPS:

			if(Item = FindThisItem(Menu,MEN_DISABLE_TRAPS))
			{
				ObtainSemaphore(&GenericListTable[GLIST_TRAP] -> ListSemaphore);

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

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

			break;

			/* Edit the trap settings? */

		case MEN_EDIT_TRAPS:

			BlockWindows();

			TrapPanel();

			if(Item = FindThisItem(Menu,MEN_DISABLE_TRAPS))
			{
				if(WatchTraps)
					Item -> Flags &= ~CHECKED;
				else
					Item -> Flags |= CHECKED;
			}

			ReleaseWindows();

			break;

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

		case MEN_SET_CONSOLE:

			BlockWindows();

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

			ReleaseWindows();

			break;

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

		case MEN_PHONEBOOK:

			BlockWindows();

			HandleLocalDialList(TRUE);

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

					break;
				}

				Status = OldStatus;
			}

			SetRedialMenu();

			ReleaseWindows();

			break;

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

		case MEN_REDIAL:

			BlockWindows();

			HandleLocalDialList(TRUE);

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

					break;
				}

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

			SetRedialMenu();

			ReleaseWindows();

			break;

			/* Dial a single number. */

		case MEN_DIAL_NUMBER:

			BlockWindows();

			HandleLocalDialList(TRUE);

			DummyBuffer[0] = 0;

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

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

						NewList(LocalList);

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

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

							AddTail(LocalList,&DialNode -> VanillaNode);

							FreeDialList(TRUE);

							DialList = LocalList;

							DialPanel();

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

			SetRedialMenu();

			ReleaseWindows();

			break;

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

		case MEN_SEND_BREAK:

			SendBreak();
			break;

			/* Hang up the phone line. */

		case MEN_HANG_UP:

			BlockWindows();

			if(DialMsg)
			{
				DialMsg -> rm_Result1 = RC_WARN;
				DialMsg -> rm_Result2 = 0;

				ReplyMsg(DialMsg);

				DialMsg = NULL;
			}

			HangUp();

			ReleaseWindows();

			if(Config -> SerialConfig -> CheckCarrier)
				HungUp = TRUE;
			else
			{
				ObtainSemaphore(&OnlineSemaphore);

					/* Remember online state. */

				WasOnline = Online;

					/* We are no longer online. */

				Online = FALSE;

				ReleaseSemaphore(&OnlineSemaphore);

				HandleOnlineCleanup(TRUE);
			}

			break;

			/* Wait a bit... */

		case MEN_WAIT:
		{
			struct Window		*ReqWindow;
			struct EasyStruct	 Easy;

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

			BlockWindows();

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

					/* Don't echo serial output. */

				Quiet = TRUE;

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

					HandleSerial();

					StartTime(1,0);

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

					if(Signals & SIG_TIMER)
						WaitIO(TimeRequest);

					if(Signals & PORTMASK(ReqWindow -> UserPort))
					{
						if(!SysReqHandler(ReqWindow,NULL,FALSE))
						{
							if(!CheckIO(TimeRequest))
								AbortIO(TimeRequest);

							WaitIO(TimeRequest);

							Done = TRUE;
						}
					}
				}
				while(!Done);

				Quiet = FALSE;

				FreeSysRequest(ReqWindow);
			}

			ReleaseWindows();
		}

		break;

			/* Flush the serial buffers. */

		case MEN_FLUSH_BUFFER:

			ClearSerial();

			RestartSerial(FALSE);

			break;

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

		case MEN_RELEASE_DEVICE:

			ReleaseSerial = TRUE;
			break;

		case MEN_UPLOAD_ASCII:

			BlockWindows();

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

				StartXprSend(TRANSFER_ASCII,TRUE);

				BinaryTransfer = TRUE;
			}

			ResetProtocol();

			ReleaseWindows();

			break;

		case MEN_DOWNLOAD_ASCII:

			BlockWindows();

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

				StartXprReceive(TRANSFER_ASCII,NULL,TRUE);

				BinaryTransfer = TRUE;
			}

			ResetProtocol();

			ReleaseWindows();

			break;

		case MEN_UPLOAD_TEXT:

			BlockWindows();

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

				StartXprSend(TRANSFER_TEXT,TRUE);

				BinaryTransfer = TRUE;
			}

			ResetProtocol();

			ReleaseWindows();

			break;

		case MEN_DOWNLOAD_TEXT:

			BlockWindows();

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

				StartXprReceive(TRANSFER_TEXT,NULL,TRUE);

				BinaryTransfer = TRUE;
			}

			ResetProtocol();

			ReleaseWindows();

			break;

			/* Edit and transfer a file. */

		case MEN_EDIT_AND_UPLOAD_TEXT:

			BlockWindows();

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

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

					strcpy(CompoundName,Config -> PathConfig -> Editor);
					strcat(CompoundName," \"");
					strcat(CompoundName,DummyBuffer);
					strcat(CompoundName,"\"");

					SystemTags(CompoundName,
						SYS_UserShell,	TRUE,
					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(ChangeProtocol(Config -> TransferConfig -> ASCIIUploadLibrary))
									SendTextFile(TRANSFER_ASCII,DummyBuffer);

								ResetProtocol();

								break;

							case 2:	if(ChangeProtocol(Config -> TransferConfig -> TextUploadLibrary))
									SendTextFile(TRANSFER_TEXT,DummyBuffer);

								ResetProtocol();

								break;
						}

						BinaryTransfer = TRUE;
					}
				}
			}

			ReleaseWindows();
			break;

		case MEN_UPLOAD_BINARY:

			BlockWindows();

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

				StartXprSend(TRANSFER_BINARY,TRUE);
			}

			ResetProtocol();

			ReleaseWindows();

			break;

			/* Download some files. */

		case MEN_DOWNLOAD_BINARY:

			BlockWindows();

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

				StartXprReceive(TRANSFER_BINARY,NULL,TRUE);
			}

			ResetProtocol();

			ReleaseWindows();

			break;

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

		case MEN_CLEAR_BUFFER:

			if(Lines)
			{
				BlockWindows();

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

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

						TerminateBuffer();
					}
				}

				ReleaseWindows();
			}

			break;

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

		case MEN_DISPLAY_BUFFER:

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

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

				ReleaseWindows();
			}

			break;

			/* Close the buffer display. */

		case MEN_CLOSE_BUFFER:

			if(BufferTask)
			{
				Forbid();

				Signal(BufferTask,SIG_KILL);

				ClrSignal(SIG_HANDSHAKE);

				Wait(SIG_HANDSHAKE);

				Permit();
			}

			break;

			/* Is the buffer to be frozen? */

		case MEN_FREEZE_BUFFER:

			if(Item = FindThisItem(Menu,MEN_FREEZE_BUFFER))
			{
				if(Item -> Flags & CHECKED)
					BufferFrozen = TRUE;
				else
					BufferFrozen = FALSE;

				Forbid();

				ConOutputUpdate();

				Permit();
			}

			break;

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

		case MEN_OPEN_BUFFER:

			BlockWindows();

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

								case 2:	break;

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

						if(SomeFile)
						{
							LONG Len;

							LineRead(NULL,NULL,NULL);

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

							Close(SomeFile);

							BufferChanged = TRUE;
						}
					}
					else
						ShowError(Window,ERR_LOAD_ERROR,IoErr(),DummyBuffer);
				}

				FreeAslRequest(FileRequest);
			}

			ReleaseWindows();
			break;

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

		case MEN_SAVE_BUFFER_AS:

			BlockWindows();

			if(!Lines || !BufferLines)
				MyEasyRequest(Window,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
			else
			{
				if(FileRequest = GetFile(Window,LocaleString(MSG_TERMMAIN_SAVE_BUFFER_TXT),Config -> CaptureConfig -> BufferPath,"",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT),FALSE))
				{
					LONG Error = 0;

					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)
					{
						LONG i,Len;

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

						ObtainSemaphore(BufferSemaphore);

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

							if(Len)
							{
								SetIoErr(0);

								if(FWrite(SomeFile,BufferLines[i],Len,1) < 1)
								{
									Error = IoErr();

									break;
								}
							}

							SetIoErr(0);

							if(FPrintf(SomeFile,"\n") < 1)
							{
								Error = IoErr();

								break;
							}
						}

						ReleaseSemaphore(BufferSemaphore);

						Close(SomeFile);

						AddProtection(DummyBuffer,FIBF_EXECUTE);

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

						BufferChanged = FALSE;
					}
					else
						Error = IoErr();

					if(Error)
						ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);

					FreeAslRequest(FileRequest);
				}
			}

			ReleaseWindows();

			break;

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

		case MEN_CLEAR_SCREEN:

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

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

			break;

			/* Reset the current text rendering font. */

		case MEN_RESET_FONT:

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

				CurrentFont = TextFont;

				SetFont(RPort,CurrentFont);

				ConOutputUpdate();
			}

			break;

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

		case MEN_RESET_STYLES:

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

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

				ObtainSemaphore(&TerminalSemaphore);

				ClearCursor();

				Config -> EmulationConfig -> FontScale = SCALE_NORMAL;

				FgPen = GetPenIndex(SafeTextPen);
				BgPen = 0;

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

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

				SetWrMsk(RPort,DepthMask);

				ConFontScaleUpdate();

				DrawCursor();

				ReleaseSemaphore(&TerminalSemaphore);
			}

			break;

			/* Reset the whole terminal. */

		case MEN_RESET_TERMINAL:

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

				ConBypass("\033c",-1);
			}

			break;

		case MEN_SET_EMULATION:

			BlockWindows();

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

				NewOptions = FALSE;

				XEmulatorOptions(XEM_IO);

				if(NewOptions)
				{
					SetEmulatorOptions(XEM_PREFS_SAVE);

					NewOptions = FALSE;
				}

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

			ReleaseWindows();

			break;

			/* Set the serial preferences. */

		case MEN_SERIAL:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the modem preferences. */

		case MEN_MODEM:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the screen preferences. */

		case MEN_SCREEN:

			BlockWindows();

			if(ScreenPanel(Config,NULL))
			{
				if(memcmp(PrivateConfig -> ScreenConfig -> Colours,Config -> ScreenConfig -> Colours,sizeof(UWORD) * 16))
				{
					switch(Config -> ScreenConfig -> ColourMode)
					{
						case COLOUR_EIGHT:

							CopyMem(Config -> ScreenConfig -> Colours,ANSIColours,16 * sizeof(UWORD));
							break;

						case COLOUR_SIXTEEN:

							CopyMem(Config -> ScreenConfig -> Colours,EGAColours,16 * sizeof(UWORD));
							break;

						case COLOUR_AMIGA:

							CopyMem(Config -> ScreenConfig -> Colours,DefaultColours,16 * sizeof(UWORD));
							break;

						case COLOUR_MONO:

							CopyMem(Config -> ScreenConfig -> Colours,AtomicColours,16 * sizeof(UWORD));
							break;
					}
				}

				ConfigSetup();

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

							CopyMem(Config -> ScreenConfig -> Colours,ANSIColours,16 * sizeof(UWORD));
							break;

						case COLOUR_SIXTEEN:

							CopyMem(Config -> ScreenConfig -> Colours,EGAColours,16 * sizeof(UWORD));
							break;

						case COLOUR_AMIGA:

							CopyMem(Config -> ScreenConfig -> Colours,DefaultColours,16 * sizeof(UWORD));
							break;

						case COLOUR_MONO:

							CopyMem(Config -> ScreenConfig -> Colours,AtomicColours,16 * sizeof(UWORD));
							break;
					}

					ConfigChanged = TRUE;
				}
			}

			ReleaseWindows();

			break;

			/* Set the terminal preferences. */

		case MEN_TERMINAL:

			BlockWindows();

			if(TerminalPanel(Config,NULL))
			{
				Update_CR_LF_Translation();

				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the clipboard preferences. */

		case MEN_CLIPBOARD:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the capture preferences. */

		case MEN_CAPTURE:

			BlockWindows();

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

				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the command preferences. */

		case MEN_COMMANDS:

			BlockWindows();

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

			ReleaseWindows();

			break;

			/* Set the miscellaneous preferences. */

		case MEN_MISC:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the path settings. */

		case MEN_PATH:

			BlockWindows();

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

			ReleaseWindows();

			break;

			/* Set the file transfer options. */

		case MEN_TRANSFER:

			BlockWindows();

			XprIO -> xpr_filename = NULL;

				/* Set up the library options. */

			if(XProtocolBase)
			{
				XPRCommandSelected = FALSE;

				ClearSerial();

				NewOptions = FALSE;

				TransferBits = XProtocolSetup(XprIO);

				RestartSerial(FALSE);

				DeleteTransferPanel(TRUE);

					/* Successful? */

/*				if(!XPRCommandSelected)*/
				{
					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;

						SetTransferMenu(FALSE);
					}
					else
						SaveProtocolOpts();
				}
			}

			ReleaseWindows();

			break;

			/* Set the file transfer procol settings. */

		case MEN_TRANSFER_PROTOCOL:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the translation tables. */

		case MEN_TRANSLATION:

			BlockWindows();

			TranslationChanged |= TranslationPanel(&SendTable,&ReceiveTable,LastTranslation,Window);

				/* Choose the right console write routine. */

			ConOutputUpdate();

			ReleaseWindows();

			break;

			/* Set the keyboard macros. */

		case MEN_MACROS:

			BlockWindows();

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

				MacroChanged |= MacroPanel(MacroKeys,LastMacros,TRUE,Window);

				SetupXEM_MacroKeys(MacroKeys);
			}
			else
				MacroChanged |= MacroPanel(MacroKeys,LastMacros,TRUE,Window);

			ReleaseWindows();

			break;

			/* Set the cursor keys. */

		case MEN_CURSORKEYS:

			BlockWindows();

			CursorKeysChanged |= CursorPanel(CursorKeys,LastCursorKeys,Window);

			ReleaseWindows();

			break;

			/* Set the fast macros. */

		case MEN_FAST_MACROS:

			BlockWindows();

			FastMacrosChanged |= FastMacroPanel(&FastMacroList,LastFastMacros,Window);

			ReleaseWindows();

			break;

			/* Set the hotkey preferences. */

		case MEN_HOTKEYS:

			BlockWindows();

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

			ReleaseWindows();

			break;

			/* Set the speech preferences. */

		case MEN_SPEECH:

			BlockWindows();

			SpeechPanel();

			ReleaseWindows();

			break;

			/* Set the sound preferences. */

		case MEN_SOUND:

			BlockWindows();

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

			ReleaseWindows();

			break;

			/* Edit the phone number patterns and rates. */

			/* Edit the trap settings? */

		case MEN_RATES:

			BlockWindows();

			PatternPanel();

			ReleaseWindows();

			break;

			/* Open the preferences settings. */

		case MEN_OPEN_SETTINGS:

			BlockWindows();

			strcpy(DummyBuffer,LastConfig);

			DummyChar = PathPart(DummyBuffer);

			*DummyChar = 0;

			if(FileRequest = GetFile(Window,LocaleString(MSG_TERMMAIN_OPEN_PREFERENCES_TXT),DummyBuffer,FilePart(LastConfig),DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,NULL,TRUE))
			{
				if(ReadConfig(DummyBuffer,PrivateConfig))
				{
					SwapConfig(PrivateConfig,Config);

					strcpy(DummyBuffer,LastConfig);

					ConfigSetup();

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

				FreeAslRequest(FileRequest);
			}

			ReleaseWindows();

			break;

			/* Save the terminal preferences. */

		case MEN_SAVE_SETTINGS:

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

				if(!WriteConfig(LastConfig,Config))
					ShowError(Window,ERR_SAVE_ERROR,IoErr(),LastConfig);
				else
					ConfigChanged = FALSE;

				ReleaseWindows();

				break;
			}

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

		case MEN_SAVE_SETTINGS_AS:

			BlockWindows();

			strcpy(DummyBuffer,LastConfig);

			DummyChar = PathPart(DummyBuffer);

			*DummyChar = 0;

			if(FileRequest = GetFile(Window,LocaleString(MSG_TERMMAIN_SAVE_PREFERENCES_AS_TXT),DummyBuffer,FilePart(LastConfig),DummyBuffer,"#?.prefs",TRUE,FALSE,FALSE,NULL,TRUE))
			{
				if(WriteConfig(DummyBuffer,Config))
				{
					strcpy(LastConfig,DummyBuffer);

					ConfigChanged = FALSE;
				}
				else
					ShowError(Window,ERR_SAVE_ERROR,IoErr(),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:

			CreatePacketWindow();
			break;

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

		case MEN_FAST_MACROS_WINDOW:

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

			break;

			/* Open the upload queue window. */

		case MEN_UPLOAD_QUEUE_WINDOW:

			CreateQueueProcess();
			break;

		default:if(Code >= DIAL_MENU_LIMIT)
			{
				LONG Index = Code - DIAL_MENU_LIMIT;

				if(!LocalDialList && !Online)
				{
					if(LocalDialList = (struct List *)AllocVecPooled(sizeof(struct List),MEMF_ANY))
					{
						LONG i;

							/* Clear previous list contents, we
							 * don't want to redial yet.
							 */

						for(i = 0 ; i < NumPhoneEntries ; i++)
							Phonebook[i] -> Count = -1;

						NewList(LocalDialList);
					}
				}

				if(Phonebook[Index] -> Count == -1)
				{
					if(LocalDialList)
					{
						struct PhoneNode *NewNode;

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

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

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

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

							SPrintf(NewNode -> LocalName,"%3ld - %s",LocalCount + 1,Phonebook[Index] -> Header -> Name);

								/* Install back-link. */

							NewNode -> Entry -> Node = NewNode;

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

			break;
	}
}

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

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

	DisplayReopened = FALSE;

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

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

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

			if(Apocalypse)
				return;

			if(DisplayReopened)
			{
				DisplayReopened = FALSE;

				return;
			}

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

	HandleLocalDialList(FALSE);
}

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

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

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

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

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

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

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

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

														strcat(SharedBuffer,".info");

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

															UnLock(InfoLock);
														}
													}
												}
											}
										}
									}

									UnLock(FileLock);
								}

								CurrentDir(OldLock);
							}
						}
					}
				}

				ReplyMsg((struct Message *)AppMessage);
			}

			if(FilesFound)
			{
				SortFileTransferInfo(Info);

				BlockWindows();

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

						StartXprSendFromList(TRANSFER_BINARY,TRUE);

						break;

					case 2:	BinaryTransfer		= FALSE;
						FileTransferInfo	= Info;

						StartXprSendFromList(TRANSFER_TEXT,TRUE);

						break;

					case 0:	FreeFileTransferInfo(Info);
						break;
				}

				ReleaseWindows();
			}
		}

		FreeDosObject(DOS_FIB,FileInfo);
	}

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

	return(FALSE);
}

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

VOID
HandleIconify()
{
	BYTE Released = FALSE;

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

	BlockWindows();

		/* Open workbench.library. */

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

		if(IconBase)
		{
			struct DiskObject *Icon;

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

				/* Did we get an icon? */

			if(Icon)
			{
				struct MsgPort *IconPort;

					/* Reset the icon type. */

				Icon -> do_Type		= NULL;

					/* Default icon position. */

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

					/* Create the Workbench reply port. */

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

						/* Add the application icon. */

					if(AppIcon = AddAppIcon(0,0,TermIDString,IconPort,NULL,Icon,TAG_DONE))
					{
						struct AppMessage	*AppMessage;
						UBYTE			*String,*Error;
						ULONG			 SignalSet;

							/* Reset the guardian. */

						IconTerminated = FALSE;

							/* Release the window. */

						Released = TRUE;

						ReleaseWindows();

						WindowBox . Left	= Window -> LeftEdge;
						WindowBox . Top		= Window -> TopEdge;
						WindowBox . Width	= Window -> Width;
						WindowBox . Height	= Window -> Height;

							/* Close the display. full stop. */

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

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

								DeleteSerial();
							}

								/* Wait for double-click. */

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

								if(SignalSet & PORTMASK(IconPort))
								{
										/* Pick up application messages. */

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

										IconTerminated = TRUE;

										ReplyMsg(AppMessage);
									}
								}

									/* Wake up if ARexx command received. */

								if(SignalSet & SIG_REXX)
									while(HandleRexx());

								if(SignalSet & SIGBREAKF_CTRL_F)
									IconTerminated = TRUE;
							}

								/* Open the serial driver. */

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

									switch(MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_ICONIFY_IGNORE_QUIT_TXT),Error))
									{
										case 1:	IconTerminated = FALSE;
											goto IconLoop;

										case 0:	MainTerminated = TRUE;
									}
								}
								else
								{
									if(SerialMessage)
									{
										MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SerialMessage);

										SerialMessage = NULL;
									}
								}
							}

							if(CantQuit && MainTerminated)
								MainTerminated = FALSE;

								/* Create the display. */

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

										DeleteSerial();

										IconTerminated = FALSE;

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

									PubScreenStuff();
								}
							}
						}
						else
						{
							BlockWindows();

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

							ReleaseWindows();
						}

							/* Remove the application icon. */

						RemoveAppIcon(AppIcon);

							/* Reply pending messages. */

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

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

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

	if(!Released)
		ReleaseWindows();

		/* Finished! */

	DoIconify = FALSE;
}

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

VOID __regargs
HandleOnlineCleanup(BOOL Hangup)
{
	SoundPlay(SOUND_DISCONNECT);

		/* Execute logoff macro. */

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

	StopCall(FALSE);

	if(CurrentPay)
	{
		if(Hangup)
			LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_HANG_UP_COST_TXT),CreateSum(CurrentPay,TRUE));
		else
			LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_COST_TXT),CreateSum(CurrentPay,TRUE));
	}
	else
	{
		if(Hangup)
			LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_HANG_UP_TXT));
		else
			LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
	}

	SetDialMenu(TRUE);

	if(!Hangup)
		Say(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));

		/* Clear the password. */

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

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

	ObtainSemaphore(&OnlineSemaphore);

	if(!Config -> SerialConfig -> CheckCarrier)
		Online = WasOnline = FALSE;

	ReleaseSemaphore(&OnlineSemaphore);

	ObtainSemaphore(&PatternSemaphore);

	ChosenEntry	= NULL;
	ChosenPattern	= NULL;

	ReleaseSemaphore(&PatternSemaphore);

	LimitCount = -1;

		/* Previous configuration available? */

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

		SaveConfig(Config,PrivateConfig);

			/* Copy configuration. */

		SaveConfig(BackupConfig,Config);

			/* Set up new configuration. */

		ConfigSetup();

			/* Free old configuration. */

		DeleteConfiguration(BackupConfig);

		BackupConfig = NULL;
	}

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

		SoftReset();

			/* Display how much we expect
			 * the user will have to pay for
			 * this call.
			 */

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

		CurrentPay = 0;
	}

	if(Config -> ModemConfig -> RedialAfterHangup)
	{
		if(DialList)
		{
			if(DialList -> lh_Head -> ln_Succ)
			{
				Online = WasOnline = FALSE;

				DoDial = DIAL_REDIAL;
			}
		}
	}
}

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

VOID
HandleFlowChange()
{
	if(Online)
	{
		if(FlowInfo . NoCarrier)
		{
			if(Config -> SerialConfig -> CheckCarrier)
			{
					/* Is the carrier still present? */

				if(!(GetSerialStatus() & CIAF_COMCD))	// = Carrier detected
					FlowInfo . NoCarrier = FALSE;
			}

			if(FlowInfo . NoCarrier)
			{
				ObtainSemaphore(&OnlineSemaphore);

				WasOnline	= Online;
				Online		= FALSE;

				ReleaseSemaphore(&OnlineSemaphore);
			}
		}
	}
	else
	{
		if(FlowInfo . Voice)
		{
			UBYTE DateTimeBuffer[256];

			FormatStamp(NULL,NULL,NULL,DateTimeBuffer,FALSE);

			WakeUp(Window,SOUND_VOICE);

			ConWrites(LocaleString(MSG_TERMMAIN_INCOMING_VOIC_CALL_TXT),DateTimeBuffer);

			Say(LocaleString(MSG_TERMMAIN_SAY_INCOMING_VOICE_CALL_TXT));
		}

		if(FlowInfo . Ring)
		{
			UBYTE DateTimeBuffer[256];

			FormatStamp(NULL,NULL,NULL,DateTimeBuffer,FALSE);

			WakeUp(Window,SOUND_RING);

			ConWrites(LocaleString(MSG_TERMMAIN_INCOMING_CALL_TXT),DateTimeBuffer);

			Say(LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));
		}

		if(FlowInfo . Connect)
		{
				/* Are we to check the carrier signal? */

			if(Config -> SerialConfig -> CheckCarrier)
			{
					/* No carrier signal present? */

				if(GetSerialStatus() & CIAF_COMCD)	// = Carrier lost
					FlowInfo . Connect = FALSE;
			}

			if(FlowInfo . Connect)
			{
				WakeUp(Window,SOUND_CONNECT);

				ObtainSemaphore(&OnlineSemaphore);

				WasOnline	= Online;
				Online		= TRUE;
				BaudPending	= FALSE;

				ReleaseSemaphore(&OnlineSemaphore);

				SetDialMenu(FALSE);
			}
		}
	}

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

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

			switch(UploadPanel())
			{
				case UPLOAD_TEXT:

					BinaryTransfer = FALSE;

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

					break;

				case UPLOAD_BINARY:

					BinaryTransfer = TRUE;

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

					break;

				case UPLOAD_ABORT:

					SerWrite(ZModemCancel,20);
					break;

				case UPLOAD_BINARY_FROM_LIST:

					StartUpload(UPLOAD_BINARY);
					break;

				case UPLOAD_TEXT_FROM_LIST:

					StartUpload(UPLOAD_TEXT);
					break;
			}

			ReleaseWindows();
		}
	}

	FlowInit(TRUE);
}

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

VOID
HandleSerialReset()
{
	ClearSerial();

	DeleteSerial();

	BlockWindows();

	ReopenSerial();

	ReleaseWindows();
}

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

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

	ThisProcess -> pr_WindowPtr = (APTR)Window;

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

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

	BlockWindows();

		/* Prevent catastrophes! */

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

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

			DeleteSerial();

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

	ReleaseSerial = FALSE;

	ThisProcess -> pr_WindowPtr = OldPtr;

	ReleaseWindows();
}

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

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

		ResetDisplay = TRUE;
	}
}

	/* HandleSerialCheck():
	 *
	 *	Handle routine checkup actions.
	 */

BYTE
HandleSerialCheck()
{
		/* Take a look at the carrier signal. */

	if(Config -> SerialConfig -> CheckCarrier && WriteRequest)
	{
		register UWORD Status = GetSerialStatus();

			/* Still online? */

		if(Online)
		{
				/* Carrier detect signal lost? */

			if(Status & CIAF_COMCD)	// = Carrier lost
			{
				ObtainSemaphore(&OnlineSemaphore);

				WasOnline	= Online;
				Online		= FALSE;

				ReleaseSemaphore(&OnlineSemaphore);
			}
		}
		else
		{
				/* Is the carrier detect signal
				 * present?
				 */

			if(!(Status & CIAF_COMCD))	// = Carrier detected
			{
				ObtainSemaphore(&OnlineSemaphore);

				WasOnline		= Online;
				Online			= TRUE;

				ReleaseSemaphore(&OnlineSemaphore);

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

				CurrentPay		= 0;

				ObtainSemaphore(&PatternSemaphore);

				ChosenEntry		= NULL;
				ChosenPattern		= NULL;

				ReleaseSemaphore(&PatternSemaphore);

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

				SendStartup		= FALSE;

				LimitCount		= -1;

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

				SetDialMenu(FALSE);
			}
		}
	}

		/* Check online time limit. */

	if(!LimitCount)
	{
		LimitCount = -1;

		BlockWindows();

		SendARexxCommand(LimitMacro);

		ReleaseWindows();
	}

		/* Flush capture file contents to disk,
		 * this routine is executed each minute
		 * in order to store the captured data.
		 */

	if(BufferFlushCount-- <= 0)
	{
		BufferFlushCount = 60;

			/* Flush the capture file. */

		if(FileCapture)
			BufferFlush(FileCapture);
	}

	return(FALSE);
}

	/* HandleQueueMsg():
	 *
	 *	Process the special message queue.
	 */

BYTE
HandleQueueMsg()
{
	struct DataMsg *Item;

	if(Item = GetMsgItem(SpecialQueue))
	{
		struct FileTransferInfo *Info;
		BYTE			 OldEcho;

		switch(Item -> Type)
		{
				// Output data.

			case DATAMSGTYPE_WRITE:

				SerWrite(Item -> Data,Item -> Size);
				break;

				// Execute a command.

			case DATAMSGTYPE_SERIALCOMMAND:

				SerialCommand(Item -> Data);
				break;

				// Execute a command, but don't echo it.

			case DATAMSGTYPE_SERIALCOMMANDNOECHO:

				OldEcho = Config -> SerialConfig -> Duplex;

				Config -> SerialConfig -> Duplex = DUPLEX_FULL;

				SerialCommand(Item -> Data);

				Config -> SerialConfig -> Duplex = OldEcho;
				break;

				// Output contents of clipboard

			case DATAMSGTYPE_WRITECLIP:

				if(!ClipInput)
				{
					if(!OpenClip(Item -> Size))
						ClipInput = ClipXerox = TRUE;
					else
						ClipInput = ClipXerox = FALSE;
				}

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

				if(ClipInput)
				{
					UBYTE	InputBuffer[257];
					WORD	Len;

					if((Len = GetClip(InputBuffer,256,TRUE)) < 0)
					{
						CloseClip();

						ClipInput = FALSE;

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

							ClipXerox = FALSE;
						}

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

							ClipPrefix = TRUE;
						}

						if(Len > 0)
							SendInputTextBuffer(InputBuffer,Len,FALSE);
					}
				}

				break;

				// Start an upload

			case DATAMSGTYPE_UPLOAD:

				if(((struct List *)Item -> Data) -> lh_Head -> ln_Succ)
				{
					if(Info = AllocFileTransferInfo())
					{
						struct FileInfoBlock *FileInfo;
						LONG FilesFound = 0,Type = Item -> Size;

						if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
						{
							BPTR FileLock;
							struct List *List;
							struct Node *Node,*Next;
							APTR OldPtr = ThisProcess -> pr_WindowPtr;

							ThisProcess -> pr_WindowPtr = (APTR)-1;

							List = (struct List *)Item -> Data;

							for(Node = List -> lh_Head ; Next = Node -> ln_Succ ; Node = Next)
							{
								if(FileLock = Lock(Node -> ln_Name,ACCESS_READ))
								{
									if(Examine(FileLock,FileInfo))
									{
										if(FileInfo -> fib_DirEntryType < 0)
										{
											if(AddFileTransferNode(Info,Node -> ln_Name,FileInfo -> fib_Size))
												FilesFound++;

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

												strcpy(SharedBuffer,Node -> ln_Name);

												strcat(SharedBuffer,".info");

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

													UnLock(InfoLock);
												}
											}

											Remove(Node);

											FreeVecPooled(Node);
										}
									}

									UnLock(FileLock);
								}
							}

							ThisProcess -> pr_WindowPtr = OldPtr;

							FreeDosObject(DOS_FIB,FileInfo);
						}

						DeleteMsgItem(Item);

						Item = NULL;

						if(FilesFound)
						{
							BlockWindows();

							SortFileTransferInfo(Info);

							switch(Type)
							{
								case UPLOAD_BINARY:

									BinaryTransfer		= TRUE;
									FileTransferInfo	= Info;

									StartXprSendFromList(TRANSFER_BINARY,TRUE);

									break;

								case UPLOAD_TEXT:

									BinaryTransfer		= FALSE;
									FileTransferInfo	= Info;

									StartXprSendFromList(TRANSFER_TEXT,TRUE);

									break;
							}

							ReleaseWindows();
						}
						else
							FreeFileTransferInfo(Info);
					}
				}
				else
				{
					UBYTE Type = Item -> Size;

					DeleteMsgItem(Item);

					Item = NULL;

					if(Type == UPLOAD_BINARY)
					{
						BinaryTransfer = TRUE;

						if(!StartXprSend(TRANSFER_BINARY,TRUE))
							SerWrite(ZModemCancel,20);
					}
					else
					{
						BinaryTransfer = FALSE;

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

				break;

				// ARexx script execution finished.

			case DATAMSGTYPE_COMMANDDONE:

				if(CantQuit > 0)
					CantQuit--;

				BumpWindow(Window);

				ReleaseWindows();

				break;

				// Call a menu item

			case DATAMSGTYPE_MENU:

				HandleMenuCode((ULONG)Item -> Size,(ULONG)Item -> Data);

				break;

				// Rendezvous with external process

			case DATAMSGTYPE_RENDEZVOUS:

				if(ReadRequest && WriteRequest)
				{
						// Abort serial I/O processing

					ClearSerial();

					BlockWindows();

						// Return the message, caution, we're not ready yet

					Forbid();

					DeleteMsgItem(Item);

					Item = NULL;

						// Prepare to wait...

					ClrSignal(SIG_HANDSHAKE);

					Wait(SIG_HANDSHAKE);

						// Pick up the queue

					RestartSerial(FALSE);

					Permit();

					ReleaseWindows();
				}

				break;
		}

		if(Item)
			DeleteMsgItem(Item);

		return(TRUE);
	}
	else
		return(FALSE);
}

	/* HandleOwnDevUnit():
	 *
	 *	Deal with the OwnDevUnit signal notification.
	 */

BYTE
HandleOwnDevUnit()
{
	if(!Online || !ReadPort)
		HandleSerialRelease();

	return(FALSE);
}
