[net.sources] PD uu clone Part 2 of 2

lamb@lids.mit.edu.UUCP (04/16/87)

----------------PART 2 of 2 ---------------------
Some time ago I wrote a "from-scratch" uucp clone for use on our DG AOS machine
(with its brain-damaged uucp, useless to us and DG being no help).
Later I ported it to MS-DOS and VAX/VMS and its been working fine for a year
(Ive also hacked up a "rmail" for use between machines.)
Recently, with the help of John Gilmore, I was able to get the "g" protocol
realy workin (window size > 1). Previously all I could figure out was a
degenerate "g" proto using 1-window.
Im not crazy enough to say its perfect, but it does work.
Although this is a two-way (master+slave) uucico clone, compared to John's
uuslave, the coding and portibility has much to be desired. (This
project started as just an internal attempt to connect our DG to the world).
In any case for what its worth, Here it is...........
Hope everyone finds it useful.
As were not a real unix site, Id appreciate all correspondence thru
mail and not NEWS. (It took me most of last week to drum up a way to
post stuf to USENET writting a NNTP program).

                        Rick Lamb
                        Lamb@lids.mit.edu
                        or ...ihnp4!mit-eddie!lids!lamb
-------------CUT here ----------------------------------------
echo readme
cat >readme <<'@@@ Finished readme'
-------Notes on dcp.-------------------
---R.H.Lamb 6/86----------------------
Fix dcps.h for right system
Fix rmail.c for local mailer or no (#define LCLMAIL)
For PC compile comm.asm & dcpasm.asm files
Compile the rest of the .c files
Link dcp+ .c except rmail.c files + (comm+dcpasm for PC)
Link rmail
**************Finished creation**************
Modify "systems" for your site 
Modify "userfile" for your site
**************Ready to run ******************
To que up mail in current directory type
		rmail mit-eddie!lids!lamb <CR> or <NL>
		Enter your message here ending with a line with only a "."
(Note: rmail does not presently put things in RFC820 format. A "filter"
	program piped into rmail could do this easily. With out this 
	format things work ok, but youll see "Apparently to" s in your 
	mail.)
To read incomming mail type
		rmail <CR> or <NL>
		followed by <CR> or <NL> for each message
To send/receive files type
		dcp master 3 <CR>
		Where the last number is debug level
		(0 is least)


**** Prog descriptions *****
dcp.c	"uucico"
dcpsys.c	Top level state machine
dcpstart.c	uucp startup protocol+ dialing algorithm
dcpscan.c	directory scan for work
dcpsend.c	send file proto
dcprec.c	rec file proto
dcpio.c		general purpose serial I/O interface
dcppkt.c,dcpggpkt.c	"g" proto Windowsize=1 (Previously tested))
dcpgpkt.c	"g" proto Var windowsize (In use)
dcptpkt.c	"t" proto no-error chk: for virt links
dcprpkt.c	"r" proto My sliding window proto
dcpvms.c	VMS support routines
dcxqt.c		"uuxqt"
rmail.c		"rmail"
comm.asm	PC serial drivers (Saltzers pkg)
dcpasm.asm	PC directory and other asm routines
systems		"L.sys"
userfile	site info
readme		this file
format.doc	info on msg formats (RFC8??) to be passed to rmail
makeobj.*	make object files for PC(.bat) DG(.cli)
makeexe.*	make dcp.exe or dcp.pr for PC or DG
call.*		execute dcp in master mode
spawn.c         VMS spawn testing subroutine (Not needed for oper)

------notes-----
PC info: MSC 3.0, LINK 3.01, MASM 4.00
DG info: C 3.21, LINK 6.00
VMS info: C 2.0, LINK ?


--------VMS notes--------
To send mail in VMS note:
rmail "a!b!c" 
message
(Those dammed "."'s screwed up my posting on the first run >.<)

To send a file in VMS using redirected I/O (example "ss")
ss "rmail ""a!b!c" file nl:

In VMS host names with "_,-,?,&" are no good.
Make sure who you talk to has a simple name like "dgvax"

"userfile" should have
TT: for local console
0 for speed (use default speed on logon)

BUGS!!!!
The spawn command in dcxqt (lib$spawn in dcpvms) seems to work
only for small files. Redirection of input file to "rmail" larger than
a certain size get lost.
Cause is differing record file formats. Presently its a kludge that
runs "CONVERT/FDL=VAR" on the input files. Please- an VMS C hacker FIX.
@@@ Finished readme
echo format.doc
cat >format.doc <<'@@@ Finished format.doc'
-------A sample message that was received-----
-------/** denotes stuff my pgm added, the rest (**/) is what a---
------d.file should look like before sending---------
---The message was sent using:
% mail ggt@rutgers.UUCP
Subject: jeez
Hello there
(dammed dots >.<)
EOF

------------------------------------------------------
---------after recipt---------------

From uucp Tue Mar 10 16:36:03 1987 EDT remote from rutgers
>From tae  Sat Mar 14 12:53:36 1987 remote from dspvax
Received: by dspvax.MIT.EDU (5.51/MIT.1.01x)
	 on Sat, 14 Mar 87 12:53:36 EST; User rutgers!ggt; Host rutgers
Date: Sat, 14 Mar 87 12:53:36 EST
From: Tae Joo <dspvax!tae>
Message-Id: <8703141753.AA02983@dspvax.MIT.EDU>
To: rutgers!ggt
Subject: jeez

Hello there

---------before send---------------
*****The Drutg115 file
From tae  Sat Mar 14 12:53:36 1987 remote from dspvax
Received: by dspvax.MIT.EDU (5.51/MIT.1.01x)
	 on Sat, 14 Mar 87 12:53:36 EST; User rutgers!ggt; Host rutgers
Date: Sat, 14 Mar 87 12:53:36 EST
From: Tae Joo <dspvax!tae>
Message-Id: <8703141753.AA02983@dspvax.MIT.EDU>
To: rutgers!ggt
Subject: jeez

Hello there

******The Brutg115 file 
-----note: for forwarding the last line is C rmail ggt!seismo!lamb
-----U=user I=input C=command F=general file
U uucp rutgers
F D.rutgers115
I D.rutgers115
C rmail ggt
******The Crutg115 file
----S=send R=receive(not common)
S Drutg115 D.rutgers115 uucp - Drutg115 0666
S Brutg115 X.rutgers115 uucp - Brutg115 0666
----------------end of document----------------
@@@ Finished format.doc
echo mboxuucp
cat >mboxuucp <<'@@@ Finished mboxuucp'
From uucp Sun Mar 15 22:18:54 1987 EDT remote from lids
Received: by lids on Sun Mar 15 22:18:54 1987 EDT
>From uucp  Tue Apr  7 20:28:41 1987 remote from mit-eddie
Received: by EDDIE.MIT.EDU with UUCP with smail2.3 with sendmail-5.31/4.7 id <AA05017@EDDIE.MIT.EDU>; Tue, 7 Apr 87 20:28:30 EDT
Received: by lids on Sun Mar 15 22:14:42 1987 EDT
Date: 7 Apr 87 19:28:17 EST (Tue)
From: uucp@EDDIE.MIT.EDU
Message-Id: <8704071928.AA05012@EDDIE.MIT.EDU>
To: lids!lamb

Hello there.
From uucp Sun Mar 15 22:51:39 1987 EDT remote from lids
Received: by lids on Sun Mar 15 22:51:39 1987 EDT
>From uucp  Tue Apr  7 20:55:47 1987 remote from mit-eddie
Received: by EDDIE.MIT.EDU with UUCP with smail2.3 with sendmail-5.31/4.7 id <AA05699@EDDIE.MIT.EDU>; Tue, 7 Apr 87 20:55:33 EDT
Received: by lids on Sun Mar 15 22:36:58 1987 EDT
Date: 7 Apr 87 19:55:25 EST (Tue)
From: uucp@EDDIE.MIT.EDU
Message-Id: <8704071955.AA05697@EDDIE.MIT.EDU>
To: lids!uucp

>From uucp  Tue Apr  7 20:45:40 1987 remote from mit-eddie
Received: by EDDIE.MIT.EDU with UUCP with smail2.3 with sendmail-5.31/4.7 id <AA05435@EDDIE.MIT.EDU>; Tue, 7 Apr 87 20:44:59 EDT
Received: by lids on Sun Mar 15 22:26:58 1987 EDT
Received: by rutgers.UUCP (5.51/UUCP.1.01x) on Sat, 14 Mar 87 12:53:36 EST; 
Date: Sat, 14 Mar 87 12:53:36 EST
From: UUCP <rutgers!uucp@EDDIE.MIT.EDU>
Subject: jeez
Message-Id: <8704071944.AA05432@EDDIE.MIT.EDU>
To: lids!mit-eddie!lids!uucp

Hello there
#include "dcp.h"
#include "dcp0.h"

/*<FF>*/
/* usage dcp (master/slave(D)) (debug level 0=none(D)) (system name(MYNAME))*/
/* (console device)                          */
main(argc,argv)
int argc;
char *argv[];
{
int ftmp;
char line[132];

flog=creat(SYSLOG,0775);
close(flog); flog=open(SYSLOG,2);

remote=TRUE;
debug=3;        
fp = -1;
fw = -1;

ftmp=open(USERFILE,0);
getline(ftmp,line);
sscanf(line,"%s %s %s",myname,username);
getline(ftmp,line);
sscanf(line,"%s %s",tty,speed);
strcpy(spooldir,".");  /* default spooldir is current dir */
close(ftmp);

if(argc > 1 && strcmp(argv[1],"master") == 0) remote=FALSE;
if(argc > 2) sscanf(argv[2],"%d",&debug);
if(argc > 3) strcpy(myname,argv[3]);
if(argc > 4) strcpy(tty,argv[4]);

if(! remote) 
{
if((fsys=open(SYSTEMS,0)) ==-1) return(FALSE);
state='I';
while(TRUE)
{
if(debug>0) printmsg("Mstate = %c",state);
switch(state)
{
case 'I': state=getsystem();    break;
case 'S': state=callup();       break;
case 'P': state=startup();      break;
case 'D': state=master();       break;
case 'Y': state=sysend();       break;
case 'G': state='I';            break;
}
if(state=='A') break;
}
close(fsys);
}
else
{
if(openline(tty,speed)==-1) return(FALSE);
state='L';
while(TRUE)
{
if(debug>0) printmsg("Sstate = %c",state);
switch(state)
{
case 'L':state=login();     break;
case 'I':state=startup();   break;
case 'R':state=slave();     break;
case 'Y':state=sysend();    break;
}
if(state=='A') break;
}
closeline();
}

if(dcxqt()) if(debug) printmsg("ERROR in DCXQT");
	/* scan and process any recieved files */


close(flog);
}

