/*
**	termTransfer.c
**
**	File transfer routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* The action strings to display. */

STATIC UBYTE *SendQuery[3] =
{
	NULL,
	NULL,
	NULL
};

STATIC UBYTE *ReceiveQuery[3] =
{
	NULL,
	NULL,
	NULL
};

	/* The transfer types to display. */

STATIC UBYTE *TransferTypes[3] =
{
	NULL,
	NULL,
	NULL
};

	/* FreeFileTransferInfo(struct FileTransferInfo *Info):
	 *
	 *	Free a file transfer info list as allocated
	 *	by AllocFileTransferInfo() and AddFileTransferNode().
	 */

VOID
FreeFileTransferInfo(struct FileTransferInfo *Info)
{
	if(Info)
	{
		struct FileTransferNode	*Node,
					*Next;

		Node = (struct FileTransferNode *)Info -> FileList . mlh_Head;

		while(Next = (struct FileTransferNode *)Node -> Node . mln_Succ)
		{
			FreeVec(Node);

			Node = Next;
		}

		FreeVec(Info);
	}
}

	/* AllocFileTransferInfo():
	 *
	 *	Allocate a FileTransferInfo structure for use with
	 *	AddFileTransferNode().
	 */

struct FileTransferInfo *
AllocFileTransferInfo()
{
	struct FileTransferInfo *Info;

	if(Info = (struct FileTransferInfo *)AllocVec(sizeof(struct FileTransferInfo),MEMF_ANY | MEMF_CLEAR))
	{
		NewList((struct List *)&Info -> FileList);

		return(Info);
	}

	return(NULL);
}

	/* AddFileTransferNode(struct FileTransferInfo *Info,STRPTR Name,ULONG Size):
	 *
	 *	Allocate a file transfer information node.
	 */

BYTE
AddFileTransferNode(struct FileTransferInfo *Info,STRPTR Name,ULONG Size)
{
	struct FileTransferNode	*Node;
	WORD			 Len;

	Len = strlen(Name) + 1;

	if(Node = (struct FileTransferNode *)AllocVec(sizeof(struct FileTransferNode) + Len,MEMF_ANY))
	{
		Node -> Size	= Size;
		Node -> Name	= (STRPTR)(Node + 1);

		strcpy(Node -> Name,Name);

		AddTail((struct List *)&Info -> FileList,(struct Node *)Node);

		Info -> TotalSize += Size;

		Info -> TotalFiles++;

		return(TRUE);
	}

	return(FALSE);
}

	/* Compare(struct FileTransferNode **A,struct FileTransferNode **B):
	 *
	 *	Local subroutine required by qsort().
	 */

STATIC int __stdargs
Compare(struct FileTransferNode **A,struct FileTransferNode **B)
{
	if((*A) -> Size > (*B) -> Size)
		return(-1);
	else
	{
		if((*A) -> Size < (*B) -> Size)
			return(1);
		else
			return(Stricmp(FilePart((*A) -> Name),FilePart((*B) -> Name)));
	}
}

	/* SortFileTransferInfo(struct FileTransferInfo *Info):
	 *
	 *	Sorts the file transfer information list in ascending
	 *	order, but makes sure that the files are sorted
	 *	in descending order (i.e. the larger files come
	 *	first and files of equal size are sorted
	 *	lexically).
	 */

VOID
SortFileTransferInfo(struct FileTransferInfo *Info)
{
	if(Info -> TotalFiles > 1)
	{
		struct FileTransferNode **NodeList;

		if(NodeList = (struct FileTransferNode **)AllocVec(sizeof(struct FileTransferNode *) * Info -> TotalFiles,MEMF_ANY))
		{
			struct FileTransferNode	*Node,
						*Next;
			LONG			 i = 0;

			Node = (struct FileTransferNode *)Info -> FileList . mlh_Head;

			while(Next = (struct FileTransferNode *)Node -> Node . mln_Succ)
			{
				NodeList[i++] = Node;

				Node = Next;
			}

			qsort((APTR)NodeList,Info -> TotalFiles,sizeof(struct FileTransferNode *),Compare);

			NewList((struct List *)&Info -> FileList);

			for(i = 0 ; i < Info -> TotalFiles ; i++)
				AddTail((struct List *)&Info -> FileList,(struct Node *)&NodeList[i] -> Node);

			FreeVec(NodeList);
		}
	}
}

	/* BuildFileTransferInfo(struct FileRequester *FileRequester):
	 *
	 *	Build a file transfer information list from
	 *	information provided by a FileRequester structure.
	 */

