/*
**	Last modified for v2.4 by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
**		9-Oct-95
**
**	:ts=3
*/

/* $Revision Header built by Ueli Kaufmann ********** (please edit) **********
*
*  Copyright by Ueli Kaufmann
*
* File             : xprascii.library
* Created on       : Monday 28-Dec-92 13:21:45
* Created by       : Ueli Kaufmann
* Email via znet   : U.KAUFMANN@LINK-CH1.ZER
* Email via uucp   : Ueli_Kaufmann@augs1.adsp.sub.org
* Created with     : SAS/C 6.1, Cygnus-Ed V2.12, Shell OS2.04
* Current revision : 2.3
*
*
* Purpose
* -------
*   replacement for xprascii.library v0.9  by Willy Langeveld
*
*****************************************************************************/



/************************/

#include <dos/dosextens.h>

#include <exec/execbase.h>
#include <exec/memory.h>

#include <clib/utility_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#include <pragmas/utility_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>

#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>

#include "xproto.h"
#include "xprascii.h"

STATIC BOOL test(struct XPR_IO *io);
STATIC BOOL setup(struct XPR_IO *io);
STATIC VOID ParseConfigString(struct XPR_IO *io, char *buf);
STATIC UBYTE *FindOption(UBYTE *buf, UBYTE option);
LONG AtoL(STRPTR);
VOID myGetSysTime(ULONG *);
VOID __stdargs upderr(struct XPR_IO *io, UBYTE *err, ...);

struct	ExecBase			*SysBase;
struct	DosLibrary		*DOSBase;
struct	Library			*UtilityBase;

VOID __saveds __asm __UserLibCleanup(register __a6 struct Library *libBase)
{
	if(UtilityBase)
	{
		CloseLibrary(UtilityBase);
		UtilityBase = NULL;
	}

	if(DOSBase)
	{
		CloseLibrary((struct Library *)DOSBase);
		DOSBase = NULL;
	}
}


int __saveds __asm __UserLibInit(register __a6 struct Library *libBase)
{
	SysBase = *(struct ExecBase **)4;

	if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37))
	{
		if(UtilityBase = OpenLibrary("utility.library", 37))
			return(0);
		else
		{
			CloseLibrary(DOSBase);
			DOSBase = NULL;
		}
	}

	return(1);
}


LONG __saveds __asm XProtocolCleanup(register __a0 struct XPR_IO *io)
{
	struct XProtocolData *xData = (struct XProtocolData *)io->xpr_data;

	if(xData != NULL)
	{
		FreeMem(xData, sizeof(struct XProtocolData));
		io->xpr_data = NULL;
	}

	return(XPRS_SUCCESS);
}


STATIC VOID  EncodePromptChar(UBYTE pChar, UBYTE *pBuf);
STATIC UBYTE DecodePromptChar(UBYTE *pBuf);