/*<FF>*/
/*
**
**
**master
**
**
*/
master()
{
state='I';
while(TRUE)
{
if(debug>1) printmsg("Top level state (master mode) %c",state);
switch(state)
{
case 'I':state=sinit();      break;
case 'B':state=scandir();    break;
case 'S':state=send();       break;
case 'Q':state=sbreak();     break;
case 'G':state=receive();    break;
case 'C':state='Y';          break;
case 'Y':state=endp();       break;
case 'P':return('Y');
case 'A':return('A');
default:return('A');
}
}
}

/*<FF>*/
/*
**
**
**slave
**
**
*/
slave()
{
state='I';
while(TRUE)
{
if(debug>1) printmsg("Top level state (slave mode) %c",state);
switch(state)
{
case 'I':state=rinit();      break;
case 'F':state=receive();    break;
case 'C':state=schkdir();    break;
case 'T':state='B';          break;
case 'B':state=scandir();    break;
case 'S':state=send();       break;
case 'Q':state=sbreak();     break;
case 'G':return('Y');
case 'Y':state=endp();       break;
case 'P':return('Y');
case 'A':return('A');
default:return('A');
}
}
}

/*<FF>*/
/*
 *  r e c e i v e
 *
 *  This is the state table switcher for receiving files.
 */

receive()
{

state = 'F';/* Receive-Init is the start state */

while(TRUE)
{
if (debug > 2) printmsg(" receive state: %c",state);
switch(state)/* Do until done */
{
case 'F':state = rfile(); break; /* Receive-File */
case 'D':state = rdata(); break; /* Receive-Data */
case 'C':return('C');/* Complete state */
case 'A':return('Y');/* "Abort" state */
default:return('Y');
}
}
}

/*<FF>*/
/*
 *  s e n d 
 *
 *  Sendsw is the state table switcher for sending files.  It loops until
 *  either it finishes, or an error is encountered.  The routines called
 *  by sendsw are responsible for changing the state.
 *
 */
send()
{
fp = -1;                /* reset file getter/opener */
state = 'F';/* Send initiate is the start state */
while(TRUE)/* Do this as long as necessary */
{
if (debug > 2) printmsg("send state: %c",state);
switch(state)
{
case 'F':state = sfile();  break; /* Send-File */
case 'D':state = sdata();  break; /* Send-Data */
case 'Z':state = seof();  break; /* Send-End-of-File */
case 'B':return ('B'); /* Complete */
case 'A':return ('Y'); /* "Abort" */
default:return ('Y'); /* Unknown, fail */
}
}
}

/*<FF>*/
/*
 *
 *      login (for slave in PC mode)
 *
*/
login()
{
char logmsg[132];
#ifdef PC
msgtime= 2*MSGTIME;
lretry:
wmsg("Username:",0);
rmsg(logmsg,0);
if(debug > 0) printmsg("Username = %s",logmsg);
wmsg("Password:",0);
rmsg(logmsg,0);
if(debug > 0) printmsg("Password = %s",logmsg);
if(strcmp(logmsg,"uucp") != 0) goto lretry;
#endif
return('I');
}
From uucp Mon Mar 16 03:20:48 1987 EDT remote from lids
Received: by lids on Mon Mar 16 03:20:48 1987 EDT
>From uucp  Tue Apr  7 21:03:05 1987 remote from mit-eddie
Received: by EDDIE.MIT.EDU with UUCP with smail2.3 with sendmail-5.31/4.7 id <AA05879@EDDIE.MIT.EDU>; Tue, 7 Apr 87 21:02:42 EDT
Received: by lids on Sun Mar 15 22:43:44 1987 EDT
Date: 7 Apr 87 20:02:39 EST (Tue)
From: uucp@EDDIE.MIT.EDU
Message-Id: <8704072002.AA05877@EDDIE.MIT.EDU>
To: lids!uucp

>From uucp  Tue Apr  7 20:49:16 1987 remote from mit-eddie
Received: by EDDIE.MIT.EDU with UUCP with smail2.3 with sendmail-5.31/4.7 id <AA05507@EDDIE.MIT.EDU>; Tue, 7 Apr 87 20:48:44 EDT
Received: by lids on Sun Mar 15 22:34:18 1987 EDT
Received: by rutgers.UUCP (5.51/UUCP.1.01x) on Sat, 14 Mar 87 12:53:36 EST; 
Date: Sat, 14 Mar 87 12:53:36 EST
From: UUCP <rutgers!uucp@EDDIE.MIT.EDU>
Subject: jeez
Message-Id: <8704071948.AA05505@EDDIE.MIT.EDU>
To: lids!mit-eddie!lids!uucp

Hello there
#include "dcp.h"
#include "dcp0.h"

/*<FF>*/
/* usage dcp (master/slave(D)) (debug level 0=none(D)) (system name(MYNAME))*/
/* (console device)                          */
main(argc,argv)
int argc;
char *argv[];
{
int ftmp;
char line[132];

flog=creat(SYSLOG,0775);
close(flog); flog=open(SYSLOG,2);

remote=TRUE;
debug=3;        
fp = -1;
fw = -1;

ftmp=open(USERFILE,0);
getline(ftmp,line);
sscanf(line,"%s %s %s",myname,username);
getline(ftmp,line);
sscanf(line,"%s %s",tty,speed);
strcpy(spooldir,".");  /* default spooldir is current dir */
close(ftmp);

if(argc > 1 && strcmp(argv[1],"master") == 0) remote=FALSE;
if(argc > 2) sscanf(argv[2],"%d",&debug);
if(argc > 3) strcpy(myname,argv[3]);
if(argc > 4) strcpy(tty,argv[4]);

if(! remote) 
{
if((fsys=open(SYSTEMS,0)) ==-1) return(FALSE);
state='I';
while(TRUE)
{
if(debug>0) printmsg("Mstate = %c",state);
switch(state)
{
case 'I': state=getsystem();    break;
case 'S': state=callup();       break;
case 'P': state=startup();      break;
case 'D': state=master();       break;
case 'Y': state=sysend();       break;
case 'G': state='I';            break;
}
if(state=='A') break;
}
close(fsys);
}
else
{
if(openline(tty,speed)==-1) return(FALSE);
state='L';
while(TRUE)
{
if(debug>0) printmsg("Sstate = %c",state);
switch(state)
{
case 'L':state=login();     break;
case 'I':state=startup();   break;
case 'R':state=slave();     break;
case 'Y':state=sysend();    break;
}
if(state=='A') break;
}
closeline();
}

if(dcxqt()) if(debug) printmsg("ERROR in DCXQT");
	/* scan and process any recieved files */


close(flog);
}

/*<FF>*/
/*
**
**
**master
**
**
*/
master()
{
state='I';
while(TRUE)
{
if(debug>1) printmsg("Top level state (master mode) %c",state);
switch(state)
{
case 'I':state=sinit();      break;
case 'B':state=scandir();    break;
case 'S':state=send();       break;
case 'Q':state=sbreak();     break;
case 'G':state=receive();    break;
case 'C':state='Y';          break;
case 'Y':state=endp();       break;
case 'P':return('Y');
case 'A':return('A');
default:return('A');
}
}
}

/*<FF>*/
/*
**
**
**slave
**
**
*/
slave()
{
state='I';
while(TRUE)
{
if(debug>1) printmsg("Top level state (slave mode) %c",state);
switch(state)
{
case 'I':state=rinit();      break;
case 'F':state=receive();    break;
case 'C':state=schkdir();    break;
case 'T':state='B';          break;
case 'B':state=scandir();    break;
case 'S':state=send();       break;
case 'Q':state=sbreak();     break;
case 'G':return('Y');
case 'Y':state=endp();       break;
case 'P':return('Y');
case 'A':return('A');
default:return('A');
}
}
}

/*<FF>*/
/*
 *  r e c e i v e
 *
 *  This is the state table switcher for receiving files.
 */

receive()
{

state = 'F';/* Receive-Init is the start state */

while(TRUE)
{
if (debug > 2) printmsg(" receive state: %c",state);
switch(state)/* Do until done */
{
case 'F':state = rfile(); break; /* Receive-File */
case 'D':state = rdata(); break; /* Receive-Data */
case 'C':return('C');/* Complete state */
case 'A':return('Y');/* "Abort" state */
default:return('Y');
}
}
}

/*<FF>*/
/*
 *  s e n d 
 *
 *  Sendsw is the state table switcher for sending files.  It loops until
 *  either it finishes, or an error is encountered.  The routines called
 *  by sendsw are responsible for changing the state.
 *
 */
send()
{
fp = -1;                /* reset file getter/opener */
state = 'F';/* Send initiate is the start state */
while(TRUE)/* Do this as long as necessary */
{
if (debug > 2) printmsg("send state: %c",state);
switch(state)
{
case 'F':state = sfile();  break; /* Send-File */
case 'D':state = sdata();  break; /* Send-Data */
case 'Z':state = seof();  break; /* Send-End-of-File */
case 'B':return ('B'); /* Complete */
case 'A':return ('Y'); /* "Abort" */
default:return ('Y'); /* Unknown, fail */
}
}
}

