#include <stdio.h>
#include <sys/types.h>

#ifdef	HELPER
/* We define these so that we ccan use common code for both
 * the server and helper ends
 */
#define	real_ioctl	ioctl
#define	real_open	open
#define	real_read	read
#define	real_write	write
#define real_fcntl	fcntl
#endif	HELPER

/*
 * cbratp uses packets of the form:
 *
 * Start/Stop	-	Unique byte indicating either the start
 *			or stop of the packet
 *
 * Sequence Byte -	bits	function
 * 			7-6	Cyclic sequence identifier
 *			5-4	Id of last successfully recieved packet
 *			3	If set indicates a retransmission.
 *			2	If set indicates Sequence info only.
 *			1	If set indicates the packet has been compressed
 *			0	If set indicates the packet is to be continued
 * [ 
 * Control Byte	-	Byte indicating how the packet should be interpreted.
 *
 * Data Bytes	-	A maximum of PACKETSIZE bytes of data
 * ]
 *
 * CRC		-	16 bit Cyclic Redundancy Check of all data including
 *			Sequence Byte
 * [
 * Start/Stop	-	optional end of packet marker
 * ]
 *
 */

#define	START_STOP	0xac		/* framing byte code */
#define	ESCAPE_BYTE	0xca		/* bytes<0x20 escape byte */

#define SEQ(a)		(((a)>>6) & 3)	/* 2 bit sequence id */
#define ACK(a)		(((a)>>4) & 3)	/* 2 bit sequence id */

#define CNT_FLAG	(1<<0)		/* Continuation bit */
#define CMP_FLAG	(1<<1)		/* Compression bit */
#define SYNC		(1<<2)		/* Seq info only bit */
#define	RETRY		(1<<3)		/* Retransmition bit */

#define NCHANNELS	256		/* maximum control channel */

#define NEED_MORE	(-1)		/* indicates no more input */
#define START		(-2)		/* indicates start/stop encountered */

#define MAXQSIZE	8		/* size of out going queue */

#define COMPRESSSIZE	5		/* minimum size to compress */

#define QBUFSIZE	128		/* uncompressed packet size */
#define	MAXPKTSIZE	(QBUFSIZE * 2)	/* compressed packet size */

#define IDLE		0		/* packet to be read/written */
#define FILLING		1		/* packet being read */
#define READ		2		/* packet has been read */
#define SENT		3		/* packet has been sent */
#define ABORT		4		/* packet is corrupted */

#define NEXT(a)		(((a) + 1) & 3)		/* The next sequence id */
#define LAST(a)		(((a) - 1) & 3)		/* The previous sequence id */

/* Predefined channel types for the Nut implementation */

#define CONTROL_CHN	0
#define OPEN_CHN	1
#define CLOSE_CHN	2
#define LSEEK_CHN	3
#define OPENCON_CHN	4
#define ACCEPTCON_CHN	5
#define SERVERADDR_CHN	6
#define CLIENTADDR_CHN	7
#define SERVERNAME_CHN	8
#define GETENV_CHN	9
#define HOMEDIR_CHN	10
#define PUTENV_CHN	11
#define SPAWN_CHN	12
#define	FILESIZE_CHN	13
#define	CWD_CHN		14
#define READ_CHN	15
#define WRITE_CHN	16
#define	GETHOSTNAME_CHN	17
#define	GETHOSTADDR_CHN	18
#define	VERSION_CHN	19
#define	PIPE_CHN	20

/* Special control channel functions */
#define QUIT_CMD	0
#define SPEED_CMD	1
#define CRC_CMD		2

struct frame {
    u_char	f_state;		/* current state of pkt. SENT, IDLE */
    u_char	f_chan;			/* packets channel no. */
    u_char	f_flags;		/* packets flags */
    u_short	f_crc;			/* partially calculated CRC */
    short	f_len;			/* compressed length of packet */
    short	f_ulen;			/* uncompressed length of packet */
    u_char	f_buf[MAXPKTSIZE];	/* packet data */
};

struct channel {
    u_char	type;			/* index into type()[] */
    u_char	arg;			/* channel specific data, a fd */
    u_short	len;			/* length of data waiting on channel */
    u_char	*buf;			/* data waiting of channel */
};

struct ioproc {
    u_char	state;			/* state of reader/writer. IDLE ... */
    u_char	frame;			/* current frame no. */
    u_char	lastack;		/* last packet successfully send/read */
    u_char	control;		/* control byte of packet */
    u_char	*ptr;			/* current character pointer */
};

struct qdata {
    u_char	q_chan;			/* channel of request */
    u_char	q_flags;		/* flags of request */
    short	q_len;			/* length of data */
    u_char	q_buf[MAXPKTSIZE];	/* data */
};

struct queue {
    short		size;		/* current size of queue */
    struct qdata	*head;		/* start of queue */
    struct qdata	*tail;		/* end of queue */
    struct qdata	data[MAXQSIZE];	/* actual queue */
};

struct cqueue {		/* input queue for read channels */
    u_short	size;			/* size of queue */
    u_short	bufsize;		/* maximum size of queue */
    u_char	*head;			/* start of queue */
    u_char	*tail;			/* end of queue */
    u_char	*buf;			/* queue buffer */
};

struct version {
    short	version;
    short	firstfd;
    int		res1;
    int		res2;
    int		res3;
};

typedef struct version VERSION;

struct frame	in_coming[4];		/* reader packets */
struct frame	out_going[4];		/* writer packets */
struct channel	*chan[NCHANNELS];	/* then channel data */
struct ioproc	reader;			/* reader state structure */
struct ioproc	writer;			/* writer stae structure */
struct queue	out_queue;		/* queue of requests */
#ifndef	WIRETAP
VERSION		version;		
#endif	/*WIRETAP*/

unsigned long	timeout;		/* ms till we should retransmit */
unsigned long	min_timeout;		/* minimum time to ack 1 char */
int		(*types[])();		/* functions for each channel type */
int		rs232baudrate;		/* current baudrate */
int		crc_mode;		/* true if no crc should be used/checked */
int		pkt_mode;		/* true if in packet mode */
u_char		rd_chan[FD_SETSIZE];	/* fd -> channel index */
u_char		wr_chan[FD_SETSIZE];	/* fd -> channel index */
fd_set		read_fds;		/* remote read fds */
int		maximum_fd;		/* maximum fd allocated so far */

#ifndef	WIRETAP
char		my_hostname[40];
char		*myname;
#endif	/*WIRETAP*/
#ifndef	HELPER
struct cqueue	*rd_queue[FD_SETSIZE];	/* read channel character queues */
#ifndef	WIRETAP
struct hostent	*hlist_pntr;
#endif	/*WIRETAP*/
int		return_int;		/* value returned by rcv functions */
int		return_int2;		/* value returned by rcv functions */
long		return_long;		/* value returned by rcv functions */
char		*return_ptr;		/* value returned by rcv functions */
#endif	/*HELPER*/

extern	char	*xnewshome;
extern u_char	*encode_long();
extern long	decode_long();
extern u_char	*encode_short();
extern short	decode_short();

u_char		draining;		/* true if all pkts have been sent and rcv'd */
u_char		should_sync;		/* true if a sync packet should be sent */
#ifdef	DEBUG
u_char		rs232_debug;
FILE		*rs232_debugfile;
#endif	/*DEBUG*/
FILE		*rs232_stats;

extern char	*malloc();
/*extern char	*sprintf();*/
extern char	*nut_getenv();
extern struct cqueue *cq_alloc();
extern u_short	calculate_crc();
extern void	enqueue();
extern char     *strcpy();
extern char     *strcat();
extern void	exit();