LONG __saveds __asm XProtocolSetup(register __a0 struct XPR_IO *io)
{
	struct XProtocolData *xData;

	if(test(io) == FALSE)
		return(XPRS_FAILURE);

	if(io->xpr_data == NULL)
	{
		if(setup(io) == FALSE)
			return(XPRS_FAILURE);
	}

	xData = (struct XProtocolData *)io->xpr_data;


	/* If setup string isn't handed to us, ask questions */

	if(io->xpr_filename == NULL)
	{
		if(io->xpr_options != NULL)
		{
			enum { OPT_HEADER=0, OPT_CHARDELAY, OPT_LINEDELAY, OPT_LF_CONVERT,
					 OPT_CR_CONVERT, OPT_UUE, OPT_DEL,
					 OPT_PROMPTCHAR, OPT_EXPANDBLANKS,
					 OPT_STRIPHIBIT };
			ULONG numopts;

			struct xpr_option *opti[11];
			UBYTE charBuf[LONGLEN], lineBuf[LONGLEN], lfBuf[CHARLEN],
					crBuf[CHARLEN], stripBuf[STRINGLEN],
					uueBuf[STRINGLEN], delBuf[STRINGLEN],
					expandBuf[STRINGLEN], promptBuf[10];

			struct xpr_option opt0;
			struct xpr_option opt1;
			struct xpr_option opt2;
			struct xpr_option opt3;
			struct xpr_option opt4;
			struct xpr_option opt5;
			struct xpr_option opt6;
			struct xpr_option opt7;
			struct xpr_option opt8;
			struct xpr_option opt9;
			struct xpr_option opt10;

			opti[0]	= &opt0;
			opti[1]	= &opt1;
			opti[2]	= &opt2;
			opti[3]	= &opt3;
			opti[4]	= &opt4;
			opti[5]	= &opt5;
			opti[6]	= &opt6;
			opti[7]	= &opt7;
			opti[8]	= &opt8;
			opti[9]	= &opt9;
			opti[10]	= &opt10;


			numopts = 0;

			opti[OPT_HEADER]->xpro_description	= "ASCII Options:  [s=send / r=receive]";
			opti[OPT_HEADER]->xpro_type	= XPRO_HEADER;
			opti[OPT_HEADER]->xpro_value	= NULL;
			opti[OPT_HEADER]->xpro_length	= NULL;

/* */

			numopts++;
			opti[OPT_CHARDELAY]->xpro_description	= "Char Delay (ticks) [s]:";
			opti[OPT_CHARDELAY]->xpro_type			= XPRO_LONG;
			sprintf(charBuf, "%ld", xData->CharDelay);
			opti[OPT_CHARDELAY]->xpro_value			= charBuf;
			opti[OPT_CHARDELAY]->xpro_length			= LONGLEN;

/* */

			numopts++;
			opti[OPT_LINEDELAY]->xpro_description	= "Line Delay (ticks) [s]:";
			opti[OPT_LINEDELAY]->xpro_type			= XPRO_LONG;
			sprintf(lineBuf, "%ld", xData->LineDelay);
			opti[OPT_LINEDELAY]->xpro_value			= lineBuf;
			opti[OPT_LINEDELAY]->xpro_length			= LONGLEN;

/* */

			numopts++;
			switch(xData->LF_Mode)
			{
				case STRIP_MODE:
					lfBuf[0] = 'S';
				break;

				case ADD_MODE:
					lfBuf[0] = 'A';
				break;

				case EXCHANGE_MODE:
					lfBuf[0] = 'X';
				break;

				default:
					lfBuf[0] = 'N';
				break;

			}
			lfBuf[1] = '\0';

			opti[OPT_LF_CONVERT]->xpro_description	= "Convert `LF' (N,S,X,A) [s]:";
			opti[OPT_LF_CONVERT]->xpro_type			= XPRO_STRING;
			opti[OPT_LF_CONVERT]->xpro_value			= lfBuf;
			opti[OPT_LF_CONVERT]->xpro_length		= CHARLEN;

/* */

			numopts++;
			switch(xData->CR_Mode)
			{
				case STRIP_MODE:
					crBuf[0] = 'S';
				break;

				case ADD_MODE:
					crBuf[0] = 'A';
				break;

				case EXCHANGE_MODE:
					crBuf[0] = 'X';
				break;

				default:
					crBuf[0] = 'N';
				break;

			}
			crBuf[1] = '\0';

			opti[OPT_CR_CONVERT]->xpro_description	= "Convert `CR' (N,S,X,A) [s]:";
			opti[OPT_CR_CONVERT]->xpro_type			= XPRO_STRING;
			opti[OPT_CR_CONVERT]->xpro_value			= crBuf;
			opti[OPT_CR_CONVERT]->xpro_length		= CHARLEN;

/* */

			numopts++;
			if(xData->BinToASCII != FALSE)
				strcpy(uueBuf, "on");
			else
				strcpy(uueBuf, "off");
			opti[OPT_UUE]->xpro_description	= "Use uuencode & decode [s+r]:";
			opti[OPT_UUE]->xpro_type			= XPRO_BOOLEAN;
			opti[OPT_UUE]->xpro_value			= uueBuf;
			opti[OPT_UUE]->xpro_length			= STRINGLEN;


/* */

			numopts++;
			if(xData->DelTmpFile != FALSE)
				strcpy(delBuf, "on");
			else
				strcpy(delBuf, "off");
			opti[OPT_DEL]->xpro_description	= "Delete uuencoded file [r]:";
			opti[OPT_DEL]->xpro_type			= XPRO_BOOLEAN;
			opti[OPT_DEL]->xpro_value			= delBuf;
			opti[OPT_DEL]->xpro_length			= STRINGLEN;


/* */

			numopts++;
			opti[OPT_PROMPTCHAR]->xpro_description	= "Prompt Char [s]:";
			opti[OPT_PROMPTCHAR]->xpro_type			= XPRO_STRING;
			EncodePromptChar(xData->PromptChar, promptBuf);
			opti[OPT_PROMPTCHAR]->xpro_value			= promptBuf;
			opti[OPT_PROMPTCHAR]->xpro_length		= 10;

/* */

			numopts++;
			if(xData->ExpandBlanks != FALSE)
				strcpy(expandBuf, "on");
			else
				strcpy(expandBuf, "off");
			opti[OPT_EXPANDBLANKS]->xpro_description	= "Expand Blank Lines [s]:";
			opti[OPT_EXPANDBLANKS]->xpro_type			= XPRO_BOOLEAN;
			opti[OPT_EXPANDBLANKS]->xpro_value			= expandBuf;
			opti[OPT_EXPANDBLANKS]->xpro_length			= STRINGLEN;

/* */

			numopts++;
			if(xData->StripHiBit != FALSE)
				strcpy(stripBuf, "on");
			else
				strcpy(stripBuf, "off");
			opti[OPT_STRIPHIBIT]->xpro_description	= "Strip High Bit [r]:";
			opti[OPT_STRIPHIBIT]->xpro_type			= XPRO_BOOLEAN;
			opti[OPT_STRIPHIBIT]->xpro_value			= stripBuf;
			opti[OPT_STRIPHIBIT]->xpro_length		= STRINGLEN;




			io->xpr_options(++numopts, opti);


			xData->CharDelay = AtoL(charBuf);
			if(xData->CharDelay > 500)
				xData->CharDelay = 500;


			xData->LineDelay = AtoL(lineBuf);
			if(xData->LineDelay > 500)
				xData->LineDelay = 500;

			switch(ToUpper(*lfBuf))
			{
				case 'S':	/* Strip LF */
					xData->LF_Mode = STRIP_MODE;
				break;

				case 'A':	/* Add CR */
					xData->LF_Mode = ADD_MODE;
				break;

				case 'X':	/* LF -> CR */
					xData->LF_Mode = EXCHANGE_MODE;
				break;

				default:		/* None */
					xData->LF_Mode = NONE_MODE;
				break;

			}

			switch(ToUpper(*crBuf))
			{
				case 'S':	/* Strip CR */
					xData->CR_Mode = STRIP_MODE;
				break;

				case 'A':	/* Add LF */
					xData->CR_Mode = ADD_MODE;
				break;

				case 'X':	/* CR -> LF */
					xData->CR_Mode = EXCHANGE_MODE;
				break;

				default:		/* None */
					xData->CR_Mode = NONE_MODE;
				break;

			}

			xData->ExpandBlanks	= (!stricmp(expandBuf, "yes") ||
											!stricmp(expandBuf, "on"));


			xData->BinToASCII		= (!stricmp(uueBuf, "yes") ||
											!stricmp(uueBuf, "on"));

			xData->DelTmpFile		= (!stricmp(delBuf, "yes") ||
											!stricmp(delBuf, "on"));

			xData->StripHiBit		= (!stricmp(stripBuf, "yes") ||
											!stricmp(stripBuf, "on"));

			xData->PromptChar = DecodePromptChar(promptBuf);
		}
		else
		{
			if(io->xpr_gets != NULL)
			{
				UWORD expand, strip;
				UBYTE lf, cr, uue, del, promptBuf[4], buffy[128];

				uue	 = (xData->BinToASCII)		? 1 : 0;
				del	 = (xData->DelTmpFile)		? 1 : 0;
				expand = (xData->ExpandBlanks)	? 1 : 0;
				strip	 = (xData->StripHiBit)		? 1 : 0;
				EncodePromptChar(xData->PromptChar, promptBuf);

				switch(xData->LF_Mode)
				{
					case STRIP_MODE:
						lf = 'S';
					break;

					case ADD_MODE:
						lf = 'A';
					break;

					case EXCHANGE_MODE:
						lf = 'X';
					break;

					default:
						lf = 'N';
					break;

				}

				switch(xData->CR_Mode)
				{
					case STRIP_MODE:
						cr = 'S';
					break;

					case ADD_MODE:
						cr = 'A';
					break;

					case EXCHANGE_MODE:
						cr = 'X';
					break;

					default:
						cr = 'N';
					break;

				}

				sprintf(buffy, "C%ld,L%ld,F%lc,R%lc,U%lc,D%lc,E%ld,S%ld,P%s", xData->CharDelay, xData->LineDelay, lf, cr, uue, del, expand, strip, promptBuf);

				if(io->xpr_gets("ASCII Options", buffy)  != NULL)
					ParseConfigString(io, buffy);
			}
		}
	}
	else
		ParseConfigString(io, io->xpr_filename);

	return(XPRS_SUCCESS);
}