/*<FF>*/
/*
 *
 *      login (for slave in PC mode)
 *
*/
login()
{
char logmsg[132];
#ifdef PC
msgtime= 2*MSGTIME;
lretry:
wmsg("Username:",0);
rmsg(logmsg,0);
if(debug > 0) printmsg("Username = %s",logmsg);
wmsg("Password:",0);
rmsg(logmsg,0);
if(debug > 0) printmsg("Password = %s",logmsg);
if(strcmp(logmsg,"uucp") != 0) goto lretry;
#endif
return('I');
}
@@@ Finished mboxuucp
echo systems
cat >systems <<'@@@ Finished systems'
ihnp4 Slave
lids Slave COM1 DIR 9600 g \n-me:-op\n-word:-dogbridge\ntest\n
dlids Slave COM1 DIR 9600 g \n-me:-tuucp\n-word:-ggggg\n
mit-eddie Any COM2 ACU 1200 g ATZ\r-OK\r-ATDT88222\r-CONNECT\r-\r-ogin:-uucp\r-assword:-uucp\r
hurob1 Slave
lids Slave COM2 ACU 1200 g ATZ\r-K\r-ATDT87444\r-CT\r-\n-ame:-op\n-ord:-dogbridge\ntest\n
lids Slave COM2 ACU 1200 g ATZ\r-K\r-ATDT87444\r-CT\r-\n-ame:-uucp\n-ord:-uucp\n
seismo Slave
orly Slave
rutgers Slave
speedy Slave
dspvax Any COM2 ACU 1200 g ATZ\r-K\r-ATDT86666\r-CT\r-\r-ogin:-uucp\r-ord:-what\r
mit-atrp Slave COM2 ACU 1200 g ATZ\r-K\r-ATDT87922\r-CT\r-\r-ogin:-uucp\r-ord:-duck\r
allegra Slave COM2 ACU 1200 g ATZ\r-K\r-ATDT9,15551212392\r-CT\r-\r-ogin:-uucp\r-ord:-attttt\r
@@@ Finished systems
echo userfile
cat >userfile <<'@@@ Finished userfile'
lids uucp
COM1 9600
(arghhhhhh >.< want a dot here!!!)

/* prototype */
machine-name user-name
default-console-for-call-in's default-baud
default-spool-directory
/************/
@@@ Finished userfile
echo comm.h
cat >comm.h <<'@@@ Finished comm.h'
/*	declarations for comm.asm
**
**	compilation must use the Ze switch to enable the
**	"far" keyword for the small memory model
**
**	Robin Rohlicek   3/86
*/

void far select_port( int );	/*	select active port (1 or 2) */

void far save_com();		/*	save the interupt vectors */

void far restore_com();		/*	restore those vectors */

int far install_com();		/*	install our vectors */

void far open_com( 		/*	open com port */
	int, 	/* baud */
	int, 	/* 'M'odem or 'D'irect */
	int, 	/* Parity 'N'one, 'O'dd, 'E'ven, 'S'pace, 'M'ark */
	int, 	/* stop bits (1 or 2) */
	int);	/* Xon/Xoff 'E'nable, 'D'isable */

void far close_com();		/* 	close com port */

void far dtr_off();		/*	clear DTR */

void far dtr_on();		/*	set DTR */

long far r_count();		/*	receive counts */
	/* high word = total size of receive buffer */
	/* low word = number of pending chars */
#define r_count_size() ( (int) (r_count()>>16) )
#define r_count_pending() ( (int) r_count() )

int far receive_com();		/*	get one character */
	/* return -1 if none available */

long far s_count();		/*	send counts */
	/* high word = total size of transmit buffer */
	/* low word = number of bytes free in transmit buffer */
#define s_count_size() ( (int) (s_count()>>16) )
#define s_count_free() ( (int) s_count() )

void far send_com(int);		/* 	send a character */

void far send_local(int);	/*	simulate receive of char */

void far sendi_com(int);	/*	send immediately */

void far break_com();		/*	send a BREAK */

int * far com_errors();		/*	pointer to error counts 
					(in static area) */
#define COM_EOVFLOW 0	/* buffer overflows */
#define COM_EOVRUN  1	/* receive overruns */
#define COM_EBREAK  2	/* break chars */
#define COM_EFRAME  3	/* framing errors */
#define COM_EPARITY 4	/* parity errors */
#define COM_EXMIT   5	/* transmit erros */
#define COM_EDSR    6	/* data set ready errors */
#define COM_ECTS    7	/* clear to send errors */
#define COM_NERR    8	/* number of errors */
@@@ Finished comm.h
echo dcp.h
cat >dcp.h <<'@@@ Finished dcp.h'
/* DCP a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
#include <stdio.h>		/* Standard UNIX  definitions */
#include "dcps.h"
#define MSGTIME         20
#define MAXPACK         256

#define ACK     4       /*      general definitions     */
#define NAK     2
#define DATA    0
#define CLOSE   1
#define ERROR   10
#define EMPTY   11


#define TRUE    -1
#define FALSE   0

/*<FF>*/
typedef int (*procref)();

typedef struct {
        char type;
        procref a;
        procref b;
        procref c;
        procref d;
} Proto;

/* the various protocols available. Add here for others */
extern procref          getpkt,sendpkt,openpk,closepk;

extern int              ggetpkt(),gsendpkt(),gopenpk(),gclosepk();
extern int              kgetpkt(),ksendpkt(),kopenpk(),kclosepk();
extern int              rgetpkt(),rsendpkt(),ropenpk(),rclosepk();
extern int              tgetpkt(),tsendpkt(),topenpk(),tclosepk();

/*<FF>*/
extern int              pktsize;                /* packet size for this pro*/
extern int              flog;                   /* system log file */
extern int              fw;                     /* cfile pointer */
extern int              fpr,fpw;                /* comm dev pointer */
extern char             cfile[80];              /* work file pointer */
extern int              remote;                 /* -1 means we're remote*/
extern int              debug;                  /* debugging level */
extern int              msgtime;                /* timout setting */
extern char             fromfile[132];
extern char             tofile[132];
extern char             state;                  /* present state */
extern int              fp;                     /* current disk file ptr */
extern int              size;                   /* nbytes in buff */
extern int              fsys;
extern char             tty[20];
extern char             myname[20];
extern char             username[20];
extern char             spooldir[80];
extern char             rmtname[20];
extern char             cctime[20];
extern char             device[20];
extern char             type[10];
extern char             speed[10];
extern char             proto[5];
extern char             loginseq[132];
extern unsigned int     checksum();
@@@ Finished dcp.h
echo dcps.h
cat >dcps.h <<'@@@ Finished dcps.h'
/* DCP a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/** select system */
#define PC /* */
/*#define DG /* */
/*#define VMS /* */

#define USERFILE	"userfile"
#define SYSTEMS		"systems"
#define SYSLOG		"dcp.log"
@@@ Finished dcps.h
echo comm.asm
cat >comm.asm <<'@@@ Finished comm.asm'
	TITLE   COM_PKG2 -- Last updated 10/6/85
        PAGE    75,132
;
;	modified to use MSC calling sequence.
;	jrr 3/86
;
; Communications Package for the IBM PC, XT, AT and PCjr
; and strict compatibles.
; May be copied and used freely -- This is a public domain program
; Developed by Richard Gillmann, John Romkey, Jerry Saltzer,
; Craig Milo Rogers, Dave Mitton and Larry Afrin.
;
; We'd sure like to see any improvements you might make.
; Please send all comments and queries about this package
; to GILLMANN@USC-ISIB.ARPA
;
; o Supports both serial ports simultaneously
; o All speeds to 19200 baud
; o Compatible with PC, XT, AT and PCjr.
; o Built in XON/XOFF flow control option
; o Assembly language calling conventions
; o Logs all comm errors
; o Direct connect or modem protocol
;
; MAXIMUM BUFFER SIZES
R_SIZE	EQU     500		; SIZE OF RECEIVE BUFFERS
S_SIZE	EQU     500		; SIZE OF TRANSMIT BUFFERS rhl/4/86
; INTERRUPT NUMBERS
INT_COM1 EQU	0CH		; COM1: FROM 8259
INT_COM2 EQU	0BH		; COM2: FROM 8259
; 8259 PORTS
INTA00  EQU     20H             ; 8259A PORT, A0 = 0
INTA01  EQU     21H             ; 8259A PORT, A0 = 1
; COM1: LEVEL 4
IRQ4	EQU	2*2*2*2			; 8259A OCW1 MASK, M4=1, A0=0
NIRQ4	EQU	NOT IRQ4 AND 0FFH	; COMPLEMENT OF ABOVE
EOI4	EQU	4 OR 01100000B		; 8259A OCW2 SPECIFIC IRQ4 EOI, A0=0
; COM2: LEVEL 3
IRQ3	EQU	2*2*2			; 8259A OCW1 MASK, M3=1, A0=0
NIRQ3	EQU	NOT IRQ3 AND 0FFH	; COMPLEMENT OF ABOVE
EOI3	EQU	3 OR 01100000B		; 8259A OCW2 SPECIFIC IRQ3 EOI, A0=0
; FLOW CONTROL CHARACTERS
CONTROL_Q EQU	11H		; XON
CONTROL_S EQU	13H		; XOFF
; MISC.
DOS	EQU	21H		; DOS FUNCTION CALLS
	PAGE
;
; ROM BIOS Data Area
;
RBDA	SEGMENT	AT 40H
RS232_BASE DW	4 DUP(?)	; ADDRESSES OF RS232 ADAPTERS
RBDA	ENDS
;
; ROM PC-Type IDENT
;
ROM	SEGMENT	AT 0F000H
	ORG	0FFFEH
ROMID	DB	?		; 0FFH=PC OR EARLY XT, 0FEH=XT, 0FDH=JR
ROM	ENDS
        PAGE
