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

#include "TermGlobal.h"

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

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

VOID
ConfigSetup()
{
	if(strcmp(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 . Font != Config . Font)
	{
		if(Config . Font == FONT_IBM && IBM)
			CurrentFont = IBM;
		else
			CurrentFont = Topaz;

		SetFont(RPort,CurrentFont);
	}

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

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

	if(memcmp(&PrivateConfig,&Config,58))
	{
		ClearSerial();

		DeleteSerial();

		if(!CreateSerial())
		{
			MyEasyRequest(Window,"`term' has a problem:\nFailed to open %s!","Continue",Config . SerialDevice);

			DeleteSerial();
		}
	}

	if(!ResetDisplay && 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:
			default:		BlinkColours[3] = BlinkColours[0];
						break;
		}
	}

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

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

		BackupRender();

		SetAPen(RPort,0);
		RectFill(RPort,0,(LastLine + 1) * 8,Window -> Width - 1,Window -> Height - 1);

		BackupRender();
	}
	else
	{
		LastColumn	= (Window -> Width >> 3) - 1;
		LastLine	= (Window -> Height >> 3) - 1;

		if(!RegionSet)
			Bottom = LastLine;
	}

	if(CursorY > LastLine)
		CursorY = LastLine;

	if(PrivateConfig . FontScale == SCALE_HALF && Config . FontScale != SCALE_HALF)
	{
		CursorX >>= 1;

		if(Config . EightyColumns)
			LastColumn = 79;
		else
			LastColumn = (Window -> Width >> 3) - 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 && Config . EmulationName[0])
	{
		if(Stricmp(PrivateConfig . EmulationName,Config . EmulationName))
		{
			if(!ResetDisplay)
			{
				if(!CreateEmulator(Config . EmulationName,TRUE))
				{
					Config . Emulation = EMULATION_ANSIVT100;

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

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

					EraseScreen("2");
				}

				NewEmulatorPlease = FALSE;
			}
			else
				NewEmulatorPlease = TRUE;
		}
		else
		{
			if(!Console)
				NewEmulatorPlease = TRUE;
		}
	}

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

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

	if(Config . DisableBlinking && !ResetDisplay)
		LoadRGB4(VPort,&Config . Colours[0],16);

	SetCursor();
}

	/* 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("term");
	}
	else
	{
		PublicModes &= ~SHANGHAI;

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

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

		SetPubScreenModes(PublicModes);
	}
}

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

	if(Config . Emulation == EMULATION_EXTERNAL)
		DeleteEmulator(NewEmulatorPlease);

	NewEmulatorPlease = FALSE;

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

		Signal(StatusTask,SIGBREAKF_CTRL_C);

		Wait(SIGBREAKF_CTRL_C);
	}

	DeleteRaster();

	DeleteScale();

	if(Screen)
		ScreenToBack(Screen);

	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(FastWindow)
	{
		HadFastMacros = TRUE;

		CloseFastWindow();
	}
	else
		HadFastMacros = FALSE;

	if(Menu)
	{
		FreeMenus(Menu);

		Menu = NULL;
	}

	if(VisualInfo)
	{
		FreeVisualInfo(VisualInfo);

		VisualInfo = NULL;
	}

	DeletePacketWindow();

	if(Screen)
	{
		CloseScreen(Screen);

		Screen = NULL;
	}

	return(TRUE);
}

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

UBYTE *
CreateDisplay(BYTE FirstSetup)
{
	UWORD		 Dummy = ~0,Count = 0,i;
	LONG		 ErrorCode;
	ULONG		 TagArray[9];
	struct MenuItem	*SomeItem;

		/* 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:	TagArray[Count++] = 4;

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

					TagArray[Count++] = SA_Pens;
					TagArray[Count++] = (LONG)&ANSIPens;

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

					break;

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

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

					TagArray[Count++] = SA_Pens;
					TagArray[Count++] = (LONG)&EGAPens;

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

					break;

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

					TagArray[Count++] = SA_Pens;
					TagArray[Count++] = (LONG)&Dummy;

					break;

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

					TagArray[Count++] = SA_Pens;
					TagArray[Count++] = (LONG)&Dummy;

					break;
	}

		/* Terminate the tag array. */

	TagArray[Count] = TAG_END;

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

