/*
**	$Id: termInit.c,v 1.16 92/08/18 16:12:31 olsen Sta Locker: olsen $
**	$Revision: 1.16 $
**	$Date: 92/08/18 16:12:31 $
**
**	Program initialization and shutdown routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

#include "OwnDevUnit.h"

	/* Screen title. */

STATIC UBYTE ScreenTitle[80];

	/* A couple of private strings which are to `impersonate' the
	 * control sequences associated with the four function keys.
	 */

STATIC UBYTE *FunctionKeyCodes[4] =
{
	"\\eOP",
	"\\eOQ",
	"\\eOR",
	"\\eOS"
};

	/* This variable helps us to remember whether the fast!
	 * macro panel was open or not.
	 */

STATIC BYTE HadFastMacros = FALSE;

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

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

	Forbid();

	UnLoadSeg(SegList);

	CloseLibrary(DOSBase);
}

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

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

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

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

		return(Child);
	}
	else
		return(NULL);
}

	/* LoadKeyMap(STRPTR Name):
	 *
	 *	Load a keymap file from disk.
	 */

struct KeyMap *
LoadKeyMap(STRPTR Name)
{
	struct KeyMapResource	*KeyMapResource;
	struct KeyMap		*Map = NULL;

		/* Try to get access to the list of currently loaded
		 * keymap files.
		 */

	if(KeyMapResource = (struct KeyMapResource *)OpenResource("keymap.resource"))
	{
		struct KeyMapNode *Node;

			/* Try to find the keymap in the list. */

		Forbid();

		if(Node = (struct KeyMapNode *)FindName(&KeyMapResource -> kr_List,FilePart(Config . KeyMapName)))
			Map = &Node -> kn_KeyMap;

		Permit();
	}

		/* Still no keymap available? */

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

			/* Disable DOS requesters. */

		ThisProcess -> pr_WindowPtr = (APTR)-1;

			/* Unload the old keymap code. */

		if(KeySegment)
			UnLoadSeg(KeySegment);

			/* Try to load the keymap from the
			 * name the user entered.
			 */

		if(!(KeySegment = LoadSeg(Config . KeyMapName)))
		{
				/* Second try: load it from
 				 * the standard keymaps drawer.
 				 */

			strcpy(SharedBuffer,"KEYMAPS:");

			if(AddPart(SharedBuffer,FilePart(Config . KeyMapName),256))
			{
				if(!(KeySegment = LoadSeg(SharedBuffer)))
				{
					strcpy(SharedBuffer,"Devs:Keymaps");

					if(AddPart(SharedBuffer,FilePart(Config . KeyMapName),256))
						KeySegment = LoadSeg(SharedBuffer);
				}
			}
		}

			/* Did we get the keymap file? */

		if(KeySegment)
		{
			struct KeyMapNode *Node = (struct KeyMapNode *)&((ULONG *)BADDR(KeySegment))[1];

			Map = &Node -> kn_KeyMap;
		}

			/* Enable DOS requesters again. */

		ThisProcess -> pr_WindowPtr = OldPtr;
	}
	else
	{
		if(KeySegment)
		{
			UnLoadSeg(KeySegment);

			KeySegment = NULL;
		}
	}

	return(Map);
}

	/* ConfigSetup():
	 *
	 *	Compare the current configuration with the
	 *	last backup and reset the serial device, terminal,
	 *	etc. if necessary.
	 */