;
; TABLE FOR EACH SERIAL PORT
;
SP_TAB		STRUC
PORT		DB	?	; 1 OR 2
; PARAMETERS FOR THIS INTERRUPT LEVEL
INT_COM		DB	?	; INTERRUPT NUMBER
IRQ		DB	?	; 8259A OCW1 MASK
NIRQ		DB	?	; COMPLEMENT OF ABOVE
EOI		DB	?	; 8259A OCW2 SPECIFIC END OF INTERRUPT
; INTERRUPT HANDLERS FOR THIS LEVEL
INT_HNDLR	DW	?	; OFFSET TO INTERRUPT HANDLER
OLD_COM_OFF	DW	?	; OLD HANDLER'S OFFSET
OLD_COM_SEG	DW	?	; OLD HANDLER'S SEGMENT
; ATTRIBUTES
INSTALLED	DB	?	; IS PORT INSTALLED ON THIS PC? (1=YES,0=NO)
BAUD_RATE	DW	?	; 19200 MAX
CONNECTION	DB	?	; M(ODEM), D(IRECT)
PARITY		DB	?	; N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
STOP_BITS	DB	?	; 1, 2
XON_XOFF	DB	?	; E(NABLED), D(ISABLED)
; FLOW CONTROL STATE
HOST_OFF	DB	?	; HOST XOFF'ED (1=YES,0=NO)
PC_OFF		DB	?	; PC XOFF'ED (1=YES,0=NO)
; ERROR COUNTS
ERROR_BLOCK	DW	8 DUP(?)	; EIGHT ERROR COUNTERS
; 8250 PORTS
DATREG		DW	?	; DATA REGISTER
IER		DW	?	; INTERRUPT ENABLE REGISTER
IIR		DW      ?	; INTERRUPT IDENTIFICATION REGISTER
LCR		DW      ?	; LINE CONTROL REGISTER
MCR		DW      ?	; MODEM CONTROL REGISTER
LSR		DW      ?	; LINE STATUS REGISTER
MSR		DW      ?	; MODEM STATUS REGISTER
; BUFFER POINTERS
START_TDATA     DW      ?       ; INDEX TO FIRST CHARACTER IN X-MIT BUFFER
END_TDATA       DW      ?       ; INDEX TO FIRST FREE SPACE IN X-MIT BUFFER
START_RDATA     DW      ?       ; INDEX TO FIRST CHARACTER IN REC. BUFFER
END_RDATA       DW      ?       ; INDEX TO FIRST FREE SPACE IN REC. BUFFER
; BUFFER COUNTS
SIZE_TDATA      DW      ?       ; NUMBER OF CHARACTERS IN X-MIT BUFFER
SIZE_RDATA      DW      ?       ; NUMBER OF CHARACTERS IN REC. BUFFER
; BUFFERS
TDATA           DB      S_SIZE DUP(?)	; SEND BUFFER
RDATA           DB      R_SIZE DUP(?)	; RECEIVE BUFFER
SP_TAB		ENDS
; SP_TAB EQUATES
; WE HAVE TO USE THESE BECAUSE OF PROBLEMS WITH STRUC
EOVFLOW		EQU	ERROR_BLOCK	; BUFFER OVERFLOWS
EOVRUN		EQU	ERROR_BLOCK+2	; RECEIVE OVERRUNS
EBREAK		EQU	ERROR_BLOCK+4	; BREAK CHARS
EFRAME		EQU	ERROR_BLOCK+6	; FRAMING ERRORS
EPARITY		EQU	ERROR_BLOCK+8	; PARITY ERRORS
EXMIT		EQU	ERROR_BLOCK+10	; TRANSMISSION ERRORS
EDSR    	EQU	ERROR_BLOCK+12	; DATA SET READY ERRORS
ECTS    	EQU	ERROR_BLOCK+14	; CLEAR TO SEND ERRORS
DLL		EQU	DATREG		; LOW DIVISOR LATCH
DLH		EQU	IER		; HIGH DIVISOR LATCH
	PAGE
;	put the data in the DGROUP segment
;	far calls enter with DS pointing to DGROUP
;
DGROUP	GROUP _DATA
_DATA	SEGMENT PUBLIC 'DATA'
;
DIV50PC		EQU	2304		; DIVISOR FOR 50 BAUD (PC,XT)
DIV50JR		EQU	2237		; DIVISOR FOR 50 BAUD (JR)
DIV50		DW	2304		; ACTUAL DIVISOR FOR 50 BAUD IN USE
CURRENT_AREA	DW	AREA1		; CURRENTLY SELECTED AREA
; DATA AREAS FOR EACH PORT
AREA1	SP_TAB	<1,INT_COM1,IRQ4,NIRQ4,EOI4>	; COM1 DATA AREA
AREA2	SP_TAB	<2,INT_COM2,IRQ3,NIRQ3,EOI3>	; COM2 DATA AREA
_DATA    ENDS
        PAGE
COM_TEXT    SEGMENT PARA PUBLIC 'CODE'
        ASSUME  CS:COM_TEXT,DS:DGROUP,ES:NOTHING

	PUBLIC	_select_port
	PUBLIC	_save_com
	PUBLIC	_install_com
	PUBLIC	_restore_com
	PUBLIC	_open_com
	PUBLIC	_close_com
	PUBLIC	_dtr_on
	PUBLIC	_dtr_off
	PUBLIC	_r_count
	PUBLIC	_s_count
	PUBLIC	_receive_com
	PUBLIC	_send_com
	PUBLIC	_sendi_com
	PUBLIC	_send_local
	PUBLIC	_break_com
	PUBLIC	_com_errors
	PAGE
;
; SELECT WHICH PORT IS TO BE "ACTIVE"
;	[bp+6] = port number
_select_port	PROC FAR
	push bp
	mov bp,sp
	mov AX,[bp+6]	; get aguement
	TEST	AL,1		; FIRST PORT?
	JZ	SP1		; IF NOT, IT MUST BE SECOND PORT
	MOV	AX,OFFSET DGROUP:AREA1	; SELECT COM1 DATA AREA
	JMP	SHORT SPX	; CONTINUE
SP1:	MOV	AX,OFFSET DGROUP:AREA2	; SELECT COM2 DATA AREA
SPX:	MOV	CURRENT_AREA,AX	; SET SELECTION IN MEMORY
	mov sp,bp
	pop bp
	RET			; DONE
_select_port	ENDP
	PAGE
;
; SAVE ORIGINAL COM VECTOR
;
_save_com	PROC FAR
	push bp
	mov bp,sp
	push si
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	PUSH	ES		; SAVE EXTRA SEGMENT
	MOV	AREA1.INT_HNDLR,OFFSET INT_HNDLR1
	MOV	AREA2.INT_HNDLR,OFFSET INT_HNDLR2
	MOV	AH,30H		; GET DOS VERSION NUMBER
	INT	DOS		; DOS FUNCTION
	CMP	AL,2		; AT LEAST DOS 2?
	JB	SVC1		; JUMP IF DOS 1
; SAVE OLD VECTOR WITH DOS 2 CALLS
	MOV	AH,35H		; FETCH INTERRUPT VECTOR CONTENTS
	MOV	AL,INT_COM[SI]	; INTERRUPT NUMBER
	INT	DOS		; DOS 2 FUNCTION
	MOV	OLD_COM_OFF[SI],BX	; SAVE
	MOV	BX,ES			; ES:BX
	MOV	OLD_COM_SEG[SI],BX	; FOR LATER RESTORATION
	JMP	SHORT SVCX	; DONE
; SAVE OLD VECTOR WITH DOS 1 CALLS
SVC1:	MOV	AX,0		; ZERO SEGMENT
	MOV	ES,AX		; ES POINTS TO INTERRUPT VECTORS
	MOV	BL,INT_COM[SI]	; OUR INTERRUPT NUMBER
	MOV	BH,0		; BL -> BX
	SHL	BX,1		; TIMES FOUR
	SHL	BX,1		; IS OFFSET OF VECTOR IN MEMORY
	MOV	AX,WORD PTR ES:[BX]	; SAVE
	MOV	OLD_COM_OFF[SI],AX	; THE
	ADD	BX,2			; OLD
	MOV	AX,WORD PTR ES:[BX]	; INTERRUPT
	MOV	OLD_COM_SEG[SI],AX	; VECTOR
SVCX:	POP	ES		; RESTORE ES
	pop si
	mov sp,bp
	pop bp
	RET			; DONE
_save_com	ENDP
	PAGE
;
; INSTALL_COM:  INSTALL THE ACTIVE PORT
;
; SET 8250 PORTS FROM RS-232 BASE IN ROM BIOS DATA AREA
; INITIALIZE PORT CONSTANTS AND ERROR COUNTS
; INSTALL INTERRUPT VECTOR
;
;	return ax=1 on success ax=0 on failure
;
_install_com	PROC FAR
	push bp
	mov bp,sp
	push si
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	PUSH	ES		; SAVE EXTRA SEGMENT
	CMP	INSTALLED[SI],1	; ALREADY INSTALLED?
	JNE	INSTOK		; NO, CONTINUE
	JMP	INSTX		; ELSE JUMP IF ALREADY INSTALLED
; CLEAR ERROR COUNTS
INSTOK:	MOV	WORD PTR EOVFLOW[SI],0	; BUFFER OVERFLOWS
	MOV	WORD PTR EOVRUN[SI],0	; RECEIVE OVERRUNS
	MOV	WORD PTR EBREAK[SI],0	; BREAK CHARS
	MOV	WORD PTR EFRAME[SI],0	; FRAMING ERRORS
	MOV	WORD PTR EPARITY[SI],0	; PARITY ERRORS
	MOV	WORD PTR EXMIT[SI],0	; TRANSMISSION ERRORS
	MOV	WORD PTR EDSR[SI],0	; DATA SET READY ERRORS
	MOV	WORD PTR ECTS[SI],0	; CLEAR TO SEND ERRORS
; SENSE PC TYPE AND SET DIVISOR ACCORDINGLY
	MOV	BX,ROM		; HIGH ROM SEGMENT
	MOV	ES,BX		; TO ES
	ASSUME	ES:ROM
	MOV	DIV50,DIV50PC	; ASSUME PC OR XT
	CMP	ROMID,0FDH	; IS IT A PCjr?
	JNE	INST0		; JUMP IF NOT
	MOV	DIV50,DIV50JR	; ELSE SET JR DIVISOR
