[net.sources] tvi920 emulator

ctk@ecsvax.UUCP (Tim Kelley) (02/17/85)

These are the files for a televideo tvi920c terminal emulator. Features are
listed in the READ.ME and term.doc files. The code is based on stuff that
R.F. Starr and Dave Betz posted to the net a while back. Betz's code
is in the file modem.c (which has been hacked up a little). Starr's code
is part of komm.c and has been hacked up a lot. Blame all bugs on me.
-----------------------------   cut  here ------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting READ.ME'
sed 's/^X//' <<'//go.sysin dd *' >READ.ME
	This program is a Televideo 920 emulation (pretty complete, no block
modes). Features include

	Ascii file transfer (using your line editor, ed on the ecsvax system).

	Binary file transfer using xmodem protocol.

	Works with the full screen package at NCSU and with vi on UN*X systems.

	On line help.

	Use of the exec dos call to allow you do local work while still on
	line.

	True break.

	Other goodies too numerous to mention (dials the phone etc.)

	

*********  Please report all bugs to ecsvax!ctk  ******************
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 755 READ.ME
	/bin/echo -n '	'; /bin/ls -ld READ.ME
fi
/bin/echo 'Extracting commio.h'
sed 's/^X//' <<'//go.sysin dd *' >commio.h

#include "stdio.h"
#define ON 1
#define OFF 2
#define SOH 1
#define BELL 7
#define LF 10
#define CR 13
#define XON 17
#define XOFF 19
#define EOZ 26
#define ESC 27
#define XTRA 127
#define DIE 129
#define IER 0x3f9
#define MCR 0x3fc
#define MSR 0x3fe
#define LSR 0x3fd
#define INTA00 0x20
#define EOI 0x20
#define CAN 0x18
#define BUFSIZE 4096   /* The buffer that the interrupt vector fills */
#define getkey() (bdos(7)&0xff)
#define lindel() linesx(0)
#define linins() linesx(1)
#define rowpos() (posit()>>8)
#define colpos() (posit()&0xff)
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 755 commio.h
	/bin/echo -n '	'; /bin/ls -ld commio.h
fi
/bin/echo 'Extracting funkey.c'
sed 's/^X//' <<'//go.sysin dd *' >funkey.c
X/* funtion keys */
#include "commio.h"

extern int brk(),menu(),dnl1(),upl(),hexdp(),clstat(),chterm(),exec1(),ferr();
extern int mdm7(),mdm8();

int (*fkey[])() = {brk,menu,dnl1,upl,hexdp,clstat,chterm,exec1,mdm8,mdm7};

funkey()
{
	int i,j,k,c,tvoff,tst;
	extern int hafdup,cms,unix;
	i=getkey();

	/* Function keys */
	if((i>58) && (i< 69) ) {(*fkey[i-59])(); return;}

	/* Alt-1 thru Alt-- are tvi keys F1 - F11  */
	/* shift-alt-1 thru shift-alt-- are the shifted tvi funct keys */
	if((i>119) && (i<131)){
	/* Test for the shift key */
	if(peek(0x17,0x40)&3) tvoff=24;
	else tvoff=56;
	tvi(i-tvoff);
	return;}

	/* So it's something else */
	switch(i)
	{
	case 83:  /* Del */
		if(cms) {xputc(ESC); xputc('W'); chdel(); break;}

	case 81:  /* Pg Dn */
		if(cms) { tvi('G'); break;}

	case 79:  /* end */
		if(!cms) brk();
		if(cms)   tvi('B');
		break;

	case 73:  /* page up for cms  */
		if(cms) tvi('F');
		break;

	case 82: /* insert for cms */
		if(cms) {xputc(ESC); xputc('Q'); chins();}
		break;

	case 71:  /* for cms the home key is PA2 in simterm */
		if(cms) tvi('2');
		break;

	case 18:	  /* alt-e toggles halfdup */
		dupsw();
		break;

	case 22:	/* alt-u or F4 toggle upload */
		upl();
		break;

	case 25:	 /* alt-p configures printer */
		xxprint();
		break;

	case 32:	 /* alt-d toggles download  */
		dwnl(0);  /* to named file*/
		break;

	case 35:	 /* alt-h calls help  */
		help();
		break;

	case 37:	/* alt-k sends passwork also */
		psswd();
		break;
	case 38:       /* alt-l sends logon line if any */
		/* Test for the shift key */
		if(peek(0x17,0x40)&3) {psswd(); break;}
		logon();
		break;

	case 46:	 /* alt-c cls  */
		cls();
		break;

	case 48:	 /* alt-b toggles bell */
		bellsw();
		break;

	case  72:    /* up arrow key  */
		if(hafdup) crup();
		xputc(11);
		break;

	case  75:
		if(hafdup) putchar('\b');     /* back arrow key */
		xputc(8);
		break;

	case  77:
		if(hafdup) crfr();   /* forward arrow key */
		xputc(12);
		break;

	case  80:	     /* down arrow key */
		if(hafdup){
			   k=colpos();
			   if(rowpos() == 23) {scroll(); locate(23,k);}
				else {crdn();}
			  }
		xputc(10);
		break;
X/* These control F-keys are for my logon to a remote machine */

	case 94:	/* purdue logon sequence */
		xwrite("xxxxxxx\r");
		break;
	case 95:
		xwrite("xxxxx\r");
		break;
	case 96:
		xwrite("xxx\r");
		break;
	case 103:	  /* cntrl-F10 exits */
		die();
		break;

	case 117:	/* cntrl-END hangs up the phone */
		cls();
		blast("Hanging up. Please wait.",7,0,0);
		wait(990);xwrite("+++");wait(900);wait(900);xwrite("ATH\r");
		break;

	case 119:	/* cntl-HOME gets to sim3278  */
		if(cms) xwrite("dial sim3278\r");
		break;

	case 131:     /* alt-= toggles tvi FUNC key  */
		status("tvi FUNC ON. Press key.",1);
		pshcur(); locate(24,40);
		k=menkey();
		popcur();
		tvi(k);
		clstat();
		break;

	default:
		ferr();
		break;
	}
}


tvi(c)	 /* Sends SOH c CR for tvi function key codes  */
int c;
{xputc(SOH); xputc(c); xputc(CR);}


dnl1() { dwnl(1); return;}



ferr() {
	 status("function key undefined. cntrl-F10 exits.",1);}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 funkey.c
	/bin/echo -n '	'; /bin/ls -ld funkey.c
fi
/bin/echo 'Extracting k2.c'
sed 's/^X//' <<'//go.sysin dd *' >k2.c
#include "commio.h"
X/* k2.c small system dependent routines
 * These functions use BIOS calls and
 * writes to screen memory.
 */

extern int *BLKLN,*TABLE,DATSEG,VIDEO;

struct regval
{
        unsigned int ax,bx,cx,dx,si,di,ds,es;
} destrv;

X/* Keyboard input functions  */

X/*
 *  inkey() -- Get a character from the keyboard if there is one.
 *  I have to use ROM BIOS rather than
 *  Dos calls in order to get XOFF to
 *  transmit properly when I hit CNTRL-S
 *  read about it on A-33 of TRM
 */
inkey()
{
        static struct regval chrts={0x100,0,0,0,0,0,0,0};
        if(sysint(0x16,&chrts,&destrv)&0x40) return(-2);
        return(bdos(7)&0xff);
}

X/* menkey -- flush keyboard buffer and get a character. */
menkey()
{
        static struct regval menks={0xc01,0,0,0,0,0,0,0};
        sysint21(&menks,&destrv);
        return(destrv.ax&0xff);
}


X/* Time and date related functions. */

