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

#include "TermGlobal.h"

enum	{	MEN_SKIP=1,MEN_NEWLIB=1,MEN_ONLINE,MEN_ABORT,MEN_QUITPANEL };
enum	{	MEN_OKAY=1,MEN_CANCEL,MEN_LOADSOMEFILE };

STATIC struct NewMenu OptionsMenu[] =
{
	{ NM_TITLE, "Project",			 0 , 0, 0, (APTR)0},
	{  NM_ITEM, "Select New Protocol",	"P", 0, 0, (APTR)MEN_NEWLIB},
	{  NM_ITEM, NM_BARLABEL,		 0 , 0, 0, (APTR)0},
	{  NM_ITEM, "Quit",			"Q", 0, 0, (APTR)MEN_QUITPANEL},
	{ NM_END, 0,				 0 , 0, 0, (APTR)0}
};

struct NewMenu GetsMenu[] =
{
	{ NM_TITLE, "Project",		 0 , 0, 0, (APTR)0},
	{  NM_ITEM, "Okay",		"O", 0, 0, (APTR)MEN_OKAY},
	{  NM_ITEM, "Cancel",		"C", 0, 0, (APTR)MEN_CANCEL},
	{  NM_ITEM, NM_BARLABEL,	 0 , 0, 0, (APTR)0},
	{  NM_ITEM, "Quit",		"Q", 0, 0, (APTR)MEN_QUITPANEL},
	{ NM_END, 0,			 0 , 0, 0, (APTR)0}
};

	/* This tiny flag controls whether xpr_fopen opened a file
	 * for writing/appending or not. Since only a single library is
	 * allowed to make the call a single variable may suffice.
	 */

STATIC BYTE FileWrite;

	/* xpr_fopen(UBYTE *FileName,UBYTE *AccessMode):
	 *
	 *	Open a file for random access.
	 */

LONG __saveds __asm
xpr_fopen(register __a0 UBYTE *FileName,register __a1 UBYTE *AccessMode)
{
	BPTR File = NULL,SomeLock;

	switch(AccessMode[0])
	{
		case 'r':	if(AccessMode[1] == '+')
					File = Open(FileName,MODE_READWRITE);
				else
					File = Open(FileName,MODE_OLDFILE);

				if(File)
					LogAction("Send file \"%s\".",FileName);

				break;

		case 'w':	if(AccessMode[1] == '+')
				{
					if(SomeLock = Lock(FileName,ACCESS_WRITE))
					{
						UnLock(SomeLock);

						DeleteFile(FileName);
					}

					File = Open(FileName,MODE_READWRITE);
				}
				else
					File = Open(FileName,MODE_NEWFILE);

				if(File)
				{
					FileWrite = TRUE;

					LogAction("Receive file \"%s\".",FileName);
				}

				AddDownloadObject(FileName);

				break;

		case 'a':	if(SomeLock = Lock(FileName,ACCESS_WRITE))
				{
					UnLock(SomeLock);

					if(File = Open(FileName,MODE_READWRITE))
					{
						if(Seek(File,0,OFFSET_END) == -1)
						{
							Close(File);

							File = NULL;
						}
					}
				}
				else
					File = Open(FileName,MODE_NEWFILE);

				if(File)
				{
					FileWrite = TRUE;

					LogAction("Update file \"%s\".",FileName);
				}

				break;
	}

	return(File);
}

	/* xpr_fclose(BPTR File):
	 *
	 *	Close a file opened by xpr_fopen.
	 */

LONG __saveds __asm
xpr_fclose(register __a0 BPTR File)
{
	UBYTE SomeBuffer[256];
	LONG Success;

	Success = NameFromFH(File,SomeBuffer,256);

	Close(File);

	if(Success)
	{
		if(!GetFileSize(SomeBuffer))
		{
			if(FileWrite)
			{
				DeleteFile(SomeBuffer);

				LogAction("Close file \"%s\" (incomplete file removed).",SomeBuffer);
			}
			else
				LogAction("Close file \"%s\".",SomeBuffer);
		}
		else
		{
			LogAction("Close file \"%s\".",SomeBuffer);

				/* Try to identify the file type. */

			if(FileWrite)
				Identify(SomeBuffer);
		}
	}

	FileWrite = FALSE;

	return(1);
}

	/* xpr_fread(APTR Buffer,LONG Size,LONG Count,BPTR File):
	 *
	 *	Read a few bytes from a file.
	 */

LONG __saveds __asm
xpr_fread(register __a0 APTR Buffer,register __d0 LONG Size,register __d1 LONG Count,register __a1 BPTR File)
{
	return(Read(File,Buffer,Size * Count) / Size);
}

	/* xpr_fwrite(APTR Buffer,LONG Size,LONG Count,BPTR File):
	 *
	 *	Write a few bytes to a file.
	 */

LONG __saveds __asm
xpr_fwrite(register __a0 APTR Buffer,register __d0 LONG Size,register __d1 LONG Count,register __a1 BPTR File)
{
	return(Write(File,Buffer,Size * Count) / Size);
}

	/* xpr_sread(UBYTE *Buffer,LONG Size,LONG Timeout):
	 *
	 *	Read a few bytes from the serial port (including
	 *	timeouts).
	 */