STATIC BOOL WaitForPrompt(struct XPR_IO *io)
{
	struct XProtocolData *xData = (struct XProtocolData *)io->xpr_data;
	UWORD data;

	if(data = io->xpr_sread(xData->SerBuf, 1, 0) > 0)
	{
		UWORD i;

		for(i=0; i<data; i++)
		{
			if(xData->SerBuf[i] == xData->PromptChar)
				return(0);
		}
	}

	for(;;)
	{
		if(io->xpr_sread(xData->SerBuf, 1, 10000000) > 0)
		{
			if(xData->SerBuf[0] == xData->PromptChar)
				return(0);
		}
		else
			return(1);
	}

	return(1);
}


STATIC LONG SendLine(struct XPR_IO *io, UBYTE *fileBuf, ULONG lineLen)
{
	struct XProtocolData *xData = (struct XProtocolData *)io->xpr_data;
	LONG brkFlag=0;

	xData->xpru.xpru_updatemask = XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE;
	xData->xpru.xpru_bytes     += lineLen;
	xData->xpru.xpru_blocksize  = lineLen;
	xData->xpru.xpru_blocks++;
	io->xpr_update(&xData->xpru);


	if(xData->ExpandBlanks != FALSE  &&
		(xData->SerBuf[0] == '\n'  ||  xData->SerBuf[0] == '\r'))
	{
		io->xpr_swrite(" ", 1);
	}


	if(xData->CharDelay != 0)	/* writin' in slo'-motion..(-: */
	{
		UWORD i;
		UBYTE *ptr;

		ptr = xData->SerBuf;
		for(i=0; i<lineLen; i++, ptr++)
		{
			io->xpr_swrite(ptr, 1);
   		Delay(xData->CharDelay);
		}
	}
	else
		io->xpr_swrite(xData->SerBuf, lineLen);	/* BLAST IT..!! */



	if(xData->LineDelay != 0)
  		Delay(xData->LineDelay);

	if(xData->PromptChar != '\0')
		brkFlag = WaitForPrompt(io);

	io->xpr_sflush();


	brkFlag = (io->xpr_chkabort() != 0  ||  brkFlag != 0);

	return(brkFlag);
}