struct FileTransferInfo *
BuildFileTransferInfo(struct FileRequester *FileRequester)
{
	struct FileTransferInfo *Info;

	if(Info = AllocFileTransferInfo())
	{
		BYTE	Success = FALSE;
		BPTR	NewLock,
			OldLock;

		if(NewLock = Lock(FileRequester -> rf_Dir,ACCESS_READ))
		{
			OldLock = CurrentDir(NewLock);

			if(FileRequester -> rf_NumArgs)
			{
				struct FileInfoBlock *FileInfo;

				if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
				{
					BPTR		 FileLock;
					struct WBArg	*ArgList = FileRequester -> rf_ArgList;
					LONG		 i;

					Success = TRUE;

					for(i = 0 ; Success && i < FileRequester -> rf_NumArgs ; i++)
					{
						if(ArgList[i] . wa_Name)
						{
							if(ArgList[i] . wa_Lock)
							{
								CurrentDir(ArgList[i] . wa_Lock);

								if(FileLock = Lock(ArgList[i] . wa_Name,ACCESS_READ))
								{
									if(Examine(FileLock,FileInfo))
									{
										if(FileInfo -> fib_DirEntryType < 0)
										{
											if(NameFromLock(FileLock,SharedBuffer,512))
											{
												if(!AddFileTransferNode(Info,SharedBuffer,FileInfo -> fib_Size))
													Success = FALSE;
											}
										}
									}

									UnLock(FileLock);
								}

								CurrentDir(NewLock);
							}
							else
							{
								if(FileLock = Lock(ArgList[i] . wa_Name,ACCESS_READ))
								{
									if(Examine(FileLock,FileInfo))
									{
										if(FileInfo -> fib_DirEntryType < 0)
										{
											if(NameFromLock(FileLock,SharedBuffer,512))
											{
												if(!AddFileTransferNode(Info,SharedBuffer,FileInfo -> fib_Size))
													Success = FALSE;
											}
										}
									}

									UnLock(FileLock);
								}
							}
						}
					}
				}

				FreeDosObject(DOS_FIB,FileInfo);
			}
			else
			{
				struct AnchorPath *Anchor;

				if(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath),MEMF_ANY | MEMF_CLEAR))
				{
					if(!MatchFirst(FileRequester -> rf_File,Anchor))
					{
						Success = TRUE;

						if(Anchor -> ap_Info . fib_DirEntryType < 0)
						{
							if(NameFromLock(NewLock,SharedBuffer,512))
							{
								if(AddPart(SharedBuffer,Anchor -> ap_Info . fib_FileName,512))
								{
									if(!AddFileTransferNode(Info,SharedBuffer,Anchor -> ap_Info . fib_Size))
										Success = FALSE;
								}
							}
						}

						if(Success)
						{
							while(!MatchNext(Anchor))
							{
								if(NameFromLock(NewLock,SharedBuffer,512))
								{
									if(AddPart(SharedBuffer,Anchor -> ap_Info . fib_FileName,512))
									{
										if(!AddFileTransferNode(Info,SharedBuffer,Anchor -> ap_Info . fib_Size))
										{
											Success = FALSE;

											break;
										}
									}
								}
							}
						}

						if(IoErr() != ERROR_NO_MORE_ENTRIES)
							Success = FALSE;
					}

					MatchEnd(Anchor);

					FreeVec(Anchor);
				}
			}

			CurrentDir(OldLock);

			UnLock(NewLock);
		}

		if(Success)
		{
			SortFileTransferInfo(Info);

			Info -> DoneSize	= 0;
			Info -> DoneFiles	= 0;

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

			return(Info);
		}
		else
			FreeFileTransferInfo(Info);
	}

	return(NULL);
}

	/* SendTextFile(UBYTE *TheFile):
	 *
	 *	Send a single text file via xpr.
	 */

