/*
**	termConfig.c
**
**	Configuration processing routines
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Number of chunks to stop at. */

#define	NUM_STOPS	19

	/* Reset routine function pointer. */

typedef VOID		(* RESET)(APTR,STRPTR);

	/* Local routines. */

STATIC BYTE		ReadSerialPrefs(struct SerialPrefs *Prefs);

STATIC VOID		ResetSerialConfig(struct SerialSettings *SerialConfig);
STATIC VOID		ResetModem(struct ModemSettings *ModemConfig);
STATIC VOID		ResetScreen(struct ScreenSettings *ScreenConfig);
STATIC VOID		ResetTerminal(struct TerminalSettings *TerminalConfig);
STATIC VOID		ResetEmulation(struct EmulationSettings *EmulationConfig);
STATIC VOID		ResetClip(struct ClipSettings *ClipConfig);
STATIC VOID		ResetCapture(struct CaptureSettings *CaptureConfig);
STATIC VOID		ResetFile(struct FileSettings *FileConfig,STRPTR PathBuffer);
STATIC VOID		ResetPath(struct PathSettings *PathConfig,STRPTR PathBuffer);
STATIC VOID		ResetMisc(struct MiscSettings *MiscConfig);
STATIC VOID		ResetCommand(struct CommandSettings *CommandConfig);
STATIC VOID		ResetTransfer(struct TransferSettings *TransferConfig,STRPTR DefaultLib);

STATIC BYTE		WriteConfigChunk(struct IFFHandle *Handle,struct Configuration *Config,BYTE Type,APTR TempBuffer,STRPTR Password);
STATIC BYTE		WriteConfigChunks(struct IFFHandle *Handle,struct Configuration *Config,APTR TempBuffer,STRPTR Password);
STATIC UBYTE		IsConfigChunk(ULONG ID);
STATIC BYTE		ReadConfigChunk(struct IFFHandle *Handle,struct Configuration *Config,UBYTE Type,LONG Len,STRPTR Password);

STATIC UWORD SizeTable[] =
{
	sizeof(struct SerialSettings),
	sizeof(struct ModemSettings),
	sizeof(struct CommandSettings),
	sizeof(struct ScreenSettings),
	sizeof(struct TerminalSettings),
	sizeof(struct PathSettings),
	sizeof(struct MiscSettings),
	sizeof(struct ClipSettings),
	sizeof(struct CaptureSettings),
	sizeof(struct FileSettings),
	sizeof(struct EmulationSettings),
	sizeof(struct TransferSettings)
};

STATIC RESET ResetTable[] =
{
	(RESET)ResetSerialConfig,
	(RESET)ResetModem,
	(RESET)ResetCommand,
	(RESET)ResetScreen,
	(RESET)ResetTerminal,
	ResetPath,
	(RESET)ResetMisc,
	(RESET)ResetClip,
	(RESET)ResetCapture,
	ResetFile,
	(RESET)ResetEmulation,
	ResetTransfer
};

STATIC ULONG TypeTable[] =
{
	ID_SERL,
	ID_MODM,
	ID_COMD,
	ID_SCRN,
	ID_TRML,
	ID_PATH,
	ID_MISC,
	ID_CLIP,
	ID_CPTR,
	ID_FILE,
	ID_EMLN,
	ID_XFER
};

STATIC ULONG Stops[NUM_STOPS * 2] =
{
	ID_TERM,ID_CAT,
	ID_TERM,ID_VERS,
	ID_TERM,ID_DIAL,
	ID_TERM,ID_DATE,
	ID_TERM,ID_PHON,
	ID_TERM,ID_PSWD,

	ID_TERM,ID_SERL,
	ID_TERM,ID_MODM,
	ID_TERM,ID_COMD,
	ID_TERM,ID_SCRN,
	ID_TERM,ID_TRML,
	ID_TERM,ID_PATH,
	ID_TERM,ID_MISC,
	ID_TERM,ID_CLIP,
	ID_TERM,ID_CPTR,
	ID_TERM,ID_FILE,
	ID_TERM,ID_EMLN,
	ID_TERM,ID_XFER,
	ID_TERM,ID_WINF
};

STATIC VOID __regargs
FixOldConfig(struct Configuration *Config,UBYTE ConfigChunkType,BOOLEAN IsPhonebook)
{
	if(ConfigChunkType == PREF_SERIAL)
		Config -> SerialConfig -> UseOwnDevUnit = TRUE;

	if(ConfigChunkType == PREF_SCREEN)
	{
		Config -> ScreenConfig -> UsePens	= TRUE;
		Config -> ScreenConfig -> Depth		= 0;
		Config -> ScreenConfig -> PenColourMode	= 42;	// Avoid trouble
	}

	if(ConfigChunkType == PREF_TRANSFER)
		Config -> TransferConfig -> MangleFileNames = FALSE;

	if(ConfigChunkType == PREF_MODEM)
		Config -> ModemConfig -> AbortHangsUp = FALSE;

	if(ConfigChunkType == PREF_COMMAND && IsPhonebook)
	{
		strcpy(Config -> CommandConfig -> LoginMacro,Config -> CommandConfig -> StartupMacro);

		memset(Config -> CommandConfig -> StartupMacro,0,sizeof(Config -> CommandConfig -> StartupMacro));
	}

	if(ConfigChunkType == PREF_CAPTURE)
		Config -> CaptureConfig -> SearchHistory = 10;

	if(ConfigChunkType == PREF_EMULATION)
	{
		if(Config -> EmulationConfig -> DestructiveBackspace < 0 || Config -> EmulationConfig -> DestructiveBackspace > 2)
			Config -> EmulationConfig -> DestructiveBackspace = 1;
	}
}

VOID __regargs
FixScreenPens(struct ScreenSettings *ScreenConfig)
{
	WORD i,Count;

	for(Count = 0, i = DETAILPEN ; i <= BARTRIMPEN ; i++)
	{
		if(ScreenConfig -> PenArray[i])
			Count++;
	}

	if(!Count)
		ScreenConfig -> UsePens = TRUE;
}

	/* ReadSerialPrefs():
	 *
	 *	Reads the default serial preferences settings.
	 */

STATIC BYTE
ReadSerialPrefs(struct SerialPrefs *Prefs)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	LONG			 Error = 0;

		/* Allocate an IFF handle. */

	if(Handle = AllocIFF())
	{
			/* Open the preferences settings file. */

		if(Handle -> iff_Stream = Open("ENV:sys/serial.prefs",MODE_OLDFILE))
		{
				/* Make it known as a DOS file handle. */

			InitIFFasDOS(Handle);

				/* Open the file for reading. */

			if(!(Error = OpenIFF(Handle,IFFF_READ)))
			{
					/* Stop at the `body' chunk. */

				if(!(Error = StopChunk(Handle,ID_PREF,ID_SERL)))
				{
						/* Look for it... */

					if(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
							/* Read the data. */

						if(ReadChunkBytes(Handle,Prefs,sizeof(struct SerialPrefs)) == sizeof(struct SerialPrefs))
							Success = TRUE;
						else
							Error = IoErr();
					}
				}

					/* Close the handle. */

				CloseIFF(Handle);
			}

				/* Release the handle. */

			Close(Handle -> iff_Stream);
		}
		else
			Error = IoErr();

			/* Clean up. */

		FreeIFF(Handle);
	}
	else
		Error = ERR_NO_MEM;

	if(Error)
		SetIoErr(Error);

		/* Return sucess/failure. */

	return(Success);
}

