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

#include "TermGlobal.h"

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

VOID
SetPrefToDefaults(struct Configuration *Config,UBYTE *PathBuffer)
{
	if(!PathBuffer)
		PathBuffer = "ENVARC:term";

	strcpy(Config -> DefaultStorage,PathBuffer);

	/* Serial Preferences. */

	Config -> BaudRate		= 2400;
	Config -> BitsPerChar		= 8;
	Config -> Parity		= PARITY_NONE;
	Config -> StopBits		= 1;
	Config -> Handshaking		= HANDSHAKING_XONXOFF;
	Config -> Duplex		= DUPLEX_FULL;
	Config -> HighSpeed		= FALSE;
	Config -> BreakLength		= 250000;
	Config -> UnitNumber		= 0;

	strcpy(Config -> SerialDevice,SERIALNAME);

	/* Modem Preferences. */

	Config -> RedialDelay		= 2;
	Config -> DialRetries		= 10;
	Config -> DialTimeout		= 60;
	Config -> ConnectAutoBaud	= FALSE;

	strcpy(Config -> ModemInit,	"AT\\r");
	strcpy(Config -> ModemExit,	"");
	strcpy(Config -> ModemHangup,	"~~~~~~~~+++~~~~~~ATH0\\r");
	strcpy(Config -> DialPrefix,	"~~ATX3DP");
	strcpy(Config -> NoCarrier,	"NO CARRIER");
	strcpy(Config -> Connect,	"CONNECT");
	strcpy(Config -> Voice,		"VOICE");
	strcpy(Config -> Ring,		"RING");
	strcpy(Config -> Busy,		"BUSY");

	/* Transfer Preferences. */

	strcpy(Config -> Protocol,"xprzmodem.library");

	/* Macro Preferences. */

	strcpy(LastMacros,PathBuffer);
	AddPart(LastMacros,"Macros.term",256);

	strcpy(Config -> MacroFile,LastMacros);

	/* Screen Preferences. */

	Config -> DisplayMode		= ModeID[0];
	Config -> MakeScreenPublic	= TRUE;

	/* Terminal Preferences. */

	Config -> CaptureFilter		= TRUE;
	Config -> DestructiveBackspace	= TRUE;
	Config -> AudibleBell		= TRUE;
	Config -> VisibleBell		= FALSE;
	Config -> EightyColumns		= FALSE;
	Config -> SendCR		= CR_ASCR;
	Config -> SendLF		= LF_ASLF;
	Config -> ColourMode		= COLOUR_AMIGA;
	Config -> Emulation		= EMULATION_ANSIVT100;
	Config -> Font			= FONT_TOPAZ;

	Config -> SwapBSDelete		= FALSE;
	Config -> StripBit8		= FALSE;

	Config -> RasterEnabled		= TRUE;

	Config -> EmulationName[0]	= 0;
}

	/* CreatePhoneList():
	 *
	 *	Turn the array of pointers to phonebook entries into
	 *	a linked standard Amiga List (gadtools needs this).
	 */

struct List *
CreatePhoneList()
{
	struct List	*PhoneList;
	struct Node	*PhoneNode;
	LONG		 i;

	if(Phonebook && NumPhoneEntries)
	{
		if(PhoneList = (struct List *)AllocVec(sizeof(struct List) + NumPhoneEntries * sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))
		{
			NewList(PhoneList);

			PhoneNode = (struct Node *)(PhoneList + 1);

			for(i = 0 ; i < NumPhoneEntries ; i++)
			{
				PhoneNode[i] . ln_Name	= Phonebook[i] -> Name;

				AddTail(PhoneList,&PhoneNode[i]);
			}

			return(PhoneList);
		}
	}
	else
	{
		if(PhoneList = (struct List *)AllocVec(sizeof(struct List),MEMF_PUBLIC|MEMF_CLEAR))
		{
			NewList(PhoneList);

			return(PhoneList);
		}
	}

	return(NULL);
}

	/* DeletePhoneList(struct List *PhoneList):
	 *
	 *	Delete the entries listed in the Amiga List
	 *	created by the routine above.
	 */

