/*
**	Main.c
**
**	Program main routines and event loop
**
**	Copyright © 1990-1996 by Olaf `Olsen' Barthel
**		All Rights Reserved
**
**	:ts=4
*/

#ifndef _GLOBAL_H
#include "Global.h"
#endif

	/* 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_LANGUAGE,ARG_PHONEBOOK,ARG_AUTODIAL,
			ARG_AUTOEXIT,ARG_WINDOWTITLE,

			ARG_COUNT
		};

	/* The shell argument template and the corresponding help message. */

STATIC STRPTR 		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,LANGUAGE/K,PHONEBOOK/K,"
									"AUTODIAL/S,AUTOEXIT/S,WINDOWTITLE/K";

STATIC STRPTR		ArgHelp =		"\nUsage: term [WINDOW <Name>] [PUBSCREEN <Name>] [STARTUP <File name>]\n"
									"            [SETTINGS <File or path name>] [UNIT <Number>] [DEVICE <Name>]\n"
									"            [NEW] [SYNC] [QUIET] [BEHIND] [LANGUAGE <Name>] [PHONEBOOK <File name>]\n"
									"            [AUTODIAL] [AUTOEXIT] [WINDOWTITLE <Title>]\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"
									"   Phonebook = Name of phonebook file to load\n"
									"    Autodial = Dial phonebook entries which are marked for autodialing\n"
									"    Autoexit = Exit `term' after dialing all autodial entries\n"
									" Windowtitle = Display this text as the terminal window title\n"
									"    Language = Language to use for the user interface\n\n";

	/* Local config path variable. */

STATIC STRPTR		ConfigPath;
STATIC UBYTE		ThePath[MAX_FILENAME_LENGTH];

	/* Startup file name. */

STATIC UBYTE		StartupFile[MAX_FILENAME_LENGTH];

	/* Console output window specifier. */

STATIC UBYTE		WindowName[256];

	/* Did we hang up the line? */

STATIC BOOL			HungUp;

	/* Go on redialing? */

STATIC BOOL			KeepRedialing;
STATIC BOOL			AutoDial;
STATIC BOOL			AutoExit;

	/* Display the connection cost? */

STATIC BOOL			DisplayHangup;
STATIC ULONG		DisplayPay;

	/* Poll OwnDevUnit.library for the device to become available again? */

STATIC BOOL			PollODU;
STATIC UWORD		PollODUCount;

	/* Check the menu for items to dial? */

STATIC BOOL			CheckDialMenu;

	/* Local routines */

STATIC BOOL HandleInput(VOID);
STATIC VOID ClearDialMenu(VOID);
STATIC BOOL DialMenuToDialList(VOID);
STATIC VOID HandleMenu(ULONG Code,ULONG Qualifier);
STATIC VOID HandleIconify(VOID);
STATIC VOID HandleOnlineCleanup(BOOL Hangup);
STATIC VOID HandleFlowChange(VOID);
STATIC VOID FullHangup(BOOL ForceIt);
STATIC BOOL AskDial(struct Window *Parent);
STATIC VOID GoOnline(VOID);
STATIC VOID ReadyToDial(struct DataDialMsg *DialMsg);
STATIC VOID HandleUpload(UBYTE Type);
STATIC VOID LocalReleaseSerial(VOID);
STATIC VOID HandleKeyboardInput(UBYTE Char,UWORD Code,ULONG Qualifier,STRPTR InputBuffer,LONG Len);

	/* Main():
	 *
	 *	This is our main entry point.
	 */

LONG
Main()
{
	LONG Error = 0;

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

	ThisProcess = (struct Process *)FindTask(NULL);

	if(ThisProcess->pr_CLI)
		WBenchMsg = NULL;
	else
	{
		WaitPort(&ThisProcess->pr_MsgPort);

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

		/* Now try to open dos.library and utility.library and
		 * proceed to examine the startup parameters.
		 */

	DOSBase		= (struct DosLibrary *)OpenLibrary("dos.library",0);
	UtilityBase	= OpenLibrary("utility.library",0);

	if(DOSBase && UtilityBase)
	{
		struct RDArgs *ArgsPtr;
		STRPTR *ArgArray;
		BOOL LaunchNew;

			/* Reset these first. */

		ArgsPtr		= NULL;
		ArgArray	= NULL;
		LaunchNew	= TRUE;

			/* We were called from Shell. */

		if(ThisProcess->pr_CLI)
		{
				/* No home directory to return to. */

			WBenchLock = NULL;

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

			if(ArgArray = (STRPTR *)AllocVec(sizeof(STRPTR) * (ARG_COUNT),MEMF_ANY|MEMF_CLEAR))
			{
				if(ArgsPtr = (struct RDArgs *)AllocDosObject(DOS_RDARGS,TAG_DONE))
				{
					ArgsPtr->RDA_ExtHelp = ArgHelp;

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

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

						if(!ArgArray[ARG_NEW])
							LaunchNew = FALSE;

							/* For debugging purposes; not used yet. */

						if(ArgArray[ARG_DEBUG])
							DebugFlag = TRUE;

							/* Special language requested? */

						if(ArgArray[ARG_LANGUAGE])
							LimitedStrcpy(sizeof(Language),Language,ArgArray[ARG_LANGUAGE]);

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

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

							LimitedStrcpy(sizeof(ThePath),ThePath,ArgArray[ARG_SETTINGS]);
						}

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

						if(ArgArray[ARG_PORTNAME])
							LimitedStrcpy(sizeof(RexxPortName),RexxPortName,ArgArray[ARG_PORTNAME]);

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

						if(ArgArray[ARG_WINDOW])
							LimitedStrcpy(sizeof(WindowName),WindowName,ArgArray[ARG_WINDOW]);

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

						if(ArgArray[ARG_STARTUP])
							LimitedStrcpy(sizeof(StartupFile),StartupFile,ArgArray[ARG_STARTUP]);

							/* Load a special phonebook file */

						if(ArgArray[ARG_PHONEBOOK])
							LimitedStrcpy(sizeof(LastPhone),LastPhone,ArgArray[ARG_PHONEBOOK]);

						if(ArgArray[ARG_AUTODIAL])
							AutoDial = TRUE;

						if(ArgArray[ARG_AUTOEXIT])
							AutoExit = TRUE;

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

						if(ArgArray[ARG_PUBSCREEN])
							LimitedStrcpy(sizeof(SomePubScreenName),SomePubScreenName,ArgArray[ARG_PUBSCREEN]);

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

						if(ArgArray[ARG_DEVICE])
						{
							LimitedStrcpy(sizeof(NewDevice),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;

							/* Use a special window title? */

						if(ArgArray[ARG_WINDOWTITLE])
						{
							CopyMem(ArgArray[ARG_WINDOWTITLE],WindowTitle,79);
							WindowTitle[79] = 0;
						}
						else
							WindowTitle[0] = 0;
					}
					else
						Error = IoErr();
				}
				else
					Error = IoErr();
			}
			else
				Error = IoErr();
		}
		else
		{
			BOOL ScrewThePath = TRUE;

				/* Change to the program's home directory. */

			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((UBYTE **)Icon->do_ToolTypes,"DEBUG"))
						DebugFlag = TRUE;

					if(FindToolType((UBYTE **)Icon->do_ToolTypes,"NOPATHFIX"))
						ScrewThePath = FALSE;

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"LANGUAGE"))
						LimitedStrcpy(sizeof(Language),Language,Type);

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

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

						LimitedStrcpy(sizeof(ThePath),ThePath,ConfigPath);

						ConfigPath = ThePath;
					}

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"PHONEBOOK"))
						LimitedStrcpy(sizeof(LastPhone),LastPhone,Type);

					if(FindToolType((UBYTE **)Icon->do_ToolTypes,"AUTODIAL"))
						AutoDial = TRUE;

					if(FindToolType((UBYTE **)Icon->do_ToolTypes,"AUTOEXIT"))
						AutoExit = TRUE;

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"PORTNAME"))
						LimitedStrcpy(sizeof(RexxPortName),RexxPortName,Type);
					else
						RexxPortName[0] = 0;

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"WINDOW"))
						LimitedStrcpy(sizeof(WindowName),WindowName,Type);

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"WINDOWTITLE"))
						LimitedStrcpy(sizeof(WindowTitle),WindowTitle,Type);
					else
						WindowTitle[0] = 0;

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"PUBSCREEN"))
						LimitedStrcpy(sizeof(SomePubScreenName),SomePubScreenName,Type);
					else
						SomePubScreenName[0] = 0;

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"STARTUP"))
						LimitedStrcpy(sizeof(StartupFile),StartupFile,Type);
					else
						StartupFile[0] = 0;

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

					if(Type = FindToolType((UBYTE **)Icon->do_ToolTypes,"DEVICE"))
					{
						if(Type[0])
						{
							LimitedStrcpy(sizeof(NewDevice),NewDevice,Type);

							UseNewDevice = TRUE;
						}
					}

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

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

							UseNewUnit = TRUE;
						}
					}

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

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

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

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

						/* Free the icon. */

					FreeDiskObject(Icon);
				}

				CloseLibrary(IconBase);
				IconBase = NULL;
			}

				/* Try to create a local CLI structure so
				 * Shell commands will receive a valid
				 * search path list.
				 */

			if(ScrewThePath)
				AttachCLI(WBenchMsg);
		}

			/* Show the error message; Error can be non-zero only if
			 * `term' was started from shell.
			 */

		if(Error)
			PrintFault(Error,"term");
		else
		{
				/* If there is already a `term' program running, pop its window to the front. */

			if(!LaunchNew)
			{
				struct TermPort *TermPort;

					/* If no other program is running, don't bother. */

				Forbid();

				if(!(TermPort = TermPort = (struct TermPort *)FindPort(TERMPORTNAME)))
					LaunchNew = TRUE;
				else
				{
						/* Open intuition and pop the window to the front. */

					if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
					{
						if(TermPort->TopWindow)
							BumpWindow(TermPort->TopWindow);

						CloseLibrary((struct Library *)IntuitionBase);
						IntuitionBase = NULL;
					}
				}

				Permit();
			}

				/* Do something sensible? */

			if(LaunchNew)
			{
				BYTE OldTaskPri = ThisProcess->pr_Task.tc_Node.ln_Pri;

				if(StackSize(NULL) < 16384)
				{
					LONG Success;

					if(!StackCall(&Success,16384,0,(STACKCALL)HandleInput))
						Error = ERROR_NO_FREE_STORE;
				}
				else
				{
					if(!HandleInput())
						Error = ERROR_NO_FREE_STORE;
				}

				CloseAll();

				SetTaskPri((struct Task *)ThisProcess,OldTaskPri);
			}
		}

			/* Now clean up any allocated data. */

		if(ArgsPtr)
		{
			FreeArgs(ArgsPtr);
			FreeDosObject(DOS_RDARGS,ArgsPtr);
		}

		FreeVec(ArgArray);

			/* Return to the old drawer. */

		if(WBenchMsg)
			CurrentDir(WBenchLock);
	}

		/* Close the libraries. */

	CloseLibrary((struct Library *)DOSBase);
	CloseLibrary(UtilityBase);

		/* If run from Workbench, return the startup message. */

	if(WBenchMsg)
	{
		Forbid();

		ReplyMsg((struct Message *)WBenchMsg);
	}

	if(Error)
		return(RETURN_ERROR);
	else
		return(RETURN_OK);
}

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