STATIC VOID
ResetSerialConfig(struct SerialSettings *SerialConfig)
{
	STATIC BYTE			SerialPrefsRead		= FALSE,
					SerialPrefsReadFailed	= FALSE;
	STATIC struct SerialPrefs	SerialPrefs;

		/* The program will only try to read the preferences
		 * settings once; if the first access failed, no
		 * other accesses will be made.
		 */

	if(!SerialPrefsRead && !SerialPrefsReadFailed)
		SerialPrefsReadFailed = ReadSerialPrefs(&SerialPrefs) ^ TRUE;

		/* Did we succeed in reading the file? */

	if(!SerialPrefsRead)
	{
		SerialConfig -> BaudRate		= 2400;
		SerialConfig -> BitsPerChar		= 8;
		SerialConfig -> Parity			= PARITY_NONE;
		SerialConfig -> StopBits		= 1;
		SerialConfig -> HandshakingProtocol	= HANDSHAKING_NONE;
		SerialConfig -> xONxOFF			= TRUE;
		SerialConfig -> SerialBufferSize	= 32768;
	}
	else
	{
			/* Fill in the common data. */

		SerialConfig -> BaudRate		= SerialPrefs . sp_BaudRate;
		SerialConfig -> SerialBufferSize	= SerialPrefs . sp_InputBuffer;
		SerialConfig -> BitsPerChar		= SerialPrefs . sp_BitsPerChar;
		SerialConfig -> StopBits		= SerialPrefs . sp_StopBits;

			/* Convert the handshaking mode. */

		switch(SerialPrefs . sp_InputHandshake)
		{
			case HSHAKE_NONE:

				SerialConfig -> HandshakingProtocol	= HANDSHAKING_NONE;
				SerialConfig -> xONxOFF			= FALSE;

				break;

			case HSHAKE_RTS:

				SerialConfig -> HandshakingProtocol	= HANDSHAKING_RTSCTS;
				SerialConfig -> xONxOFF			= FALSE;

				break;

			default:

				SerialConfig -> HandshakingProtocol	= HANDSHAKING_NONE;
				SerialConfig -> xONxOFF			= TRUE;

				break;
		}

			/* Convert the parity settings. */

		if(SerialPrefs . sp_Parity <= PARITY_SPACE)
			SerialConfig -> Parity = SerialPrefs . sp_Parity;
		else
			SerialConfig -> Parity = PARITY_NONE;

		SerialPrefsRead = TRUE;
	}

	strcpy(SerialConfig -> SerialDevice,SERIALNAME);

	SerialConfig -> Duplex		= DUPLEX_FULL;
	SerialConfig -> HighSpeed	= FALSE;
	SerialConfig -> Shared		= FALSE;
	SerialConfig -> BreakLength	= 250000;
	SerialConfig -> UnitNumber	= 0;
	SerialConfig -> StripBit8	= FALSE;
	SerialConfig -> CheckCarrier	= FALSE;
	SerialConfig -> PassThrough	= FALSE;
	SerialConfig -> IgnoreCarrier	= FALSE;

	SerialConfig -> Quantum		= 256;

	SerialConfig -> UseNet		= FALSE;
	SerialConfig -> NetID		= 0002;
}

STATIC VOID
ResetModem(struct ModemSettings *ModemConfig)
{
	strcpy(ModemConfig -> ModemInit,	"ATZ\\r");
	strcpy(ModemConfig -> ModemExit,	"");
	strcpy(ModemConfig -> ModemHangup,	"~~~~~~~~+++~~~~~~ATH0\\r");
	strcpy(ModemConfig -> DialPrefix,	"~~ATDP");
	strcpy(ModemConfig -> DialSuffix,	"\\r");

	strcpy(ModemConfig -> NoCarrier,	"NO CARRIER");
	strcpy(ModemConfig -> NoDialTone,	"NO DIALTONE");
	strcpy(ModemConfig -> Connect,		"CONNECT");
	strcpy(ModemConfig -> Voice,		"VOICE");
	strcpy(ModemConfig -> Ring,		"RING");
	strcpy(ModemConfig -> Busy,		"BUSY");
	strcpy(ModemConfig -> Ok,		"OK");
	strcpy(ModemConfig -> Error,		"ERROR");

	ModemConfig -> RedialDelay		= 2;
	ModemConfig -> DialRetries		= 10;
	ModemConfig -> DialTimeout		= 60;
	ModemConfig -> ConnectAutoBaud		= FALSE;
	ModemConfig -> DropDTR			= FALSE;
	ModemConfig -> RedialAfterHangup	= FALSE;

	ModemConfig -> NoCarrierIsBusy		= TRUE;

	ModemConfig -> ConnectLimit		= 0;
	ModemConfig -> ConnectLimitMacro[0]	= 0;

	ModemConfig -> TimeToConnect		= 0;
}

STATIC VOID
ResetScreen(struct ScreenSettings *ScreenConfig)
{
	memset(ScreenConfig,0,sizeof(struct ScreenSettings));

	ScreenConfig -> DisplayMode		= DEFAULT_MONITOR_ID|HIRES_KEY;
	ScreenConfig -> ColourMode		= COLOUR_AMIGA;
	ScreenConfig -> MakeScreenPublic	= TRUE;
	ScreenConfig -> ShanghaiWindows		= FALSE;
	ScreenConfig -> TitleBar		= TRUE;
	ScreenConfig -> StatusLine		= STATUSLINE_STANDARD;
	ScreenConfig -> Blinking		= TRUE;
	ScreenConfig -> FasterLayout		= FALSE;
	ScreenConfig -> UseWorkbench		= FALSE;

	strcpy(ScreenConfig -> FontName,"topaz.font");
	ScreenConfig -> FontHeight = 8;

	ScreenConfig -> PubScreenName[0]	= 0;
	ScreenConfig -> TimeMode		= ONLINETIME_BOTH;
	ScreenConfig -> UsePens			= TRUE;
	ScreenConfig -> PenColourMode		= COLOUR_AMIGA;

	ScreenConfig -> DisplayWidth		= 0;
	ScreenConfig -> DisplayHeight		= 0;
	ScreenConfig -> OverscanType		= OSCAN_TEXT;

	ScreenConfig -> ShareScreen		= FALSE;
	ScreenConfig -> SplitStatus		= FALSE;
}

STATIC VOID
ResetTerminal(struct TerminalSettings *TerminalConfig)
{
	TerminalConfig -> BellMode		= BELL_AUDIBLE;
	TerminalConfig -> AlertMode		= ALERT_BEEP_SCREEN;
	TerminalConfig -> EmulationMode		= EMULATION_ANSIVT100;
	TerminalConfig -> FontMode		= FONT_STANDARD;

	TerminalConfig -> SendCR		= CR_ASCR;
	TerminalConfig -> SendLF		= LF_ASLF;
	TerminalConfig -> ReceiveCR		= CR_ASCR;
	TerminalConfig -> ReceiveLF		= LF_ASLF;

	TerminalConfig -> NumColumns		= 0;
	TerminalConfig -> NumLines		= 0;

	TerminalConfig -> KeyMapFileName[0]	= 0;
	TerminalConfig -> EmulationFileName[0]	= 0;
	TerminalConfig -> BeepFileName[0]	= 0;

	strcpy(TerminalConfig -> TextFontName,"topaz.font");
	TerminalConfig -> TextFontHeight = 8;

	TerminalConfig -> UseTerminalTask = FALSE;
	TerminalConfig -> Pad = 0;

	strcpy(TerminalConfig -> IBMFontName,"IBM.font");
	TerminalConfig -> IBMFontHeight = 8;
}

STATIC VOID
ResetEmulation(struct EmulationSettings *EmulationConfig)
{
	EmulationConfig -> CursorMode		= KEYMODE_STANDARD;
	EmulationConfig -> NumericMode		= KEYMODE_STANDARD;

	EmulationConfig -> NewLineMode		= FALSE;
	EmulationConfig -> InsertMode		= FALSE;

	EmulationConfig -> LineWrap		= TRUE;
	EmulationConfig -> CursorWrap		= FALSE;

	EmulationConfig -> FontScale		= SCALE_NORMAL;
	EmulationConfig -> ScrollMode		= SCROLL_JUMP;
	EmulationConfig -> DestructiveBackspace	= FALSE;
	EmulationConfig -> SwapBSDelete		= FALSE;
	EmulationConfig -> PrinterEnabled	= TRUE;
	EmulationConfig -> AnswerBack[0]	= 0;
	EmulationConfig -> CLSResetsCursor	= 0;

	EmulationConfig -> KeysLocked		= FALSE;
	EmulationConfig -> MaxScroll		= 0;
	EmulationConfig -> MaxJump		= 1;
	EmulationConfig -> CursorLocked		= FALSE;
	EmulationConfig -> FontLocked		= FALSE;
	EmulationConfig -> Pad			= 0;
}