ULONG __saveds __asm
xpr_sread(register __a0 UBYTE *Buffer,register __d0 LONG Size,register __d1 LONG Timeout)
{
	if(!WriteRequest)
		return(0);

	if(Size)
	{
		ULONG SignalSet,Length;

		if(Timeout < 1)
		{
			WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

			DoIO(WriteRequest);

			if((Length = WriteRequest -> IOSer . io_Actual) > 0)
			{
				if(Length > Size)
					Length = Size;

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

				DoIO(ReadRequest);
			}

			return(Length);
		}

		TimeRequest -> tr_node . io_Command	= TR_ADDREQUEST;
		TimeRequest -> tr_time . tv_secs	= Timeout >= MILLION ? Timeout / MILLION : 0;
		TimeRequest -> tr_time . tv_micro	= Timeout % MILLION;

		ReadRequest -> IOSer . io_Command	= CMD_READ;
		ReadRequest -> IOSer . io_Data		= Buffer;
		ReadRequest -> IOSer . io_Length	= Size;

			/* Prevent early termination. */

		SetSignal(0,(1 << ReadPort -> mp_SigBit) | (1 << TimeRequest -> tr_node . io_Message . mn_ReplyPort -> mp_SigBit));

		SendIO(ReadRequest);
		SendIO(TimeRequest);

		FOREVER
		{
			SignalSet = (1 << ReadPort -> mp_SigBit) | (1 << TimeRequest -> tr_node . io_Message . mn_ReplyPort -> mp_SigBit);

			if(TransferWindow)
				SignalSet |= 1 << TransferWindow -> UserPort -> mp_SigBit;

			SignalSet = Wait(SignalSet);

			if(SignalSet & (1 << TimeRequest -> tr_node . io_Message . mn_ReplyPort -> mp_SigBit))
			{
				WaitIO(TimeRequest);

				AbortIO(ReadRequest);
				WaitIO(ReadRequest);

				return(ReadRequest -> IOSer . io_Actual);
			}

			if(SignalSet & (1 << ReadPort -> mp_SigBit))
			{
				WaitIO(ReadRequest);

				AbortIO(TimeRequest);
				WaitIO(TimeRequest);

				return(ReadRequest -> IOSer . io_Actual);
			}

			if(TransferWindow)
			{
				if(SignalSet & (1 << TransferWindow -> UserPort -> mp_SigBit))
				{
					if(xpr_chkabort() == -1)
					{
						AbortIO(TimeRequest);
						WaitIO(TimeRequest);

						AbortIO(ReadRequest);
						WaitIO(ReadRequest);

						return(-1);
					}
				}
			}
		}
	}

	return(0);
}

	/* xpr_swrite(UBYTE *Buffer,LONG Size):
	 *
	 *	Write a few bytes to the serial port.
	 */

LONG __saveds __asm
xpr_swrite(register __a0 UBYTE *Buffer,register __d0 LONG Size)
{
	if(!WriteRequest)
		return(-1);

	WriteRequest -> IOSer . io_Command	= CMD_WRITE;
	WriteRequest -> IOSer . io_Data		= Buffer;
	WriteRequest -> IOSer . io_Length	= Size;

	return((LONG)DoIO(WriteRequest));
}

	/* xpr_sflush():
	 *
	 *	Release the contents of all serial buffers.
	 */

LONG __saveds
xpr_sflush()
{
	if(!WriteRequest)
		return(-1);

	WriteRequest -> IOSer . io_Command = CMD_CLEAR;

	return((LONG)DoIO(WriteRequest));
}

	/* xpr_update(struct XPR_UPDATE *UpdateInfo):
	 *
	 *	Update the information displayed in the transfer window.
	 */

LONG __saveds __asm
xpr_update(register __a0 struct XPR_UPDATE *UpdateInfo)
{
	if(!TransferWindow)
	{
		BlockWindows();

		LogAction("Initiate binary download.");

		if(!TransferPanel("Receive File(s)"))
		{
			ReleaseWindows();

			return(0);
		}
	}

	if(UpdateInfo)
	{
		if((UpdateInfo -> xpru_updatemask & XPRU_PROTOCOL) && UpdateInfo -> xpru_protocol)
			TransferInfo(20, 0,"%-50.50s",UpdateInfo -> xpru_protocol);

		if((UpdateInfo -> xpru_updatemask & XPRU_FILENAME) && UpdateInfo -> xpru_filename)
			TransferInfo(20, 2,"%-50.50s",UpdateInfo -> xpru_filename);

		if((UpdateInfo -> xpru_updatemask & XPRU_FILESIZE) && UpdateInfo -> xpru_filesize != -1)
			TransferInfo(20, 3,"%ld",UpdateInfo -> xpru_filesize);

		if((UpdateInfo -> xpru_updatemask & XPRU_BYTES) && UpdateInfo -> xpru_bytes != -1)
			TransferInfo(20, 5,"%ld",UpdateInfo -> xpru_bytes);

		if((UpdateInfo -> xpru_updatemask & XPRU_BLOCKS) && UpdateInfo -> xpru_blocks != -1)
			TransferInfo(55, 5,"%ld",UpdateInfo -> xpru_blocks);

		if((UpdateInfo -> xpru_updatemask & XPRU_BLOCKCHECK) && UpdateInfo -> xpru_blockcheck)
			TransferInfo(20, 6,"%-14.14s",UpdateInfo -> xpru_blockcheck);

		if((UpdateInfo -> xpru_updatemask & XPRU_BLOCKSIZE) && UpdateInfo -> xpru_blocksize != -1)
			TransferInfo(55, 6,"%ld",UpdateInfo -> xpru_blocksize);

		if((UpdateInfo -> xpru_updatemask & XPRU_EXPECTTIME) && UpdateInfo -> xpru_expecttime)
			TransferInfo(20, 8,"%-14.14s",UpdateInfo -> xpru_expecttime);

		if((UpdateInfo -> xpru_updatemask & XPRU_ELAPSEDTIME) && UpdateInfo -> xpru_elapsedtime)
			TransferInfo(55, 8,"%-14.14s",UpdateInfo -> xpru_elapsedtime);

		if((UpdateInfo -> xpru_updatemask & XPRU_MSG) && UpdateInfo -> xpru_msg)
			TransferInfo(20,10,"%-50.50s",UpdateInfo -> xpru_msg);

		if((UpdateInfo -> xpru_updatemask & XPRU_ERRORMSG) && UpdateInfo -> xpru_errormsg)
			TransferInfo(20,11,"%-50.50s",UpdateInfo -> xpru_errormsg);

		if((UpdateInfo -> xpru_updatemask & XPRU_ERRORS) && UpdateInfo -> xpru_errors != -1)
			TransferInfo(20,13,"%ld",UpdateInfo -> xpru_errors);

		if((UpdateInfo -> xpru_updatemask & XPRU_TIMEOUTS) && UpdateInfo -> xpru_timeouts != -1)
			TransferInfo(55,13,"%ld",UpdateInfo -> xpru_timeouts);

		if((UpdateInfo -> xpru_updatemask & XPRU_PACKETTYPE) && UpdateInfo -> xpru_packettype != -1)
			TransferInfo(20,15,"%ld/%lc",UpdateInfo -> xpru_packettype,UpdateInfo -> xpru_packettype);

		if((UpdateInfo -> xpru_updatemask & XPRU_PACKETDELAY) && UpdateInfo -> xpru_packetdelay != -1)
			TransferInfo(55,15,"%ld",UpdateInfo -> xpru_packetdelay);

		if((UpdateInfo -> xpru_updatemask & XPRU_DATARATE) && UpdateInfo -> xpru_datarate != -1)
			TransferInfo(20,16,"%ld",UpdateInfo -> xpru_datarate);

		if((UpdateInfo -> xpru_updatemask & XPRU_CHARDELAY) && UpdateInfo -> xpru_chardelay != -1)
			TransferInfo(55,16,"%ld",UpdateInfo -> xpru_chardelay);
	}

	return(1);
}

	/* xpr_chkabort():
	 *
	 *	Check if the user has aborted the transfer.
	 */