STATIC LONG SendPacket(struct XPR_IO *io, UBYTE *fileBuf, ULONG dataLen)
{
	struct XProtocolData *xData = (struct XProtocolData *)io->xpr_data;
	LONG retVal;
	WORD i, out;
	UBYTE *ptr;

	ptr = fileBuf;

	for(i=0, out=0; i<dataLen; i++, ptr++)
	{
		if(isprint(*ptr) == FALSE)
		{
			switch(*ptr)
			{
				case '\n':
					switch(xData->LF_Mode)
					{
						case STRIP_MODE:
							;
						break;

						case ADD_MODE:
							xData->SerBuf[out++] = '\r';
							xData->SerBuf[out++] = '\n';
						break;

						case EXCHANGE_MODE:
							xData->SerBuf[out++] = '\r';
						break;

						default:
							xData->SerBuf[out++] = '\n';
						break;

					}
				break;

				case '\r':
					switch(xData->CR_Mode)
					{
						case STRIP_MODE:
							;
						break;

						case ADD_MODE:
							xData->SerBuf[out++] = '\r';
							xData->SerBuf[out++] = '\n';
						break;

						case EXCHANGE_MODE:
							xData->SerBuf[out++] = '\n';
						break;

						default:
							xData->SerBuf[out++] = '\r';
						break;

					}
				break;

				default:
					xData->SerBuf[out++] = *ptr;
				break;

			}

			if(isprint(ptr[1]) != FALSE)
			{
				if((retVal = SendLine(io, xData->SerBuf, out)) != 0)
					return(retVal);

				out = 0;
			}
		}
		else
			xData->SerBuf[out++] = *ptr;
	}

	if(out > 0)		/* Anything left in the buffer? Flush it! */
	{
		if((retVal = SendLine(io, xData->SerBuf, out)) != 0)
			return(retVal);
	}

	return(0);
}

