/*
**	termASCIITransfer.c
**
**	ASCII file transfer routines
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#include "termARexxGlobal.h"

	/* Local variables. */

STATIC LONG		WaitCount,PromptCount;
STATIC UBYTE __far	ASCIISendPrompt[256];
STATIC LONG		ASCIISendPromptLen;
STATIC BYTE		(* ASCIISendLine)(register STRPTR,register LONG);

STATIC LONG __regargs
MangleASCIIBuffer(BYTE TranslateCR,BYTE TranslateLF,STRPTR Source,LONG SourceLen,STRPTR Destination)
{
	WORD	CR_Len,
		LF_Len;
	STRPTR	CR_String,
		LF_String;
	UBYTE	Mask;
	LONG	Len = 0;

	switch(TranslateCR)
	{
		case CR_IGNORE:

			CR_Len = 0;
			break;

		case CR_ASCR:

			CR_Len		= 1;
			CR_String	= "\r";
			break;

		case CR_ASCRLF:

			CR_Len		= 2;
			CR_String	= "\r\n";
			break;
	}

	switch(TranslateLF)
	{
		case LF_IGNORE:

			LF_Len = 0;
			break;

		case LF_ASLF:

			LF_Len		= 1;
			LF_String	= "\n";
			break;

		case LF_ASLFCR:

			LF_Len		= 2;
			LF_String	= "\n\r";
			break;
	}

	if(Config -> TransferConfig -> StripBit8)
		Mask = 0x7F;
	else
		Mask = 0xFF;

	do
	{
		switch(*Source)
		{
			case '\r':

				if(CR_Len)
				{
					CopyMem(CR_String,Destination,CR_Len);

					Destination	+= CR_Len;
					Len		+= CR_Len;
				}

				break;

			case '\n':

				if(LF_Len)
				{
					CopyMem(LF_String,Destination,LF_Len);

					Destination	+= LF_Len;
					Len		+= LF_Len;
				}

				break;

			default:

				*Destination++ = (*Source) & Mask;

				Len++;

				break;
		}

		Source++;
	}
	while(--SourceLen);

	return(Len);
}

	/* MatchPrompt():
	 *
	 *	Search incoming data stream for a match.
	 */

STATIC BYTE __regargs
MatchPrompt(register STRPTR Data,register LONG Size,register STRPTR Prompt,register LONG PromptLen)
{
	register UBYTE c,Mask;

	if(Config -> SerialConfig -> StripBit8)
		Mask = 0x7F;
	else
		Mask = 0xFF;

	do
	{
		if(c = ((*Data++) & Mask))
		{
			register BYTE MatchMade;

			do
			{
				MatchMade = FALSE;

				if(PromptCount == WaitCount)
				{
					if(c == Prompt[WaitCount] & Mask)
					{
						MatchMade = TRUE;

						if(PromptLen == ++PromptCount)
							return(TRUE);
					}
				}

				if(MatchMade)
					WaitCount++;
				else
				{
					if(WaitCount)
					{
						WaitCount = 0;

						PromptCount = 0;
					}
					else
						break;
				}
			}
			while(!WaitCount);
		}
	}
	while(--Size);

	return(FALSE);
}

	/* WaitForPrompt(STRPTR Prompt,LONG PromptLen):
	 *
	 *	Scan the incoming data flow for a certain string.
	 */