LONG __saveds
xpr_chkabort()
{
	if(TransferWindow)
	{
		struct IntuiMessage	*Massage;
		ULONG			 Class,Code;
		struct Gadget		*Gadget;

		while(Massage = (struct IntuiMessage *)GT_GetIMsg(TransferWindow -> UserPort))
		{
			Class	= Massage -> Class;
			Code	= Massage -> Code;
			Gadget	= (struct Gadget *)Massage -> IAddress;

			GT_ReplyIMsg(Massage);

			if(Class == IDCMP_MENUPICK)
			{
				struct MenuItem *MenuItem;

				while(Code != MENUNULL)
				{
					MenuItem = ItemAddress(TransferMenu,Code);

					switch((ULONG)MENU_USERDATA(MenuItem))
					{
						case MEN_ABORT:
						case MEN_QUITPANEL:	LogAction("Transfer aborted.");

									return(-1);

									break;

						case MEN_SKIP:		LogAction("File skipped.");

									return(1);

						default:		break;
					}

					Code = MenuItem -> NextSelect;
				}
			}

			if(Class == IDCMP_CLOSEWINDOW)
			{
				LogAction("Transfer aborted.");

				return(-1);
			}

			if(Class == IDCMP_GADGETUP)
			{
				if(Gadget -> GadgetID == 0)
				{
					LogAction("Transfer aborted.");

					return(-1);
				}

				if(Gadget -> GadgetID == 1)
				{
					LogAction("File skipped.");

					return(1);
				}
			}
		}
	}

	return(0);
}

	/* The following subroutine creates the gadgets required by
	 * xpr_gets().
	 */

struct Gadget *
CreateAllGetsGadgets(BYTE LoadGadget,UBYTE *String,UBYTE *Prompt,LONG *WindowWidth,struct Gadget **GadgetArray,struct Gadget **GadgetList,APTR VisualInfo,UWORD TopEdge)
{
	struct Gadget		*Gadget;
	struct NewGadget	 NewGadget;
	UWORD			 Counter = 0;

	if(Gadget = CreateContext(GadgetList))
	{
		SHORT Width = strlen(Prompt);

		if(Width < 40)
			Width = 40;

		NewGadget . ng_Width		= Width * 8 + 6;
		NewGadget . ng_Height		= 12;
		NewGadget . ng_GadgetText	= Prompt;
		NewGadget . ng_TextAttr		= &DefaultFont;
		NewGadget . ng_VisualInfo	= VisualInfo;
		NewGadget . ng_GadgetID		= Counter;
		NewGadget . ng_Flags		= NG_HIGHLABEL|PLACETEXT_ABOVE;
		NewGadget . ng_LeftEdge		= 10;
		NewGadget . ng_TopEdge		= 1 + TopEdge + 8 + 8;

		GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget,
			GTST_MaxChars,	256,
			GTST_String,	String,
		TAG_DONE);

		NewGadget . ng_Width		= 52;
		NewGadget . ng_Height		= 12;
		NewGadget . ng_GadgetText	= "_Okay";
		NewGadget . ng_GadgetID		= Counter;
		NewGadget . ng_Flags		= 0;
		NewGadget . ng_TopEdge		= Gadget -> TopEdge + Gadget -> Height + 3;

		GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
			GT_Underscore,	'_',
		TAG_DONE);

		if(LoadGadget)
		{
			NewGadget . ng_Width		= 76;
			NewGadget . ng_GadgetText	= "_Load File";
			NewGadget . ng_GadgetID		= Counter;
			NewGadget . ng_LeftEdge		= (Width * 8 + 6 - NewGadget . ng_Width) >> 1;

			GadgetArray[Counter] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
				GT_Underscore,	'_',
			TAG_DONE);
		}

		Counter++;

		NewGadget . ng_Width		= 52;
		NewGadget . ng_GadgetText	= "_Cancel";
		NewGadget . ng_GadgetID		= Counter;
		NewGadget . ng_LeftEdge		= GadgetArray[0] -> LeftEdge + GadgetArray[0] -> Width + 6 - NewGadget . ng_Width;

		GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
			GT_Underscore,	'_',
		TAG_DONE);

		if(Gadget)
		{
			*WindowWidth = GadgetArray[0] -> Width + 32;

			DubGadList(GadgetArray[0]);
		}
	}

	return(Gadget);
}

	/* xpr_gets(UBYTE *Prompt,UBYTE *Buffer):
	 *
	 *	Prompt the user for string input.
	 */