VOID
SendTextFile(UBYTE *TheFile)
{
	BYTE OldStatus = Status;

	Uploading = TRUE;

	LocalizeString(SendQuery,MSG_TERMTRANSFER_UPLOAD_FILE_TXT,MSG_TERMTRANSFER_UPLOAD_ASCII_TXT);
	LocalizeString(TransferTypes,MSG_TERMTRANSFER_BINARY_TXT,MSG_TERMTRANSFER_ASCII_TXT);

		/* If not initialized, try to set up a new
		 * external transfer protocol.
		 */

	if(!XProtocolBase)
	{
		NewLibrary = FALSE;

		xpr_options(0,NULL);

		if(NewLibrary)
		{
			if(ProtocolSetup())
			{
				SaveProtocolOpts();

				strcpy(Config . FileConfig . ProtocolFileName,LastXprLibrary);
			}
		}
	}

	if(XProtocolBase)
	{
		XprIO -> xpr_filename = TheFile;

		if(TransferPanel(SendQuery[TRANSFER_TEXT]))
		{
			BYTE Aborted;

			Status = STATUS_UPLOAD;

			ClearSerial();

			LogAction(LocaleString(MSG_TERMTRANSFER_LOGMSG_INITIATE_UPLOAD_TXT),TransferTypes[TRANSFER_TEXT]);

			if(!XProtocolSend(XprIO))
				Aborted = TRUE;
			else
				Aborted = FALSE;

			if(TransferWindow)
			{
				WakeUp(TransferWindow);

				WaitTime(2,0);
			}

			if(Aborted)
				Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
			else
				Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

			Status = OldStatus;

			DeleteTransferPanel();

			if(ReadRequest)
			{
				ReadRequest -> IOSer . io_Command	= CMD_READ;
				ReadRequest -> IOSer . io_Data		= ReadBuffer;
				ReadRequest -> IOSer . io_Length	= 1;

				SetSignal(0,SIG_SERIAL);

				SendIO(ReadRequest);
			}
		}
	}

	if(SendAbort && UsesZModem)
		SerWrite(ZModemCancel,20);

	SendAbort = FALSE;

	Uploading = FALSE;

	if(Config . CommandConfig . UploadMacro[0])
		SerialCommand(Config . CommandConfig . UploadMacro);

	DidTransfer = FALSE;
}

	/* StartXprReceive():
	 *
	 *	Receive files via xpr.
	 */