VOID
ConfigSetup()
{
	BYTE NewEmulation = FALSE;

	if(Config . OpenFastMacroPanel)
		HadFastMacros = TRUE;

	if(!Config . BufferEnabled)
		BufferFrozen = TRUE;

	if(Menu)
	{
		struct MenuItem *SomeItem;

		if(SomeItem = FindThisItem(MEN_FREEZE_BUFFER))
		{
			if(BufferFrozen)
				SomeItem -> Flags |= CHECKED;
			else
				SomeItem -> Flags &= ~CHECKED;
		}
	}

	if(PrivateConfig . SerBuffSize != Config . SerBuffSize)
	{
		if(StripBuffer)
			FreeVec(StripBuffer);

		if(!(StripBuffer = (UBYTE *)AllocVec(Config . SerBuffSize,MEMF_ANY)))
			MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_GLOBAL_NO_AUX_BUFFERS_TXT));
	}

	if(Stricmp(PrivateConfig . FastMacroFile,Config . FastMacroFile))
		LoadFastMacros(Config . FastMacroFile);

		/* No custom keymap this time? */

	if(!Config . KeyMapName[0])
	{
		KeyMap = NULL;

		if(KeySegment)
		{
			UnLoadSeg(KeySegment);

			KeySegment = NULL;
		}
	}
	else
	{
			/* Check whether the keymap name has changed. */

		if(strcmp(PrivateConfig . KeyMapName,Config . KeyMapName))
			KeyMap = LoadKeyMap(Config . KeyMapName);
	}

	if(Stricmp(PrivateConfig . MacroFile,Config . MacroFile))
	{
		if(!LoadMacros(Config . MacroFile,MacroKeys))
		{
			WORD i,j;

			for(j = 0 ; j < 4 ; j++)
			{
				for(i = 0 ; i < 10 ; i++)
					MacroKeys -> Keys[j][i][0] = 0;
			}

			for(i = 0 ; i < 4 ; i++)
				strcpy(MacroKeys -> Keys[1][i],FunctionKeyCodes[i]);
		}
		else
			strcpy(LastMacros,Config . MacroFile);
	}

	if(PrivateConfig . FontHeight != Config . FontHeight)
		ResetDisplay = TRUE;

	if(Stricmp(PrivateConfig . FontName,Config . FontName))
		ResetDisplay = TRUE;

	if(PrivateConfig . Font != Config . Font)
		ResetDisplay = TRUE;

	if(PrivateConfig . TextFontHeight != Config . TextFontHeight)
		ResetDisplay = TRUE;

	if(Stricmp(PrivateConfig . TextFontName,Config . TextFontName))
		ResetDisplay = TRUE;

	if(PrivateConfig . DisplayMode != Config . DisplayMode || PrivateConfig . ColourMode != Config . ColourMode)
		ResetDisplay = TRUE;

	if(PrivateConfig . ColourMode == COLOUR_EIGHT && Config . ColourMode == COLOUR_EIGHT)
	{
		if((PrivateConfig . DisableBlinking & ~TERMINAL_FASTER) != (Config . DisableBlinking & ~TERMINAL_FASTER))
			ResetDisplay = TRUE;
	}

	if((PrivateConfig . DisableBlinking & TERMINAL_FASTER) != (Config . DisableBlinking & TERMINAL_FASTER))
		ResetDisplay = TRUE;

	if(PrivateConfig . StatusLine != Config . StatusLine)
		ResetDisplay = TRUE;

	if(PrivateConfig . TitleBar != Config . TitleBar)
		ResetDisplay = TRUE;

	if(strcmp(PrivateConfig . Protocol,Config . Protocol))
	{
		strcpy(LastXprLibrary,Config . Protocol);

		ProtocolSetup();
	}

		/* Serial configuration needs updating? */

	if(!SerialSet && (memcmp(&PrivateConfig,&Config,offsetof(struct Configuration,ModemInit)) || PrivateConfig . SerBuffSize != Config . SerBuffSize))
	{
		BYTE SameDevice = TRUE;

			/* Any device name change? */

		if(strcmp(PrivateConfig . SerialDevice,Config . SerialDevice))
			SameDevice = FALSE;
		else
		{
			if(PrivateConfig . SerBuffSize != Config . SerBuffSize)
				SameDevice = FALSE;

				/* Handshaking mode changed to RTS/CTS protocol? */

			if(PrivateConfig . HandshakingProtocol == HANDSHAKING_NONE && PrivateConfig . HandshakingProtocol != HANDSHAKING_NONE)
				SameDevice = FALSE;
		}

		if(ReadRequest)
		{
				/* Stop any IO activity. */

			ClearSerial();
		}
		else
			SameDevice = FALSE;

			/* No dramatic changes? Simply change the parameters. */

		if(SameDevice)
		{
			LONG Error;

				/* Use new parameters... */

			SetFlags(WriteRequest);
			SetFlags(ReadRequest);

				/* ...and set them. */

			WriteRequest -> IOSer . io_Command = SDCMD_SETPARAMS;

			if(Error = DoIO(WriteRequest))
			{
				STRPTR	String;
				BYTE	Reset;

				if(!(String = GetSerialError(Error,&Reset)))
					String = LocaleString(MSG_SERIAL_ERROR_DEVBUSY_TXT);

				SPrintf(SharedBuffer,String,Config . SerialDevice,Config . UnitNumber);

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

				if(Reset)
				{
					WriteRequest -> IOSer . io_Command = CMD_RESET;

					DoIO(WriteRequest);

					GetFlags(&Config,WriteRequest);
					SetFlags(ReadRequest);
				}
			}

				/* Restart read request. */

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

			SetSignal(0,SIG_SERIAL);

			SendIO(ReadRequest);
		}
		else
		{
			UBYTE *Error;

			DeleteSerial();

			if(Error = CreateSerial())
			{
				MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Error);

				DeleteSerial();
			}
			else
			{
				if(SerialMessage)
				{
					MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SerialMessage);

					SerialMessage = NULL;
				}
			}
		}
	}

	if(Config . EightyColumns)
	{
		ClearCursor();

		if(Config . FontScale == SCALE_HALF)
			LastColumn = 131;
		else
			LastColumn = 79;

		if(Config . EightyColumns == 1)
			LastLine = 23;
		else
			LastLine = 24;

		LastPixel = 80 * 8 - 1;

		BackupRender();

		SetAPen(RPort,0);

		SetWrMsk(RPort,0xFF);

		ScrollLineRectFill(RPort,0,(LastLine + 1) * TextFontHeight,Window -> Width - 1,Window -> Height - 1);
		ScrollLineRectFill(RPort,80 * TextFontWidth,0,Window -> Width - 1,Window -> Height - 1);

		BackupRender();

		SetCursor();
	}
	else
	{
		LastLine	= Window -> Height / TextFontHeight - 1;
		LastColumn	= Window -> Width / TextFontWidth - 1;
		LastPixel	= (LastColumn + 1) * TextFontWidth - 1;

		if(!RegionSet)
			Bottom = LastLine;
	}

	if(LastLine > Window -> Height / TextFontHeight - 1)
		LastLine = Window -> Height / TextFontHeight - 1;

	if(CursorY > LastLine)
	{
		ClearCursor();

		CursorY = LastLine;
	}

	if(PrivateConfig . FontScale == SCALE_HALF && Config . FontScale != SCALE_HALF)
	{
		CursorX /= 2;

		if(Config . EightyColumns)
		{
			LastColumn	= 79;
			LastPixel	= 80 * 8 - 1;
		}
		else
		{
			LastColumn	= Window -> Width / TextFontWidth - 1;
			LastPixel	= (LastColumn + 1) * TextFontWidth - 1;
		}
	}

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

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

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

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

	if(Config . Emulation == EMULATION_EXTERNAL)
	{
		if(PrivateConfig . Emulation != EMULATION_EXTERNAL)
			NewEmulation = TRUE;

		if(Stricmp(PrivateConfig . EmulationName,Config . EmulationName))
			NewEmulation = TRUE;
	}
	else
	{
		if(XEmulatorBase && PrivateConfig . Emulation == EMULATION_EXTERNAL)
		{
			XEmulatorClearConsole(XEM_IO);

			CloseEmulator();

			Reset();
		}

		OnMenu(Window,FULLMENUNUM(0,0,1));
		OnMenu(Window,FULLMENUNUM(0,2,0));

		Config . RasterEnabled = TRUE;
	}

	if(!ResetDisplay && NewEmulation && Config . EmulationName[0])
	{
		if(!OpenEmulator(Config . EmulationName))
		{
			Config . Emulation = EMULATION_ANSIVT100;

			ResetDisplay = TRUE;

			Config . RasterEnabled = TRUE;

			MyEasyRequest(Window,LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_EMULATION_LIBRARY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Config . EmulationName);
		}
		else
		{
			if(Config . RasterEnabled)
			{
				Config . RasterEnabled = FALSE;

				OffMenu(Window,FULLMENUNUM(0,0,1));
				OffMenu(Window,FULLMENUNUM(0,2,0));
			}
		}
	}

	if(!ResetDisplay)
	{
		if(PrivateConfig . RasterEnabled != Config . RasterEnabled)
		{
			RasterEraseScreen(2);

			if(Config . RasterEnabled)
			{
				OnMenu(Window,FULLMENUNUM(0,0,1));
				OnMenu(Window,FULLMENUNUM(0,2,0));
			}
			else
			{
				OffMenu(Window,FULLMENUNUM(0,0,1));
				OffMenu(Window,FULLMENUNUM(0,2,0));
			}
		}

		if(Config . Emulation != EMULATION_EXTERNAL)
			SetCursor();

		if(memcmp(&PrivateConfig . Colours[0],&Config . Colours[0],sizeof(UWORD) * 16))
		{
			WORD i;

			for(i = 0 ; i < 16 ; i++)
				BlinkColours[i] = Config . Colours[i];

			LoadRGB4(VPort,&Config . Colours[0],(1 << Screen -> RastPort . BitMap -> Depth));

			switch(Config . ColourMode)
			{
				case COLOUR_EIGHT:	for(i = 0 ; i < 8 ; i++)
								BlinkColours[i + 8] = BlinkColours[0];

							break;

				case COLOUR_SIXTEEN:	break;

				case COLOUR_AMIGA:	BlinkColours[3] = BlinkColours[0];
							break;

				default:		BlinkColours[3] = BlinkColours[0];
							break;
			}
		}
		else
		{
			if(Config . DisableBlinking & ~TERMINAL_FASTER)
				LoadRGB4(VPort,&Config . Colours[0],16);
		}

		if(!XProtocolBase)
			OffMenu(Window,FULLMENUNUM(4,NOITEM,NOSUB));
		else
			OnMenu(Window,FULLMENUNUM(4,NOITEM,NOSUB));

		if(Config . OpenFastMacroPanel && !FastWindow)
			OpenFastWindow();

		Blocking = FALSE;
	}

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

	/* PubScreenStuff():
	 *
	 *	This part handles the public screen setup stuff.
	 */

VOID
PubScreenStuff()
{
		/* Are we to make our screen public? */

	if(Config . MakeScreenPublic)
		PubScreenStatus(Screen,NULL);
	else
		PubScreenStatus(Screen,PSNF_PRIVATE);

		/* Are we to `shanghai' Workbench windows? */

	if(Config . ShanghaiWindows)
	{
		PublicModes |= SHANGHAI;

		SetPubScreenModes(PublicModes);

			/* Make this the default public screen. */

		SetDefaultPubScreen(TermIDString);
	}
	else
	{
		PublicModes &= ~SHANGHAI;

		if(LockPubScreen(DefaultPubScreen))
		{
			SetDefaultPubScreen(DefaultPubScreen);

			UnlockPubScreen(DefaultPubScreen,NULL);
		}
		else
			SetDefaultPubScreen(NULL);

		SetPubScreenModes(PublicModes);
	}
}

	/* DisplayReset():
	 *
	 *	Reset the entire display if necessary.
	 */