LONG __saveds __asm
xpr_gets(register __a0 UBYTE *Prompt,register __a1 UBYTE *Buffer)
{
	struct Gadget	*GadgetList;
	struct Gadget	*GadgetArray[4];
	struct Window	*PanelWindow;
	struct Menu	*PanelMenu;
	LONG		 Width,Success = FALSE;

	if(!Prompt)
		Prompt = "Input Required";

	if(CreateAllGetsGadgets(FALSE,Buffer,Prompt,&Width,&GadgetArray[0],&GadgetList,VisualInfo,Screen -> WBorTop + Screen -> Font -> ta_YSize + 1))
	{
		if(PanelMenu = CreateMenus(GetsMenu,
			GTMN_FrontPen, 0,
		TAG_DONE))
		{
			if(LayoutMenus(PanelMenu,VisualInfo,
				GTMN_TextAttr,&DefaultFont,
			TAG_DONE))
			{
				if(PanelWindow = OpenWindowTags(NULL,
					WA_Width,	Width,
					WA_Height,	56,

					WA_Left,	(Screen -> Width - Width) >> 1,
					WA_Top,		(Screen -> Height - 56) >> 1,

					WA_Activate,	TRUE,
					WA_DragBar,	TRUE,
					WA_DepthGadget,	TRUE,
					WA_CloseGadget,	TRUE,
					WA_RMBTrap,	TRUE,
					WA_CustomScreen,Screen,

					WA_IDCMP,	IDCMP_GADGETDOWN | IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_MENUPICK | IDCMP_RAWKEY,

					WA_Title,	"Enter A String",
				TAG_DONE))
				{
					struct IntuiMessage	*Massage;
					ULONG			 Class,Code;
					struct Gadget		*Gadget;
					BYTE			 Terminated = FALSE;

					PushWindow(PanelWindow);

					SetMenuStrip(PanelWindow,PanelMenu);

					PanelWindow -> Flags &= ~WFLG_RMBTRAP;

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

					ActiveGadget = GadgetArray[0];

					ActivateGadget(GadgetArray[0],PanelWindow,NULL);

					while(!Terminated)
					{
						WaitPort(PanelWindow -> UserPort);

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

							GT_ReplyIMsg(Massage);

							if(Class == IDCMP_GADGETDOWN)
							{
								if((Gadget -> GadgetType & GTYP_GTYPEMASK) == STRGADGET)
									ActiveGadget = Gadget;
							}

							if(Class == IDCMP_RAWKEY)
							{
								if(Code == IECODE_UP_PREFIX|103 && CommandWindow == PanelWindow)
									ActivateGadget(CommandGadget,PanelWindow,NULL);
							}

							if(Class == IDCMP_ACTIVEWINDOW)
								ActivateGadget(GadgetArray[0],PanelWindow,NULL);

							if(Class == IDCMP_MENUPICK)
							{
								struct MenuItem *MenuItem;

								while(Code != MENUNULL)
								{
									MenuItem = ItemAddress(PanelMenu,Code);

									switch((ULONG)MENU_USERDATA(MenuItem))
									{
										case MEN_CANCEL:
										case MEN_QUITPANEL:	Class = IDCMP_CLOSEWINDOW;
													break;

										case MEN_OKAY:		strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);

													Success = TRUE;

													Terminated = TRUE;
													break;
									}

									Code = MenuItem -> NextSelect;
								}

								if(ActiveGadget)
									ActivateGadget(ActiveGadget,PanelWindow,NULL);
							}

							if(Class == IDCMP_CLOSEWINDOW)
								Terminated = TRUE;

							if(Class == IDCMP_GADGETUP)
							{
								if(!DontActivate)
								{
									switch(Gadget -> GadgetID)
									{
										case 0:
										case 1:	strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);

											Success = TRUE;

											Terminated = TRUE;
											break;

										case 3:	Terminated = TRUE;
											break;
									}
								}
								else
									DontActivate = FALSE;
							}
						}
					}

					PanelWindow -> Flags |= WFLG_RMBTRAP;

					ClearMenuStrip(PanelWindow);

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

					PopWindow();

					CloseWindow(PanelWindow);
				}

				FreeGadgets(GadgetList);
			}

			FreeMenus(PanelMenu);
		}
	}

	return(Success);
}

	/* xpr_setserial(LONG Status):
	 *
	 *	Set/read the serial status (parameters).
	 */

LONG __saveds __asm
xpr_setserial(register __d0 LONG Status)
{
	STATIC LONG XprBauds[12] =
	{
		110,
		300,
		1200,
		2400,
		4800,
		9600,
		19200,
		31250,
		38400,
		57600,
		76800,
		115200
	};

	LONG Return,i;

	if(!WriteRequest)
		return(-1);

	WriteRequest -> IOSer . io_Command = SDCMD_QUERY;
	DoIO(WriteRequest);

	Return = WriteRequest -> io_SerFlags & 0xFF;

	if(WriteRequest -> io_ExtFlags & SEXTF_MSPON)
		Return |= ST_PARTYMARKON;

	if(WriteRequest -> io_ExtFlags & SEXTF_MARK)
		Return |= ST_PARTYMARK;

	if(WriteRequest -> io_StopBits == 2)
		Return |= ST_2BITS;

	if(WriteRequest -> io_ReadLen == 7)
		Return |= ST_READ7;

	if(WriteRequest -> io_WriteLen == 7)
		Return |= ST_WRITE7;

	for(i = 0 ; i < 12 ; i++)
	{
		if(WriteRequest -> io_Baud == XprBauds[i])
		{
			Return |= (i << 16);

			break;
		}
	}

	if(Status != -1)
	{
		WriteRequest -> IOSer . io_Command	= SDCMD_SETPARAMS;

		WriteRequest -> io_SerFlags		= Status & 0xFF;
		WriteRequest -> io_ExtFlags		= 0;

		if(Status & ST_PARTYMARKON)
			WriteRequest -> io_ExtFlags |= SEXTF_MSPON;

		if(Status & ST_PARTYMARK)
			WriteRequest -> io_ExtFlags |= SEXTF_MARK;

		if(Status & ST_2BITS)
			WriteRequest -> io_StopBits = 2;
		else
			WriteRequest -> io_StopBits = 1;

		if(Status & ST_READ7)
			WriteRequest -> io_ReadLen = 7;
		else
			WriteRequest -> io_ReadLen = 8;

		if(Status & ST_WRITE7)
			WriteRequest -> io_WriteLen = 7;
		else
			WriteRequest -> io_WriteLen = 8;

		DoIO(WriteRequest);

		ReadRequest -> io_SerFlags	= WriteRequest -> io_SerFlags;
		ReadRequest -> io_ExtFlags	= WriteRequest -> io_ExtFlags;

		ReadRequest -> io_StopBits	= WriteRequest -> io_StopBits;
		ReadRequest -> io_ReadLen	= WriteRequest -> io_ReadLen;
		ReadRequest -> io_WriteLen	= WriteRequest -> io_WriteLen;
	}

	return(Return);
}

	/* xpr_ffirst(UBYTE *Buffer,UBYTE *Pattern):
	 *
	 *	Batch file upload: find the first matching file and return
	 *	its name.
	 */

