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

#include "termGlobal.h"

	/* Panel gadget IDs. */

enum	{	GAD_SKIP,GAD_REMOVE,GAD_ONLINE,GAD_ABORT,
		GADGET_COUNT };

	/* Panel box IDs. */

enum	{	BOX_CALL_COMMENT_NUMBER_NEXT,BOX_TIME_TRY,BOX_MESSAGE,
		BOX_COUNT };

	/* CreateAllGadgets():
	 *
	 *	Create all gadgets required by the dial panel.
	 */

STATIC struct Gadget *
CreateAllGadgets(struct TextBox **BoxArray,struct TextBox **BoxList,struct Gadget **GadgetArray,struct Gadget **GadgetList)
{
	struct Gadget		*Gadget;
	struct NewGadget	 NewGadget;
	UWORD			 Counter = 0,BoxCounter = 0;
	struct TextBox		*Box;

	memset(&NewGadget,0,sizeof(struct NewGadget));

	SZ_SizeSetup(Window -> WScreen,&UserFont,TRUE);

	if(Gadget = CreateContext(GadgetList))
	{
		LONG ButtonWidth,LeftEdge;

		LeftEdge = SZ_LeftOffsetDelta(MSG_DIALPANEL_CALLING_TXT,MSG_DIALPANEL_MESSAGE_TXT);

		SZ_AddLeftOffset(LeftEdge);

		SZ_ResetMaxWidth();

		SZ_UpdateMaxWidth(BUTTON_KIND,LocaleString(MSG_DIALPANEL_SKIP_GAD),0,NULL);
		SZ_UpdateMaxWidth(BUTTON_KIND,LocaleString(MSG_GLOBAL_REMOVE_GAD),0,NULL);
		SZ_UpdateMaxWidth(BUTTON_KIND,LocaleString(MSG_DIALPANEL_GO_TO_ONLINE_GAD),0,NULL);
		SZ_UpdateMaxWidth(BUTTON_KIND,LocaleString(MSG_GLOBAL_ABORT_GAD),0,NULL);

		ButtonWidth = SZ_ResetMaxWidth();

		if(ButtonWidth * 4 + 3 * InterWidth > SZ_BoxWidth(45) + LeftEdge)
			SZ_SetWidth(ButtonWidth * 4 + 3 * InterWidth - LeftEdge);
		else
			SZ_SetWidth(SZ_BoxWidth(45));

		BoxArray[BoxCounter++] = Box = SZ_CreateTextBox(BoxList,
			SZ_Chars,	45,
			SZ_Lines,	4,
			SZ_AutoWidth,	TRUE,
		TAG_DONE);

		SZ_SetBoxTitles(Box,LocaleString(MSG_DIALPANEL_CALLING_TXT),LocaleString(MSG_DIALPANEL_COMMENT_TXT),LocaleString(MSG_DIALPANEL_NUMBER_TXT),LocaleString(MSG_DIALPANEL_NEXT_TXT),NULL);

		BoxArray[BoxCounter++] = Box = SZ_CreateTextBox(BoxList,
			SZ_Chars,	45,
			SZ_Lines,	2,
			SZ_AutoWidth,	TRUE,
		TAG_DONE);

		SZ_SetBoxTitles(Box,LocaleString(MSG_DIALPANEL_TIMEOUT_TXT),LocaleString(MSG_DIALPANEL_ATTEMPT_TXT),NULL);

		BoxArray[BoxCounter] = Box = SZ_CreateTextBox(BoxList,
			SZ_Chars,	45,
			SZ_Lines,	1,
			SZ_AutoWidth,	TRUE,
		TAG_DONE);

		SZ_SetBoxTitles(Box,LocaleString(MSG_DIALPANEL_MESSAGE_TXT),NULL);

		if(Box)
		{
			NewGadget . ng_GadgetText	= LocaleString(MSG_DIALPANEL_SKIP_GAD);
			NewGadget . ng_GadgetID		= Counter;

			SZ_SetWidth(ButtonWidth);

			GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
				SZ_Adjust,	TRUE,
				SZ_AutoWidth,	TRUE,
				SZ_AlignExtra,	TRUE,
				SZ_AlignBottom,	TRUE,
				SZ_GroupCount,	4,
			TAG_DONE);

			NewGadget . ng_GadgetText	= LocaleString(MSG_GLOBAL_REMOVE_GAD);
			NewGadget . ng_GadgetID		= Counter;

			GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
				SZ_Adjust,	TRUE,
				SZ_AutoWidth,	TRUE,
				SZ_GroupNext,	TRUE,
			TAG_DONE);

			NewGadget . ng_GadgetText	= LocaleString(MSG_DIALPANEL_GO_TO_ONLINE_GAD);
			NewGadget . ng_GadgetID		= Counter;

			GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
				SZ_Adjust,	TRUE,
				SZ_AutoWidth,	TRUE,
				SZ_GroupNext,	TRUE,
			TAG_DONE);

			NewGadget . ng_GadgetText	= LocaleString(MSG_GLOBAL_ABORT_GAD);
			NewGadget . ng_GadgetID		= Counter;

			GadgetArray[Counter] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
				SZ_Adjust,	TRUE,
				SZ_AutoWidth,	TRUE,
				SZ_GroupNext,	TRUE,
			TAG_DONE);
		}
		else
			return(NULL);
	}

	return(Gadget);
}

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

	/* FixName(STRPTR Name):
	 *
	 *	Build a correct AmigaDOS filename from a BBS name.
	 */

