/*
**	Config.c
**
**	Configuration processing routines
**
**	Copyright © 1990-1996 by Olaf `Olsen' Barthel
**		All Rights Reserved
**
**	:ts=4
*/

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

	/* Reset routine function pointer. */

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

	/* Local routines. */

STATIC BOOL	ReadSystemPrefs(STRPTR Name,ULONG ID,APTR Data,LONG Size,LONG Count);

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 VOID	ResetTranslationFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetMacroFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetCursorFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetFastMacroFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetSpeechFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetSoundFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetAreaCodeFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetPhonebookFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetHotkeyFile(STRPTR Arg,STRPTR PathBuffer);
STATIC VOID	ResetTrapFile(STRPTR Arg,STRPTR PathBuffer);

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

/*****************************************************************************/

STATIC BOOLEAN				FontPrefsRead		= FALSE,
							FontPrefsReadFailed	= FALSE;
STATIC struct FontPrefs		FontPrefs[3];

/*****************************************************************************/

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),
	MAX_FILENAME_LENGTH,				// Translation file name
	MAX_FILENAME_LENGTH,				// Macro file name
	MAX_FILENAME_LENGTH,				// Cursor file name
	MAX_FILENAME_LENGTH,				// Fast macro file name
	MAX_FILENAME_LENGTH,				// Speech file name
	MAX_FILENAME_LENGTH,				// Sound file name
	MAX_FILENAME_LENGTH,				// Area code file name
	MAX_FILENAME_LENGTH,				// Phonebook file name
	MAX_FILENAME_LENGTH,				// Hotkey file name
	MAX_FILENAME_LENGTH					// Trap file name
};

STATIC RESET ResetTable[] =
{
	(RESET)ResetSerialConfig,
	(RESET)ResetModem,
	(RESET)ResetCommand,
	(RESET)ResetScreen,
	(RESET)ResetTerminal,
	ResetPath,
	(RESET)ResetMisc,
	(RESET)ResetClip,
	(RESET)ResetCapture,
	ResetFile,
	(RESET)ResetEmulation,
	ResetTransfer,
	(RESET)ResetTranslationFile,
	(RESET)ResetMacroFile,
	(RESET)ResetCursorFile,
	(RESET)ResetFastMacroFile,
	(RESET)ResetSpeechFile,
	(RESET)ResetSoundFile,
	(RESET)ResetAreaCodeFile,
	(RESET)ResetPhonebookFile,
	(RESET)ResetHotkeyFile,
	(RESET)ResetTrapFile
};

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,
	ID_XLNM,
	ID_MFNM,
	ID_CRNM,
	ID_FMNM,
	ID_SPNM,
	ID_SONM,
	ID_ACNM,
	ID_PBNM,
	ID_HKNM,
	ID_TRNM
};

#define NUM_STOPS (sizeof(Stops) / (2 * sizeof(ULONG)))

STATIC LONG Stops[] =
{
	ID_TERM,ID_CAT,
	ID_TERM,ID_VERS,
	ID_TERM,ID_DIAL,
	ID_TERM,ID_DAT2,
	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,
	ID_TERM,ID_GRUP,
	ID_TERM,ID_XLNM,
	ID_TERM,ID_MFNM,
	ID_TERM,ID_CRNM,
	ID_TERM,ID_FMNM,
	ID_TERM,ID_SPNM,
	ID_TERM,ID_SONM,
	ID_TERM,ID_ACNM,
	ID_TERM,ID_PBNM,
	ID_TERM,ID_HKNM,
	ID_TERM,ID_TRNM
};

/*****************************************************************************/

enum	{	CR_IGNORE,CR_ASCR,CR_ASCRLF };
enum	{	LF_IGNORE,LF_ASLF,LF_ASLFCR };

/*****************************************************************************/

VOID
StripGlobals(struct Configuration *Config)
{
	if(Config)
	{
		FreeVecPooled(Config->SpeechFileName);
		FreeVecPooled(Config->SoundFileName);
		FreeVecPooled(Config->AreaCodeFileName);
		FreeVecPooled(Config->PhonebookFileName);
		FreeVecPooled(Config->HotkeyFileName);
		FreeVecPooled(Config->TrapFileName);

		Config->SpeechFileName		= NULL;
		Config->SoundFileName		= NULL;
		Config->AreaCodeFileName	= NULL;
		Config->PhonebookFileName	= NULL;
		Config->HotkeyFileName		= NULL;
		Config->TrapFileName		= NULL;
	}
}

VOID
FinalFix(struct Configuration *Config,BOOL IsPhonebook,LONG Version,LONG Revision)
{
	if(Config)
	{
		if(Version < 4 || (Version == 4 && Revision < 3))
		{
			if(Config->TransferConfig && Config->MiscConfig)
			{
				Config->TransferConfig->OverridePath	= Config->MiscConfig->OverridePath;
				Config->TransferConfig->SetArchivedBit	= Config->MiscConfig->SetArchivedBit;
				Config->TransferConfig->IdentifyFiles	= Config->MiscConfig->IdentifyFiles;
				Config->TransferConfig->TransferIcons	= Config->MiscConfig->TransferIcons;
				Config->TransferConfig->PerfMeter		= Config->MiscConfig->PerfMeter;
				Config->TransferConfig->HideUploadIcon	= Config->MiscConfig->HideUploadIcon;
			}
		}

		if(Version < 4 || (Version == 4 && Revision < 4))
		{
			if(Config->TerminalConfig && Config->MiscConfig)
				Config->MiscConfig->AlertMode = Config->TerminalConfig->AlertMode;
		}
	}
}

