/*
 * xprQuickB.library
 * XPR implementation of CompuServe Quick-B protocol, written by Marc Boucher.

Files in this release:

 aztec.h	- includes usual aztec stuff, function decls etc..
 protolib.c	- An exec library Based on "elib", an example library,
 protolib.h	- created by Jim Mackraz using mylib.asm by Neil Katin.
 timeout.c	- timer.device routines for a simple dos Delay() style function
 protocol.c	- quick-b routines
 xprquickb.c	- main module
 Makefile
 libface.asm	- other library code, from examples by J.Mackraz etc.. Adapted for XPR by Willy Langeveld
 xprquickb.library - your compiled library
 funky.asm	- initial Manx C .begin stuff, (C) by Manx but modified by J.Mackraz
 xproto.h	- include file of most xpr structures by XPR author.
 rtag.asm	- RomTag structure for an exec lib, written by J. Mackraz

	Placed in the public domain, no copyrights apply on this stuff; but
please  do  not  claim  credit  for  code that isn't yours.  Distribute the
complete package, PLEASE!  not just the .library file..

	Please   note   however   that  "protocol.c"  is  based  on  freely
distributable  source  code  placed  on CompuServe.  Some copyrights and/or
restrictions  on  these  may  be  in  effect  -  Read  the notice on top of
"protocol.c".

	I  am  not  yet  on  the  CompuServe  network.  This was written to
satisfy  interest in XPR and to finish a previous attempt which was written
for a friend.

	 Thanks  to  all who contributed to the XPR definition and who have
written  software  to  support  it..   Willy  Langeveld,  Marco  Papa, Rick
Huebner,  and  others  that  I  forget,  don't know, or that will do in the
future.

--
Send bug reports, suggestions, ting ting jahe candy to:

-Marc Boucher------------------------------------------Phone: 514/466+8932-
  AmiNet    postmaster@marcami        | Bitnet    UUQRL0 at POLYTECA
  UUCP      ...!killer!jolnet!boucher | Internet  boucher@jolnet.Orpk.IL.US
       CompuServe (EasyPlex): ">INTERNET:boucher@jolnet.Orpk.IL.US"


Money, flames, trouble, to Gunnar Nordmark's NULL: device.

 *
 *
 */

#include <exec/types.h>

#include "aztec.h"
#include "xproto.h"

/*#define DEBUG*/

#define	DLE		16
#define	ENQ		05
#define	ESC		27

void DosEntry()	/* in case someone runs us from AmigaDOS! */
{
}

char  XPRname[]   = "xprquickb.library";
char  XPRid[]     = "xprQuickB library 0.9 (Jul 89)\r\n";
UWORD XPRrevision = 1;

extern long calla(), callaa(), callad(), calladd(), calladda(), calld();
extern long bp_DLE();

long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), \
	(*xfread)(), (*xsread)(),  (*xchkabort)(), (*xfwrite)(), \
	(*xchkmisc)(), (*xsetserial)(),(*xsflush)();

long ctimeouts , cbytes, cnaks, cblocks, gbufsize;	/* counts for status */

short cgetc(timeout)
long timeout;
{
	short result;
	UBYTE dat[2];

	if(calladd(xsread, dat, 1L, ((long)timeout)*60000L)==-1L) {
		result=-1;
	}
	else {
		result=dat[0];
	} 
	return(result);
}

void
cputc(bytetowrite)
char bytetowrite;
{
	UBYTE dat[2];

	dat[0]=bytetowrite;
	callad(xswrite, dat, 1L);
}

static struct XPR_UPDATE xpru;

long XPR_QuickB(IO)
struct XPR_IO *IO;
{
	static long i, NewStatus, OldSerStatus, finished, active;

	if ((xupdate=IO->xpr_update) == NULL) return(0L);
	if ((xswrite=IO->xpr_swrite) == NULL) {
		Error("No xpr_swrite() function available!");
		return(0L);
	}
	if ((xfopen=IO->xpr_fopen) == NULL) {
		Error("No xpr_fopen() function!");
		return(0L);
	}
	if ((xfclose=IO->xpr_fclose) == NULL) {
		Error("No xpr_fclose() function!");
		return(0L);
	}
	if ((xfread=IO->xpr_fread) == NULL) {
		Error("No xpr_fread() function!");
		return(0L);
	}
	if ((xfwrite=IO->xpr_fwrite) == NULL) {
		Error("No xpr_fwrite() function!");
		return(0L);
	}
	if ((xsread=IO->xpr_sread) == NULL) {
		Error("No xpr_sread() function!");
		return(0L);
	}
	xsflush=IO->xpr_sflush;
	xchkabort=IO->xpr_chkabort;
	xsetserial=IO->xpr_setserial;
	xchkmisc=IO->xpr_chkmisc;

	finished=FALSE;
	active=FALSE;

	if(xsetserial) {
		OldSerStatus = calld(xsetserial,-1L);
		NewStatus = OldSerStatus & 0xFFFFE0BC;
		if (NewStatus != OldSerStatus) calld(xsetserial,NewStatus);
 	}

	xpru.xpru_updatemask = XPRU_PROTOCOL;
	xpru.xpru_protocol = "xprQuickB library 0.9 (Jul 89) by Marc Boucher";
	calla(xupdate, &xpru);
	TimeOut(50L);