STATIC VOID __regargs
FixName(STRPTR Name)
{
	WORD	NameLen	= strlen(Name),
		i;

		/* Replace special characters. */

	for(i = 0 ; i < NameLen ; i++)
	{
		switch(Name[i])
		{
			case ' ':

				Name[i] = '_';
				break;

			case ':':

				Name[i] = '.';
				break;

			case '/':

				Name[i] = '\\';
				break;

			case '\"':

				Name[i] = '\'';
				break;
		}
	}

		/* Truncate the name. */

	if(NameLen > 31)
		Name[31] = 0;
}

	/* 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)
					BPrintf(FileCapture,LocaleString(MSG_DIALPANEL_FILE_CREATED_TXT),Time,Date);
			}
			else
				CheckItem(MEN_CAPTURE_TO_FILE,FALSE);

			ConOutputUpdate();
		}
	}
}

	/* 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 Gadget		*GadgetList = NULL;
	struct Gadget		*GadgetArray[GADGET_COUNT];
	struct TextBox		*BoxList = NULL;
	struct TextBox		*BoxArray[BOX_COUNT];
	struct Window		*PanelWindow;
	struct PhoneNode	*DialNode;
	BYTE			 Result = FALSE;

	ChosenEntry = NULL;

		/* We are dialing. */

	Status = STATUS_DIALING;

		/* Create the gadgets. */

	if(CreateAllGadgets(BoxArray,&BoxList,GadgetArray,&GadgetList))
	{
			/* At last, open the window. */

		if(PanelWindow = OpenWindowTags(NULL,
			WA_Left,	GetScreenLeft(Window) + (GetScreenWidth(Window) - SZ_GetWindowWidth()) / 2,
			WA_Top,		GetScreenTop(Window) + (GetScreenHeight(Window) - SZ_GetWindowHeight())	/ 2,
			WA_Width,	SZ_GetWindowWidth(),
			WA_Height,	SZ_GetWindowHeight(),

			WA_Activate,	TRUE,
			WA_DragBar,	TRUE,
			WA_DepthGadget,	TRUE,
			WA_CloseGadget,	TRUE,
			WA_RMBTrap,	TRUE,
			WA_CustomScreen,Window -> WScreen,

			WA_IDCMP,	IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY | BUTTONIDCMP,

			WA_Title,	LocaleString(MSG_DIALPANEL_DIALING_TXT),
		TAG_DONE))
		{
			struct IntuiMessage	*Massage;
			ULONG			 IClass,Code;
			struct Gadget		*Gadget;
			LONG			 RedialDelay = 0,DialTimeout,DialRetries,DialAttempt;
			BYTE			 Dialing,Terminated = FALSE,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;

			GuideContext(CONTEXT_DIAL);

			ExitString[0] = 0;

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

			PushWindow(PanelWindow);

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

			SaveConfig(Config,PrivateConfig);

				/* Add the gadgets and refresh them. */

			AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
			RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
			GT_RefreshWindow(PanelWindow,NULL);

			SZ_DrawBoxes(PanelWindow -> RPort,BoxList);

				/* 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])
				{
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_EXIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(ExitString);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],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(PanelWindow,DialNode -> Entry -> Config -> SerialConfig) == RECONFIGURE_FAILURE)
						goto Quit;
				}

					/* Send the modem init string. */

				if(InitBuffer[0] && !Terminated)
				{
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_INIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(InitBuffer);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}

					/* Remember the new exit string. */

				strcpy(ExitString,ExitBuffer);

				SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],0,DialNode -> Entry -> Header -> Name);

				if(DialNode -> Entry -> Header -> Comment[0])
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],1,DialNode -> Entry -> Header -> Comment);
				else
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],1,"-");

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

				strcpy(SomeBuffer,PrefixBuffer);

				SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],2,NumberBuffer);

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

					/* Send the modem exit string. */

				if(ExitString[0])
				{
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_EXIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(ExitBuffer);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}

					/* Remember the new exit string. */

				strcpy(ExitString,ExitBuffer);

				SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],0,LocaleString(MSG_GLOBAL_UNKNOWN_TXT));

				SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],1,"-");

				Say(LocaleString(MSG_DIALPANEL_NOW_CALLING_TXT),NumberBuffer);

				strcpy(SomeBuffer,PrefixBuffer);

				SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],2,NumberBuffer);

				strcat(SomeBuffer,NumberBuffer);

					/* Send the modem init string. */

				if(InitBuffer[0])
				{
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_INIT_COMMAND_TXT));

					FlowInit(TRUE);

					SerialCommand(InitBuffer);

					WaitTime(1,0);

					HandleSerial();

					if(FlowInfo . Changed && FlowInfo . Error)
					{
						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

						GotError = TRUE;

						goto Quit;
					}
				}
			}

			if(NextNumber)
			{
				if(DialNode -> Entry)
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],3,DialNode -> Entry -> Header -> Name);
				else
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],3,DialNode -> VanillaNode . ln_Name);
			}
			else
			{
				if(DialNode -> VanillaNode . ln_Succ -> ln_Succ)
				{
					if(DialNode -> Entry)
						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],3,((struct PhoneNode *)DialNode -> VanillaNode . ln_Succ) -> Entry -> Header -> Name);
					else
						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],3,DialNode -> VanillaNode . ln_Succ -> ln_Name);
				}
				else
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_CALL_COMMENT_NUMBER_NEXT],3,LocaleString(MSG_GLOBAL_NONE_TXT));
			}

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

			SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_DIALING_TXT));

				/* Dial the number. */

			SerialCommand(SomeBuffer);

				/* Reset the signal. */

			SetSignal(NULL,SIG_SKIP | SIG_BREAK);

			while(!Terminated)
			{
				if(CheckSignal(SIG_BREAK))
				{
					Terminated = TRUE;

					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ABORTING_TXT));

					SerWrite("\r",1);
					WaitTime(1,0);

						/* Ignore the response of the modem. */

					HandleSerial();

					FlowInit(TRUE);

					break;
				}

				if(Dialing)
				{
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_TIME_TRY],0,"%2ld:%02ld",DialTimeout / 60,DialTimeout % 60);
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_TIME_TRY],1,LocaleString(MSG_DIALPANEL_ATTEMPT_OF_TXT),DialAttempt + 1,DialRetries);
				}
				else
					SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_TIME_TRY],0,"%2ld:%02ld",RedialDelay / 60,RedialDelay % 60);

				WaitTime(0,MILLION / 2);

					/* The following commands are executed each second */

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

						/* Are we dialing or waiting? */

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

						if(!(--DialTimeout))
						{
							SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_DIAL_ATTEMPT_TIMEOUT_TXT));