VOID
FixOldConfig(struct Configuration *Config,UBYTE ConfigChunkType,BOOL IsPhonebook,LONG Version,LONG Revision)
{
	if((Version == 3 && Revision < 6) || Version < 3)
	{
		if(ConfigChunkType == PREF_CLIP)
			Config->ClipConfig->ConvertLF = TRUE;

		if(ConfigChunkType == PREF_SERIAL)
			Config->SerialConfig->UseOwnDevUnit = TRUE;

		if(ConfigChunkType == PREF_MISC)
			Config->MiscConfig->ProtectiveMode = TRUE;

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

		if(ConfigChunkType == PREF_TRANSFER)
		{
			LONG i;

			Config->TransferConfig->MangleFileNames = FALSE;

			if(Config->TransferConfig->ASCIIUploadLibrary[0])
				Config->TransferConfig->ASCIIUploadType = XFER_XPR;

			if(Config->TransferConfig->ASCIIDownloadLibrary[0])
				Config->TransferConfig->ASCIIDownloadType = XFER_XPR;

			if(Config->TransferConfig->TextUploadLibrary[0])
				Config->TransferConfig->TextUploadType = XFER_XPR;

			if(Config->TransferConfig->TextDownloadLibrary[0])
				Config->TransferConfig->TextDownloadType = XFER_XPR;

			if(Config->TransferConfig->BinaryUploadLibrary[0])
				Config->TransferConfig->BinaryUploadType = XFER_XPR;

			if(Config->TransferConfig->BinaryDownloadLibrary[0])
				Config->TransferConfig->BinaryDownloadType = XFER_XPR;

			for(i = 0 ; i < strlen(Config->TransferConfig->DefaultLibrary) - 6 ; i++)
			{
				if(!Strnicmp(&Config->TransferConfig->DefaultLibrary[i],"zmodem",6))
				{
					strcpy(Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature,"*\030B01");

					Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Length = strlen(Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature);

					break;
				}
			}
		}

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

	if((Version == 4 && Revision < 1) || Version < 4)
	{
		if(ConfigChunkType == PREF_CLIP)
			Config->ClipConfig->ConvertLF = TRUE;

		if(ConfigChunkType == PREF_SERIAL)
		{
			Config->SerialConfig->xONxOFF		= FALSE;
			Config->SerialConfig->PassThrough	= TRUE;
		}

		if(ConfigChunkType == PREF_MISC)
			Config->MiscConfig->ProtectiveMode = TRUE;

		if(ConfigChunkType == PREF_MODEM)
		{
			Config->ModemConfig->RedialDelay	= (Config->ModemConfig->RedialDelay / 6) * 60 + (Config->ModemConfig->RedialDelay % 6) * 10;
			Config->ModemConfig->TimeToConnect	= (Config->ModemConfig->TimeToConnect / 6) * 60 + (Config->ModemConfig->TimeToConnect % 6) * 10;
			Config->ModemConfig->VerboseDialing	= FALSE;
		}

		if(ConfigChunkType == PREF_TERMINAL)
		{
			switch(Config->TerminalConfig->SendCR)
			{
				case CR_IGNORE:

					Config->TerminalConfig->SendCR = EOL_IGNORE;
					break;

				case CR_ASCR:

					Config->TerminalConfig->SendCR = EOL_CR;
					break;

				case CR_ASCRLF:

					Config->TerminalConfig->SendCR = EOL_CRLF;
					break;
			}

			switch(Config->TerminalConfig->ReceiveCR)
			{
				case CR_IGNORE:

					Config->TerminalConfig->ReceiveCR = EOL_IGNORE;
					break;

				case CR_ASCR:

					Config->TerminalConfig->ReceiveCR = EOL_CR;
					break;

				case CR_ASCRLF:

					Config->TerminalConfig->ReceiveCR = EOL_CRLF;
					break;
			}

			switch(Config->TerminalConfig->SendLF)
			{
				case LF_IGNORE:

					Config->TerminalConfig->SendLF = EOL_IGNORE;
					break;

				case LF_ASLF:

					Config->TerminalConfig->SendLF = EOL_LF;
					break;

				case LF_ASLFCR:

					Config->TerminalConfig->SendLF = EOL_LFCR;
					break;
			}

			switch(Config->TerminalConfig->ReceiveLF)
			{
				case LF_IGNORE:

					Config->TerminalConfig->ReceiveLF = EOL_IGNORE;
					break;

				case LF_ASLF:

					Config->TerminalConfig->ReceiveLF = EOL_LF;
					break;

				case LF_ASLFCR:

					Config->TerminalConfig->ReceiveLF = EOL_LFCR;
					break;
			}
		}

		if(ConfigChunkType == PREF_TRANSFER)
		{
			LONG i;

			if(Config->TransferConfig->ASCIIUploadLibrary[0])
				Config->TransferConfig->ASCIIUploadType = XFER_XPR;

			if(Config->TransferConfig->ASCIIDownloadLibrary[0])
				Config->TransferConfig->ASCIIDownloadType = XFER_XPR;

			if(Config->TransferConfig->TextUploadLibrary[0])
				Config->TransferConfig->TextUploadType = XFER_XPR;

			if(Config->TransferConfig->TextDownloadLibrary[0])
				Config->TransferConfig->TextDownloadType = XFER_XPR;

			if(Config->TransferConfig->BinaryUploadLibrary[0])
				Config->TransferConfig->BinaryUploadType = XFER_XPR;

			if(Config->TransferConfig->BinaryDownloadLibrary[0])
				Config->TransferConfig->BinaryDownloadType = XFER_XPR;

			for(i = 0 ; i < strlen(Config->TransferConfig->DefaultLibrary) - 6 ; i++)
			{
				if(!Strnicmp(&Config->TransferConfig->DefaultLibrary[i],"zmodem",6))
				{
					strcpy(Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature,"*\030B01");

					Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Length = strlen(Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature);

					break;
				}
			}

			switch(Config->TransferConfig->SendCR)
			{
				case CR_IGNORE:

					Config->TransferConfig->SendCR = EOL_IGNORE;
					break;

				case CR_ASCR:

					Config->TransferConfig->SendCR = EOL_CR;
					break;

				case CR_ASCRLF:

					Config->TransferConfig->SendCR = EOL_CRLF;
					break;
			}

			switch(Config->TransferConfig->ReceiveCR)
			{
				case CR_IGNORE:

					Config->TransferConfig->ReceiveCR = EOL_IGNORE;
					break;

				case CR_ASCR:

					Config->TransferConfig->ReceiveCR = EOL_CR;
					break;

				case CR_ASCRLF:

					Config->TransferConfig->ReceiveCR = EOL_CRLF;
					break;
			}

			switch(Config->TransferConfig->SendLF)
			{
				case LF_IGNORE:

					Config->TransferConfig->SendLF = EOL_IGNORE;
					break;

				case LF_ASLF:

					Config->TransferConfig->SendLF = EOL_LF;
					break;

				case LF_ASLFCR:

					Config->TransferConfig->SendLF = EOL_LFCR;
					break;
			}

			switch(Config->TransferConfig->ReceiveLF)
			{
				case LF_IGNORE:

					Config->TransferConfig->ReceiveLF = EOL_IGNORE;
					break;

				case LF_ASLF:

					Config->TransferConfig->ReceiveLF = EOL_LF;
					break;

				case LF_ASLFCR:

					Config->TransferConfig->ReceiveLF = EOL_LFCR;
					break;
			}
		}
	}

	if(Version == 4 && Revision < 3)
	{
		if(ConfigChunkType == PREF_CLIP)
			Config->ClipConfig->ConvertLF = TRUE;

		if(ConfigChunkType == PREF_SERIAL)
		{
			Config->SerialConfig->xONxOFF		= FALSE;
			Config->SerialConfig->PassThrough	= TRUE;
		}

		if(ConfigChunkType == PREF_MISC)
			Config->MiscConfig->ProtectiveMode = TRUE;

		if(ConfigChunkType == PREF_TRANSFER)
		{
			LONG i;

			for(i = 0 ; i < strlen(Config->TransferConfig->DefaultLibrary) - 6 ; i++)
			{
				if(!Strnicmp(&Config->TransferConfig->DefaultLibrary[i],"zmodem",6))
				{
					strcpy(Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature,"*\030B01");

					Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Length = strlen(Config->TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature);

					break;
				}
			}

			if(Config->TransferConfig->ASCIIUploadLibrary[0])
				Config->TransferConfig->ASCIIUploadType = XFER_XPR;

			if(Config->TransferConfig->ASCIIDownloadLibrary[0])
				Config->TransferConfig->ASCIIDownloadType = XFER_XPR;

			if(Config->TransferConfig->InternalASCIIUpload)
				Config->TransferConfig->ASCIIUploadType = XFER_INTERNAL;

			if(Config->TransferConfig->InternalASCIIDownload)
				Config->TransferConfig->ASCIIDownloadType = XFER_INTERNAL;

			if(Config->TransferConfig->TextUploadLibrary[0])
				Config->TransferConfig->TextUploadType = XFER_XPR;

			if(Config->TransferConfig->TextDownloadLibrary[0])
				Config->TransferConfig->TextDownloadType = XFER_XPR;

			if(Config->TransferConfig->BinaryUploadLibrary[0])
				Config->TransferConfig->BinaryUploadType = XFER_XPR;

			if(Config->TransferConfig->BinaryDownloadLibrary[0])
				Config->TransferConfig->BinaryDownloadType = XFER_XPR;
		}
	}
}

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

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

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

/*****************************************************************************/

	/* ReadSystemPrefs():
	 *
	 *	Reads the system preferences settings.
	 */

STATIC BOOL
ReadSystemPrefs(STRPTR Name,ULONG ID,APTR Data,LONG Size,LONG Count)
{
	struct IFFHandle	*Handle;
	BOOL				 Success = FALSE;
	LONG				 Error;

		/* Allocate an IFF handle. */

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

		if(Handle->iff_Stream = Open(Name,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)))
				{
						/* Look for it... */

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

						if(ReadChunkBytes(Handle,Data,Size) == Size)
						{
							Success = TRUE;

							if(Count)
							{
								Count--;

								Data = (APTR)((ULONG)Data + Size);
							}
							else
								break;
						}
						else
						{
							Error = IoErr();

							Success = FALSE;

							break;
						}
					}
				}

					/* 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 BOOLEAN				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 = ReadSystemPrefs("ENV:sys/serial.prefs",ID_SERL,&SerialPrefs,sizeof(SerialPrefs),1) ^ TRUE;

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

	if(!SerialPrefsRead)
	{
		SerialConfig->BaudRate				= 19200;
		SerialConfig->BitsPerChar			= 8;
		SerialConfig->Parity				= PARITY_NONE;
		SerialConfig->StopBits				= 1;
		SerialConfig->HandshakingProtocol	= HANDSHAKING_RTSCTS_DSR;
		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;

				break;

			case HSHAKE_RTS:

				SerialConfig->HandshakingProtocol = HANDSHAKING_RTSCTS_DSR;

				break;

			default:

				SerialConfig->HandshakingProtocol = HANDSHAKING_NONE;

				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->BreakLength			= 250000;
	SerialConfig->UnitNumber			= 0;
	SerialConfig->PassThrough			= TRUE;

	SerialConfig->Quantum				= 256;

	SerialConfig->NetID					= 0002;

	SerialConfig->SatisfyODURequests	= ODU_RELEASE;
}

STATIC VOID
ResetModem(struct ModemSettings *ModemConfig)
{
	strcpy(ModemConfig->ModemInit,			"ATX3E1V1Q0\\r");
	strcpy(ModemConfig->ModemExit,			"");
	strcpy(ModemConfig->ModemHangup,		"~~~~+++~~~~ATH0\\r");
	strcpy(ModemConfig->DialPrefix,			"ATD\\w");
	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				= 20;
	ModemConfig->DialRetries				= 10;
	ModemConfig->DialTimeout				= 60;

	ModemConfig->NoCarrierIsBusy			= TRUE;

	ModemConfig->DialMode					= DIALMODE_PULSE;

	strcpy(ModemConfig->PBX_Prefix,			"0,,,");
}

STATIC VOID
ResetScreen(struct ScreenSettings *ScreenConfig)
{
	ULONG			 DisplayID;
	struct Screen	*PubScreen;

	if(!FontPrefsRead && !FontPrefsReadFailed)
		FontPrefsReadFailed = ReadSystemPrefs("ENV:sys/font.prefs",ID_FONT,FontPrefs,sizeof(struct FontPrefs),3) ^ TRUE;

	DisplayID = INVALID_ID;

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

	if(!FontPrefsReadFailed)
	{
		LONG i;

		for(i = 0 ; i < 3 ; i++)
		{
			if(FontPrefs[i].fp_Type == FP_SCREENFONT)
			{
				strcpy(ScreenConfig->FontName,FontPrefs[i].fp_Name);
				ScreenConfig->FontHeight = FontPrefs[i].fp_TextAttr.ta_YSize;

				break;
			}
		}
	}

	if(DisplayID == INVALID_ID)
	{
		if(PubScreen = LockPubScreen(NULL))
		{
			DisplayID = GetVPModeID(&PubScreen->ViewPort);

			UnlockPubScreen(NULL,PubScreen);
		}
		else
			DisplayID = DEFAULT_MONITOR_ID | HIRESLACE_KEY;
	}

	ScreenConfig->DisplayMode		= DisplayID;
	ScreenConfig->ColourMode		= COLOUR_AMIGA;
	ScreenConfig->MakeScreenPublic	= TRUE;
	ScreenConfig->TitleBar			= TRUE;
	ScreenConfig->StatusLine		= STATUSLINE_STANDARD;
	ScreenConfig->Blinking			= TRUE;
	ScreenConfig->FasterLayout		= TRUE;

	ScreenConfig->TimeMode			= ONLINETIME_BOTH;
	ScreenConfig->UsePens			= TRUE;
	ScreenConfig->PenColourMode		= COLOUR_AMIGA;

	ScreenConfig->OverscanType		= OSCAN_TEXT;
}

STATIC VOID
ResetTerminal(struct TerminalSettings *TerminalConfig)
{
	if(!FontPrefsRead && !FontPrefsReadFailed)
		FontPrefsReadFailed = ReadSystemPrefs("ENV:sys/font.prefs",ID_FONT,FontPrefs,sizeof(struct FontPrefs),3) ^ TRUE;

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

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

	if(!FontPrefsReadFailed)
	{
		LONG i;

		for(i = 0 ; i < 3 ; i++)
		{
			if(FontPrefs[i].fp_Type == FP_SYSFONT)
			{
				strcpy(TerminalConfig->TextFontName,FontPrefs[i].fp_Name);
				TerminalConfig->TextFontHeight = FontPrefs[i].fp_TextAttr.ta_YSize;

				if(TerminalConfig->TextFontHeight == 8 || TerminalConfig->TextFontHeight == 11)
					TerminalConfig->IBMFontHeight = TerminalConfig->TextFontHeight;

				break;
			}
		}
	}

	TerminalConfig->BellMode				= BELL_AUDIBLE;
	TerminalConfig->AlertMode				= ALERT_BEEP_SCREEN;
	TerminalConfig->EmulationMode			= EMULATION_ANSIVT100;
	TerminalConfig->FontMode				= FONT_STANDARD;

	TerminalConfig->SendCR					= EOL_CR;
	TerminalConfig->SendLF					= EOL_LF;
	TerminalConfig->ReceiveCR				= EOL_CR;
	TerminalConfig->ReceiveLF				= EOL_LF;
}

STATIC VOID
ResetEmulation(struct EmulationSettings *EmulationConfig)
{
	LONG i;

	EmulationConfig->CursorMode				= KEYMODE_STANDARD;
	EmulationConfig->NumericMode			= KEYMODE_STANDARD;

	EmulationConfig->LineWrap				= TRUE;

	EmulationConfig->FontScale				= SCALE_NORMAL;
	EmulationConfig->ScrollMode				= SCROLL_JUMP;
	EmulationConfig->PrinterEnabled			= TRUE;
	EmulationConfig->MaxJump				= 1;

	EmulationConfig->UseStandardPens		= TRUE;

	for(i = TEXTATTR_UNDERLINE ; i <= TEXTATTR_INVERSE ; i++)
		EmulationConfig->Attributes[i] = i;

	for(i = 0 ; i < 16 ; i++)
		EmulationConfig->Pens[i] = i;

	EmulationConfig->TerminalType = TERMINAL_VT200;
}

STATIC VOID
ResetClip(struct ClipSettings *ClipConfig)
{
	strcpy(ClipConfig->InsertSuffix,"\\r");

	ClipConfig->PacingMode		= PACE_DIRECT;
	ClipConfig->ConvertLF		= TRUE;
}

STATIC VOID
ResetCapture(struct CaptureSettings *CaptureConfig)
{
	CaptureConfig->BufferEnabled		= TRUE;

	CaptureConfig->CaptureFilterMode	= FILTER_BOTH;

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

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

	CaptureConfig->BufferScreenMode		= INVALID_ID;

	CaptureConfig->BufferMode			= BUFFERMODE_FLOW;
}

STATIC VOID
ResetTranslationFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

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

	strcpy(Here,LastTranslation);
}

STATIC VOID
ResetMacroFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

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

	strcpy(Here,LastMacros);
}

STATIC VOID
ResetCursorFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

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

	strcpy(Here,LastCursorKeys);
}

STATIC VOID
ResetFastMacroFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

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

	strcpy(Here,LastFastMacros);
}

STATIC VOID
ResetSpeechFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

		AddPart(LastSpeech,"speech.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(Here,LastSpeech);
}

STATIC VOID
ResetSoundFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

		AddPart(LastSound,"sound.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(Here,LastSound);
}

STATIC VOID
ResetAreaCodeFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

		AddPart(LastPattern,"rates.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(Here,LastPattern);
}

STATIC VOID
ResetPhonebookFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

		AddPart(LastPhone,"phonebook.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(Here,LastPhone);
}

STATIC VOID
ResetHotkeyFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

		AddPart(LastKeys,"hotkeys.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(Here,LastKeys);
}

STATIC VOID
ResetTrapFile(STRPTR Here,STRPTR PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "TERM:config";

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

		AddPart(LastTraps,"trap.prefs",MAX_FILENAME_LENGTH);
	}

	strcpy(Here,LastTraps);
}

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

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

	strcpy(PathConfig->DefaultStorage,PathBuffer);

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

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

	MiscConfig->ReleaseDevice		= TRUE;

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

	MiscConfig->OverridePath		= TRUE;
	MiscConfig->AutoUpload			= TRUE;
	MiscConfig->IdentifyFiles		= IDENTIFY_FILETYPE;

	MiscConfig->IOBufferSize		= 32768;

	MiscConfig->ProtectiveMode		= TRUE;

	MiscConfig->AlertMode			= ALERT_BEEP_SCREEN;
	MiscConfig->RequesterMode		= REQUESTERMODE_IGNORE;

	strcpy(MiscConfig->WaitString," \\b");

	MiscConfig->WaitDelay			= 1;	// Just one second
}

STATIC VOID
ResetCommand(struct CommandSettings *CommandConfig)
{
}

STATIC VOID
ResetTransfer(struct TransferSettings *TransferConfig,STRPTR DefaultLib)
{
	LONG i;

	if(!DefaultLib)
		strcpy(TransferConfig->DefaultLibrary,"xprzmodem.library");
	else
		strcpy(TransferConfig->DefaultLibrary,DefaultLib);

	for(i = 0 ; i < strlen(TransferConfig->DefaultLibrary) - 6 ; i++)
	{
		if(!Strnicmp(&TransferConfig->DefaultLibrary[i],"zmodem",6))
		{
			strcpy(TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature,"*\030B01");

			TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Length = strlen(TransferConfig->Signatures[TRANSFERSIG_DEFAULTUPLOAD].Signature);

			break;
		}
	}

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

	strcpy(TransferConfig->BinaryUploadLibrary,"run hydracom device %p speed %b line %c nocarrier rec %> send %m");
	strcpy(TransferConfig->BinaryDownloadLibrary,"run hydracom device %p speed %b line %c nocarrier rec %> get");

	TransferConfig->PacingMode				= PACE_DIRECT;
	TransferConfig->IgnoreDataPastArnold	= TRUE;
	TransferConfig->TerminatorChar			= 0x1A;
	TransferConfig->SendCR					= EOL_CR;
	TransferConfig->SendLF					= EOL_LF;
	TransferConfig->ReceiveCR				= EOL_CR;
	TransferConfig->ReceiveLF				= EOL_LF;

	TransferConfig->ErrorNotification		= 20;
	TransferConfig->TransferNotification	= XFERNOTIFY_ALWAYS;

	TransferConfig->DefaultType				= XFER_XPR;
	TransferConfig->ASCIIDownloadType		= XFER_XPR;
	TransferConfig->ASCIIUploadType			= XFER_XPR;
	TransferConfig->TextDownloadType		= XFER_DEFAULT;
	TransferConfig->TextUploadType			= XFER_DEFAULT;
	TransferConfig->BinaryDownloadType		= XFER_DEFAULT;
	TransferConfig->BinaryUploadType		= XFER_DEFAULT;

	TransferConfig->OverridePath			= TRUE;
	TransferConfig->IdentifyFiles			= IDENTIFY_FILETYPE;
}

/*****************************************************************************/

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