STATIC BOOL
HandleInput()
{
	STRPTR			 Result;
	SENDLINE		 OriginalSendLine;
	PhonebookHandle	*PhoneHandle;

	ThisProcess = (struct Process *)FindTask(NULL);

		/* Open the resources we need. */

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

		return(FALSE);
	}

		/* Store the output window name. */

	if(WindowName[0])
		LimitedStrcpy(sizeof(Config->MiscConfig->WindowName),Config->MiscConfig->WindowName,WindowName);

		/* Tell the user what he probably doesn't know yet. */

	if(TermVersion > Config->SerialConfig->LastVersionSaved || (TermVersion == Config->SerialConfig->LastVersionSaved && TermRevision > Config->SerialConfig->LastRevisionSaved))
	{
		BlockWindows();

		ScreenToFront(Window->WScreen);

		DisplayBeep(Window->WScreen);
		DisplayBeep(Window->WScreen);

		ShowInfo(Window,LocaleString(MSG_ATTENTION_PLEASE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_REMINDER_TXT));

		ReleaseWindows();
	}

		/* Give a hint. */

	if(Config->MiscConfig->ProtectiveMode && !FirstInvocation)
	{
		BlockWindows();

		if(Config->SerialConfig->BaudRate >= 4800 && Config->SerialConfig->HandshakingProtocol == HANDSHAKING_NONE && !Config->SerialConfig->DirectConnection)
		{
			ScreenToFront(Window->WScreen);

			if(ShowRequest(Window,LocaleString(MSG_NO_RTSCTS_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Config->SerialConfig->BaudRate))
			{
				SaveConfig(Config,PrivateConfig);

				Config->SerialConfig->HandshakingProtocol = HANDSHAKING_RTSCTS_DSR;

				ConfigSetup();
			}
		}

		if(Config->SerialConfig->BaudRate >= 4800 && Config->ModemConfig->ConnectAutoBaud)
		{
			ScreenToFront(Window->WScreen);

			if(ShowRequest(Window,LocaleString(MSG_AUTOBAUD_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
			{
				SaveConfig(Config,PrivateConfig);

				Config->ModemConfig->ConnectAutoBaud = FALSE;

				ConfigSetup();
			}
		}

		ReleaseWindows();
	}

		/* Don't confuse the user yet, do it later ;-) */

	FirstInvocation = FALSE;

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

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

		if(!(GetSerialStatus() & CIAF_COMCD))
			GoOnline();
	}

		/* Start up iconified? */

	if(DoIconify)
	{
		HandleIconify();

		DoIconify = FALSE;
	}

		/* If we came out of iconified mode, check if were told to quit. */

	if(!MainTerminated)
	{
		if(!KeepQuiet)
			BumpWindow(Window);

			/* Set up the public screen data. */

		PubScreenStuff();

			/* Change program priority. */

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

		BlockWindows();

			/* Load the phone book. */

		if(PhoneHandle = LoadPhonebook(LastPhone))
		{
			DeletePhonebook(GlobalPhoneHandle);
			GlobalPhoneHandle = PhoneHandle;

			strcpy(Config->PhonebookFileName,LastPhone);
		}

			/* Build new menu strip. */

		if(!AttachMenu(NULL))
		{
			if(IntuitionBase)
				ShowRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_MENUS_TXT));

			return(FALSE);
		}
		else
		{
			if(Online)
				SetDialMenu(FALSE);
		}

			/* Show our business card. */

		if(!StartupFile[0] && !Config->CommandConfig->StartupMacro[0] && !KeepQuiet && !(GlobalPhoneHandle->AutoDial || AutoDial))
			ShowAbout(TRUE);

		ReleaseWindows();

			/* Don't do anything silly. */

		KeepQuiet = FALSE;

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

			/* Initialize the modem. */

		OriginalSendLine = ChangeSendLine(SendLineDial);

		SerialCommand(Config->ModemConfig->ModemInit);

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

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

		RestoreSendLine(SendLineDial,OriginalSendLine);

			/* Check if we should dial some entries from the phonebook */
			/* right upon startup */

		if(GlobalPhoneHandle->AutoDial || AutoDial)
		{
			PhoneEntry **Phonebook;
			BOOL DidSomething;
			LONG i;

			Phonebook = GlobalPhoneHandle->Phonebook;
			DidSomething = FALSE;

			for(i = 0 ; i < GlobalPhoneHandle->NumPhoneEntries ; i++)
			{
				if(Phonebook[i]->Header->AutoDial && GlobalPhoneHandle->Phonebook[i]->Header->Number[0])
				{
					MarkDialEntry(GlobalPhoneHandle,Phonebook[i]);

					DidSomething = TRUE;
				}
			}

			if(DidSomething)
			{
				if(AddAllDialEntries(GlobalPhoneHandle))
				{
					DoDial = DIAL_LIST;

					if(GlobalPhoneHandle->AutoExit || AutoExit)
						KeepRedialing = TRUE;
				}
			}
		}
		else
		{
			PhoneEntry **Phonebook;
			LONG HowMany;
			LONG i;

			Phonebook = GlobalPhoneHandle->Phonebook;
			HowMany = 0;

			for(i = 0 ; i < GlobalPhoneHandle->NumPhoneEntries ; i++)
			{
				if(Phonebook[i]->Header->Marked > 0)
					HowMany++;
			}

			if(HowMany > 0)
			{
				LONG j,Counter,Which;

				for(j = 0 ; j < HowMany ; j++)
				{
					Counter	= Which = -1;

					for(i = 0 ; i < GlobalPhoneHandle->NumPhoneEntries ; i++)
					{
						if(Phonebook[i]->Header->Marked > 0)
						{
							if(Counter == -1 || Phonebook[i]->Header->Marked <= Counter)
							{
								Counter	= Phonebook[i]->Header->Marked;
								Which	= i;
							}
						}
					}

					if(Which != -1)
					{
						MarkDialEntry(GlobalPhoneHandle,Phonebook[Which]);
						Phonebook[Which]->Header->Marked = 0;
					}
				}

				AddAllDialEntries(GlobalPhoneHandle);
			}
		}

			/* Process the startup file if any. */

		if(StartupFile[0])
			ActivateJob(MainJobQueue,StartupFileJob);

			/* Go into input loop... */

		do
		{
				/* Dial the list */

			if(DoDial != DIAL_IGNORE)
			{
				DoDial = DIAL_IGNORE;

				if(Online && !IsListEmpty(&RexxDialMsgList))
					DispatchRexxDialMsgList(FALSE);
				else
				{
					BlockWindows();

					ClearDialMenu();

					do
					{
						if(!DialPanel(GlobalPhoneHandle))
						{
							KeepRedialing = FALSE;
							break;
						}
					}
					while(PhonePanel(NULL));

					if(!GlobalPhoneHandle->AutoExit)
						KeepRedialing = FALSE;

					SetRedialMenu();

					ReleaseWindows();
				}
			}

				/* Process the job queue. */

			ProcessJobQueue(MainJobQueue);

				/* Is that it? */

			if(MainTerminated)
			{
				LONG Complaint;

					/* Check if there are ARexx programs running in the background. */

				if(GetLaunchCounter() > 0)
					Complaint = MSG_TERMMAIN_CANNOT_QUIT_YET_TXT;
				else
				{
						/* If we are about to quit, try to close the screen. */

					if(!DeleteDisplay())
						Complaint = MSG_TERMMAIN_CANNOT_CLOSE_SCREEN_YET_TXT;
					else
						Complaint = 0;
				}

					/* Check if we must complain. */

				if(Complaint > 0)
				{
					BlockWindows();
					ShowRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(Complaint));
					ReleaseWindows();

					MainTerminated = FALSE;
				}
			}
			else
			{
					/* Make the user notice not too obvious events. */

				if(FlowInfo.Changed)
					HandleFlowChange();
			}
		}
		while(!MainTerminated);
	}

		/* Send the modem exit command. */

	SendLine = (SENDLINE)SendLineDial;
	SerialCommand(Config->ModemConfig->ModemExit);

		/* Stop I/O processing. */

	ClearSerial();

		/* Say goodbye. */

	LogAction(LocaleString(MSG_TERMMAIN_LOGMSG_PROGRAM_TERMINATED_TXT));
	Say(LocaleString(MSG_TERMMAIN_BYE_BYE_TXT));

	return(TRUE);
}

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

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

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

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

				if(Get_xOFF())
				{
					if(Bell)
						BellSignal();
				}
				else
				{
					if(ConvertLF)
					{
						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;
						}
					}
					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(Get_xOFF())
				{
					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;

				/* Restart in/output. */

			case CHAR_XON:

				if(Config->SerialConfig->xONxOFF)
					Clear_xOFF();

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

				break;

				/* Stop in/output. */

			case CHAR_XOFF:

				if(Config->SerialConfig->xONxOFF)
					Set_xOFF();

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

				break;

				/* Any other character. */

			case CHAR_VANILLA:

				if(Get_xOFF())
				{
					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;
		}
	}
}