VOID
DeletePhoneList(struct List *PhoneList)
{
	if(PhoneList)
	{
		FreeVec(PhoneList);

		PhoneList = NULL;
	}
}

	/* Compare(struct PhoneEntry **A,struct PhoneEntry **B):
	 *
	 *	Comparison subroutine required by the QuickSort
	 *	call below.	 
	 */

STATIC LONG
Compare(struct PhoneEntry **A,struct PhoneEntry **B)
{
	return(Stricmp((*A) -> Name,(*B) -> Name));
}

	/* SortPhoneEntries():
	 *
	 *	Sorts the current phone list array in ascending order.
	 */

VOID
SortPhoneEntries()
{
	qsort(Phonebook,NumPhoneEntries,sizeof(struct PhoneEntry *),Compare);
}

	/* RemPhoneEntry(LONG Num):
	 *
	 *	Remove a given entry from the phone book.
	 */

VOID
RemPhoneEntry(LONG Num)
{
	struct PhoneEntry	*Entry;
	LONG			 i;

	Entry = Phonebook[Num];

	for(i = Num ; i < NumPhoneEntries ; i++)
		Phonebook[i] = Phonebook[i + 1];

	Phonebook[NumPhoneEntries--] = NULL;

	FreeVec(Entry);
}

	/* NewPhoneEntry():
	 *
	 *	Create a new phone book entry with default values and
	 *	add it to the array. Expand the phone book if necessary.
	 */

BYTE
NewPhoneEntry()
{
	struct PhoneEntry	**PrivatePhonebook;
	LONG			 PrivatePhoneSize;
	LONG			 i;

		/* The phone book is filled `to the brim', so let's expand
		 * it.
		 */

	if(NumPhoneEntries + 1 > PhoneSize)
	{
			/* Allocate another phone book. */

		if(PrivatePhonebook = CreatePhonebook(PhoneSize + 1,&PrivatePhoneSize,FALSE))
		{
				/* Copy the data. */

			if(Phonebook && PhoneSize)
			{
				for(i = 0 ; i < PhoneSize ; i++)
					PrivatePhonebook[i] = Phonebook[i];

					/* Remove the old phonebook. */

				DeletePhonebook(Phonebook,PhoneSize,FALSE);
			}

				/* Assign the new pointers. */

			Phonebook = PrivatePhonebook;
			PhoneSize = PrivatePhoneSize;
		}
		else
			return(FALSE);
	}

		/* Allocate another entry and add it to the phone book. */

	if(Phonebook[NumPhoneEntries] = (struct PhoneEntry *)AllocVec(sizeof(struct PhoneEntry),MEMF_PUBLIC|MEMF_CLEAR))
	{
		strcpy(Phonebook[NumPhoneEntries] -> Name,"-- Unused Entry --");

		CopyMem(&Config,&Phonebook[NumPhoneEntries] -> Config,sizeof(struct Configuration));

			/* These are the german default values. */

		Phonebook[NumPhoneEntries] -> PayPerUnit[0] = 23;
		Phonebook[NumPhoneEntries] -> PayPerUnit[1] = 23;

		Phonebook[NumPhoneEntries] -> SecPerUnit[0] =  6 * 60;
		Phonebook[NumPhoneEntries] -> SecPerUnit[1] = 12 * 60;

		Phonebook[NumPhoneEntries] -> TimeOfDay[0] =  48;
		Phonebook[NumPhoneEntries] -> TimeOfDay[1] = 108;

		NumPhoneEntries++;

		return(TRUE);
	}

	return(FALSE);
}

	/* CreatePhonebook(LONG Size,LONG *AllocSize,BYTE CreateEntries):
	 *
	 *	Create a new phone entry array (so-called phone book).
	 */