LONG __saveds __asm
xpr_ffirst(register __a0 UBYTE *Buffer,register __a1 UBYTE *Pattern)
{
	if(MultipleFiles)
	{
		FileCount = 0;

		strcpy(Buffer,FileArg[FileCount++] . wa_Name);

		return(1);
	}
	else
	{
		FileMatch = TRUE;

		if(!MatchFirst(Pattern,FileAnchor))
		{
			if(FileAnchor -> ap_Info . fib_DirEntryType < 0)
			{
				strcpy(Buffer,FileAnchor -> ap_Info . fib_FileName);

				return(1);
			}
			else
			{
				while(!MatchNext(FileAnchor))
				{
					if(FileAnchor -> ap_Info . fib_DirEntryType < 0)
					{
						strcpy(Buffer,FileAnchor -> ap_Info . fib_FileName);

						return(1);
					}
				}
			}
		}
	}

	return(0);
}

	/* xpr_fnext(LONG OldState,UBYTE *Buffer,UBYTE *Pattern):
	 *
	 *	Batch file upload: find the next matching file
	 *	- if any - and return its name.
	 */

LONG __saveds __asm
xpr_fnext(register __d0 LONG OldState,register __a0 UBYTE *Buffer,register __a1 UBYTE *Pattern)
{
	if(MultipleFiles)
	{
		if(FileCount < FileCountMax)
		{
			strcpy(Buffer,FileArg[FileCount++] . wa_Name);
			return(1);
		}
	}
	else
	{
		while(!MatchNext(FileAnchor))
		{
			if(FileAnchor -> ap_Info . fib_DirEntryType < 0)
			{
				strcpy(Buffer,FileAnchor -> ap_Info . fib_FileName);
				return(1);
			}
		}
	}

	return(0);
}

	/* xpr_finfo(UBYTE *FileName,LONG InfoType):
	 *
	 *	Return information on a given file.
	 */