STATIC VOID
ClearDialMenu()
{
	if(Menu)
	{
		struct Menu	*ThisMenu;
		struct MenuItem	*Item;

		ClearMenuStrips();

		for(ThisMenu = Menu ; ThisMenu ; ThisMenu = ThisMenu->NextMenu)
		{
			if(Item = ThisMenu->FirstItem)
			{
				do
				{
					if((ULONG)GTMENUITEM_USERDATA(Item) >= DIAL_MENU_LIMIT)
					{
						Item->Flags &= ~CHECKED;

						if(Item->SubItem)
						{
							struct MenuItem *SubItem = Item->SubItem;

							do
								SubItem->Flags &= ~CHECKED;
							while(SubItem = SubItem->NextItem);
						}
					}
				}
				while(Item = Item->NextItem);
			}
		}

		ResetMenuStrips(Menu);
	}
}

STATIC BOOL
DialMenuToDialList()
{
	ClearDialMenu();

	if(QuickDialMax > 0)
	{
		BOOL GotAll;
		LONG i;

		DeleteDialList(GlobalPhoneHandle);

		GotAll = TRUE;

		for(i = 0 ; i < QuickDialMax ; i++)
		{
			if(QuickDialTable[i] != -1)
			{
				if(GotAll)
					GotAll = AddDialEntry(GlobalPhoneHandle,GlobalPhoneHandle->Phonebook[QuickDialTable[i] - DIAL_MENU_LIMIT],NULL);

				QuickDialTable[i] = -1;
			}
		}

		QuickDialMax = 0;

		if(GotAll)
			return(TRUE);

		DeleteDialList(GlobalPhoneHandle);
	}

	return(FALSE);
}

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

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

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

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

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

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

		/* Enter the selected entries from the quick dial menu? */

	if(CheckDialMenu)
	{
		CheckDialMenu = FALSE;

		if(DialMenuToDialList())
			DoDial = DIAL_LIST;
	}
}

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

STATIC VOID
HandleIconify()
{
	BOOL Released = FALSE;

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

	BlockWindows();

		/* Open workbench.library. */

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

		if(IconBase)
		{
			UBYTE LocalBuffer[MAX_FILENAME_LENGTH];
			struct DiskObject *Icon;

			strcpy(LocalBuffer,Config->PathConfig->DefaultStorage);

			if(AddPart(LocalBuffer,"term_SleepIcon",sizeof(LocalBuffer)))
				Icon = GetDiskObject(LocalBuffer);
			else
				Icon = NULL;

			if(!Icon)
				Icon = GetDiskObject("PROGDIR:term_SleepIcon");

			if(!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 = AddAppIconA(0,0,TermIDString,IconPort,NULL,Icon,NULL))
					{
						struct AppMessage *AppMessage;

							/* Release the window. */

						Released = TRUE;
						ReleaseWindows();

							/* Close the display. full stop. */

						if(DeleteDisplay())
						{
							ULONG Signals;

								/* Reset and release the serial driver. */

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

								/* Wait for double-click. */

							IconTerminated = FALSE;

							do
							{
								Signals = Wait(PORTMASK(IconPort) | SIG_REXX | SIGBREAKF_CTRL_F);

									/* Received a double-click? */

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

									while(AppMessage = (struct AppMessage *)GetMsg(IconPort))
									{
										IconTerminated = TRUE;

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

									/* Wake up if ARexx command received. */

								if(Signals & SIG_REXX)
									while(RunJob(RexxJob));

									/* Generic wakeup signal. */

								if(Signals & SIGBREAKF_CTRL_F)
									IconTerminated = TRUE;

									/* Ready to leave? */

								if(IconTerminated)
								{
										/* Open the serial driver. */

									if(Config->MiscConfig->ReleaseDevice)
									{
										if(!CreateSerial(LocalBuffer,sizeof(LocalBuffer)))
										{
											switch(ShowRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_ICONIFY_IGNORE_QUIT_TXT),LocalBuffer))
											{
												case 0:

													MainTerminated = TRUE;
													break;

												case 1:

													IconTerminated = FALSE;
													break;
											}
										}
									}
								}

									/* Still ready to leave? */

								if(IconTerminated && !MainTerminated)
								{
									STRPTR String;

										/* Create the display. */

									if(String = CreateDisplay(TRUE,FALSE))
									{
										switch(ShowRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_ICONIFY_QUIT_TXT),String))
										{
											case 0:

												MainTerminated = TRUE;
												break;

											case 1:

													/* Reset and release the serial driver. */

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

												IconTerminated = FALSE;
												break;
										}
									}
									else
									{
										BumpWindow(Window);

										PubScreenStuff();
									}
								}
							}
							while(!IconTerminated);
						}
						else
						{
							BlockWindows();

							ShowRequest(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((struct Message *)AppMessage);
					}
					else
						ShowRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_ADD_APPLICATION_ICON_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

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

				FreeDiskObject(Icon);
			}
			else
				ShowRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_TOOL_ICON_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
		}
		else
			ShowRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_OPEN_ICON_LIBRARY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
	}
	else
		ShowRequest(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.
	 */

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

		/* Execute logoff macro. */

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

	StopCall(FALSE);

		/* Keep the current connection costs */

	DisplayPay = StopAccountant();

	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;

	if(!Config->SerialConfig->CheckCarrier || Config->SerialConfig->DirectConnection)
	{
		ObtainSemaphore(&OnlineSemaphore);
		Online = WasOnline = FALSE;
		ReleaseSemaphore(&OnlineSemaphore);
	}

	SetActivePattern(NULL);
	SetActiveEntry(GlobalPhoneHandle,NULL);

	DisarmLimit();

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

		/* Display the connection cost next time control */
		/* passes through the main loop. */

	ActivateJob(MainJobQueue,DisplayCostJob);

	DisplayHangup = Hangup;

	if(Config->ModemConfig->RedialAfterHangup || KeepRedialing)
	{
		if(GlobalPhoneHandle->DialList)
		{
			if(!IsListEmpty(GlobalPhoneHandle->DialList))
			{
				ObtainSemaphore(&OnlineSemaphore);
				Online = WasOnline = FALSE;
				ReleaseSemaphore(&OnlineSemaphore);

				DoDial = DIAL_LIST;
			}
			else
			{
				if(KeepRedialing)
				{
					KeepRedialing = FALSE;

					if(GlobalPhoneHandle->AutoExit)
						MainTerminated = TRUE;
				}
			}
		}
		else
			KeepRedialing = FALSE;
	}
}

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

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

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

			if(FlowInfo.NoCarrier)
				SetOnlineState(FALSE,0);
		}
	}
	else
	{
		if(FlowInfo.Voice)
		{
			UBYTE DateTimeBuffer[256];

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

			WakeUp(Window,SOUND_VOICE);

			ConPrintf(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,DateTimeBuffer,sizeof(DateTimeBuffer),FALSE);

			WakeUp(Window,SOUND_RING);

			ConPrintf(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 && !Config->SerialConfig->DirectConnection)
			{
					/* No carrier signal present? */

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

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

				SetOnlineState(TRUE,0);

				BaudPending = FALSE;

				SetDialMenu(FALSE);
			}
		}
	}

		/* Check if we are to prompt the user for
		 * file transfer.
		 */

	if(FlowInfo.Signature)
	{
		LONG Type = FlowInfo.Signature - SCAN_SIGDEFAULTUPLOAD + TRANSFERSIG_DEFAULTUPLOAD;

		BlockWindows();

		switch(Type)
		{
			case TRANSFERSIG_DEFAULTUPLOAD:

				switch(UploadPanel(TRUE))
				{
					case UPLOAD_TEXT:

#ifdef BUILTIN_ZMODEM
						if(UseInternalZModem)
						{
							InternalZModemTextUpload();
							break;
						}
#endif	/* BUILTIN_ZMODEM */

						StartSendXPR_AskForFile(TRANSFER_TEXT,TRUE);
						break;

					case UPLOAD_BINARY:

#ifdef BUILTIN_ZMODEM
						if(UseInternalZModem)
						{
							InternalZModemBinaryUpload();
							break;
						}
#endif	/* BUILTIN_ZMODEM */

						StartSendXPR_AskForFile(TRANSFER_BINARY,TRUE);
						break;

					case UPLOAD_ABORT:

						CancelZModem();
						break;

					case UPLOAD_BINARY_FROM_LIST:

						HandleUpload(UPLOAD_BINARY);
						break;

					case UPLOAD_TEXT_FROM_LIST:

						HandleUpload(UPLOAD_TEXT);
						break;
				}

				break;

			case TRANSFERSIG_DEFAULTDOWNLOAD:

#ifdef BUILTIN_ZMODEM
				if(UseInternalZModem)
				{
					ZReceive();
					break;
				}
#endif	/* BUILTIN_ZMODEM */

				switch(UploadPanel(FALSE))
				{
					case UPLOAD_TEXT:

						StartReceiveXPR_AskForFile(TRANSFER_TEXT,TRUE);
						break;

					case UPLOAD_BINARY:

						StartReceiveXPR_AskForFile(TRANSFER_BINARY,TRUE);
						break;
				}

				break;

			case TRANSFERSIG_ASCIIUPLOAD:

				if(ChangeProtocol(Config->TransferConfig->ASCIIUploadLibrary,Config->TransferConfig->ASCIIUploadType))
					StartSendXPR_AskForFile(TRANSFER_ASCII,TRUE);

				ResetProtocol();

				break;

			case TRANSFERSIG_ASCIIDOWNLOAD:

				if(ChangeProtocol(Config->TransferConfig->ASCIIDownloadLibrary,Config->TransferConfig->ASCIIDownloadType))
					StartReceiveXPR_AskForFile(TRANSFER_ASCII,TRUE);

				ResetProtocol();

				break;

			case TRANSFERSIG_TEXTUPLOAD:

#ifdef BUILTIN_ZMODEM
				if(UseInternalZModem)
				{
					InternalZModemTextUpload();
					break;
				}
#endif	/* BUILTIN_ZMODEM */

				if(ChangeProtocol(Config->TransferConfig->TextUploadLibrary,Config->TransferConfig->TextUploadType))
					StartSendXPR_AskForFile(TRANSFER_TEXT,TRUE);

				ResetProtocol();

				break;

			case TRANSFERSIG_TEXTDOWNLOAD:

#ifdef BUILTIN_ZMODEM
				if(UseInternalZModem)
				{
					ZReceive();
					break;
				}
#endif	/* BUILTIN_ZMODEM */

				if(ChangeProtocol(Config->TransferConfig->TextDownloadLibrary,Config->TransferConfig->TextDownloadType))
					StartReceiveXPR_AskForFile(TRANSFER_TEXT,TRUE);

				ResetProtocol();

				break;

			case TRANSFERSIG_BINARYUPLOAD:

#ifdef BUILTIN_ZMODEM
				if(UseInternalZModem)
				{
					InternalZModemBinaryUpload();
					break;
				}
#endif	/* BUILTIN_ZMODEM */

				if(ChangeProtocol(Config->TransferConfig->BinaryUploadLibrary,Config->TransferConfig->BinaryUploadType))
					StartSendXPR_AskForFile(TRANSFER_BINARY,TRUE);

				ResetProtocol();

				break;

			case TRANSFERSIG_BINARYDOWNLOAD:

#ifdef BUILTIN_ZMODEM
				if(UseInternalZModem)
				{
					ZReceive();
					break;
				}
#endif	/* BUILTIN_ZMODEM */

				if(ChangeProtocol(Config->TransferConfig->BinaryDownloadLibrary,Config->TransferConfig->BinaryDownloadType))
					StartReceiveXPR_AskForFile(TRANSFER_BINARY,TRUE);

				ResetProtocol();

				break;
		}

		ReleaseWindows();
	}

	ResetDataFlowFilter();
}

	/* FullHangup():
	 *
	 *	In a nutshell, do the full work required to hang up the line.
	 */

