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

#include "termGlobal.h"

	/* Number of chunks to stop at. */

#define	NUM_STOPS	16

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

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

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

STATIC ULONG Stops[NUM_STOPS * 2] =
{
	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
};

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

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

		/* 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(!OpenIFF(Handle,IFFF_READ))
			{
					/* Stop at the `body' chunk. */

				if(!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;
					}
				}

					/* Close the handle. */

				CloseIFF(Handle);
			}

				/* Release the handle. */

			Close(Handle -> iff_Stream);
		}

			/* Clean up. */

		FreeIFF(Handle);
	}

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

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

STATIC VOID
ResetModem(struct ModemSettings *ModemConfig)
{
	strcpy(ModemConfig -> ModemInit,	"ATZ\\r");
	strcpy(ModemConfig -> ModemExit,	"");
	strcpy(ModemConfig -> ModemHangup,	"~~~~~~~~+++\\r~~~~~~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;
}

STATIC VOID
ResetScreen(struct ScreenSettings *ScreenConfig)
{
	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;
}

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

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

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

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

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

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

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

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

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

					Config -> SerialConfig = NULL;
				}

				break;

			case PREF_MODEM:

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

					Config -> ModemConfig = NULL;
				}

				break;

			case PREF_COMMAND:

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

					Config -> CommandConfig = NULL;
				}

				break;

			case PREF_SCREEN:

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

					Config -> ScreenConfig = NULL;
				}

				break;

			case PREF_TERMINAL:

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

					Config -> TerminalConfig = NULL;
				}

				break;

			case PREF_PATH:

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

					Config -> PathConfig = NULL;
				}

				break;

			case PREF_MISC:

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

					Config -> MiscConfig = NULL;
				}

				break;

			case PREF_CLIP:

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

					Config -> ClipConfig = NULL;
				}

				break;

			case PREF_CAPTURE:

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

					Config -> CaptureConfig = NULL;
				}

				break;

			case PREF_FILE:

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

					Config -> FileConfig = NULL;
				}

				break;

			case PREF_EMULATION:

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

					Config -> EmulationConfig = NULL;
				}

				break;
		}
	}
}

VOID
ResetConfigEntry(struct Configuration *Configuration,BYTE Type,BYTE Default)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type <= PREF_EMULATION ; 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));

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

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

		default:

			return(NULL);
	}
}

BYTE
CreateConfigEntry(struct Configuration *Config,BYTE Type)
{
	if(Type == PREF_ALL)
	{
		for(Type = PREF_SERIAL ; Type <= PREF_EMULATION ; 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;

			default:

				return(FALSE);
		}

		if(!Data)
		{
			if(Data = AllocVec(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;
				}

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

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

		FreeVec(Config);
	}
}

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

	if(Config = (struct Configuration *)AllocVec(sizeof(struct Configuration),MEMF_ANY | MEMF_CLEAR))
	{
		if(Fill)
		{
			if(!CreateConfigEntry(Config,PREF_ALL))
			{
				FreeVec(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;

		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_EMULATION ; 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_EMULATION ; Type++)
	{
		if(!WriteConfigChunk(Handle,Config,Type,TempBuffer,Password))
			return(FALSE);
	}

	return(TRUE);
}

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

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

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

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

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

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

BYTE
SavePhonebook(STRPTR Name)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;

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

				if(!OpenIFF(Handle,IFFF_WRITE))
				{
					if(!PushChunk(Handle,ID_TERM,ID_CAT,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN))
						{
							if(!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(!PopChunk(Handle))
									{
										STRPTR TempBuffer = NULL;

										if(PhonePasswordUsed)
										{
											if(!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_EMULATION ; Type++)
													{
														if(SizeTable[Type - 1] > Max)
															Max = SizeTable[Type - 1];
													}

													if(!(TempBuffer = AllocVec(Max,MEMF_ANY)))
														Success = FALSE;
												}
											}
										}
										else
											Success = TRUE;

										if(Success)
										{
											Success = FALSE;

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

															Success = TRUE;

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

																if(!PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN))
																{
																	if(!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(!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(!PushChunk(Handle,0,ID_DATE,IFFSIZE_UNKNOWN))
																							{
																								if(WriteChunkBytes(Handle,&TimeDateNode -> Header,sizeof(struct TimeDateHeader)) != sizeof(struct TimeDateHeader))
																								{
																									Success = FALSE;

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

																										break;
																									}
																								}

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

																									break;
																								}

																								TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
																							}
																						}
																					}
																					else
																						Success = FALSE;
																				}
																			}
																		}
																		else
																		{
																			if(WriteChunkRecords(Handle,Phonebook[i] -> Header,sizeof(struct PhoneHeader),1) == 1)
																			{
																				if(!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(!PushChunk(Handle,0,ID_DATE,IFFSIZE_UNKNOWN))
																							{
																								if(WriteChunkBytes(Handle,&TimeDateNode -> Header,sizeof(struct TimeDateHeader)) != sizeof(struct TimeDateHeader))
																								{
																									Success = FALSE;

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

																										break;
																									}
																								}

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

																									break;
																								}

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

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

										if(TempBuffer)
											FreeVec(TempBuffer);
									}
								}
							}
						}

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

					CloseIFF(Handle);
				}

				Close(Handle -> iff_Stream);
			}

			FreeIFF(Handle);
		}

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

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

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

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

			return(TRUE);
		}
	}

	return(FALSE);
}

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

BYTE
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];


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

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunks(Handle,Stops,NUM_STOPS))
				{
					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

						if(Chunk -> cn_ID == ID_VERS)
						{
							struct TermInfo TermInfo;

							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;

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

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

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

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

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

									break;
								}
							}
							else
							{
								if(!ReadConfigChunk(Handle,PrivatePhonebook[Index] -> Config,ConfigChunkType,Chunk -> cn_Size,NULL))
								{
									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(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
										FreeTimeDateNode(TimeDateNode);
								}
								else
									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);

								FreeVec(Phonebook[i]);

								Phonebook[i] = NULL;
							}
						}

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

							Success = FALSE;
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	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
WriteConfig(STRPTR Name,struct Configuration *Config)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;

		/* 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(!OpenIFF(Handle,IFFF_WRITE))
			{
					/* Push outmost chunk onto stack. */

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

					if(!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(PopChunk(Handle))
								Success = FALSE;
							else
							{
								if(WriteConfigChunks(Handle,Config,NULL,NULL))
									Success = TRUE;
							}
						}
						else
							Success = FALSE;
					}

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

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

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

				CloseIFF(Handle);
			}

				/* Close the DOS handle itself. */

			Close(Handle -> iff_Stream);
		}

			/* And free the IFF handle. */

		FreeIFF(Handle);
	}

	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
ReadConfig(STRPTR Name,struct Configuration *Config)
{
	struct IFFHandle	*Handle;
	BYTE			 Success	= FALSE,
				 UseOld		= FALSE;
	struct ContextNode	*Chunk;
	UBYTE			 ConfigChunkType;

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

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunks(Handle,Stops,NUM_STOPS))
				{
					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

						if(Chunk -> cn_ID == ID_VERS)
						{
							struct TermInfo TermInfo;

							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;

									break;
								}
							}
							else
								break;
						}

						if(ConfigChunkType = IsConfigChunk(Chunk -> cn_ID))
						{
							if(ReadConfigChunk(Handle,Config,ConfigChunkType,Chunk -> cn_Size,NULL))
								Success = TRUE;
							else
							{
								Success = FALSE;

								break;
							}
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

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