[net.micro.atari] terminal emulator source

bammi@cwruecmp.UUCP (Jwahar R. Bammi) (01/17/86)

	You asked for source, you get source. This is a shar format
posting of a terminal emulator with Xmodem transfers and Ascii file
capture. We hope to improve it as time permits. We are posting it
in hopes of getting your feed back to some minor problems, and your
comments suggestions.
				Enjoy.

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	capture.c
#	main.c
#	util.c
#	xmodem.c
#	xmdm.h
#	xmdm.doc
# This archive created: Fri Jan 17 04:10:16 1986
# By:	Jwahar R. Bammi ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'capture.c'" '(2141 characters)'
if test -f 'capture.c'
then
	echo shar: over-writing existing file "'capture.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'capture.c'
X/*
X * Ascii File Capture / Dump Module
X * 
X *	ST users @ Case Western Reserve University
X * Dump is not implemented.
X */
X
X#include <osbind.h>
X#include "xmdm.h"
X
X#define sendchar(X)	Cauxout(X) /* Send a character to serial port */
X
X 	/* extern variables */
Xextern char bufr[];		/* file buffer */
Xextern unsigned int buf_index;  /* index to file buffer */
Xextern char capture;		/* Capture flag */
X
X 	/* Global Variables */
Xstatic int fd;
X
X/*
X * s_capture() - Start Ascii File Capture
X *
X */
Xvoid s_capture()
X{
X	register char *f;
X	char *r_filename();
X	
X	sendchar(CTRL('S'));
X
X	/* Get filename */
X	if((f = r_filename()) == (char *)NULL)
X	{
X		/* User Cancelled */
X		Cconws("Capture is Off\r\n");
X		capture = 0;
X		sendchar(CTRL('Q'));
X		return;
X	}
X	
X	/* create/open the file */
X	if((fd = Fcreate(f,0)) < 0)
X	{
X		if((fd = Fopen(f,1)) < 0)
X		{
X			/* Did'nt make it */
X			Cconws("Could not open ");
X			Cconws(f);
X			Cconws("\r\nCapture is off\r\n");
X			capture = 0;
X			hit_key();
X			sendchar(CTRL('Q'));
X			return;
X		}
X	}
X	
X	
X	/* All set to capture */
X	capture = 1;
X	Cconws("Capture is ON\r\n");
X	buf_index = 0;
X	sendchar(CTRL('Q'));
X}
X
X/*
X * c_capture() -  close capture
X *
X */
Xvoid c_capture()
X{
X	sendchar(CTRL('S'));
X	if(buf_index > 0)
X	{
X		/* Flush stuff in file buffer */
X		if(Fwrite(fd,(long)buf_index,bufr) != buf_index)
X		{
X			Cconws("\r\nWarning - error writing capture file\r\n");
X			hit_key();
X		}
X	}
X
X	/* All done */
X	buf_index = 0;
X	capture = 0;
X	Cconws("\r\nCapture is OFF\r\n");
X	Fclose(fd);
X	sendchar(CTRL('Q'));
X}
X
X
X/*
X * a_capture - Add a char to capture buffer
X *
X */
Xvoid a_capture(c)
Xregister int c;
X{
X	bufr[buf_index++] = c;
X	
X	if(buf_index == BUFSIZ)
X	{
X		/* Buffer full dump it to file */
X		sendchar(CTRL('S'));
X		if(Fwrite(fd,(long)buf_index,bufr) != buf_index)
X		{
X			/* Problem Writing file */
X			EscSeq(j);	/* save cursor position */
X			my_screen();	/* switch to my screen memory */
X			Cconws("\r\nWarning - error writing capture file\r\n");
X			Cconws("Capture Forced OFF\r\n");
X			Fclose(fd);
X			hit_key();
X			his_screen(); /* Back to his screen memory */
X			capture = 0;
X		}
X		buf_index = 0;
X		sendchar(CTRL('Q'));
X	}
X}
SHAR_EOF
if test 2141 -ne "`wc -c 'capture.c'`"
then
	echo shar: error transmitting "'capture.c'" '(should have been 2141 characters)'
fi
echo shar: extracting "'main.c'" '(7955 characters)'
if test -f 'main.c'
then
	echo shar: over-writing existing file "'main.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'main.c'