STATIC VOID
FullHangup(BOOL ForceIt)
{
	BlockWindows();

	DispatchRexxDialMsgList(FALSE);

	HangUp();

	ReleaseWindows();

	if(Config->SerialConfig->CheckCarrier && !ForceIt && !Config->SerialConfig->DirectConnection)
		HungUp = TRUE;
	else
	{
		SetOnlineState(FALSE,0);

		HandleOnlineCleanup(TRUE);
	}
}

	/* AskDial(struct Window *Parent):
	 *
	 *	This is called when the user is about to start dialing. If the
	 *	dial button/menu item is available with the protective mode
	 *	enabled, a message will be displayed, asking if the line
	 *	should be hung up before proceeding.
	 */

STATIC BOOL
AskDial(struct Window *Parent)
{
	if(!DialItemsAvailable)
	{
		if(ShowRequest(Parent,LocaleString(MSG_CANNOT_DIAL_BECAUSE_TXT),LocaleString(MSG_DIAL_CANCEL_TXT)))
			FullHangup(TRUE);
		else
			return(FALSE);
	}

	return(TRUE);
}

	/* GoOnline():
	 *
	 *	Go into online state.
	 */

STATIC VOID
GoOnline()
{
	SetOnlineState(TRUE,0);

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

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

	SendStartup		= FALSE;

	DisarmLimit();

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

	SetActivePattern(NULL);
	SetActiveEntry(GlobalPhoneHandle,NULL);

	SetDialMenu(FALSE);
}

STATIC VOID
ReadyToDial(struct DataDialMsg *DialMsg)
{
	struct GenericDialNode *Node;
	PhoneEntry **Phonebook;
	BOOL DidSomething;

	DidSomething = FALSE;

	/* Careful, this can be NULL (and is most of the time). */
	if(DialMsg->DialMsg)
	{
		AddTail(&RexxDialMsgList,(struct Node *)DialMsg->DialMsg);
		DialMsg->DialMsg = NULL;
	}

	Phonebook = GlobalPhoneHandle->Phonebook;

	while(Node = (struct GenericDialNode *)RemHead(DialMsg->DialList))
	{
		if(Node->Index != -1)
		{
			if(Node->Index >= 0 && Node->Index < GlobalPhoneHandle->NumPhoneEntries)
				DidSomething |= AddDialEntry(GlobalPhoneHandle,Phonebook[Node->Index],NULL);
		}
		else
		{
			if(Node->Number != NULL)
				DidSomething |= AddDialEntry(GlobalPhoneHandle,NULL,Node->Number);
			else
			{
				LONG i;

				for(i = 0 ; i < GlobalPhoneHandle->NumPhoneEntries ; i++)
				{
					if(!Stricmp(Phonebook[i]->Header->Name,Node->Node.ln_Name))
					{
						if(Phonebook[i]->Header->Number[0])
							DidSomething |= AddDialEntry(GlobalPhoneHandle,Phonebook[i],NULL);
					}
				}
			}
		}

		FreeVecPooled(Node);
	}

	if(DidSomething)
		DoDial = DIAL_LIST;
}

STATIC VOID
HandleUpload(UBYTE Type)
{
	LockGenericList(GenericListTable[GLIST_UPLOAD]);

	if(GenericListCount(GenericListTable[GLIST_UPLOAD]) > 0)
	{
		struct FileTransferInfo *Info;

		if(!(Info = AllocFileTransferInfo()))
			UnlockGenericList(GenericListTable[GLIST_UPLOAD]);
		else
		{
			LONG FilesFound;
			APTR OldPtr;
			struct Node *Node;
			BPTR FileLock;
			D_S(struct FileInfoBlock,FileInfo);

			FilesFound = 0;

			DisableDOSRequesters(&OldPtr);

			for(Node = ((struct List *)GenericListTable[GLIST_UPLOAD])->lh_Head ; Node->ln_Succ ; Node = Node->ln_Succ)
			{
				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->TransferConfig->TransferIcons)
							{
								UBYTE LocalBuffer[MAX_FILENAME_LENGTH];
								BPTR InfoLock;

								LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,"%s.info",Node->ln_Name);

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

									UnLock(InfoLock);
								}
							}
						}
					}

					UnLock(FileLock);
				}
			}

			ClearGenericList(GenericListTable[GLIST_UPLOAD],TRUE);

			UnlockGenericList(GenericListTable[GLIST_UPLOAD]);

			EnableDOSRequesters(OldPtr);

			if(FilesFound)
			{
				BlockWindows();

				ReadyFileTransferInfo(Info,FALSE);

				FileTransferInfo = Info;

				StartSendXPR_FromList(Type == UPLOAD_BINARY ? TRANSFER_BINARY : TRANSFER_TEXT,TRUE);

				ReleaseWindows();
			}
			else
				FreeFileTransferInfo(Info);
		}
	}
	else
	{
		UnlockGenericList(GenericListTable[GLIST_UPLOAD]);

		StartSendXPR_AskForFile(Type == UPLOAD_BINARY ? TRANSFER_BINARY : TRANSFER_TEXT,TRUE);
	}
}

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