X/* gdate -- get the date from DOS  */
gdate(d)
int d[];
{
        struct regval gdats;
        gdats.ax=0x2a00;
        sysint21(&gdats,&gdats);
        d[2]=gdats.cx-1900;
        d[0]=gdats.dx>>8;
        d[1]=gdats.dx&0xff;
}

X/* prdate -- printe the date. */
static unsigned char *datest = "00/00/00";
prdate()
{
        unsigned int dt[3];
        unsigned char *ctm;
        int k,j;
        ctm=datest;
        gdate(dt);
        for(k=0;k<3;k++) {
                j=dt[k]/10;
                *(ctm++)='0'+j;
                dt[k]-=j*10;
                *(ctm++)='0'+dt[k];
                ctm++;
        }
        blast(datest,7,0,0);
}

X/* gtime -- get the time from DOS  */
gtime(t)
int t[];
{
        struct regval gtims;
        gtims.ax=0x2c00;
        sysint21(&gtims,&gtims);
        t[0]=gtims.dx&0xff;
        t[1]=gtims.cx>>8;
        t[2]=gtims.cx&0xff;
        t[3]=gtims.dx>>8;
}

X/* time -- get the sec/100 from the time string. Used by wait(). */
time()
{
        int tt[4];
        gtime(tt);
        return(tt[0]);
}

X/* xrtime -- clock routine, does not move cursor. Writes to screen memory. */
static unsigned char *timest = "00:00:00";
xrtime(nr,ncl)
int nr,ncl;
{
        int j,k,time[4];
        char *ctm;
        ctm=timest;
        gtime(time);
        for(k=0;k<3;k++) {
                j=time[k+1]/10;
                *(ctm++)='0'+j;
                time[k+1]-=j*10;
                *(ctm++)='0'+time[k+1];
                ctm++;
        }
        blast(timest,7,nr,ncl);
}


X/* Location related functions. */


static struct regval posrv={
        0x300,0,0,0,0,0,0,0};
static struct regval locasx={
        0x200,0,0,0,0,0,0,0};
X/* posit -- gets cursor location from BIOS. See commio.h. */
posit()
{sysint(0x10,&posrv,&destrv);
return(destrv.dx);
}


X/* locate -- positions cursor, upper left corner = (0,0). */
locate(r,c)
int r,c;
{
        if((r<0) || (r>24) || (c<0) || (c>79)) {status("locate error",1);
                                                return;}
        locasx.dx=(r<<8)+c;
        sysint(0x10,&locasx,&destrv);  /* flush keyboard buffer and get a char. */
}


X/* linesx -- insert (ldl=1) or delete (ldl=0) line with BIOS. */
linesx(idl)
int idl;
{static struct regval lnrv={0,0x700,0,0x174f,0,0,0,0};
lnrv.cx=posit()&0xff00;    /* upper left corner of scroll at current line */
lnrv.ax=( idl ? 0x701 : 0x601);
sysint(0x10,&lnrv,&lnrv);
putchar('\r');
}

int attrib=0x700;
zputc(c)
int c;
{
int row,col,pst;
sysint(0x10,&posrv,&destrv);
row=destrv.dx>>8;
col=destrv.dx&0xff;
pokew(TABLE[row]+(col<<1),VIDEO,c|attrib);
if(col != 79) {
        locasx.dx=destrv.dx+1;
        sysint(0x10,&locasx,&destrv);
        return 0;
}
if(row != 23) {
        locate(row+1,0);
        return 1;
}
scroll();
return(1);
}