X/*
X * Main Module
X *
X *
X *	ST users @ Case Western Reserve University
X */
X
X#include <osbind.h>
X#include "xmdm.h"
X
X#define	esc	27
X#define cr	0x0d
X
X 	/* Global variable  definitions, extern everywhere else */
Xchar bufr[ BUFSIZ ];		/* File buffer */
Xchar filename[FILEMAX+3];	/* File name */
Xunsigned int buf_index = 0;	/* Index to file buffer */
Xchar capture = 0;		/* Ascii capture flag   */
Xlong *ms_ptr;			/* Pointer to my screen memory, aligned at
X				   a 256 bytes boundary */
Xlong m_screen[8*1024+32];	/* My screen memory
X				   32K bytes + 256 Bytes guard for alignement
X				   In the worst case when we align we have to
X				   go 255 bytes from &m_screen[0], hence the
X				   256 Byte guard is required */
X
X
X 	/* Types */
X/* The structure returned by Iorec(), really ptr to this type */
Xtypedef struct {
X	char *ibuf;
X	int ibufsiz;
X	int ibufhd;
X	int ibuftl;
X	int ibuflow;
X	int ibufhi;
X} IOREC;
X
X/* The type word */
Xtypedef short word;
X
X
X 	/* Globals belonging to this module only */
XIOREC save,	/* the original Iorec is saved here for the duration of this
X		   process */
X 	*p;	/* ptr returned by Iorec() */
X
Xchar iobuf[IBUFSIZ]; /* My large Rs232 receive buffer */
X
Xword	rs232 = 1,		/* Ports */
X        console = 2;
Xword	speed,			  /* rs232 setup parameters */
X 	flowctl = 1,
X	ucr = -1,
X	rsr = -1,
X	tsr = -1,
X	scr = -1;
X
X/*
X * SetIoBuf() - Save the systems Rs232 buffer and install my large
X * Rs232 buffer.
X *
X */
Xvoid SetIoBuf()
X{
X	/* Get pointer to Rs232 input record */
X	p = Iorec(0);
X	
X	/* Save the info */
X	save.ibuf	= p->ibuf;
X	save.ibufsiz	= p->ibufsiz;
X	save.ibufhd	= p->ibufhd;
X	save.ibuftl	= p->ibuftl;
X	save.ibuflow	= p->ibuflow;
X	save.ibufhi	= p->ibufhi;
X	
X	/* Install my buffer in its place */
X	p->ibuf		= &iobuf[0];
X	p->ibufsiz	= IBUFSIZ;
X	p->ibuflow	= IBUFSIZ/4;
X	p->ibufhi	= IBUFSIZ / 4 * 3;
X	p->ibufhd = p->ibuftl = 0;
X	
X}
X
X/*
X * ResetIoBuf() - Reset the Rs232 buffer to the saved (system's) buffer
X *
X */
Xvoid ResetIoBuf()
X{
X	p->ibuf		= save.ibuf;
X	p->ibufsiz	= save.ibufsiz;
X	p->ibuflow	= save.ibuflow;
X	p->ibufhi	= save.ibufhi;
X	p->ibufhd	= save.ibufhd;
X	p->ibuftl	= save.ibuftl;
X}
X
X/* the following code is stolen from Tsu Wang - with permission of course */
X
X/*
X * setRs232() - set rs232 port configuration
X */
Xvoid setRs232 ()
X{
X	char ch;
X	long conin;
X	
X	Cconws("Baud rate: ");
X	EscSeq(p);
X	Cconws("0=19200 1=9600, 2=4800, 3=2400, 4=1200, 5=300\r\n");
X	EscSeq(q);
X	Cconout('\t');
X	EscSeq(p);
X	Cconws("What speed==>");
X	EscSeq(q);
X	
X	conin = Bconin(console);	/* get speed */
X	if (conin == 0x610000)
X	{
X		/* He hit <UNDO> */
X		if(capture)
X		{
X			Cconws("Closing Capture File\r\n");
X			c_capture();
X		}
X		his_screen();
X		ResetIoBuf();
X		Pterm0();
X		
X	}
X	ch = (char) (conin & 0x7f);
X	Cconout(' ');
X	switch (ch)
X	{
X	    case '0':		/* 19200 */
X		speed = 0;
X		Cconws("19200");
X		break;
X		
X	    case '1':
X		speed = 1;	/* 9600 */
X		Cconws("9600");
X		break;
X		
X	    case '2':
X		speed = 2;	/* 4800 */
X		Cconws("4800");
X		break;
X		
X	    case '3':
X		speed = 4;	/* 2400 */
X		Cconws("2400");
X		break;
X		
X	    case '4':
X		speed = 7;	/* 1200 */
X		Cconws("1200");
X		break;
X		
X	    case '5':
X		speed = 9;	/* 300 */
X		Cconws("300");
X		break;
X		
X	    default:
X		speed = 7;	/* 1200 */
X		Cconws("1200");
X	}
X	Cconws(" Baud\r\n");
X	
X	/* Set new Baud rate */
X	Rsconf(speed, flowctl, ucr, rsr, tsr, scr);
X
X	/* get rid of extraneous characters that get sent out */
X	Bconout(rs232,(word)'\b');
X	
X}
X
X/*
X * help() - display help info and menu
X */
Xvoid help ()
X{
X	word c;
X	long conin;
X	char *r_filename();
X	
X	EscSeq(j);		/* Save Cursor */
X	my_screen();		/* Switch to my screen memory */
X	EscSeq(v);		/* wrap at end of line */
X	EscSeq(E);		/* clear screen */
X	
X	/* Put up menu */
X	Cconws("\r\n\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("Undo");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" to exit.\r\n");
X	
X	Cconws("\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("Help");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" for this message.\r\n");
X	
X	Cconws("\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("C or c");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" to toggle Capture.\r\n");
X	
X	Cconws("\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("S or s");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" to Send a file using Xmodem.\r\n");
X	
X	
X	Cconws("\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("R or r");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" to Receive a file using Xmodem.\r\n");
X	
X	Cconws("\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("Return");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" to do nothing.\r\n");
X	
X	Cconws("\t");
X	EscSeq(p);		/* reverse video */
X	Cconws("B or b");
X	EscSeq(q);		/* quit reverse video */
X	Cconws(" to set baud rate.     Default is ");
X	EscSeq(p);
X	Cconws("1200 Baud.\r\n\r\n");
X	EscSeq(q);
X
X	/* get response */
X	conin = Bconin(console);
X
X	if (conin == 0x610000)
X	{
X		/* He hit <UNDO> */
X		if(capture)
X		{
X			Cconws("Closing Capture File\r\n");
X			c_capture();
X		}
X		his_screen();
X		ResetIoBuf();
X		Pterm0();
X	}
X	
X	switch((int)(conin & 0x7f))
X	{
X	    case 'B':
X	    case 'b':
X		/* Set baud rate */
X		setRs232();
X		break;
X		
X	    case 'C':
X	    case 'c':
X		/* Toggle Capture */
X		if(capture)
X		    c_capture();
X		else
X		    s_capture();
X		break;
X		
X	    case 'S':
X	    case 's':
X	    {
X		    /* Send a file using Xmodem */
X		    register char *f;
X		    if(capture)
X		    {
X			    /* We are capturing */
X			    Cconws("Closing Capture File\r\n");
X			    c_capture();
X		    }
X
X		    if((f = r_filename()) == (char *)NULL)
X		    {
X			    /* user cancelled transfer */
X			    canit();
X			    flushinput();
X			    break;
X		    }
X
X		    /* Set no flow Control */
X		    Rsconf(-1,0,-1,-1,-1,-1);
X
X		    /* Send file */
X		    if(sendfile(f) == FALSE)
X			Cconws("\r\nTransfer not Completed\r\n");
X		    else
X			Cconws("\r\nTransfer Complete\r\n");
X		    
X		    /* Flow Control On */
X		    Rsconf(-1,1,-1,-1,-1,-1);
X		    Bconout(rs232,(word)'\b');
X	    }
X		break;
X		
X	    case 'r':
X	    case 'R':
X	    {
X		    /* receive using Xmodem */
X		    register char *f;
X		    if(capture)
X		    {
X			    /* We are capturing */
X			    Cconws("Closing Capture File\r\n");
X			    c_capture();
X		    }
X
X		    if((f = r_filename()) == (char *)NULL)
X		    {
X			    /* user cancelled transfer */
X			    canit();
X			    flushinput();
X			    break;
X		    }
X		    
X
X		    /* No flow control */
X		    Rsconf(-1,0,-1,-1,-1,-1);
X
X		    /* receive file */
X		    if(readfile(f) == FALSE)
X			Cconws("\r\nTransfer not Completed\r\n");
X		    else
X			Cconws("\r\nTransfer Complete\r\n");
X		    
X		    /* flow control on */
X		    Rsconf(-1,1,-1,-1,-1,-1);
X		    Bconout(rs232,(word)'\b');
X	    }
X		break;
X		
X	    default:
X		Cconws("No Change\r\n");
X	}
X
X	/* Wait for a key hit */
X	hit_key();
X	/* back to terminal screen */
X	his_screen();
X}
X
Xmain ()
X{
X	word	c;		/* rs232 input */
X	long	conin;
X	int	i;
X	
X	ms_ptr = (long *) ((0xffffff00 & ((long)(&m_screen[0]))) + 0x00000100);
X	EscSeq(v);		/* wrap at end of line */
X	EscSeq(E);		/* clear screen */
X	SetIoBuf();
X
X	Rsconf((word) 7, flowctl, ucr, rsr, tsr, scr);  /* init set */
X	Bconout(rs232,(word)'\b');
X
X	help();
X
X	while (0 == 0)	/* infinite loop */
X	{
X		i = 0;
X		while (Bconstat(rs232) == 0xffff)
X		{
X			/* Char at Modem */
X			c = Bconin(rs232) & 0x7f;
X			Bconout(console, c);
X			if(capture)
X			    /* We are capturing */
X			    a_capture(c);
X
X			/* Check the console once in a while */
X			/* important at High speeds */
X			if ((++i) & 32)
X			    if (Bconstat(console) == 0xffff)
X	      		    {
X				    conin = Bconin(console);
X				    Bconout(rs232, (word) (conin & 0x7f));
X				    i = 0;
X			    }
X		}
X		
X		if (Bconstat(console) == 0xffff)
X		{
X			/* Char at Console */
X			conin = Bconin(console);
X			if (conin == 0x610000)		/* Undo */
X			{
X				if(capture)
X				{
X					Cconws("Closing Capture File\r\n");
X					c_capture();
X				}
X				ResetIoBuf();
X				Pterm0();
X			}
X			
X			if (conin == 0x620000)		/* Help */
X			    help();
X			else
X			    Bconout(rs232, (word) (conin & 0x7f));
X		}
X	}
X}
SHAR_EOF
if test 7955 -ne "`wc -c 'main.c'`"
then
	echo shar: error transmitting "'main.c'" '(should have been 7955 characters)'
fi
echo shar: extracting "'util.c'" '(1633 characters)'
if test -f 'util.c'
then
	echo shar: over-writing existing file "'util.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'util.c'
X/*
X * Utilities Module
X *
X *
X *	ST users @ Case Western Reserve University
X */
X
X#include <osbind.h>
X#include "xmdm.h"
X
X#define Vsync()	xbios(37)	/* Atari forgot this one in osbind.h */
X
X 	/* External Variables */
Xextern char filename[];	/* Pointer to filename buffer	*/
Xextern long *ms_ptr;	/* pointer to my screen memory aligned to a 256
X			   byte boundary */
X
X 	/* Globals */
Xstatic char *hs_ptr;   /* pointer to his screen memory */
X
X/*
X * my_screen() - Start using my screen memory
X * for all output.
X *
X */
Xvoid my_screen()
X{
X	/* The cursor position has been saved prior to calling this routine */
X	/* save his screen memory pointer */
X	hs_ptr = Logbase();
X	
X	/* switch to my display memory */
X	Setscreen(ms_ptr, ms_ptr, -1);
X}
X
X
Xvoid his_screen()
X{
X	/* switch to his Screen memory, wait for a Vblank, so
X	 * that the Logical Loc == Physical Loc, then pop saved
X	 * cursor */
X	Setscreen(hs_ptr, hs_ptr, -1);
X	Vsync();
X	Vsync();	/* starts happening at the last one */
X	EscSeq(k);
X}
X
X/*
X * r_filename() - Read a file name from the console
X * giving the user a chance to cancel by hitting <RETURN>
X *
X */
Xchar *r_filename()
X{
X	Cconws("Filename (<RETURN> to cancel): ");
X	filename[0] = FILEMAX;
X	Cconrs(filename);
X	Cconws("\r\n");
X	if(filename[1] == 0)
X	{
X		/* User Cancelled */
X		Cconws("Cancelled\r\n");
X		return((char *)NULL);
X	}
X	/* Terminate string that starts at filename[2] */
X	filename[filename[1]+2] = '\0';
X	return(&filename[2]);
X}
X
X
X/*
X * hit_key() - wait for the user to hit a key
X * 
X */
Xvoid hit_key()
X{
X	Cconws("\r\n");
X	EscSeq(p);
X	Cconws("Hit Any Key To Continue .....");
X	EscSeq(q);
X	Cnecin();
X	Cconws("\r\n");
X}
SHAR_EOF
if test 1633 -ne "`wc -c 'util.c'`"
then
	echo shar: error transmitting "'util.c'" '(should have been 1633 characters)'
fi
echo shar: extracting "'xmodem.c'" '(14676 characters)'
if test -f 'xmodem.c'
then
	echo shar: over-writing existing file "'xmodem.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'xmodem.c'
X/*
X * Xmodem Send / Receive Module
X * adapted from generic Xmodem send/receive code
X * posted to SIG*ATARI on CompuServe
X *
X *	ST users @ Case Western Reserve University
X */
X
X#include <osbind.h>
X#include <setjmp.h>
X#include "xmdm.h"
X
X 	/* Xmodem specific defines */
X#define DOTS		50	/* SECTOR COUNTING DOTS PER LINE */
X#define	SECSIZ		0x80	/* Size of a xmodem sector/block */
X#define	ERRORMAX	20	/* MAX ERRORS BEFORE ABORT very conservative */
X#define	RETRYMAX	15	/* MAXIMUM RETRYS BEFORE ABORT */
X#define	SOH		1	/* START OF SECTOR CHAR */
X#define	EOT		4	/* end of transmission char */
X#define	ACK		6	/* acknowledge sector transmission */
X#define	NAK		21	/* error in transmission detected */
X#define CAN		('X'&037) /* Cancel transmission	  */
X
X#define sendchar(X)	Cauxout(X) /* Send a character to serial port */
X#define Supexec(X) xbios(38,X)
X
X 	/* External Variables */
Xextern char bufr[ ];	/* file buffer */
X
X 	/* Global Variables */
Xstatic int mtimeout,	         /* Time out period	*/
X	   mdm_sp,     /* #packets sent */
X	   mdm_rp,     /* #packets received */
X	   mdm_bad_packets,	 /* #bad packets      */
X	   mdm_naked_packets;	 /* #naked packets    */
X
Xlong mdm_bytes_xferred,   /* #packets sent/received	   */
X     alrm_time = 0L,	  /* Time of next timeout (200 Hz) */
X     pr_time   = 0L,	  /* Present time	  (200 Hz) */
X     *hz_200 = (long *)0x000004ba; /* Yes the Hitch Hikers Guide is wrong!! */
X
Xjmp_buf abort_env,		  /* Long jump when transfers are aborted */
X        time_env;		  /* Long jump on timeout		  */
X
X#ifdef DEBUG
Xstatic int    debug = 1;
X#endif
X
X
X
X
X/*
X * rd_time() - read the value of the systems 200 Hz counter
X * must be called in Super Mode else you get
X * what you deserve - MUSHROOMS!!
X */
Xvoid rd_time()
X{
X	pr_time = *hz_200;
X}
X
X
X/*
X * read_modem() - read a character from the modem port
X * Check for user abort (^C) and timeout at the same time
X */
Xint read_modem()
X{
X	while(1)
X	{
X		if(Cconis())
X		{
X			/* Character Hit at the Keyboard - is it ^C */
X			if((Crawcin() & 0x7f) == CTRL('C'))
X			    /* It is a Control-C */
X			    longjmp(abort_env,-1);
X		}
X
X		if(Cauxis())
X		    /* Character available at Modem Port */
X		    return(Cauxin());
X		
X		/* Check for time out if required */
X		if(alrm_time != 0)
X		{
X			/* Alarm Set */
X			Supexec(rd_time);
X			if(pr_time >= alrm_time)
X			    /* timeout */
X			    longjmp(time_env, -1);
X		}
X	}
X}
X
X/*
X * mdmini() - initialize variables for a Xmodem Transfer
X *
X */
Xvoid mdmini()
X{
X	mtimeout = 20;
X	mdm_bytes_xferred = 0L;
X	mdm_sp = 0;
X	mdm_rp = 0;
X	mdm_bad_packets = 0;
X	mdm_naked_packets = 0;
X}
X
X
X/*
X * readfile() - Xmodem Receive
X * We use extremely conservative timeout/retry parameters
X * to deal with lazy dogs like CompuServe. The program
X * could be enhanced to be adaptive by increasing the
X * timeout as and when timeouts occur, dynamically.
X */
Xint readfile(file)
Xchar *file;
X{
X	int firstchar,	/* First character of the packet		*/
X	sectnum,	/* The currently expected sector # 		*/
X	sectcurr,	/* The received sector # 			*/
X	sectcomp,	/* The 1's complements of sectcurr		*/
X 	fd,		/* File descriptor for opened file	  	*/
X	errors,	/* The number of errors encountered in this transfer 	*/
X	errorflag;	/* Just a flag					*/
X	
X	unsigned int
X	    checksum,	/* Computed Checksum (of the received data)	*/
X	    j,		/* Counter					*/
X	    bufptr;	/* Buffer index					*/
X
X	
X	/* Initialize myself */
X	mdmini ();
X	
X	/* Create/Open file for write - overwrite if it exists */
X	if ((fd = Fcreate(file,0)) < 0) /* Will fail is file present */
X	{
X		/* Overwrite existing file */
X		if((fd = Fopen(file,1)) < 0)
X		{
X			/* CAN the transfer if we cannot open file */
X			Cconws("Cannot Open ");
X			Cconws(file);
X			Cconws("\r\n");
X			canit();
X			flushinput();
X			return(FALSE);
X		}
X	}
X	else
X	{
X		/* We are ready now */
X		Cconws("Receiving ");
X		Cconws(file);
X		Cconws(" ( CTRL-C to Abort )\r\n");
X	}
X	sectnum = errors = bufptr = 0;
X	
X    r_again:
X	flushinput();
X	
X	/* Send NAK to let sender know that we are ready */
X	sendchar(NAK);
X	
X	if (setjmp(time_env))
X	{
X		/* On a Timeout */
X		if(++errors < ERRORMAX)
X		{
X			Cconout('T');
X			goto r_again;	/* Sorry about that !! */
X		}
X		Cconws("\r\nToo many time outs Aborted Transfer\r\n");
X		Fclose(fd);
X		alarm(0);
X		canit();
X		flushinput();
X		return(FALSE);
X	}
X	
X	if (setjmp(abort_env))
X	{
X		/* User initiated Abort - (CTRL-C) */
X		Cconws("\r\nUser Aborted Transfer\r\n");
X		Fclose(fd);
X		alarm(0);
X		canit();
X		flushinput();
X		return(FALSE);
X	}
X	
X	firstchar = 0;
X	while (firstchar != EOT && errors != ERRORMAX)
X	{
X		errorflag = FALSE;
X		alarm (mtimeout);			/* set timeout trap */
X		do					/* get sync char */
X		{
X			firstchar = read_modem();
X#ifdef DEBUG
X			if (debug)
X			{
X				Cconws("Got char ");
X				printi( firstchar);
X				Cconws("\r\n");
X			}
X#endif
X		} while (firstchar != SOH && firstchar != EOT && firstchar != CAN);
X		
X		if( firstchar == CAN)
X		{
X			/* Sender Cancelled */
X			Cconws("Transfer Cancelled By Sender\r\n");
X			Fclose(fd);
X			flushinput();
X			alarm(0);
X			return(FALSE);
X		}
X		
X		if (firstchar == SOH)
X		{
X			/* Ok, got Start of a new packet, pick up the sector # and ~# */
X			sectcurr = read_modem();
X			sectcomp = read_modem();
X			
X			if (((sectcurr - 1) % DOTS) == 0)
X			{
X				/* Let us know about it - newline every DOTS dots */
X				Cconws("\r\n.");
X#ifdef DEBUG
X				if(debug)
X				    printi(sectcurr);
X#endif
X			}
X			else
X			    Cconout('.');
X			
X#ifdef DEBUG
X			/*	if (debug)
X				{
X				Cconws("Sector ");
X				printi( sectcurr);
X				Cconout(' ');
X				printi( sectcomp);
X				Cconws("\r\n");
X				}
X				*/
X#endif
X			if ((sectcurr + sectcomp) == 255)
X			{
X				/* Valid sector # */
X				if (sectcurr == (sectnum + 1 & 0xff))
X				{
X					/* And sector in expected sequence */
X					checksum = 0;
X					for (j = bufptr;j < (bufptr + SECSIZ);j++)
X					{
X						/* Pick up data */
X						bufr[j] = read_modem();
X						/* Computing checksum as we go along */
X						checksum = (checksum + bufr[j]) & 0xff;
X					}
X					if (checksum == read_modem())
X					{
X						/* Computed Checksum matches received checksum */
X						mdm_rp++;
X						
X						errors = 0;
X						sectnum++;
X						bufptr += SECSIZ;
X						mdm_bytes_xferred += SECSIZ;
X						if (bufptr == BUFSIZ)
X						{
X							/* Buffer Full - flush it out to file */
X							bufptr = 0;
X							if (Fwrite(fd,(long)BUFSIZ,bufr) < 0)
X							{
X								Cconws("\r\nError writing file - Aborting Transfer\r\n");
X								Fclose(fd);
X								alarm(0);
X								canit();
X								flushinput();
X								return(FALSE);
X							};
X						};
X						flushinput ();
X						/* Every thing ok - send the ACK */
X						sendchar(ACK);
X					}
X					else
X					{
X						/* Received Checksum doe not match computed checksum */
X						mdm_bad_packets++;
X						
X						errorflag = TRUE;
X#ifdef DEBUG
X						if (debug)
X						{
X							Cconout('C');
X						};
X#endif
X					}
X				}
X				else
X				{
X					/* Sector received is not the expected one */
X					/* Could be a duplicate sector, or just a curropted sector */
X					if (sectcurr == (sectnum & 0xff))
X					{
X						/* Duplicate sector - just ignore it and ACK */
X						Cconout('D');
X						flushinput();
X						sendchar(ACK);
X					}
X					else
X					{
X						/* Garbage */
X#ifdef DEBUG
X						if (debug)
X						{
X							Cconws("synch error\r\n");
X						}
X#endif
X						
X						mdm_bad_packets++;
X						
X						errorflag = TRUE;
X					}
X				}
X			}
X			else
X			{
X#ifdef DEBUG
X				if (debug)
X				{
X					Cconws("sector number error\r\n");
X				}
X#endif
X				mdm_bad_packets++;
X				
X				errorflag = TRUE;
X			}
X		}
X		if (errorflag == TRUE)
X		{
X			/* NAK it if errorflag is set */
X			errors++;
X			flushinput();
X			sendchar(NAK);
X		}
X		
X	};	/* end while  Not EOT and errors < ERRORMAX */
X	
X	
X	if ((firstchar == EOT) && (errors < ERRORMAX))
X	{
X		/* Last packet */
X		sendchar(ACK);
X		if(Fwrite(fd,(long)bufptr,bufr) != bufptr)
X		{
X			Cconws("\r\nError writing file\r\n");
X			Fclose(fd);
X			alarm(0);
X			return(FALSE);
X		}
X		Fclose(fd);
X		alarm(0);
X		return(TRUE);
X	}
X	alarm(0);
X	return(FALSE);
X}
X
X/*
X * sendfile() - Xmodem Send
X * See comments for readfile() concerning timeouts/retries.
X *
X */
Xint sendfile(file)
Xchar *file;
X{
X	int sectnum,	/* Current sector number */
X	sectors,	/* #of sectors sent      */
X	attempts,	/* #of attempts to send  */
X	fd;		/* File descriptor	 */
X	
X	unsigned int
X	    checksum,	/* Computed checksum	 */
X	j,		/* all purpose counter	 */
X	bufptr;		/* Ptr to file buffer	 */
X	
X	char
X	    c;		/* General Character var */
X	
X	/* init. myself */
X	mdmini ();
X
X	/* Open file for read */
X	if ((fd = Fopen(file, 0)) < 0)
X	{
X		/* CAN tranfer if we can't open */
X		Cconws("cannot open ");
X		Cconws(file);
X		Cconws("\r\n");
X		canit();
X		flushinput();
X		return(FALSE);
X	}
X	else
X	{
X		Cconws("Sending ");
X		Cconws(file);
X		Cconws(" ( CTRL-C to Abort )\r\n");
X	}
X
X	/* All set to go */
X	attempts = 0;
X	sectnum = 1;
X	j = 0;
X	
X	
X	if (setjmp(abort_env))
X	{
X		/* On user initiated abort (CTRL-C) */
X		Cconws("\r\nUser Aborted Transfer\r\n");
X		Fclose(fd);
X		alarm(0);
X		canit();
X		flushinput();
X		return(FALSE);
X	}
X	
X	attempts = 0;
X	
X	do {
X	    s_again:
X		
X		if (setjmp(time_env))
X		{
X			/* On Time Out */
X			if(attempts < (2*ERRORMAX))
X			{
X				Cconout('T');
X				flushinput();
X				goto s_again;	/* Sorry about that !! */
X			}
X			Cconws("\r\nToo many time outs Aborted Transfer\r\n");
X			Fclose(fd);
X			alarm(0);
X			canit();
X			flushinput();
X			return(FALSE);
X		}
X		
X		/* Wait for First char from receiver */
X		alarm(mtimeout);
X		c = read_modem();
X		
X#ifdef DEBUG
X		if (debug)
X		{
X			Cconws("Ate char ");
X			printi( c);
X			Cconws("\r\n");
X		}
X#endif
X		/* Eat everything but a NAK or CAN */
X	} while ((c != NAK) && (c != CAN) && (j++ < (ERRORMAX*2)));
X	
X	if( c == CAN)
X	{
X		/* receiver cancelled */
X		Cconws("Transfer Cancelled By Receiver\r\n");
X		Fclose(fd);
X		flushinput();
X		alarm(0);
X		return(FALSE);
X	}
X	
X	if (j >= (ERRORMAX*2))
X	{
X		/* Too many errors */
X		Cconws("\r\nReceiver not sending NAKs - Aborting\r\n");
X		canit();
X		flushinput();
X		alarm(0);
X		return(FALSE);
X	}
X	
X#ifdef DEBUG
X	if (debug)
X	    Cconws ("Got ACK\r\n");
X#endif
X	
X	flushinput (); /* Get rid of any junk on the line */
X	alarm(mtimeout);
X	
X	while ((sectors = Fread(fd,(long)BUFSIZ,bufr))
X	       && (attempts != RETRYMAX))
X	{
X		if (sectors < 0)
X		{
X			/* Unable to read the file */
X			Cconws("\r\nError reading file - Aborting Transfer\r\n");
X			Fclose(fd);
X			alarm(0);
X			canit();
X			flushinput();
X			return(FALSE);
X		}
X
X		bufptr = 0;
X		do
X		{
X			attempts = 0;
X			do
X			{
X			    s_ag2:
X				alarm(mtimeout);
X				if (setjmp(time_env))
X				{
X					/* on time out */
X					if(attempts < (2*ERRORMAX))
X					{
X						Cconout('T');
X						flushinput();
X						goto s_ag2;	/* Sorry about that !! */
X					}
X					Cconws("\r\nToo many time outs Aborted Transfer\r\n");
X					Fclose(fd);
X					alarm(0);
X					canit();
X					flushinput();
X					return(FALSE);
X				}
X				
X				if (((sectnum) % DOTS) == 0)
X				{
X					Cconws("\r\n");
X#ifdef DEBUG
X					if(debug)
X					    printi(sectnum);
X#endif
X					Cconout('.');
X				}
X				else
X				    Cconout('.');
X				
X				/* Send a packet */
X				sendchar(SOH);
X				sendchar(sectnum);
X				sendchar(~sectnum);
X				checksum = 0;
X				write_modem(&bufr[bufptr],SECSIZ);
X				for (j = bufptr; j < (bufptr+SECSIZ); j++)
X				    checksum += bufr[j];
X				sendchar(checksum);
X				flushinput();
X				mdm_sp++;
X				
X				attempts++;
X				/* Did it get sent over ? */
X				c = read_modem();
X				
X				if (c != ACK)
X				    /* Oh no */
X				    mdm_naked_packets++;
X#ifdef DEBUG
X				if (debug)
X				{
X					Cconws ("Response char is ");
X					printi( c);
X					Cconws("\r\n");
X				}
X#endif
X				if( c == CAN )
X				{ 
X					/* Receiver cancelled - so i'll abort */
X					Cconws("Transfer Cancelled By Receiver\r\n");
X					Fclose(fd);
X					flushinput();
X					alarm(0);
X					return(FALSE);
X				}
X				
X			} while ((c != ACK) && (attempts != RETRYMAX));
X			/* Packet got sent and I received an Ack, or
X			   too many attempts */
X			bufptr += SECSIZ;
X			mdm_bytes_xferred += SECSIZ;
X			sectnum++;
X		} while ((bufptr < sectors) && (attempts != RETRYMAX));
X	};
X	
X	Fclose(fd);
X	if (attempts == RETRYMAX)
X	{
X		/* Too many attempts */
X		Cconws("\r\nNo acknowledgment of sector, aborting\r\n");
X		alarm(0);
X		canit();
X		flushinput();
X		return(FALSE);
X	}
X	else
X	{
X		/* All sectors that needed to be sent are done,
X		   Now send the EOT to complete transfer,
X		   The EOT may or may not get ACK'ed, warn
X		   the user if it does'nt */
X		attempts = 0;
X		do
X		{
X		    s_ag3:
X			alarm(mtimeout);
X			if (setjmp(time_env))
X			{
X				if(attempts < (2*ERRORMAX))
X				{
X					Cconout('T');
X					flushinput();
X					goto s_ag3;	/* Sorry about that !! */
X				}
X			}
X			
X			sendchar(EOT);
X			attempts++;
X		} while ((read_modem() != ACK) && (attempts != RETRYMAX));
X		if (attempts == RETRYMAX)
X		    Cconws("\r\nNo acknowledgment of end of file - Hopefully the file made it\r\n");
X	};
X	alarm(0);
X	return(TRUE);
X}
X
X/*
X * alarm() - set the alarm time
X */
Xvoid alarm(n)
Xunsigned int n;
X{
X	if(n != 0)
X	{
X		Supexec(rd_time);
X		/* We really need n * 200 but n * 256 if close enough */
X		alrm_time = pr_time + ( n << 8 );
X	}
X	else
X	    alrm_time = 0L;
X}
X
X/*
X * canit() - Cancel the transfer
X */
X
Xcanit()
X{
X	register int i;
X	
X	/* Send 5 CAN's */
X	for(i = 0; i < 5; i++)
X	    sendchar(CAN);
X
X	/* Get rid of 4 of them, some receivers expect at least 2
X	   CANs to confirm that the first CAN was not a corrupted
X	   ACK, but eat only one (Ymodem for instance). */
X	   
X	for(i = 0; i < 4; i++)
X	    sendchar('\b');
X}
X
X/*
X * write_modem() - send buffer to the modem port
X *
X*/
Xvoid write_modem(buf,len)
Xregister char *buf;
Xregister int len;
X{
X	register int i;
X	for(i = 0; i < len; i++)
X	    Cauxout(*buf++);
X}
X
X
X/*
X * flushinput() - flush any characters in the modem port
X * a future enhancement may be flush any characters that are in there
X * and any that come in over the next 1 second -- Ymodem does that
X *
X */
Xvoid flushinput()
X{
X	while(Cauxis())
X	    Cauxin();
X}
X
X#ifdef DEBUG
X/*
X * Print an integer (16 bits) to the console
X *
X */
Xvoid printi(val)
Xregister int val;
X{
X        register int j;
X        register int div_idx;
X        register int first;
X	
X        static int divisors[] = { 10000, 1000, 100, 10, 1 };
X	
X	
X	/* Special Cases */
X        if (val == 0)
X	{
X		Cconout('0');
X	}
X        else if (val == -32768)
X	{
X                Cconws("-32768");
X		
X	}
X	
X	/* Get digit for each power of 10 and print them, skip leading 0's */
X        first = div_idx  = 0;
X	
X        if (val < 0)
X	{
X                Cconout('-');
X                val = -val;
X	}
X	
X        while( div_idx < 5 )
X	{
X                if(((j = val / divisors[div_idx]) != 0) || first != 0)
X		{
X                        Cconout(j + '0');
X                        first = 1;
X		}
X                val %= divisors[div_idx++];
X	}
X	
X}
X#endif
SHAR_EOF
if test 14676 -ne "`wc -c 'xmodem.c'`"
then
	echo shar: error transmitting "'xmodem.c'" '(should have been 14676 characters)'
fi
echo shar: extracting "'xmdm.h'" '(494 characters)'
if test -f 'xmdm.h'
then
	echo shar: over-writing existing file "'xmdm.h'"
fi
sed 's/^X//' << \SHAR_EOF > 'xmdm.h'
X 	/* Common defines */
X#define NULL		(0L)
X#define void 		int	/* Alcyon forgot about voids */
X#define	FALSE 		0
X#define TRUE 		1
X
X#define EscSeq(x)	Cconout('\033'); Cconout('x') /* Send Esc. Seq. to
X							 console */
X#define CTRL(X)		(X & 037) /* CTRL-anything */
X#define IBUFSIZ		16*1024	/* Size of my Rs232 receive buffer */
X#define	BUFSIZ		0x4000	/* Size of file buffer 		 */
X 				/* MUST BE a multiple of SECSIZE (128)  */
X#define FILEMAX 	32	/* Max length of file name (must be <=127 ) */
SHAR_EOF
if test 494 -ne "`wc -c 'xmdm.h'`"
then
	echo shar: error transmitting "'xmdm.h'" '(should have been 494 characters)'
fi
echo shar: extracting "'xmdm.doc'" '(4175 characters)'
if test -f 'xmdm.doc'
then
	echo shar: over-writing existing file "'xmdm.doc'"
fi
sed 's/^X//' << \SHAR_EOF > 'xmdm.doc'
XThis the first version of xmdm:
X
X	Features:
X		- Keeps up with high speed serial lines
X			(tested upto 19.2K Baud lines)
X
X		- Does'nt send ANY Xon/Xoff's in the terminal
X		  emulation mode to the host. This is important
X		  to us as we are all Emacs fans.
X
X		- Supports all baud rates.
X
X		- Ascii file capture.
X
X		- Xmodem Send/Receive.
X	
X		- Uses large Rs232 receive buffer.
X
X		- Uses large file buffers. Will not beat your disk
X		  drive to death like STTALK.
X
X		- Uses 2 screens. All local functions (prompts etc) are done
X		  on a on one screen, and all host communication
X		  appears and the other screen.
X
X		- Uses very conservative timeouts/retries figures.
X		  Good for dealing with dogs like CompuServe.
X		  If you have a very responsive host, then it does'nt
X		  matter anyways.
X
X		- PD, share it with your friends. Only thing we ask for is
X		  your comments, bug reports (& fixes). Of course we
X		  are not in anyway responsible for any brain damage
X		  it may cause.
X
X	Known Bugs:
X		- Send spurious characters when it changes Rs232
X		parameters (Baud rate, Flow Control). Normally this
X	    	does not cause a problem, just hit a return when you
X		get back to your host.
X
X		- When switching screens, it always homes the cursor.
X		(We would appreciate if anyone could tell us how to
X		 fix this. What we are doing in the Code (routines
X		 his_screen & my_screen) is pushing the cursor, 
X		 changing screens, doing local functions, changing
X		 back to the old screen, and doing a pop cursor. The
X		 HH guide says that the vt52 emulator is only reset
X		 when you change rez.) This does cause inconvenience.
X
X		- Has not been extensively debugged!
X
X		- Sketchy documentation.
X
X	So why are we posting it? 
X	To get your feedback on the general scheme of things (interface
Xetc.) and suggestions to fix the above bugs.
X
X	Coming Up:
X		- Kermit transfers, and remote server support.
X
X		- Key Macros and binding of keys to functions.
X
X		- Dialing Directory.
X
X		- dir, space, remove, rename, cd, change drive
X		  functions.
X
X		- Code needs cleaning up.
X
X	Not coming up:
X		- Ascii file transmit. We do not see a need for this.
X
XTo compile and link:
X	Compile each .c to get  .o's
X
X	link68 [u] xmdm.68k=[gems|gemstart], <all the .o's>,osbind.o,gemlib
X	relmod xmdm
X	
XIf you use gemstart, then the stack+heap size must be appropriately
Xmodified. I use 16K.
X
X	get rid of xmdm.68k
X	rename xmdm.prg to xmdm.tos to use from the desktop.
X
XUSAGE: 
X	Double click on xmdm.tos and follow the first prompt that
Xcomes up. Hit the <help> key at any time to get back at this menu.
X
XCapturing files:
X	Hit the <help> key, then choose the function 'c' for capture
Xtoggle. Give it a file name when it asks for one.
X	All host data will be captured from now onwards.
X	To end capture, hit <help> and choose the function 'c' again.
XThis will terminate the capture and close the file. Capture is also
Xterminate automatically when you choose any of the Xmodem functions,
Xon file errors, or when you exit the program.
X
XXmodem send:
X	Prepare your host to receive a file using xmodem. Hit the
X<help> key. Choose the 's' function, for xmodem send, and give it a
Xfile name. If you want to terminate at this point, hit return instead
Xof entering a file name. After the transfer has begun, you may
Xterminate the transfer at any time by hitting CTRL-C.
X
XXmodem receive:
X	Prepare your host to send a file using xmodem. Hit the
X<help> key. Choose the 'r' function, for xmodem receive, and give it a
Xfile name. If you want to terminate at this point, hit return instead
Xof entering a file name. After the transfer has begun, you may
Xterminate the transfer at any time by hitting CTRL-C.
X
XExiting xmdm:
X	The program may be exited at any time by hitting the <undo>
Xkey, except in the middle of Xmodem transfers.
X
XChanging baud rates:
X	Hit <help> then choose the 'b' function and make a selection.
X
X	Currently only the baud rate can be changed by the user. The
Xother Rs232 port parameters cannot be changed.
X
XPlease send you comments / bug reports and fixes to:
X
X			Jwahar R. Bammi
X		       Usenet:  .....!decvax!cwruecmp!bammi
X		        CSnet:  bammi@case
X			 Arpa:  bammi%case@csnet-relay
X		   CompuServe:  71515,155
SHAR_EOF
if test 4175 -ne "`wc -c 'xmdm.doc'`"
then
	echo shar: error transmitting "'xmdm.doc'" '(should have been 4175 characters)'
fi
#	End of shell archive
exit 0

-- 
					Jwahar R. Bammi
			       Usenet:  .....!decvax!cwruecmp!bammi
			        CSnet:  bammi@case
				 Arpa:  bammi%case@csnet-relay
			   CompuServe:  71515,155

langdon@lll-lcc.UUcp (Bruce Langdon) (02/10/86)

I have sent the source, termcap and documentation of ACSTERM to our
moderator for possible inclusion in the archives. I will also send it
directly to anyone who requests it. It is about 39K bytes.

------------
ACSTERM is a terminal emulator for the Atari 800, 800xl, 1200xl, 130xe.
It provides cursor motion, insert, delete, etc. The 'termcap' file tells
UNIX systems how to manipulate your screen. With 'more' and screen editors
like 'vi', this does near the best that can be done with a 40 column screen.
	The tilde and curly brace characters are provided using a redefined
character set; ^M etc. have their usual ascii meanings.
	ACSTERM was written by Clint Parker, author of the Action system.
All sources are in the Action language.
    As downloaded from the bbs he maintained, you must use the Action cartridge.
Here there is also a modification that compiles with the run-time library
to make an executable file that needs no cartridge.

	NB! R-Verter owners: The RHAND1C modem handler converts tilde and
brace characters. Since they provide the source, I deleted those parts.
I also cured occasional glitches it had running full tilt at 9600 baud,
and improved its handling of S/Reset. As that software is copyright, I
can't upload my version. However I am willing to upload a 'diff' file
that shows the changes I made. 

	These are the files:
TERM.DOC 	read this
TERMCAP.ACS	get this into your UNIX
TERM.AC0	Compile this file.
TERM1.AC0	these files will
TERM2.ACT	be INCLUDEd
TERM.AC2	My modifications
TERM1.ACT	of TERM, TERM1.
BLKIO.ACT	CIO caller and fast I/O.

I wrote an XMODEM module but never got it integrated into ACSTERM.
---------------------------------------------------------------------------
    This is an archive made with the UNIX utility 'ar'. Its first line is:
        !<arch>
For some reason the ! causes 'more' to think it's not an ascii file; but
'cat file | more' works, as does vi.
    If you don't have 'ar', split it with a text editor.



----------------------------------------------------------------------
	Bruce Langdon  L-472                langdon%lll-lcc@lll-crg.ARPA
	Physics Department                  "langdon#bruce%d"@lll-mfe.ARPA
	Lawrence Livermore National Laboratory       
	Livermore, CA 94550                 (415) 422-5444
UUCP: ..{gymble,ihnp4,seismo}!lll-crg!lll-lcc!langdon
----------------------------------------------------------------------
	Bruce Langdon  L-472                langdon%lll-lcc@lll-crg.ARPA
	Physics Department                  "langdon#bruce%d"@lll-mfe.ARPA
	Lawrence Livermore National Laboratory       
	Livermore, CA 94550                 (415) 422-5444
UUCP: ..{gymble,ihnp4,seismo}!lll-crg!lll-lcc!langdon