STATIC VOID
LocalReleaseSerial()
{
	BOOL Continue,SerialClosed;
	APTR OldPtr;

	DB(kprintf("in: LocalReleaseSerial()\n"));

	ChangeWindowPtr(&OldPtr,(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;

	DB(kprintf("blockwindows\n"));

	BlockWindows();

		/* Prevent catastrophes! */

	if(!Config->MiscConfig->ProtectiveMode)
		Continue = TRUE;
	else
	{
		if(Online && !SerialClosed)
		{
			if(!ShowRequest(Window,LocaleString(MSG_TERMMAIN_YOU_ARE_STILL_ONLINE_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
				Continue = FALSE;
			else
				Continue = TRUE;
		}
		else
			Continue = TRUE;
	}

	DB(kprintf("continue=%ld serialclosed=%ld\n",Continue,SerialClosed));

	if(Continue)
	{
		if(SerialClosed)
		{
			DB(kprintf("reopenserial\n"));

			ReopenSerial();
		}
		else
		{
			DB(kprintf("clearserial\n"));
			ClearSerial();

			DB(kprintf("deleteserial\n"));
			DeleteSerial();

			switch(ShowRequest(Window,LocaleString(MSG_TERMMAIN_UNIT_RESET_AND_RELEASED_TXT),LocaleString(MSG_TERMMAIN_RETURN_QUIT_TXT),Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber))
			{
				case 0:

					MainTerminated = TRUE;
					break;

				case 1:

					ReopenSerial();
					break;

				case 2:

					ActivateJob(MainJobQueue,IconifyJob);
					break;
			}
		}
	}

	RestoreWindowPtr(OldPtr);

	ReleaseWindows();

	DB(kprintf("out: LocalReleaseSerial()\n"));
}

	/* HandleKeyboardInput():
	 *
	 *	Process the keyboard input.
	 */

STATIC VOID
HandleKeyboardInput(UBYTE Char,UWORD Code,ULONG Qualifier,STRPTR InputBuffer,LONG Len)
{
		/* 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;
		LONG	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
				{
					LONG QualType;

						/* Find the appropriate qualifier. */

					if(Qualifier & SHIFT_KEY)
						QualType = 1;
					else
					{
						if(Qualifier & ALT_KEY)
							QualType = 2;
						else
						{
							if(Qualifier & CONTROL_KEY)
								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 & CONTROL_KEY)
					SerialCommand(MacroKeys->Keys[3][Char - FN1]);
				else
				{
					if(Qualifier & ALT_KEY)
						SerialCommand(MacroKeys->Keys[2][Char - FN1]);
					else
					{
						if(Qualifier & SHIFT_KEY)
							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 & SHIFT_KEY))
				{
					RememberInputText("\r",1);

					Len = 0;

					PopStatus();
					PushStatus(STATUS_RECORDING_LINE);

					RecordingLine = TRUE;

					RememberResetInput();

					RememberOutput = FALSE;
					RememberInput = TRUE;

					CheckItem(MEN_RECORD_LINE,TRUE);
				}

				break;
		}

			/* Any characters to send? */

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

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

BOOL
HandleSerialCheckJob(JobNode *UnusedJob)
{
		/* Attempt to lock the serial device? */

	if(PollODU)
	{
			/* We don't want to poll too often */

		if(PollODUCount++ >= (5 + ROUTINE_CHECK_INTERVAL - 1) / ROUTINE_CHECK_INTERVAL)
		{
			PollODUCount = 0;

				/* Still supporting the locking protocol? */

			if(Config->SerialConfig->UseOwnDevUnit)
			{
				BlockWindows();

					/* Give it a try */

				if(LockDevice(Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber,NULL,0))
				{
						/* Check */

					ReopenSerial();

					PollODU = FALSE;
				}

				ReleaseWindows();
			}
			else
				PollODU = FALSE;
		}
	}

		/* Take a look at the carrier signal. */

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

			/* Still online? */

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

			if(Status & CIAF_COMCD)
				SetOnlineState(FALSE,0);
		}
		else
		{
				/* Is the carrier detect signal
				 * present?
				 */

			if(!(Status & CIAF_COMCD))
				GoOnline();
		}
	}

		/* Check online time limit. */

	if(CheckLimit())
		LaunchRexxAsync(LimitMacro);

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

	if(BufferFlushCount++ >= (60 + ROUTINE_CHECK_INTERVAL - 1) / ROUTINE_CHECK_INTERVAL)
	{
		BufferFlushCount = 0;

			/* Flush the capture file. */

		if(FileCapture)
			BufferFlush(FileCapture);
	}

	return(FALSE);
}

	/* HandleQueueJob(JobNode *UnusedJob):
	 *
	 *	Process the special message queue.
	 */

BOOL
HandleQueueJob(JobNode *UnusedJob)
{
	struct DataMsg *Item;

	if(Item = GetMsgItem(SpecialQueue))
	{
		WORD OldEcho,Type;

		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[256];
					LONG Len;

					if((Len = GetClip(InputBuffer,sizeof(InputBuffer) - 1)) < 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,Config->ClipConfig->ConvertLF);
					}
				}

				break;

				/* Start an upload */

			case DATAMSGTYPE_UPLOAD:

				Type = Item->Size;

				DeleteMsgItem((struct MsgItem *)Item);
				Item = NULL;

				HandleUpload(Type);
				break;

				/* Call a menu item */

			case DATAMSGTYPE_MENU:

				HandleMenuCode(NULL,(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((struct MsgItem *)Item);

					Item = NULL;

						/* Prepare to wait... */

					WaitForHandshake();

						/* Pick up the queue */

					RestartSerial();

					Permit();

					ReleaseWindows();
				}

				break;

				/* Discard current buffer contents */

			case DATAMSGTYPE_CLEARBUFFER:

				FreeBuffer();
				break;

				/* Redial current dial list */

			case DATAMSGTYPE_REDIAL:

				if(!Online)
					DoDial = DIAL_LIST;

				break;

				/* Hang up the line */

			case DATAMSGTYPE_HANGUP:

				FullHangup(FALSE);
				break;

				/* Go to online state */

			case DATAMSGTYPE_GOONLINE:

				if(!Online)
					GoOnline();

				break;

				/* Dial a list of numbers */

			case DATAMSGTYPE_DIAL:

				ReadyToDial((struct DataDialMsg *)Item);
				break;

				/* Output data as if it had come from the main window. */

			case DATAMSGTYPE_WRITESTRING:

				SendInputTextBuffer(Item->Data,Item->Size,TRUE,TRUE);
				break;

				/* Output data as if it had come from the main window. */

			case DATAMSGTYPE_WRITESTRING_NOECHO:

				OldEcho = Config->SerialConfig->Duplex;

				Config->SerialConfig->Duplex = DUPLEX_FULL;

				SendInputTextBuffer(Item->Data,Item->Size,TRUE,TRUE);

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

		if(Item)
			DeleteMsgItem((struct MsgItem *)Item);

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

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

BOOL
HandleOwnDevUnitJob(JobNode *UnusedJob)
{
	DB(kprintf("handle ODU\n"));

	if(!Online || !ReadPort || (Online && Config->SerialConfig->ReleaseODUWhenOnline))
	{
		if(Config->SerialConfig->SatisfyODURequests == ODU_RELEASE)
		{
			DB(kprintf("ODU release\n"));
			LocalReleaseSerial();
		}

		if(Config->SerialConfig->SatisfyODURequests == ODU_WAIT)
		{
			BOOL Continue,SerialClosed;
			APTR OldPtr;

			DB(kprintf("ODU wait\n"));

			ChangeWindowPtr(&OldPtr,(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 && !Config->SerialConfig->ReleaseODUWhenOnline)
			{
				if(!ShowRequest(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)
				{
					ClearSerial();

					DeleteSerial();
				}
			}

			RestoreWindowPtr(OldPtr);

			ReleaseWindows();

				/* Start polling for the device to become */
				/* available again */

			PollODU = TRUE;
		}
	}

	DB(kprintf("ODU done\n"));

	return(FALSE);
}

	/* HandleWindowJob(JobNode *UnusedJob):
	 *
	 *	Just makes a call to HandleWindow().
	 */

BOOL
HandleWindowJob(JobNode *UnusedJob)
{
	return(HandleWindow());
}

	/* HandleWindowAndXEMJob(JobNode *UnusedJob):
	 *
	 *	Calls both HandleXEM() and HandleWindow().
	 */

BOOL
HandleWindowAndXEMJob(JobNode *UnusedJob)
{
	HandleXEM();

	return(HandleWindow());
}

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

BOOL
HandleWindow()
{
	STATIC ULONG	ClickSeconds,ClickMicros;
	STATIC ULONG	LastSeconds,LastMicros;
	STATIC BOOL		TestingDoubleClick;

	struct IntuiMessage	*Message;
	ULONG				 MsgClass,Code,Qualifier,Seconds,Micros;
	LONG				 MouseX,MouseY,Len,GadgetID;
	struct Gadget		*Gadget;
	UBYTE				 Char,InputBuffer[256];
	struct Window		*IDCMPWindow;
	BOOL				 Result,WindowJustActivated;

	Result				= FALSE;
	WindowJustActivated	= FALSE;

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

	if(ClipInput)
	{
		LONG Length = GetClip(InputBuffer,sizeof(InputBuffer) - 1);

		if(Length < 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(Length > 0)
				SendInputTextBuffer(InputBuffer,Length,FALSE,Config->ClipConfig->ConvertLF);

			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)
				WindowJustActivated = TRUE;
		}

		LastSeconds	= Seconds;
		LastMicros	= Micros;

			/* Pick up the pieces. */

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

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

		IDCMPWindow	= Message->IDCMPWindow;

		Len		= 0;
		Char	= 0;

		switch(MsgClass)
		{
			case IDCMP_IDCMPUPDATE:

				GadgetID = GetTagData(GA_ID,0,(struct TagItem *)Gadget);
				break;

			case IDCMP_GADGETUP:
			case IDCMP_GADGETDOWN:

				GadgetID = Gadget->GadgetID;
				break;

			case IDCMP_RAWKEY:

					/* Perform key conversion. */

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

				/* Falls through to... */

			default:

				GadgetID = 0;
				break;
		}

		ReplyMsg((struct Message *)Message);

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

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

				case IDCMP_CLOSEWINDOW:

					CloseFastWindow();
					return(TRUE);

					/* Gadget or window size change event. */

				case IDCMP_GADGETUP:
				case IDCMP_NEWSIZE:

					HandleFastWindowGadget(MsgClass,Code);
					return(TRUE);
			}
		}

			/* Status window activated? */

		if(IDCMPWindow == StatusWindow)
		{
			switch(MsgClass)
			{
				case IDCMP_ACTIVEWINDOW:

					if(!Config->ScreenConfig->SplitStatus)
						NormalCursor();

					break;

				case IDCMP_CLOSEWINDOW:

					ShakeHands((struct Task *)StatusProcess,SIG_CLOSEWINDOW);

					ClearMenuStrip(StatusWindow);
					CloseWindowSafely(StatusWindow);

					StatusWindow = NULL;
					break;
			}
		}

			/* What about the matrix window? */

		if(IDCMPWindow == MatrixWindow)
		{
			if(DispatchMatrixWindow(&MsgClass,Code,Qualifier,Char))
				CloseMatrixWindow();
		}

			/* Main window message? */

		if(IDCMPWindow == Window)
		{
			switch(MsgClass)
			{
				case IDCMP_GADGETUP:

					if(GadgetID == CHAT_GadgetID)
						HandleChatGadget(Code);

					break;

				case IDCMP_GADGETDOWN:

					if(GadgetID == CHAT_GadgetID)
						MarkChatGadgetAsActive();

					break;

				case IDCMP_INACTIVEWINDOW:

					WindowMarkerInterrupt();

					GhostCursor();

					break;

				case IDCMP_ACTIVEWINDOW:

						/* Take care of the chat gadget if necessary */

					ActivateChat(TRUE);

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

					ForceStatusUpdate();

					HandleMenuCode(NULL,MEN_RESET_TERMINAL,Qualifier);

						/* Take care of the chat gadget if necessary */

					ActivateChat(TRUE);

					TTYResize();

					break;

				case IDCMP_CLOSEWINDOW:

					HandleMenuCode(NULL,MEN_QUIT,Qualifier);
					break;

				case IDCMP_MOUSEMOVE:

					WindowMarkerMoveMouse();
					break;

				case IDCMP_MOUSEBUTTONS:

					if(Code == SELECTUP)
						ActivateChat(TRUE);

					if((!WindowJustActivated || Code != SELECTDOWN) && (!XEmulatorBase || Config->TerminalConfig->EmulationMode != EMULATION_EXTERNAL))
					{
						switch(Code)
						{
							case SELECTUP:

								WindowMarkerInterrupt();
								break;

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

								if(Qualifier & CONTROL_KEY)
								{
									LONG FirstX,FirstY;

									FirstX = (MouseX * CharCellDenominator) / (TextFontWidth * CharCellNominator);
									FirstY = MouseY / TextFontHeight;

									if(FirstX < RasterWidth && FirstY < RasterHeight)
									{
										UBYTE LocalChar[2];

										SafeObtainSemaphoreShared(&RasterSemaphore);

										LocalChar[0] = Raster[FirstY * RasterWidth + FirstX];

										ReleaseSemaphore(&RasterSemaphore);

										if(LocalChar[0])
										{
											LONG Len;

											if(Qualifier & SHIFT_KEY)
											{
												LocalChar[1] = '\r';
												Len = 2;
											}
											else
												Len = 1;

											SendInputTextBuffer(LocalChar,Len,TRUE,TRUE);
										}
									}

									return(TRUE);
								}

								if((Qualifier & ALT_KEY) && (Qualifier & IEQUALIFIER_LEFTBUTTON))
								{
									LONG DeltaX,DeltaY;

									ObtainSemaphore(&TerminalSemaphore);

									DeltaX = (MouseX * CharCellDenominator) / (TextFontWidth * CharCellNominator)  - 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);
								}

								if(TestingDoubleClick)
								{
									ULONG CurrentSeconds,CurrentMicros;

									TestingDoubleClick = FALSE;

									CurrentTime(&CurrentSeconds,&CurrentMicros);

									if(DoubleClick(ClickSeconds,ClickMicros,CurrentSeconds,CurrentMicros))
									{
										WindowMarkWord();

										return(TRUE);
									}
								}
								else
								{
									TestingDoubleClick = TRUE;

									CurrentTime(&ClickSeconds,&ClickMicros);
								}

								WindowMarkerStart(Qualifier);
								break;
						}
					}

					break;
			}
		}

			/* Now for general information. */

		switch(MsgClass)
		{
			case IDCMP_REFRESHWINDOW:

				BeginRefresh(IDCMPWindow);
				EndRefresh(IDCMPWindow,TRUE);
				break;

			case IDCMP_RAWKEY:

				HandleKeyboardInput(Char,Code,Qualifier,InputBuffer,Len);
				break;

				/* A menu item was selected. */

			case IDCMP_MENUPICK:

				HandleMenu(Code,Qualifier);

					/* Take care of the chat gadget if necessary */

				ActivateChat(TRUE);

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

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

VOID
HandleMenuCode(struct MenuItem *ThisItem,ULONG Code,ULONG Qualifier)
{
	struct FileRequester	*FileRequest;
	UBYTE					 DummyBuffer[MAX_FILENAME_LENGTH];

	struct Window			*ReqWindow;
	struct EasyStruct		 Easy;

	BPTR					 SomeFile;
	APTR					 OldPtr;

	BOOL					 Checked;

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

		case MEN_SAVE_AS_PICTURE:

			BlockWindows();

			DummyBuffer[0] = 0;

			if(FileRequest = SaveFile(Window,LocaleString(MSG_TERMMAIN_SAVE_SCREEN_IFF_TXT),NULL,NULL,DummyBuffer,sizeof(DummyBuffer)))
			{
				FreeAslRequest(FileRequest);

				if(!SaveWindow(DummyBuffer,Window))
					ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
			}

			ReleaseWindows();

			break;

			/* Save screen as ASCII file. */

		case MEN_SAVE_AS_TEXT:

			BlockWindows();

			DummyBuffer[0] = 0;

			if(FileRequest = SaveFileOverwrite(Window,LocaleString(MSG_TERMMAIN_SAVE_SCREEN_ASCII_TXT),NULL,NULL,DummyBuffer,sizeof(DummyBuffer)))
			{
				LONG Error = 0;

				FreeAslRequest(FileRequest);

				SomeFile = NULL;

				if(GetFileSize(DummyBuffer))
				{
					switch(ShowRequest(Window,LocaleString(MSG_GLOBAL_FILE_ALREADY_EXISTS_TXT),LocaleString(MSG_GLOBAL_CREATE_APPEND_CANCEL_TXT),DummyBuffer))
					{
						case 0:

							SetIoErr(0);
							break;

						case 1:

							SomeFile = Open(DummyBuffer,MODE_NEWFILE);
							break;

						case 2:

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

				if(SomeFile)
				{
					UBYTE *Buffer;
					LONG i,j;

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

						j = RasterWidth - 1;

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

			ReleaseWindows();

			break;

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

		case MEN_PRINT_SCREEN:

			BlockWindows();

			if(RasterEnabled)
				PrintSomething(PRINT_SCREEN);
			else
				ShowRequest(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(FALSE);

			break;

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

		case MEN_CAPTURE_TO_RAW_FILE:

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

			break;

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

		case MEN_CAPTURE_TO_PRINTER:

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

			break;

			/* Iconify the program. */

		case MEN_ICONIFY:

			if(Config->MiscConfig->ProtectiveMode)
			{
				if(Online && Config->MiscConfig->ReleaseDevice && !(Qualifier & SHIFT_KEY))
				{
					BlockWindows();

					if(!ShowRequest(Window,LocaleString(MSG_TERMMAIN_YOU_ARE_STILL_ONLINE_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT)))
					{
						ReleaseWindows();

						break;
					}

					ReleaseWindows();
				}
			}

			ActivateJob(MainJobQueue,IconifyJob);

			break;

			/* Say who we are. */

		case MEN_ABOUT:

			if(Qualifier & IEQUALIFIER_LSHIFT)
				StartTerminalTest(Qualifier);
			else
			{
				BlockWindows();
				ShowAbout(FALSE);
				ReleaseWindows();
			}

			break;

			/* Terminate the program. */

		case MEN_QUIT:

			if((Qualifier & SHIFT_KEY) || !Config->MiscConfig->ProtectiveMode)
				MainTerminated = TRUE;
			else
			{
				LONG OldLen,Len;
				STRPTR Buffer;

				OldLen = Len = strlen(LocaleString(MSG_TERMMAIN_REALLY_QUIT_TXT)) + 3;

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

				ChangeWindowPtr(&OldPtr,(APTR)Window);

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

						if(Online)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_PROGRAM_IS_STILL_ONLINE_TXT));

						if(BufferChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_REVIEW_BUFFER_NOT_SAVED_TXT));

						if(ConfigChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_CONFIGURATION_HAS_BEEN_CHANGED_TXT));

						if(PhonebookChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_PHONEBOOK_NOT_SAVED_TXT));

						if(TranslationChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_TRANSLATION_TABLES_CHANGED_TXT));

						if(MacroChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_MACRO_KEYS_CHANGED_TXT));

						if(CursorKeysChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_CURSOR_KEYS_CHANGED_TXT));

						if(FastMacrosChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_FAST_MACROS_CHANGED_TXT));

						if(HotkeysChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_HOTKEYS_CHANGED_TXT));

						if(SpeechChanged)
							FormatAppend(Buffer," · %s\n",LocaleString(MSG_WAIT_SPEECH_SETTINGS_CHANGED_TXT));

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

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

				RestoreWindowPtr(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 & SHIFT_KEY)
					ClipXerox = TRUE;
			}
			else
				ClipInput = FALSE;

			break;

		case MEN_COPY:

			WindowMarkerTransfer(Qualifier);
			break;

		case MEN_CLEAR:

			WindowMarkerStop();
			break;

		case MEN_SELECT_ALL:

			WindowMarkerSelectAll();
			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))
			{
				if(AmigaDOSCommandBuffer[0])
					LaunchCommandAsync(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))
			{
				if(ARexxCommandBuffer[0])
					LaunchRexxAsync(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;

						PushStatus(STATUS_RECORDING);

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

					RememberOutput = FALSE;
					RememberInput = FALSE;

					Recording = FALSE;
					RecordingLine = FALSE;

					PopStatus();

					OffItem(MEN_RECORD_LINE);
				}
			}

			break;

		case MEN_RECORD_LINE:

			if(Recording)
			{
				if(GetItem(MEN_RECORD))
				{
					if(!RecordingLine)
					{
						PopStatus();
						PushStatus(STATUS_RECORDING_LINE);

						RecordingLine = TRUE;

						RememberResetInput();

						RememberOutput = FALSE;
						RememberInput = TRUE;
					}
				}
				else
				{
					if(RecordingLine)
					{
						PopStatus();
						PushStatus(STATUS_RECORDING);

						RememberSpill();

						RecordingLine = FALSE;

						RememberOutput = TRUE;
						RememberInput = FALSE;
					}
				}
			}

			break;

		case MEN_DISABLE_TRAPS:

			Checked = GetItem(MEN_DISABLE_TRAPS);

			if(Checked || GenericListCount(GenericListTable[GLIST_TRAP]) == 0)
				WatchTraps = FALSE;
			else
				WatchTraps = TRUE;

			break;

			/* Edit the trap settings? */

		case MEN_EDIT_TRAPS:

			BlockWindows();

			TrapPanelConfig(Config,&TrapsChanged);

			CheckItem(MEN_DISABLE_TRAPS,!WatchTraps);

			ReleaseWindows();

			break;

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

		case MEN_PHONEBOOK:

			BlockWindows();

			if(PhonePanel(Qualifier))
			{
				if(AskDial(Window))
					DoDial = DIAL_LIST;
			}

			ReleaseWindows();

			break;

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

		case MEN_REDIAL:

			BlockWindows();

				/* If the modem is still online, provide help. */

			if(AskDial(Window))
				DoDial = DIAL_LIST;

			ReleaseWindows();

			break;

			/* Dial a single number. */

		case MEN_DIAL_NUMBER:

			BlockWindows();

				/* If the modem is still online, provide help. */

			if(AskDial(Window))
			{
				if(GetString(FALSE,FALSE,0,LocaleString(MSG_TERMMAIN_ENTER_PHONE_NUMBER_TXT),DialNumberBuffer))
				{
					if(DialNumberBuffer[0])
					{
							/* Remove all entries from the list. */

						DeleteDialList(GlobalPhoneHandle);

						if(AddDialEntry(GlobalPhoneHandle,NULL,DialNumberBuffer))
							DoDial = DIAL_LIST;
					}
				}
			}

			ReleaseWindows();

			break;

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

		case MEN_SEND_BREAK:

			SendBreak();
			break;

			/* Hang up the phone line. */

		case MEN_HANG_UP:

			FullHangup(FALSE);

			break;

			/* Wait a bit... */

		case MEN_WAIT:

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

			BlockWindows();

			if(ReqWindow = BuildEasyRequest(Window,&Easy,IDCMP_RAWKEY,NULL))
			{
				ULONG Signals,Mask,Which;
				LONG Seconds;
				BOOL More;

					/* Don't echo serial output. */

			/*	Quiet = TRUE; */

				if(!(Seconds = Config->MiscConfig->WaitDelay))
					Seconds = 1;

				SerialCommand(Config->MiscConfig->WaitString);
				RunJob(SerialJob);

				StartTime(Seconds,0);

				if(ReadPort && !Get_xOFF() && ProcessIO)
					Mask = SIG_SERIAL;
				else
					Mask = NULL;

				More = FALSE;

				FOREVER
				{
					Which = Mask | SIG_REXX | SIG_TIMER | PORTMASK(ReqWindow->UserPort);

					if(More)
					{
						Signals = SetSignal(0,Which) & Which;
						More = FALSE;
					}
					else
						Signals = Wait(Which);

					if(Signals & PORTMASK(ReqWindow->UserPort))
					{
						ULONG IDCMP = NULL;
						LONG Result;

						Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);

						if(Result == 0 || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
						{
							StopTime();

							SerialCommand(Config->MiscConfig->WaitString);

							break;
						}
					}

					if(Signals & SIG_TIMER)
					{
						WaitTime();

						SerialCommand(Config->MiscConfig->WaitString);

						StartTime(Seconds,0);
					}

					if(Signals & Mask)
					{
						More = RunJob(SerialJob);

						if(Get_xOFF())
						{
							Mask = NULL;
							More = FALSE;
						}
					}

					if(Signals & SIG_REXX)
					{
						struct RexxMsg *Msg;

						if(Msg = (struct RexxMsg *)GetMsg(TermRexxPort))
						{
							Msg->rm_Result1 = RC_ERROR;
							Msg->rm_Result2 = ERR10_001;

							ReplyMsg((struct Message *)Msg);

							More = TRUE;
						}
					}
				}

				RunJob(SerialJob);

			/*	Quiet = FALSE; */

				FreeSysRequest(ReqWindow);
			}

			ReleaseWindows();

			break;

			/* Flush the serial buffers. */

		case MEN_FLUSH_BUFFER:

			ClearSerial();

			RestartSerial();

			break;

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

		case MEN_RELEASE_DEVICE:

			ActivateJob(MainJobQueue,ReleaseSerialJob);
			break;

		case MEN_UPLOAD_ASCII:

			BlockWindows();

			if(ChangeProtocol(Config->TransferConfig->ASCIIUploadLibrary,Config->TransferConfig->ASCIIUploadType))
				StartSendXPR_AskForFile(TRANSFER_ASCII,TRUE);

			ResetProtocol();

			ReleaseWindows();

			break;

		case MEN_DOWNLOAD_ASCII:

			BlockWindows();

			if(ChangeProtocol(Config->TransferConfig->ASCIIDownloadLibrary,Config->TransferConfig->ASCIIDownloadType))
				StartReceiveXPR_AskForFile(TRANSFER_ASCII,TRUE);

			ResetProtocol();

			ReleaseWindows();

			break;

		case MEN_UPLOAD_TEXT:

			BlockWindows();