X/* scroll -- scolls the top 24 lines. */
scroll()
{
int q;
q=TABLE[23];
movblock(160,VIDEO,0,VIDEO,q);
locate(23,0);
movblock(BLKLN,DATSEG,q,VIDEO,160);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 k2.c
	/bin/echo -n '	'; /bin/ls -ld k2.c
fi
/bin/echo 'Extracting k3.c'
sed 's/^X//' <<'//go.sysin dd *' >k3.c
X/* k3.c  character handling. */
#include "commio.h"

extern int *TABLE,*BLKLN,DATSEG,VIDEO;

int klock=0; /* tvi keyboard lock flag */
outchar(c)
int c;
{
	static int escout=0,oc=2; /* oc=2 means ESC sent from terminal */
	extern int hafdup,cms,klock;
	if(c==NULL) {klock=0; funkey();}
	if(klock) return;
	/* check for tab and the ncsu cms system */
	if((c=='\t')&&cms) {tvi('C'); return;}
	if(c>0) xputc(c);
	if(hafdup && c>0)
	{
		if(posit()==0x174f) scroll();
		if(!escout && isprint(c)) putchar(c);
		if(escout) {
			esctr(c,&oc);
			escout=0;
		}
		if(iscntrl(c)){
			if(c== '\r')
			{
				if(!cms) {
					if((rowpos() == 23)) scroll();
					else putchar('\n');
				}
			}
			else
				cntltr(c,&escout);
		}
	}
}


X/* screen routines. These use the ansi.sys device driver. */

X/* cursor up */
crup()
{
	bdos(9,"\033[A$");
}

X/* cursor down */
crdn()
{
	bdos(9,"\033[B$");
}

X/* cursor forward */
crfr()
{
	bdos(9,"\033[C$");
}

X/* clear screen */
cls()
{
	scnorm();
	bdos(9,"\033[2J$");
}

X/* push the current cursor position */
pshcur()
{
	bdos(9,"\033[s$");
}

X/* pop the cursor position */
popcur()
{
	bdos(9,"\033[u$");
}

X/* clear to end of line  */
cline()
{
	int pst,row,col,colrem;
	pst=posit();
	row=pst>>8;
	col=(pst&0xff)<<1;
	colrem=160-col;
	movblock(BLKLN,DATSEG,TABLE[row]+col,VIDEO,colrem);
}

X/* underline mode on */
uline()
{
	extern int attrib;
	attrib=0x2100;
}

X/* inverse video on */
hion()
{
	extern int attrib;
	attrib=0x7000;
}

X/* video back to normal */
scnorm()
{
	extern int attrib;
	attrib=0x700;
}

X/* clear the status line */
clstat()
{
	movblock(BLKLN,DATSEG,TABLE[24],VIDEO,160);
}

X/* hexdp  print the hex representation of the incoming characters  */
unsigned char *hextab="0123456789ABCDEF";
hexdp()
{
	int c,ci;
	while((c=inkey()) !=DIE )
	{
		if(c==NULL) {
			getkey();
			return;
		}
		if((ci=getcx())!=-1)
		{
			fputs("< ",stdout);
			putchar(ci); fputs(" -- ",stdout);
			putchar(*(hextab+(ci/16)));
			putchar(*(hextab+(ci%16)));
			fputs(" >",stdout);
		}
		if(c>0) {
			outchar(c);
		}
	}
}

exec1()
{
	char exline[128],*tline;
	extern int cms;
	int c,c1;
	pshscr();
	cls();
	tline=exline;
	blast("DOS subset. Press any function key to exit.",7,0,0);
	locate(1,0);
	fputs("<>",stdout);
	while((c=getkey()) != NULL) {
		if(isprint(c)) (*tline++)=c;
		if(c=='\b' && (tline-exline)>0) tline--;
		putchar(c);
		if(c==CR) {
			*(tline++)='\0' ;
			system(exline) ;
			fputs("<>",stdout);
			tline=exline;
		}
	}
	getkey();
	popscr();
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 k3.c
	/bin/echo -n '	'; /bin/ls -ld k3.c
fi
/bin/echo 'Extracting k4.c'
sed 's/^X//' <<'//go.sysin dd *' >k4.c
X/* k4.c escape and cntrl char translation  */
#include "commio.h"


static int bel=1;		 /* bell starts life as off	 */
extern int *TABLE,VIDEO;


esctr(c,ip)
int c,*ip;
{
	int i,h;
	extern int klock;  /* tvi keyboard enable,disable flag */
	static int locf=0,rnum,cnum;
	if((*ip !=2) && locf){
		if(locf==2) rnum=c-32;
		if(locf==1) {
			cnum=c-32;
			locate(rnum,cnum);
			*ip=0;
		}
		locf--;
	}
	else {
		*ip=0;
		switch(c)
		{
		case 'T':
		case 't':
			cline();
			break;
		case 'Q':
			chins();
			break;
		case 'W':
			chdel();
			break;
		case 'E':
			linins();
			break;
		case 'i':
			/*	putchar('\t');   */
			break;
		case 'j':
			hion();
			break;
		case 'l':
			uline();
			break;
		case 'k':
		case 'm':
			scnorm();
			break;
		case 'R':
			lindel();
			break;
		case 'y':
		case 'Y':
			cline();
			if((h=rowpos())<23){
				pshcur();
				for(i=h+1;i<24;i++)  {
					locate(i,0);
					cline();
				}
				popcur();
			}
			break;
		case '=':
			if(*ip !=2){
				locf=2;
				*ip=1;
			}
			break;
		case '?':
			xputc(rowpos()+32);
			xputc(colpos()+32);
			xputc('\r');
			break;
		case '+':
		case '*':
		case ':':
		case ';':
			cls();
			break;
		case '#':  /* tvi keyboard disable */
			klock=1;
			status("LOCK",1);
			break;
		case '"':  /* tvi keyboard enable */
			klock=0;
			clstat();
			break;
		default:
			break;
		}
	}
}
cntltr(cc,mp)
int cc,*mp;
{
	int pk;
	extern int cms;
	if( (cc=='\r') || (cc=='\t') || ((cc == BELL) && !bel)) {putchar(cc); return;}
	switch((cc)+64)
	{
	case 'K' :
		if(rowpos() !=0 ) crup();
		else locate(23,colpos());
		break;
	case 'H' :
		if(colpos() != 0 ) {putchar(cc); break;}
		if(posit()==0) locate(23,79);
		else locate(rowpos()-1,79);
		break;
	case 'J' :      /* LF  */
		if(rowpos() != 23) {
			crdn();
			break;
		}
		pk=colpos();
		scroll();
		locate(23,pk);
		break;
	case 'Z' :
		cls();
		break;
	case 'L' :
		if(colpos() != 79) crfr();
		else {
			if(rowpos() != 23) locate(rowpos()+1,0);
		}
		break;
	case '^' :
	case '~' :
		locate(0,0);
		break;
	case 91  :    /* set escape flag if ESC received  */
		*mp=1;
		break;
	case '_':
		if(rowpos() == 23) {
			scroll();
			break;
		}
		locate(rowpos()+1,0);
		break;
	default:
		break;
	}
}


bellsw()
{
	bel=turn(bel);
}


chins()
{
	int cn;
	unsigned soff;
	soff=TABLE[rowpos()]+((cn=colpos())<<1);
	movblock(soff,VIDEO,soff+2,VIDEO,(79-cn)<<1);
	fputs(" \b",stdout);
}
chdel()
{
	int cn;
	unsigned doff;
	doff=TABLE[rowpos()]+((cn=colpos())<<1);
	movblock(doff+2,VIDEO,doff,VIDEO,(79-cn)<<1);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 k4.c
	/bin/echo -n '	'; /bin/ls -ld k4.c
fi
/bin/echo 'Extracting komm.c'
sed 's/^X//' <<'//go.sysin dd *' >komm.c
X/*
 * komm.c  basic routines. A hacked up version of R.F. Starr's interrupt
 *	   routines. Blame all bugs on Kelley.
 */

#include "commio.h"
struct regval
{
	unsigned int ax,bx,cx,dx,si,di,ds,es;
}
srv,rrv;

static int rs_vec = 0x14;  /* RS232_IO in BIOS */
unsigned char *combuf;
static int first = 1;
static int cptr = 0;
static int head = 0;
static int bfm = BUFSIZE-1;


int_com()    /* Communications interrupt service routine */
{
	unsigned char inportb();

	/* Check lsb of lsr... if 0, no data is available */
	if(inportb(0x3fd) & 0x01) {	/* if data is there   */
					/*	read the RBR for the char */
		cptr &= bfm;
		combuf[cptr++] = inportb (0x3f8);
	} /* and put it in the buffer */
	outportb (0x3fc,0xb);	/* Reset MCR */
	outportb (0x20,0x20);	/* Send EOI to 8259 */
	return;
}


X/* Routine to set up the RS232 interface ( baud rate, #data bits, etc.) */
xopen (device,baud,parity,databits,stopbits)
char *device;
int baud;
char parity;  /* Must be 'e', 'o', or 'n' */
int databits,stopbits;
{
	char *calloc();
	unsigned int rs232_param;
	unsigned int baud_bit,parity_bit,stop_bit,data_bit;
	int i;

	baud/=300;
	baud_bit=2;
	while(baud/=2) baud_bit++;

	switch(parity)
	{
	case 'n':
		parity_bit=0;
		break;
	case 'o':
		parity_bit=1;
		break;
	case 'e':
		parity_bit=3;
		break;
	}

	stop_bit=stopbits-1;

	data_bit=databits-5;

	rs232_param = 0;
	rs232_param |= (baud_bit << 5);
	rs232_param |= (parity_bit << 3);
	rs232_param |= (stop_bit << 2);
	rs232_param |= data_bit;

	srv.ax = rs232_param;  /* Tell Int14 to initialize for rs232 */
	srv.dx = 0;	/* Select COM1: */
	sysint (rs_vec,&srv,&rrv);
	intrinit (int_com,3000,12);
	xcom_set ();	  /* Activate com interrupt rs_vec */
	outportb (0x3fc,0x9);

	/* make the buffer if first time through */
	if(first)  {
		first=0;
		combuf=calloc(BUFSIZE,1);
		if(!combuf) status("Not enough RAM",1);
	}

	return;
}

xfread (string)   /* Read a string from COM1: and filter it */
char *string;
{
	int i;
	unsigned char cbuf;

	*(string) = '\0';  /* Just in case */
	i = 0;
	if (cptr == head) return 0;
	while( head != cptr)
	{
		head &= bfm;
		if ((cbuf=combuf[head++]&0x7f) == '\0') continue;
		if((cbuf == EOZ) || (cbuf == XON) || (cbuf == XOFF) || (cbuf==XTRA) ) continue;
		*(string+i++) = cbuf;
	}
	*(string + i) = '\0';
	return i;  /* The number of characters read */
}

X/* prtbuf   print the contents of the comm port buffer on the screen.  */
prtbuf()
{
	extern int cms;
	static int escf=0,scrf=0;
	unsigned char c;
	if (cptr == head) return;
	while( head != cptr)
	{
		head &= bfm;
		if((c= combuf[head++]&0x7f)=='\0') continue;
		if(escf) {
			esctr(c,&escf);
			continue;
		}
		if(isprint(c)) {scrf = zputc(c); continue;}
		if((c == CR) && scrf) continue;
		if((c == LF) && scrf) { scrf=0; continue;}
		scrf=0;
		cntltr(c,&escf);

	}
}

X/* Write a string to COM1: */
xwrite (string)
char *string;
{
	while ( *string != '\0' ) xputc(*string++);
}

xclose()  /* Close the com device */
{
	unsigned char inportb();
	unsigned char cc;
	outportb (0x3fc,0x00);	/* Reset MCR */
	outportb (0x3f9,0x00);	/* Reset IER */
	cc = inportb (0x21)|0x10;
	outportb (0x21,cc);
	outportb (0x20,0x20);
	return;
}

brk()  /* Send break down com line */
{
	unsigned char inportb();
	unsigned char cc;
	cc = inportb (0x3fb);	/* Read line control register */
	outportb (0x3fb,cc|0x40);   /* Set break high */
	wait (300);  /* Delay ~300 msec */
	outportb (0x3fb,cc&0xbf);  /* Reset break bit low */
	return;
}


wait(q)    /* wait q ms */
int q;
{
	int t,s,time();
	t=time();
	q/=10;
	if(q > 99) status("wait - interval must be < 1 sec",1);
	if((s=t+q) <100) {
		while((s>time()) && (time()>=t)) ;
	}
	else {
		s-=100;
		while((time()>=t) || (s>time())) ;
	}
}




getcx ()   /* Read a char from COM1:   */
{
	/* Latch onto last character pointer */
	if (cptr == head) return -1;
	head &= bfm;
	return(combuf[head++]);
}

X/*
 *  xputc(cc) sends cc out on the comm port but does not check for DSR as the
 *  IBM rom code does. This makes some auto dial modems happy
 *  (like Datec PALs).
 */

xputc(cc)
unsigned char cc;
{
	unsigned int timer;
	unsigned char inportb();
	outportb(0x3fc,0xb);   /* Send dtr and rts */
	/* test cts and THRE */
	for(timer=64000;timer>0;timer--)
	if((inportb(0x3fe)&0x10)&&(inportb(0x3fd)&0x20)) {outportb(0x3f8,cc);
							  return;}
	status("Time out error. Check modem. Press any key to go to menu.",1);
	if(menkey() == 0) getkey();
	menu();
}

static
xcom_set()
{
	unsigned char prtb,inportb();

	outportb(0x3fc,0xb);	  /* set msr */

	prtb=inportb(0x3fb)&0x7f;  /* set dlab */
	outportb(0x3fb,prtb);

	outportb(0x3f9,1);	    /* interrupt on char */

	prtb=inportb(0x21)&0xef;    /* allow interrupt from com1: */
	outportb(0x21,prtb);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 komm.c
	/bin/echo -n '	'; /bin/ls -ld komm.c
fi
/bin/echo 'Extracting modem.c'
sed 's/^X//' <<'//go.sysin dd *' >modem.c
X/*
 * modem.c  binary transfer based on code by D. Betz
 * supporting routines by Kelley
 */

X/*
	By David Betz
	   114 Davenport Ave.
	   Manchester, NH  03103
	   (603) 625-4691


	This module provides a pair of routines that implement the
	Ward Christianson MODEM protocol.  The following entry points
	are defined:


	    int dl_snd(getch)
		int (*getch)();

		This routine sends data to the modem.  It gets the
		data to send by calling the function pointed to by
		getch.	This function should return each byte of
		the message followed by -1 indicating end of file.
		It returns 1 if the transfer succeeds and 0 if the
		transfer fails.


	    int dl_rcv(putch)
		int (*putch)(ch);

		This routine receives data from the modem.  It calls
		putch with each character received by the modem.
		It returns 1 if the transfer succeeds and 0 if the
		transfer fails.


	In order to use these routines, the following functions must
	be defined:


	    int md_get(tmo)
		int tmo;	timeout interval in seconds

		This routine returns the next character received by
		the modem.  The character should not be sign extended.
		If no character is received before the timeout interval
		expires, a -1 should be returned.


	    md_put(ch)
		int ch; 	the character to output

		This routine outputs a character to the modem.

*/

#include "stdio.h"

X/* useful definitions */
#define TRUE	1
#define FALSE	0
#define md_put(A) xputc(A)

X/* protocol characters */
#define SOH	0x01
#define EOT	0x04
#define ACK	0x06
#define NAK	0x15
#define CAN	0x18

X/* routine status codes */
#define DT_EOF	-1
#define DT_ERR	-2
#define DT_OK	1
#define DT_TIME -1

X/* data message length */
#define MSGLEN	128

X/* number of times to retry */
#define RETRY	10

X/* timeout loop counters */
#define STIME	1
#define LTIME	10
#define XTIME	60

X/* data buffer structure */
struct buffer {
    char b_soh; 	/* start of header */
     unsigned char b_blk1;	  /* block number */
     unsigned char b_blk2;	  /* complemented block number */
     unsigned char b_data[MSGLEN];/* data */
     unsigned char b_chksum;	  /* checksum */
};

X/* the data buffer */
static struct buffer buff;

X/* global variables */
static int blknum;	/* the current block number */
static int bufptr;	/* the current buffer pointer */

X/* dl_snd - send data across the link */
int dl_snd(getch)
  int (*getch)();
{
    int ch,retries;

    /* initialize */
    cls();
    blast("transmitting -- block num =",7,0,0);
    blknum = 1;
    bufptr = 0;

    /* wait for the initial NAK */
    for (retries = 0; retries < RETRY; retries++)
	if (md_get(XTIME) == NAK)
	    break;
	else
	    xabort();

    /* check for failure */
    if (retries >= RETRY)
	return (FALSE);

    /* send each byte */
    while ((ch = (*getch)()) != EOF)
	if (msgput(ch) == DT_ERR)
	    return (FALSE);

    /* flush partial buffer */
    if (bufptr > 0)
	while (bufptr > 0)
	    if (msgput(0) == DT_ERR)
		return (FALSE);

    /* send EOT and wait for ACK */
    for (retries = 0; retries < RETRY; retries++) {
	md_put(EOT);
	if (md_get(LTIME) == ACK)
	    return (TRUE);
    }

    /* return failure */
    return (FALSE);
}

X/* dl_rcv - receive data across the link */
int dl_rcv(putch)
  int (*putch)();
{
    int ch;

    /* initialize */
    cls();
    blast("receiving -- block num =",7,0,0);
    blknum = 1;
    bufptr = MSGLEN;

    /* send the initial NAK */
    md_put(NAK);

    /* receive each byte */
    while ((ch = msgget()) != DT_EOF && ch != DT_ERR)
	(*putch)(ch);

    /* return with status */
    return (ch == DT_EOF);
}

X/* msgput - put a message data character */
static int msgput(ch)
  int ch;
{
    int sts;

    buff.b_data[bufptr++] = ch;
    if (bufptr == MSGLEN) {
	if ((sts = mdsnd(blknum++,&buff)) != DT_OK)
	    return (sts);
	bufptr = 0;
    }
    prtnum(blknum,0,30);
    return (ch);
}

X/* msgget - get a message data character */
static int msgget()
{
    int sts;

    if (bufptr == MSGLEN) {
	if ((sts = mdrcv(blknum++,&buff)) != DT_OK)
	    return (sts);
	bufptr = 0;
    }
	prtnum(blknum-1,0,30);
    return (buff.b_data[bufptr++] & 0xFF);
}

X/* mdsnd - send a buffer of data */
static int mdsnd(blk,buf)
  int blk; struct buffer *buf;
{
    int chksum,i,retries,ch;
     unsigned char *b;

    /* insert the header info */
    buf->b_soh = SOH;
    buf->b_blk1 = blk;
    buf->b_blk2 = ~blk;


    /* compute the checksum */
    for (i = chksum = 0; i < MSGLEN; i++)
	chksum += buf->b_data[i];
    buf->b_chksum = chksum;

    /* compute the buffer address */
    b = ( unsigned char *) buf;

    /* send data and wait for an ACK */
    for (retries = 0; retries < RETRY; retries++) {

	/* send the data */
	for (i = 0; i < sizeof(struct buffer); i++)
	    md_put(b[i]);

	/* return on an ACK */
	if ((ch = md_get(LTIME)) == ACK)
	    return (DT_OK);
	else if (ch == CAN)
	    break;
    }

    /* return failure */
    return (DT_ERR);
}

X/* mdrcv - receive a buffer of data */
static int mdrcv(blk,buf)
  int blk; struct buffer *buf;
{
    int chksum,i,ch,retries;
     unsigned char *b;

    /* compute the buffer address */
    b = ( unsigned char *) buf;

    /* receive data */
    for (retries = 0; retries < RETRY+1; retries++) {

	/* check for data packet or eot */
	if ((ch = md_get(LTIME)) == DT_TIME) {
	    md_put(NAK);
	    continue;
	}
	else if (ch == EOT) {
	    md_put(ACK);
	    return (DT_EOF);
	}
	else if (ch != SOH) {
	    xabort();
	    md_put(NAK);
	    continue;
	}

	/* receive the data */
	for (i = 1; i < sizeof(struct buffer); b[i++] = ch)
	    if ((ch = md_get(STIME)) == DT_TIME)
		break;

	/* check for timeout */
	if (i < sizeof(struct buffer)) {
	    xabort();
	    md_put(NAK);
	    continue;
	}

	/* check the block number */
	if ((buf->b_blk1 & 0xFF) != (~buf->b_blk2 & 0xFF)) {
	    md_put(NAK);
	    continue;
	}

	/* check the checksum */
	for (i = chksum = 0; i < MSGLEN; i++)
	    chksum += buf->b_data[i];
	if ((buf->b_chksum & 0xFF) != (chksum & 0xFF)) {
	    md_put(NAK);
	    continue;
	}

	/* check the block number */
	if ((buf->b_blk1 & 0xFF) == (blk & 0xFF)) {
	    md_put(ACK);
	    return (DT_OK);
	}
	else if ((buf->b_blk1 & 0xFF) != ((blk - 1) & 0xFF)) {
	    md_put(CAN);
	    break;
	}

	/* send a ack */
	md_put(ACK);
    }

    /* return failure */
    return (DT_ERR);
}

X/* xabort - wait for the line to clear */
static xabort()
{
    while (md_get(STIME) != DT_TIME)
	;
}



X/* Here are the service routines required by D. Betz's modem programs.
 * Their functions are described in the header to his code.
 */

static int inchr=0;/* inchr = 1 means transfer fails */
static int inpf;   /* inpf = local file handle */

md_get(tmo)
int tmo;
{
	int i,cg;
	int jj=0,count=0;
	unsigned char c;
	for(i=0;i<tmo*5;i++) {
		if((cg = getcx()) != -1)
			return(c=cg);
		locate(3,0);
		blast("timeout ",7,3,0);
		prtnum(++jj,3,9);
		wait(200);
	}
	return(-1);
}



static int
mdmgt()  /* get a character from the open file	     */
{
	static int d=0,hh=0;
	static unsigned char cbuff[512];
	if(hh==0){
		d=read(inpf,cbuff,512);
		if(d<=0) return(EOF);
		hh=d;
	}
	return(cbuff[d-(hh--)]);
}



static int
mdmpt(ch)  /* get a character from the open file  */
int ch;   /* no buffers necessary as DOS does it for you */
{
	static int d=0,hh=0;
	char c;
	c=ch;
	if(write(inpf,&c,1)!=1) return(0);
	return(1);
}



X/*
 * pointers to funcitons for the binary transfer
 */

extern int mdmpt(),mdmgt(),dl_rcv(),dl_snd();
int (*fptr[])()={mdmpt,mdmgt};
int (*fptr1[])()={dl_rcv,dl_snd};

X/*
 * binary transfer   method=0 <--> download   method=1 <--> upload
 */

static int
btrans(method)
int method;
{ extern int modem,inpf;
	int inchr,mflag=0;
	inchr=0;
	/* set to (8,n,1) if not already there */
	if(!modem) {
		xclose();
		xopen("COM1:",1200,'n',8,1);
		modem=1;
		mflag=1;
	}
	if(bopen(method) <0) {if(!mflag) return;
	/* return to (7,e,1) if necessary */
		modem=0;
		xclose();
		xopen("COM1:",1200,'e',7,1);
		return;}
	if((*fptr1[method])(fptr[method]) == 0)
	{status("transfer fails",1);
	inchr=1;}
	close(inpf);
	if(!inchr) status("transfer complete",0);
	locate(7,0);
	putchar('\7');
	if(!mflag) return;
	modem=0;
	xclose();
	xopen("COM1:",1200,'e',7,1);
}



extern int creat(),open();
int (*mptr[])()={creat,open};
int mode[]={BWRITE,BREAD};
static int
bopen(method) /* open a file for reading/writing with the modem program */
int method;   /* method=0 download,  method=1 upload  */
{
	unsigned char fname[16];
	ask(fname,method); /* Get the name of the file */
	if((inpf=(*mptr[method])(fname,mode[method]))<0) {
		stterr("file error, file not found.");
		return(-1);
	}
}

static unsigned char *numbs="0123456789";
static unsigned char *blknb="      ";
prtnum(ib,row,col)
int ib,row,col;
{int i,t,j,k;
if(ib<0) ib=-ib;
j=5;
t=10000;
while(ib<t) {j--; t/=10; *(blknb+j)=32;}
if(j==0) *(blknb)='0';
for(i=0;i<j;i++){
	  *(blknb+i)=numbs[k=ib/t];
	   ib-=k*t;
	  t/=10;}
blast(blknb,7,row,col);
}

X/*
 * the functions called by funkey  Press F9 for binary download, F10 for
 * binary upload
 */
mdm8() {btrans(0);}
mdm7() {btrans(1);}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 modem.c
	/bin/echo -n '	'; /bin/ls -ld modem.c
fi
/bin/echo 'Extracting print.c'
sed 's/^X//' <<'//go.sysin dd *' >print.c
X/* print.c -- contains various functions that use screen memory. Status line
 *	      management, printer configure, the help screen, direct screen
 *	      writes and saves.
 */

#include "commio.h"

extern int *TABLE,DATSEG,VIDEO;
extern char *line;

struct regval  {
	unsigned int ax,bx,cx,dx,si,di,ds,es;
}
sst1;

static int norm[] = {
	27,64,1000}; /* initial state  */
static int doub[]= {
	27,'G',1000}; /* double strike on  */
static int ndoub[]={
	27,'H',1000}; /* double strike off */
static int emph[]={
	27,'E',1000};  /* emphasized mode on */
static int nemph[]={
	27,'F',1000}; /* emphasized mode off */
static int comp[] ={
	15,27,'0',1000};    /* compressed mode (132 col) */
static int ncomp[]={
	27,18,27,'2',1000};    /* compressed mode off (80 col) */
static int halfsp[]={
	27,'s',1,1000};     /* half speed */
static int fullsp[]={
	27,'s',0,1000};    /* full speed */
static int lmarg[]={
	27,'l',0,1000};     /* set left margin */
static int skip[]={
	27,'N',0,1000};      /* lines to skip at perforation */
static int *prlines[]={
	norm,doub,ndoub,emph,nemph,comp,ncomp,halfsp,fullsp,
	lmarg,skip};
static char*  prmenu[]={
	"1. normal","2. double strike on","3. double strike off",
	"4. emphasized on","5. emphasized off","6. compressed on (132)","7. compressed off (80)",
	"8. half speed","9. full speed","10. set left margin","11. set line skip at eof"};

X/* xxprint -- printer configure utility. */
xxprint()
{
	int iget,i,ah,argerr;
	char chline[10];
	pshscr();
	cls();
	argerr=0;
	sst1.ax=0x0200; 	/* Test if printer on */
	sysint(0x17,&sst1,&sst1);
	ah= (sst1.ax>>8);
	ah&=8;
	ah &=0x68;
	if(ah!=0){
		popscr();
		status("Printer not on.",1);
		return;
	}
	for (i=0;i<11;i++) {
		blast(prmenu[i],7,i+1,0);
	}
argline:
	clstat();
	getarg(chline,"Give choice. Choose 0 to exit.  ");
	iget=ltoint(chline);
	if(iget==0) {popscr(); return;}
	if((iget<=9)&&(iget>=1)) {
		toprt(prlines[iget-1]);
		locate(iget,0);
		hion();
		zputc('*');
		scnorm();
		if(argerr){
			argerr=0;
			locate(20,0);
			cline();
		}
		goto argline;
	}
	clstat();
	if(iget==10) { getarg(chline,"column to start--");
			iget=ltoint(chline);
			blast(chline,7,10,25);
			lmarg[2]=iget;
			toprt(lmarg);
			goto argline;}
	if(iget==11) { getarg(chline,"rows to skip at perfortation--");
			iget=ltoint(chline);
			blast(chline,7,11,25);
			skip[2]=iget;
			toprt(skip);
			goto argline;}
	locate(20,0);
	blast("arguement error",7,20,0);
	argerr=1;
	goto argline;
}

X/* toprt -- send a line to the printer. */
static int
toprt(line)
int *line;
{
	int i;
	while((i=*line++) != 1000){
		sst1.ax=i;
		sysint(0x17,&sst1,&sst1);
	}
}

X/*
 * help.c  on line help screen.
 */

char *hline[] = {"Alt Keys.  Alt-key means press key while alt is held down.",
"alt -b toggles bell,default=off      alt -c  local clear screen.",
"alt -d ascii download                alt -e  toggles local echo, on for cms.",
"alt -h prints this help screen.      alt -p  calls printer set up routine.",
"alt -u ascii upload",
"alt -1 through - send the tvi function keys F1 - F11.",
"shift-alt-1 thru shift-alt-- send shifted tvi function key.",
"alt -= is the tvi-FUNC key. You will be prompted for the key.",
"  ","Function Keys.",
"F1 sends break.                       F2 closes comm port and returns to menu.",
"F3 download to c:buff.trm.            F4 ascii upload.",
"F5 toggles hex dump.                  F6 clears status line.",
"F7 toggles for cms and unix modes.    F8 uses exec to talk to DOS.",
"F9 binary download.                   F10 binary upload",
"cntrl-F10 ends program.",
" ","END sends break in unix mode, in cms mode sends tvi function key 3.",
"In cms mode with simterm the pgup, pgdn ,del, and ins keys work.",
"In cms mode the home key sends FUNC-2.",
"Arrow keys work as on a tvi 920.",
"ESC and CNTRL codes work as on tvi-920."};
#define LINENUM 22

help()
{int p,o;
extern int cms,unix;
pshscr();
cls();
for(p=0;p<LINENUM;p++){
blast(hline[p],7,p,0);}
blast("Press any key to return to term",112,24,0);
locate (24,40);
o=menkey();
if(o==NULL) o=getkey();
popscr();
}

X/* Screen memory functions. These write directly to screen memory. */


X/* blast(bline)  write bline directly to screen memory. Starts at (row,col),
 *		 and writes in normal (lite=7), inverse video (i=112),
 *		 high intensity (15) etc.
 */
blast(bline,lite,row,col)
char *bline;
int lite,row,col;
{	int doff,j;
	char ctm[256];
	doff=TABLE[row]+(col<<1);
	j=0;
	while(*bline)
	{*(ctm+(j++))=*(bline++);
	*(ctm+(j++))=lite;}
	movblock(ctm,DATSEG,doff,VIDEO,j);
}


int rowsav,colsav;

X/* pshscr -- push the screen into the buffer line. */
pshscr()
{
 int sseg;
 rowsav=rowpos();
 colsav=colpos();
 movblock(0,0xb000,line,DATSEG,4000);
}

X/* popscr -- pop the screen from line. */
popscr()
{
locate(rowsav,colsav);
movblock(line,DATSEG,0,VIDEO,4000);
}


X/*status --  print message on the status line. p=0 normal, p=1 reverse video.*/
status(lmsg,p)
char *lmsg;
int p;
{
	clstat();
	blast(lmsg,(p ? 112:7),24,0);
}

X/* stterr -- print an error message on the status line. */
stterr(line)
char *line;
{
clstat();
blast(line,112,24,0);
blast("F6 clears status line.",112,24,40);
}

X/* getarg -- *fline is the response to the prompt, *pmtln. */
getarg(fline,pmtln)
char *fline,*pmtln;
{
	int c;
	char *base;
	pshcur();
	blast(pmtln,7,24,0);
	locate(24,strlen(pmtln)+1);
	base=fline;
	while((c=getkey())!=CR) {
		if(isprint(c) && ((fline-base)<14)) (*fline++)=c;
		if(c=='\b' && ((fline-base)>0)) fline--;
		putchar(c);
	}
	*(fline++)='\0';
	popcur();
}

X/* ask --  Get the name of a file to transfer. Used in the file transfer
 * functions. dir=0 download, dir=1 upload.
 */
ask(filen,dir)
int dir;
char *filen;
{if(dir) getarg(filen,"Give name of file to be uploaded --- ");
else
getarg(filen,"Give name of target file for download --- ");
}

ltoint(agl)
unsigned char *agl;
{int i,j;
j=0;
while((i=*agl++) != '\0')
	{if((i< '0') || (i>'9')) return(0);
	 j*=10;
	 j+=(i-'0');}
return(j);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 print.c
	/bin/echo -n '	'; /bin/ls -ld print.c
fi
/bin/echo 'Extracting term.c'
sed 's/^X//' <<'//go.sysin dd *' >term.c
#include "commio.h"

X/*  Tell the compiler to make it small. Helps with 128k machines. */

int _MAXFMEM=0x400;	       /* MAXIMUM STACK+HEAP REQUIRED */
int _MINFMEM=0x200;		/* MINIMUM STACK+HEAP REQUIRED */
int _MINRMEM=01;		/* RESERVED AT TOP OF MEM */
int _STAKMEM=512;		/* MIN STACK IN SBRK BEFORE REFUSING ALLOC */



char *line;   /* A buffer used by the screen push and ascii transfer. */

int  VIDEO;
int *TABLE;   /* Table of multiples of 160 for screen write */
int *BLKLN;   /* A line of 80 blanks. */
int  DATSEG;  /* The current data segment. */

X/*
 *   term.c   communications package mostly by Tim Kelley (ecsvax!ctk)
 *	      Includes tvi920 terminal emulation, ascii and binary upload
 *	      and download, support for the SIMTERM package running under
 *	      VM/370 and CMS, and some other stuff.
 *	      Basic interrupt support package by R.F. Starr (shell!starr)
 *	      Xmodem protocol support by Dave Betz (decvax!betz)
 */

main()
{
	int c,i;
	struct segval { int scs,sss,sds,ses; } rrv;
	extern char *calloc();
	VIDEO=0xb000;
	line=calloc(4096,1);
	segread(&rrv);
	DATSEG=rrv.sds;
	TABLE=(int*)calloc(25,2);
	BLKLN=(int*)calloc(80,2);
	if((!BLKLN)||(!TABLE) ||(!line)) {status("BUY MORE RAM",1); exit(0);}
	for(i=0;i<25;i++) *(TABLE+i)=160*i;
	for(i=0;i<80;i++) *(BLKLN+i)=0x720;
	menu();

X/* tight loop that runs the show. */

start:
	prtbuf();
	if((c=inkey())>=0) outchar(c);
	goto start;
}

X/*
 *    global variables -- terminal type, duplex, xmodem flag
 */

int unix,hafdup,cms,modem,cyber;

struct host  {			/* stuff a host machine has */
	char *mname;		/* menu entry		    */
	char *phone;		/* phone number 	*/
	char *logline;		/* logon line		*/
	char *psswd;		/* password		*/
	int  baudr;		/* baud rate		*/
	int  dbits;		/* data bits		*/
	char prty;		/* parity		*/
	int duplex;		/* 0=full 1=half	*/
	}
 *chost, mhost[] = {
{"cms1","3981","xxxxxxxxxxxxxxxxxxxxx\r","xxxxxxx\r",1200,7,'e',1},
{"cms2","3981","xxxxxxxxxxxxxxxxxxxxx\r","xxxxxxx\r",1200,7,'e',1},
{"ecsvax","3981","ctk\r","xxxx\r",1200,7,'e',0},
{"ncsuvax","3759","ctk\r","xxxx\r",1200,7,'e',0},
{"ncsuvax2","3924","ctk\r","xxxx\r",1200,7,'e',0},
{"cyber","9,5498139","ID ;xxxxxxxxxxxxxxx\r","xxxxxx\r",1200,7,'e',1},
{"bboard","9,5499403","ctk\r","xxxx\r",1200,8,'n',0}
};

menu()
X/*
 * prints a menu, sets up the comm port, calls the printer configure
 * utility if needed.
 */
{
	int i,c,j,nterms;
	char *spacer=".    ";
	nterms=sizeof(mhost)/sizeof(struct host);
	xclose();  /* initialize the comm port */
mstt:	cls();
	prdate();
	xrtime(0,40);
	blast("Atomaterm -- mostly by C.T. Kelley (!decvax!ecsvax!ctk).",7,1,0);
	blast("Based on code by R.F.Starr(shell!starr) and D.Betz (decvax!betz).",7,2,0);
	blast("Terminal Types -- Choose Number",7,3,30);
	blast("0.   Printer configure",7,5,30);
	for(j=1;j<=nterms;j++)
		{locate(5+j,30); putchar('0'+j);
		blast(spacer,7,5+j,31);
		blast(mhost[j-1].mname,7,5+j,35);}
	blast("Press a function key to end program.",7,8+nterms,0);
	locate(9+nterms,0);
	i=menkey();  /* get the menu selection */

	/* It's a function key, clean up and exit */
	if(i==0) {getkey();die();}


	/* Printer configure. Do it and start over. */
	if(i=='0') {xxprint(); goto mstt;}

	locate(8+nterms,0); cline();
	/* ecsvax is the default		*/
	chost=mhost+(((i>'0')&&(i<'1'+nterms))? (i-'1'):2);

	cms=((i=='1')||(i=='2'));      /* WARNING -- CHANGE IF 3rd CMS ACCT IS ADDED */

	unix=!cms;
	cyber=0;
	if(i=='6') {cyber=1;cms=1;unix=0;}

	modem=(i=='1'+nterms);

	hafdup=chost->duplex;
	blast(chost->mname,7,8+nterms,0);
	blast(" -- ",7,8+nterms,2+strlen(chost->mname));
	/* wait for the connection. The port is closed at this point. */

	blast("Make connection and press any regular key to start.",7,9+nterms,0);
	blast("Press any function key to dial phone.",7,10+nterms,0);
	locate(20,0);
	while((c=inkey()) == -2) xrtime(0,40);

	xopen("COM1:",chost->baudr,chost->prty,chost->dbits,1);
	if(c==0) {getkey(); dial();}
}

X/* toggle a flag, p is the flag */

turn(p)
int p;
{
	return(((p==0)? 1:0));
}

X/* close the port and exit to dos  */

die()
{
	xclose();
	exit(0);
}

X/* change the duplex  */

dupsw()
{
	extern int hafdup;
	hafdup=turn(hafdup);
}
dial()
{
 if(*(chost->phone)=='\0') return;
 xputc('\r');
 xwrite("ATD"); xwrite(chost->phone); xputc('\r');
}
logon()
{xwrite(chost->logline);}

psswd()
{xwrite(chost->psswd);}

chterm()
{extern int cms,unix,hafdup;
cms=hafdup=unix;
unix=!cms;
chost=mhost+(cms ? 0:2);
}

//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 term.c
	/bin/echo -n '	'; /bin/ls -ld term.c
fi
/bin/echo 'Extracting updn.c'
sed 's/^X//' <<'//go.sysin dd *' >updn.c
X/*
 *  updn.c  ascii file transfer
 */

#include "commio.h"
#define MXLEN 256
extern char *line;
dwnl(dp)
int dp;
{
	FILE *outp;
	int c,method;
	method=1-dp;
	if(atopen(&outp,method) == 0) return;
	while((c=inkey()) !=DIE )
	{
		if(c==NULL) {
			fputc(CR,outp);
			fclose(outp);
			getkey();
			clstat();
			return;
		}
		if(xfread(line))
		{
			fputs(line,outp);
			cmmprt(line);
		}
		if(c>0) {
			outchar(c);
		}
	}
}
upl()
{
	extern int cms,hafdup,unix,cyber;
	int c,dc,method,edpmt;
	FILE *inpf;
	char  inline[256],*tline;
	tline=inline;
	if(!hafdup) {
		status("upload works only in half duplex mode.",1);
		return;
	}
	edpmt=(cms ? XON : ':');
	if(cyber) edpmt='=';
	method=3-cms;
	if(atopen(&inpf,method)==0) return;
	while(fgets(inline,MXLEN,inpf) != NULL)
	{
		tline=inline;
		if(*inline == EOZ ) break;
		if(cms && ((*inline == '\r')||(*inline == '\n'))) xwrite(" ");
		while( cms && (*tline == '\t')) {
			tline++;
			xwrite("         ");
		}
		xwrite(tline);
		cmmprt(inline);
		while((c=getcx()) != edpmt) {
			if((dc=inkey()) == NULL) {
				cmmprt("upload terminated");
				fclose(inpf);
				putchar('\7');
				clstat();
				xwrite("\r");
				getkey();
				return;
			}
			if(isprint(c) && c!=0x20) putchar(c);
			if(c=='?') {
				clstat();
				status("upload error",0);
				fclose(inpf);
				putchar('\7');
				return;
			}
		}
		if(isprint(c) && c!=0x20) putchar(c);
	}
	fclose(inpf);
	if(unix) xwrite("\r.");
	scroll();
	xwrite("\r");
	putchar('\7');
	clstat();
}
static char *md[]={
	"ab","wb","rb","r"};
static char *dirct[]={
	"down","up"};
static char *prep[]={
	" to "," from "};
static int
atopen(afile,method)
FILE *(*afile);
int method;
{
	extern char *calloc();
	char *direct,*outstr;
	char *bxf="c:buff.trm";
	char fname[16], *filenam;
	int xdir;
	xdir=((method<2) ? 0:1);
	direct=dirct[xdir];
	if(method == 0) filenam=bxf;
	else {
		filenam=fname;
		ask(filenam,xdir);
	}
	if((*afile=fopen(filenam,md[method]))==NULL)
	{

		outstr = calloc(255,1);
		strcpy(outstr,"File open error in ascii ");
		strcat(outstr,dirct[xdir]);
		strcat(outstr,"load.");
		clstat();
		status(outstr,1);
		free(outstr);
		return(0);
	}
	outstr = calloc(255,1);
	strcpy(outstr,dirct[xdir]);
	strcat(outstr,"loading");
	strcat(outstr,prep[xdir]);
	strcat(outstr,filenam);
	strcat(outstr,".     Press any function key to end transfer.");
	clstat();
	status(outstr,0);
	free(outstr);
	return(1);
}

cmmprt(xline)
char *xline;
{
	int c;
	while((c=(*xline++)&0x7f) != '\0')
	{
		if(posit() == 0x174f) scroll();
		{
			switch(c)
			{
			case '\n':
				if(rowpos() != 23) {
					putchar(c);
					break;
				}
				scroll();
				break;
			case '\t':
			case '\b':
			case '\r':
				putchar(c);
				break;
			default:
				if(isprint(c)) zputc(c);
				break;
			}
		}
	}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 updn.c
	/bin/echo -n '	'; /bin/ls -ld updn.c
fi
/bin/echo 'Extracting term.doc'
sed 's/^X//' <<'//go.sysin dd *' >term.doc
This program emulates a tvi-920c. The required hardware is

        1. An IBM PC or highly compatible clone.
        2. The IBM monochrome adaptor and monitor.
        3. DOS 2.0 or higher and installation of the ansi.sys driver.
        4. At least 128k of RAM.

The program plays dirty is the following ways:

        1. It writes directly to screen memory.
        2. It talks to the serial port at the i/o address level.
           A consequence of this is that is only works on port COM1:.
        3. It uses ROM BIOS calls to video and keyboard.

        To use the program type "term" at the keyboard. The menu will appear
giving you choices of host machines to talk to. At present the menu is hard
coded in the program menu.c and you will have to make your own changes there.
You will be given the option of either letting the program dial the phone for
you (if you have a Hayes type autodial modem) or dialing and making the
connection yourself. If you do the latter press the return key after
the connection is made. When logged on the program will respond to most
of the tvi escape codes and the tvi-function keys can be sent.

        The program is designed for the systems we use locally here at
NCSU. The systems presently hard coded in menu.c are the unix-vax on campus,
the ecs vax in the triangle, and the IBM 4341 on campus. The cms part of
the program is designed for use with the SIM3278 program for full screen
editing. Simply tell SIM3278 that you have a tvi-920 (answer 3 to the
SIM3278 prompt). When talking to the 4341 the cursor keys and the 
page up and page down keys work as they should. When talking to a unix
system the cursor keys work.

        The function keys and the alt+key combinations have the following
functions.

F1 --   Sends break.
F2 --   Returns to the main menu and closes the comm port, but does not
        drop carrier. This is useful if you want to change hosts and also
        as a panic button.
F3 --   Toggles ascii data caputre to a file c:buff.trm. This is on my
        c: drive which is a RAM-disk on my system. You may want to change
        the name and/or drive of this file. This data is in the file
        updn.c inside the function afile.c.
        ***WARNING***  This does not check if your disk is too full to
                       hold the incoming data. Take care. I hope to
                       fix this soon.
F4 --   Opens a file for ascii upload to the host machine. You will be
        prompted for the name of the file. To use this feature you must
        be in imput mode of your line editor and host machine echo must be
        off ( stty -echo for unix). The editor prompt is hardcoded in the
        file updn.c. Note that in cms you must be logged on in line mode
        (not using SIM3278) for this to work. The current editor prompts are
        ":" for unix and XON for cms. In cms be sure to tell the editor
        case m if you want to keep lower case. In unix use the ed editor.
	If anyone would like to give me some code for full duplex vi support
	I'll be grateful.
F5 --   Dumps incoming data in hex. Nice if your editor prompt is invisible
        and you want to know what it is.
F6 --   Clears the status line.
F7 --   Toggles between cms and unix mode.
F8 --   Uses the DOS 2.0 exec function to load a copy of command.com and
        do something. This feature likes 192k. You can easily run the
        personal editor and stuff as large from the program using this
        feature. On a large system you can download C code, compile and
	test it without logging off.
F9 --   Opens a file for binary download using the modem protocol. Modem
        should be started on the host machine before pressing this button.
        The code for the modem part itself is by D. Betz (decvax!betz). The
        stuff that drives it is mine.
F10 -   Opens a file for binary upload to the host machine using the modem
        protocol. All comments for F9 apply.

Other function keys and their uses are

1. Insert  --  on cms sends ESC-Q
2. Del     --  on cms sends ESC-W
3. cursor keys   -- they work on both cms and unix but do different things.
                    See the code in funkey.c.
4. pageup and page down -- on cms they work.
5. End  - sends break on unix (it's right next to the return key. Nice for
          reading netnews.)
          on cms this sends the tvi funciton key #3 which is the quit 
          key for the full screen xedit under SIM3278.
5. Home - On cms it sends tvi func-2 which is the pa2 key that you need
          so often.


Alt-keys

1.      alt-b    Toggles the bell. Default is off. I hate bells.
2.      alt-c    Local clear screen. Sends nothing to the host. To do a
                 normal cls use CNTRL-z as usual.
3.      alt-d    Toggles ascii download to a file you name. Works like
                 the F3 key.
4.      alt-e    Toggles local character echoing.
5.      alt-h    Puts the help screen up. 
5.5	alt-k	 Sends your password to the host machine.
6.      alt-l    Sends your logon line to the host machine.
7.      alt-p    Brings up the printer configure menu. This works only
                 with Epson priners. To hack it up for another printer
                 look at the file print.c. Not all the features are 
		 available on all printers. The IBM graphics printer does
		 not, to my knowledge, allow one to set the left margin.
8.      alt-u    Does the same thing as F4. Ascii upload.

			A Word About the Code

	The code is written for the Computer Innovations CI-C86 compiler.
A conversion to another compiler might be a pain. Most of the low level 
functions I wrote myself for the 1.33 compiler and continue to use them
even though the 2.1 compiler has some of them. The 2.1 compiler is essential
for this code as I do use come of the new features in this version.
	An effort was made to keep the code as small as possible in order
that the space remaining under the dos exec function be large. Hence I do
not use printf or scanf (You pay a large size price for these with the
CI compiler.).
	The code has been tested on IBM machines (PC, XT, AT) only. It
might be possible to make it work with the color monitor. When I changed
the VIDEO global variable (the address of screen memory) for color and ran
the program I got a flicker problem that no human should put up with. More
needs to be done to resolve this. Attention must be payed to the refresh cycle
of the color monitors. Any help would be appreciated.
	It is my firm belief that this program would work at 9600 baud. If
someone will test this I'd like to hear about it. (I've only been able to test
at 1200 and 300).
	This program is truly a child of the netnews. The original idea came
from a posting of an interrupt driver by R.F. Starr (shell!starr). Starr`s 
very nice code has been brutally hacked by me and any errors in the file
komm.c are mine. The modem.c file is essentially all by Dave Betz
(decvax!betz). I only wrote the routines that he requires and the hooks to
my program. The rest of the code is mine. As Starr and Betz posted their 
code to net.sources, I suppose the whole shooting match is public domain.
However, if you find this code useful we can talk about
	
			Donations

If you find this code useful and use it a lot. Please send whatever you think
it's worth to the Red Cross for Ethiopian relief.	
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 term.doc
	/bin/echo -n '	'; /bin/ls -ld term.doc
fi
-- 
C.T. Kelley  decvax!mcnc!ecsvax!ctk
Dept. of Math.    N.C. State U. Box 8205
Raleigh, N.C. 27695-8205,  919-737-3300