BYTE
DisplayReset()
{
	UBYTE	*Result;
	BYTE	 Success = TRUE;

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

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

			MyEasyRequest(NULL,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Result);

			Success = FALSE;
		}
		else
		{
			BumpWindow(Window);

			PubScreenStuff();

			DisplayReopened = TRUE;
		}
	}
	else
	{
		CopyMem(&PrivateConfig,&Config,sizeof(struct Configuration));

		BlockWindows();

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

		ReleaseWindows();

		Success = TRUE;
	}

	ResetDisplay = FALSE;

	return(Success);
}

	/* DeleteDisplay():
	 *
	 *	Free all resources associated with the terminal
	 *	display (tasks, interrupts, screen, window, etc.).
	 */

BYTE
DeleteDisplay()
{
	if(Screen)
	{
		struct List		*PubScreenList;
		struct PubScreenNode	*ScreenNode;

		PubScreenList = LockPubScreenList();

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

		if(ScreenNode)
		{
			if(ScreenNode -> psn_VisitorCount)
			{
				UnlockPubScreenList();

				return(FALSE);
			}
			else
			{
				Forbid();

				UnlockPubScreenList();

				PubScreenStatus(Screen,PSNF_PRIVATE);

				Permit();
			}
		}
		else
			UnlockPubScreenList();
	}

	CloseInfoWindow();

	DeleteReview();

	if(Config . Emulation == EMULATION_EXTERNAL && XEmulatorBase)
		CloseEmulator();

	if(StatusProcess)
	{
		SetSignal(0,SIGBREAKF_CTRL_C);

		Signal(StatusProcess,SIGBREAKF_CTRL_C);

		Wait(SIGBREAKF_CTRL_C);
	}

	DeleteRaster();

	DeleteScale();

	if(ScrollLines)
	{
		FreeVec(ScrollLines);

		ScrollLines = NULL;
	}

	if(Screen)
		ScreenToBack(Screen);

	if(FastWindow)
	{
		HadFastMacros = TRUE;

		CloseFastWindow();
	}
	else
		HadFastMacros = FALSE;

	if(StatusWindow)
	{
		ClearMenuStrip(StatusWindow);
		CloseWindowSafely(StatusWindow);

		StatusWindow = NULL;
	}

	if(Window)
	{
		ClearMenuStrip(Window);

		ThisProcess -> pr_WindowPtr = OldWindowPtr;

		PopWindow();

		if(TermPort)
			TermPort -> TopWindow = NULL;

		CloseWindow(Window);

		Window = NULL;
	}

	if(Menu)
	{
		FreeMenus(Menu);

		Menu = NULL;
	}

	if(VisualInfo)
	{
		FreeVisualInfo(VisualInfo);

		VisualInfo = NULL;
	}

	DeletePacketWindow(FALSE);

	if(UserTextFont)
	{
		CloseFont(UserTextFont);

		UserTextFont = NULL;
	}

		/* Before we can close screen we will have to
		 * make sure that it is no longer the default
		 * public screen.
		 */

	if(Config . ShanghaiWindows)
	{
		if(LockPubScreen(DefaultPubScreen))
		{
			SetDefaultPubScreen(DefaultPubScreen);

			UnlockPubScreen(DefaultPubScreen,NULL);
		}
		else
			SetDefaultPubScreen(NULL);
	}

	if(Screen)
	{
		CloseScreen(Screen);

		Screen = NULL;
	}

	if(InterleavedBitMap)
	{
		DeleteInterleavedBitMap(InterleavedBitMap);

		InterleavedBitMap = NULL;
	}

	if(GFX)
	{
		CloseFont(GFX);

		GFX = NULL;
	}

	if(TextFont)
	{
		CloseFont(TextFont);

		TextFont = NULL;
	}

	return(TRUE);
}

	/* CreateDisplay(BYTE FirstSetup):
	 *
	 *	Open the display and allocate associated data.
	 */