LONG __saveds __asm
xpr_finfo(register __a0 UBYTE *FileName,register __d0 LONG InfoType)
{
	struct FileInfoBlock	*FileInfo;
	BPTR			 FileLock;

	if(InfoType == 1)
	{
		LONG Size = 0;

		if(FileInfo = AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
		{
			if(FileLock = Lock(FileName,ACCESS_READ))
			{
				if(Examine(FileLock,FileInfo))
					Size = FileInfo -> fib_Size;

				UnLock(FileLock);
			}

			FreeMem(FileInfo,sizeof(struct FileInfoBlock));
		}

		return(Size);
	}

	if(InfoType == 2)
		return(BinaryTransfer ? 1 : 2);
}

	/* xpr_fseek(BPTR File,LONG Offset,LONG Origin):
	 *
	 *	Move the read/write pointer in a file.
	 */

LONG __saveds __asm
xpr_fseek(register __a0 BPTR File,register __d0 LONG Offset,register __d1 LONG Origin)
{
	switch(Origin)
	{
		case 0:	Origin = OFFSET_BEGINNING;
			break;

		case 1:	Origin = OFFSET_CURRENT;
			break;

		case 2:	Origin = OFFSET_END;
			break;

		default:return(-1);
	}

	if(Seek(File,Offset,Origin) == -1)
		return(-1);
	else
		return(0);
}

	/* The following routines are to support the xpr_options function. */

STATIC BYTE
GetOptionMode(struct xpr_option *Option)
{
	if(Option)
	{
		if(!StrCmp(Option -> xpro_value,"OFF"))
			return(FALSE);

		if(!StrCmp(Option -> xpro_value,"FALSE"))
			return(FALSE);

		if(!StrCmp(Option -> xpro_value,"F"))
			return(FALSE);

		if(!StrCmp(Option -> xpro_value,"NO"))
			return(FALSE);

		if(!StrCmp(Option -> xpro_value,"N"))
			return(FALSE);


		if(!StrCmp(Option -> xpro_value,"ON"))
			return(TRUE);

		if(!StrCmp(Option -> xpro_value,"TRUE"))
			return(TRUE);

		if(!StrCmp(Option -> xpro_value,"T"))
			return(TRUE);

		if(!StrCmp(Option -> xpro_value,"YES"))
			return(TRUE);

		if(!StrCmp(Option -> xpro_value,"Y"))
			return(TRUE);
	}

	return(FALSE);
}

STATIC struct Gadget *
CreateAllOptionGadgets(LONG *Count,LONG *Width,LONG *Height,LONG NumOpts,struct xpr_option *Opts[],struct Gadget *GadgetArray[],struct Gadget **GadgetList,APTR VisualInfo,UWORD TopEdge)
{
	struct Gadget		*Gadget;
	struct NewGadget	 NewGadget;
	LONG			 i,MaxLength = 0,AddTop = 0;

	*Count = 0;

	if(Gadget = CreateContext(GadgetList))
	{
		NewGadget . ng_TopEdge		= 1 + TopEdge - 2;
		NewGadget . ng_Height		= 12;
		NewGadget . ng_Width		= 208;

		NewGadget . ng_TextAttr		= &DefaultFont;
		NewGadget . ng_VisualInfo	= VisualInfo;
		NewGadget . ng_Flags		= NG_HIGHLABEL;

		for(i = 0 ; i < NumOpts ; i++)
		{
			if(!Opts[i])
				continue;

			switch(Opts[i] -> xpro_type)
			{
				case XPRO_BOOLEAN:

					NewGadget . ng_GadgetText	= Opts[i] -> xpro_description;
					NewGadget . ng_GadgetID		= i;
					NewGadget . ng_LeftEdge		= 218;
					NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + AddTop;

					GadgetArray[i] = Gadget = CreateGadget(CHECKBOX_KIND,Gadget,&NewGadget,
						GTCB_Checked,GetOptionMode(Opts[i]),
					TAG_DONE);

					if(Gadget)
						AddTop = Gadget -> Height + 1;

					break;

				case XPRO_LONG:

					NewGadget . ng_GadgetText	= Opts[i] -> xpro_description;
					NewGadget . ng_GadgetID		= i;
					NewGadget . ng_LeftEdge		= 218;
					NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + AddTop;

					GadgetArray[i] = Gadget = CreateGadget(INTEGER_KIND,Gadget,&NewGadget,
						GTIN_Number,atol(Opts[i] -> xpro_value),
					TAG_DONE);

					AddTop = 13;

					break;

				case XPRO_STRING:
				case XPRO_COMMPAR:

					NewGadget . ng_GadgetText	= Opts[i] -> xpro_description;
					NewGadget . ng_GadgetID		= i;
					NewGadget . ng_LeftEdge		= 218;
					NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + AddTop;

					GadgetArray[i] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget,
						GTST_String,	Opts[i] -> xpro_value,
						GTST_MaxChars,	Opts[i] -> xpro_length,
					TAG_DONE);

					AddTop = 13;

					break;

				case XPRO_HEADER:

					NewGadget . ng_GadgetText	= "";
					NewGadget . ng_GadgetID		= i;
					NewGadget . ng_LeftEdge		= 10;
					NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + AddTop;

					GadgetArray[i] = Gadget = CreateGadget(TEXT_KIND,Gadget,&NewGadget,
						GTTX_Text,Opts[i] -> xpro_description,
					TAG_DONE);

					AddTop = 11;

					break;

				case XPRO_COMMAND:

					NewGadget . ng_GadgetText	= Opts[i] -> xpro_description;
					NewGadget . ng_GadgetID		= i;
					NewGadget . ng_LeftEdge		= 10;
					NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + 13;

					GadgetArray[i] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
						TAG_DONE);

					if(Gadget)
						AddTop = Gadget -> Height + 1;

					MaxLength = 25;

					break;

				default:break;
			}

			if(Gadget)
			{
				if(strlen(NewGadget . ng_GadgetText) > MaxLength)
					MaxLength = strlen(NewGadget . ng_GadgetText);
			}
		}

		NewGadget . ng_GadgetText	= "Current Protocol";
		NewGadget . ng_GadgetID		= 32;
		NewGadget . ng_LeftEdge		= 218;
		NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + AddTop + 2;

		GadgetArray[i++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget,
			GTST_MaxChars,	40,
			GTST_String,	LastXprLibrary,
		TAG_DONE);

		NewGadget . ng_GadgetText	= "Select New _Protocol";
		NewGadget . ng_GadgetID		= 33;
		NewGadget . ng_TopEdge		= NewGadget . ng_TopEdge + 13;

		GadgetArray[i++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
			GT_Underscore,	'_',
		TAG_DONE);

		if(Gadget)
		{
			*Height = Gadget -> TopEdge + Gadget -> Height + 3;

			if(MaxLength < 16)
				MaxLength = 16;

			if(MaxLength < 25)
			{
				LONG j;

				MaxLength = (25 - MaxLength) * 8;

				for(j = 0 ; j < NumOpts ; j++)
				{
					if(Opts[j] && GadgetArray[j])
					{
						if(Opts[j] -> xpro_type != XPRO_HEADER)
							GadgetArray[j] -> LeftEdge -= MaxLength;
					}
				}

				GadgetArray[i - 1] -> LeftEdge -= MaxLength;
				GadgetArray[i - 2] -> LeftEdge -= MaxLength;
			}

			*Width = Gadget -> LeftEdge + Gadget -> Width + 10;

			*Count = i;
		}
	}

	DubGadList(GadgetArray[0]);

	return(Gadget);
}

	/* xpr_options(LONG NumOpts,struct xpr_option **Opts):
	 *
	 *	Provide a more polished user interface to set the
	 *	transfer protocol options.
	 */