VOID
ResetConfig(struct Configuration *Config,STRPTR PathBuffer)
{
	LONG	Type;
	APTR	Data;
	STRPTR	Arg;

	if(!PathBuffer)
		PathBuffer = "TERM:config";

	for(Type = PREF_SERIAL ; Type < PREF_RATES ; Type++)
	{
		if(Data = GetConfigEntry(Config,Type))
		{
			memset(Data,0,SizeTable[Type - PREF_SERIAL]);

			switch(Type)
			{
				case PREF_PATH:
				case PREF_FILE:
				case PREF_TRANSLATIONFILENAME:
				case PREF_MACROFILENAME:
				case PREF_CURSORFILENAME:
				case PREF_FASTMACROFILENAME:
				case PREF_SPEECHFILENAME:
				case PREF_SOUNDFILENAME:
				case PREF_AREACODEFILENAME:
				case PREF_PHONEBOOKFILENAME:
				case PREF_HOTKEYFILENAME:
				case PREF_TRAPFILENAME:

					Arg = PathBuffer;
					break;

				case PREF_TRANSFER:

					if(Config->FileConfig)
						Arg = Config->FileConfig->ProtocolFileName;
					else
						Arg = "xprzmodem.library";

					break;

				default:

					Arg = NULL;
					break;
			}

			(*ResetTable[Type - PREF_SERIAL])(Data,Arg);
		}
	}
}