UBYTE *
CreateDisplay(BYTE FirstSetup)
{
	UWORD			 Count = 0,i;
	LONG			 ErrorCode,Top,Height;
	ULONG			 TagArray[9];
	struct MenuItem		*SomeItem;
	struct Rectangle	 OverscanSize;
	BYTE			 OpenFailed = FALSE,
				 ScreenDepth;

	strcpy(UserFontName,Config . FontName);

	UserFont . ta_Name	= UserFontName;
	UserFont . ta_YSize	= Config . FontHeight;
	UserFont . ta_Style	= FS_NORMAL;
	UserFont . ta_Flags	= FPF_DESIGNED;

	if(DiskfontBase)
	{
		if(!(UserTextFont = OpenDiskFont(&UserFont)))
		{
			strcpy(Config . FontName,	"topaz.font");
			strcpy(UserFontName,		"topaz.font");

			Config . FontHeight = 8;

			UserFont . ta_YSize	= Config . FontHeight;
			UserFont . ta_Style	= FS_NORMAL;
			UserFont . ta_Flags	= FPF_DESIGNED | FPF_ROMFONT;

			if(!(UserTextFont = OpenFont(&UserFont)))
				return(LocaleString(MSG_TERMINIT_UNABLE_TO_OPEN_FONT_TXT));
		}
	}
	else
	{
		if(!(UserTextFont = OpenFont(&UserFont)))
		{
			strcpy(Config . FontName,	"topaz.font");
			strcpy(UserFontName,		"topaz.font");

			Config . FontHeight = 8;

			UserFont . ta_YSize	= Config . FontHeight;
			UserFont . ta_Style	= FS_NORMAL;
			UserFont . ta_Flags	= FPF_DESIGNED | FPF_ROMFONT;

			if(!(UserTextFont = OpenFont(&UserFont)))
				return(LocaleString(MSG_TERMINIT_UNABLE_TO_OPEN_FONT_TXT));
		}
	}

Reopen:	if(Config . Font == FONT_IBM)
		strcpy(TextFontName,"IBM.font");
	else
		strcpy(TextFontName,Config . TextFontName);

	TextAttr . ta_Name	= TextFontName;
	TextAttr . ta_YSize	= Config . TextFontHeight;
	TextAttr . ta_Style	= FS_NORMAL;
	TextAttr . ta_Flags	= 0;

	if(DiskfontBase)
	{
		if(!(TextFont = OpenDiskFont(&TextAttr)))
		{
			if(!Stricmp(TextFontName,"IBM.font") && Stricmp("IBM.font",Config . TextFontName))
			{
				Config . Font = FONT_TOPAZ;

				goto Reopen;
			}

			strcpy(Config . TextFontName,	"topaz.font");
			strcpy(TextFontName,		"topaz.font");

			Config . TextFontHeight = 8;

			TextAttr . ta_YSize	= Config . TextFontHeight;
			TextAttr . ta_Style	= FS_NORMAL;
			TextAttr . ta_Flags	= FPF_DESIGNED | FPF_ROMFONT;

			if(!(TextFont = OpenFont(&TextAttr)))
				return(LocaleString(MSG_TERMINIT_UNABLE_TO_OPEN_TEXT_TXT));
		}
	}
	else
	{
		if(!(TextFont = OpenFont(&TextAttr)))
		{
			if(!Stricmp(TextFontName,"IBM.font") && Stricmp("IBM.font",Config . TextFontName))
			{
				Config . Font = FONT_TOPAZ;

				goto Reopen;
			}

			strcpy(Config . TextFontName,	"topaz.font");
			strcpy(TextFontName,		"topaz.font");

			Config . TextFontHeight = 8;

			TextAttr . ta_YSize	= Config . TextFontHeight;
			TextAttr . ta_Style	= FS_NORMAL;
			TextAttr . ta_Flags	= FPF_DESIGNED | FPF_ROMFONT;

			if(!(TextFont = OpenFont(&TextAttr)))
				return(LocaleString(MSG_TERMINIT_UNABLE_TO_OPEN_TEXT_TXT));
		}
	}

	TextFontHeight		= TextFont -> tf_YSize;
	TextFontWidth		= TextFont -> tf_XSize;
	TextFontBase		= TextFont -> tf_Baseline;

	CurrentFont = TextFont;

	GFXFont . ta_YSize = Config . FontHeight;

	if(DiskfontBase)
		GFX = (struct TextFont *)OpenDiskFont(&GFXFont);
	else
		GFX = (struct TextFont *)OpenFont(&GFXFont);

	UserFontHeight		= UserTextFont -> tf_YSize;
	UserFontWidth		= UserTextFont -> tf_XSize;
	UserFontBase		= UserTextFont -> tf_Baseline;

		/* We'll configure the screen parameters at
		 * run time, at first we'll set up the screen
		 * depth.
		 */

	TagArray[Count++] = SA_Depth;

		/* Now set up the approriate colour mode. */

	switch(Config . ColourMode)
	{
		case COLOUR_EIGHT:	if(Config . DisableBlinking & ~TERMINAL_FASTER)
						TagArray[Count++] = ScreenDepth = 3;
					else
						TagArray[Count++] = ScreenDepth = 4;

					TagArray[Count++] = SA_DetailPen;
					TagArray[Count++] = 0;

					if(Config . DisableBlinking & TERMINAL_FASTER)
					{
						TagArray[Count++] = SA_BlockPen;
						TagArray[Count++] = 7;
					}
					else
					{
						TagArray[Count++] = SA_Pens;
						TagArray[Count++] = (LONG)&ANSIPens;

						TagArray[Count++] = SA_BlockPen;
						TagArray[Count++] = 4;
					}

					break;

		case COLOUR_SIXTEEN:	TagArray[Count++] = ScreenDepth = 4;

					TagArray[Count++] = SA_DetailPen;
					TagArray[Count++] = 0;

					if(Config . DisableBlinking & TERMINAL_FASTER)
					{
						TagArray[Count++] = SA_BlockPen;
						TagArray[Count++] = 15;
					}
					else
					{
						TagArray[Count++] = SA_Pens;
						TagArray[Count++] = (LONG)&EGAPens;

						TagArray[Count++] = SA_BlockPen;
						TagArray[Count++] = 8;
					}

					break;

		case COLOUR_MONO:	TagArray[Count++] = ScreenDepth = 1;

					break;

		case COLOUR_AMIGA:	TagArray[Count++] = ScreenDepth = 2;

					if(!(Config . DisableBlinking & TERMINAL_FASTER))
					{
						TagArray[Count++] = SA_Pens;
						TagArray[Count++] = (LONG)&StandardPens;
					}

					break;
	}

		/* Terminate the tag array. */

	TagArray[Count] = TAG_END;

		/* Inquire overscan limits and try to create an interleaved
		 * bitmap if possible.
		 */

	if((Config . DisableBlinking & TERMINAL_FASTER) && ScreenDepth > 1)
	{
		if(QueryOverscan(Config . DisplayMode,&OverscanSize,OSCAN_TEXT))
		{
			if(IntuitionBase -> LibNode . lib_Version < 39)
				InterleavedBitMap = CreateInterleavedBitMap(OverscanSize . MaxX - OverscanSize . MinX + 1,OverscanSize . MaxY - OverscanSize . MinY + 1,ScreenDepth);
			else
				InterleavedBitMap = NULL;
		}
	}

		/* Open the screen with the given requirements. */

#ifdef MC68030
OpenS:	SPrintf(ScreenTitle,LocaleString(MSG_TERMINIT_SCREENTITLE_30_TXT),TermName,TermDate,TermIDString);
#else
OpenS:	SPrintf(ScreenTitle,LocaleString(MSG_TERMINIT_SCREENTITLE_00_TXT),TermName,TermDate,TermIDString);
#endif	/* MC68030 */

	if(InterleavedBitMap)
	{
		Screen = (struct Screen *)OpenScreenTags(NULL,
			SA_Title,	ScreenTitle,
			SA_DClip,	&OverscanSize,
			SA_BitMap,	InterleavedBitMap,
			SA_DisplayID,	Config . DisplayMode,
			SA_Font,	&UserFont,
			SA_Behind,	TRUE,
			SA_AutoScroll,	TRUE,
			SA_ShowTitle,	Config . TitleBar,
			SA_PubName,	TermIDString,
			SA_ErrorCode,	&ErrorCode,
			TAG_MORE,	&TagArray[0],
		TAG_END);
	}
	else
	{
		BYTE Interleaved;

		if((Config . DisableBlinking & TERMINAL_FASTER) && IntuitionBase -> LibNode . lib_Version >= 39)
			Interleaved = TRUE;
		else
			Interleaved = FALSE;

		Screen = (struct Screen *)OpenScreenTags(NULL,
			SA_Title,	ScreenTitle,
			SA_Overscan,	OSCAN_TEXT,
			SA_DisplayID,	Config . DisplayMode,
			SA_Font,	&UserFont,
			SA_Behind,	TRUE,
			SA_AutoScroll,	TRUE,
			SA_ShowTitle,	Config . TitleBar,
			SA_PubName,	TermIDString,
			SA_ErrorCode,	&ErrorCode,
			SA_Interleaved,	Interleaved,
			TAG_MORE,	&TagArray[0],
		TAG_END);
	}

		/* We've got an error. */

	if(!Screen)
	{
		if(!OpenFailed)
		{
			switch(ErrorCode)
			{
					/* Can't open screen with these display
					 * modes.
					 */

				case OSERR_NOMONITOR:
				case OSERR_NOCHIPS:
				case OSERR_UNKNOWNMODE:		if(Config . DisplayMode & LACE)
									Config . DisplayMode = HIRESLACE_KEY;
								else
									Config . DisplayMode = HIRES_KEY;

								OpenFailed = TRUE;

								goto OpenS;

				case OSERR_PUBNOTUNIQUE:	return(LocaleString(MSG_TERMINIT_SCREEN_ID_ALREADY_IN_USE_TXT));
			}
		}

			/* Some different error, probably out of
			 * memory.
			 */

		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_SCREEN_TXT));
	}

	SZ_SizeSetup(Screen,&UserFont,TRUE);

		/* Set up scaling data (bitmaps & rastports). */

	if(!CreateScale())
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_FONT_SCALING_INFO_TXT));

		/* Obtain visual info (whatever that may be). */

	if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OBTAIN_VISUAL_INFO_TXT));

	VPort = &Screen -> ViewPort;

		/* Fill the `default' colour with current values. */

	if(Initializing)
	{
		for(i = 0 ; i < 16 ; i++)
			DefaultColours[i] = GetRGB4(VPort -> ColorMap,i);

		Initializing = FALSE;
	}

		/* Load the approriate colours. */

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

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

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

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

		LoadColours = FALSE;
	}

		/* Reset the current colours and the blinking equivalents. */

	for(i = 0 ; i < 16 ; i++)
		BlinkColours[i] = Config . Colours[i];

	LoadRGB4(VPort,&Config . Colours[0],(1 << Screen -> RastPort . BitMap -> Depth));

		/* Fiddle with the blinking colours. */

	switch(Config . ColourMode)
	{
		case COLOUR_EIGHT:	for(i = 0 ; i < 8 ; i++)
						BlinkColours[i + 8] = BlinkColours[0];

					break;

		case COLOUR_SIXTEEN:	break;

		case COLOUR_AMIGA:
		default:		BlinkColours[3] = BlinkColours[0];
					break;
	}

	if(Config . TitleBar)
	{
		Top = Screen -> BarHeight + 2;

		if(Config . StatusLine)
		{
			if(Config . StatusLine == STATUSLINE_COMPRESSED)
				Height = Screen -> Height - (Screen -> BarHeight + 2) - (UserFontHeight + 2);
			else
				Height = Screen -> Height - (Screen -> BarHeight + 2) - (2 + SZ_BoxHeight(2));
		}
		else
			Height = Screen -> Height - (Screen -> BarHeight + 2);
	}
	else
	{
		Top = 0;

		if(Config . StatusLine)
		{
			if(Config . StatusLine == STATUSLINE_COMPRESSED)
				Height = Screen -> Height - (UserFontHeight + 2);
			else
				Height = Screen -> Height - (2 + SZ_BoxHeight(2));
		}
		else
			Height = Screen -> Height;
	}

		/* Open the main window. */

	if(!(Window = OpenWindowTags(NULL,
		WA_Top,		Top,
		WA_Left,	0,
		WA_Width,	Screen -> Width,
		WA_Height,	Height,
		WA_Backdrop,	TRUE,
		WA_Borderless,	TRUE,
		WA_SmartRefresh,TRUE,
		WA_CustomScreen,Screen,
		WA_NewLookMenus,TRUE,
		WA_RMBTrap,	TRUE,
		WA_IDCMP,	IDCMP_RAWKEY | IDCMP_MOUSEMOVE | IDCMP_GADGETUP | IDCMP_MENUPICK | IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | LISTVIEWIDCMP,
	TAG_DONE)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_WINDOW_TXT));

		/* Push it on the window stack (should become bottommost
		 * entry).
		 */

	PushWindow(Window);

	if(TermPort)
		TermPort -> TopWindow = Window;

		/* Open the tiny status window. */

	if(Config . StatusLine)
	{
		if(!(StatusWindow = OpenWindowTags(NULL,
			WA_Top,		Window -> TopEdge + Window -> Height,
			WA_Left,	0,
			WA_Width,	Screen -> Width,
			WA_Height,	Screen -> Height - (Window -> TopEdge + Window -> Height),
			WA_Backdrop,	TRUE,
			WA_Borderless,	TRUE,
			WA_SmartRefresh,TRUE,
			WA_NewLookMenus,TRUE,
			WA_CustomScreen,Screen,
			WA_RMBTrap,	TRUE,
		TAG_DONE)))
			return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_STATUS_WINDOW_TXT));
	}
	else
		StatusWindow = NULL;

		/* Default console setup. */

	if(Config . EightyColumns)
	{
		LastColumn = 79;

		if(Config . EightyColumns == 1)
			LastLine = 23;
		else
			LastLine = 24;

		LastPixel = 80 * 8 - 1;
	}
	else
	{
		LastLine	= Window -> Height / TextFontHeight - 1;
		LastColumn	= Window -> Width / TextFontWidth - 1;
		LastPixel	= (LastColumn + 1) * TextFontWidth - 1;
	}

	if(LastLine > Window -> Height / TextFontHeight - 1)
		LastLine = Window -> Height / TextFontHeight - 1;

	CursorX = 0;
	CursorY	= 0;

	SetDrMd(Window -> RPort,JAM2);

	if(StatusWindow)
	{
		StatusWindow -> UserPort = Window -> UserPort;

		ModifyIDCMP(StatusWindow,Window -> IDCMPFlags);
	}

	RPort = Window -> RPort;

		/* Redirect AmigaDOS requesters. */

	OldWindowPtr = ThisProcess -> pr_WindowPtr;

	ThisProcess -> pr_WindowPtr = (APTR)Window;

		/* Create the character raster. */

	if(!CreateRaster())
		return(LocaleString(MSG_TERMINIT_UNABLE_TO_CREATE_SCREEN_RASTER_TXT));

		/* Set up the scrolling info. */

	ScrollLineCount = Window -> Height / TextFontHeight;

	if(!(ScrollLines = (struct ScrollLine *)AllocVec(sizeof(struct ScrollLineInfo) * ScrollLineCount,MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_SCROLLING_SUPPORT_INFO_TXT));

		/* Reset terminal emulation. */

	if(Config . Emulation != EMULATION_EXTERNAL) 
		Reset();
	else
	{
		if(XEmulatorBase)
			XEmulatorResetConsole(XEM_IO);
	}

		/* Set the font. */

	SetFont(RPort,CurrentFont);

		/* Create the menu strip. */

	if(!(Menu = CreateMenus(TermMenu,TAG_DONE)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_MENUS_TXT));

		/* Do the menu layout. */

	if(!LayoutMenus(Menu,VisualInfo,
		GTMN_NewLookMenus,	TRUE,
		GTMN_TextAttr,		&UserFont,
	TAG_DONE))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_LAYOUT_MENUS_TXT));

		/* Disable the `Execute ARexx Command' menu item if
		 * the rexx server is not available.
		 */

	if(!RexxSysBase)
	{
		struct MenuItem *SomeItem;

		if(SomeItem = FindThisItem(MEN_EXECUTE_REXX_COMMAND))
			SomeItem -> Flags &= ~ITEMENABLED;
	}

		/* Add a tick if file capture is active. */

	if(FileCapture)
	{
		if(SomeItem = FindThisItem(MEN_CAPTURE_TO_FILE))
			SomeItem -> Flags |= CHECKED;
	}

		/* Add a tick if printer capture is active. */

	if(PrinterCapture)
	{
		if(SomeItem = FindThisItem(MEN_CAPTURE_TO_PRINTER))
			SomeItem -> Flags |= CHECKED;
	}

		/* Add a tick if the buffer is frozen. */

	if(BufferFrozen)
	{
		if(SomeItem = FindThisItem(MEN_FREEZE_BUFFER))
			SomeItem -> Flags |= CHECKED;
	}

		/* Disable the dialing functions if online. */

	if(Online)
		SetDialMenu(FALSE);

		/* Add the menu to the windows. */

	SetMenuStrip(Window,Menu);

	if(!XProtocolBase)
		SetTransferMenu(FALSE);

		/* Disable the `Print Screen' and `Save ASCII' functions
		 * if raster is not enabled.
		 */

	if(!Config . RasterEnabled)
	{
		OffMenu(Window,FULLMENUNUM(0,0,1));
		OffMenu(Window,FULLMENUNUM(0,2,0));
	}

		/* Enable the menu. */

	Window -> Flags &= ~WFLG_RMBTRAP;

	if(StatusWindow)
	{
		SetMenuStrip(StatusWindow,Menu);

		StatusWindow -> Flags &= ~WFLG_RMBTRAP;

		SetDrMd(StatusWindow -> RPort,JAM2);
	}

	strcpy(EmulationName,LocaleString(MSG_TERMXEM_NO_EMULATION_TXT));

		/* Create the status server. */

	StatusProcess = CreateNewProcTags(
		NP_Entry,	StatusServer,
		NP_Name,	"term status process",
		NP_WindowPtr,	-1,
		NP_Priority,	5,
	TAG_DONE);

		/* Wait for ringback signal. */

	Wait(SIGBREAKF_CTRL_C);

		/* Status server has `died'. */

	if(!StatusProcess)
		return(LocaleString(MSG_TERMINIT_UNABLE_TO_CREATE_STATUS_TASK_TXT));

		/* Obtain the default public screen name just in case
		 * we'll need it later.
		 */

	GetDefaultPubScreen(DefaultPubScreen);

	if(Config . Emulation == EMULATION_EXTERNAL && Config . EmulationName[0])
	{
		if(!OpenEmulator(Config . EmulationName))
		{
			Config . Emulation = EMULATION_ANSIVT100;

			ResetDisplay = TRUE;

			Config . RasterEnabled = TRUE;

			MyEasyRequest(Window,LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_EMULATION_LIBRARY_TXT),Config . EmulationName);
		}
		else
		{
			if(Config . RasterEnabled)
			{
				Config . RasterEnabled = FALSE;

				OffMenu(Window,FULLMENUNUM(0,0,1));
				OffMenu(Window,FULLMENUNUM(0,2,0));
			}
		}
	}

		/* Restart the fast! macro panel. */

	if(HadFastMacros || Config . OpenFastMacroPanel)
		OpenFastWindow();

	return(NULL);
}

	/* CloseAll():
	 *
	 *	Free all resources and leave the program.
	 */

