/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1990 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .	| || the authors:			      BBS: (919) 382-8265    */
/* | o	| ||   Dave Baker      Alan Beale	  Jim Cooper		     */
/* |  . |//    Jay Denebeim    Bruce Drake	  Gordon Keener 	     */
/* ======      John Mainwaring Andy Mercier	  Jack Rouse		     */
/*	       John Toebes     Mary Ellen Toebes  Doug Walker  Mike Whitcher */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
   
/*
 *  portions are from QUICKB.C by Paul M. Resch
 *  modified to function as an Amiga XPR protocol library by
 *	Jack Rouse of the Software Distillery.
 */

#include <exec/types.h>
#include <proto/exec.h>
#include <stdlib.h>
#include <string.h>
#include "xproto.h"

/*#define	TRUE	1*/
/*#define	FALSE	0*/

#define CPMEOF		0x1A

#define	DLE		16
#define	ETX		03
#define	NAK		21
#define	ENQ		05
#define	CR		0x0D
#define	LF		0x0A
#define	MAX_BUF_SIZE	1032		/* Largest data block we can handle */
#define	MAX_SA		2		/* Maximum number of waiting packets */

#define	DEF_BUF_SIZE	511		/* Default data block               */
#define	DEF_WS		1		/* I can send 2 packets ahead       */
#define	DEF_WR		1		/* I can receive single send-ahead  */
#define	DEF_BS		8		/* I can handle 1024 bytes          */
#define	DEF_CM		1		/* I can handle CRC                 */
#define	DEF_DQ		1		/* I can handle non-quoted NUL      */

#define	MAX_ERRORS	10


/* Receive States */

#define	R_GET_DLE	0
#define	R_GET_B		1
#define	R_GET_SEQ	2
#define	R_GET_DATA	3
#define	R_GET_CHECKSUM	4
#define	R_SEND_ACK	5
#define	R_TIMED_OUT	6
#define	R_SUCCESS	7

/* Send States */

#define	S_GET_DLE	1
#define	S_GET_NUM	2
#define	S_HAVE_ACK	3
#define	S_GET_PACKET	4
#define	S_TIMED_OUT	5
#define	S_SEND_NAK	6
#define	S_SEND_ENQ	7
#define	S_SEND_DATA	8

typedef	struct	PACKETB {
	int	seq;    /* Packet's sequence number  */
	int	num;    /* Number of bytes in packet */
	unsigned char buf[MAX_BUF_SIZE]; /* Actual packet data */
	} PACKET;


struct XPR_DATA {
   struct XPR_IO *xio;	/* back pointer to our XPR_IO structure */

   long (*__asm xpr_fopen) 		/* Open file                */
		(register __a0 char *filename,
		 register __a1 char *accessmode);
   long (*__asm xpr_fclose)		/* Close file               */
		(register __a0 long fileptr);
   long (*__asm xpr_fread)		/* Get char from file       */
		(register __a0 char *buffer,
		 register __d0 long size,
		 register __d1 long count,
		 register __a1 long fileptr);
   long (*__asm xpr_fwrite)		/* Put string to file       */
		(register __a0 char *buffer,
		 register __d0 long size,
		 register __d1 long count,
		 register __a1 long fileptr);
   long (*__asm xpr_sread)		/* Get char from serial     */
		(register __a0 char *buffer,
		 register __d0 long size,
		 register __d1 long timeout);
   long (*__asm xpr_swrite)		/* Put string to serial     */
		(register __a0 char *buffer,
		 register __d0 long size);
   long (*__asm xpr_update)		/* Print stuff              */
		(register __a0 struct XPR_UPDATE *updatestruct);
   long (*xpr_chkabort)(void);		/* Check for abort          */
   long (*xpr_chkmisc)(void);		/* Check misc. stuff        */
   long (*__asm xpr_gets)		/* Get string interactively */
		(register __a0 char *prompt,
		 register __a1 char *buffer);
   long (*__asm xpr_setserial)		/* Set and Get serial info  */
		(register __d0 long newstatus);
   long (*__asm xpr_finfo)		/* Return file info         */
   		(register __a0 char *filename,
		 register __d0 long typeofinfo);
   long (*__asm xpr_options)
		(register __d0 long n,
		 register __a0 struct xpr_option **opt);
   long (*__asm xpr_unlink)		/* Delete a file.           */
		(register __a0 char *filename);