STATIC BYTE __regargs
WaitForPrompt(STRPTR Prompt,LONG PromptLen)
{
	ULONG Signals;

	WaitCount = PromptCount = 0;

	if(DataHold)
	{
		DataHold = NULL;

		RestartSerial(FALSE);
	}

	if(CheckIO(ReadRequest))
		Signals = SIG_SERIAL;
	else
		Signals = NULL;

	StartTime(Config -> TransferConfig -> SendTimeout / 100,(Config -> TransferConfig -> SendTimeout % 100) * 10000);

	for(;;)
	{
		if(Signals & SIG_SERIAL)
		{
			if(!WaitIO(ReadRequest))
			{
				LONG Length;

				BytesIn++;

				ConProcess(ReadBuffer,1);

				Status = STATUS_READY;

				if(MatchPrompt(ReadBuffer,1,Prompt,PromptLen))
				{
					if(!CheckIO(TimeRequest))
						AbortIO(TimeRequest);

					WaitIO(TimeRequest);

					RestartSerial(FALSE);

					return(TRUE);
				}

				do
				{
						/* Check how many bytes are still in
						 * the serial buffer.
						 */

					WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

					DoIO(WriteRequest);

					if(Length = WriteRequest -> IOSer . io_Actual)
					{
						if(Length > Config -> SerialConfig -> SerialBufferSize)
							Length = Config -> SerialConfig -> SerialBufferSize;

						ReadRequest -> IOSer . io_Command	= CMD_READ;
						ReadRequest -> IOSer . io_Data		= ReadBuffer;
						ReadRequest -> IOSer . io_Length	= Length;

						if(!DoIO(ReadRequest))
						{
							BytesIn += Length;

							ConProcess(ReadBuffer,Length);

							Status = STATUS_READY;

							if(MatchPrompt(ReadBuffer,Length,Prompt,PromptLen))
							{
								if(!CheckIO(TimeRequest))
									AbortIO(TimeRequest);

								WaitIO(TimeRequest);

								RestartSerial(FALSE);

								return(TRUE);
							}
						}
					}
				}
				while(Length);
			}

			RestartSerial(FALSE);
		}

		if(Signals & SIG_TIMER)
		{
			WaitIO(TimeRequest);

			return(FALSE);
		}

		Signals = Wait(SIG_SERIAL | SIG_TIMER);
	}
}

	/* ASCIISendLinePrompt(STRPTR Line,LONG Len):
	 *
	 *	Send text line, wait for prompt.
	 */

STATIC BYTE
ASCIISendLinePrompt(STRPTR Line,LONG Len)
{
	LONG i;

	if(Len == -1)
		Len = strlen(Line);

	while(Len)
	{
		i = 0;

		while(i < Len && Line[i] != '\r')
			i++;


		if(Line[i] == '\r')
		{
			i++;

			SerWrite(Line,i);

			if(!WaitForPrompt(ASCIISendPrompt,ASCIISendPromptLen))
				return(FALSE);
		}
		else
		{
			if(i)
				SerWrite(Line,i);
		}

		Len	-= i;
		Line	+= i;
	}

	return(TRUE);
}

	/* ASCIISendLineSimple(STRPTR Line,LONG Len):
	 *
	 *	Send a text line, no fancy features.
	 */

STATIC BYTE
ASCIISendLineSimple(STRPTR Line,LONG Len)
{
	if(Len == -1)
		Len = strlen(Line);

	SerWrite(Line,Len);

	return(TRUE);
}

	/* ASCIISendLineDelay(STRPTR Line,LONG Len):
	 *
	 *	Send a text line, include a delay where necessary.
	 */

STATIC BYTE
ASCIISendLineDelay(STRPTR Line,LONG Len)
{
	if(Len == -1)
		Len = strlen(Line);

	while(Len--)
	{
		SerWrite(Line,1);

		if(*Line == '\r')
		{
			if(Config -> TransferConfig -> LineDelay)
				WaitTime(Config -> TransferConfig -> LineDelay / 100,(Config -> TransferConfig -> LineDelay % 100) * 10000);
		}
		else
		{
			if(Config -> TransferConfig -> CharDelay)
				WaitTime(Config -> TransferConfig -> CharDelay / 100,(Config -> TransferConfig -> CharDelay % 100) * 10000);
		}

		Line++;
	}

	return(TRUE);
}

	/* ASCIISendLineEcho(STRPTR Line,LONG Len):
	 *
	 *	Send a text line, wait for single characters to be echoed.
	 */

STATIC BYTE
ASCIISendLineEcho(STRPTR Line,LONG Len)
{
	ULONG Signals;

	if(DataHold)
	{
		DataHold = NULL;

		RestartSerial(FALSE);
	}

	if(Len == -1)
		Len = strlen(Line);

	while(Len--)
	{
		SerWrite(Line,1);

		StartTime(Config -> TransferConfig -> SendTimeout / 100,(Config -> TransferConfig -> SendTimeout % 100) * 10000);

		FOREVER
		{
			Signals = Wait(SIG_TIMER | SIG_SERIAL);

			if(Signals & SIG_SERIAL)
			{
				if(!WaitIO(ReadRequest))
				{
					if(*(UBYTE *)ReadBuffer == *Line)
					{
						if(!CheckIO(TimeRequest))
							AbortIO(TimeRequest);

						WaitIO(TimeRequest);

						RestartSerial(FALSE);

						break;
					}

					RestartSerial(FALSE);
				}
				else
				{
					if(!CheckIO(TimeRequest))
						AbortIO(TimeRequest);

					WaitIO(TimeRequest);

					RestartSerial(FALSE);

					return(FALSE);
				}
			}

			if(Signals & SIG_TIMER)
			{
				WaitIO(TimeRequest);

				return(FALSE);
			}
		}

		Line++;
	}

	return(TRUE);
}

	/* ASCIISendLineAnyEcho(STRPTR Line,LONG Len):
	 *
	 *	Send a text line, wait for characters to be echoed.
	 */