STATIC VOID
ResetClip(struct ClipSettings *ClipConfig)
{
	ClipConfig -> ClipboardUnit	= 0;
	ClipConfig -> LineDelay		= 0;
	ClipConfig -> CharDelay		= 0;

	ClipConfig -> InsertPrefix[0] = 0;
	strcpy(ClipConfig -> InsertSuffix,"\\r");

	ClipConfig -> LinePrompt[0]	= 0;
	ClipConfig -> SendTimeout	= 0;
	ClipConfig -> PacingMode	= PACE_DIRECT;
}

STATIC VOID
ResetCapture(struct CaptureSettings *CaptureConfig)
{
	CaptureConfig -> LogActions		= FALSE;
	CaptureConfig -> LogCall		= FALSE;
	CaptureConfig -> LogFileName[0]		= 0;

	CaptureConfig -> MaxBufferSize		= 0;
	CaptureConfig -> BufferEnabled		= TRUE;

	CaptureConfig -> ConnectAutoCapture	= FALSE;
	CaptureConfig -> CaptureFilterMode	= FILTER_BOTH;
	CaptureConfig -> CapturePath[0]		= 0;

	CaptureConfig -> CallLogFileName[0]	= 0;
	CaptureConfig -> BufferPath[0]		= 0;

	CaptureConfig -> AutoCaptureDate	= AUTOCAPTURE_DATE_NAME;
	CaptureConfig -> SearchHistory		= 10;

	CaptureConfig -> OpenBufferWindow	= BUFFER_END;
	CaptureConfig -> OpenBufferScreen	= BUFFER_TOP;
	CaptureConfig -> BufferScreenPosition	= SCREEN_CENTRE;
	CaptureConfig -> BufferWidth		= 80;

	CaptureConfig -> RememberBufferWindow	= FALSE;
	CaptureConfig -> RememberBufferScreen	= FALSE;

	CaptureConfig -> BufferScreenMode	= INVALID_ID;
}