VOID	uuencode_header(UBYTE *name, UBYTE *buf);
VOID	uuencode_footer(UBYTE *buf, ULONG size);
VOID	uuencode(UBYTE *in, UBYTE *out, UBYTE *temp, UBYTE len);
BOOL	uudecode(VOID);


LONG __saveds __asm XProtocolSend(register __a0 struct XPR_IO *io)
{
	struct XProtocolData *xData;
	VOID *fp;
	LONG read, size, brkFlag;

	if(test(io) == FALSE)
		return(XPRS_FAILURE);

	if(io->xpr_data == NULL)
	{
		if(setup(io) == FALSE)
		{
			upderr(io, "Ran out of memory!");
			return(XPRS_FAILURE);
		}
	}
	xData = (struct XProtocolData *)io->xpr_data;


	fp = (void *)io->xpr_fopen(io->xpr_filename, "r");
   if(fp == NULL)
	{
		upderr(io, "Failed to open input file \"%s\"", io->xpr_filename);
		return(XPRS_FAILURE);
	}


	xData->numerrs					= 0;
	xData->xpru.xpru_bytes		= 0;
	xData->xpru.xpru_blocks		= 0;
	xData->xpru.xpru_blocksize	= 0;


	if(xData->BinToASCII != FALSE)
	{
		uuencode_header(io->xpr_filename, xData->FileBuf);
		SendPacket(io, xData->FileBuf, strlen(xData->FileBuf));
	}

	xData->xpru.xpru_updatemask= XPRU_FILENAME  | XPRU_PACKETDELAY |
										  XPRU_CHARDELAY | XPRU_PROTOCOL | XPRU_MSG;
	xData->xpru.xpru_filename	= io->xpr_filename;
	xData->xpru.xpru_packetdelay=xData->LineDelay * 20;	/* msec! */
	xData->xpru.xpru_chardelay	= xData->CharDelay * 20;	/* msec! */

	xData->xpru.xpru_protocol	= "ascii";
	xData->xpru.xpru_msg = (xData->BinToASCII == FALSE) ? "Starting ASCII Send" :
											"Starting ASCII Send  [uuencoded file]";
	io->xpr_update(&xData->xpru);

	brkFlag = 0;
	size = 0;
	while(read = io->xpr_fread(xData->FileBuf, 1, FILEBUF, fp))
	{
		WORD inBuf, sentOut;
		UBYTE *fileBuf, *outBuf;

		xData->FileBuf[read] = '\0';

		size += read;

		for(inBuf=read, fileBuf=xData->FileBuf; inBuf>0; fileBuf+=sentOut, inBuf-=sentOut)
		{
			UWORD readyToSend;

			if(xData->BinToASCII != FALSE)
			{
				sentOut = (inBuf > 45) ? 45 : inBuf;

				outBuf = xData->BTA_outbuf;
				uuencode(fileBuf, outBuf, xData->BTA_tmpbuf, sentOut);
				readyToSend = strlen(outBuf);
			}
			else
			{
				outBuf	= fileBuf;
				sentOut	= strcspn(outBuf, "\n\r");
				if(outBuf[sentOut] != '\0')
					sentOut++;

				if(sentOut == 0)
				{
					UWORD i;

					sentOut++;
					for(i=0; i<inBuf; i++)
					{
						if(outBuf[i] == '\0')	/* collect null's */
							sentOut++;
					}
				}

				if(sentOut > inBuf)	/* just to be on the wild side..(-; */
					sentOut = inBuf;

				readyToSend = sentOut;
			}

			if((brkFlag = SendPacket(io, outBuf, readyToSend)) != 0)
				goto bibi;
		}
	}

	if(xData->BinToASCII != FALSE)
	{
		UBYTE *tmp;

		tmp = xData->BTA_outbuf;
		uuencode("", tmp, xData->BTA_tmpbuf, 0);
		SendPacket(io, tmp, strlen(tmp));

		uuencode_footer(tmp, size);
		SendPacket(io, tmp, strlen(tmp));
	}


bibi:
	io->xpr_fclose(fp);

	xData->xpru.xpru_updatemask = XPRU_MSG;
	xData->xpru.xpru_msg = (brkFlag != 0) ? "Aborted" : "Done";
	io->xpr_update(&xData->xpru);

	return((brkFlag != 0) ? XPRS_SUCCESS : XPRS_FAILURE);
}