struct PhoneEntry **
CreatePhonebook(LONG Size,LONG *AllocSize,BYTE CreateEntries)
{
	struct PhoneEntry **PhoneEntry = NULL;

	if(Size)
	{
			/* Round the number of phone entries to a
			 * multiple of eight.
			 */

		*AllocSize = (((Size + 7) >> 3) << 3);

			/* Create the list of pointers. */

		if(PhoneEntry = (struct PhoneEntry **)AllocVec(*AllocSize * sizeof(struct PhoneEntry *),MEMF_PUBLIC|MEMF_CLEAR))
		{
				/* And create some entries if necessary. */

			if(CreateEntries)
			{
				LONG i;

				for(i = 0 ; i < Size ; i++)
				{
					if(!(PhoneEntry[i] = (struct PhoneEntry *)AllocVec(sizeof(struct PhoneEntry),MEMF_PUBLIC|MEMF_CLEAR)))
					{
						LONG j;

						for(j = 0 ; j < i ; j++)
							FreeVec(PhoneEntry[j]);

						FreeVec(PhoneEntry);

						return(NULL);
					}
				}
			}
		}
	}

	return(PhoneEntry);
}

	/* DeletePhonebook(struct PhoneEntry **PhoneBook,LONG Size,BYTE FreeEntries):
	 *
	 *	Deallocates a given phone book and its entries if necessary.
	 */

VOID
DeletePhonebook(struct PhoneEntry **PhoneBook,LONG Size,BYTE FreeEntries)
{
	if(FreeEntries)
	{
		LONG i;

		for(i = 0 ; i < Size ; i++)
		{
			if(PhoneBook[i])
				FreeVec(PhoneBook[i]);
		}
	}

	FreeVec(PhoneBook);
}

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