#ifdef BUILTIN_ZMODEM
			if(UseInternalZModem)
			{
				InternalZModemTextUpload();

				ReleaseWindows();
				break;
			}
#endif	/* BUILTIN_ZMODEM */

			if(ChangeProtocol(Config->TransferConfig->TextUploadLibrary,Config->TransferConfig->TextUploadType))
				StartSendXPR_AskForFile(TRANSFER_TEXT,TRUE);

			ResetProtocol();

			ReleaseWindows();

			break;

		case MEN_DOWNLOAD_TEXT:

			BlockWindows();

#ifdef BUILTIN_ZMODEM
			if(UseInternalZModem)
			{
				ZReceive();

				ReleaseWindows();
				break;
			}
#endif	/* BUILTIN_ZMODEM */

			if(ChangeProtocol(Config->TransferConfig->TextDownloadLibrary,Config->TransferConfig->TextDownloadType))
				StartReceiveXPR_AskForFile(TRANSFER_TEXT,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])
			{
				DummyBuffer[0] = 0;

				if(FileRequest = OpenSingleFile(Window,LocaleString(MSG_TERMMAIN_EDIT_AND_TRANSFER_FILE_TXT),LocaleString(MSG_TERMMAIN_EDIT_TXT),NULL,DummyBuffer,sizeof(DummyBuffer)))
				{
					UBYTE CompoundName[2 * MAX_FILENAME_LENGTH];

					FreeAslRequest(FileRequest);

					LimitedStrcpy(sizeof(CompoundName),CompoundName,Config->PathConfig->Editor);
					LimitedStrcat(sizeof(CompoundName),CompoundName," \"");
					LimitedStrcat(sizeof(CompoundName),CompoundName,DummyBuffer);
					LimitedStrcat(sizeof(CompoundName),CompoundName,"\"");

					LaunchCommand(CompoundName);

					BumpWindow(Window);

					if(GetFileSize(DummyBuffer))
					{
						switch(ShowRequest(Window,LocaleString(MSG_TERMMAIN_TRANSFER_FILE_AS_TXT),LocaleString(MSG_TERMMAIN_ASCII_UPLOAD_CANCEL_TXT),FilePart(DummyBuffer)))
						{
							case 1:

								if(ChangeProtocol(Config->TransferConfig->ASCIIUploadLibrary,Config->TransferConfig->ASCIIUploadType))
									StartSendXPR_File(TRANSFER_ASCII,DummyBuffer,TRUE);

								ResetProtocol();

								break;

							case 2:

								if(ChangeProtocol(Config->TransferConfig->TextUploadLibrary,Config->TransferConfig->TextUploadType))
									StartSendXPR_File(TRANSFER_TEXT,DummyBuffer,TRUE);

								ResetProtocol();

								break;
						}
					}
				}
			}

			ReleaseWindows();
			break;

		case MEN_UPLOAD_BINARY:

			BlockWindows();