Skip1:							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)
								{
									SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

									WakeUp(PanelWindow,SOUND_BELL);

									WaitTime(2,0);

									Say(LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

									Terminated = 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. */

										SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],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)
						{
							SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],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);

						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_NO_DIALTONE_TXT));

						WakeUp(PanelWindow,SOUND_BELL);

						WaitTime(2,0);

						Say(LocaleString(MSG_DIALPANEL_NO_DIALTONE_TXT));

						Terminated = TRUE;
					}

						/* Somebody tries to call us. */

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

						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));

						WakeUp(PanelWindow,SOUND_RING);

						WaitTime(2,0);

						Say(LocaleString(MSG_GLOBAL_INCOMING_CALL_TXT));

						Terminated = TRUE;
					}

						/* Somebody's talking. */

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

						SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_INCOMING_VOICE_CALL_TXT));

						WakeUp(PanelWindow,SOUND_VOICE);

						WaitTime(2,0);

						Say(LocaleString(MSG_DIALPANEL_INCOMING_VOICE_CALL_TXT));

						Terminated = TRUE;
					}

						/* We got a connect. */

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

							/* Install the new configuration. */

						if(DialNode -> Entry)
						{
							UpdateConfig(DialNode -> Entry -> Config,Config);

							ConfigChanged = FALSE;

							MakeCall(DialNode -> Entry -> Header -> Name,NumberBuffer);
						}
						else
							MakeCall("???",NumberBuffer);

							/* Reset the scanner. */

						FlowInit(TRUE);

							/* Copy the remaining data. */

						if(DialNode -> Entry)
						{
							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 -> 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
						{
							CurrentPay		= 0;

							ChosenEntry		= NULL;

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

							strcpy(CurrentBBSNumber,NumberBuffer);

							Password[0]		= 0;
							UserName[0]		= 0;

							SendStartup		= FALSE;

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

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

							/* We are now online. */

						Online		= TRUE;
						Terminated	= TRUE;

							/* Add another logfile entry. */

						if(DialNode -> Entry)
							LogAction(LocaleString(MSG_DIALPANEL_CONNECTED_TO_1_TXT),DialNode -> Entry -> Header -> Name,NumberBuffer);
						else
							LogAction(LocaleString(MSG_DIALPANEL_CONNECTED_TO_2_TXT),NumberBuffer);

							/* Open auto-capture file if necessary. */

						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 the node from the
							 * dialing list.
							 */

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

						Remove(&DialNode -> VanillaNode);

						FreeVec(DialNode);

							/* Wake the user up. */

						if(BaudBuffer[0])
						{
							strcpy(SharedBuffer,"CONNECT ");
							strcat(SharedBuffer,BaudBuffer);

							SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,SharedBuffer);

							WakeUp(PanelWindow,SOUND_CONNECT);

							WaitTime(2,0);

								/* Install new baud rate if desired. */

							if(Config -> ModemConfig -> ConnectAutoBaud && DTERate > 110)
								Config -> SerialConfig -> BaudRate = DTERate;
						}
						else
						{
							SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_CONNECTION_ESTABLISHED_TXT));

							WakeUp(PanelWindow,SOUND_CONNECT);
						}

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

						Say(LocaleString(MSG_DIALPANEL_CONNECTION_ESTABLISHED_TXT));

							/* Perform system initialization. */

						ConfigSetup();
					}
				}

					/* Look for the hotkey. */

				if(CheckSignal(SIG_SKIP))
				{
						/* Are we dialing or waiting? */

					if(Dialing)
					{
						DialTimeout = 0;

						goto Skip1;
					}
					else
					{
						RedialDelay = 0;

						goto Skip2;
					}
				}

					/* Pick up the window input. */

				while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
				{
					IClass	= Massage -> Class;
					Code	= Massage -> Code;
					Gadget	= (struct Gadget *)Massage -> IAddress;

					GT_ReplyIMsg(Massage);

					if(IClass == IDCMP_VANILLAKEY)
					{
						if(Code == ' ')
						{
							IClass	= IDCMP_GADGETUP;
							Code	= 0;
							Gadget	= GadgetArray[GAD_SKIP];
						}
						else
							KeySelect(GadgetArray,GAD_ABORT,Code,PanelWindow,&Gadget,&IClass,&Code);
					}

					if(IClass == IDCMP_RAWKEY)
						KeySelect(GadgetArray,GAD_ABORT,Code,PanelWindow,&Gadget,&IClass,&Code);

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

					if(IClass == IDCMP_CLOSEWINDOW)
					{
						IClass	= IDCMP_GADGETUP;
						Gadget	= GadgetArray[GAD_ABORT];

						Result = TRUE;
					}

					if(IClass == IDCMP_GADGETUP)
					{
						switch(Gadget -> GadgetID)
						{
									/* 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)
											{
												SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

												WakeUp(PanelWindow,SOUND_BELL);

												WaitTime(2,0);

												Say(LocaleString(MSG_DIALPANEL_MAXIMUM_NUMBER_OF_DIAL_RETRIES_TXT));

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

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

											SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_DIALING_LIST_IS_EMPTY_TXT));

											WaitTime(2,0);
										}
									}

									DialTimeout = 0;

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

									FreeVec(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.
											 */

										Terminated = TRUE;

										SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_DIALING_LIST_IS_EMPTY_TXT));

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

									FreeVec(LastNode);

										/* Get back to first list entry. */

									if(!Terminated)
									{
										RedialDelay = 0;

										goto Skip2;
									}
								}

								break;

							case GAD_SKIP:

								if(Dialing)
								{
									DialTimeout = 0;

									goto Skip1;
								}
								else
								{
									RedialDelay = 0;

									goto Skip2;
								}

							case GAD_ONLINE:

									/* Forced online,
									 * install new configuration
									 * first.
									 */

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

									/* We are now online. */

								Online		= TRUE;
								Terminated	= TRUE;

									/* Add a new log action. */

								if(DialNode -> Entry)
									LogAction(LocaleString(MSG_DIALPANEL_CONNECTED_TO_1_TXT),DialNode -> Entry -> Header -> Name,NumberBuffer);
								else
									LogAction(LocaleString(MSG_DIALPANEL_CONNECTED_TO_2_TXT),NumberBuffer);

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

								FreeVec(DialNode);

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

								ConfigSetup();

								break;

								/* Abort the dialing process. */

							case GAD_ABORT:

								Terminated = TRUE;

								SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ABORTING_TXT));

								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(PanelWindow,NULL) != RECONFIGURE_FAILURE)
					{
						if(ExitString[0])
						{
							SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_EXIT_COMMAND_TXT));

							FlowInit(TRUE);

							SerialCommand(ExitBuffer);

							WaitTime(1,0);

							HandleSerial();

							if(FlowInfo . Changed && FlowInfo . Error)
							{
								SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

								GotError = TRUE;
							}
						}

						if(Config -> ModemConfig -> ModemInit[0] && !GotError)
						{
							SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_SENDING_MODEM_INIT_COMMAND_TXT));

							FlowInit(TRUE);

							SerialCommand(Config -> ModemConfig -> ModemInit);

							WaitTime(1,0);

							HandleSerial();

							if(FlowInfo . Changed && FlowInfo . Error)
							{
								SZ_PrintLine(PanelWindow -> RPort,BoxArray[BOX_MESSAGE],0,LocaleString(MSG_DIALPANEL_ERROR_SENDING_MODEM_COMMAND_TXT));

								GotError = TRUE;
							}
						}
					}
				}
			}

			if(GotError)
			{
				WORD i;

				for(i = GAD_SKIP ; i <= GAD_REMOVE ; i++)
				{
					GT_SetGadgetAttrs(GadgetArray[i],PanelWindow,NULL,
						GA_Disabled,TRUE,
					TAG_DONE);
				}

				WakeUp(PanelWindow,SOUND_BELL);

				Terminated = FALSE;

				do
				{
					if(Wait(PORTMASK(PanelWindow -> UserPort) | SIG_BREAK) & SIG_BREAK)
						Terminated = TRUE;
					else
					{
						while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
						{
							IClass	= Massage -> Class;
							Code	= Massage -> Code;
							Gadget	= (struct Gadget *)Massage -> IAddress;

							GT_ReplyIMsg(Massage);

							KeySelect(GadgetArray,GAD_ABORT,Code,PanelWindow,&Gadget,&IClass,&Code);

							if(IClass == IDCMP_CLOSEWINDOW || (IClass = IDCMP_GADGETDOWN && Gadget -> GadgetID == GAD_ABORT))
								Terminated = TRUE;
						}
					}
				}
				while(!Terminated);
			}

			RemoveGList(PanelWindow,GadgetList,(UWORD)-1);

			PopWindow();

			CloseWindow(PanelWindow);
		}
	}

	FreeGadgets(GadgetList);

	SZ_FreeBoxes(BoxList);

			/* Reset the scanner. */

	FullCheck = FALSE;

	FlowInit(TRUE);

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

	Quiet = FALSE;

		/* Reset the display if necessary. */

	if(ResetDisplay)
		DisplayReset();

	if(Online)
	{
		SetDialMenu(FALSE);

			/* Send the startup macro if necessary. */

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

			SendStartup = FALSE;
		}
	}

	return(Result);
}