LONG __saveds __asm XProtocolReceive(register __a0 struct XPR_IO *io)
{
	struct XProtocolData *xData;
	VOID *fp;
	LONG bytesRead, fileSize, brkFlag=0;

	if(test(io) == FALSE)
		return(XPRS_FAILURE);

	if(io->xpr_data == NULL)
	{
		if(setup(io) == FALSE)
		{
			upderr(io, "Ran out of memory!");
			return(XPRS_FAILURE);
		}
	}
	xData = (struct XProtocolData *)io->xpr_data;


	if(xData->BinToASCII != FALSE)
	{
		if(strstr(io->xpr_filename, ".uue") == NULL)
			strcat(io->xpr_filename, ".uue");
	}

	fp = (void *)io->xpr_fopen(io->xpr_filename, "w");
   if(fp == NULL)
	{
		upderr(io, "Failed to open output file \"%s\"", io->xpr_filename);
		return(XPRS_FAILURE);
   }

	xData->xpru.xpru_updatemask = XPRU_MSG | XPRU_PROTOCOL | XPRU_FILENAME;
	xData->xpru.xpru_protocol	= "ascii";
	xData->xpru.xpru_filename   = io->xpr_filename;
	xData->xpru.xpru_msg = (xData->BinToASCII == FALSE) ? "Starting ASCII Receive" :
											"Starting ASCII Receive [uuencoded file]";
	io->xpr_update(&xData->xpru);


	fileSize = 0;

	xData->numerrs					= 0;
	xData->xpru.xpru_bytes		= 0;
	xData->xpru.xpru_blocks		= 0;
	xData->xpru.xpru_blocksize	= 0;
	while(bytesRead = io->xpr_sread(xData->SerBuf, 80, 5000000))
	{
		if(bytesRead < 0)
		{
	   	brkFlag = 1;
	   	break;
		}

		if(xData->StripHiBit != FALSE)
		{
			UWORD i;

			for(i=0; i<bytesRead; i++)
				xData->SerBuf[i] &= 0x7f;
		}

		fileSize += bytesRead;

      xData->xpru.xpru_updatemask= XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE;
      xData->xpru.xpru_bytes	   = fileSize;
      xData->xpru.xpru_blocksize = bytesRead;
      xData->xpru.xpru_blocks++;
      io->xpr_update(&xData->xpru);

      io->xpr_fwrite(xData->SerBuf, 1, bytesRead, fp);

		if((brkFlag = io->xpr_chkabort()) != 0)
			break;
   }


	io->xpr_fclose(fp);

	if(fileSize > 0)
	{
		if(xData->BinToASCII != FALSE  &&  brkFlag == 0)
		{
			BOOL ProcessUUeFile(struct XPR_IO *io, UBYTE *buf_source, UBYTE *buf_dest, VOID *fp_source);
			BOOL success;

			fp = (void *)io->xpr_fopen(io->xpr_filename, "r");
		   if(fp == NULL)
			{
				upderr(io, "Failed to reopen output file \"%s\"", io->xpr_filename);
				return(XPRS_FAILURE);
		   }

			success = ProcessUUeFile(io, xData->FileBuf, xData->BTA_outbuf, fp);

			io->xpr_fclose(fp);

			if(xData->DelTmpFile != FALSE  &&  success != FALSE)
				io->xpr_unlink(io->xpr_filename);
		}
	}
	else
		io->xpr_unlink(io->xpr_filename);


	xData->xpru.xpru_updatemask = XPRU_MSG;
	xData->xpru.xpru_msg = (brkFlag != 0) ? "Aborted" : "Done";
	io->xpr_update(&xData->xpru);

	return((brkFlag != 0) ? XPRS_SUCCESS : XPRS_FAILURE);
}