VOID
StartXprReceive(BYTE Type)
{
	struct FileRequester	*FileRequest;
	UBYTE			 DummyBuffer[256];
	BYTE			 OldStatus = Status;

	LocalizeString(ReceiveQuery,MSG_TERMTRANSFER_DOWNLOAD_FILE_TXT,MSG_TERMTRANSFER_DOWNLOAD_ASCII_TXT);
	LocalizeString(TransferTypes,MSG_TERMTRANSFER_BINARY_TXT,MSG_TERMTRANSFER_ASCII_TXT);

		/* Select the download path. */

	switch(Type)
	{
		case TRANSFER_BINARY:	DownloadPath = Config . PathConfig . BinaryDownloadPath;
					break;

		case TRANSFER_TEXT:	DownloadPath = Config . PathConfig . TextDownloadPath;
					break;

		case TRANSFER_ASCII:	DownloadPath = Config . PathConfig . ASCIIDownloadPath;
					break;
	}

	BlockWindows();

		/* Set up the library if necessary. */

	if(!XProtocolBase)
	{
		NewLibrary = FALSE;

		xpr_options(0,NULL);

		if(NewLibrary)
		{
			if(ProtocolSetup())
			{
				SaveProtocolOpts();

				strcpy(Config . FileConfig . ProtocolFileName,LastXprLibrary);
			}
		}
	}

	if(XProtocolBase)
	{
			/* Do we need to ask the user for
			 * the destination file name?
			 */

		if(TransferBits & XPRS_NORECREQ)
		{
				/* Obviously not, let's open
				 * the transfer info window as
				 * usual and download the file(s).
				 */

			if(TransferPanel(ReceiveQuery[Type]))
			{
				Status = STATUS_DOWNLOAD;

				ClearSerial();

				LogAction(LocaleString(MSG_TERMTRANSFER_LOGMSG_INITIATE_DOWNLOAD_TXT),TransferTypes[Type]);

					/* Receive the data. */

				if(!XProtocolReceive(XprIO))
					TransferAborted = TRUE;

					/* In case the transfer has been aborted,
					 * flush the input buffer of dirty data.
					 */

				if(TransferAborted)
					xpr_sflush();

					/* Wake the user up. */

				if(TransferWindow)
				{
					WakeUp(TransferWindow);

					WaitTime(2,0);
				}

				if(TransferAborted)
				{
					TransferAborted = FALSE;

					Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
				}
				else
					Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

				Status = OldStatus;

					/* Queue another read request. */

				if(ReadRequest)
				{
					ReadRequest -> IOSer . io_Command	= CMD_READ;
					ReadRequest -> IOSer . io_Data		= ReadBuffer;
					ReadRequest -> IOSer . io_Length	= 1;

					SetSignal(0,SIG_SERIAL);

					SendIO(ReadRequest);
				}

				DeleteTransferPanel();
			}
		}
		else
		{
				/* Download the file(s). */

			if(FileRequest = GetFile(ReceiveQuery[Type],DownloadPath,"",DummyBuffer,NULL,TRUE,FALSE,FALSE,LocaleString(MSG_TERMTRANSFER_RECEIVE_TXT)))
			{
					/* Save the download path. */

				strcpy(DownloadPath,FileRequest -> rf_Dir);

					/* Install the name of the file to receive. */

				XprIO -> xpr_filename = DummyBuffer;

					/* Open the transfer panel. */

				if(TransferPanel(ReceiveQuery[Type]))
				{
					Status = STATUS_DOWNLOAD;

					ClearSerial();

					LogAction(LocaleString(MSG_TERMTRANSFER_LOGMSG_INITIATE_DOWNLOAD_TXT),TransferTypes[Type]);

						/* Receive the file. */

					if(!XProtocolReceive(XprIO))
						TransferAborted = TRUE;

						/* In case the transfer has been aborted,
						 * flush the input buffer of dirty data.
						 */

					if(TransferAborted)
						xpr_sflush();

						/* Wake the user up. */

					if(TransferWindow)
					{
						WakeUp(TransferWindow);

						WaitTime(2,0);
					}

					if(TransferAborted)
					{
						TransferAborted = FALSE;

						Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
					}
					else
						Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

					Status = OldStatus;

						/* Close the transfer panel. */

					DeleteTransferPanel();

						/* Queue another read
						 * request.
						 */

					if(ReadRequest)
					{
						ReadRequest -> IOSer . io_Command	= CMD_READ;
						ReadRequest -> IOSer . io_Data		= ReadBuffer;
						ReadRequest -> IOSer . io_Length	= 1;

						SetSignal(0,SIG_SERIAL);

						SendIO(ReadRequest);
					}
				}

				FreeAslRequest(FileRequest);
			}
		}
	}

	if(SendAbort && UsesZModem)
		SerWrite(ZModemCancel,20);

	SendAbort = FALSE;

	ReleaseWindows();

	DownloadPath = NULL;

	DidTransfer = FALSE;

	if(Config . CommandConfig . DownloadMacro[0])
		SerialCommand(Config . CommandConfig . DownloadMacro);
}

	/* StartXprSend():
	 *
	 *	Send files via xpr.
	 */