	for (i = 0; i < (long)strlen(IO->xpr_filename); i++)	/* send filename */
		cputc(*(IO->xpr_filename + i));
	cputc(0x0d);	/* carriage return */

	do {
		switch(cgetc(100L)) {
			case DLE: if (cgetc (10L) != 'B') break;
				active=TRUE;
				finished=bp_DLE();
				break;
			case ENQ: bp_ENQ();
				break;
		}
		if(xchkmisc) xchkmisc();
		if(xchkabort) if((xchkabort())&&(!active)) finished=TRUE;
	} while (!finished);
	return(TRUE);
}

long user_abort()
{
	if(xchkmisc) xchkmisc();

	if(xchkabort) return(xchkabort());
	else return(FALSE);
}

long XProtocolSend(IO)
struct XPR_IO *IO;
{
	return(XPR_QuickB(IO));
}

long XProtocolReceive(IO)
struct XPR_IO *IO;
{
	return(XPR_QuickB(IO));
}

long XProtocolSetup(IO)
struct XPR_IO *IO;
{
	return(TRUE);
}

long XProtocolCleanup(IO)
struct XPR_IO *IO;
{
	return(TRUE);
}

Status(text)
char *text;
{
	xpru.xpru_updatemask = XPRU_MSG;
	xpru.xpru_msg   = text;
	calla(xupdate, &xpru);
}

OtherStats()
{
	xpru.xpru_blocks=cblocks;
	xpru.xpru_errors=cnaks;
	xpru.xpru_timeouts=ctimeouts;
	xpru.xpru_blocksize=gbufsize;
	xpru.xpru_updatemask = XPRU_BLOCKS|XPRU_ERRORS|XPRU_TIMEOUTS|XPRU_BLOCKSIZE;
	calla(xupdate, &xpru);
}

Error(text)
char *text;
{
	xpru.xpru_updatemask = XPRU_ERRORMSG;
	xpru.xpru_errormsg   = text;
	calla(xupdate, &xpru);
}

LastError(text)
char *text;
{
	cnaks++;

	xpru.xpru_updatemask = XPRU_ERRORMSG;
	xpru.xpru_errormsg   = text;
	calla(xupdate, &xpru);
	OtherStats();
}

Bytes(bytesnum)
long bytesnum;
{
	xpru.xpru_bytes=bytesnum;
	xpru.xpru_updatemask = XPRU_BYTES;
	calla(xupdate, &xpru);
}

Filename(text)
char *text;
{
		xpru.xpru_updatemask = XPRU_FILENAME;
		xpru.xpru_filename = text;
		calla(xupdate, &xpru);
}

/* The following can be used to debug. uncomment #define DEBUG at line 15 */

#ifdef DEBUG
static long deblog = 0L;

DebugMsg(text)
char *text;
{
	xpru.xpru_updatemask = XPRU_ERRORMSG;
	xpru.xpru_errormsg   = text;
	calla(xupdate, &xpru);

	if (!deblog) deblog = callaa(xfopen,"ram:qb.debug","a");
	calladda(xfwrite,text,1L,(long)strlen(text),deblog);
	calladda(xfwrite,"\n",1L,1L,deblog);
	calla(xfclose,deblog);
	deblog=0L;
}

static char msg[200];

DebugVal(val)
long val;
{
	sprintf(msg,"val (hex)=%lx (dec)=%ld",val,val);
	DebugMsg(msg);
}
#endif

/* (m.b. note) the following routines were written by W.G.J. Langeveld
	Copyrights may be in effect.
 */

/**
*
*   The following functions setup the proper registers for the call-back 
*   functions.
*
**/
#asm
        public _callad
_callad:
        movea.l 8(sp),a0                ; Second argument goes in a0
        move.l  12(sp),d0               ; Third  argument goes in d0
/*
*   Now this is a trick to avoid using another register.
*   Charlie taught me this...
*/
        move.l  4(sp),-(sp)             ; First  argument is function
        rts

        public  _calladda
_calladda:
        movea.l 8(sp),a0                ; Second argument goes in a0
        move.l  12(sp),d0               ; Third  argument goes in d0
        move.l  16(sp),d1               ; Fourth argument goes in d1
        movea.l 20(sp),a1               ; Fifth  argument goes in a1
        move.l  4(sp),-(sp)             ; First  argument is function
        rts

        public  _calla
_calla:
        movea.l 8(sp),a0                ; Second argument goes in a0
        move.l  4(sp),-(sp)             ; First  argument is function
        rts

        public  _callaa
_callaa:
        movea.l 8(sp),a0                ; Second argument goes in a0
        movea.l 12(sp),a1               ; Third  argument goes in a1
        move.l  4(sp),-(sp)             ; First  argument is function
        rts

        public  _calladd
_calladd:
        move.l  8(sp),a0                ; Second argument goes in a0
        move.l  12(sp),d0               ; Third  argument goes in d0
        move.l  16(sp),d1               ; Fourth argument goes in d1
        move.l  4(sp),-(sp)             ; First  argument is function
        rts

        public  _calld
_calld:
        move.l  8(sp),d0                ; Second argument goes in d0
        move.l  4(sp),-(sp)             ; First  argument is function
        rts

#endasm
/*
*   Could have added any other functions needed for other call-backs.
*   Could have written a fancier single one... Could've...
*/