VOID
CloseAll()
{
	SZ_SizeCleanup();

	FreeDialList();

	if(SpecialTable)
		FreeVec(SpecialTable);

	if(AbortTable)
		FreeVec(AbortTable);

	if(StripBuffer)
		FreeVec(StripBuffer);

	if(BackupConfig)
		FreeVec(BackupConfig);

	if(IntuitionBase && Window)
		BlockWindows();

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

		Wait(SIGBREAKF_CTRL_C);
	}

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

		Wait(SIGBREAKF_CTRL_C);
	}

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

		Wait(SIGBREAKF_CTRL_C);
	}

	if(TermRexxPort)
	{
		if(RexxSysBase)
		{
			struct RexxMsg *RexxMsg;

			while(RexxMsg = (struct RexxMsg *)GetMsg(TermRexxPort))
				ReplyRexxCommand(RexxMsg,RC_ERROR,0,NULL);
		}

		DeleteMsgPort(TermRexxPort);
	}

	if(XprIO && XProtocolBase)
		XProtocolCleanup(XprIO);

	if(XProtocolBase)
		CloseLibrary(XProtocolBase);

	if(XprIO)
		FreeVec(XprIO);

	if(FileAnchor)
		FreeVec(FileAnchor);

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

	if(MacroKeys)
		FreeVec(MacroKeys);

	ClearBuffer();

	DeleteSpeech();

	Forbid();

	BufferClosed = TRUE;

	if(BufferLines)
		FreeVec(BufferLines);

	if(BufferSemaphore)
		FreeVec(BufferSemaphore);

	Permit();

	ClearDownloadObjects();

	if(DownloadSemaphore)
		FreeVec(DownloadSemaphore);

	if(AttentionBuffers[0])
		FreeVec(AttentionBuffers[0]);

	FreeDialList();

	ClearFastMacroList(&FastMacroList);

	if(FileCapture)
	{
		BufferClose(FileCapture);

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

	if(PrinterCapture)
		Close(PrinterCapture);

	CloseEmulator();

	if(XEM_MacroKeys)
		FreeVec(XEM_MacroKeys);

	DeleteDisplay();

	if(KeySegment)
		UnLoadSeg(KeySegment);

	StopCall(TRUE);

	if(ClipBit != -1)
		FreeSignal(ClipBit);

	if(CheckBit != -1)
		FreeSignal(CheckBit);

	ClearSerial();

	DeleteSerial();

	if(TimeRequest)
	{
		if(TimeRequest -> tr_node . io_Device)
			CloseDevice(TimeRequest);

		DeleteIORequest(TimeRequest);
	}

	if(TimePort)
		DeleteMsgPort(TimePort);

	DeleteBeep();

	ShutdownCx();

	if(TermPort)
	{
		if(TermID != -1)
		{
			ObtainSemaphore(&TermPort -> OpenSemaphore);

			TermPort -> OpenCount--;

			if(TermPort -> OpenCount <= 0 && !TermPort -> HoldIt)
			{
				RemPort(&TermPort -> ExecNode);

				ReleaseSemaphore(&TermPort -> OpenSemaphore);

				FreeVec(TermPort);
			}
			else
				ReleaseSemaphore(&TermPort -> OpenSemaphore);
		}
	}

	CloseClip();

	if(RequesterList)
		FreeVec(RequesterList);

	if(OwnDevUnitBase)
		CloseLibrary(OwnDevUnitBase);

	if(LayersBase)
		CloseLibrary(LayersBase);

	if(CxBase)
		CloseLibrary(CxBase);

	if(IFFParseBase)
		CloseLibrary(IFFParseBase);

	if(AslBase)
		CloseLibrary(AslBase);

	if(DiskfontBase)
		CloseLibrary(DiskfontBase);

	if(FakeInputEvent)
		FreeVec(FakeInputEvent);

	if(ConsoleDevice)
		CloseDevice(ConsoleRequest);

	if(ConsoleRequest)
		FreeVec(ConsoleRequest);

	if(Topaz)
		CloseFont(Topaz);

	if(RexxSysBase)
		CloseLibrary(RexxSysBase);

	if(GadToolsBase)
		CloseLibrary(GadToolsBase);

	if(UtilityBase)
		CloseLibrary(UtilityBase);

	if(GfxBase)
		CloseLibrary(GfxBase);

	if(IntuitionBase)
		CloseLibrary(IntuitionBase);

	LocaleClose();

	if(WBenchMsg)
	{
		if(DOSBase)
			CloseLibrary(DOSBase);

		Forbid();

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

	/* OpenAll():
	 *
	 *	Open all required resources or return an error message
	 *	if anything went wrong.
	 */

UBYTE *
OpenAll(STRPTR ConfigPath)
{
	UBYTE	 PathBuffer[256];
	WORD	 i;
	UBYTE	*Result,
		*Error;

	DateStamp(&SessionStart);

	LocaleOpen("term.catalog","english",7);

	LocalizeMenu(TermMenu,MSG_TERMDATA_PROJECT_MEN);

	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_INTUITION_LIBRARY_TXT));

	if((SysBase -> SoftVer < 175 && SysBase -> LibNode . lib_Version == 37) || SysBase -> LibNode . lib_Version < 37)
	{
		if(!MyEasyRequest(NULL,LocaleString(MSG_TERMINIT_VERSION_WARNING_TXT),
			LocaleString(MSG_TERMINIT_PROCEED_BACK_OUT_TXT),SysBase -> LibNode . lib_Version,SysBase -> SoftVer))
				return("");
	}

	PublicModes = SetPubScreenModes(0);

	SetPubScreenModes(PublicModes);

	if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_GRAPHICS_LIBRARY_TXT));

	if(!(UtilityBase = OpenLibrary("utility.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_UTILITY_LIBRARY_TXT));

	LanguageCheck();

	if(!(GadToolsBase = OpenLibrary("gadtools.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_GADTOOLS_LIBRARY_TXT));

	if(!(AslBase = OpenLibrary("asl.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_ASL_LIBRARY_TXT));

	if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_IFFPARSE_LIBRARY_TXT));

	if(!(CxBase = OpenLibrary("commodities.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_COMMODITIES_LIBRARY_TXT));

	if(!(LayersBase = OpenLibrary("layers.library",0)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_LAYERS_LIBRARY_TXT));

	OwnDevUnitBase = OpenLibrary(ODU_NAME,0);

	if(!(Topaz = (struct TextFont *)OpenFont(&DefaultFont)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_DEFAULT_FONT_TXT));

	if(!(ConsoleRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_CONSOLE_REQUEST_TXT));

	if(OpenDevice("console.device",CONU_LIBRARY,ConsoleRequest,0))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_CONSOLE_DEVICE_TXT));

	ConsoleDevice = &ConsoleRequest -> io_Device -> dd_Library;

	if(!(FakeInputEvent = (struct InputEvent *)AllocVec(sizeof(struct InputEvent),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_INPUTEVENT_TXT));

	FakeInputEvent -> ie_Class = IECLASS_RAWKEY;

	if(!(MacroKeys = (struct MacroKeys *)AllocVec(sizeof(struct MacroKeys),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_MACROKEYS_TXT));

	if(!(RequesterList = (struct Requester *)AllocVec(10 * sizeof(struct Requester),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_REQUESTER_DATA_TXT));

	DiskfontBase = (struct Library *)OpenLibrary("diskfont.library",0);

		/* Set up the attention buffers. */

	if(!(AttentionBuffers[0] = (UBYTE *)AllocVec(8 * 81,MEMF_PUBLIC|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_SEQUENCE_ATTENTION_INFO_TXT));

	for(i = 1 ; i < 8 ; i++)
		AttentionBuffers[i] = &AttentionBuffers[i - 1][81];

		/* Obtain the default environment storage
		 * path.
		 */

	if(!ConfigPath)
	{
		ConfigPath = PathBuffer;

		if(!GetEnvDOS("TERMPATH",PathBuffer))
		{
			APTR LastPtr = ThisProcess -> pr_WindowPtr;
			BPTR FileLock;

			strcpy(PathBuffer,"TERM:config");

			SetEnvDOS("TERMPATH",PathBuffer);

			ThisProcess -> pr_WindowPtr = (APTR)-1;

			if(FileLock = Lock("TERM:",ACCESS_READ))
				UnLock(FileLock);
			else
			{
				FileLock = DupLock(ThisProcess-> pr_CurrentDir);

					/* Create TERM: assignment referring to
					 * current directory.
					 */

				if(!AssignLock("TERM",FileLock))
					UnLock(FileLock);
			}

			if(!(FileLock = Lock(PathBuffer,ACCESS_READ)))
				FileLock = CreateDir(PathBuffer);

			if(FileLock)
				UnLock(FileLock);

			ThisProcess -> pr_WindowPtr = LastPtr;
		}
	}

		/* Check for proper assignment path if necessary. */

        if(!Strnicmp(ConfigPath,"TERM:",5))
        {
        	APTR OldPtr = ThisProcess -> pr_WindowPtr;
        	BPTR DirLock;

			/* Block dos requesters. */

        	ThisProcess -> pr_WindowPtr = (APTR)-1;

			/* Try to get a lock on `TERM:' assignment. */

		if(DirLock = Lock("TERM:",ACCESS_READ))
			UnLock(DirLock);
		else
		{
				/* Clone current directory lock. */

			DirLock = DupLock(ThisProcess-> pr_CurrentDir);

				/* Create TERM: assignment referring to
				 * current directory.
				 */

			if(!AssignLock("TERM",DirLock))
				UnLock(DirLock);
		}

		ThisProcess -> pr_WindowPtr = OldPtr;
        }

		/* Create proper path names. */

	strcpy(LastConfig,ConfigPath);

	AddPart(LastConfig,"term_preferences.iff",256);

	if(!GetFileSize(LastConfig))
	{
		strcpy(LastConfig,ConfigPath);

		AddPart(LastConfig,"term.prefs",256);
	}

	strcpy(DefaultPubScreen,"Workbench");

		/* Read some more environment variables. */

	if(!GetEnvDOS("TERMWINDOW",WindowName))
		strcpy(WindowName,"CON:0/11//100/term Output Window/CLOSE/SCREEN TERM");

	GetEnvDOS("EDITOR",Config . Editor);

	SetPrefToDefaults(&Config,ConfigPath);

		/* Look for the default configuration file. */

	if(!ReadIFFData(LastConfig,&Config,sizeof(struct Configuration),'PREF'))
	{
		SetPrefToDefaults(&Config,ConfigPath);

		Initializing = TRUE;

		LoadColours = TRUE;
	}
	else
	{
		switch(Config . ColourMode)
		{
			case COLOUR_EIGHT:	CopyMem(&Config . Colours[0],&ANSIColours[0],16 * sizeof(UWORD));
						break;

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

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

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

		if(Config . ColourMode == COLOUR_AMIGA)
			Initializing = FALSE;
		else
			Initializing = TRUE;
	}

	UpdatePrefs(&Config);

	if(Config . OpenFastMacroPanel)
		HadFastMacros = TRUE;

	NewList(&FastMacroList);

	strcpy(LastPhone,	Config . DefaultStorage);
	AddPart(LastPhone,	"term_phonebook.iff",256);

	if(!GetFileSize(LastPhone))
	{
		strcpy(LastPhone,	Config . DefaultStorage);
		AddPart(LastPhone,	"phonebook.prefs",256);
	}

	strcpy(LastKeys,	Config . DefaultStorage);
	AddPart(LastKeys,	"term_hotkeys.iff",256);

	if(!GetFileSize(LastKeys))
	{
		strcpy(LastKeys,	Config . DefaultStorage);
		AddPart(LastKeys,	"hotkeys.prefs",256);
	}

	strcpy(LastSpeech,	Config . DefaultStorage);
	AddPart(LastSpeech,	"term_speech.iff",256);

	if(!GetFileSize(LastSpeech))
	{
		strcpy(LastSpeech,	Config . DefaultStorage);
		AddPart(LastSpeech,	"speech.prefs",256);
	}

	strcpy(LastFastMacros,	Config . DefaultStorage);
	AddPart(LastFastMacros,	"term_fastmacros.iff",256);

	if(!GetFileSize(LastFastMacros))
	{
		strcpy(LastFastMacros,	Config . DefaultStorage);
		AddPart(LastFastMacros,	"fastmacros.prefs",256);
	}

	strcpy(LastMacros,Config . MacroFile);

		/* Load the keyboard macros. */

	if(!LoadMacros(LastMacros,MacroKeys))
	{
		for(i = 0 ; i < 4 ; i++)
			strcpy(MacroKeys -> Keys[1][i],FunctionKeyCodes[i]);
	}

		/* Load the fast! macro settings. */

	LoadFastMacros(LastFastMacros);

		/* Load the speech settings. */

	if(!ReadIFFData(LastSpeech,&SpeechConfig,sizeof(struct SpeechConfig),'SPEK'))
	{
		SpeechConfig . Rate		= DEFRATE;
		SpeechConfig . Pitch		= DEFPITCH;
		SpeechConfig . Frequency	= DEFFREQ;
		SpeechConfig . Volume		= DEFVOL;
		SpeechConfig . Sex		= DEFSEX;
		SpeechConfig . Enabled		= FALSE;
	}

		/* Load the hotkey settings. */

	if(!LoadHotkeys(LastKeys,&Hotkeys))
	{
		strcpy(Hotkeys . termScreenToFront,	"lshift rshift return");
		strcpy(Hotkeys . BufferScreenToFront,	"control rshift return");
		strcpy(Hotkeys . SkipDialEntry,		"control lshift rshift return");
		strcpy(Hotkeys . AbortARexx,		"lshift rshift escape");

		Hotkeys . CommodityPriority	= 0;
		Hotkeys . HotkeysEnabled	= TRUE;
	}

		/* Initialize the data flow parser. */

	FlowInit();

		/* Set up parsing jump tables. */

	if(!(SpecialTable = (JUMP *)AllocVec(256 * sizeof(JUMP),MEMF_ANY|MEMF_CLEAR)))
		MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_GLOBAL_NO_AUX_BUFFERS_TXT));

	for(i = 0 ; i < sizeof(SpecialKeys) / sizeof(struct SpecialKey) ; i++)
		SpecialTable[SpecialKeys[i] . Key] = (JUMP)SpecialKeys[i] . Routine;

	if(!(AbortTable = (JUMP *)AllocVec(256 * sizeof(JUMP),MEMF_ANY)))
		MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocaleString(MSG_GLOBAL_NO_AUX_BUFFERS_TXT));

	for(i = 0 ; i < 256 ; i++)
	{
		switch(AbortMap[i])
		{
			case 0:	AbortTable[i] = ParseCode;
				break;

			case 1:	AbortTable[i] = (JUMP)DoCancel;
				break;

			case 2:	AbortTable[i] = DoNewEsc;
				break;

			case 3:	AbortTable[i] = DoNewCsi;
				break;
		}
	}

		/* Allocate the ANSI sequence work buffer. */

	if(!(StripBuffer = (UBYTE *)AllocVec(Config . SerBuffSize,MEMF_ANY)))
		return(LocaleString(MSG_GLOBAL_NO_AUX_BUFFERS_TXT));

		/* Set up the serial driver. */

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

		DeleteSerial();
	}
	else
	{
		if(SerialMessage)
		{
			MyEasyRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SerialMessage);

			SerialMessage = NULL;
		}
	}

		/* Get two signal bits. */

	if((ClipBit = AllocSignal(-1)) == -1)
		return(LocaleString(MSG_TERMINIT_FAILED_TO_GET_CLIP_SIGNAL_TXT));

	if((CheckBit = AllocSignal(-1)) == -1)
		return(LocaleString(MSG_TERMINIT_FAILED_TO_GET_CHECK_SIGNAL_TXT));

		/* Load alternative beep sound if desired. */

	if(Config . BeepSound[0])
		OpenSound(Config . BeepSound);

	if(!CreateBeep())
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_AUDIO_DEVICE_TXT));

	if(!(TimePort = (struct MsgPort *)CreateMsgPort()))
		return(LocaleString(MSG_GLOBAL_FAILED_TO_CREATE_MSGPORT_TXT));

	if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_IOREQUEST_TXT));

	if(OpenDevice("timer.device",UNIT_VBLANK,TimeRequest,0))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_OPEN_TIMER_DEVICE_TXT));

	TimerBase = (struct Device *)TimeRequest -> tr_node . io_Device;

	if(ClipProcess = CreateNewProcTags(
		NP_Entry,	ClipServer,
		NP_Name,	"term clipboard process",
		NP_WindowPtr,	-1,
		NP_Priority,	20,
	TAG_DONE))
		Wait(SIGBREAKF_CTRL_C);

	if(!ClipProcess)
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_CLIPBOARD_SERVER_TXT));

		/* Add the global term port. */

	if(!TermPort)
	{
		if(!(TermPort = (struct TermPort *)AllocVec(sizeof(struct TermPort),MEMF_PUBLIC|MEMF_CLEAR)))
			return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_GLOBAL_PORT_TXT));

		NewList(&TermPort -> ExecNode . mp_MsgList);

		InitSemaphore(&TermPort -> OpenSemaphore);

		TermPort -> ExecNode . mp_Flags			= PA_IGNORE;
		TermPort -> ExecNode . mp_Node . ln_Name	= "term Port";

		AddPort(&TermPort -> ExecNode);
	}

		/* Keep another term task from removing the port. */

	TermPort -> HoldIt = TRUE;

		/* Install a new term process. */

	ObtainSemaphore(&TermPort -> OpenSemaphore);

	TermPort -> OpenCount++;

	TermPort -> HoldIt = FALSE;

	TermID = TermPort -> ID++;

	ReleaseSemaphore(&TermPort -> OpenSemaphore);

		/* Set up the ID string. */

	if(TermID)
		SPrintf(TermIDString,"TERM.%ld",TermID);
	else
		strcpy(TermIDString,"TERM");

		/* Install the hotkey handler. */

	SetupCx();

		/* Allocate the first few lines for the display buffer. */

	if(!(BufferLines = (UBYTE **)AllocVec(MaxLines * sizeof(UBYTE *),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_VIEW_BUFFER_TXT));

	if(!(XprIO = (struct XPR_IO *)AllocVec(sizeof(struct XPR_IO),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_PROTOCOL_BUFFER_TXT));

	if(!(FileAnchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_CREATE_ANCHOR_PATH_TXT));

		/* Create the download list access semaphore. */

	if(!(DownloadSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_SEMAPHORE_TXT));

	InitSemaphore(DownloadSemaphore);

	NewList(&SequenceList);
	NewList(&PacketHistoryList);
	NewList(&DownloadList);
	NewList(&EmptyList);

		/* Create the buffer access semaphore. */

	if(!(BufferSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_SEMAPHORE_TXT));

	InitSemaphore(BufferSemaphore);

		/* Set up the external emulation macro data. */

	if(!(XEM_MacroKeys = (struct XEmulatorMacroKey *)AllocVec((2 + 10 * 4) * sizeof(struct XEmulatorMacroKey),MEMF_ANY|MEMF_CLEAR)))
		return(LocaleString(MSG_TERMINIT_FAILED_TO_ALLOCATE_MACRO_KEY_DATA_TXT));

	strcpy(LastXprLibrary,Config . Protocol);

	ProtocolSetup();

		/* Double buffered file locking. */

	NewList(&DoubleBufferList);

	InitSemaphore(&DoubleBufferSemaphore);

		/* Load a keymap file if required. */

	if(Config . KeyMapName[0])
		KeyMap = LoadKeyMap(Config . KeyMapName);

	if(!(TermRexxPort = (struct MsgPort *)CreateMsgPort()))
		return(LocaleString(MSG_GLOBAL_FAILED_TO_CREATE_MSGPORT_TXT));

		/* If rexxsyslib.library opens cleanly it's time for
		 * us to create the background term Rexx server.
		 */

	if(RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME,0))
	{
			/* Create a background process handling the
			 * rexx messages asynchronously.
			 */

		if(RexxProcess = (struct Process *)CreateNewProcTags(
			NP_Entry,	RexxServer,
			NP_Name,	"term Rexx Process",
			NP_Priority,	5,
			NP_StackSize,	8192,
			NP_WindowPtr,	-1,
		TAG_END))
		{
			Wait(SIGBREAKF_CTRL_C);

			if(!RexxProcess)
				return(LocaleString(MSG_TERMINIT_UNABLE_TO_CREATE_AREXX_PROCESS_TXT));
		}
	}

	BinaryTransfer	= TRUE;

	Status		= STATUS_READY;
	Online		= FALSE;

	InSequence	= FALSE;
	Quiet		= FALSE;

	NewList(&TransferInfoList);

	CommandHook . h_Entry		= (APTR)CommandKey;
	CommandHook . h_SubEntry	= NULL;
	CommandHook . h_Data		= NULL;

		/* Create the whole display. */

	if(Result = CreateDisplay(TRUE))
		return(Result);
	else
		return(NULL);
}
