/*
**	termDial.c
**
**	The dialing routine as called by the phonebook
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Panel gadget IDs. */

enum	{	GAD_CALLING=1,GAD_TIME,GAD_NOTE,
		GAD_SKIP,GAD_REMOVE,GAD_ONLINE,GAD_ABORT
	};

STATIC VOID __stdargs
PrintBox(struct LayoutHandle *Handle,LONG Box,LONG Line,STRPTR String,...)
{
	UBYTE	 LocalBuffer[256];
	va_list	 VarArgs;

	va_start(VarArgs,String);
	VSPrintf(LocalBuffer,String,VarArgs);
	va_end(VarArgs);

	LT_SetAttributes(Handle,Box,LABX_Index,Line,LABX_Text,LocalBuffer,TAG_DONE);
}

	/* BuildName(STRPTR Name):
	 *
	 *	Build a file name from a BBS name and the current date.
	 */

STATIC VOID __regargs
BuildName(STRPTR Name,STRPTR Date)
{
	if(Date[0])
	{
		WORD	NameLen = strlen(Name),
			DateLen = strlen(Date),
			Delta;

		if((Delta = NameLen + 1 + DateLen - 32) > 0)
			Name[NameLen - Delta] = 0;

		strcat(Name,"_");
		strcat(Name,Date);
	}
}

	/* OpenAutoCaptureFile(STRPTR SomeName):
	 *
	 *	Open a capture file.
	 */

STATIC VOID __regargs
OpenAutoCaptureFile(STRPTR SomeName)
{
	UBYTE		SharedBuffer[MAX_FILENAME_LENGTH],
			Name[50],
			Date[20],
			Time[20];
	struct DateTime	DateTime;

		/* Get the current time and date. */

	DateStamp(&DateTime . dat_Stamp);

		/* Prepare for date conversion. */

	DateTime . dat_Format	= FORMAT_DOS;
	DateTime . dat_Flags	= 0;
	DateTime . dat_StrDay	= NULL;
	DateTime . dat_StrDate	= Date;
	DateTime . dat_StrTime	= Time;

		/* Convert the date. */

	if(DateToStr(&DateTime))
	{
			/* Remember the BBS name. */

		strcpy(Name,SomeName);

			/* Append the creation date if necessary. */

		if(Config -> CaptureConfig -> AutoCaptureDate == AUTOCAPTURE_DATE_NAME)
			BuildName(Name,Date);

			/* Make it a reasonable name. */

		FixName(Name);

			/* Get the capture file path. */

		strcpy(SharedBuffer,Config -> CaptureConfig -> CapturePath);

			/* Try to build a valid file and path name. */

		if(AddPart(SharedBuffer,Name,MAX_FILENAME_LENGTH))
		{
				/* Is the capture file still open? */

			if(FileCapture)
			{
					/* Close the file. */

				BufferClose(FileCapture);

					/* Any data written? */

				if(!GetFileSize(CaptureName))
					DeleteFile(CaptureName);
				else
				{
					AddProtection(CaptureName,FIBF_EXECUTE);

					if(Config -> MiscConfig -> CreateIcons)
						AddIcon(CaptureName,FILETYPE_TEXT,TRUE);
				}
			}

				/* Try to append the new data. */

			if(FileCapture = BufferOpen(SharedBuffer,"a"))
			{
					/* Set the menu checkmark. */

				CheckItem(MEN_CAPTURE_TO_FILE,TRUE);

					/* Remember the current capture file name. */

				strcpy(CaptureName,SharedBuffer);

					/* Add the creation date if necessary. */

				if(Config -> CaptureConfig -> AutoCaptureDate == AUTOCAPTURE_DATE_INCLUDE)
				{
					UBYTE DateTimeBuffer[256];

					if(FormatStamp(&DateTime . dat_Stamp,NULL,NULL,DateTimeBuffer,FALSE))
						BPrintf(FileCapture,LocaleString(MSG_DIALPANEL_FILE_CREATED_TXT),DateTimeBuffer);
				}
			}
			else
				CheckItem(MEN_CAPTURE_TO_FILE,FALSE);

			ConOutputUpdate();
		}
	}
}

	/* Connect(struct PhoneNode *DialNode,STRPTR NumberBuffer):
	 *
	 *	Perform connect action(s).
	 */