STATIC BYTE
ASCIISendLineAnyEcho(STRPTR Line,LONG Len)
{
	ULONG Signals;

	if(DataHold)
	{
		DataHold = NULL;

		RestartSerial(FALSE);
	}

	if(Len == -1)
		Len = strlen(Line);

	while(Len--)
	{
		SerWrite(Line,1);

		StartTime(Config -> TransferConfig -> SendTimeout / 100,(Config -> TransferConfig -> SendTimeout % 100) * 10000);

		FOREVER
		{
			Signals = Wait(SIG_TIMER | SIG_SERIAL);

			if(Signals & SIG_SERIAL)
			{
				if(!WaitIO(ReadRequest))
				{
					if(!CheckIO(TimeRequest))
						AbortIO(TimeRequest);

					WaitIO(TimeRequest);

					RestartSerial(FALSE);

					break;
				}
				else
				{
					if(!CheckIO(TimeRequest))
						AbortIO(TimeRequest);

					WaitIO(TimeRequest);

					RestartSerial(FALSE);

					return(FALSE);
				}
			}

			if(Signals & SIG_TIMER)
			{
				WaitIO(TimeRequest);

				return(FALSE);
			}
		}

		Line++;
	}

	return(TRUE);
}

	/* ASCIISendLineKeyDelay(STRPTR Line,LONG Len):
	 *
	 *	Send a text line, include keyboard delay pauses between characters.
	 */

STATIC BYTE
ASCIISendLineKeyDelay(STRPTR Line,LONG Len)
{
	struct Preferences Prefs;

	if(Len == -1)
		Len = strlen(Line);

		/* Get current key repeat delay. */

	GetPrefs(&Prefs,offsetof(struct Preferences,KeyRptDelay));

		/* Any delay specified at all? */

	if(Prefs . KeyRptSpeed . tv_secs || Prefs . KeyRptSpeed . tv_micro)
	{
		while(Len--)
		{
			SerWrite(Line++,1);

			if(Len)
			{
				TimeRequest -> tr_node . io_Command	= TR_ADDREQUEST;
				TimeRequest -> tr_time			= Prefs . KeyRptSpeed;

				DoIO(TimeRequest);
			}
		}
	}
	else
		SerWrite(Line,Len);

	return(TRUE);
}

	/* ASCIOSendSetup():
	 *
	 *	Choose the right routine for the text line output job.
	 */

VOID
ASCIISendSetup()
{
		/* Pick the line send routine. */

	switch(Config -> TransferConfig -> PacingMode)
	{
		case PACE_DIRECT:

			ASCIISendLine = ASCIISendLineSimple;
			break;

		case PACE_ECHO:

			if(Config -> TransferConfig -> SendTimeout)
				ASCIISendLine = ASCIISendLineEcho;
			else
				ASCIISendLine = ASCIISendLineSimple;

			break;

		case PACE_ANYECHO:

			if(Config -> TransferConfig -> SendTimeout)
				ASCIISendLine = ASCIISendLineAnyEcho;
			else
				ASCIISendLine = ASCIISendLineSimple;

			break;

		case PACE_PROMPT:

			if(Config -> TransferConfig -> SendTimeout)
			{
					/* Prepare the prompt string. */

				if(Config -> TransferConfig -> LinePrompt[0])
					ASCIISendPromptLen = TranslateString(Config -> TransferConfig -> LinePrompt,ASCIISendPrompt);
				else
				{
					ASCIISendPrompt[0] = 0;
					ASCIISendPromptLen = 0;
				}

				ASCIISendLine = ASCIISendLinePrompt;
			}
			else
				ASCIISendLine = ASCIISendLineSimple;

			break;

		case PACE_DELAY:

			if(Config -> TransferConfig -> LineDelay || Config -> TransferConfig -> CharDelay)
				ASCIISendLine = ASCIISendLineDelay;
			else
				ASCIISendLine = ASCIISendLineSimple;

			break;

		case PACE_KEYBOARD:

			ASCIISendLine = ASCIISendLineKeyDelay;
			break;
	}
}