   int	seq_num;	/* Current Sequence Number - init by Term_ENQ */
   int	checksum;	/* May hold CRC */
   int	r_size;			/* size of receiver buffer */
   unsigned int	s_counter;
   unsigned int	r_counter;
   int	timed_out;	/* we timed out before receiving character */
   int	cchar;                  /* current character */
   int	masked;			/* TRUE if ctrl character was 'masked' */
   int	packet_received;	/* True if a packet was received */

   /* Other End's Parameters */
   char	His_WS;                      /* Sender's Window Send     */
   char	His_WR;                      /* Sender's Window Receive  */
   char	His_BS;                      /* Sender's Block Size      */
   char	His_CM;               	     /* Sender's Check Method    */

   /* Negotiated Parameters */
   char	Our_WS;			/* Negotiated Window Send   */
   char	Our_WR;			/* Negotiated Window Receive */
   char	Our_BS;			/* Negotiated Block Size     */
   char	Our_CM;			/* Negotiated Check Method   */

   int	Quick_B;		/* True if Quick B in effect */
   int	Use_CRC;		/* True if CRC in effect     */
   int	buffer_size;		/* Our_BS * 4                */
   int	SA_Max;			/* 1 if SA not enabled, else MAX_SA */
   int	SA_Enabled;		/* True if Send-Ahead is permitted  */
   int	ack_SA;		/* Which SA_Buf is waiting for an ACK */
   int	fill_SA;	/* Which SA_Buf is ready for new data */
   int	SA_Waiting;		/* Number of SA_Buf's waiting for ACK */
   int	Aborting;		/* TRUE if aborting transfer */

   unsigned short	crc_16;

   int  Done;

   unsigned char r_buffer[MAX_BUF_SIZE];

   struct XPR_UPDATE xpru;

   /* options stuff */
   char optText;	/* text processing control */
   char optOwrt;	/* overwrite handling */
   char optAuto;	/* auto-activate */
   char optDelt;	/* delete after send */
   char optKeep;	/* keep partial file */

   long TextMode;	/* do line terminator translation */
   int TextC;		/* previous character for text processing */

   /* serial buffering */
#define MAX_SERBUF 256
   unsigned char serbuf[MAX_SERBUF];
   int nserbuf;
   unsigned char *serbufp;

   /* disk I/O buffering */
   char *iobuf;
   char *iobufp;
   long maxiobuf;
   long iobufn;
   int writing;		/* buffer is for output */

   PACKET	SA_Buf[MAX_SA+1];  /* Send-ahead buffers */
};

void bp_DLE(struct XPR_DATA *xd);
void bp_ENQ(struct XPR_DATA *xd);
void bp_ESC_I(struct XPR_DATA *xd);

long bfopen(struct XPR_DATA *xd, char *filename, char *mode);
long bfclose(struct XPR_DATA *xd, long file);
long bfwrite(struct XPR_DATA *xd, char *buf, long len, long file);
long bfwread(struct XPR_DATA *xd, char *buf, long len, long file);
long xbfwrite(struct XPR_DATA *xd, char *buf, long len, long file);
long xbfwread(struct XPR_DATA *xd, char *buf, long len, long file);

void cputc(struct XPR_DATA *xd, int c);
int cfilbuf(struct XPR_DATA *xd, long timeout);
#define cgetc(xd, to) \
	((--(xd)->nserbuf < 0) ? cfilbuf((xd), (to)) : *(xd)->serbufp++)

void errormsg(struct XPR_DATA *xd, char *msg);

#define min(a, b) ((a)<=(b)?(a):(b))
#define max(a, b) ((a)>=(b)?(a):(b))