OpenS:	SPrintf(ScreenTitle,"%s (%s) ARexx ID/Screen ID = \"%s\"",TermName,TermDate,TermIDString);

	if(!(Screen = (struct Screen *)OpenScreenTags(NULL,
		SA_Title,	ScreenTitle,
		SA_Overscan,	OSCAN_TEXT,
		SA_DisplayID,	Config . DisplayMode,
		SA_Font,	&DefaultFont,
		SA_Behind,	TRUE,
		SA_AutoScroll,	TRUE,
		SA_PubName,	TermIDString,
		SA_ErrorCode,	&ErrorCode,
		TAG_MORE,	&TagArray[0],
	TAG_END)))
	{
			/* We've got an error. */

		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;

							goto OpenS;

			case OSERR_PUBNOTUNIQUE:	return("Screen ID already in use");

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

			default:			return("Failed to open screen");
		}
	}

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

	if(!CreateScale())
		return("Failed to create font scaling info");

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

	if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
		return("Failed to obtain visual info");

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

		/* Open the main window. */

	if(!(Window = OpenWindowTags(NULL,
		WA_Top,		Screen -> BarHeight + 2,
		WA_Left,	0,
		WA_Width,	Screen -> Width,
		WA_Height,	Screen -> Height - (Screen -> BarHeight + 2) - (4 + 2 * 8),
		WA_Backdrop,	TRUE,
		WA_Borderless,	TRUE,
		WA_SmartRefresh,TRUE,
		WA_CustomScreen,Screen,
		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("Failed to open window");

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

	PushWindow(Window);

	if(TermPort)
		TermPort -> TopWindow = Window;

		/* Open the tiny status window. */

	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_CustomScreen,Screen,
		WA_RMBTrap,	TRUE,
	TAG_DONE)))
		return("Failed to open status window");

		/* Default console setup. */

	if(Config . EightyColumns)
	{
		LastColumn = 79;

		if(Config . EightyColumns == 1)
			LastLine = 23;
		else
			LastLine = 24;
	}
	else
	{
		LastColumn	= (Window -> Width >> 3) - 1;
		LastLine	= (Window -> Height >> 3) - 1;
	}

	CursorX = 0;
	CursorY	= 0;

	SetDrMd(Window -> RPort,JAM2);

	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("Unable to create screen raster");

		/* Reset terminal emulation. */

	Reset();

		/* Set the font. */

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

	SetFont(RPort,CurrentFont);

		/* Create the menu strip. */

	if(!(Menu = CreateMenus(TermMenu,
		GTMN_FrontPen, 0,
	TAG_DONE)))
		return("Failed to create menus");

		/* Do the menu layout. */

	if(!LayoutMenus(Menu,VisualInfo,
		GTMN_TextAttr,&DefaultFont,
	TAG_DONE))
		return("Failed to layout menus");

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

	if(!RexxSysBase)
	{
		struct MenuItem *SomeItem;

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

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

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

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

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

		/* Add the menu to the windows. */

	SetMenuStrip(Window,Menu);
	SetMenuStrip(StatusWindow,Menu);

		/* Enable the menu. */

	Window -> Flags		&= ~WFLG_RMBTRAP;
	StatusWindow -> Flags	&= ~WFLG_RMBTRAP;

		/* Set up the status window, draw a border. */

	DrawBevelBox(StatusWindow -> RPort,0,0,StatusWindow -> Width,StatusWindow -> Height,
		GT_VisualInfo,VisualInfo,
	TAG_DONE);

		/* Render the information. */

	switch(Config . ColourMode)
	{
		case COLOUR_EIGHT:	SetAPen(StatusWindow -> RPort,4);
					break;

		case COLOUR_SIXTEEN:	SetAPen(StatusWindow -> RPort,8);
					break;

		case COLOUR_AMIGA:
		default:		SetAPen(StatusWindow -> RPort,1);
					break;
	}

	SetBPen(StatusWindow -> RPort,0);
	SetDrMd(StatusWindow -> RPort,JAM2);

	Move(StatusWindow -> RPort,(Screen -> Width - (79 << 3)) >> 1,2 + 6 + 0);
	Text(StatusWindow -> RPort,"Status ..:          Protocol :          Baud Rate:          Time ....:",70);

	Move(StatusWindow -> RPort,(Screen -> Width - (79 << 3)) >> 1,2 + 6 + 8);
	Text(StatusWindow -> RPort,"Font ....:          Emulation:          Parameters          Online ..:",70);

	switch(Config . ColourMode)
	{
		case COLOUR_EIGHT:	SetAPen(StatusWindow -> RPort,6);
					break;

		case COLOUR_SIXTEEN:	SetAPen(StatusWindow -> RPort,7);
					break;

		case COLOUR_AMIGA:	SetAPen(StatusWindow -> RPort,2);
					break;

		case COLOUR_MONO:	SetAPen(StatusWindow -> RPort,1);
					break;
	}

		/* Create the status server. */

	if(!(StatusTask = (struct Task *)CreateTask("term Status Task",5,StatusServer,4096)))
		return("Unable to create status task");

		/* Wait for ringback signal. */

	Wait(SIGBREAKF_CTRL_C);

		/* Status server has `died'. */

	if(!StatusTask)
		return("Unable to create status task");

		/* Restart the fast! macro panel. */

	if(HadFastMacros)
		OpenFastWindow();

		/* 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(!CreateEmulator(Config . EmulationName,NewEmulatorPlease))
		{
			Config . Emulation = EMULATION_ANSIVT100;

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

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

				RasterEraseScreen(2);

				EraseScreen("2");

				OffMenu(Window,FULLMENUNUM(0,4,0));
				OffMenu(Window,FULLMENUNUM(5,5,0));
			}
		}
	}

	NewEmulatorPlease = FALSE;

	return(NULL);
}

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

VOID
CloseAll()
{
	if(IntuitionBase && Window && StatusWindow)
		BlockWindows();

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

		Wait(SIGBREAKF_CTRL_C);
	}

	if(ClipProcess)
	{
		Signal(ClipProcess,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);

	FreeSubList();

	ClearFastMacroList(&FastMacroList);

	if(FileCapture)
	{
		BufferClose(FileCapture);

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

	if(PrinterCapture)
		Close(PrinterCapture);

	DeleteEmulator(TRUE);

	DeleteDisplay();

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

		if(TimeRequest -> tr_node . io_Message . mn_ReplyPort)
			DeleteMsgPort(TimeRequest -> tr_node . io_Message . mn_ReplyPort);

		DeleteIORequest(TimeRequest);
	}

	DeleteBeep();

	ClearSerial();

	DeleteSerial();

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

	if(KeymapBase)
		CloseLibrary(KeymapBase);

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

	if(GFX)
		CloseFont(GFX);

	if(Topaz)
		CloseFont(Topaz);

	if(RexxSysBase)
		CloseLibrary(RexxSysBase);

	if(GadToolsBase)
		CloseLibrary(GadToolsBase);

	if(UtilityBase)
		CloseLibrary(UtilityBase);

	if(GfxBase)
		CloseLibrary(GfxBase);

	if(IntuitionBase)
		CloseLibrary(IntuitionBase);

	if(RemoteCurrentDir)
		UnLock(RemoteCurrentDir);

	if(DOSBase)
		CloseLibrary(DOSBase);

	if(WBenchMsg)
	{
		Forbid();

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

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

UBYTE *
OpenAll()
{
	UBYTE		 PathBuffer[256];
	struct MsgPort	*IOPort;
	WORD		 i;
	UBYTE		*Result;

	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
		return("Failed to open intuition.library");

	if((SysBase -> SoftVer < 175 && SysBase -> LibNode . lib_Version == 37) || SysBase -> LibNode . lib_Version < 37)
	{
		if(!MyEasyRequest(NULL,"This   nifty  little  program  requires  Kickstart\nversion 37.175 or higher to work properly.  You are\ncurrently  using Kickstart version %ld.%ld, do you\nreally wish to continue???",
			"Proceed with fingers crossed|Back out backwards!",SysBase -> LibNode . lib_Version,SysBase -> SoftVer))
				return("");
	}

	PublicModes = SetPubScreenModes(0);

	SetPubScreenModes(PublicModes);

	if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
		return("Failed to open graphics.library");

	if(!(UtilityBase = OpenLibrary("utility.library",0)))
		return("Failed to open utility.library");

	if(!(GadToolsBase = OpenLibrary("gadtools.library",0)))
		return("Failed to open gadtools.library");

	if(!(AslBase = OpenLibrary("asl.library",0)))
		return("Failed to open asl.library");

	if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
		return("Failed to open iffparse.library");

	if(!(CxBase = OpenLibrary("commodities.library",0)))
		return("Failed to open commodities.library");

	if(!(KeymapBase = OpenLibrary("keymap.library",0)))
		return("Failed to open keymap.library");

	if(!(LayersBase = OpenLibrary("layers.library",0)))
		return("Failed to open layers.library");

	if(!(Topaz = (struct TextFont *)OpenFont(&DefaultFont)))
		return("Failed to open default font");

	if(!(ConsoleRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to allocate console request");

	if(OpenDevice("console.device",CONU_LIBRARY,ConsoleRequest,0))
		return("Failed to open console.device");

	ConsoleDevice = &ConsoleRequest -> io_Device -> dd_Library;

	if(!(FakeInputEvent = (struct InputEvent *)AllocVec(sizeof(struct InputEvent),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to allocate InputEvent");

	FakeInputEvent -> ie_Class = IECLASS_RAWKEY;

	if(!(MacroKeys = (struct MacroKeys *)AllocVec(sizeof(struct MacroKeys),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to allocate MacroKeys");

	if(DiskfontBase = (struct Library *)OpenLibrary("diskfont.library",0))
	{
		if(!(IBM = (struct TextFont *)OpenFont(&IBMFont)))
			IBM = (struct TextFont *)OpenDiskFont(&IBMFont);

		if(!(GFX = (struct TextFont *)OpenFont(&GFXFont)))
			GFX = (struct TextFont *)OpenDiskFont(&GFXFont);
	}

		/* Initialize the data flow parser. */

	FlowInit();

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

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

		strcpy(PathBuffer,"ENVARC:term");

		SetEnvDOS("TERMPATH",PathBuffer);

		ThisProcess -> pr_WindowPtr = (APTR)-1;

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

		if(FileLock)
			UnLock(FileLock);

		ThisProcess -> pr_WindowPtr = LastPtr;
	}

		/* Create proper path names. */

	strcpy(LastConfig,PathBuffer);

	AddPart(LastConfig,"Preferences.term",256);

	strcpy(DefaultPubScreen,"Workbench");

		/* Read some more environment variables. */

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

	GetEnvDOS("EDITOR",Config . Editor);

		/* Look for the default configuration file. */

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

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

	NewList(&FastMacroList);

	strcpy(LastPhone,Config . DefaultStorage);
	strcpy(LastMacros,Config . DefaultStorage);
	strcpy(LastKeys,Config . DefaultStorage);
	strcpy(LastSpeech,Config . DefaultStorage);
	strcpy(LastFastMacros,Config . DefaultStorage);

	AddPart(LastPhone,"Phonebook.term",256);
	AddPart(LastMacros,"Macros.term",256);
	AddPart(LastKeys,"Hotkeys.term",256);
	AddPart(LastSpeech,"Speech.term",256);
	AddPart(LastFastMacros,"Fast!Macros.term",256);

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

	LoadPhonebook(LastPhone);

		/* 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(!ReadIFFData(LastKeys,&Hotkeys,sizeof(struct Hotkeys),'HOTK'))
	{
		strcpy(Hotkeys . termScreenToFront,"lshift rshift return");
		strcpy(Hotkeys . BufferScreenToFront,"control rshift return");
		strcpy(Hotkeys . SkipDialEntry,"control lshift rshift return");

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

		/* Set up the serial driver. */

	if(!CreateSerial())
	{
		MyEasyRequest(NULL,"`term' has a problem:\nFailed to open %s!","Continue",Config . SerialDevice);

		DeleteSerial();
	}

		/* Load alternative beep sound if desired. */

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

	if(!CreateBeep())
		return("Failed to open audio.device");

	if(!(IOPort = (struct MsgPort *)CreateMsgPort()))
		return("Failed to create msgport");

	if(!(IOPort = (struct MsgPort *)CreateMsgPort()))
		return("Failed to create msgport");

	if(!(TimeRequest = (struct timerequest *)CreateIORequest(IOPort,sizeof(struct timerequest))))
	{
		DeleteMsgPort(IOPort);
		return("Failed to create iorequest");
	}

	if(OpenDevice("timer.device",UNIT_VBLANK,TimeRequest,0))
		return("Failed to open timer.device");

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

	ClipProcess = CreateNewProcTags(
		NP_Entry,	ClipServer,
		NP_Name,	"term Clipboard Server",
		NP_WindowPtr,	-1,
		NP_Priority,	20,
	TAG_DONE);

	Wait(SIGBREAKF_CTRL_C);

	if(!ClipProcess)
		return("Failed to create clipboard server");

		/* Add the global term port. */

	if(!TermPort)
	{
		if(!(TermPort = (struct TermPort *)AllocVec(sizeof(struct TermPort),MEMF_PUBLIC|MEMF_CLEAR)))
			return("Failed to create global port");

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

		/* Create the speech data. */

	CreateSpeech();

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

	if(!(BufferLines = (UBYTE **)AllocVec(MaxLines * sizeof(UBYTE *),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to allocate view buffer");

	if(!(XprIO = (struct XPR_IO *)AllocVec(sizeof(struct XPR_IO),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to create protocol buffer");

	if(!(FileAnchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to create anchor path");

		/* Create the download list access semaphore. */

	if(!(DownloadSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to allocate semaphore");

	InitSemaphore(DownloadSemaphore);

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

		/* Create the buffer access semaphore. */

	if(!(BufferSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_PUBLIC|MEMF_CLEAR)))
		return("Failed to allocate semaphore");

	InitSemaphore(BufferSemaphore);

	strcpy(LastXprLibrary,Config . Protocol);

	ProtocolSetup();

		/* Double buffered file locking. */

	NewList(&DoubleBufferList);
	InitSemaphore(&DoubleBufferSemaphore);

	if(!(TermRexxPort = (struct MsgPort *)CreateMsgPort()))
		return("Failed to create msgport");

		/* 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("Unable to create rexx process");
		}
	}

	BinaryTransfer	= TRUE;

	Status		= STATUS_READY;
	Online		= FALSE;

	InSequence	= FALSE;
	Quiet		= FALSE;

	memset(&SpecialMap[0],-1,256);

	for(i = 0 ; i < SPECIALKEYS ; i++)
		SpecialMap[SpecialKeys[i] . Key] = i;

	InitHook(&CommandHook,CommandKey);

		/* Create the whole display. */

	if(Result = CreateDisplay(TRUE))
		return(Result);
	else
	{
		if(Config . RasterEnabled)
		{
			OnMenu(Window,FULLMENUNUM(0,4,0));
			OnMenu(Window,FULLMENUNUM(5,5,0));
		}
		else
		{
			OffMenu(Window,FULLMENUNUM(0,4,0));
			OffMenu(Window,FULLMENUNUM(5,5,0));
		}

		return(NULL);
	}
}