BYTE __regargs
InternalASCIIUpload(STRPTR SingleFile,BYTE WaitForIt)
{
	BYTE	OldStatus = Status,DidSend = FALSE;
	BPTR	NewDir,OldDir;

		/* We are uploading data. */

	Uploading = TRUE;

	if(NewDir = Lock(Config -> PathConfig -> ASCIIUploadPath,ACCESS_READ))
		OldDir = CurrentDir(NewDir);
	else
		OldDir = NULL;

	BlockWindows();

	if(!FileTransferInfo)
	{
		if(SingleFile)
		{
			ULONG Size;

			if(Size = GetFileSize(SingleFile))
			{
				if(FileTransferInfo = AllocFileTransferInfo())
				{
					if(!AddFileTransferNode(FileTransferInfo,SingleFile,Size))
					{
						FreeFileTransferInfo(FileTransferInfo);

						FileTransferInfo = NULL;
					}
				}
			}
		}
		else
		{
			struct FileRequester	*FileRequest;
			UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH];

			if(FileRequest = GetFile(Window,LocaleString(MSG_TERMTRANSFER_UPLOAD_FILE_TXT + TRANSFER_ASCII),Config -> PathConfig -> ASCIIUploadPath,"",DummyBuffer,"",FALSE,TRUE,FALSE,LocaleString(MSG_TERMTRANSFER_SEND_TXT),TRUE))
			{
				strcpy(Config -> PathConfig -> ASCIIUploadPath,FileRequest -> rf_Dir);

				ConfigChanged = TRUE;

				FileTransferInfo = BuildFileTransferInfo(FileRequest);

				FreeAslRequest(FileRequest);
			}
		}
	}
	else
	{
		if(SingleFile)
		{
			ULONG Size;

			if(Size = GetFileSize(SingleFile))
			{
				if(!AddFileTransferNode(FileTransferInfo,SingleFile,Size))
				{
					FreeFileTransferInfo(FileTransferInfo);

					FileTransferInfo = NULL;
				}
			}
		}
	}

	TransferAborted = FALSE;

	TransferFailed = TRUE;

	if(FileTransferInfo)
	{
		struct Window *ThisWindow;

		if(ThisWindow = CreateASCIIWindow(TRUE))
		{
			struct Buffer	*File;
			LONG		 Chars = 0,Lines = 0,Len,i;
			BYTE		 Terminated = FALSE;

			FileTransferInfo -> DoneSize	= 0;
			FileTransferInfo -> DoneFiles	= 0;

			FileTransferInfo -> CurrentFile	= (struct FileTransferNode *)FileTransferInfo -> FileList . mlh_Head;
			FileTransferInfo -> CurrentSize	= FileTransferInfo -> CurrentFile -> Size;

			Status = STATUS_UPLOAD;

			ASCIISendSetup();

			if(DataHold)
			{
				if(!Config -> TransferConfig -> QuietTransfer)
				{
					ConProcess(DataHold,DataSize);

					Status = STATUS_UPLOAD;
				}

				DataHold = NULL;

				RestartSerial(FALSE);
			}

			while(!Terminated && FileTransferInfo -> CurrentFile -> Node . mln_Succ)
			{
				if(File = BufferOpen(FileTransferInfo -> CurrentFile -> Name,"r"))
				{
					UBYTE	DummyBuffer[512],
						OtherBuffer[256];
					ULONG	Signals;
					BYTE	LastCR = FALSE,Skipped = FALSE;

					AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_OPENING_FILE_TXT),FileTransferInfo -> CurrentFile -> Name);

					while(!Skipped && !Terminated && (Len = BufferRead(File,OtherBuffer,256)) > 0)
					{
						if(Len = MangleASCIIBuffer(Config -> TransferConfig -> SendCR,Config -> TransferConfig -> SendLF,OtherBuffer,Len,DummyBuffer))
						{
							for(i = 0 ; i < Len ; i++)
							{
								if(DummyBuffer[i] == '\r')
								{
									Lines++;

									LastCR = TRUE;
								}
								else
								{
									if(DummyBuffer[i] == '\n' && !LastCR)
										Lines++;

									LastCR = FALSE;
								}
							}

							Chars += Len;

							DidSend = TRUE;

							TransferFailed = FALSE;

							(*ASCIISendLine)(DummyBuffer,Len);
						}

						Signals = CheckSignal(SIG_BREAK | SIG_SERIAL | PORTMASK(ThisWindow -> UserPort));

						if(Signals & SIG_BREAK)
							Terminated = TransferAborted = TRUE;

						if(Signals & PORTMASK(ThisWindow -> UserPort))
						{
							switch(HandleASCIIWindow(ThisWindow))
							{
								case 1:	Terminated = TransferAborted = TRUE;
									break;

								case 2:	Skipped = TRUE;
									break;
							}

							if(Terminated || Skipped)
								break;
						}

						if(Signals & SIG_SERIAL)
						{
							if(!WaitIO(ReadRequest))
							{
								LONG Length;

								if(!Config -> TransferConfig -> QuietTransfer)
								{
									BytesIn++;

									ConProcess(ReadBuffer,1);

									Status = STATUS_UPLOAD;
								}

									/* Check how many bytes are still in
									 * the serial buffer.
									 */

								WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

								DoIO(WriteRequest);

								if(Length = WriteRequest -> IOSer . io_Actual)
								{
									if(Length > Config -> SerialConfig -> SerialBufferSize)
										Length = Config -> SerialConfig -> SerialBufferSize;

									if(Length > Config -> SerialConfig -> Quantum)
										Length = Config -> SerialConfig -> Quantum;

									ReadRequest -> IOSer . io_Command	= CMD_READ;
									ReadRequest -> IOSer . io_Data		= ReadBuffer;
									ReadRequest -> IOSer . io_Length	= Length;

									if(!DoIO(ReadRequest))
									{
										if(!Config -> TransferConfig -> QuietTransfer)
										{
											BytesIn += Length;

												/* Send the data to the console. */

											ConProcess(ReadBuffer,Length);

											Status = STATUS_UPLOAD;
										}
									}
								}
							}

							RestartSerial(FALSE);
						}

						UpdateASCIIWindow(ThisWindow,Chars,FileTransferInfo -> CurrentFile -> Size,Lines);
					}

					if(Len < 0)
					{
						AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_ERROR_READING_FILE_TXT),FileTransferInfo -> CurrentFile -> Name);

						TransferFailed = TRUE;

						break;
					}

					BufferClose(File);

					RemoveUploadListItem(FileTransferInfo -> CurrentFile -> Name);
				}
				else
				{
					AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_ERROR_OPENING_FILE_TXT),FileTransferInfo -> CurrentFile -> Name);

					TransferFailed = TRUE;

					break;
				}

				FileTransferInfo -> DoneSize	+= FileTransferInfo -> CurrentSize;
				FileTransferInfo -> DoneFiles	+= 1;

				FileTransferInfo -> CurrentFile  = (struct FileTransferNode *)FileTransferInfo -> CurrentFile -> Node . mln_Succ;
				FileTransferInfo -> CurrentSize  = FileTransferInfo -> CurrentFile -> Size;
			}

			if(TransferFailed || TransferError)
				WakeUp(ThisWindow,SOUND_BADTRANSFER);
			else
			{
				WakeUp(ThisWindow,SOUND_GOODTRANSFER);

				WaitTime(2,0);
			}

			DeleteASCIIWindow(ThisWindow,TransferFailed && WaitForIt);
		}

		FreeFileTransferInfo(FileTransferInfo);

		FileTransferInfo = NULL;
	}

	if(TransferFailed || TransferAborted)
		Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
	else
		Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

	if(OldDir)
		CurrentDir(OldDir);

	if(NewDir)
		UnLock(NewDir);

	SendAbort = FALSE;

	Status = OldStatus;

	ReleaseWindows();

	DidTransfer = FALSE;

	if(WaitForIt)
	{
		if(Config -> CommandConfig -> DownloadMacro[0])
			SerialCommand(Config -> CommandConfig -> DownloadMacro);
	}

	DidTransfer = FALSE;

	return(DidSend);
}