LONG __saveds __asm XProtocolHostMon(register __a0 struct XPR_IO *io, register __a1 UBYTE *serbuff, register __d0 LONG actual, register __d1 LONG maxsize)
{
  return(actual);
}


LONG __saveds __asm XProtocolUserMon(register __a0 struct XPR_IO *io, register __a1 UBYTE *serbuff, register __d0 LONG actual, register __d1 LONG maxsize)
{
  return(actual);
}


STATIC BOOL test(struct XPR_IO *io)
{
	UBYTE *func;

	/* all we need..(-: */

	if(io->xpr_swrite == NULL)
	{
		func = "xpr_swrite";
		goto error;
	}

	if(io->xpr_sread == NULL)
	{
		func = "xpr_sread";
		goto error;
	}

	if(io->xpr_sflush == NULL)
	{
		func = "xpr_sflush";
		goto error;
	}

	if(io->xpr_fopen == NULL)
	{
		func = "xpr_fopen";
		goto error;
	}

	if(io->xpr_fwrite == NULL)
	{
		func = "xpr_fwrite";
		goto error;
	}

	if(io->xpr_fread == NULL)
	{
		func = "xpr_fread";
		goto error;
	}

	if(io->xpr_fclose == NULL)
	{
		func = "xpr_fclose";
		goto error;
	}

	if(io->xpr_update == NULL)
	{
		func = "xpr_update";
		goto error;
	}

	if(io->xpr_chkabort == NULL)
	{
		func = "xpr_chkabort";
		goto error;
	}

	return(TRUE);


error:
	upderr(io, "Comm prog missing required function \"%s", func);
	return(FALSE);
}


STATIC BOOL setup(struct XPR_IO *io)
{
	struct XProtocolData *xData;

	io->xpr_data = AllocMem(sizeof(struct XProtocolData), MEMF_PUBLIC | MEMF_CLEAR);

	if(io->xpr_data == NULL)
		return(FALSE);

   xData = (struct XProtocolData *)io->xpr_data;

/* some good settings.. */
	xData->CharDelay	= 0;
	xData->LineDelay	= 0;
	xData->PromptChar	= '\0';

	xData->ExpandBlanks	= TRUE;
	xData->StripHiBit		= FALSE;
	xData->BinToASCII		= FALSE;
	xData->DelTmpFile		= FALSE;

	xData->LF_Mode = NONE_MODE;
	xData->CR_Mode = NONE_MODE;

	return(TRUE);
}

/* Search for specified option setting in string */
STATIC UBYTE *FindOption(UBYTE *buf, UBYTE option)
{
	while(*buf)
	{
		buf += strspn(buf," ,\t\r\n");
		if(*buf == option)
			return(++buf);
		buf += strcspn(buf," ,\t\r\n");
  }

  return(NULL);
}