VOID
DeleteConfigEntry(struct Configuration *Config,LONG Type)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type < PREF_RATES ; Type++)
			DeleteConfigEntry(Config,Type);
	}
	else
	{
		APTR *Mem;

		switch(Type)
		{
			case PREF_SERIAL:

				Mem = (APTR *)&Config->SerialConfig;
				break;

			case PREF_MODEM:

				Mem = (APTR *)&Config->ModemConfig;
				break;

			case PREF_COMMAND:

				Mem = (APTR *)&Config->CommandConfig;
				break;

			case PREF_SCREEN:

				Mem = (APTR *)&Config->ScreenConfig;
				break;

			case PREF_TERMINAL:

				Mem = (APTR *)&Config->TerminalConfig;
				break;

			case PREF_PATH:

				Mem = (APTR *)&Config->PathConfig;
				break;

			case PREF_MISC:

				Mem = (APTR *)&Config->MiscConfig;
				break;

			case PREF_CLIP:

				Mem = (APTR *)&Config->ClipConfig;
				break;

			case PREF_CAPTURE:

				Mem = (APTR *)&Config->CaptureConfig;
				break;

			case PREF_FILE:

				Mem = (APTR *)&Config->FileConfig;
				break;

			case PREF_EMULATION:

				Mem = (APTR *)&Config->EmulationConfig;
				break;

			case PREF_TRANSFER:

				Mem = (APTR *)&Config->TransferConfig;
				break;

			case PREF_TRANSLATIONFILENAME:

				Mem = (APTR *)&Config->TranslationFileName;
				break;

			case PREF_MACROFILENAME:

				Mem = (APTR *)&Config->MacroFileName;
				break;

			case PREF_CURSORFILENAME:

				Mem = (APTR *)&Config->CursorFileName;
				break;

			case PREF_FASTMACROFILENAME:

				Mem = (APTR *)&Config->FastMacroFileName;
				break;

			case PREF_SPEECHFILENAME:

				Mem = (APTR *)&Config->SpeechFileName;
				break;

			case PREF_SOUNDFILENAME:

				Mem = (APTR *)&Config->SoundFileName;
				break;

			case PREF_AREACODEFILENAME:

				Mem = (APTR *)&Config->AreaCodeFileName;
				break;

			case PREF_PHONEBOOKFILENAME:

				Mem = (APTR *)&Config->PhonebookFileName;
				break;

			case PREF_HOTKEYFILENAME:

				Mem = (APTR *)&Config->HotkeyFileName;
				break;

			case PREF_TRAPFILENAME:

				Mem = (APTR *)&Config->TrapFileName;
				break;

			default:

				Mem = NULL;
				break;
		}

		if(Mem)
		{
			FreeVecPooled(*Mem);

			*Mem = NULL;
		}
	}
}