BYTE
StartXprSend(BYTE Type)
{
	struct FileRequester	*FileRequest;
	UBYTE			 DummyBuffer[256];
	BYTE			 OldStatus = Status;
	UBYTE			*UploadPath;
	BYTE			 DidSend = TRUE;

	LocalizeString(SendQuery,MSG_TERMTRANSFER_UPLOAD_FILE_TXT,MSG_TERMTRANSFER_UPLOAD_ASCII_TXT);
	LocalizeString(TransferTypes,MSG_TERMTRANSFER_BINARY_TXT,MSG_TERMTRANSFER_ASCII_TXT);

		/* We are uploading data. */

	Uploading = TRUE;

		/* Select the upload path. */

	switch(Type)
	{
		case TRANSFER_BINARY:	UploadPath = Config . PathConfig . BinaryUploadPath;
					break;

		case TRANSFER_TEXT:	UploadPath = Config . PathConfig . TextUploadPath;
					break;

		case TRANSFER_ASCII:	UploadPath = Config . PathConfig . ASCIIUploadPath;
					break;
	}

	BlockWindows();

		/* If not initialized, try to set up a new
		 * external transfer protocol.
		 */

	if(!XProtocolBase)
	{
		NewLibrary = FALSE;

		xpr_options(0,NULL);

		if(NewLibrary)
		{
			if(ProtocolSetup())
			{
				SaveProtocolOpts();

				strcpy(Config . FileConfig . ProtocolFileName,LastXprLibrary);
			}
		}
	}

	if(XProtocolBase)
	{
			/* Do we need to use our own file requester or
			 * will xpr handle this job for us?
			 */

		if(TransferBits & XPRS_NOSNDREQ)
		{
				/* Open the transfer info window. */

			if(TransferPanel(SendQuery[Type]))
			{
				BYTE Aborted;

				Status = STATUS_UPLOAD;

					/* Shut up the serial line. */

				ClearSerial();

				LogAction(LocaleString(MSG_TERMTRANSFER_LOGMSG_INITIATE_UPLOAD_TXT),TransferTypes[Type]);

					/* Perform upload. */

				if(!XProtocolSend(XprIO))
					Aborted = TRUE;
				else
					Aborted = FALSE;

				if(TransferWindow)
				{
					WakeUp(TransferWindow);

					WaitTime(2,0);
				}

				if(Aborted)
					Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
				else
					Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

				Status = OldStatus;

					/* Close the info window. */

				DeleteTransferPanel();

					/* And request another character. */

				if(ReadRequest)
				{
					ReadRequest -> IOSer . io_Command	= CMD_READ;
					ReadRequest -> IOSer . io_Data		= ReadBuffer;
					ReadRequest -> IOSer . io_Length	= 1;

					SetSignal(0,SIG_SERIAL);

					SendIO(ReadRequest);
				}
			}
		}
		else
		{
				/* We will need the file requester to find
				 * out which file(s) are to be transferred.
				 * Multiple files and wildcards are
				 * supported as well as plain file names.
				 */

			if(FileRequest = GetFile(SendQuery[Type],UploadPath,"",DummyBuffer,"",FALSE,TRUE,FALSE,LocaleString(MSG_TERMTRANSFER_SEND_TXT)))
			{
				strcpy(UploadPath,FileRequest -> rf_Dir);

				if(FileTransferInfo = BuildFileTransferInfo(FileRequest))
				{
						/* Make sure that at least the
						 * first file gets transferred
						 * in case the protocol does
						 * no support batch upload.
						 */

					XprIO -> xpr_filename = FileTransferInfo -> CurrentFile -> Name;

					if(TransferPanel(SendQuery[Type]))
					{
						BYTE Aborted;

						Status = STATUS_UPLOAD;

						ClearSerial();

						LogAction(LocaleString(MSG_TERMTRANSFER_LOGMSG_INITIATE_UPLOAD_TXT),TransferTypes[Type]);

						if(!XProtocolSend(XprIO))
							Aborted = TRUE;
						else
							Aborted = FALSE;

						if(TransferWindow)
						{
							WakeUp(TransferWindow);

							WaitTime(2,0);
						}

						if(Aborted)
							Say(LocaleString(MSG_GLOBAL_TRANSFER_FAILED_OR_ABORTED_TXT));
						else
							Say(LocaleString(MSG_GLOBAL_TRANSFER_COMPLETED_TXT));

						Status = OldStatus;

						DeleteTransferPanel();

						if(ReadRequest)
						{
							ReadRequest -> IOSer . io_Command	= CMD_READ;
							ReadRequest -> IOSer . io_Data		= ReadBuffer;
							ReadRequest -> IOSer . io_Length	= 1;

							SetSignal(0,SIG_SERIAL);

							SendIO(ReadRequest);
						}
					}
					else
						MyEasyRequest(Window,LocaleString(MSG_TERMTRANSFER_FAILED_TO_LOCATE_DIRECTORY_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),FileRequest -> rf_Dir);

					if(FileTransferInfo)
					{
						FreeFileTransferInfo(FileTransferInfo);

						FileTransferInfo = NULL;
					}
				}

				FreeAslRequest(FileRequest);
			}
			else
				DidSend = FALSE;
		}
	}

	if(SendAbort && UsesZModem)
		SerWrite(ZModemCancel,20);

	SendAbort = FALSE;

	ReleaseWindows();

	Uploading = FALSE;

	if(Config . CommandConfig . UploadMacro[0])
		SerialCommand(Config . CommandConfig . UploadMacro);

	DidTransfer = FALSE;

	return(DidSend);
}

	/* ASCIISetup():
	 *
	 *	Set up xprascii.library for plain ASCII file
	 *	transfer. This routine temporarily selects a
	 *	different protocol than currently set.
	 */