BYTE __regargs
InternalASCIIDownload(STRPTR Name,BYTE WaitForIt)
{
	struct FileRequester	*FileRequest;
	UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH];
	BYTE			 OldStatus = Status,DidSend = FALSE;
	BPTR			 NewDir,OldDir;

	ClearGenericList(GenericListTable[GLIST_DOWNLOAD]);

	DownloadPath = Config -> PathConfig -> ASCIIDownloadPath;

	if(DownloadPath[0])
	{
		if(NewDir = Lock(DownloadPath,ACCESS_READ))
			OldDir = CurrentDir(NewDir);
		else
			OldDir = NULL;
	}
	else
		NewDir = OldDir = NULL;

	BlockWindows();

	if(!Name)
	{
		if(FileRequest = GetFile(Window,LocaleString(MSG_TERMTRANSFER_DOWNLOAD_FILE_TXT + TRANSFER_ASCII),DownloadPath,"",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_TERMTRANSFER_RECEIVE_TXT),TRUE))
		{
				/* Save the download path. */

			strcpy(DownloadPath,FileRequest -> rf_Dir);

			ConfigChanged = TRUE;

			FreeAslRequest(FileRequest);

			Name = DummyBuffer;
		}
	}
	else
	{
		STRPTR Index;

		strcpy(DownloadPath,Name);

		ConfigChanged = TRUE;

		Index = PathPart(DownloadPath);

		*Index = 0;
	}

	TransferAborted = FALSE;

	TransferFailed = TRUE;

	if(Name)
	{
		struct Window *ThisWindow;

		if(ThisWindow = CreateASCIIWindow(FALSE))
		{
			struct Buffer *File;

			if(File = BufferOpen(Name,"w"))
			{
				UBYTE	OtherBuffer[512];
				LONG	Chars = 0,Lines = 0,i;
				BYTE	Terminated = FALSE;
				ULONG	Signals;

				AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_OPENING_FILE_TXT),Name);

				TransferFailed = FALSE;

				Status = STATUS_DOWNLOAD;

				if(DataHold)
				{
					LONG Size,Len;

					do
					{
						if(DataSize > 256)
							Size = 256;
						else
							Size = DataSize;

						if(Len = MangleASCIIBuffer(Config -> TransferConfig -> ReceiveCR,Config -> TransferConfig -> ReceiveLF,DataHold,Size,OtherBuffer))
						{
							if(Config -> TransferConfig -> IgnoreDataPastArnold)
							{
								for(i = 0 ; i < Len ; i++)
								{
									if(OtherBuffer[i] == '\r')
										Lines++;

									if(OtherBuffer[i] == Config -> TransferConfig -> TerminatorChar)
									{
										Len = i;

										Terminated = TRUE;

										break;
									}
								}
							}
							else
							{
								for(i = 0 ; i < Len ; i++)
								{
									if(OtherBuffer[i] == '\r')
										Lines++;
								}
							}

							if(Len)
							{
								Chars += Len;

								if(BufferWrite(File,OtherBuffer,Len) != Len)
								{
									TransferFailed = Terminated = TRUE;

									AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_ERROR_WRITING_FILE_TXT),Name);
								}
							}
						}

						if(!Config -> TransferConfig -> QuietTransfer)
						{
							ConProcess(DataHold,Size);

							Status = STATUS_DOWNLOAD;
						}

						DataSize -= Size;

						if(DataSize > 0)
							DataHold += Size;
						else
							DataHold = NULL;
					}
					while(DataHold && !Terminated);

					RestartSerial(FALSE);

					UpdateASCIIWindow(ThisWindow,Chars,0,Lines);
				}

				if(!Terminated)
				{
					StartTime(5,0);

					do
					{
						Signals = Wait(SIG_BREAK | SIG_SERIAL | SIG_TIMER | PORTMASK(ThisWindow -> UserPort));

						if(Signals & PORTMASK(ThisWindow -> UserPort))
						{
							if(HandleASCIIWindow(ThisWindow))
								break;
						}

						if(Signals & SIG_SERIAL)
						{
							StopTime();

							if(!WaitIO(ReadRequest))
							{
								LONG Length;

								BytesIn++;

								if(!Config -> TransferConfig -> QuietTransfer)
								{
									ConProcess(ReadBuffer,1);

									Status = STATUS_DOWNLOAD;
								}

								if(Length = MangleASCIIBuffer(Config -> TransferConfig -> ReceiveCR,Config -> TransferConfig -> ReceiveLF,ReadBuffer,1,OtherBuffer))
								{
									if(Config -> TransferConfig -> IgnoreDataPastArnold)
									{
										for(i = 0 ; i < Length ; i++)
										{
											if(OtherBuffer[i] == Config -> TransferConfig -> TerminatorChar)
											{
												Length = i;

												Terminated = TRUE;

												break;
											}
										}

										if(Terminated)
										{
											RestartSerial(FALSE);

											break;
										}
									}

									if(Length)
									{
										if(BufferWrite(File,OtherBuffer,Length) != Length)
										{
											TransferFailed = Terminated = TRUE;

											AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_ERROR_WRITING_FILE_TXT),Name);
										}

										for(i = 0 ; i < Length ; i++)
										{
											if(OtherBuffer[i] == '\r')
												Lines++;
										}

										Chars += Length;
									}
								}

									/* Check how many bytes are still in
									 * the serial buffer.
									 */

								WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

								DoIO(WriteRequest);

								if(Length = WriteRequest -> IOSer . io_Actual)
								{
									if(Length > Config -> SerialConfig -> SerialBufferSize)
										Length = Config -> SerialConfig -> SerialBufferSize;

									if(Length > Config -> SerialConfig -> Quantum)
										Length = Config -> SerialConfig -> Quantum;

									if(Length > 256)
										Length = 256;

									ReadRequest -> IOSer . io_Command	= CMD_READ;
									ReadRequest -> IOSer . io_Data		= ReadBuffer;
									ReadRequest -> IOSer . io_Length	= Length;

									if(!DoIO(ReadRequest))
									{
										BytesIn += Length;

											/* Send the data to the console. */

										if(!Config -> TransferConfig -> QuietTransfer)
										{
											ConProcess(ReadBuffer,Length);

											Status = STATUS_DOWNLOAD;
										}

										if(Length = MangleASCIIBuffer(Config -> TransferConfig -> ReceiveCR,Config -> TransferConfig -> ReceiveLF,ReadBuffer,Length,OtherBuffer))
										{
											if(Config -> TransferConfig -> IgnoreDataPastArnold)
											{
												for(i = 0 ; i < Length ; i++)
												{
													if(OtherBuffer[i] == '\r')
														Lines++;

													if(OtherBuffer[i] == Config -> TransferConfig -> TerminatorChar)
													{
														Length = i;

														Terminated = TRUE;

														break;
													}
												}
											}
											else
											{
												for(i = 0 ; i < Length ; i++)
												{
													if(OtherBuffer[i] == '\r')
														Lines++;
												}
											}

											if(Length)
											{
												Chars += Length;

												if(BufferWrite(File,OtherBuffer,Length) != Length)
												{
													TransferFailed = Terminated = TRUE;

													AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_ERROR_WRITING_FILE_TXT),Name);
												}
											}
										}
									}
								}

								UpdateASCIIWindow(ThisWindow,Chars,0,Lines);
							}

							StartTime(5,0);

							Signals &= ~SIG_TIMER;

							RestartSerial(FALSE);
						}

						if(Signals & SIG_TIMER)
							Terminated = TRUE;

						if(Signals & SIG_BREAK)
							TransferAborted = Terminated = TRUE;
					}
					while(!Terminated);

					StopTime();
				}

				BufferClose(File);
			}
			else
			{
				AddASCIIMessage(ThisWindow,LocaleString(MSG_ASCIIPANEL_ERROR_OPENING_FILE_TXT),Name);

				TransferFailed = TRUE;
			}

			if(TransferFailed || TransferError)
				WakeUp(ThisWindow,SOUND_BADTRANSFER);
			else
			{
				WakeUp(ThisWindow,SOUND_GOODTRANSFER);

				WaitTime(2,0);
			}

			DeleteASCIIWindow(ThisWindow,TransferFailed && WaitForIt);
		}
	}

	if(TransferFailed || TransferAborted)
		Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
	else
		Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

	if(OldDir)
		CurrentDir(OldDir);

	if(NewDir)
		UnLock(NewDir);

	SendAbort = FALSE;

	Status = OldStatus;

	ReleaseWindows();

	DownloadPath = NULL;

	DidTransfer = FALSE;

	if(WaitForIt)
	{
		if(Config -> CommandConfig -> DownloadMacro[0])
			SerialCommand(Config -> CommandConfig -> DownloadMacro);
	}

	DidTransfer = FALSE;

	return(DidSend);
}