VOID
ResetConfigEntry(struct Configuration *LocalConfig,LONG Type,BOOL Default)
{
	if(LocalConfig)
	{
		if(Type == PREF_ALL)
		{
			for(Type = PREF_SERIAL ; Type < PREF_RATES ; Type++)
				ResetConfigEntry(LocalConfig,Type,Default);
		}
		else
		{
			if(Type >= PREF_SERIAL && Type < PREF_RATES)
			{
				APTR From,To;

				From	= GetConfigEntry(Config,Type);
				To		= GetConfigEntry(LocalConfig,Type);

				if(To)
				{
					LONG Size = SizeTable[Type - PREF_SERIAL];

					if(Default || !From)
					{
						memset(To,0,Size);

						(*ResetTable[Type - PREF_SERIAL])(To,NULL);
					}
					else
						CopyMem(From,To,Size);

					if(Type == PREF_SCREEN)
						FixScreenPens(LocalConfig->ScreenConfig);
				}
			}
		}
	}
}

APTR
GetConfigEntry(const struct Configuration *Config,LONG Type)
{
	if(!Config)
		return(NULL);

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

		case PREF_TRANSLATIONFILENAME:

			return(Config->TranslationFileName);

		case PREF_MACROFILENAME:

			return(Config->MacroFileName);

		case PREF_CURSORFILENAME:

			return(Config->CursorFileName);

		case PREF_FASTMACROFILENAME:

			return(Config->FastMacroFileName);

		case PREF_SPEECHFILENAME:

			return(Config->SpeechFileName);

		case PREF_SOUNDFILENAME:

			return(Config->SoundFileName);

		case PREF_AREACODEFILENAME:

			return(Config->AreaCodeFileName);

		case PREF_PHONEBOOKFILENAME:

			return(Config->PhonebookFileName);

		case PREF_HOTKEYFILENAME:

			return(Config->HotkeyFileName);

		case PREF_TRAPFILENAME:

			return(Config->TrapFileName);

		default:

			return(NULL);
	}
}

BOOL
CreateConfigEntry(struct Configuration *Config,LONG Type)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type < PREF_RATES ; Type++)
		{
			if(!CreateConfigEntry(Config,Type))
			{
				DeleteConfigEntry(Config,PREF_ALL);

				return(FALSE);
			}
		}
	}
	else
	{
		APTR Data;

		if(Type < PREF_SERIAL || Type >= PREF_RATES)
			return(FALSE);
		else
		{
			if(!(Data = GetConfigEntry(Config,Type)))
			{
				DB(kprintf("creating config entry %ld, size = %ld\n",Type,SizeTable[Type - PREF_SERIAL]));

				if(!(Data = AllocVecPooled(SizeTable[Type - PREF_SERIAL],MEMF_ANY | MEMF_CLEAR)))
				{
					DB(kprintf("\tallocation failed\n"));
					return(FALSE);
				}
				else
				{
					DB(kprintf("\tok\n"));

					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;

						case PREF_TRANSLATIONFILENAME:

							Config->TranslationFileName = Data;
							break;

						case PREF_MACROFILENAME:

							Config->MacroFileName = Data;
							break;

						case PREF_CURSORFILENAME:

							Config->CursorFileName = Data;
							break;

						case PREF_FASTMACROFILENAME:

							Config->FastMacroFileName = Data;
							break;

						case PREF_SPEECHFILENAME:

							Config->SpeechFileName = Data;
							break;

						case PREF_SOUNDFILENAME:

							Config->SoundFileName = Data;
							break;

						case PREF_AREACODEFILENAME:

							Config->AreaCodeFileName = Data;
							break;

						case PREF_PHONEBOOKFILENAME:

							Config->PhonebookFileName = Data;
							break;

						case PREF_HOTKEYFILENAME:

							Config->HotkeyFileName = Data;
							break;

						case PREF_TRAPFILENAME:

							Config->TrapFileName = Data;
							break;
					}

					DB(kprintf("\tresetting\n"));
					ResetConfigEntry(Config,Type,FALSE);
					DB(kprintf("\tdone\n"));
				}
			}
		}
	}

	return(TRUE);
}

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

		FreeVecPooled(Config);
	}
}