; SET 8250 PORT ADDRESSES
INST0:	MOV	BX,RBDA		; ROM BIOS DATA AREA
	MOV	ES,BX		; TO ES
	ASSUME	ES:RBDA
	TEST	PORT[SI],1	; PORT 1?
	JZ	INST1		; JUMP IF NOT
	MOV	AX,3F8H		; COM1 BASE PORT ADDRESS
	JMP	SHORT INST2	; CONTINUE
INST1:	MOV	AX,2F8H		; COM2 BASE PORT ADDRESS
INST2:	CMP	AX,RS232_BASE	; INSTALLED?
	JE	INST2A		; JUMP IF SO
	CMP	AX,RS232_BASE+2	; INSTALLED?
	JNE	INST666		; JUMP IF NOT
INST2A:	MOV	BX,DATREG	; OFFSET OF TABLE OF PORTS
	MOV	CX,7		; LOOP SIX TIMES
INST3:	MOV	WORD PTR [SI][BX],AX ; SET PORT ADDRESS
	INC	AX		; NEXT PORT
	ADD	BX,2		; NEXT WORD ADDRESS
	LOOP	INST3		; RS232 BASE LOOP
; RESET VECTOR TO POINT TO OUR HANDLER
	MOV	AREA1.INT_HNDLR,OFFSET INT_HNDLR1
	MOV	AREA2.INT_HNDLR,OFFSET INT_HNDLR2
	MOV	AH,25H		; SET INTERRUPT VECTOR CONTENTS
	MOV	AL,INT_COM[SI]	; INTERRUPT NUMBER
	MOV	DX,OFFSET DGROUP:INT_HNDLR[SI] ; OUR INTERRUPT HANDLER
	PUSH    DS              ; SAVE DATA SEGMENT
	PUSH	CS		; COPY CS
	POP	DS		; TO DS
	INT	DOS		; DOS FUNCTION
	POP     DS              ; RECOVER DATA SEGMENT
; PORT INSTALLED
INSTX:	MOV	INSTALLED[SI],1	; PORT INSTALLED
	POP	ES		; RESTORE ES
	mov ax,1
	pop si
	mov sp,bp
	pop bp
        RET			; DONE
; PORT NOT INSTALLED
INST666:MOV	INSTALLED[SI],0	; PORT NOT INSTALLED ON THIS PC
	POP	ES		; RESTORE ES
	mov ax,0
	pop si
	mov sp,bp
	pop bp
	RET			; DONE
_install_com	ENDP
	PAGE
;
; RESTORE ORIGINAL INTERRUPT VECTOR
;
_restore_com	PROC FAR
	push bp
	mov bp,sp
	push si
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	MOV	INSTALLED[SI],0	; PORT IS NO LONGER INSTALLED
	MOV	AH,25H		; SET INTERRUPT VECTOR FUNCTION
	MOV	AL,INT_COM[SI]	; INTERRUPT NUMBER
	MOV	DX,OLD_COM_OFF[SI] ; OLD OFFSET TO DX
	MOV	BX,OLD_COM_SEG[SI] ; OLD SEG
	PUSH	DS		; SAVE DS
	MOV	DS,BX		; TO DS
	INT	DOS		; DOS FUNCTION
	POP	DS		; RECOVER DS
	pop si
	mov sp,bp
	pop bp
        RET			; DONE
_restore_com	ENDP
        PAGE
;
; OPEN_COM ON CURRENT PORT
;
; CLEAR BUFFERS
; RE-INITIALIZE THE INTEL 8250 UART
; ENABLE INTERRUPTS ON THE INTEL 8259 INTERRUPT CONTROL CHIP
;
; [bp+6] = BAUD RATE
; [bp+8] = CONNECTION: M(ODEM), D(IRECT)
; [bp+10] = PARITY:     N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
; [bp+12] = STOP BITS:  1, 2
; [bp+14] = XON/XOFF:   E(NABLED), D(ISABLED)
;
_open_com	PROC FAR
	push bp
	mov bp,sp
	push si
	MOV	SI,CURRENT_AREA		; SI POINTS TO DATA AREA

	CLI				; INTERRUPTS OFF
	mov ax,[bp+6]
	MOV	BAUD_RATE[SI],AX	; SET
	mov bh,[bp+8]
	MOV	CONNECTION[SI],BH	;     ARGS
	mov bl,[bp+10]
	MOV	PARITY[SI],BL		;          IN
	mov ch,[bp+12]
	MOV	STOP_BITS[SI],CH	;             MEMORY
	mov cl,[bp+14]
	MOV	XON_XOFF[SI],CL	

; RESET FLOW CONTROL
	MOV	HOST_OFF[SI],0		; HOST FLOWING
	MOV	PC_OFF[SI],0		; PC FLOWING

; RESET BUFFER COUNTS AND POINTERS
	MOV	START_TDATA[SI],0
	MOV	END_TDATA[SI],0
	MOV	START_RDATA[SI],0
	MOV	END_RDATA[SI],0
	MOV	SIZE_TDATA[SI],0
	MOV	SIZE_RDATA[SI],0

	TEST	INSTALLED[SI],1		; PORT INSTALLED?
	JNZ	OC1			; SKIP IF SO
	JMP	OCX			; ELSE ABORT
OC1:
; RESET THE 8250
        MOV     AL,0
        MOV     DX,MCR[SI]
        OUT     DX,AL
	JMP	$+2		; I/O DELAY FOR JR

        MOV     DX,LSR[SI]	; RESET LINE STATUS CONDITION
        IN      AL,DX
	JMP	$+2		; I/O DELAY FOR JR
        MOV     DX,DATREG[SI]	; RESET RECSIVE DATA CONDITION
        IN      AL,DX
	JMP	$+2		; I/O DELAY FOR JR
        MOV     DX,MSR[SI]	; RESET MODEM DELTAS AND CONDITIONS
        IN      AL,DX

; CONVERT PASSED BAUD RATE TO 8250 DIVISOR
	MOV	AX,50		; 50 BAUD
	MUL	DIV50		; TIMES ITS DIVISOR
	DIV	BAUD_RATE[SI]	; OTHER SPEEDS ARE PROPORTIONAL
	MOV	BX,AX		; RESULT TO BX

; SET 8250 DIVISOR
        MOV     DX,LCR[SI]	; LINE CONTROL REGISTER
        MOV     AL,80H          ; HI BIT ON
        OUT     DX,AL           ; SET DLAB = 1
	JMP	$+2		; I/O DELAY FOR JR
        MOV     DX,WORD PTR DLL[SI]	; LEAST SIGNIFICANT BYTE
        MOV     AL,BL		; LSB FROM TABLE
        OUT     DX,AL           ; SET LSB ON 8250
	JMP	$+2		; I/O DELAY FOR JR
        MOV     DX,WORD PTR DLH[SI]	; MOST SIGNIFICANT BYTE
        MOV     AL,BH		; MSB FROM TABLE
        OUT     DX,AL           ; SET MSB ON 8250
	JMP	$+2		; I/O DELAY FOR JR

; SET PARITY AND NUMBER OF STOP BITS
	MOV	AL,03H		; NONE OR SPACE PARITY IS THE DEFAULT
	CMP	PARITY[SI],'O'	; ODD PARITY REQUESTED?
	JNE	P1		; JUMP IF NOT
	MOV	AL,0AH		; SELECT ODD PARITY
	JMP	SHORT P3	; CONTINUE
P1:	CMP	PARITY[SI],'E'	; EVEN PARITY REQUESTED?
	JNE	P2		; JUMP IF NOT
	MOV	AL,1AH		; SELECT EVEN PARITY
	JMP	SHORT P3	; CONTINUE
P2:	CMP	PARITY[SI],'M'	; MARK PARITY REQUESTED?
	JNE	P3		; JUMP IF NOT
	MOV	AL,2AH		; SELECT MARK PARITY
P3:	TEST	STOP_BITS[SI],2	; 2 STOP BITS REQUESTED?
	JZ	STOP1		; NO
	OR	AL,4		; YES
STOP1:	MOV     DX,LCR[SI]	; LINE CONTROL REGISTER
        OUT     DX,AL           ; SET 8250 PARITY MODE AND DLAB=0

; ENABLE INTERRUPTS ON 8259 AND 8250
        IN      AL,INTA01	; SET ENABLE BIT ON 8259
        AND     AL,NIRQ[SI]
        OUT     INTA01,AL
        MOV     DX,IER[SI]	; ENABLE INTERRUPTS ON 8250
        MOV     AL,5		; RECEIVE & LINE ERROR
        OUT     DX,AL
	JMP	$+2		; I/O DELAY FOR JR
        MOV     DX,MCR[SI]	; SET DTR AND ENABLE INT DRIVER
        MOV     AL,0BH
        OUT     DX,AL

OCX:	STI			; INTERRUPTS ON
	pop si
	mov sp,bp
	pop bp
	RET			; DONE
_open_com	ENDP
	PAGE
;
; CLOSE_COM - TURNS OFF INTERRUPTS FROM THE COMMUNICATIONS PORT
;
_close_com	PROC FAR
	push bp
	mov bp,sp
	push si
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1	; PORT INSTALLED?
	JZ	CCX		; ABORT IF NOT

; TURN OFF 8250
        MOV     DX,IER[SI]
        MOV     AL,0
        OUT     DX,AL

; TURN OFF 8259
        MOV     DX,INTA01
        IN      AL,DX
        OR      AL,IRQ[SI]
	JMP	$+2		; DELAY FOR AT
        OUT     DX,AL

CCX:	pop si
	mov sp,bp
	pop bp
	RET
_close_com	ENDP
        PAGE
;
; DTR_OFF - TURNS OFF DTR TO TELL MODEMS THAT THE TERMINAL HAS GONE AWAY
;           AND TO HANG UP THE PHONE
;
_dtr_off	PROC FAR
	push bp
	mov bp,sp
	push si
	PUSHF			; SAVE FLAGS
	PUSH	AX		; SAVE REGS
	PUSH	DX
	PUSH	SI
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1	; PORT INSTALLED?
	JZ	DFX		; ABORT IF NOT

        MOV     DX,MCR[SI]
        MOV     AL,08H		; DTR OFF, RTS OFF, OUT2 ON
        OUT     DX,AL