STATIC VOID __regargs
Connect(struct PhoneNode *DialNode,STRPTR NumberBuffer)
{
	if(DialNode -> Entry)
	{
		UpdateConfig(DialNode -> Entry -> Config,Config);

		ConfigChanged = FALSE;

		MakeCall(DialNode -> Entry -> Header -> Name,NumberBuffer);

		SelectTime(DialNode -> Entry);

		ChosenEntry	= DialNode -> Entry;
		WhichUnit	= DT_FIRST_UNIT;
		CurrentPay	= 0;
		SendStartup	= TRUE;

		strcpy(Password,DialNode -> Entry -> Header -> Password);
		strcpy(UserName,DialNode -> Entry -> Header -> UserName);

		strcpy(CurrentBBSName,DialNode -> Entry -> Header -> Name);
		strcpy(CurrentBBSComment,DialNode -> Entry -> Header -> Comment);

		strcpy(CurrentBBSNumber,NumberBuffer);

		if(DialNode -> Entry -> Config && DialNode -> Entry -> Config -> ModemConfig)
		{
			OnlinePlus = DialNode -> Entry -> Config -> ModemConfig -> TimeToConnect;

			if(DialNode -> Entry -> Config -> ModemConfig -> ConnectLimit > 0 && DialNode -> Entry -> Config -> ModemConfig -> ConnectLimitMacro[0])
			{
				LimitCount = DialNode -> Entry -> Config -> ModemConfig -> ConnectLimit;

				strcpy(LimitMacro,DialNode -> Entry -> Config -> ModemConfig -> ConnectLimitMacro);
			}
			else
				LimitCount = -1;
		}
		else
		{
			OnlinePlus = Config -> ModemConfig -> TimeToConnect;

			if(Config -> ModemConfig -> ConnectLimit > 0 && Config -> ModemConfig -> ConnectLimitMacro[0])
			{
				LimitCount = Config -> ModemConfig -> ConnectLimit;

				strcpy(LimitMacro,Config -> ModemConfig -> ConnectLimitMacro);
			}
			else
				LimitCount = -1;
		}

		LogAction(LocaleString(MSG_DIALPANEL_CONNECTED_TO_1_TXT),DialNode -> Entry -> Header -> Name,NumberBuffer);
	}
	else
	{
		OnlinePlus = Config -> ModemConfig -> TimeToConnect;

		MakeCall("???",NumberBuffer);

		CurrentPay	= 0;
		ChosenEntry	= NULL;
		Password[0]	= 0;
		UserName[0]	= 0;
		SendStartup	= FALSE;

		CurrentBBSName[0]	= 0;
		CurrentBBSComment[0]	= 0;

		strcpy(CurrentBBSNumber,NumberBuffer);

		if(Config -> ModemConfig -> ConnectLimit > 0 && Config -> ModemConfig -> ConnectLimitMacro[0])
		{
			LimitCount = Config -> ModemConfig -> ConnectLimit;

			strcpy(LimitMacro,Config -> ModemConfig -> ConnectLimitMacro);
		}
		else
			LimitCount = -1;

		LogAction(LocaleString(MSG_DIALPANEL_CONNECTED_TO_2_TXT),NumberBuffer);
	}

		/* We are now online. */

	Online = TRUE;

		/* Open auto-capture file. */

	if(Config -> CaptureConfig -> ConnectAutoCapture && Config -> CaptureConfig -> CapturePath[0])
	{
		if(DialNode -> Entry)
			OpenAutoCaptureFile(DialNode -> Entry -> Header -> Name);
		else
			OpenAutoCaptureFile(LocaleString(MSG_DIALPANEL_CAPTURE_NAME_TXT));
	}

		/* Remove node from
		 * dialing list and
		 * perform system
		 * setup.
		 */

	if(DialNode -> Entry)
		RemoveDialNode(DialNode);

	Remove(&DialNode -> VanillaNode);

	FreeVecPooled(DialNode);

	if(PrivateConfig -> MiscConfig -> BackupConfig)
	{
		if(!BackupConfig)
		{
			if(BackupConfig = CreateConfiguration(TRUE))
				SaveConfig(PrivateConfig,BackupConfig);
		}
	}

		/* Make sure that the following
		 * setup/initialization will not
		 * touch the serial configuration.
		 */

	memcpy(PrivateConfig -> SerialConfig,Config -> SerialConfig,sizeof(struct SerialSettings));

	ConfigSetup();

		/* Reset the scanner. */

	FlowInit(TRUE);
}

	/* DialPanel():
	 *
	 *	This routine opens a small window in the middle of the
	 *	console window and walks down the list of numbers to
	 *	dial.
	 */