#ifdef BUILTIN_ZMODEM
			if(UseInternalZModem)
			{
				InternalZModemBinaryUpload();

				ReleaseWindows();
				break;
			}
#endif	/* BUILTIN_ZMODEM */

			if(ChangeProtocol(Config->TransferConfig->BinaryUploadLibrary,Config->TransferConfig->BinaryUploadType))
				StartSendXPR_AskForFile(TRANSFER_BINARY,TRUE);

			ResetProtocol();

			ReleaseWindows();

			break;

			/* Download some files. */

		case MEN_DOWNLOAD_BINARY:

			BlockWindows();

#ifdef BUILTIN_ZMODEM
			if(UseInternalZModem)
			{
				ZReceive();

				ReleaseWindows();
				break;
			}
#endif	/* BUILTIN_ZMODEM */

			if(ChangeProtocol(Config->TransferConfig->BinaryDownloadLibrary,Config->TransferConfig->BinaryDownloadType))
				StartReceiveXPR_AskForFile(TRANSFER_BINARY,TRUE);

			ResetProtocol();

			ReleaseWindows();

			break;

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

		case MEN_CLEAR_BUFFER:

			if(Lines)
			{
				BlockWindows();

				if((Qualifier & SHIFT_KEY) || !Config->MiscConfig->ProtectiveMode)
				{
					FreeBuffer();

					TerminateBuffer();
				}
				else
				{
					if(ShowRequest(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 appropriate.
			 */

		case MEN_DISPLAY_BUFFER:

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

				ShowRequest(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:

			TerminateBuffer();
			break;

			/* Is the buffer to be frozen? */

		case MEN_FREEZE_BUFFER:

			BufferFrozen = GetItem(MEN_FREEZE_BUFFER);
			ConOutputUpdate();

			break;

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

		case MEN_OPEN_BUFFER:

			BlockWindows();

			DummyBuffer[0] = 0;

			if(FileRequest = OpenSingleFile(Window,LocaleString(MSG_TERMMAIN_LOAD_BUFFER_TXT),LocaleString(MSG_GLOBAL_LOAD_TXT),NULL,DummyBuffer,sizeof(DummyBuffer)))
			{
				FreeAslRequest(FileRequest);

				if(GetFileSize(DummyBuffer))
				{
					if(SomeFile = Open(DummyBuffer,MODE_OLDFILE))
					{
						if(Lines)
						{
							switch(ShowRequest(Window,LocaleString(MSG_TERMMAIN_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_TERMMAIN_DISCARD_APPPEND_CANCEL_TXT),Lines))
							{
								case 0:

									Close(SomeFile);
									SomeFile = NULL;
									break;

								case 1:

									FreeBuffer();
									break;
							}
						}

						if(SomeFile)
						{
							LONG Len;

							LineRead(NULL,NULL,NULL);

							while((Len = LineRead(SomeFile,DummyBuffer,80)) > 0)
								CaptureParser(ParserStuff,DummyBuffer,Len,(COPTR)AddLine);

							Close(SomeFile);

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

			ReleaseWindows();
			break;

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

		case MEN_SAVE_BUFFER_AS:

			BlockWindows();

			if(!Lines || !BufferLines)
				ShowRequest(Window,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
			else
			{
				DummyBuffer[0] = 0;

				if(FileRequest = SaveFileOverwrite(Window,LocaleString(MSG_TERMMAIN_SAVE_BUFFER_TXT),NULL,NULL,DummyBuffer,sizeof(DummyBuffer)))
				{
					LONG Error = 0;

					FreeAslRequest(FileRequest);

					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(ShowRequest(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:

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

					if(SomeFile)
					{
						LONG i,Len;

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

						SafeObtainSemaphoreShared(&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);
				}
			}

			ReleaseWindows();

			break;

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

		case MEN_CLEAR_SCREEN:

			ConClear();
			break;

			/* Reset the current text rendering font. */

		case MEN_RESET_FONT:

			ConResetFont();
			break;

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

		case MEN_RESET_STYLES:

			ConResetStyles();
			break;

			/* Reset the whole terminal. */

		case MEN_RESET_TERMINAL:

			ConResetTerminal();
			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
			{
				if(EmulationPanel(Window,Config))
				{
					ConfigSetup();

					ConfigChanged = TRUE;
				}
			}

			ReleaseWindows();

			break;

			/* Set the serial preferences. */

		case MEN_SERIAL:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the modem preferences. */

		case MEN_MODEM:

			BlockWindows();

			if(ModemPanel(Window,Config))
			{
				ResetDataFlowFilter();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the screen preferences. */

		case MEN_SCREEN:

			BlockWindows();

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

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

						case COLOUR_SIXTEEN:

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

						case COLOUR_AMIGA:

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

						case COLOUR_MONO:

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

				ConfigSetup();

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

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

						case COLOUR_SIXTEEN:

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

						case COLOUR_AMIGA:

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

						case COLOUR_MONO:

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

					ConfigChanged = TRUE;
				}
			}

			ReleaseWindows();

			break;

			/* Set the terminal preferences. */

		case MEN_TERMINAL:

			BlockWindows();

			if(!TerminalPanel(Window,Config))
				ReleaseWindows();
			else
			{
				ReleaseWindows();

				Update_CR_LF_Translation();

				ConfigSetup();

				ConfigChanged = TRUE;

					/* Make the changes now */

				if(FixScreenSize && !ResetDisplay)
				{
					ScreenSizeStuff();

					ForceStatusUpdate();

					HandleMenuCode(NULL,MEN_RESET_TERMINAL,0);
				}
			}

			break;

			/* Set the clipboard preferences. */

		case MEN_CLIPBOARD:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the capture preferences. */

		case MEN_CAPTURE:

			BlockWindows();

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

				ConfigSetup();

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the command preferences. */

		case MEN_COMMANDS:

			BlockWindows();

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

			ReleaseWindows();

			break;

			/* Set the miscellaneous preferences. */

		case MEN_MISC:

			BlockWindows();

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

				ConfigChanged = TRUE;
			}

			ReleaseWindows();

			break;

			/* Set the path settings. */

		case MEN_PATH:

			BlockWindows();

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

			ReleaseWindows();

			break;

			/* Set the file transfer options. */

		case MEN_TRANSFER:

			BlockWindows();

#ifdef BUILTIN_ZMODEM
			if(UseInternalZModem)
			{
				ZSettings();

				ReleaseWindows();

				break;
			}
#endif	/* BUILTIN_ZMODEM */

			XprIO->xpr_filename = NULL;

				/* Set up the library options. */

			if(XProtocolBase)
			{
				XPRCommandSelected = FALSE;

				ClearSerial();

				NewOptions = FALSE;

				TransferBits = XProtocolSetup(XprIO);

				RestartSerial();

				DeleteTransferPanel(TRUE);

					/* Successful? */

				if(!(TransferBits & XPRS_SUCCESS))
				{
					ShowRequest(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(TRUE);
				}
				else
					SaveProtocolOpts();
			}

			ReleaseWindows();

			break;

			/* Set the file transfer procol settings. */

		case MEN_TRANSFER_PROTOCOL:

			BlockWindows();

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

				ConfigChanged = TRUE;

				ResetDataFlowFilter();
			}

			ReleaseWindows();

			break;

			/* Set the translation tables. */

		case MEN_TRANSLATION:

			BlockWindows();

			TranslationPanelConfig(Config,&SendTable,&ReceiveTable,LastTranslation,Window,&TranslationChanged);

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

				MacroPanelConfig(Config,MacroKeys,LastMacros,Window,&MacroChanged);

				SetupXEM_MacroKeys(MacroKeys);
			}
			else
				MacroPanelConfig(Config,MacroKeys,LastMacros,Window,&MacroChanged);

			ReleaseWindows();

			break;

			/* Set the cursor keys. */

		case MEN_CURSORKEYS:

			BlockWindows();

			CursorPanelConfig(Config,CursorKeys,LastCursorKeys,Window,&CursorKeysChanged);

			ReleaseWindows();

			break;

			/* Set the fast macros. */

		case MEN_FAST_MACROS:

			BlockWindows();

			if(FastMacroPanelConfig(Config,&FastMacroList,LastFastMacros,Window,&FastMacrosChanged))
			{
				FastMacroCount = GetListSize(&FastMacroList);
				RefreshFastWindow();
			}

			ReleaseWindows();

			break;

			/* Set the hotkey preferences. */

		case MEN_HOTKEYS:

			BlockWindows();

			if(HotkeyPanelConfig(Config,&Hotkeys,LastKeys,&HotkeysChanged))
			{
				if(LastKeys[0] && !SetupCx())
					ShowRequest(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();

			SpeechPanelConfig(&SpeechConfig,LastSpeech,&SpeechChanged);

			ReleaseWindows();

			break;

			/* Set the sound preferences. */

		case MEN_SOUND:

			BlockWindows();

			if(SoundPanelConfig(&SoundConfig,LastSound,&SoundChanged))
			{
				if(LastSound[0])
					SoundInit();
			}

			ReleaseWindows();

			break;

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

		case MEN_RATES:

			BlockWindows();

			PatternPanelConfig(PatternList,LastPattern,&PatternsChanged);

			ReleaseWindows();

			break;

			/* Open the preferences settings. */

		case MEN_OPEN_SETTINGS:

			BlockWindows();

			strcpy(DummyBuffer,LastConfig);

			if(FileRequest = OpenSingleFile(Window,LocaleString(MSG_TERMMAIN_OPEN_PREFERENCES_TXT),NULL,"#?.prefs",DummyBuffer,sizeof(DummyBuffer)))
			{
				FreeAslRequest(FileRequest);

				if(ReadConfig(DummyBuffer,PrivateConfig))
				{
					SwapConfig(PrivateConfig,Config);

					strcpy(LastConfig,DummyBuffer);

					ConfigSetup();

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

			ReleaseWindows();

			break;

			/* Save the terminal preferences. */

		case MEN_SAVE_SETTINGS:

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

				if(!Screen)
					PutWindowInfo(WINDOW_MAIN,Window->LeftEdge,Window->TopEdge,Window->Width,Window->Height);

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

			if(FileRequest = SaveFile(Window,LocaleString(MSG_TERMMAIN_SAVE_PREFERENCES_AS_TXT),NULL,"#?.prefs",DummyBuffer,sizeof(DummyBuffer)))
			{
				FreeAslRequest(FileRequest);

				if(!Screen)
					PutWindowInfo(WINDOW_MAIN,Window->LeftEdge,Window->TopEdge,Window->Width,Window->Height);

				if(WriteConfig(DummyBuffer,Config))
				{
					strcpy(LastConfig,DummyBuffer);

					ConfigChanged = FALSE;
				}
				else
					ShowError(Window,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
			}

			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;

		case MEN_MATRIX_WINDOW:

			if(MatrixWindow)
				CloseMatrixWindow();
			else
				OpenMatrixWindow(Window);

			break;

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

		case MEN_PACKET_WINDOW:

			CreatePacketWindow();
			break;

			/* Enable or disable the packet window */

		case MEN_CHAT_LINE:

			Checked = GetItem(MEN_CHAT_LINE);

			if(Checked != ChatMode)
			{
				ChatMode = Checked;

				ResetDisplay = TRUE;
				ActivateJob(MainJobQueue,ResetDisplayJob);
			}

			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;

			/* Check if we should go for the quick dial menu */

		default:

			if(Code >= DIAL_MENU_LIMIT && ThisItem != NULL)
			{
				LONG i;

				if(ThisItem->Flags & CHECKED)
				{
					if(QuickDialMax < DIAL_MENU_MAX)
					{
						LONG Which;

						Which = -1;

						for(i = 0 ; i < QuickDialMax ; i++)
						{
							if(QuickDialTable[i] == Code)
							{
								Which = i;
								break;
							}
							else
							{
								if(QuickDialTable[i] == -1)
									Which = i;
							}
						}

						if(Which == -1)
							Which = QuickDialMax++;

						QuickDialTable[Which] = Code;
					}
				}
				else
				{
					for(i = 0 ; i < QuickDialMax ; i++)
					{
						if(QuickDialTable[i] == Code)
							QuickDialTable[i] = -1;
					}

					for(i = QuickDialMax - 1 ; i >= 0 ; i--)
					{
						if(QuickDialTable[i] == -1)
							QuickDialMax = i;
						else
							break;
					}
				}

				CheckDialMenu = TRUE;
			}

			break;
	}
}

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

BOOL
HandleReleaseSerial(JobNode *UnusedJob)
{
	if(!MainTerminated)
		LocalReleaseSerial();

	return(FALSE);
}

	/* HandleStartupFile(JobNode *Job):
	 *
	 *	Launches the startup ARexx script.
	 */

BOOL
HandleStartupFile(JobNode *UnusedJob)
{
	if(!MainTerminated)
	{
		LaunchRexxAsync(StartupFile);

		StartupFile[0] = 0;
	}

	return(FALSE);
}

BOOL
HandleIconifyJob(JobNode *UnusedJob)
{
	if(!MainTerminated)
		HandleIconify();

	return(FALSE);
}

BOOL
HandleRebuildMenuJob(JobNode *UnusedJob)
{
	if(!ResetDisplay && !MainTerminated)
	{
		struct Menu *Menu;

		if(Menu = BuildMenu())
			AttachMenu(Menu);
		else
			DisconnectDialMenu();

		RebuildMenu = FALSE;
	}

	return(FALSE);
}

BOOL
HandleResetDisplayJob(JobNode *UnusedJob)
{
	if(!MainTerminated)
	{
		if(!DisplayReset())
			MainTerminated = TRUE;
	}

	return(FALSE);
}

BOOL
HandleOnlineCleanupJob(JobNode *UnusedJob)
{
	if(!MainTerminated)
	{
		HandleOnlineCleanup(HungUp);

		WasOnline	= FALSE;
		HungUp		= FALSE;
	}

	return(FALSE);
}

BOOL
HandleDisplayCostJob(JobNode *Job)
{
	BOOL TurnOff = TRUE;

	if(!MainTerminated)
	{
		if(ResetDisplay)
			TurnOff = FALSE;
		else
		{
			UBYTE Sum[20];
			LONG ID;

				/* Reset the text rendering styles, font, etc. in
				 * order to keep the following text from getting
				 * illegible.
				 */

			SoftReset();

			if(DisplayPay)
			{
				if(DisplayHangup)
					ID = MSG_TERMMAIN_LOGMSG_HANG_UP_COST_TXT;
				else
					ID = MSG_TERMAUX_CARRIER_LOST_COST_TXT;

				CreateSum((DisplayPay + 5000) / 10000,TRUE,Sum,sizeof(Sum));

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

				ConPrintf(LocaleString(MSG_TERMMAIN_THIS_CALL_WILL_COST_YOU_TXT),Sum);
			}
			else
			{
				if(DisplayHangup)
					ID = MSG_TERMMAIN_LOGMSG_HANG_UP_TXT;
				else
					ID = MSG_TERMAUX_CARRIER_LOST_TXT;

				Sum[0] = 0;
			}

			LogAction(LocaleString(ID),Sum);

			DisplayHangup	= FALSE;
			DisplayPay		= 0;
		}
	}

	if(TurnOff)
		SuspendJob(MainJobQueue,Job);

	return(FALSE);
}