DFX:	POP	SI		; RECOVER REGS
	POP	DX
	POP	AX
	POPF			; RECOVER FLAGS
	pop si
	mov sp,bp
	pop bp
	RET
_dtr_off	ENDP
;
; DTR_ON - TURNS DTR ON
;
_dtr_on	PROC FAR
	push bp
	mov bp,sp
	push si
	PUSHF			; SAVE FLAGS
	PUSH	AX		; SAVE REGS
	PUSH	DX
	PUSH	SI
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1	; PORT INSTALLED?
	JZ	DNX		; ABORT IF NOT

        MOV     DX,MCR[SI]
        MOV     AL,0BH
        OUT     DX,AL
DNX:	POP	SI		; RECOVER REGS
	POP	DX
	POP	AX
	POPF			; RECOVER FLAGS
	pop si
	mov sp,bp
	pop bp
	RET			; DONE
_dtr_on	ENDP
        PAGE
;
; R_COUNT - RETURNS NUMBER OF BYTES IN THE RECEIVE BUFFER IN AX
;             total in DX
;
_r_count	PROC FAR
	push bp
	mov bp,sp
	push si
	PUSHF			; SAVE FLAGS
	PUSH	SI		; SAVE SI
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	MOV	AX,0		; NOTHING RECEIVED IF NOT INSTALLED
	mov dx,R_SIZE

	TEST	INSTALLED[SI],1	; PORT INSTALLED?
	JZ	RCX		; ABORT IF NOT

        MOV     AX,SIZE_RDATA[SI] ; GET NUMBER OF BYTES USED
RCX:	POP	SI		; RESTORE SI
	POPF			; RESTORE FLAGS
	pop si
	mov sp,bp
	pop bp
	RET
_r_count	ENDP
	PAGE
;
; RECEIVE - RETURNS THE NEXT CHARACTER FROM THE RECEIVE BUFFER IN AL
;            AND REMOVES IT FROM THE BUFFER
;            THE PARITY BIT IS STRIPPED OFF
;
_receive_com	PROC FAR
	push bp
	mov bp,sp
	push si
	PUSHF				; SAVE FLAGS
	PUSH	BX			; SAVE REGS
	PUSH	SI
	MOV	SI,CURRENT_AREA		; SI POINTS TO DATA AREA
	mov	ax,-1 ; -1 if bad call
	TEST	INSTALLED[SI],1		; PORT INSTALLED?
	JZ	RCVX			; ABORT IF NOT
	CMP	SIZE_RDATA[SI],0	; ANY CHARACTERS?
	JE	RCVX			; ABORT IF NOT

; GOOD CALL
	mov ah,0	; good call
        MOV     BX,START_RDATA[SI]	; GET POINTER TO OLDEST CHAR
        MOV     AL,RDATA[SI][BX]	; GET CHAR FROM BUFFER
; MOD BY LBA, 10/6/85 FOR PROPER SUPPORT OF NO PARITY COMMUNICATIONS
	CMP	PARITY[SI],'N'		; ARE WE RUNNING WITH NO PARITY?
	JE	L11			; IF SO, DON'T STRIP HIGH BIT
; END OF MOD
	AND	AL,7FH			; STRIP PARITY BIT
L11:	INC     BX              	; BUMP START_RDATA
        CMP     BX,R_SIZE		; SEE IF PAST END
        JB      L12             	; IF NOT THEN SKIP
        MOV	BX,0			; ADJUST TO BEGINNING
L12:    MOV     START_RDATA[SI],BX	; SAVE THE NEW START_RDATA VALUE
        DEC     SIZE_RDATA[SI]		; ONE LESS CHARACTER
	CMP	XON_XOFF[SI],'E'	; FLOW CONTROL ENABLED?
	JNE	RCVX			; DO NOTHING IF DISABLED
	CMP	HOST_OFF[SI],1		; HOST TURNED OFF?
	JNE	RCVX			; JUMP IF NOT
	CMP	SIZE_RDATA[SI],R_SIZE/20 ; RECEIVE BUFFER NEARLY EMPTY?
	JGE	RCVX			; DONE IF NOT
	MOV	HOST_OFF[SI],0		; TURN ON HOST IF SO
	PUSH	AX			; SAVE RECEIVED CHAR
	MOV	AL,CONTROL_Q		; TELL HIM TO TALK
	CLI				; TURN OFF INTERRUPTS
	CALL	SENDII			; SEND IMMEDIATELY INTERNAL
	STI				; INTERRUPTS BACK ON
	POP	AX			; RESTORE RECEIVED CHAR
RCVX:	POP	SI			; RECOVER REGS
	POP	BX
	POPF				; RECOVER FLAGS
	pop si
	mov sp,bp
	pop bp
	RET				; DONE
_receive_com	ENDP
        PAGE
;
; S_COUNT - RETURNS IN AX THE AMOUNT OF FREE SPACE
;              REMAINING IN THE TRANSMIT BUFFER
;	 DX total size
;
_s_count	PROC FAR
	push bp
	mov bp,sp
	push si
	PUSHF			; SAVE FLAGS
	PUSH	SI		; SAVE SI
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	MOV	AX,0		; NO SPACE LEFT IF NOT INSTALLED
	mov dx,S_SIZE

	TEST	INSTALLED[SI],1	; PORT INSTALLED?
	JZ	SCX		; ABORT IF NOT

        MOV     AX,S_SIZE	; GET THE SIZE OF THE X-MIT BUFFER
        SUB     AX,SIZE_TDATA[SI] ; SUBTRACT THE NUMBER OF BYTES USED
SCX:	POP	SI		; RECOVER SI
	POPF			; RESTORE FLAGS
	pop si
	mov sp,bp
	pop bp
	RET
_s_count	ENDP
        PAGE
;
; SEND - SEND A CHARACTER
;	[bp+6] = char
;
_send_com	PROC FAR
	push bp
	mov bp,sp
	push si
	mov al,[bp+6]
	PUSHF				; SAVE FLAGS
	PUSH	AX			; SAVE REGS
	PUSH	BX
	PUSH	DX
	PUSH	SI
	MOV	SI,CURRENT_AREA		; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1		; PORT INSTALLED?
	JZ	L44			; ABORT IF NOT

	CMP	SIZE_TDATA[SI],S_SIZE	; BUFFER FULL?
	JL	L4A			; JUMP IF NOT
	INC	WORD PTR EOVFLOW[SI]	; BUMP ERROR COUNT
	JMP	SHORT L44		; PUNT
L4A:	MOV     BX,END_TDATA[SI]	; BX POINTS TO FREE SPACE
        MOV     TDATA[SI][BX],AL	; MOVE CHAR TO BUFFER
        INC     BX              	; INCREMENT END_TDATA
        CMP     BX,S_SIZE		; SEE IF PAST END
        JL      L4              	; IF NOT THEN SKIP
	MOV	BX,0			; ADJUST TO BEGINNING
L4:     MOV     END_TDATA[SI],BX	; SAVE NEW END_TDATA
        INC     SIZE_TDATA[SI]		; ONE MORE CHARACTER IN X-MIT BUFFER
	MOV     DX,IER[SI]		; INTERRUPT ENABLE REGISTER
        IN      AL,DX			; GET IT
	TEST	AL,2			; SEE IF TX INTERRUPTS ARE ENABLED
        JNZ     L44			; JUMP IF SO
        MOV     AL,7			; IF NOT THEN RCV, TX, LINE ERROR
        OUT     DX,AL			; ARE ENABLED
L44:	POP	SI			; RESTORE REGS
	POP	DX
	POP	BX
	POP	AX
	POPF				; RESTORE FLAGS
	pop si
	mov sp,bp
	pop bp
	RET				; DONE
_send_com	ENDP
        PAGE
;
; SENDI - SEND A CHARACTER IMMEDIATELY
; [bp+6] = char to send
;
_sendi_com	PROC FAR
	push bp
	mov bp,sp
	push si
	mov al,[bp+6]
	PUSHF				; SAVE FLAGS
	PUSH	AX			; SAVE REGS
	PUSH	BX
	PUSH	DX
	PUSH	SI
	MOV	SI,CURRENT_AREA		; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1		; PORT INSTALLED?
	JZ	LQ44			; ABORT IF NOT

	CLI				; MASK INTERRUPTS
	CALL	SENDII			; CALL INTERNAL SEND IMMEDIATE
	STI				; INTERRRUPTS BACK ON

LQ44:	POP	SI			; RESTORE REGS
	POP	DX
	POP	BX
	POP	AX
	POPF				; RESTORE FLAGS
	pop si
	mov sp,bp
	pop bp
	RET				; DONE
_sendi_com	ENDP
        PAGE
;
; INTERNAL ROUTINE
; DEPENDS ON CALLER TO KEEP INTERRUPTS CLEARED AND SET SI
; SENDI - SEND A CHARACTER IMMEDIATELY (PUT AT BEGINNING OF QUEUE)
; AL = CHAR TO WRITE
;
SENDII	PROC    NEAR
	PUSH	DX			; SAVE DX
	CMP	SIZE_TDATA[SI],S_SIZE	; BUFFER FULL?
	JB	LI4A			; JUMP IF NOT
	INC	WORD PTR EOVFLOW[SI]	; BUMP ERROR COUNT
	MOV	BX,START_TDATA[SI]	; BX POINTS TO FIRST CHAR IN BUFFER
	MOV     TDATA[SI][BX],AL 	; CLOBBER FIRST CHAR IN BUFFER
	JMP	SHORT LI4B		; CONTINUE
LI4A:	MOV	BX,START_TDATA[SI]	; BX POINTS TO FIRST CHAR IN BUFFER
	DEC	BX			; BACKUP THE PTR
	CMP	BX,-1			; BEFORE BEGINNING?
	JNE	LI4			; JUMP IF NOT
	MOV	BX,S_SIZE-1		; POINT TO END IF SO