BYTE
DialPanel()
{
	struct LayoutHandle	*Handle;
	struct PhoneNode	*DialNode;
	BYTE			 Result = FALSE,
				 Record = FALSE;

	BlockWindows();

	ChosenEntry = NULL;

		/* We are dialing. */

	Status = STATUS_DIALING;

	if(Handle = LT_CreateHandleTags(Window -> WScreen,
		LH_LocaleHook,	&LocaleHook,
	TAG_DONE))
	{
		struct Window *Window;

		LT_New(Handle,
			LA_Type,	VERTICAL_KIND,
		TAG_DONE);
		{
			LT_New(Handle,
				LA_Type,	VERTICAL_KIND,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,	VERTICAL_KIND,
				TAG_DONE);
				{
					LT_New(Handle,
						LA_Type,		BOX_KIND,
						LA_ID,			GAD_CALLING,
						LA_Chars,		45,
						LA_Lines,		4,
						LABX_ReserveSpace,	TRUE,
						LABX_FirstLabel,	MSG_DIALPANEL_CALLING_TXT,
						LABX_LastLabel,		MSG_DIALPANEL_NEXT_TXT,
					TAG_DONE);

					LT_New(Handle,
						LA_Type,		BOX_KIND,
						LA_ID,			GAD_TIME,
						LA_Chars,		45,
						LA_Lines,		2,
						LABX_ReserveSpace,	TRUE,
						LABX_FirstLabel,	MSG_DIALPANEL_TIMEOUT_TXT,
						LABX_LastLabel,		MSG_DIALPANEL_ATTEMPT_TXT,
					TAG_DONE);

					LT_New(Handle,
						LA_Type,		BOX_KIND,
						LA_ID,			GAD_NOTE,
						LA_Chars,		45,
						LA_Lines,		1,
						LABX_ReserveSpace,	TRUE,
						LABX_FirstLabel,	MSG_DIALPANEL_MESSAGE_TXT,
						LABX_LastLabel,		MSG_DIALPANEL_MESSAGE_TXT,
					TAG_DONE);

					LT_EndGroup(Handle);
				}

				LT_New(Handle,
					LA_Type,	VERTICAL_KIND,
				TAG_DONE);
				{
					LT_New(Handle,
						LA_Type,		XBAR_KIND,
					TAG_DONE);

					LT_New(Handle,
						LA_Type,		CHECKBOX_KIND,
						LA_LabelID,		MSG_DIALPANEL_RECORD_ON_CONNECTION_TXT,
						LA_BYTE,		&Record,
					TAG_DONE);

					LT_EndGroup(Handle);
				}

				LT_EndGroup(Handle);
			}

			LT_New(Handle,
				LA_Type,VERTICAL_KIND,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,	XBAR_KIND,
					LAXB_FullSize,	TRUE,
				TAG_DONE);

				LT_EndGroup(Handle);
			}

			LT_New(Handle,LA_Type,HORIZONTAL_KIND,
				LAGR_Spread,	TRUE,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_DIALPANEL_SKIP_GAD,
					LA_ID,		GAD_SKIP,
					LABT_ExtraFat,	TRUE,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_GLOBAL_REMOVE_GAD,
					LA_ID,		GAD_REMOVE,
					LABT_ExtraFat,	TRUE,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_DIALPANEL_GO_TO_ONLINE_GAD,
					LA_ID,		GAD_ONLINE,
					LABT_ReturnKey,	TRUE,
					LABT_ExtraFat,	TRUE,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_GLOBAL_ABORT_GAD,
					LA_ID,		GAD_ABORT,
					LABT_ExtraFat,	TRUE,
				TAG_DONE);

				LT_EndGroup(Handle);
			}

			LT_EndGroup(Handle);
		}

		if(Window = LT_Layout(Handle,LocaleString(MSG_DIALPANEL_DIALING_TXT),NULL,0,0,IDCMP_CLOSEWINDOW,0,
			LAWN_HelpHook,		&GuideHook,
			WA_DepthGadget,		TRUE,
			WA_CloseGadget,		TRUE,
			WA_DragBar,		TRUE,
			WA_RMBTrap,		TRUE,
			WA_Activate,		TRUE,
		TAG_DONE))
		{
			struct IntuiMessage	*Message;
			BOOLEAN			 Done = FALSE;
			ULONG			 MsgClass,
						 MsgQualifier;
			UWORD			 MsgCode;
			struct Gadget		*MsgGadget;
			LONG			 MsgGadgetID;

			LONG			 RedialDelay = 0,DialTimeout,DialRetries,DialAttempt;
			BYTE			 Dialing,RunCount = 0,GotError = FALSE;

			UBYTE			 SomeBuffer[300],ExitString[80],
						 NumberBuffer[100],	*NextNumber	= NULL,
						 InitBuffer[80],	*NextInit	= NULL,
						 ExitBuffer[80],	*NextExit	= NULL,
						 PrefixBuffer[80],	*NextPrefix	= NULL;

			struct SerialSettings	 OriginalSerialConfig;
			BOOLEAN			 UseHangUp;

			LT_ShowWindow(Handle,TRUE);

				/* Remember the original serial settings, so we
				 * can return to them later.
				 */

			CopyMem(Config -> SerialConfig,&OriginalSerialConfig,sizeof(struct SerialSettings));

			GuideContext(CONTEXT_DIAL);

			ExitString[0] = 0;

				/* Make the current one the active one. */

			PushWindow(Window);

				/* Make a backup of the current configuration. */

			SaveConfig(Config,PrivateConfig);

				/* Don't echo serial output. */

			Quiet		= TRUE;

				/* Perform full sequence check. */

			FullCheck	= TRUE;

				/* Reset the scanner. */

			FlowInit(TRUE);

				/* Reset the number of dial attempts. */

			DialAttempt	= 0;

				/* Get the first dial list entry. */

			DialNode	= (struct PhoneNode *)DialList -> lh_Head;

				/* The big dialing loop, implemented as a goto -> mark
				 * loop rather than one of those classical while .. do
				 * loops.
				 */

Dial:			Dialing		= TRUE;

				/* Reset the sequence scanner, the user may have skipped
				 * the previous dial attempt causing the modem to return
				 * `NO CARRIER'. To prevent the dialer from skipping the
				 * next dial entry as well as the previous we have to
				 * flush any data pending on the serial line.
				 */

			HandleSerial();

			FlowInit(TRUE);

				/* Now for multiple phone numbers separated
				 * by `|' characters. If `NextNumber' happens
				 * to be zero, we will prepare to extract
				 * the first phone number from the list.
				 * In any other case we will try to obtain
				 * the next number.
				 */

			if(NextNumber)
			{
				NextNumber	= ExtractString(NextNumber,	NumberBuffer,TRUE);
				NextInit	= ExtractString(NextInit,	InitBuffer,FALSE);
				NextExit	= ExtractString(NextExit,	ExitBuffer,FALSE);
				NextPrefix	= ExtractString(NextPrefix,	PrefixBuffer,FALSE);
			}
			else
			{
				if(DialNode -> Entry)
				{
					NextNumber = ExtractString(DialNode -> Entry -> Header -> Number,NumberBuffer,TRUE);

					if(DialNode -> Entry -> Config -> ModemConfig)
					{
						NextInit	= ExtractString(DialNode -> Entry -> Config -> ModemConfig -> ModemInit,InitBuffer,FALSE);
						NextExit	= ExtractString(DialNode -> Entry -> Config -> ModemConfig -> ModemExit,ExitBuffer,FALSE);
						NextPrefix	= ExtractString(DialNode -> Entry -> Config -> ModemConfig -> DialPrefix,PrefixBuffer,FALSE);
					}
					else
					{
						NextInit	= ExtractString(Config -> ModemConfig -> ModemInit,InitBuffer,FALSE);
						NextExit	= ExtractString(Config -> ModemConfig -> ModemExit,ExitBuffer,FALSE);
						NextPrefix	= ExtractString(Config -> ModemConfig -> DialPrefix,PrefixBuffer,FALSE);
					}
				}
				else
				{
					NextNumber	= ExtractString(DialNode -> VanillaNode . ln_Name,NumberBuffer,TRUE);

					NextInit	= ExtractString(Config -> ModemConfig -> ModemInit,InitBuffer,FALSE);
					NextExit	= ExtractString(Config -> ModemConfig -> ModemExit,ExitBuffer,FALSE);
					NextPrefix	= ExtractString(Config -> ModemConfig -> DialPrefix,PrefixBuffer,FALSE);
				}
			}

				/* If DialNode -> Entry is nonzero it has
				 * a configuration attached.
				 */

			if(DialNode -> Entry)
			{
				if(DialNode -> Entry -> Config -> ModemConfig)
				{
					DialTimeout	= DialNode -> Entry -> Config -> ModemConfig -> DialTimeout;
					DialRetries	= DialNode -> Entry -> Config -> ModemConfig -> DialRetries;
				}
				else
				{
					DialTimeout	= Config -> ModemConfig -> DialTimeout;
					DialRetries	= Config -> ModemConfig -> DialRetries;
				}

					/* Send the modem exit string before we
					 * will need to reconfigure the serial
					 * device driver.
					 */

				if(ExitString[0])
				{
					PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_EXIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(ExitString);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}

					/* We will need to change the serial parameters
					 * in order to establish a connection.
					 */

				if(DialNode -> Entry -> Config -> SerialConfig)
				{
					if(ReconfigureSerial(Window,DialNode -> Entry -> Config -> SerialConfig) == RECONFIGURE_FAILURE)
						goto Quit;
				}
				else
				{
					if(ReconfigureSerial(Window,&OriginalSerialConfig) == RECONFIGURE_FAILURE)
						goto Quit;
				}

					/* Send the modem init string. */

				if(InitBuffer[0] && !Done)
				{
					PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_INIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(InitBuffer);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}

					/* Remember the new exit string. */

				strcpy(ExitString,ExitBuffer);

				PrintBox(Handle,GAD_CALLING,0,DialNode -> Entry -> Header -> Name);

				if(DialNode -> Entry -> Header -> Comment[0])
					PrintBox(Handle,GAD_CALLING,1,DialNode -> Entry -> Header -> Comment);
				else
					PrintBox(Handle,GAD_CALLING,1,"-");

				Say(LocaleString(MSG_DIALPANEL_NOW_CALLING_TXT),DialNode -> Entry -> Header -> Name);

				strcpy(SomeBuffer,PrefixBuffer);

				PrintBox(Handle,GAD_CALLING,2,NumberBuffer);

				strcat(SomeBuffer,NumberBuffer);
			}
			else
			{
				DialTimeout	= Config -> ModemConfig -> DialTimeout;
				DialRetries	= Config -> ModemConfig -> DialRetries;

					/* Send the modem exit string. */

				if(ExitString[0])
				{
					PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_EXIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(ExitBuffer);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}

					/* Remember the new exit string. */

				strcpy(ExitString,ExitBuffer);

				PrintBox(Handle,GAD_CALLING,0,LocaleString(MSG_GLOBAL_UNKNOWN_TXT));

				PrintBox(Handle,GAD_CALLING,1,"-");

				Say(LocaleString(MSG_DIALPANEL_NOW_CALLING_TXT),NumberBuffer);

				strcpy(SomeBuffer,PrefixBuffer);

				PrintBox(Handle,GAD_CALLING,2,NumberBuffer);

				strcat(SomeBuffer,NumberBuffer);

					/* Send the modem init string. */

				if(InitBuffer[0])
				{
					PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_INIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(InitBuffer);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}
			}

			if(NextNumber)
			{
				if(DialNode -> Entry)
					PrintBox(Handle,GAD_CALLING,3,DialNode -> Entry -> Header -> Name);
				else
					PrintBox(Handle,GAD_CALLING,3,DialNode -> VanillaNode . ln_Name);
			}
			else
			{
				if(DialNode -> VanillaNode . ln_Succ -> ln_Succ)
				{
					if(DialNode -> Entry)
						PrintBox(Handle,GAD_CALLING,3,((struct PhoneNode *)DialNode -> VanillaNode . ln_Succ) -> Entry -> Header -> Name);
					else
						PrintBox(Handle,GAD_CALLING,3,DialNode -> VanillaNode . ln_Succ -> ln_Name);
				}
				else
					PrintBox(Handle,GAD_CALLING,3,"-");
			}

			if(DialNode -> Entry)
			{
				if(DialNode -> Entry -> Config -> ModemConfig)
					strcat(SomeBuffer,DialNode -> Entry -> Config -> ModemConfig -> DialSuffix);
				else
					strcat(SomeBuffer,Config -> ModemConfig -> DialSuffix);
			}
			else
				strcat(SomeBuffer,Config -> ModemConfig -> DialSuffix);

			PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_DIALING_TXT));

				/* Dial the number. */

			SerialCommand(SomeBuffer);

				/* Reset the signal. */

			SetSignal(NULL,SIG_SKIP | SIG_BREAK);

			while(!Done)
			{
				if(CheckSignal(SIG_BREAK))
				{
					PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ABORTING_TXT));

					if(DialNode -> Entry && DialNode -> Entry -> Config && DialNode -> Entry -> Config -> ModemConfig)
						UseHangUp = DialNode -> Entry -> Config -> ModemConfig -> AbortHangsUp;
					else
						UseHangUp = Config -> ModemConfig -> AbortHangsUp;

					if(UseHangUp)
						HangUp();
					else
					{
						SerWrite("\r",1);
						WaitTime(1,0);
					}

						/* Ignore the response of the modem. */

					HandleSerial();

					FlowInit(TRUE);

					break;
				}

				if(Dialing)
				{
					PrintBox(Handle,GAD_TIME,0,"%2ld:%02ld",DialTimeout / 60,DialTimeout % 60);

					if(DialRetries < 0)
						PrintBox(Handle,GAD_TIME,1,LocaleString(MSG_DIAL_RETRIES_UNLIMITED_TXT));
					else
						PrintBox(Handle,GAD_TIME,1,LocaleString(MSG_DIALPANEL_ATTEMPT_OF_TXT),DialAttempt + 1,DialRetries);
				}
				else
					PrintBox(Handle,GAD_TIME,0,"%2ld:%02ld",RedialDelay / 60,RedialDelay % 60);

				WaitTime(0,MILLION / 2);

					/* The following commands are executed each second */

				if((RunCount++) && !Done)
				{
					RunCount = 0;

						/* Are we dialing or waiting? */

					if(Dialing)
					{
							/* No chance, the dial timeout
							 * has elapsed and no connection
							 * was made.
							 */

						if(!(--DialTimeout))
						{
							PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_DIAL_ATTEMPT_TIMEOUT_TXT));

Skip1:
							if(DialNode -> Entry && DialNode -> Entry -> Config && DialNode -> Entry -> Config -> ModemConfig)
								UseHangUp = DialNode -> Entry -> Config -> ModemConfig -> AbortHangsUp;
							else
								UseHangUp = Config -> ModemConfig -> AbortHangsUp;

							if(UseHangUp)
								HangUp();
							else
							{
								SerWrite("\r",1);
								WaitTime(1,0);
							}

								/* Ignore the response of the modem. */

							HandleSerial();

							FlowInit(TRUE);

								/* Did we dial all the numbers available? */

							if(NextNumber)
								goto Dial;

								/* Is this one the last entry? */

							if(DialNode -> VanillaNode . ln_Succ -> ln_Succ)
							{
									/* Proceed to the next entry. */

								DialNode = (struct PhoneNode *)DialNode -> VanillaNode . ln_Succ;

								goto Dial;
							}
							else
							{
									/* Is this one the last dial
									 * attempt to be made?
									 */

								if(++DialAttempt >= DialRetries && DialRetries >= 0)
								{
									PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

									WakeUp(Window,SOUND_BELL);

									WaitTime(2,0);

									Say(LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

									Done = TRUE;
								}
								else
								{
										/* Get the first list entry. */

									DialNode = (struct PhoneNode *)DialList -> lh_Head;

										/* Get the redial delay. */

									if(DialNode -> Entry)
									{
										if(DialNode -> Entry -> Config -> ModemConfig)
											RedialDelay = 10 * DialNode -> Entry -> Config -> ModemConfig -> RedialDelay;
										else
											RedialDelay = 10 * Config -> ModemConfig -> RedialDelay;
									}
									else
										RedialDelay = 10 * Config -> ModemConfig -> RedialDelay;

										/* No redial delay? Restart dialing... */

									if(!RedialDelay)
									{
										WaitTime(1,0);

										goto Dial;
									}
									else
									{
											/* Go into redial delay. */

										PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_REDIAL_DELAY_TXT));

										Dialing = FALSE;

										Say(LocaleString(MSG_DIALPANEL_WAITING_TXT));
									}
								}
							}
						}
					}
					else
					{
						if(!(--RedialDelay))
						{
								/* Get the first list entry. */

Skip2:							DialNode = (struct PhoneNode *)DialList -> lh_Head;

								/* We are once again dialing. */

							goto Dial;
						}
					}
				}

					/* Handle serial data flow. */

				HandleSerial();

					/* Something has changed in the flow
					 * info structure.
					 */

				if(FlowInfo . Changed)
				{
						/* Current number is busy. */

					if(FlowInfo . Busy || (FlowInfo . NoCarrier && Config -> ModemConfig -> NoCarrierIsBusy))
					{
						FlowInit(TRUE);

						FlowInfo . Busy		= FALSE;
						FlowInfo . NoCarrier	= FALSE;
						FlowInfo . Changed	= FALSE;

						if(Dialing)
						{
							PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_LINE_IS_BUSY_TXT));

							Say(LocaleString(MSG_DIALPANEL_LINE_IS_BUSY_TXT));

							WaitTime(1,0);

							goto Skip1;
						}
					}

						/* Line does not feature a dialtone. */

					if(FlowInfo . NoDialTone)
					{
						FlowInit(TRUE);

						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_NO_DIALTONE_TXT));

						WakeUp(Window,SOUND_BELL);

						WaitTime(2,0);

						Say(LocaleString(MSG_DIALPANEL_NO_DIALTONE_TXT));

						Done = TRUE;
					}

						/* Somebody tries to call us. */

					if(FlowInfo . Ring && !Done)
					{
						FlowInit(TRUE);

						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));

						WakeUp(Window,SOUND_RING);

						WaitTime(2,0);

						Say(LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));

						Done = TRUE;
					}

						/* Somebody's talking. */

					if(FlowInfo . Voice && !Done)
					{
						FlowInit(TRUE);

						PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_INCOMING_VOICE_CALL_TXT));

						WakeUp(Window,SOUND_VOICE);

						WaitTime(2,0);

						Say(LocaleString(MSG_DIALPANEL_INCOMING_VOICE_CALL_TXT));

						Done = TRUE;
					}

						/* We got a connect. */

					if(FlowInfo . Connect && !Done)
					{
						FlowInfo . Connect = FALSE;
						FlowInfo . Changed = FALSE;

						Connect(DialNode,NumberBuffer);

						Done = TRUE;

							/* Wake the user up. */

						if(BaudBuffer[0])
						{
							PrintBox(Handle,GAD_NOTE,0,"CONNECT %s",BaudBuffer);

							WakeUp(Window,SOUND_CONNECT);

							WaitTime(2,0);

								/* Install new baud rate if desired. */

							if(Config -> ModemConfig -> ConnectAutoBaud && DTERate > 110)
							{
								Config -> SerialConfig -> BaudRate = DTERate;

								ReconfigureSerial(Window,NULL);
							}
						}
						else
						{
							PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_CONNECTION_ESTABLISHED_TXT));

							WakeUp(Window,SOUND_CONNECT);
						}

						Say(LocaleString(MSG_DIALPANEL_CONNECTION_ESTABLISHED_TXT));
					}
				}

					/* Look for the hotkey. */

				if(CheckSignal(SIG_SKIP))
				{
					LT_PressButton(Handle,GAD_SKIP);

						/* Are we dialing or waiting? */

					if(Dialing)
					{
						DialTimeout = 0;

						goto Skip1;
					}
					else
					{
						RedialDelay = 0;

						goto Skip2;
					}
				}

					/* Pick up the window input. */

				while(!Done && (Message = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort)))
				{
					MsgClass	= Message -> Class;
					MsgQualifier	= Message -> Qualifier;
					MsgCode		= Message -> Code;
					MsgGadget	= (struct Gadget *)Message -> IAddress;

					GT_ReplyIMsg(Message);

					LT_HandleInput(Handle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);

					if(MsgClass == IDCMP_GADGETUP)
						MsgGadgetID = MsgGadget -> GadgetID;

					if(MsgClass == IDCMP_RAWKEY)
					{
						if(LT_GetCode(MsgQualifier,MsgClass,MsgCode,MsgGadget) == ' ')
						{
							MsgClass	= IDCMP_GADGETUP;
							MsgCode		= 0;
							MsgGadgetID	= GAD_SKIP;

							LT_PressButton(Handle,GAD_SKIP);
						}
					}

						/* Close the window, hang up the line. */

					if(MsgClass == IDCMP_CLOSEWINDOW)
					{
						MsgClass	= IDCMP_GADGETUP;
						MsgGadgetID	= GAD_ABORT;

						Result = TRUE;
					}

					if(MsgClass == IDCMP_GADGETUP)
					{
						switch(MsgGadgetID)
						{
									/* Don't proceed to the next number in the buffer! */

							case GAD_REMOVE:

								NextNumber = NULL;

								if(Dialing)
								{
									struct PhoneNode *NextNode = NULL;

										/* Is there another entry in the list? */

									if(DialNode -> VanillaNode . ln_Succ -> ln_Succ)
										NextNode = (struct PhoneNode *)DialNode -> VanillaNode . ln_Succ;
									else
									{
											/* No, there isn't; do we have a list with
											 * at least two entries in it?
											 */

										if(DialList -> lh_Head -> ln_Succ -> ln_Succ)
										{
												/* There is just a single entry
												 * available, check for dial retry
												 * limit.
												 */

											if(++DialAttempt >= DialRetries && DialRetries >= 0)
											{
												PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

												WakeUp(Window,SOUND_BELL);

												WaitTime(2,0);

												Say(LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

												Done = TRUE;
											}
											else
											{
													/* Grab first list entry and continue. */

												NextNode = (struct PhoneNode *)DialList -> lh_Head;
											}
										}
										else
										{
											Done = TRUE;

											PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_DIALING_LIST_IS_EMPTY_TXT));

											WaitTime(2,0);
										}
									}

									DialTimeout = 0;

									if(DialNode -> Entry && DialNode -> Entry -> Config && DialNode -> Entry -> Config -> ModemConfig)
										UseHangUp = DialNode -> Entry -> Config -> ModemConfig -> AbortHangsUp;
									else
										UseHangUp = Config -> ModemConfig -> AbortHangsUp;

									if(UseHangUp)
										HangUp();
									else
									{
										SerWrite("\r",1);
										WaitTime(1,0);
									}

										/* Ignore the response of the modem. */

									HandleSerial();

									FlowInit(TRUE);

										/* Remove dial entry from list. */

									if(DialNode -> Entry)
										RemoveDialNode(DialNode);

									Remove(&DialNode -> VanillaNode);

									FreeVecPooled(DialNode);

										/* Is there an entry to proceed with? */

									if(NextNode)
									{
										DialNode = NextNode;

										goto Dial;
									}
								}
								else
								{
									struct PhoneNode *LastNode;

										/* We are to leave the redial delay loop,
										 * are there at least two entries in
										 * the list?
										 */

									if(!DialList -> lh_Head -> ln_Succ -> ln_Succ)
									{
											/* No, there is just a single entry in
											 * the list.
											 */

										Done = TRUE;

										PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_DIALING_LIST_IS_EMPTY_TXT));

										if(DialNode -> Entry && DialNode -> Entry -> Config && DialNode -> Entry -> Config -> ModemConfig)
											UseHangUp = DialNode -> Entry -> Config -> ModemConfig -> AbortHangsUp;
										else
											UseHangUp = Config -> ModemConfig -> AbortHangsUp;

										if(UseHangUp)
											HangUp();
										else
										{
											SerWrite("\r",1);
											WaitTime(2,0);
										}

											/* Ignore the response of the modem. */

										HandleSerial();

										FlowInit(TRUE);
									}

										/* Remove last dial entry from list. */

									LastNode = (struct PhoneNode *)DialList -> lh_TailPred;

									if(LastNode -> Entry)
										RemoveDialNode(LastNode);

									Remove(&LastNode -> VanillaNode);

									FreeVecPooled(LastNode);

										/* Get back to first list entry. */

									if(!Done)
									{
										RedialDelay = 0;

										goto Skip2;
									}
								}

								break;

							case GAD_SKIP:

								if(Dialing)
								{
									DialTimeout = 0;

									goto Skip1;
								}
								else
								{
									RedialDelay = 0;

									goto Skip2;
								}

							case GAD_ONLINE:

								Connect(DialNode,NumberBuffer);

								Done = TRUE;

								break;

								/* Abort the dialing process. */

							case GAD_ABORT:

								Done = TRUE;

								PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ABORTING_TXT));

								if(DialNode -> Entry && DialNode -> Entry -> Config && DialNode -> Entry -> Config -> ModemConfig)
									UseHangUp = DialNode -> Entry -> Config -> ModemConfig -> AbortHangsUp;
								else
									UseHangUp = Config -> ModemConfig -> AbortHangsUp;

								if(UseHangUp)
									HangUp();
								else
								{
									SerWrite("\r",1);
									WaitTime(1,0);
								}

									/* Ignore the response of the modem. */

								HandleSerial();

								FlowInit(TRUE);

								break;
						}
					}
				}
			}

				/* Are we online or not? */