STATIC VOID ParseConfigString(struct XPR_IO *io, char *buf)
{
	struct XProtocolData *xData = (struct XProtocolData *)io->xpr_data;
	UBYTE *p;

	if(p = FindOption(buf, 'P'))
		xData->PromptChar = DecodePromptChar(p);
	else
	{
		if(p = FindOption(buf, 'p'))
			xData->PromptChar = DecodePromptChar(p);
	}

	strupr(buf);

	if(p = FindOption(buf, 'C'))
	{
		xData->CharDelay = AtoL(p);
		if(xData->CharDelay > 500)
			xData->CharDelay = 500;
	}


	if(p = FindOption(buf, 'L'))
	{
		xData->LineDelay = AtoL(p);
		if(xData->LineDelay > 500)
			xData->LineDelay = 500;
	}


	if(p = FindOption(buf, 'F'))
	{
		switch(*p)
		{
			case 'A':
				xData->LF_Mode = ADD_MODE;
			break;

			case 'S':
				xData->LF_Mode = STRIP_MODE;
			break;

			case 'X':
				xData->LF_Mode = EXCHANGE_MODE;
			break;

			default:
				xData->LF_Mode = NONE_MODE;
			break;

		}
	}


	if(p = FindOption(buf, 'R'))
	{
		switch(*p)
		{
			case 'A':
				xData->CR_Mode = ADD_MODE;
			break;

			case 'S':
				xData->CR_Mode = STRIP_MODE;
			break;

			case 'X':	/* LF -> CR */
				xData->CR_Mode = EXCHANGE_MODE;
			break;

			default:
				xData->CR_Mode = NONE_MODE;
			break;

		}
	}


	if(p = FindOption(buf, 'U'))
		xData->BinToASCII = (*p == '1');


	if(p = FindOption(buf, 'D'))
		xData->DelTmpFile = (*p == '1');


	if(p = FindOption(buf, 'E'))
		xData->ExpandBlanks = (*p == '1');


	if(p = FindOption(buf, 'S'))
		xData->StripHiBit = (*p == '1');
}


LONG AtoL(STRPTR string)
{
	LONG value=0;

	return((StrToLong(string, &value) > 0) ? value : 0);
}

VOID __stdargs upderr(struct XPR_IO *io, UBYTE *err, ...)
{
	struct XProtocolData *xData = (struct XProtocolData *)io->xpr_data;
	struct XPR_UPDATE xpru;
	va_list varargs;
	UBYTE buff[256];

	va_start(varargs, err);
	vsprintf(buff,err,varargs);
	va_end(varargs);

	xpru.xpru_updatemask = XPRU_ERRORMSG;
	xpru.xpru_errormsg = buff;

	xpru.xpru_updatemask |= XPRU_ERRORS;
	if(xData != NULL)
	{
		xData->numerrs++;
		xpru.xpru_errors = xData->numerrs;
	}
	else
		xpru.xpru_errors = 1;

	io->xpr_update(&xpru);
}


STATIC VOID EncodePromptChar(UBYTE pChar, UBYTE *pBuf)
{
	pChar = ToUpper(pChar);

	if(isprint(pChar) == 0)
	{
		switch(pChar)
		{
			case '\0':
				pBuf[0] = '\\';
				pBuf[1] = '0';
				pBuf[2] = '\0';
			break;

			case '\n':
				pBuf[0] = '\\';
				pBuf[1] = 'n';
				pBuf[2] = '\0';
			break;

			case '\r':
				pBuf[0] = '\\';
				pBuf[1] = 'r';
				pBuf[2] = '\0';
			break;

			case '\\':
				pBuf[0] = '\\';
				pBuf[1] = '\\';
				pBuf[2] = '\0';
			break;

			default:
			{
				pBuf[0] = '\\';
				pBuf[1] = 'd';
				sprintf(&pBuf[2], "%ld", pChar);
			}
			break;

		}
	}
	else
	{
		pBuf[0] = pChar;
		pBuf[1] = '\0';
	}
}


STATIC UBYTE DecodePromptChar(UBYTE *pBuf)
{
	if(pBuf[0] == '\\')
	{
		switch(ToUpper(pBuf[1]))
		{
			case 'D':
				return((UBYTE)AtoL(&pBuf[2]));

			case 'N':
				return('\n');

			case 'R':
				return('\r');

			case '\\':
				return('\\');

			default:
				return('\0');

		}
	}
	else
		return(*pBuf);

	return(' ');
}



/* end of source-code */