ULONG __saveds __asm
xpr_options(register __d0 LONG NumOpts,register __a0 struct xpr_option **Opts)
{
	struct Gadget	*GadgetList;
	struct Gadget	*GadgetArray[33];
	struct Window	*PanelWindow;
	struct Menu	*PanelMenu;
	LONG		 Width,Height,i,Count;

	ULONG		 Flags = 0;

	if(CreateAllOptionGadgets(&Count,&Width,&Height,NumOpts,Opts,&GadgetArray[0],&GadgetList,VisualInfo,Screen -> WBorTop + Screen -> Font -> ta_YSize + 1))
	{
		if(PanelMenu = CreateMenus(OptionsMenu,
			GTMN_FrontPen, 0,
		TAG_DONE))
		{
			if(LayoutMenus(PanelMenu,VisualInfo,
				GTMN_TextAttr,&DefaultFont,
			TAG_DONE))
			{
				if(PanelWindow = OpenWindowTags(NULL,
					WA_Width,	Width,
					WA_Height,	Height,

					WA_Left,	(Screen -> Width - Width) >> 1,
					WA_Top,		(Screen -> Height - Height) >> 1,

					WA_Activate,	TRUE,
					WA_DragBar,	TRUE,
					WA_DepthGadget,	TRUE,
					WA_CloseGadget,	TRUE,
					WA_RMBTrap,	TRUE,
					WA_CustomScreen,Screen,

					WA_IDCMP,	IDCMP_GADGETDOWN | IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | CHECKBOXIDCMP | IDCMP_MENUPICK | IDCMP_RAWKEY,

					WA_Title,	"Transfer Preferences",
				TAG_DONE))
				{
					struct IntuiMessage	*Massage;
					ULONG			 Class,Code;
					struct Gadget		*Gadget;
					BYTE			 Terminated = FALSE;

					PushWindow(PanelWindow);

					SetMenuStrip(PanelWindow,PanelMenu);

					PanelWindow -> Flags &= ~WFLG_RMBTRAP;

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

					for(i = 0 ; i < Count ; i++)
					{
						if((GadgetArray[i] -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET)
						{
							ActivateGadget(GadgetArray[i],PanelWindow,NULL);

							ActiveGadget = GadgetArray[i];

							break;
						}
					}

					while(!Terminated)
					{
						WaitPort(PanelWindow -> UserPort);

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

							GT_ReplyIMsg(Massage);

							if(Class == IDCMP_GADGETDOWN)
							{
								if((Gadget -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET)
									ActiveGadget = Gadget;
							}

							if(Class == IDCMP_RAWKEY)
							{
								if(Code == IECODE_UP_PREFIX|103 && CommandWindow == PanelWindow)
									ActivateGadget(CommandGadget,PanelWindow,NULL);
							}

							if(Class == IDCMP_ACTIVEWINDOW && ActiveGadget)
								ActivateGadget(ActiveGadget,PanelWindow,NULL);

							if(Class == IDCMP_MENUPICK)
							{
								struct MenuItem *MenuItem;

								while(Code != MENUNULL)
								{
									MenuItem = ItemAddress(PanelMenu,Code);

									switch((ULONG)MENU_USERDATA(MenuItem))
									{
										case MEN_QUITPANEL:	Class = IDCMP_CLOSEWINDOW;
													break;

										case MEN_NEWLIB:	Class = IDCMP_GADGETUP;
													Gadget = GadgetArray[Count - 1];
													break;
									}

									Code = MenuItem -> NextSelect;
								}

								if(ActiveGadget)
									ActivateGadget(ActiveGadget,PanelWindow,NULL);
							}

							if(Class == IDCMP_CLOSEWINDOW)
							{
								for(i = 0 ; i < NumOpts ; i++)
								{
									switch(Opts[i] -> xpro_type)
									{
										case XPRO_BOOLEAN:	if(((GadgetArray[i] -> Flags & GFLG_SELECTED) && !GetOptionMode(Opts[i])) || (!(GadgetArray[i] -> Flags & GFLG_SELECTED) && GetOptionMode(Opts[i])))
													{
														Flags |= (i << i);

														if(GadgetArray[i] -> Flags & GFLG_SELECTED)
															strcpy(Opts[i] -> xpro_value,"yes");
														else
															strcpy(Opts[i] -> xpro_value,"no");

														NewOptions = TRUE;
													}
													break;

										case XPRO_LONG:
										case XPRO_STRING:
										case XPRO_COMMPAR:	if(strcmp(Opts[i] -> xpro_value,((struct StringInfo *)GadgetArray[i] -> SpecialInfo) -> Buffer))
													{
														Flags |= (i << i);

														strcpy(Opts[i] -> xpro_value,((struct StringInfo *)GadgetArray[i] -> SpecialInfo) -> Buffer);

														NewOptions = TRUE;
													}
													break;
									}
								}

								Terminated = TRUE;
							}

							if(Class == IDCMP_GADGETUP)
							{
								if(Gadget -> GadgetID < NumOpts)
								{
									if(Opts[Gadget -> GadgetID] -> xpro_type == XPRO_COMMAND)
									{
										Flags |= (1 << Gadget -> GadgetID);

										Terminated = TRUE;
									}
								}

								if(Gadget -> GadgetID == 32)
								{
									if(strcmp(LastXprLibrary,((struct StringInfo *)Gadget -> SpecialInfo) -> Buffer))
									{
										strcpy(LastXprLibrary,((struct StringInfo *)Gadget -> SpecialInfo) -> Buffer);
										NewLibrary = TRUE;
									}
								}

								if(Gadget -> GadgetID == 33)
								{
									struct FileRequester *AslFileRequest;

									if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
										ASL_Window,	PanelWindow,
										ASL_File,	((struct StringInfo *)GadgetArray[NumOpts] -> SpecialInfo) -> Buffer,
										ASL_Dir,	"LIBS:",
										ASL_Hail,	"Select Transfer Protocol",
										ASL_FuncFlags,	0,
										ASL_Pattern,	"xpr#?.library",
										ASL_OKText,	"Select",
									TAG_END))
									{
										SetWait(PanelWindow);
										PanelWindow -> Flags |= WFLG_RMBTRAP;

										if(AslRequestTags(AslFileRequest,TAG_DONE))
										{
											if(AslFileRequest -> rf_File[0])
											{
												if(strcmp(AslFileRequest -> rf_File,((struct StringInfo *)GadgetArray[NumOpts] -> SpecialInfo) -> Buffer))
												{
													GT_SetGadgetAttrs(GadgetArray[NumOpts],PanelWindow,NULL,
														GTST_String,AslFileRequest -> rf_File,
													TAG_DONE);

													strcpy(LastXprLibrary,AslFileRequest -> rf_File);

													NewLibrary = TRUE;
												}
											}
										}

										ClearPointer(PanelWindow);
										PanelWindow -> Flags &= ~WFLG_RMBTRAP;

										FreeAslRequest(AslFileRequest);
									}
								}
							}
						}
					}

					PanelWindow -> Flags |= WFLG_RMBTRAP;

					ClearMenuStrip(PanelWindow);

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

					PopWindow();

					CloseWindow(PanelWindow);
				}
			}

			FreeMenus(PanelMenu);
		}

		FreeGadgets(GadgetList);
	}

	return(Flags);
}

	/* xpr_unlink(UBYTE *FileName):
	 *
	 *	Remove (delete) a given file.
	 */

LONG __saveds __asm
xpr_unlink(register __a0 UBYTE *FileName)
{
	LONG Success = DeleteFile(FileName) ? 0 : -1;

	if(Success)
		LogAction("Delete file \"%s\".",FileName);

	return(Success);
}

	/* xpr_squery():
	 *
	 *	Check how many characters are present in the serial buffer.
	 */

LONG __saveds
xpr_squery()
{
	if(!WriteRequest)
		return(-1);

	WriteRequest -> IOSer . io_Command = SDCMD_QUERY;

	if(!DoIO(WriteRequest))
		return((LONG)WriteRequest -> IOSer . io_Actual);
	else
		return(-1);
}

	/* xpr_getptr(LONG InfoType):
	 *
	 *	Return a pointer to the term custom screen.
	 */