Quit:			if(!Online)
			{
					/* Is the serial setup different? */

				if(memcmp(Config -> SerialConfig,PrivateConfig -> SerialConfig,sizeof(struct SerialSettings)))
				{
						/* Swap the serial data. */

					swmem(Config -> SerialConfig,PrivateConfig -> SerialConfig,sizeof(struct SerialSettings));

						/* Set up the old serial configuration. */

					if(ReconfigureSerial(Window,NULL) != RECONFIGURE_FAILURE)
					{
						if(ExitString[0])
						{
							PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_EXIT_COMMAND_TXT));

							FlowInit(TRUE);

							SerialCommand(ExitBuffer);

							WaitTime(1,0);

							HandleSerial();

							if(FlowInfo . Changed && FlowInfo . Error)
							{
								PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

								GotError = TRUE;
							}
						}

						if(Config -> ModemConfig -> ModemInit[0] && !GotError)
						{
							PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_INIT_COMMAND_TXT));

							FlowInit(TRUE);

							SerialCommand(Config -> ModemConfig -> ModemInit);

							WaitTime(1,0);

							HandleSerial();

							if(FlowInfo . Changed && FlowInfo . Error)
							{
								PrintBox(Handle,GAD_NOTE,0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

								GotError = TRUE;
							}
						}
					}
				}
			}

			if(GotError)
			{
				WORD i;

				for(i = GAD_SKIP ; i <= GAD_REMOVE ; i++)
					LT_SetAttributes(Handle,i,GA_Disabled,TRUE,TAG_DONE);

				WakeUp(Window,SOUND_BELL);

				Done = FALSE;

				do
				{
					if(Wait(PORTMASK(Window -> UserPort) | SIG_BREAK) & SIG_BREAK)
						break;

					while(Message = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort))
					{
						MsgClass	= Message -> Class;
						MsgQualifier	= Message -> Qualifier;
						MsgCode		= Message -> Code;
						MsgGadget	= (struct Gadget *)Message -> IAddress;

						GT_ReplyIMsg(Message);

						LT_HandleInput(Handle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);

						if(MsgClass == IDCMP_CLOSEWINDOW || MsgClass == IDCMP_GADGETUP)
							Done = TRUE;
					}
				}
				while(!Done);
			}

			PopWindow();
		}

		LT_DeleteHandle(Handle);
	}

	ReleaseWindows();

			/* Reset the scanner. */

	FullCheck = FALSE;

	FlowInit(TRUE);

		/* We are done now, restart echoing serial */

	Quiet = FALSE;

		/* Reset the display if necessary. */

	if(ResetDisplay)
	{
		if(!DisplayReset())
			return(FALSE);
	}

	if(Online)
	{
		SetDialMenu(FALSE);

			/* Send the startup macro if necessary. */

		if(SendStartup)
		{
			if(Config -> CommandConfig -> LoginMacro[0])
				SerialCommand(Config -> CommandConfig -> LoginMacro);

			if(Config -> CommandConfig -> StartupMacro[0])
				SerialCommand(Config -> CommandConfig -> StartupMacro);

			SendStartup = FALSE;
		}

			/* Take care of the recording feature. */

		if(Record)
		{
			if(CreateRecord(CurrentBBSName[0] ? CurrentBBSName : CurrentBBSNumber))
			{
				RememberResetOutput();
				RememberResetInput();

				RememberOutput = TRUE;

				Recording = TRUE;
				RecordingLine = FALSE;

				OnItem(MEN_RECORD_LINE);
			
				CheckItem(MEN_RECORD,TRUE);
				CheckItem(MEN_RECORD_LINE,FALSE);
			}
		}

		Forbid();

		if(DialMsg)
		{
			DialMsg -> rm_Result1 = RC_OK;
			DialMsg -> rm_Result2 = 0;

			ReplyMsg(DialMsg);

			DialMsg = NULL;
		}

		Permit();
	}
	else
	{
		Forbid();

		if(DialMsg)
		{
			DialMsg -> rm_Result1 = RC_WARN;
			DialMsg -> rm_Result2 = 0;

			ReplyMsg(DialMsg);

			DialMsg = NULL;
		}

		Permit();
	}

	return(Result);
}