struct Configuration *
CreateConfiguration(BOOL 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 BOOL
WriteConfigChunk(struct IFFHandle *Handle,struct Configuration *Config,LONG Type,APTR TempBuffer,STRPTR Password)
{
	if(Type >= PREF_SERIAL && Type < PREF_RATES && Type != PREF_FILE)
	{
		APTR Data;

		if(Data = GetConfigEntry(Config,Type))
		{
			if(TempBuffer)
			{
				Encrypt(Data,SizeTable[Type - PREF_SERIAL],TempBuffer,Password,20);

				Data = TempBuffer;
			}

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

			return(FALSE);
		}
	}

	return(TRUE);
}

STATIC LONG
IsConfigChunk(ULONG ID)
{
	LONG Type;

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

	return(0);
}

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

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

	return(TRUE);
}

VOID
SaveConfig(const struct Configuration *Src,struct Configuration *Dst)
{
	APTR From,To;
	LONG Type;

	for(Type = PREF_SERIAL ; Type < PREF_RATES ; Type++)
	{
		if((From = GetConfigEntry(Src,Type)) && (To = GetConfigEntry(Dst,Type)))
		{
			CopyMem(From,To,SizeTable[Type - PREF_SERIAL]);

			if(Type == PREF_SCREEN)
				FixScreenPens(To);
		}
	}
}

VOID
UpdateConfig(const struct Configuration *Src,struct Configuration *Dst)
{
	SaveConfig(Src,Dst);
}

VOID
SwapConfig(struct Configuration *Src,struct Configuration *Dst)
{
	APTR From,To;
	LONG Type;

	for(Type = PREF_SERIAL ; Type < PREF_RATES ; Type++)
	{
		if((From = GetConfigEntry(Src,Type)) && (To = GetConfigEntry(Dst,Type)))
			swmem(From,To,SizeTable[Type - PREF_SERIAL]);
	}
}

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

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

#ifdef BETA
	if(ShowRequest(Window,
		"ONE WAY TICKET WARNING!\n\n"
		"The file format written by this `term' beta test release\n"
		"cannot be read by older program releases. And just as it\n"
		"happens, not even the author of these lines can guarantee\n"
		"you that this very program will be able to read the files\n"
		"back it writes.",
	"Uh oh...|I know what I'm doing"))
		return(TRUE);