STATIC VOID
ResetFile(struct FileSettings *FileConfig,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

	strcpy(FileConfig -> ProtocolFileName,"xprzmodem.library");

	if(!LastTranslation[0])
	{
		strcpy(LastTranslation,PathBuffer);

		AddPart(LastTranslation,"translation.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(FileConfig -> TranslationFileName,LastTranslation);

	if(!LastMacros[0])
	{
		strcpy(LastMacros,PathBuffer);

		AddPart(LastMacros,"functionkeys.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(FileConfig -> MacroFileName,LastMacros);

	if(!LastFastMacros[0])
	{
		strcpy(LastFastMacros,PathBuffer);

		AddPart(LastFastMacros,"fastmacros.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(FileConfig -> FastMacroFileName,LastFastMacros);

	if(!LastCursorKeys[0])
	{
		strcpy(LastCursorKeys,PathBuffer);

		AddPart(LastCursorKeys,"cursorkeys.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(FileConfig -> CursorFileName,LastCursorKeys);
}

STATIC VOID
ResetPath(struct PathSettings *PathConfig,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

	strcpy(PathConfig -> DefaultStorage,PathBuffer);

	PathConfig -> ASCIIUploadPath[0]	= 0;
	PathConfig -> ASCIIDownloadPath[0]	= 0;
	PathConfig -> TextUploadPath[0]		= 0;
	PathConfig -> TextDownloadPath[0]	= 0;
	PathConfig -> BinaryUploadPath[0]	= 0;
	PathConfig -> BinaryDownloadPath[0]	= 0;

	strcpy(PathConfig -> HelpFile,"PROGDIR:term.guide");

	strcpy(PathConfig -> DefaultStorage,PathBuffer);

	GetEnvDOS(PathConfig -> Editor,"EDITOR");
}

STATIC VOID
ResetMisc(struct MiscSettings *MiscConfig)
{
	MiscConfig -> Priority			= 1;
	MiscConfig -> BackupConfig		= FALSE;

	MiscConfig -> OpenFastMacroPanel	= FALSE;
	MiscConfig -> ReleaseDevice		= TRUE;

	MiscConfig -> TransferServer		= TRUE;
	MiscConfig -> EmulationServer		= TRUE;

	MiscConfig -> OverridePath		= TRUE;
	MiscConfig -> AutoUpload		= TRUE;
	MiscConfig -> SetArchivedBit		= FALSE;
	MiscConfig -> IdentifyFiles		= IDENTIFY_FILETYPE;
	MiscConfig -> TransferIcons		= FALSE;
	MiscConfig -> CreateIcons		= FALSE;
	MiscConfig -> SimpleIO			= FALSE;
	MiscConfig -> PerfMeter			= FALSE;

	MiscConfig -> IOBufferSize		= 32768;
}

STATIC VOID
ResetCommand(struct CommandSettings *CommandConfig)
{
	CommandConfig -> StartupMacro[0]	= 0;
	CommandConfig -> LogoffMacro[0]		= 0;
	CommandConfig -> LoginMacro[0]		= 0;
	CommandConfig -> UploadMacro[0]		= 0;
	CommandConfig -> DownloadMacro[0]	= 0;
}

STATIC VOID
ResetTransfer(struct TransferSettings *TransferConfig,STRPTR DefaultLib)
{
	if(!DefaultLib)
		strcpy(TransferConfig -> DefaultLibrary,"xprzmodem.library");
	else
		strcpy(TransferConfig -> DefaultLibrary,DefaultLib);

	strcpy(TransferConfig -> ASCIIUploadLibrary,	"xprascii.library");
	strcpy(TransferConfig -> ASCIIDownloadLibrary,	"xprascii.library");

	TransferConfig -> TextUploadLibrary[0]		= 0;
	TransferConfig -> TextDownloadLibrary[0]	= 0;

	TransferConfig -> BinaryUploadLibrary[0]	= 0;
	TransferConfig -> BinaryDownloadLibrary[0]	= 0;

	TransferConfig -> InternalASCIIUpload		= FALSE;
	TransferConfig -> InternalASCIIDownload		= FALSE;
	TransferConfig -> QuietTransfer			= FALSE;
	TransferConfig -> MangleFileNames		= FALSE;

	TransferConfig -> LinePrompt[0]			= 0;
	TransferConfig -> SendTimeout			= 0;
	TransferConfig -> PacingMode			= PACE_DIRECT;
	TransferConfig -> StripBit8			= FALSE;
	TransferConfig -> IgnoreDataPastArnold		= TRUE;
	TransferConfig -> TerminatorChar		= 0x1A;
	TransferConfig -> SendCR			= CR_ASCR;
	TransferConfig -> SendLF			= LF_ASLF;
	TransferConfig -> ReceiveCR			= CR_ASCR;
	TransferConfig -> ReceiveLF			= LF_ASLF;
}

	/* ResetConfig():
	 *
	 *	Initialize configuration with default values.
	 */

VOID __regargs
ResetConfig(struct Configuration *Config,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

	ResetPath(Config -> PathConfig,PathBuffer);
	ResetFile(Config -> FileConfig,PathBuffer);

	ResetSerialConfig(Config -> SerialConfig);
	ResetModem(Config -> ModemConfig);
	ResetScreen(Config -> ScreenConfig);
	ResetTerminal(Config -> TerminalConfig);
	ResetEmulation(Config -> EmulationConfig);
	ResetClip(Config -> ClipConfig);
	ResetCapture(Config -> CaptureConfig);
	ResetMisc(Config -> MiscConfig);
	ResetCommand(Config -> CommandConfig);
	ResetTransfer(Config -> TransferConfig,Config -> FileConfig -> ProtocolFileName);
}

VOID __regargs
DeleteConfigEntry(struct Configuration *Config,BYTE Type)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type <= PREF_TRANSFER ; Type++)
			DeleteConfigEntry(Config,Type);
	}
	else
	{
		switch(Type)
		{
			case PREF_SERIAL:

				if(Config -> SerialConfig)
				{
					FreeVecPooled(Config -> SerialConfig);

					Config -> SerialConfig = NULL;
				}

				break;

			case PREF_MODEM:

				if(Config -> ModemConfig)
				{
					FreeVecPooled(Config -> ModemConfig);

					Config -> ModemConfig = NULL;
				}

				break;

			case PREF_COMMAND:

				if(Config -> CommandConfig)
				{
					FreeVecPooled(Config -> CommandConfig);

					Config -> CommandConfig = NULL;
				}

				break;

			case PREF_SCREEN:

				if(Config -> ScreenConfig)
				{
					FreeVecPooled(Config -> ScreenConfig);

					Config -> ScreenConfig = NULL;
				}

				break;

			case PREF_TERMINAL:

				if(Config -> TerminalConfig)
				{
					FreeVecPooled(Config -> TerminalConfig);

					Config -> TerminalConfig = NULL;
				}

				break;

			case PREF_PATH:

				if(Config -> PathConfig)
				{
					FreeVecPooled(Config -> PathConfig);

					Config -> PathConfig = NULL;
				}

				break;

			case PREF_MISC:

				if(Config -> MiscConfig)
				{
					FreeVecPooled(Config -> MiscConfig);

					Config -> MiscConfig = NULL;
				}

				break;

			case PREF_CLIP:

				if(Config -> ClipConfig)
				{
					FreeVecPooled(Config -> ClipConfig);

					Config -> ClipConfig = NULL;
				}

				break;

			case PREF_CAPTURE:

				if(Config -> CaptureConfig)
				{
					FreeVecPooled(Config -> CaptureConfig);

					Config -> CaptureConfig = NULL;
				}

				break;

			case PREF_FILE:

				if(Config -> FileConfig)
				{
					FreeVecPooled(Config -> FileConfig);

					Config -> FileConfig = NULL;
				}

				break;

			case PREF_EMULATION:

				if(Config -> EmulationConfig)
				{
					FreeVecPooled(Config -> EmulationConfig);

					Config -> EmulationConfig = NULL;
				}

				break;

			case PREF_TRANSFER:

				if(Config -> TransferConfig)
				{
					FreeVecPooled(Config -> TransferConfig);

					Config -> TransferConfig = NULL;
				}

				break;
		}
	}
}

VOID __regargs
ResetConfigEntry(struct Configuration *Configuration,BYTE Type,BYTE Default)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type <= PREF_TRANSFER ; Type++)
			ResetConfigEntry(Configuration,Type,Default);
	}
	else
	{
		switch(Type)
		{
			case PREF_SERIAL:

				if(Default || !Config -> SerialConfig)
					ResetSerialConfig(Configuration -> SerialConfig);
				else
					memcpy(Configuration -> SerialConfig,Config -> SerialConfig,sizeof(struct SerialSettings));

				break;

			case PREF_MODEM:

				if(Default || !Config -> ModemConfig)
					ResetModem(Configuration -> ModemConfig);
				else
					memcpy(Configuration -> ModemConfig,Config -> ModemConfig,sizeof(struct ModemSettings));

				break;

			case PREF_COMMAND:

				if(Default || !Config -> CommandConfig)
					ResetCommand(Configuration -> CommandConfig);
				else
					memcpy(Configuration -> CommandConfig,Config -> CommandConfig,sizeof(struct CommandSettings));

				break;

			case PREF_SCREEN:

				if(Default || !Config -> ScreenConfig)
					ResetScreen(Configuration -> ScreenConfig);
				else
					memcpy(Configuration -> ScreenConfig,Config -> ScreenConfig,sizeof(struct ScreenSettings));

				FixScreenPens(Configuration -> ScreenConfig);

				break;

			case PREF_TERMINAL:

				if(Default || !Config -> TerminalConfig)
					ResetTerminal(Configuration -> TerminalConfig);
				else
					memcpy(Configuration -> TerminalConfig,Config -> TerminalConfig,sizeof(struct TerminalSettings));

				break;

			case PREF_PATH:

				if(Default || !Config -> PathConfig)
					ResetPath(Configuration -> PathConfig,NULL);
				else
					memcpy(Configuration -> PathConfig,Config -> PathConfig,sizeof(struct PathSettings));

				break;

			case PREF_MISC:

				if(Default || !Config -> MiscConfig)
					ResetMisc(Configuration -> MiscConfig);
				else
					memcpy(Configuration -> MiscConfig,Config -> MiscConfig,sizeof(struct MiscSettings));

				break;

			case PREF_CLIP:

				if(Default || !Config -> ClipConfig)
					ResetClip(Configuration -> ClipConfig);
				else
					memcpy(Configuration -> ClipConfig,Config -> ClipConfig,sizeof(struct ClipSettings));

				break;

			case PREF_CAPTURE:

				if(Default || !Config -> CaptureConfig)
					ResetCapture(Configuration -> CaptureConfig);
				else
					memcpy(Configuration -> CaptureConfig,Config -> CaptureConfig,sizeof(struct CaptureSettings));

				break;

			case PREF_FILE:

				if(Default || !Config -> FileConfig)
					ResetFile(Configuration -> FileConfig,NULL);
				else
					memcpy(Configuration -> FileConfig,Config -> FileConfig,sizeof(struct FileSettings));

				break;

			case PREF_EMULATION:

				if(Default || !Config -> EmulationConfig)
					ResetEmulation(Configuration -> EmulationConfig);
				else
					memcpy(Configuration -> EmulationConfig,Config -> EmulationConfig,sizeof(struct EmulationSettings));

				break;

			case PREF_TRANSFER:

				if(Default || !Config -> TransferConfig)
					ResetTransfer(Configuration -> TransferConfig,Config -> FileConfig -> ProtocolFileName);
				else
					memcpy(Configuration -> TransferConfig,Config -> TransferConfig,sizeof(struct TransferSettings));

				break;
		}
	}
}

APTR __regargs
GetConfigEntry(struct Configuration *Config,BYTE Type)
{
	switch(Type)
	{
		case PREF_SERIAL:

			return(Config -> SerialConfig);

		case PREF_MODEM:

			return(Config -> ModemConfig);

		case PREF_COMMAND:

			return(Config -> CommandConfig);

		case PREF_SCREEN:

			return(Config -> ScreenConfig);

		case PREF_TERMINAL:

			return(Config -> TerminalConfig);

		case PREF_PATH:

			return(Config -> PathConfig);

		case PREF_MISC:

			return(Config -> MiscConfig);

		case PREF_CLIP:

			return(Config -> ClipConfig);

		case PREF_CAPTURE:

			return(Config -> CaptureConfig);

		case PREF_FILE:

			return(Config -> FileConfig);

		case PREF_EMULATION:

			return(Config -> EmulationConfig);

		case PREF_TRANSFER:

			return(Config -> TransferConfig);

		default:

			return(NULL);
	}
}

BYTE __regargs
CreateConfigEntry(struct Configuration *Config,BYTE Type)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type <= PREF_TRANSFER ; Type++)
		{
			if(!CreateConfigEntry(Config,Type))
			{
				DeleteConfigEntry(Config,PREF_ALL);

				return(FALSE);
			}
		}

		return(TRUE);
	}
	else
	{
		APTR Data;

		switch(Type)
		{
			case PREF_SERIAL:

				Data = Config -> SerialConfig;
				break;

			case PREF_MODEM:

				Data = Config -> ModemConfig;
				break;

			case PREF_COMMAND:

				Data = Config -> CommandConfig;
				break;

			case PREF_SCREEN:

				Data = Config -> ScreenConfig;
				break;

			case PREF_TERMINAL:

				Data = Config -> TerminalConfig;
				break;

			case PREF_PATH:

				Data = Config -> PathConfig;
				break;

			case PREF_MISC:

				Data = Config -> MiscConfig;
				break;

			case PREF_CLIP:

				Data = Config -> ClipConfig;
				break;

			case PREF_CAPTURE:

				Data = Config -> CaptureConfig;
				break;

			case PREF_FILE:

				Data = Config -> FileConfig;
				break;

			case PREF_EMULATION:

				Data = Config -> EmulationConfig;
				break;

			case PREF_TRANSFER:

				Data = Config -> TransferConfig;
				break;

			default:

				return(FALSE);
		}

		if(!Data)
		{
			if(Data = AllocVecPooled(SizeTable[Type - 1],MEMF_ANY | MEMF_CLEAR))
			{
				(*ResetTable[Type - 1])(Data,NULL);

				switch(Type)
				{
					case PREF_SERIAL:

						Config -> SerialConfig		= Data;
						break;

					case PREF_MODEM:

						Config -> ModemConfig		= Data;
						break;

					case PREF_COMMAND:

						Config -> CommandConfig		= Data;
						break;

					case PREF_SCREEN:

						Config -> ScreenConfig		= Data;
						break;

					case PREF_TERMINAL:

						Config -> TerminalConfig	= Data;
						break;

					case PREF_PATH:

						Config -> PathConfig		= Data;
						break;

					case PREF_MISC:

						Config -> MiscConfig		= Data;
						break;

					case PREF_CLIP:

						Config -> ClipConfig		= Data;
						break;

					case PREF_CAPTURE:

						Config -> CaptureConfig		= Data;
						break;

					case PREF_FILE:

						Config -> FileConfig		= Data;
						break;

					case PREF_EMULATION:

						Config -> EmulationConfig	= Data;
						break;

					case PREF_TRANSFER:

						Config -> TransferConfig	= Data;
						break;
				}

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

VOID __regargs
DeleteConfiguration(struct Configuration *Config)
{
	if(Config)
	{
		DeleteConfigEntry(Config,PREF_ALL);

		FreeVecPooled(Config);
	}
}

struct Configuration * __regargs
CreateConfiguration(BYTE Fill)
{
	struct Configuration *Config;

	if(Config = (struct Configuration *)AllocVecPooled(sizeof(struct Configuration),MEMF_ANY | MEMF_CLEAR))
	{
		if(Fill)
		{
			if(!CreateConfigEntry(Config,PREF_ALL))
			{
				FreeVecPooled(Config);

				return(NULL);
			}
		}

		return(Config);
	}
	else
		return(NULL);
}

STATIC BYTE
WriteConfigChunk(struct IFFHandle *Handle,struct Configuration *Config,BYTE Type,APTR TempBuffer,STRPTR Password)
{
	APTR Data;

	switch(Type)
	{
		case PREF_SERIAL:

			Data = Config -> SerialConfig;
			break;

		case PREF_MODEM:

			Data = Config -> ModemConfig;
			break;

		case PREF_COMMAND:

			Data = Config -> CommandConfig;
			break;

		case PREF_SCREEN:

			Data = Config -> ScreenConfig;
			break;

		case PREF_TERMINAL:

			Data = Config -> TerminalConfig;
			break;

		case PREF_PATH:

			Data = Config -> PathConfig;
			break;

		case PREF_MISC:

			Data = Config -> MiscConfig;
			break;

		case PREF_CLIP:

			Data = Config -> ClipConfig;
			break;

		case PREF_CAPTURE:

			Data = Config -> CaptureConfig;
			break;

		case PREF_FILE:

			Data = Config -> FileConfig;
			break;

		case PREF_EMULATION:

			Data = Config -> EmulationConfig;
			break;

		case PREF_TRANSFER:

			Data = Config -> TransferConfig;
			break;

		default:

			Data = NULL;
			break;
	}

	if(Data)
	{
		if(TempBuffer)
		{
			Encrypt(Data,SizeTable[Type - 1],TempBuffer,Password,20);

			Data = TempBuffer;
		}

		if(!PushChunk(Handle,0,TypeTable[Type - 1],SizeTable[Type - 1]))
		{
			if(WriteChunkRecords(Handle,Data,SizeTable[Type - 1],1) == 1)
			{
				if(!PopChunk(Handle))
					return(TRUE);
			}
		}

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

STATIC UBYTE
IsConfigChunk(ULONG ID)
{
	UBYTE Type;

	for(Type = PREF_SERIAL ; Type <= PREF_TRANSFER ; Type++)
	{
		if(ID == TypeTable[Type - 1])
			return(Type);
	}

	return(0);
}

STATIC BYTE
WriteConfigChunks(struct IFFHandle *Handle,struct Configuration *Config,APTR TempBuffer,STRPTR Password)
{
	UBYTE Type;

	for(Type = PREF_SERIAL ; Type <= PREF_TRANSFER ; Type++)
	{
		if(!WriteConfigChunk(Handle,Config,Type,TempBuffer,Password))
			return(FALSE);
	}

	return(TRUE);
}

VOID __regargs
SaveConfig(struct Configuration *Src,struct Configuration *Dst)
{
	if(Dst -> SerialConfig && Src -> SerialConfig)
		memcpy(Dst -> SerialConfig,Src -> SerialConfig,sizeof(struct SerialSettings));

	if(Dst -> ModemConfig && Src -> ModemConfig)
		memcpy(Dst -> ModemConfig,Src -> ModemConfig,sizeof(struct ModemSettings));

	if(Dst -> ScreenConfig && Src -> ScreenConfig)
	{
		memcpy(Dst -> ScreenConfig,Src -> ScreenConfig,sizeof(struct ScreenSettings));

		FixScreenPens(Dst -> ScreenConfig);
	}

	if(Dst -> TerminalConfig && Src -> TerminalConfig)
		memcpy(Dst -> TerminalConfig,Src -> TerminalConfig,sizeof(struct TerminalSettings));

	if(Dst -> EmulationConfig && Src -> EmulationConfig)
		memcpy(Dst -> EmulationConfig,Src -> EmulationConfig,sizeof(struct EmulationSettings));

	if(Dst -> ClipConfig && Src -> ClipConfig)
		memcpy(Dst -> ClipConfig,Src -> ClipConfig,sizeof(struct ClipSettings));

	if(Dst -> CaptureConfig && Src -> CaptureConfig)
		memcpy(Dst -> CaptureConfig,Src -> CaptureConfig,sizeof(struct CaptureSettings));

	if(Dst -> CommandConfig && Src -> CommandConfig)
		memcpy(Dst -> CommandConfig,Src -> CommandConfig,sizeof(struct CommandSettings));

	if(Dst -> MiscConfig && Src -> MiscConfig)
		memcpy(Dst -> MiscConfig,Src -> MiscConfig,sizeof(struct MiscSettings));

	if(Dst -> PathConfig && Src -> PathConfig)
		memcpy(Dst -> PathConfig,Src -> PathConfig,sizeof(struct PathSettings));

	if(Dst -> FileConfig && Src -> FileConfig)
		memcpy(Dst -> FileConfig,Src -> FileConfig,sizeof(struct FileSettings));

	if(Dst -> TransferConfig && Src -> TransferConfig)
		memcpy(Dst -> TransferConfig,Src -> TransferConfig,sizeof(struct TransferSettings));
}

VOID __regargs
UpdateConfig(struct Configuration *Src,struct Configuration *Dst)
{
	if(Src -> SerialConfig)
		memcpy(Dst -> SerialConfig,Src -> SerialConfig,sizeof(struct SerialSettings));

	if(Src -> ModemConfig)
		memcpy(Dst -> ModemConfig,Src -> ModemConfig,sizeof(struct ModemSettings));

	if(Src -> ScreenConfig)
	{
		memcpy(Dst -> ScreenConfig,Src -> ScreenConfig,sizeof(struct ScreenSettings));

		FixScreenPens(Dst -> ScreenConfig);
	}

	if(Src -> TerminalConfig)
		memcpy(Dst -> TerminalConfig,Src -> TerminalConfig,sizeof(struct TerminalSettings));

	if(Src -> EmulationConfig)
		memcpy(Dst -> EmulationConfig,Src -> EmulationConfig,sizeof(struct EmulationSettings));

	if(Src -> ClipConfig)
		memcpy(Dst -> ClipConfig,Src -> ClipConfig,sizeof(struct ClipSettings));

	if(Src -> CaptureConfig)
		memcpy(Dst -> CaptureConfig,Src -> CaptureConfig,sizeof(struct CaptureSettings));

	if(Src -> CommandConfig)
		memcpy(Dst -> CommandConfig,Src -> CommandConfig,sizeof(struct CommandSettings));

	if(Src -> MiscConfig)
		memcpy(Dst -> MiscConfig,Src -> MiscConfig,sizeof(struct MiscSettings));

	if(Src -> PathConfig)
		memcpy(Dst -> PathConfig,Src -> PathConfig,sizeof(struct PathSettings));

	if(Src -> FileConfig)
		memcpy(Dst -> FileConfig,Src -> FileConfig,sizeof(struct FileSettings));

	if(Src -> TransferConfig)
		memcpy(Dst -> TransferConfig,Src -> TransferConfig,sizeof(struct TransferSettings));
}

VOID __regargs
SwapConfig(struct Configuration *Src,struct Configuration *Dst)
{
	swmem(Dst -> SerialConfig,Src -> SerialConfig,sizeof(struct SerialSettings));
	swmem(Dst -> ModemConfig,Src -> ModemConfig,sizeof(struct ModemSettings));
	swmem(Dst -> ScreenConfig,Src -> ScreenConfig,sizeof(struct ScreenSettings));
	swmem(Dst -> TerminalConfig,Src -> TerminalConfig,sizeof(struct TerminalSettings));
	swmem(Dst -> EmulationConfig,Src -> EmulationConfig,sizeof(struct EmulationSettings));
	swmem(Dst -> ClipConfig,Src -> ClipConfig,sizeof(struct ClipSettings));
	swmem(Dst -> CaptureConfig,Src -> CaptureConfig,sizeof(struct CaptureSettings));
	swmem(Dst -> CommandConfig,Src -> CommandConfig,sizeof(struct CommandSettings));
	swmem(Dst -> MiscConfig,Src -> MiscConfig,sizeof(struct MiscSettings));
	swmem(Dst -> PathConfig,Src -> PathConfig,sizeof(struct PathSettings));
	swmem(Dst -> FileConfig,Src -> FileConfig,sizeof(struct FileSettings));
	swmem(Dst -> TransferConfig,Src -> TransferConfig,sizeof(struct TransferSettings));
}

	/* SavePhonebook(STRPTR Name):
	 *
	 *	Save the current phone book to a disk file.
	 */

BYTE __regargs
SavePhonebook(STRPTR Name)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	LONG			 Error = 0;

	if(Phonebook && NumPhoneEntries)
	{
		if(Handle = (struct IFFHandle *)AllocIFF())
		{
			if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
			{
				InitIFFasDOS(Handle);

				if(!(Error = OpenIFF(Handle,IFFF_WRITE)))
				{
					if(!(Error = PushChunk(Handle,ID_TERM,ID_CAT,IFFSIZE_UNKNOWN)))
					{
						if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
						{
							if(!(Error = PushChunk(Handle,0,ID_VERS,IFFSIZE_UNKNOWN)))
							{
								struct TermInfo TermInfo;

								TermInfo . Version	= TermVersion;
								TermInfo . Revision	= TermRevision;

								if(WriteChunkRecords(Handle,&TermInfo,sizeof(struct TermInfo),1) == 1)
								{
									if(!(Error = PopChunk(Handle)))
									{
										STRPTR TempBuffer = NULL;

										if(PhonePasswordUsed)
										{
											if(!(Error = PushChunk(Handle,0,ID_PSWD,20)))
											{
												Success = TRUE;

												if(WriteChunkBytes(Handle,PhonePassword,20) != 20)
													Success = FALSE;

												if(PopChunk(Handle))
													Success = FALSE;

												if(Success)
												{
													LONG Max = sizeof(struct PhoneHeader),Type;

													for(Type = PREF_SERIAL ; Type <= PREF_TRANSFER ; Type++)
													{
														if(SizeTable[Type - 1] > Max)
															Max = SizeTable[Type - 1];
													}

													if(!(TempBuffer = AllocVecPooled(Max,MEMF_ANY)))
													{
														Error = ERR_NO_MEM;

														Success = FALSE;
													}
												}
											}
										}
										else
											Success = TRUE;

										if(Success)
										{
											Success = FALSE;

											if(!(Error = PushChunk(Handle,0,ID_DIAL,IFFSIZE_UNKNOWN)))
											{
												if(WriteChunkBytes(Handle,&NumPhoneEntries,sizeof(LONG)) == sizeof(LONG))
												{
													if(!(Error = PopChunk(Handle)))
													{
														if(!(Error = PopChunk(Handle)))
														{
															LONG i;

															Success = TRUE;

															for(i = 0 ; Success && i < NumPhoneEntries ; i++)
															{
																Success = FALSE;

																if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
																{
																	if(!(Error = PushChunk(Handle,0,ID_PHON,sizeof(struct PhoneHeader))))
																	{
																		if(TempBuffer)
																		{
																			Encrypt((UBYTE *)Phonebook[i] -> Header,sizeof(struct PhoneHeader),TempBuffer,PhonePassword,20);

																			if(WriteChunkRecords(Handle,TempBuffer,sizeof(struct PhoneHeader),1) == 1)
																			{
																				if(!(Error = PopChunk(Handle)))
																				{
																					if(WriteConfigChunks(Handle,Phonebook[i] -> Config,TempBuffer,PhonePassword))
																					{
																						struct TimeDateNode *TimeDateNode;

																						Success = TRUE;

																						TimeDateNode = (struct TimeDateNode *)Phonebook[i] -> TimeDateList . mlh_Head;

																						while(TimeDateNode -> VanillaNode . ln_Succ)
																						{
																							if(!(Error = PushChunk(Handle,0,ID_DATE,IFFSIZE_UNKNOWN)))
																							{
																								if(WriteChunkBytes(Handle,&TimeDateNode -> Header,sizeof(struct TimeDateHeader)) != sizeof(struct TimeDateHeader))
																								{
																									Error = IoErr();

																									Success = FALSE;

																									break;
																								}
																								else
																								{
																									if(WriteChunkBytes(Handle,TimeDateNode -> Table,TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate)) != TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate))
																									{
																										Error = IoErr();

																										Success = FALSE;

																										break;
																									}
																								}

																								if(Success)
																								{
																									if(Error = PopChunk(Handle))
																									{
																										Success = FALSE;
	
																										break;
																									}
																								}

																								TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
																							}
																						}
																					}
																					else
																					{
																						Error = IoErr();

																						Success = FALSE;
																					}
																				}
																			}
																			else
																				Error = IoErr();
																		}
																		else
																		{
																			if(WriteChunkRecords(Handle,Phonebook[i] -> Header,sizeof(struct PhoneHeader),1) == 1)
																			{
																				if(!(Error = PopChunk(Handle)))
																				{
																					if(WriteConfigChunks(Handle,Phonebook[i] -> Config,NULL,NULL))
																					{
																						struct TimeDateNode *TimeDateNode;

																						Success = TRUE;

																						TimeDateNode = (struct TimeDateNode *)Phonebook[i] -> TimeDateList . mlh_Head;

																						while(TimeDateNode -> VanillaNode . ln_Succ)
																						{
																							if(!(Error = PushChunk(Handle,0,ID_DATE,IFFSIZE_UNKNOWN)))
																							{
																								if(WriteChunkBytes(Handle,&TimeDateNode -> Header,sizeof(struct TimeDateHeader)) != sizeof(struct TimeDateHeader))
																								{
																									Error = IoErr();

																									Success = FALSE;

																									break;
																								}
																								else
																								{
																									if(WriteChunkBytes(Handle,TimeDateNode -> Table,TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate)) != TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate))
																									{
																										Error = IoErr();

																										Success = FALSE;

																										break;
																									}
																								}

																								if(Success)
																								{
																									if(Error = PopChunk(Handle))
																									{
																										Success = FALSE;
	
																										break;
																									}
																								}

																								TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
																							}
																						}
																					}
																					else
																					{
																						Success = FALSE;

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

																	if(Success)
																	{
																		if(PopChunk(Handle))
																			Success = FALSE;
																	}
																}
															}
														}
													}
												}
												else
													Error = IoErr();
											}
										}

										if(TempBuffer)
											FreeVecPooled(TempBuffer);
									}
								}
								else
									Error = IoErr();
							}
						}

						if(Success)
						{
							if(Error = PopChunk(Handle))
								Success = FALSE;
						}
					}

					CloseIFF(Handle);
				}

				Close(Handle -> iff_Stream);
			}
			else
				Error = IoErr();

			FreeIFF(Handle);
		}
		else
			Error = ERR_NO_MEM;

		if(Success)
			AddProtection(Name,FIBF_EXECUTE);
		else
			DeleteFile(Name);
	}

	if(Error)
		SetIoErr(Error);

	return(Success);
}

STATIC BYTE
ReadConfigChunk(struct IFFHandle *Handle,struct Configuration *Config,UBYTE Type,LONG Len,STRPTR Password)
{
	if(CreateConfigEntry(Config,Type))
	{
		APTR Data;

		switch(Type)
		{
			case PREF_SERIAL:

				Data = Config -> SerialConfig;
				break;

			case PREF_MODEM:

				Data = Config -> ModemConfig;
				break;

			case PREF_COMMAND:

				Data = Config -> CommandConfig;
				break;

			case PREF_SCREEN:

				Data = Config -> ScreenConfig;
				break;

			case PREF_TERMINAL:

				Data = Config -> TerminalConfig;
				break;

			case PREF_PATH:

				Data = Config -> PathConfig;
				break;

			case PREF_MISC:

				Data = Config -> MiscConfig;
				break;

			case PREF_CLIP:

				Data = Config -> ClipConfig;
				break;

			case PREF_CAPTURE:

				Data = Config -> CaptureConfig;
				break;

			case PREF_FILE:

				Data = Config -> FileConfig;
				break;

			case PREF_EMULATION:

				Data = Config -> EmulationConfig;
				break;

			case PREF_TRANSFER:

				Data = Config -> TransferConfig;
				break;
		}

		Len = MIN(SizeTable[Type - 1],Len);

		if(ReadChunkBytes(Handle,Data,Len) == Len)
		{
			if(Password)
				Decrypt(Data,Len,Data,Password,20);

			if(Type == PREF_SCREEN)
				FixScreenPens(Data);

			return(TRUE);
		}
	}

	return(FALSE);
}

	/* LoadPhonebook(STRPTR Name):
	 *
	 *	Restore a phone book from a disk file.
	 */

BYTE __regargs
LoadPhonebook(STRPTR Name)
{
	struct PhoneEntry	**PrivatePhonebook;
	LONG			 PrivatePhoneSize	= 0,
				 CurrentPhoneSize	= 0,
				 Count			= 0,
				 Index			= 0;
	BYTE			 Success		= FALSE,
				 LastHadTime		= TRUE,
				 UsePhonePassword	= FALSE,
				 FirstChunk		= TRUE,
				 UseOld			= FALSE;
	struct IFFHandle	*Handle;
	struct ContextNode	*Chunk;
	struct TimeDateNode	*TimeDateNode;
	UBYTE			 ConfigChunkType,
				 PasswordBuffer[20];
	BYTE			 CheckedChunk = FALSE;
	LONG			 Error = 0;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
			InitIFFasDOS(Handle);

			if(!(Error = OpenIFF(Handle,IFFF_READ)))
			{
				if(!(Error = StopChunks(Handle,(LONG *)Stops,NUM_STOPS)))
				{
					struct TermInfo TermInfo;

					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

							/* Is this the first chunk to be read? */

						if(!CheckedChunk)
						{
								/* The first chunk must be a
								 * catalog chunk, or this is
								 * not a proper phonebook file.
								 */

							if(Chunk -> cn_ID != ID_CAT)
								break;
							else
								CheckedChunk = TRUE;
						}

						if(Chunk -> cn_ID == ID_VERS)
						{
							if(ReadChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if(TermInfo . Version != TermVersion || (TermInfo . Version == TermVersion && TermInfo . Revision > TermRevision))
								{
									if(TermInfo . Version == 2 && TermInfo . Revision == 4)
										UseOld = TRUE;

									if(TermInfo . Version != 3)
										break;
								}
							}
							else
							{
								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_PSWD)
						{
							if(ReadChunkBytes(Handle,PasswordBuffer,20) == 20)
							{
								if(PhonePasswordUsed)
								{
									if(!memcmp(PhonePassword,PasswordBuffer,20))
									{
										UsePhonePassword = TRUE;

										continue;
									}
								}

								memset(SharedBuffer,0,21);

								if(GetString(FALSE,TRUE,21,LocaleString(MSG_PHONEPANEL_PLEASE_ENTER_PASSWORD_TXT),SharedBuffer))
								{
									UBYTE AnotherBuffer[20];

									Encrypt(SharedBuffer,20,AnotherBuffer,SharedBuffer,strlen(SharedBuffer));

									if(!memcmp(PasswordBuffer,AnotherBuffer,20))
									{
										UsePhonePassword = TRUE;

										continue;
									}
									else
									{
										MyEasyRequest(Window,LocaleString(MSG_TERMPHONE_WRONG_PASSWORD_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Name);

										break;
									}
								}
								else
									break;
							}
							else
							{
								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_DIAL)
						{
							if(ReadChunkBytes(Handle,&CurrentPhoneSize,sizeof(LONG)) == sizeof(LONG))
							{
								if(!CurrentPhoneSize)
									break;
								else
								{
									if(!(PrivatePhonebook = CreatePhonebook(CurrentPhoneSize,&PrivatePhoneSize,TRUE)))
									{
										Error = ERR_NO_MEM;

										break;
									}
								}
							}
							else
							{
								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_PHON)
						{
							WORD Size = MIN(sizeof(struct PhoneHeader),Chunk -> cn_Size);

							if(!CurrentPhoneSize)
								break;

							if(!LastHadTime)
							{
								if(TimeDateNode = CreateTimeDateNode(-1,-1,"",2))
									AddTail((struct List *)&PrivatePhonebook[Index] -> TimeDateList,&TimeDateNode -> VanillaNode);
							}

							if(!FirstChunk)
								Index++;
							else
								FirstChunk = FALSE;

							if(ReadChunkBytes(Handle,PrivatePhonebook[Index] -> Header,Size) == Size)
							{
								if(UsePhonePassword)
									Decrypt((UBYTE *)PrivatePhonebook[Index] -> Header,Size,(UBYTE *)PrivatePhonebook[Index] -> Header,PasswordBuffer,20);

								PrivatePhonebook[Index] -> Count = -1;

								LastHadTime = FALSE;

								Count++;
							}
							else
							{
								Error = IoErr();

								break;
							}
						}

						if(ConfigChunkType = IsConfigChunk(Chunk -> cn_ID))
						{
							if(!CurrentPhoneSize)
								break;

							if(UsePhonePassword)
							{
								if(!ReadConfigChunk(Handle,PrivatePhonebook[Index] -> Config,ConfigChunkType,Chunk -> cn_Size,PasswordBuffer))
								{
									if((TermInfo . Version == 3 && TermInfo . Revision < 6) || TermInfo . Version < 3)
										FixOldConfig(PrivatePhonebook[Index] -> Config,ConfigChunkType,TRUE);

									if(Count)
										CurrentPhoneSize = Count - 1;
									else
										CurrentPhoneSize = 0;

									break;
								}
							}
							else
							{
								if(!ReadConfigChunk(Handle,PrivatePhonebook[Index] -> Config,ConfigChunkType,Chunk -> cn_Size,NULL))
								{
									if((TermInfo . Version == 3 && TermInfo . Revision < 6) || TermInfo . Version < 3)
										FixOldConfig(PrivatePhonebook[Index] -> Config,ConfigChunkType,TRUE);

									if(Count)
										CurrentPhoneSize = Count - 1;
									else
										CurrentPhoneSize = 0;

									break;
								}
							}
						}

						if(Chunk -> cn_ID == ID_DATE)
						{
							WORD Count = (Chunk -> cn_Size - sizeof(struct TimeDateHeader)) / sizeof(struct TimeDate);

							if(!CurrentPhoneSize)
								break;

							if(TimeDateNode = CreateTimeDateNode(-1,-1,"",Count))
							{
								if(ReadChunkBytes(Handle,&TimeDateNode -> Header,sizeof(struct TimeDateHeader)) == sizeof(struct TimeDateHeader))
								{
									if(ReadChunkRecords(Handle,TimeDateNode -> Table,sizeof(struct TimeDate),Count) == Count)
									{
										AdaptTimeDateNode(TimeDateNode);

										AddTail((struct List *)&PrivatePhonebook[Index] -> TimeDateList,&TimeDateNode -> VanillaNode);

										LastHadTime = TRUE;
									}
									else
									{
										Error = IoErr();

										FreeTimeDateNode(TimeDateNode);
									}
								}
								else
								{
									Error = IoErr();

									FreeTimeDateNode(TimeDateNode);
								}
							}
						}
					}

					if(CurrentPhoneSize)
					{
						LONG i;

						if(!LastHadTime)
						{
							if(TimeDateNode = CreateTimeDateNode(-1,-1,"",2))
								AddTail((struct List *)&PrivatePhonebook[Index] -> TimeDateList,&TimeDateNode -> VanillaNode);
						}

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

						Phonebook	= PrivatePhonebook;
						PhoneSize	= PrivatePhoneSize;
						NumPhoneEntries	= CurrentPhoneSize;
						Success		= TRUE;

						memcpy(PhonePassword,PasswordBuffer,20);
						PhonePasswordUsed = UsePhonePassword;

						for(i = NumPhoneEntries ; i < PhoneSize ; i++)
						{
							if(Phonebook[i])
							{
								if(Phonebook[i] -> Config)
									DeleteConfiguration(Phonebook[i] -> Config);

								FreeVecPooled(Phonebook[i]);

								Phonebook[i] = NULL;
							}
						}

						FreeDialList(TRUE);
					}
					else
					{
						if(PrivatePhoneSize)
						{
							DeletePhonebook(PrivatePhonebook,PrivatePhoneSize,TRUE);

							Success = FALSE;
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}
		else
			Error = IoErr();

		FreeIFF(Handle);
	}
	else
		Error = ERR_NO_MEM;

	if(Error)
		SetIoErr(Error);

	if(UseOld)
		return(LoadOldPhonebook(Name));
	else
		return(Success);
}

	/* WriteConfig(STRPTR Name,struct Configuration *Config):
	 *
	 *	Write the configuration to a file, very much like
	 *	WriteIFFData().
	 */

BYTE __regargs
WriteConfig(STRPTR Name,struct Configuration *Config)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	LONG			 Error = 0;

		/* Allocate a handle. */

	if(Handle = AllocIFF())
	{
			/* Open an output stream. */

		if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
		{
				/* Tell iffparse that this is
				 * a DOS handle.
				 */

			InitIFFasDOS(Handle);

				/* Open the handle for writing. */

			if(!(Error = OpenIFF(Handle,IFFF_WRITE)))
			{
					/* Push outmost chunk onto stack. */

				if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
				{
						/* Add a version identifier. */

					if(!(Error = PushChunk(Handle,0,ID_VERS,IFFSIZE_UNKNOWN)))
					{
						struct TermInfo TermInfo;

						TermInfo . Version	= TermVersion;
						TermInfo . Revision	= TermRevision;

							/* Write the version data. */

						if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
						{
								/* Pop the version chunk, i.e. write it to the file. */

							if(Error = PopChunk(Handle))
								Success = FALSE;
							else
							{
								if(WriteConfigChunks(Handle,Config,NULL,NULL))
								{
									LONG i;

									Success = TRUE;

									for(i = 0 ; Success && i < WINDOW_COUNT ; i++)
									{
										if(!(Error = PushChunk(Handle,0,ID_WINF,sizeof(struct WindowInfo))))
										{
											if(WriteChunkBytes(Handle,&WindowInfoTable[i],sizeof(struct WindowInfo)) == sizeof(struct WindowInfo))
											{
												if(Error = PopChunk(Handle))
													Success = FALSE;
											}
											else
											{
												Error = IoErr();

												Success = FALSE;
											}
										}
										else
											Success = FALSE;
									}
								}
							}
						}
						else
						{
							Error = IoErr();

							Success = FALSE;
						}
					}

						/* Seems that we're done, now try to pop the FORM chunk
						 * and return.
						 */

					if(Success)
					{
						if(Error = PopChunk(Handle))
							Success = FALSE;
					}
				}

					/* Close the handle (flush any pending data). */

				CloseIFF(Handle);
			}

				/* Close the DOS handle itself. */

			Close(Handle -> iff_Stream);
		}
		else
			Error = IoErr();

			/* And free the IFF handle. */

		FreeIFF(Handle);
	}
	else
		Error = ERR_NO_MEM;

	if(Success)
		AddProtection(Name,FIBF_EXECUTE);

	return(Success);
}

	/* ReadConfig(STRPTR Name,struct Configuration *Config):
	 *
	 *	Read the configuration file, very much the same as ReadIFFData().
	 */

BYTE __regargs
ReadConfig(STRPTR Name,struct Configuration *Config)
{
	struct IFFHandle	*Handle;
	BYTE			 Success	= FALSE,
				 UseOld		= FALSE;
	struct ContextNode	*Chunk;
	UBYTE			 ConfigChunkType;
	LONG			 Error = 0;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
			InitIFFasDOS(Handle);

			if(!(Error = OpenIFF(Handle,IFFF_READ)))
			{
				if(!StopChunks(Handle,(LONG *)Stops,NUM_STOPS))
				{
					struct TermInfo TermInfo;

					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

							/* Oops! Some is trying to
							 * use the phone book file as
							 * a configuration file.
							 */

						if(Chunk -> cn_ID == ID_CAT)
						{
							Success = FALSE;

							break;
						}

						if(Chunk -> cn_ID == ID_VERS)
						{
							if(ReadChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if(TermInfo . Version != TermVersion || (TermInfo . Version == TermVersion && TermInfo . Revision > TermRevision))
								{
									if(TermInfo . Version == 2 && TermInfo . Revision == 4)
										UseOld = TRUE;

									if(TermInfo . Version != 3)
										break;
								}
							}
							else
							{
								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_WINF)
						{
							struct WindowInfo Info;

							if(ReadChunkBytes(Handle,&Info,sizeof(Info)) == sizeof(Info))
							{
								Success = TRUE;

								ReplaceWindowInfo(&Info);
							}
							else
							{
								Error = IoErr();

								Success = FALSE;
								break;
							}
						}
						else
						{
							if(ConfigChunkType = IsConfigChunk(Chunk -> cn_ID))
							{
								if(ReadConfigChunk(Handle,Config,ConfigChunkType,Chunk -> cn_Size,NULL))
								{
									if((TermInfo . Version == 3 && TermInfo . Revision < 6) || TermInfo . Version < 3)
										FixOldConfig(Config,ConfigChunkType,FALSE);

									Success = TRUE;
								}
								else
								{
									Error = IoErr();

									Success = FALSE;

									break;
								}
							}
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}
	else
		Error = IoErr();

	if(Error)
		SetIoErr(Error);

	if(UseOld)
		return(ReadOldConfig(Name,Config));
	else
		return(Success);
}