LI4:	MOV     TDATA[SI][BX],AL 	; MOVE CHAR TO BUFFER
	MOV     START_TDATA[SI],BX	; SAVE NEW START_TDATA
	INC     SIZE_TDATA[SI]		; ONE MORE CHARACTER IN X-MIT BUFFER
LI4B:	MOV     DX,IER[SI]		; INTERRUPT ENABLE REGISTER
        IN      AL,DX			; GET IT
	TEST	AL,2			; SEE IF TX INTERRUPTS ARE ENABLED
        JNZ     LI44			; JUMP IF SO
        MOV     AL,7			; IF NOT THEN RCV, TX, LINE ERROR
        OUT     DX,AL			; ARE ENABLED
LI44:	POP	DX			; RECOVER DX
	RET				; DONE
SENDII	ENDP
	PAGE
;
; S_LOCAL
;
_send_local	PROC FAR
	push bp
	mov bp,sp
	push si
	mov al,[bp+6]
	PUSHF				; SAVE FLAGS
	PUSH	AX			; SAVE REGS
	PUSH	BX
	PUSH	SI
	MOV	SI,CURRENT_AREA		; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1		; PORT INSTALLED?
	JZ	SLX			; ABORT IF NOT

        CLI				; INTERRUPTS OFF
        CMP     SIZE_RDATA[SI],R_SIZE	; SEE IF ANY ROOM
	JB	L13A			; SKIP IF ROOM
	INC	WORD PTR EOVFLOW[SI]	; BUMP OVERFLOW COUNT
	JMP	SHORT L14		; PUNT
L13A:	MOV     BX,END_RDATA[SI]	; BX POINTS TO FREE SPACE
        MOV     RDATA[SI][BX],AL	; SEND DATA TO BUFFER
        INC     BX             		; INCREMENT END_RDATA POINTER
        CMP     BX,R_SIZE		; SEE IF GONE PAST END
        JL      L13             	; IF NOT THEN SKIP
        MOV	BX,0			; ELSE ADJUST TO BEGINNING
L13:    MOV     END_RDATA[SI],BX 	; SAVE VALUE
        INC     SIZE_RDATA[SI]		; GOT ONE MORE CHARACTER
L14:    STI				; INTERRUPTS BACK ON

SLX:	POP	SI			; RECOVER REGS
	POP	BX
	POP	AX
	POPF				; RECOVER FLAGS
	pop si
	mov sp,bp
	pop bp
	RET				; DONE
_send_local	ENDP
        PAGE
;
; BREAK - CAUSES A BREAK TO BE SENT OUT ON THE LINE
;
_break_com	PROC FAR
	push bp
	mov bp,sp
	push si
	PUSHF			; SAVE FLAGS
	PUSH	AX		; SAVE REGS
	PUSH	CX
	PUSH	DX
	MOV	SI,CURRENT_AREA	; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1	; PORT INSTALLED?
	JZ	BRX		; ABORT IF NOT

	MOV	DX,LCR[SI]	; LINE CONTROL REGISTER
	IN	AL,DX		; GET CURRENT SETTING
	JMP	$+2		; I/O DELAY FOR JR
	OR	AL,40H		; TURN ON BREAK BIT
	OUT	DX,AL		; SET IT ON THE 8250
	MOV	CX,0C000H	; WAIT APPROX. 1/4 SEC.
BREAK1:	LOOP	BREAK1		; BUSY WAIT
	AND	AL,0BFH		; TURN OFF BREAK BIT
	OUT	DX,AL		; RESTORE LINE CONTROL REGISTER
BRX:	POP	DX		; RECOVER REGS
	POP	CX
	POP	AX
	POPF			; RECOVER FLAGS
	pop si
	mov sp,bp
	pop bp
	RET			; DONE
_break_com	ENDP
	PAGE
;
; COM_ERRORS - RETURN POINTER IN dx:ax TO ERROR COUNTS
;
_com_errors	PROC FAR
	push bp
	mov bp,sp
	mov ax,OFFSET DGROUP:CURRENT_AREA
	add ax,ERROR_BLOCK
	mov dx,ds
	mov sp,bp
	pop bp
	RET			; DONE
_com_errors	ENDP
        PAGE
;
; INTERNAL ROUTINE
; BUMP ERROR COUNTS FROM LINE STATUS IN AL
;
E_BUMP	PROC	NEAR
	TEST	AL,2		; OVERRUN ERROR?
	JZ	LSI1		; JUMP IF NOT
	INC	WORD PTR EOVRUN[SI]	; ELSE BUMP ERROR COUNT
LSI1:	TEST	AL,4		; PARITY ERROR?
	JZ	LSI2		; JUMP IF NOT
	INC	WORD PTR EPARITY[SI]	; ELSE BUMP ERROR COUNT
LSI2:	TEST	AL,8		; FRAMING ERROR?
	JZ	LSI3		; JUMP IF NOT
	INC	WORD PTR EFRAME[SI]	; ELSE BUMP ERROR COUNT
LSI3:	TEST	AL,16		; BREAK RECEIVED?
	JZ	LSI4		; JUMP IF NOT
	INC	WORD PTR EBREAK[SI]	; ELSE BUMP ERROR COUNT
LSI4:	RET			; DONE
E_BUMP	ENDP
	PAGE
;
; INTERNAL ROUTINE
; MODEM SEND PROTOCOL
;
M_PROTOCOL PROC	NEAR
        CMP     CONNECTION[SI],'M' ; MODEM CONNECTION?
        JNE     S3		; IF NOT, SKIP DSR & CTS PROTOCOL

; TELL MODEM WE'RE READY TO SEND
        MOV     DX,MCR[SI]	; MODEM CONTROL REGISTER
        MOV     AL,00001011B	; OUT 2, RTS, DTR
        OUT     DX,AL           ; TERMINAL READY, REQUEST TO SEND
	JMP	$+2		; I/O DELAY FOR JR

; WAIT UNTIL MODEM SAYS DATA SET READY
	MOV     CX,1000		; TIMEOUT COUNT
        MOV     DX,MSR[SI]	; MODEM STATUS REGISTER
S1:     IN      AL,DX           ; GET MODEM STATUS
        TEST    AL,20H          ; DATA SET READY?
        JNZ     S1X		; YES, TEST CLEAR TO SEND
        LOOP    S1              ; NO, BUSY WAIT
        INC	WORD PTR EDSR[SI]	; BUMP ERROR COUNT
	JMP	SHORT S3	; WE TIMED OUT
S1X:
; WAIT UNTIL MODEM SAYS IT'S CLEAR TO SEND
	MOV	CX,1000		; TIMEOUT COUNT
S2:	IN      AL,DX           ; GET MODEM STATUS
        TEST    AL,10H          ; CLEAR TO SEND?
        JNZ     S2X		; YES
        LOOP    S2		; NO, KEEP TRYING
        INC	WORD PTR ECTS[SI]	; BUMP ERROR COUNT - WE TIMED OUT
S2X:
; TEST FOR TRANSMITTER READY
S3:	MOV     DX,LSR[SI]	; LINE STATUS REGISTER
	IN      AL,DX           ; GET LINE STATUS
        TEST    AL,20H          ; TRANSMITTER READY?
        JNZ     S4		; SKIP IF SO
	INC	WORD PTR EXMIT[SI]	; ELSE BUMP ERROR COUNT
S4:	RET			; DONE
M_PROTOCOL ENDP
	PAGE
;
; INTERNAL ROUTINES FOR FLOW CONTROL
;
; FLOW_IN - RESPOND TO FLOW CONTROL COMMANDS FROM HOST
; FLOW_OUT - ISSUE FLOW CONTROL COMMANDS TO HOST
;
FLOW_IN	PROC	NEAR
	PUSH	AX		; SAVE CHAR
	CMP	XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
	JNE	FI_2		; DO NOTHING IF DISABLED
	AND	AL,7FH		; STRIP PARITY
	CMP	AL,CONTROL_S	; STOP COMMAND RECEIVED?
	JNE	FI_1		; JUMP IF NOT
	MOV	PC_OFF[SI],1	; WE MUST SHUT UP
	JMP	SHORT FI_2	; CONTINUE
FI_1:	CMP	AL,CONTROL_Q	; GO COMMAND RECEIVED?
	JNE	FI_2		; NO, MUST BE NORMAL CHAR
	MOV	PC_OFF[SI],0	; WE START TALKING AGAIN
FI_2:	POP	AX		; RESTORE CHAR
	RET			; DONE
FLOW_IN	ENDP
;
FLOW_OUT PROC	NEAR
	CMP	XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
	JNE	FO_X		; DO NOTHING IF DISABLED
	CMP	HOST_OFF[SI],1	; HOST TURNED OFF?
	JE	FO_X		; JUMP IF SO
	CMP	SIZE_RDATA[SI],R_SIZE/2	; RECEIVE BUFFER NEARLY FULL?
	JLE	FO_X		; DONE IF NOT
	MOV	AL,CONTROL_S	; TURN OFF HOST IF SO
	CALL	SENDII		; SEND IMMEDIATELY INTERNAL
	MOV	HOST_OFF[SI],1	; HOST IS NOW OFF
FO_X:	RET			; DONE
FLOW_OUT ENDP
        PAGE
;
; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
;
INT_HNDLR1 PROC  FAR
	PUSH	SI		; SAVE SI
	MOV	SI,OFFSET AREA1	; DATA AREA FOR COM1:
	JMP	SHORT INT_COMMON ; CONTINUE
;
; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
;
INT_HNDLR2 PROC  FAR
	PUSH	SI		; SAVE SI
	MOV	SI,OFFSET AREA2	; DATA AREA FOR COM2:
;
; BODY OF INTERRUPT HANDLER
;
INT_COMMON:
	PUSH	AX		; SAVE REGS
	PUSH	BX
	PUSH	CX
	PUSH	DX
	PUSH	BP
	PUSH	DI
	PUSH	DS
	PUSH	ES

	MOV	AX,SEG _DATA		; OUR DATA SEG
	MOV	DS,AX		; TO DS

; CLEAR THE INTERRUPT CONTROLLER FLAG
	MOV	DX,INTA00	; 8259 CONTROL PORT
	MOV	AL,EOI[SI]	; SPECIFIC END OF INTERRUPT
	OUT	DX,AL		; CLEAR FLAG

; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
REPOLL:
        MOV     DX,IIR[SI]	; READ INTERRUPT STATUS REGISTER
        IN      AL,DX
        CMP     AL,4
        JE	RX_INT		; IF FROM THE RECEIVER
	CMP     AL,2
        JE      TX_INT          ; IF FROM THE TRANSMITTER
        CMP     AL,6
        JE	LSTAT_INT       ; INTERRUPT BECAUSE OF LINE STATUS
        CMP     AL,0
        JE	MSTAT_INT       ; INTERRUPT BECAUSE OF MODEM STATUS
        JMP     FAR PTR INT_END	; DONE, EXIT (DON'T FIX FAR PTR STUFF)

LSTAT_INT:
        MOV     DX,LSR[SI]	; READ AND IGNORE LINE STATUS
        IN      AL,DX		;
	CALL	E_BUMP		; JUST BUMP ERROR COUNTS
	JMP     REPOLL          ; SEE IF ANY MORE INTERRUPTS

MSTAT_INT:
        MOV     DX,MSR[SI]	; READ AND IGNORE MODEM STATUS
        IN      AL,DX		;
        JMP     REPOLL          ; SEE IF ANY MORE INTERRUPTS

TX_INT:
	CMP	PC_OFF[SI],1	; HAVE WE BEEN TOLD TO SHUT UP?
	JNE	GOODTX1		; JUMP IF NOT
	CMP	HOST_OFF[SI],1	; HAS HOST ALSO SHUT UP?
	JNE	SEND_NO_MORE	; JUMP IF NOT

; CLEAR XON/XOFF DEADLOCK
	MOV	PC_OFF[SI],0	; WE SPEAK
	MOV	HOST_OFF[SI],0	; THEY REPLY
	MOV	AL,CONTROL_Q	; BUT ONLY WHEN
	CALL	SENDII		; WE LET THEM

GOODTX1:
	CMP     SIZE_TDATA[SI],0 ; SEE IF ANY MORE DATA TO SEND
	JG	HAVE_DATA       ; IF POSITIVE THEN THERE IS DATA TO SEND

; IF NO DATA TO SEND THEN RESET TX INTERRUPT AND RETURN
SEND_NO_MORE:
        MOV     DX,IER[SI]		;
        MOV     AL,5			; JUST RCV AND LINE ERROR
        OUT     DX,AL			; ARE SET
        JMP     REPOLL			;

HAVE_DATA:
	CALL	M_PROTOCOL		; DO MODEM PROTOCOL IF NECESSARY

        MOV     BX,START_TDATA[SI]	; BX POINTS TO NEXT CHAR. TO BE SENT
        MOV     AL,TDATA[SI][BX]	; GET DATA FROM BUFFER
        MOV     DX,DATREG[SI]		; DX EQUALS PORT TO SEND DATA TO
        OUT     DX,AL           	; SEND DATA
        INC     BX              	; INCREMENT START_TDATA
        CMP     BX,S_SIZE		; SEE IF GONE PAST END
        JB      NTADJ           	; IF NOT THEN SKIP
	MOV	BX,0			; RESET TO BEGINNING
NTADJ:  MOV     START_TDATA[SI],BX	; SAVE START_TDATA
        DEC     SIZE_TDATA[SI]		; ONE LESS CHARACTER IN X-MIT BUFFER
        JMP     REPOLL

RX_INT:
        MOV     DX,DATREG[SI]		; 8250 DATA REGISTER
        IN      AL,DX			; GET DATA
	CALL	FLOW_IN			; RESPOND TO F.C. COMMANDS FROM HOST
        CMP     SIZE_RDATA[SI],R_SIZE	; SEE IF ANY ROOM
        JL	GOOD_RX1		; CONTINUE IF SO
	INC	WORD PTR EOVFLOW[SI]	; BUMP OVERFLOW ERROR COUNT
	JMP	REPOLL			; PUNT
GOOD_RX1:
        MOV     BX,END_RDATA[SI]	; BX POINTS TO FREE SPACE
        MOV     RDATA[SI][BX],AL	; MOVE DATA TO BUFFER
        INC	SIZE_RDATA[SI]		; GOT ONE MORE CHARACTER
        INC     BX              	; INCREMENT END_RDATA POINTER
        CMP     BX,R_SIZE		; SEE IF GONE PAST END
	JB	NRADJ           	; IF NOT THEN SKIP
        MOV     BX,0			; ELSE ADJUST TO BEGINNING
NRADJ:  MOV     END_RDATA[SI],BX	; SAVE VALUE
	CALL	FLOW_OUT		; ISSUE FLOW CONTROL COMMANDS TO HOST
	JMP	REPOLL			; 

INT_END:
	POP	ES		; RESTORE REGS
	POP	DS
	POP	DI
	POP	BP
        POP     DX
        POP     CX
        POP     BX
        POP     AX

	POP	SI		; RESTORE SI, TOO
        IRET
INT_HNDLR2 ENDP
INT_HNDLR1 ENDP
COM_TEXT	ENDS
        END
@@@ Finished comm.asm
echo dcpasm.asm
cat >dcpasm.asm <<'@@@ Finished dcpasm.asm'
; Support rotuines for DCP a uucp clone. 
; Copyright Richard H. Lamb, 1985,1986,1987
; dos dir scan for a file
;""""""""""""""""""""""""""""""
_text 	segment	byte	public	'code'
_text	ends
_data	segment	byte	public	'data'
_data	ends
const	segment	byte	public	'const'
const	ends
_bbs	segment	byte	public	'bbs'
_bbs	ends
dgroup	group	const,_bbs,_data
	assume	cs:_text,ds:dgroup,ss:dgroup,es:dgroup
_text	SEGMENT
	public	_dir_open
_dir_open	proc	near 
;_dir_open:
	push	bp
	mov	bp,sp
	push	ds
	push	dx
	push	cx
; set DTA
	mov	dx,word ptr [bp+6]
	mov	ah,01ah
	int	21h
; find first file
	mov	dx,word ptr [bp+4]
	mov	ah,04eh
	mov	cx,010h
	int	21h
; return 0=found 
	sub	ah,ah
	pop	cx
	pop	dx
	pop	ds
	pop	bp
	ret
_dir_open	endp
;*******************************
_text	ends
	end
@@@ Finished dcpasm.asm
echo call.bat
cat >call.bat <<'@@@ Finished call.bat'
dcp master 3
@@@ Finished call.bat
echo makeexe.bat
cat >makeexe.bat <<'@@@ Finished makeexe.bat'
link dcp+dcpstart+dcpscan+dcpsys+dcprec+dcpsend+dcpgpkt+dcprpkt+dcptpkt+dcpkpkt+dcpio+dcxqt+dcpvms+comm+dcpasm;
@@@ Finished makeexe.bat
echo makeobj.bat
cat >makeobj.bat <<'@@@ Finished makeobj.bat'
msc dcp;
msc dcpsys;
msc dcpstart;
msc -Ze dcpio;
msc -Ze dcpscan;
msc dcpsend;
msc dcprec;
msc dcpgpkt;
msc dcprpkt;
msc dcptpkt;
msc dcpkpkt;
msc -Ze dcxqt;
msc dcpvms;
masm comm;
masm dcpasm;
msc rmail;
link rmail;
@@@ Finished makeobj.bat
echo call.cli
cat >call.cli <<'@@@ Finished call.cli'
xe dcp master 3
@@@ Finished call.cli
echo makeexe.cli
cat >makeexe.cli <<'@@@ Finished makeexe.cli'
ccl dcp,dcpsys,dcpstart,dcpscan,dcprec,dcpsend,dcpgpkt,dcptpkt,dcpio,dcprpkt, &
dcpkpkt,dcxqt,dcpvms
@@@ Finished makeexe.cli
echo makeobj.cli
cat >makeobj.cli <<'@@@ Finished makeobj.cli'
cc dcp
cc dcpsys
cc dcpstart
cc dcpscan
cc dcprec
cc dcpsend
cc dcpgpkt
cc dcptpkt
cc dcpio
cc dcxqt
cc dcprpkt
cc dcpkpkt
cc dcpvms
cc rmail
ccl rmail
@@@ Finished makeobj.cli
echo clink.vms
cat >clink.vms <<'@@@ Finished clink.vms'
$	link 'p1,sys$library:crtlib/lib
@@@ Finished clink.vms
echo makeexe.vms
cat >makeexe.vms <<'@@@ Finished makeexe.vms'
$ clink dcp,dcpstart,dcpsys,dcpscan,dcpsend,dcprec,dcpgpkt,dcptpkt,dcprpkt,dcpkpkt,dcpio,dcxqt,dcpvms

@@@ Finished makeexe.vms
echo makeobj.vms
cat >makeobj.vms <<'@@@ Finished makeobj.vms'
$ cc dcp
$ cc dcpstart
$ cc dcpsys
$ cc dcpscan
$ cc dcpsend
$ cc dcprec
$ cc dcpgpkt
$ cc dcptpkt
$ cc dcprpkt
$ cc dcpkpkt
$ cc dcpio
$ cc dcxqt
$ cc dcpvms
$ cc rmail
$ clink rmail
@@@ Finished makeobj.vms
echo setup.vms
cat >setup.vms <<'@@@ Finished setup.vms'
$ rmail :== $sys$user:[lids.lamb.c.dcp2]rmail
$ dcp :== $sys$user:[lids.lamb.c.dcp2]dcp
$ ss :== $sys$user:[lids.lamb.c.dcp2]spawn
@@@ Finished setup.vms
exit 0
End of Listing