BYTE
SavePhonebook(UBYTE *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,'TERM',ID_CAT,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,'TERM',ID_FORM,IFFSIZE_UNKNOWN))
						{
							if(!PushChunk(Handle,0,'VERS',IFFSIZE_UNKNOWN))
							{
								struct TermInfo TermInfo;

								TermInfo . Version	= TermVersion;
								TermInfo . Revision	= 9;

								if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
								{
									if(PopChunk(Handle))
										Success = FALSE;
									else
									{
										if(!PushChunk(Handle,0,'DIAL',IFFSIZE_UNKNOWN))
										{
											if(WriteChunkBytes(Handle,&NumPhoneEntries,sizeof(LONG)) == sizeof(LONG))
											{
												if(PopChunk(Handle))
													Success = FALSE;
												else
												{
													if(PopChunk(Handle))
														Success = FALSE;
													else
													{
														LONG i;

														for(i = 0 ; i < NumPhoneEntries ; i++)
														{
															if(!PushChunk(Handle,'TERM',ID_FORM,IFFSIZE_UNKNOWN))
															{
																if(!PushChunk(Handle,0,'PREF',IFFSIZE_UNKNOWN))
																{
																	if(WriteChunkBytes(Handle,Phonebook[i],sizeof(struct PhoneEntry)) != sizeof(struct PhoneEntry))
																	{
																		Success = FALSE;

																		break;
																	}
																	else
																		Success = TRUE;

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

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

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

					CloseIFF(Handle);
				}

				Close(Handle -> iff_Stream);
			}

			FreeIFF(Handle);
		}

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

	return(Success);
}

	/* OldLoadPhonebook(UBYTE *Name):
	 *
	 *	Restore a phone book from a disk file (old version).
	 */

STATIC BYTE
OldLoadPhonebook(UBYTE *Name)
{
	struct PhoneEntry	**PrivatePhonebook;
	LONG			 PrivatePhoneSize;
	LONG			 Size,i;
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	struct StoredProperty	*Prop;
	struct TermInfo		*TermInfo;

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

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!PropChunks(Handle,&VersionProps[0],1))
				{
					if(!StopChunk(Handle,'TERM','DIAL'))
					{
						if(!ParseIFF(Handle,IFFPARSE_SCAN))
						{
							if(Prop = FindProp(Handle,'TERM','VERS'))
							{
								TermInfo = (struct TermInfo *)Prop -> sp_Data;

								if(TermInfo -> Version <= TermVersion && TermInfo -> Revision <= TermRevision && TermInfo -> Revision >= 6)
								{
									if(ReadChunkRecords(Handle,&Size,sizeof(LONG),1))
									{
										if(Size)
										{
											if(PrivatePhonebook = CreatePhonebook(Size,&PrivatePhoneSize,TRUE))
											{
												struct ContextNode	*Chunk;
												LONG			 ItemSize;

												Chunk = CurrentChunk(Handle);

												ItemSize = Chunk -> cn_Size / Size;

												for(i = 0 ; i < Size ; i++)
												{
													SetPrefToDefaults(&PrivatePhonebook[i] -> Config,NULL);

													if(!ReadChunkRecords(Handle,PrivatePhonebook[i],ItemSize,1))
													{
														if(i)
															Size = i - 1;
														else
															Size = 0;

														break;
													}
												}

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

													Phonebook = PrivatePhonebook;
													PhoneSize = PrivatePhoneSize;

													NumPhoneEntries = Size;

													Success = TRUE;
												}
												else
												{
													DeletePhonebook(PrivatePhonebook,PrivatePhoneSize,TRUE);
													Success = FALSE;
												}

												FreeSubList();
											}
										}
									}
								}
							}
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	return(Success);
}

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

BYTE
LoadPhonebook(UBYTE *Name)
{
	STATIC ULONG Stops[6] =
	{
		'TERM','VERS',
		'TERM','DIAL',
		'TERM','PREF'
	};

	struct PhoneEntry	**PrivatePhonebook;
	LONG			 PrivatePhoneSize = 0;
	LONG			 Size = 0,i;
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	struct ContextNode	*Chunk;
	BYTE			 UseOld = FALSE;

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

			if(!OpenIFF(Handle,IFFF_READ))
			{
				if(!StopChunks(Handle,&Stops[0],3))
				{
					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

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

							if(ReadChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if(TermInfo . Version > TermVersion || TermInfo . Revision > 9 || TermInfo . Revision < 6)
									break;

								if(TermInfo . Revision < 9)
								{
									UseOld = TRUE;

									break;
								}
							}
							else
								break;
						}

						if(Chunk -> cn_ID == 'DIAL')
						{
							if(ReadChunkBytes(Handle,&Size,sizeof(LONG)) == sizeof(LONG))
							{
								i = 0;

								if(!(PrivatePhonebook = CreatePhonebook(Size,&PrivatePhoneSize,TRUE)))
									break;
							}
							else
								break;
						}

						if(Chunk -> cn_ID == 'PREF')
						{
							if(Size && i < Size)
							{
								WORD LastSize = sizeof(struct PhoneEntry);

								if(Chunk -> cn_Size < LastSize)
									LastSize = Chunk -> cn_Size;

								SetPrefToDefaults(&PrivatePhonebook[i] -> Config,NULL);

								if(ReadChunkBytes(Handle,PrivatePhonebook[i],LastSize) == LastSize)
									i++;
								else
								{
									if(i)
										Size = i - 1;
									else
										Size = 0;

									break;
								}
							}
						}
					}

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

						Phonebook = PrivatePhonebook;
						PhoneSize = PrivatePhoneSize;

						NumPhoneEntries = Size;

						Success = TRUE;
					}
					else
					{
						if(PrivatePhoneSize)
						{
							DeletePhonebook(PrivatePhonebook,PrivatePhoneSize,TRUE);
							Success = FALSE;
						}
					}

					FreeSubList();
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}

		FreeIFF(Handle);
	}

	if(UseOld)
		Success = OldLoadPhonebook(Name);

	return(Success);
}