BYTE
ASCIISetup()
{
	UBYTE	Options[256];
	STRPTR	Index;

		/* Close the currently opened xpr.library. */

	if(XProtocolBase)
	{
		XProtocolCleanup(XprIO);

		CloseLibrary(XProtocolBase);

		XProtocolBase = NULL;
	}

		/* Use the same path name as the
		 * default protocol.
		 */

	strcpy(Options,Config . FileConfig . ProtocolFileName);

	if(Index = PathPart(Options))
	{
		*Index = 0;

		if(!AddPart(Options,"xprascii.library",256))
			strcpy(Options,"xprascii.library");
	}
	else
		strcpy(Options,"xprascii.library");

		/* Open xprascii.library... */

	if(!(XProtocolBase = (struct Library *)OpenLibrary(Options,0)))
		XProtocolBase = (struct Library *)OpenLibrary("xprascii.library",0);

	if(XProtocolBase)
	{
			/* Clear the interface buffer. */

		memset(XprIO,0,sizeof(struct XPR_IO));

			/* Try to obtain the ASCII settings. */

		if(!GetEnvDOS("xprascii",Options))
			Options[0] = 0;

			/* Initialize the interface buffer. */

		XprIO -> xpr_filename	= Options;
		XprIO -> xpr_fopen	= safe_xpr_fopen;
		XprIO -> xpr_fclose	= safe_xpr_fclose;
		XprIO -> xpr_fread	= safe_xpr_fread;
		XprIO -> xpr_fwrite	= safe_xpr_fwrite;
		XprIO -> xpr_sread	= safe_xpr_sread;
		XprIO -> xpr_swrite	= safe_xpr_swrite;
		XprIO -> xpr_sflush	= safe_xpr_sflush;
		XprIO -> xpr_update	= safe_xpr_update;
		XprIO -> xpr_chkabort	= safe_xpr_chkabort;
		XprIO -> xpr_gets	= safe_xpr_gets;
		XprIO -> xpr_setserial	= safe_xpr_setserial;
		XprIO -> xpr_ffirst	= safe_xpr_ffirst;
		XprIO -> xpr_fnext	= safe_xpr_fnext;
		XprIO -> xpr_finfo	= safe_xpr_finfo;
		XprIO -> xpr_fseek	= safe_xpr_fseek;
		XprIO -> xpr_extension	= 4;
		XprIO -> xpr_options	= safe_xpr_options;
		XprIO -> xpr_unlink	= safe_xpr_unlink;
		XprIO -> xpr_squery	= safe_xpr_squery;
		XprIO -> xpr_getptr	= safe_xpr_getptr;

			/* Initialize it. */

		TransferBits = XProtocolSetup(XprIO);

			/* Successful initialization? */

		if(!(TransferBits & XPRS_SUCCESS))
		{
			MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FAILED_TO_SET_UP_PROTOCOL_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),"xprascii.library");

			CloseLibrary(XProtocolBase);

			XProtocolBase = NULL;

			ProtocolSetup();

			return(FALSE);
		}
	}
	else
	{
		MyEasyRequest(Window,LocaleString(MSG_GLOBAL_FAILED_TO_OPEN_PROTOCOL_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),"xprascii.library");

		ProtocolSetup();

		return(FALSE);
	}

	BinaryTransfer = FALSE;

	return(TRUE);
}

	/* ASCIIShutdown():
	 *
	 *	Close down xprascii.library and reopen the library
	 *	set in the current configuration.
	 */

VOID
ASCIIShutdown()
{
	XProtocolCleanup(XprIO);

	CloseLibrary(XProtocolBase);

	XProtocolBase = NULL;

	BinaryTransfer = TRUE;

	ProtocolSetup();
}