#endif

	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	= CONFIG_FILE_VERSION;
								TermInfo.Revision	= CONFIG_FILE_REVISION;

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

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

													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)))
											{
												PhonebookGlobals Globals;

												Globals.Count			= NumPhoneEntries;
												Globals.ID				= PhonebookID;
												Globals.DefaultGroup	= PhonebookDefaultGroup;
												Globals.AutoDial		= PhonebookAutoDial;
												Globals.AutoExit		= PhonebookAutoExit;

												if(WriteChunkBytes(Handle,&Globals,sizeof(Globals)) == sizeof(Globals))
												{
													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))
																					{
																						Success = TRUE;

																						if(!Phonebook[i]->Header->NoRates)
																						{
																							struct TimeDateNode *TimeDateNode;

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

																							while(TimeDateNode->VanillaNode.ln_Succ)
																							{
																								if(!(Error = PushChunk(Handle,0,ID_DAT2,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))
																					{
																						Success = TRUE;

																						if(!Phonebook[i]->Header->NoRates)
																						{
																							struct TimeDateNode *TimeDateNode;

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

																							while(TimeDateNode->VanillaNode.ln_Succ)
																							{
																								if(!(Error = PushChunk(Handle,0,ID_DAT2,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(Error = PopChunk(Handle))
																			Success = FALSE;
																	}
																}
															}

																// Now for the groups

															if(Success && PhoneGroupList.mlh_Head->mln_Succ)
															{
																struct PhoneGroupNode	*GroupNode;
																struct PhoneNode		*Node;
																PhoneGroupHeader		 Header;
																BOOL					 GotData = FALSE;

																	// So the extension stuff is set to zero

																memset(&Header,0,sizeof(Header));

																	// Run down the groups

																for(GroupNode = (PhoneGroupNode *)PhoneGroupList.mlh_Head ; Success && GroupNode->Node.ln_Succ ; GroupNode = (PhoneGroupNode *)GroupNode->Node.ln_Succ)
																{
																		// Count the members

																	Header.Count = 0;

																	for(Node = (struct PhoneNode *)GroupNode->GroupList.mlh_Head ; Node->VanillaNode.ln_Succ ; Node = (struct PhoneNode *)Node->VanillaNode.ln_Succ)
																		Header.Count++;

																		// Open the group

																	if(Header.Count)
																	{
																		if(!GotData)
																		{
																			if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
																				GotData = TRUE;
																		}

																			// Pick up the group name

																		strcpy(Header.FullName,GroupNode->LocalName);

																		if(!Error)
																			Error = PushChunk(Handle,0,ID_GRUP,sizeof(Header) + sizeof(LONG) * Header.Count);

																		if(!Error)
																		{
																				// First the header...

																			if(WriteChunkBytes(Handle,&Header,sizeof(Header)) == sizeof(Header))
																			{
																					// ...then the IDs of the group members

																				for(Node = (struct PhoneNode *)GroupNode->GroupList.mlh_Head ; Node->VanillaNode.ln_Succ ; Node = (struct PhoneNode *)Node->VanillaNode.ln_Succ)
																				{
																					if(WriteChunkBytes(Handle,&Node->Entry->Header->ID,sizeof(ULONG)) != sizeof(ULONG))
																					{
																						Success = FALSE;
																						break;
																					}
																				}

																				if(!Success)
																				{
																					Error = IoErr();
																					break;
																				}
																			}
																			else
																			{
																				Error = IoErr();
																				Success = FALSE;
																				break;
																			}

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

																if(Success && GotData)
																{
																	if(Error = 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 BOOL
ReadConfigChunk(struct IFFHandle *Handle,struct Configuration *Config,LONG Type,LONG Len,STRPTR Password)
{
	if(CreateConfigEntry(Config,Type))
	{
		APTR Data;

		Data = GetConfigEntry(Config,Type);

		Len = MIN(SizeTable[Type - PREF_SERIAL],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.
	 */

BOOL
LoadPhonebook(STRPTR Name,PhonebookHandle *BookHandle)
{
	struct PhoneEntry	**PrivatePhonebook;
	LONG				 PrivatePhoneSize	= 0,
						 CurrentPhoneSize	= 0,
						 Count				= 0,
						 Index				= 0;
	BOOL				 Success			= FALSE,
						 LastHadTime		= TRUE,
						 UsePhonePassword	= FALSE,
						 FirstChunk			= TRUE,
						 UseOld				= FALSE;
	struct IFFHandle	*Handle;
	struct ContextNode	*Chunk;
	struct TimeDateNode	*TimeDateNode;
	UBYTE				 ConfigChunkType,
						 PasswordBuffer[20];
	LONG				 Error;
	PhonebookGlobals	 Globals;
	struct timeval		 Now;
	ULONG				 PrivatePhonebookID;
	struct MinList		 LocalPhoneGroupList;
	BOOL				 CheckedChunk = FALSE;
	BOOL				 GotID = FALSE;

	NewList((struct List *)&LocalPhoneGroupList);

	GetSysTime(&Now);

	memset(&Globals,0,sizeof(Globals));

	Globals.ID				= Now.tv_secs;
	Globals.DefaultGroup	= 0;
	Globals.AutoDial		= 0;
	Globals.AutoExit		= 0;

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

			if(!(Error = OpenIFF(Handle,IFFF_READ)))
			{
				if(!(Error = StopChunks(Handle,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 != CONFIG_FILE_VERSION || (TermInfo.Version == CONFIG_FILE_VERSION && TermInfo.Revision > CONFIG_FILE_REVISION))
								{
									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(BookHandle)
								{
									if(BookHandle->PhonePasswordUsed)
									{
										if(!memcmp(BookHandle->PhonePassword,PasswordBuffer,20))
										{
											UsePhonePassword = TRUE;

											continue;
										}
									}
								}
								else
								{
									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
									{
										ShowRequest(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)
						{
							LONG Size = MIN(sizeof(PhonebookGlobals),Chunk->cn_Size);

							if(ReadChunkBytes(Handle,&Globals,Size) == Size)
							{
								CurrentPhoneSize = Globals.Count;

								if(Size >= sizeof(PhonebookGlobals))
									GotID = TRUE;

								PrivatePhonebookID = Globals.ID;

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

							memset(PrivatePhonebook[Index]->Header,0,sizeof(struct PhoneHeader));

							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;

								if(!GotID)
									PrivatePhonebook[Index]->Header->ID = PrivatePhonebookID++;

								LastHadTime = FALSE;

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

								break;
							}
						}

							// Mucho importante -- must follow the phonebook entries

						if(Chunk->cn_ID == ID_GRUP)
						{
							PhoneGroupHeader	 Header;
							struct MinList		*GroupList;

							DB(kprintf("--> ID_GRUP\n"));

							if(BookHandle)
								GroupList = BookHandle->PhoneGroupList;
							else
								GroupList = &LocalPhoneGroupList;

							if(GroupList)
							{
								if(ReadChunkBytes(Handle,&Header,sizeof(Header)) == sizeof(Header))
								{
									PhoneGroupNode	*GroupNode;
									ULONG			 ID;
									LONG			 i;

									GroupNode = NULL;

									Success = TRUE;

									DB(kprintf("group name |%s| entries %ld\n",Header.FullName,Header.Count));

									for(i = 0 ; Success && i < Header.Count ; i++)
									{
										if(ReadChunkBytes(Handle,&ID,sizeof(ULONG)) == sizeof(ULONG))
										{
											struct PhoneNode	*Node;
											LONG				 j;

											DB(kprintf("looking for 0x%08lx\n",ID));

											for(j = 0 ; j < CurrentPhoneSize ; j++)
											{
												if(PrivatePhonebook[j]->Header->ID == ID)
												{
													DB(kprintf("found it |%s|\n",PrivatePhonebook[j]->Header->Name));

													if(!GroupNode)
													{
														if(!(GroupNode = (PhoneGroupNode *)AllocVecPooled(sizeof(PhoneGroupNode),MEMF_ANY | MEMF_CLEAR)))
														{
															Error = ERROR_NO_FREE_STORE;

															Success = FALSE;

															break;
														}

														strcpy(GroupNode->LocalName,Header.FullName);

														GroupNode->Node.ln_Name = GroupNode->LocalName;

														NewList((struct List *)&GroupNode->GroupList);

														AddTail((struct List *)&LocalPhoneGroupList,(struct Node *)GroupNode);
													}

													if(Node = (struct PhoneNode *)AllocVecPooled(sizeof(struct PhoneNode),MEMF_ANY | MEMF_CLEAR))
													{
														PrivatePhonebook[j]->ThisGroup	= GroupNode;
														PrivatePhonebook[j]->NodeGroup	= Node;

														Node->VanillaNode.ln_Name	= Node->LocalName;
														Node->Entry					= PrivatePhonebook[j];

														SPrintf(Node->LocalName,"      %s",PrivatePhonebook[j]->Header->Name);

														AddTail((struct List *)&GroupNode->GroupList,(struct Node *)Node);
													}
													else
													{
														Error = ERROR_NO_FREE_STORE;

														Success = FALSE;

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

											Success = FALSE;

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

									Success = FALSE;
								}
							}

							if(!Success)
								break;
						}

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

							if(UsePhonePassword)
							{
								if(!ReadConfigChunk(Handle,PrivatePhonebook[Index]->Config,ConfigChunkType,Chunk->cn_Size,PasswordBuffer))
								{
									if(Count)
										CurrentPhoneSize = Count - 1;
									else
										CurrentPhoneSize = 0;

									break;
								}
								else
									FixOldConfig(PrivatePhonebook[Index]->Config,ConfigChunkType,TRUE,TermInfo.Version,TermInfo.Revision);
							}
							else
							{
								if(!ReadConfigChunk(Handle,PrivatePhonebook[Index]->Config,ConfigChunkType,Chunk->cn_Size,NULL))
								{
									if(Count)
										CurrentPhoneSize = Count - 1;
									else
										CurrentPhoneSize = 0;

									break;
								}
								else
									FixOldConfig(PrivatePhonebook[Index]->Config,ConfigChunkType,TRUE,TermInfo.Version,TermInfo.Revision);
							}
						}

							// Special treatment for obsolete "FILE" chunk

						if(Chunk->cn_ID == ID_FILE)
						{
							struct Configuration *Config = PrivatePhonebook[Index]->Config;
							LONG i;

							for(i = PREF_TRANSLATIONFILENAME ; i < PREF_RATES ; i++)
							{
								if(!CreateConfigEntry(Config,i))
								{
									Error = ERROR_NO_FREE_STORE;
									break;
								}
							}

							if(!Error)
							{
								strcpy(Config->TranslationFileName,	Config->FileConfig->TranslationFileName);
								strcpy(Config->MacroFileName,		Config->FileConfig->MacroFileName);
								strcpy(Config->CursorFileName,		Config->FileConfig->CursorFileName);
								strcpy(Config->FastMacroFileName,	Config->FileConfig->FastMacroFileName);

								DeleteConfigEntry(Config,PREF_FILE);
							}
						}

						if(Chunk->cn_ID == ID_DATE)
						{
							if(!PrivatePhonebook[Index]->Header->NoRates)
							{
								LONG Count = (Chunk->cn_Size - sizeof(struct TimeDateHeader)) / sizeof(struct TimeDateOld);

								if(!CurrentPhoneSize)
									break;

								if(TimeDateNode = CreateTimeDateNode(-1,-1,"",Count))
								{
									struct TimeDateOld *Old;

									if(Old = (struct TimeDateOld *)AllocVecPooled(sizeof(struct TimeDateOld) * Count,MEMF_ANY))
									{
										if(ReadChunkBytes(Handle,&TimeDateNode->Header,sizeof(struct TimeDateHeader)) == sizeof(struct TimeDateHeader))
										{
											if(ReadChunkRecords(Handle,Old,sizeof(struct TimeDateOld),Count) == Count)
											{
												LONG i;

												for(i = 0 ; i < Count ; i++)
													ConvertTimeDate(&Old[i],&TimeDateNode->Table[i]);

												AdaptTimeDateNode(TimeDateNode);

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

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

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

											FreeTimeDateNode(TimeDateNode);
										}

										FreeVecPooled(Old);
									}
									else
										Error = ERROR_NO_FREE_STORE;
								}
								else
									Error = ERROR_NO_FREE_STORE;
							}
						}

						if(Chunk->cn_ID == ID_DAT2)
						{
							if(!PrivatePhonebook[Index]->Header->NoRates)
							{
								LONG 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);
									}
								}
								else
									Error = IoErr();
							}
						}
					}

					if(CurrentPhoneSize && !Error)
					{
						LONG i;

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

						DB(for(i = 0 ; i < CurrentPhoneSize ; i++))
							DB(kprintf("0x%08lx |%s|\n",PrivatePhonebook[i]->Header->ID,PrivatePhonebook[i]->Header->Name));

						if(BookHandle)
						{
							BookHandle->PhonebookID = PrivatePhonebookID;

							if(BookHandle->Phonebook)
								DeletePhonebook(BookHandle->Phonebook,BookHandle->PhoneSize,TRUE);

							BookHandle->Phonebook		= PrivatePhonebook;
							BookHandle->PhoneSize		= PrivatePhoneSize;
							BookHandle->NumPhoneEntries	= CurrentPhoneSize;
							BookHandle->DefaultGroup	= Globals.DefaultGroup;
							BookHandle->AutoDial		= Globals.AutoDial;
							BookHandle->AutoExit		= Globals.AutoExit;

							if(BookHandle->PhoneGroupList)
							{
								DeletePhoneGroupList(BookHandle->PhoneGroupList);

								MoveList((struct List *)&LocalPhoneGroupList,(struct List *)BookHandle->PhoneGroupList);
							}
							else
								DeletePhoneGroupList(&LocalPhoneGroupList);

							CopyMem(PasswordBuffer,BookHandle->PhonePassword,20);
							BookHandle->PhonePasswordUsed = UsePhonePassword;

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

									FreeVecPooled(BookHandle->Phonebook[i]);

									BookHandle->Phonebook[i] = NULL;
								}
							}

							for(i = 0 ; i < BookHandle->NumPhoneEntries ; i++)
							{
								FinalFix(BookHandle->Phonebook[i]->Config,TRUE,TermInfo.Version,TermInfo.Revision);
								StripGlobals(BookHandle->Phonebook[i]->Config);
							}
						}
						else
						{
							PhonebookID = PrivatePhonebookID;

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

							Phonebook				= PrivatePhonebook;
							PhoneSize				= PrivatePhoneSize;
							NumPhoneEntries			= CurrentPhoneSize;
							PhonebookDefaultGroup	= Globals.DefaultGroup;
							PhonebookAutoDial		= Globals.AutoDial;
							PhonebookAutoExit		= Globals.AutoExit;

							DeletePhoneGroupList(&PhoneGroupList);

							MoveList((struct List *)&LocalPhoneGroupList,(struct List *)&PhoneGroupList);

							CopyMem(PasswordBuffer,PhonePassword,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;
								}
							}

							for(i = 0 ; i < NumPhoneEntries ; i++)
							{
								FinalFix(Phonebook[i]->Config,TRUE,TermInfo.Version,TermInfo.Revision);
								StripGlobals(Phonebook[i]->Config);
							}
						}

						FreeDialList(TRUE);

						Success = TRUE;
					}
					else
					{
						DeletePhoneGroupList(&LocalPhoneGroupList);

						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,BookHandle));
	else
		return(Success);
}

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

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

#ifdef BETA
	if(ShowRequest(Window,
		"ONE WAY TICKET WARNING!\n\n"
		"The file format written by this `term' beta test release\n"
		"cannot be read by older program releases. And just as it\n"
		"happens, not even the author of these lines can guarantee\n"
		"you that this very program will be able to read the files\n"
		"back it writes.",
	"Uh oh...|I know what I'm doing"))
		return(TRUE);
#endif

		/* 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	= CONFIG_FILE_VERSION;
						TermInfo.Revision	= CONFIG_FILE_REVISION;

							/* Update the other configuration pointer as well. */

						Config->SerialConfig->LastVersionSaved	= TermVersion;
						Config->SerialConfig->LastRevisionSaved	= 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);
	else
		SetIoErr(Error);

	return(Success);
}

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

BOOL
ReadConfig(STRPTR Name,struct Configuration *Config)
{
	struct IFFHandle	*Handle;
	BOOL				 Success	= FALSE,
						 UseOld		= FALSE;
	struct ContextNode	*Chunk;
	LONG				 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,Stops,NUM_STOPS))
				{
					struct TermInfo TermInfo;

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

							/* Oops! Someone 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 != CONFIG_FILE_VERSION || (TermInfo.Version == CONFIG_FILE_VERSION && TermInfo.Revision > CONFIG_FILE_REVISION))
								{
									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))
								{
									FixOldConfig(Config,ConfigChunkType,FALSE,TermInfo.Version,TermInfo.Revision);

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

									Success = FALSE;

									break;
								}
							}

								// Special treatment for obsolete "FILE" chunk

							if(Chunk->cn_ID == ID_FILE)
							{
								struct Configuration *LocalConfig = Config;
								LONG Type;

								for(Type = PREF_TRANSLATIONFILENAME ; Type < PREF_RATES ; Type++)
								{
									if(!CreateConfigEntry(LocalConfig,Type))
									{
										Error = ERROR_NO_FREE_STORE;

										Success = FALSE;

										break;
									}
								}

								if(!Error)
								{
									strcpy(LocalConfig->TranslationFileName,	LocalConfig->FileConfig->TranslationFileName);
									strcpy(LocalConfig->MacroFileName,			LocalConfig->FileConfig->MacroFileName);
									strcpy(LocalConfig->CursorFileName,			LocalConfig->FileConfig->CursorFileName);
									strcpy(LocalConfig->FastMacroFileName,		LocalConfig->FileConfig->FastMacroFileName);

									DeleteConfigEntry(LocalConfig,PREF_FILE);
								}
							}
						}
					}

					if(Success)
						FinalFix(Config,FALSE,TermInfo.Version,TermInfo.Revision);
				}

				CloseIFF(Handle);
			}

			Close(Handle->iff_Stream);
		}

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

	if(Error)
		SetIoErr(Error);

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