LONG __saveds __asm
xpr_getptr(register __d0 LONG InfoType)
{
	if(InfoType == 1)
		return((LONG)Screen);
	else
		return(-1);
}

	/* xpr_stealopts(UBYTE *Prompt,UBYTE *Buffer):
	 *
	 *	Steal the contents of the options buffer (replacement
	 *	for xpr_gets).
	 */

LONG __saveds __asm
xpr_stealopts(register __a0 UBYTE *Prompt,register __a1 UBYTE *Buffer)
{
	if(Buffer)
		strcpy(ProtocolOptsBuffer,Buffer);

	return(1);
}

	/* ProtocolSetup():
	 *
	 *	Set up the library and options for the external protocol.
	 */

BYTE
ProtocolSetup()
{
	UBYTE NameBuffer[40],TestBuffer[40],i;

		/* Close the old library if still open. */

	if(XProtocolBase)
	{
		XProtocolCleanup(XprIO);

		CloseLibrary(XProtocolBase);
	}

		/* Clear the XPR interface buffer. */

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

		/* Copy the name of the library. */

	strcpy(NameBuffer,FilePart(LastXprLibrary));

		/* Extract the name itself (strip the `.library'). */

	for(i = strlen(NameBuffer) - 1 ; i >= 0 ; i--)
	{
		if(NameBuffer[i] == '.')
		{
			NameBuffer[i] = 0;
			break;
		}
	}

		/* Copy the result to the test buffer and check
		 * if the transfer protocol is a sort of ZModem.
		 */

	strcpy(TestBuffer,&NameBuffer[3]);

	TestBuffer[6] = 0;

	if(!StrCmp(TestBuffer,"zmodem"))
		UsesZModem = TRUE;
	else
		UsesZModem = FALSE;

		/* Obtain the protocol default settings. */

	if(!GetEnvDOS(NameBuffer,ProtocolOptsBuffer))
		ProtocolOptsBuffer[0] = 0;

		/* Initialize the interface structure. */

	XprIO -> xpr_filename	= ProtocolOptsBuffer;
	XprIO -> xpr_fopen	= (APTR)xpr_fopen;
	XprIO -> xpr_fclose	= (APTR)xpr_fclose;
	XprIO -> xpr_fread	= (APTR)xpr_fread;
	XprIO -> xpr_fwrite	= (APTR)xpr_fwrite;
	XprIO -> xpr_sread	= (APTR)xpr_sread;
	XprIO -> xpr_swrite	= (APTR)xpr_swrite;
	XprIO -> xpr_sflush	= (APTR)xpr_sflush;
	XprIO -> xpr_update	= (APTR)xpr_update;
	XprIO -> xpr_chkabort	= (APTR)xpr_chkabort;
	XprIO -> xpr_gets	= (APTR)xpr_gets;
	XprIO -> xpr_setserial	= (APTR)xpr_setserial;
	XprIO -> xpr_ffirst	= (APTR)xpr_ffirst;
	XprIO -> xpr_fnext	= (APTR)xpr_fnext;
	XprIO -> xpr_finfo	= (APTR)xpr_finfo;
	XprIO -> xpr_fseek	= (APTR)xpr_fseek;
	XprIO -> xpr_extension	= 4;
	XprIO -> xpr_options	= (APTR)xpr_options;
	XprIO -> xpr_unlink	= (APTR)xpr_unlink;
	XprIO -> xpr_squery	= (APTR)xpr_squery;
	XprIO -> xpr_getptr	= (APTR)xpr_getptr;

		/* Try to open the library. */

	if(XProtocolBase = (struct Library *)OpenLibrary(LastXprLibrary,0))
	{
			/* Set up the library. */

		TransferBits = XProtocolSetup(XprIO);

			/* Successful initialization? */

		if(!(TransferBits & XPRS_SUCCESS))
		{
			MyEasyRequest(Window,"Failed to set up protocol\n\"%s\"!","Continue",LastXprLibrary);

			CloseLibrary(XProtocolBase);

			XProtocolBase = NULL;

			LastXprLibrary[0] = 0;

			TransferBits = 0;

			return(FALSE);
		}
	}
	else
		MyEasyRequest(Window,"Failed to open protocol\n\"%s\"!","Continue",LastXprLibrary);

	return(TRUE);
}

	/* SaveProtocolOpts():
	 *
	 *	Save the current protocol settings to an environment variable.
	 */

VOID
SaveProtocolOpts()
{
		/* It's time to save the altered options. */

	if(NewOptions)
	{
		UBYTE NameBuffer[60],i;

			/* Strip the `.library' part. */

		strcpy(NameBuffer,LastXprLibrary);

		for(i = strlen(NameBuffer) - 1 ; i >= 0 ; i--)
		{
			if(NameBuffer[i] == '.')
			{
				NameBuffer[i] = 0;
				break;
			}
		}

			/* Cause the xpr.library to prompt for
			 * input. We expect the library to fill
			 * the prompt string with the default
			 * settings. The resulting string is
			 * intercepted by xpr_stealopts, saved
			 * to an environment variable and will
			 * serve as a reinitialization string
			 * later.
			 */

		XprIO -> xpr_filename	= NULL;
		XprIO -> xpr_gets	= (APTR)xpr_stealopts;
		XprIO -> xpr_extension	= 4;
		XprIO -> xpr_options	= (APTR)NULL;

		XProtocolSetup(XprIO);

			/* Save the options in case anything goes
			 * wrong.
			 */

		NewOptions = FALSE;

		SetEnvDOS(NameBuffer,ProtocolOptsBuffer);

			/* Reinitialize the library. */

		XprIO -> xpr_filename	= ProtocolOptsBuffer;
		XprIO -> xpr_gets	= (APTR)xpr_gets;
		XprIO -> xpr_extension	= 4;
		XprIO -> xpr_options	= (APTR)xpr_options;

		XProtocolSetup(XprIO);
	}
}
