[comp.sources.misc] uupc.dos.8.7

Stuart.Lynne@van-bc.UUCP (Stuart Lynne) (08/17/87)

>From uucp Wed Aug 12 02:39 PDT 1987
>From slynne  Wed Aug 12 02:38:30 1987 remote from slmac
Received: by van-bc.uucp (smail2.3)
	id AA17570; 12 Aug 87 02:38:30 PDT (Wed)
Received: by slmac.vnet.van-bc.uucp (pcmail) Wed Aug 12 02:37:07 1987
Date: Wed Aug 12 02:37:07 1987
From: Stuart Lynne - test a mac <slynne@slmac.vnet.van-bc.uucp>
Message-ID: <148@slmac.vnet.van-bc.uucp>
To: sl@van-bc
Subject: shar/uupc.dos.8.7

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	dos/README.DOS
#	dos/Makefile.dos
#	dos/comm.asm
#	dos/comm.h
#	dos/host.c
#	dos/host.h
#	dos/mlib.c
#	dos/ndir.c
#	dos/ndir.h
#	dos/setup.bat
#	dos/ulib.c
# This archive created: Wed Aug 12 02:03:59 1987
# By:	Stuart Lynne - test a mac ()
export PATH; PATH=/bin:$PATH
if test -f 'dos/README.DOS'
then
       echo shar: will not over-write existing file "'dos/README.DOS'"
else
cat << \SHAR_EOF > 'dos/README.DOS'
DOS                   August 3, 1987                   Samuel Lam


This file describes the IBM-PC/DOS support for uupc.

After unpacking this shell-archive, you will have a set of files
in the subdirectory "dos".  The eventual destinations of these
files and description of their content are shown below.  (The
current directory is assumed to be the uupc source directory.)

Makefile - Makefile for the complete uupc project.  This makefile
   should be used with NDMAKE 4.0 and Microsoft C 4.0.

local\host.h - MS-DOS host header file.
local\host.c - Generic main program and routines used by both.
local\mlib.c - Routines used only by the uu program.
local\ulib.c - Routines used only by the mail program.
local\ndir.h - Directory scanning routines header file.
local\ndir.c - "Berkeley-style" directory scanning routines.

Setup.Bat - Template batch file for configuring your uupc node.
   This should be edited appropriately before use.


To build a production copy of uupc from the distributed sources.
You will have to unpacking the two shell-archives containing the
sources for uu and mail into an empty work directory, create a
new subdirectory named "local" in this work directory, install
the content of the "dos" directory as described above, and then
issue a "make all" from within the work directory.

This, of course, assume that you have both Microsoft C 4.0 and
NDMAKE 4.0 (shareware by D. G. Kneller) installed on your
machine.  Note that the "make" that was bundled with Microsoft C
is not an acceptable substitute for NDMAKE in this case.  (The
makefile formats are not compatible between the two.)

This implementation of uupc has been tested on a regular IBM-PC
running PC-DOS 2.10.  It should have no problem running with
newer versions of PC-DOS or MS-DOS.

Both uu and mail will run within 64K of free memeory and/or on a
single floppy-drive system.  Although performance could be
significantly improved by using a harddisk and/or RAMdisk for the
data directories, the throughput on a minimaly configured system
is still fairly acceptable.

Although mail will work on basically any MS-DOS machine, uu will
only run on systems with an IBM-PC compatible serial port (i.e.
it must be compatible at the UART level) since uu drives the
serial port directly using its own interrupt driven I/O routines
when it talks to the remote system.

Currently, the mailboxes used by mail are being managed as binary
files, with line-feed instead of carriage-return and line-feed
being the line separator.  Therefore, MS-DOS text file copies of
incoming messages can only be obtained through the s (save) and w
(write) commands in mail.

If you would like a copy of your mailbox to always be accessible
from your favorite text-editor in DOS, you might want to use the
s (save) command to archive all incoming messages to a text
archive file as soon as they arrive in your mailbox.

Pre-composed MS-DOS text files can be sent as messages without
any problems by simply using DOS' command line I/O redirection
facilities.  e.g. mail user@host < textfile

When typing a message directly into mail through the keyboard, a
Control-Z (the MS-DOS end-of-file character) should be used to
generate an end-of-file to terminate the message input.

Since the MS-DOS file system (unlike UNIX) does not differentiate
between upper and lower cases file names, currently the system
names of all the systems which you have a direct connection to
must be in lowercase.  i.e. All system names in the "systems"
file must be in all lowercase.  This restriction does not apply
to systems which are more than one node away from your system.

The port specification in a systems file entry should be either
COM1 or COM2, which represents the serial ports at the port
addresses 0x3f8 and 0x2f8 respectively.  Cases are significant in
port specifications.  The line speed specification in the systems
file entry can specify any common baud rate up to 19200 bps.


For IBM-PC/DOS related uupc information, bug fixes, comments and
suggestions, please e-mail to:

UUCP: {seismo,ihnp4!alberta,uw-beaver}!ubc-vision!van-bc!sklpc!skl
Internet: <skl@sklpc.vnet.van-bc.UUCP>
-------

SHAR_EOF
chmod +x 'dos/README.DOS'
fi # end of overwriting check
if test -f 'dos/Makefile.dos'
then
       echo shar: will not over-write existing file "'dos/Makefile.dos'"
else
cat << \SHAR_EOF > 'dos/Makefile.dos'
# Makefile for DCP by SKL, July/87

all: uupc mail


#   The UUCP transport service program (an uucico work-alike)

UUOBJS=uuhost.obj dcp.obj dcpsys.obj dcpxfer.obj dcpgpkt.obj rmail.obj\
   ulib.obj lib.obj comm.obj local\ndir.obj

uupc: uupc.exe

uupc.exe: $(UUOBJS)
   link $(LFLAGS) /NOI /STACK:4096 $(UUOBJS),$@;

uuhost.obj: uuhost.c local\host.c host.h local\host.h
   msc $(CFLAGS) $*;

dcp.obj: dcp.c dcp.h host.h local\host.h
   msc $(CFLAGS) $*;

dcpsys.obj: dcpsys.c dcp.h host.h ndir.h local\host.h local\ndir.h
   msc $(CFLAGS) $*;

dcpxfer.obj: dcpxfer.c dcp.h host.h local\host.h
   msc $(CFLAGS) $*;

dcpgpkt.obj: dcpgpkt.c dcp.h host.h local\host.h
   msc $(CFLAGS) $*;

rmail.obj: rmail.c pcmail.c host.h local\host.h
   msc $(CFLAGS) $*;

ulib.obj: ulib.c local\ulib.c dcp.h comm.h
   msc $(CFLAGS) $*;

comm.obj: comm.asm
   masm /MX comm;

local\ndir.obj: local\ndir.c local\ndir.h
   msc $(CFLAGS) local\ndir.c,local\ndir.obj;


#   The mailer UA program (a mail work-alike)

MAILOBJS=mailhost.obj mail.obj lmail.obj mlib.obj lib.obj

mail: mail.exe

mail.exe: $(MAILOBJS)
   link /NOI /STACK:4096 $(LFLAGS) $(MAILOBJS),$@;

lmail.obj: lmail.c pcmail.c host.h local\host.h
   msc $(CFLAGS) $*;

mailhost.obj: mailhost.c local\host.c host.h local\host.h
   msc $(CFLAGS) $*;

mail.obj: mail.c host.h local\host.h
   msc $(CFLAGS) $*;

mlib.obj: mlib.c local\mlib.c
   msc $(CFLAGS) $*;


#   The common stuff

lib.obj: lib.c
   msc $(CFLAGS) $*;

SHAR_EOF
chmod +x 'dos/Makefile.dos'
fi # end of overwriting check
if test -f 'dos/comm.asm'
then
       echo shar: will not over-write existing file "'dos/comm.asm'"
else
cat << \SHAR_EOF > 'dos/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

SHAR_EOF
fi # end of overwriting check
if test -f 'dos/comm.h'
then
       echo shar: will not over-write existing file "'dos/comm.h'"
else
cat << \SHAR_EOF > 'dos/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 */

SHAR_EOF
fi # end of overwriting check
if test -f 'dos/host.c'
then
       echo shar: will not over-write existing file "'dos/host.c'"
else
cat << \SHAR_EOF > 'dos/host.c'
/*
   ibmpc/host.c
 
   IBM-PC host program
*/
 
#include <stdio.h>
#include <setjmp.h>
#include <errno.h>
#include <direct.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include <fcntl.h>

#include "host.h"

#define FILENAME "%s/%s"
 
char *curdir;

int debuglevel;   /* debuglevelging level */
 
jmp_buf	dcpexit;
 
void main(argc, argv)
int argc;
char *argv[];
{
 
   loadenv();

   curdir = getcwd(NULL, 80);
 
#ifdef CWDSPOOL
   chdir(spooldir);
#endif
 
   /* setup longjmp for error exit's */
   if (setjmp(dcpexit) == 0)
      MAIN(argc, argv);
 
#ifdef CWDSPOOL
   chdir(curdir);
#endif
 
} /*main*/
 
 
/*
   importpath - convert a canonical name to a format the host can handle

   Thise routines convert file name between canonical form, which is
   defined as a 'unix' style pathname, and the MS-DOS all uppercase
   "xxxxxxxx.xxx" format. 

   Mung the canonical file name as follows:
     1 - skip any path from the canonical name
     2 - copy up to 8 character from the canonical name converting . to _
         and uppercase to lowercase.
     3 - if the name was longer than 8 character copy a . to the host name
         and then copy the up to three characters from the tail of the
         canonical name to the host name.
*/

#define min(x,y) (((x) < (y)) ? (x) : (y))

void importpath(host, canon)
char *host, *canon;
{
   char *s, *out, c;
   int i, j, l;
 
   out = host;
 
   /* get a pointer to the last component of the path */
   if ((s = rindex(canon, '/')) == (char *)NULL)
      s = canon;
   else
      s++;
 
   j = min(l = strlen(s), 8);
 
   for (i = 0; i < j; i++) {
      c = *s++;
      *out++ = (c == '.') ? '_' : tolower(c);
   }
   *out = '\0';
 
   while (*s != '\0') s++;
 
   if (l>8)
      for (i=0; i<3; i++)
         if (*--s == '.') {
            s++;
            break;
         }
 
   if (*s != '\0') {
      (void)strcat(out, ".");
      (void)strcat(out, s);
   }
 
} /*importpath*/

 
/*
   mkfilename - build a path name out of a directory name and a file name
*/

void mkfilename(filename, dirname, name)
char *filename;
char *dirname;
char *name;
{

   sprintf(filename, FILENAME, dirname, name);

} /*mkfilename*/


/*
   genv - obtain a value form an environment variable
*/

char *genv(envname, defvalue)
char *envname, *defvalue;
{
   char *envvalue, *space;

   if ((envvalue = getenv(envname)) != NULL) {
      space = malloc((unsigned)(strlen(envvalue) + 1));
      (void)strcpy(space, envvalue);
      return(space);
   } else
      return(defvalue);

} /*genv*/

/* The following defines the environment variable names to look
   for the various global parameters under. */

#define MAILBOX "MAILBOX"
#define HOME "HOME"

#define MAILDIR "MAILDIR"
#define CONFDIR "CONFDIR"
#define SPOOLDIR "SPOOLDIR"
#define PUBDIR "PUBDIR"
#define TEMPDIR "TEMPDIR"

#define DOMAIN "DOMAIN"
#define MAILSERV "MAILSERV"

#define DEVICE "DEVICE"
#define SPEED "SPEED"

/* The following are the default value for the global parameters */

#define DMAILBOX "mailbox"
#define DNAME ""
#define DHOME "/usr/guest"

#define DMAILDIR "/usr/mail"
#define DCONFDIR "/usr/lib/uucp"
#define DSPOOLDIR "/usr/spool/uucp"
#define DPUBDIR "/usr/spool/uupublic"
#define DTEMPDIR "/tmp"

#define DDOMAIN "pc.uucp"
#define DNODENAME ""
#define DMAILSERV "host"

#define DDEVICE "COM1"
#define DSPEED "1200"

/* The following variables points to the various global parameters */

char *mailbox, *name, *home;
char *maildir, *confdir, *spooldir, *pubdir, *tempdir;
char *domain, *nodename, *mailserv;
char *device, *speed;

/*
   loadenv - define the global parameters
*/

void loadenv()
{

   mailbox = genv(MAILBOX, DMAILBOX);
   name = genv(NAME, DNAME);
   home = genv(HOME, DHOME);

   maildir = genv(MAILDIR, DMAILDIR);
   confdir = genv(CONFDIR, DCONFDIR);
   spooldir = genv(SPOOLDIR, DSPOOLDIR);
   pubdir = genv(PUBDIR, DPUBDIR);
   tempdir = genv(TEMPDIR, DTEMPDIR);

   domain = genv(DOMAIN, DDOMAIN);
   nodename = genv(NODENAME, DNODENAME);
   mailserv = genv(MAILSERV, DMAILSERV);

   device = genv(DEVICE, DDEVICE);
   speed = genv(SPEED, DSPEED);

} /*loadenv*/


/*
   filemode - default the text/binary mode for subsequently opened files
*/

void filemode(mode)
char mode;
{

   assert((mode == 'b') || (mode == 't'));
   _fmode = (mode == 't') ? O_TEXT : O_BINARY;

} /*filemode*/	

SHAR_EOF
fi # end of overwriting check
if test -f 'dos/host.h'
then
       echo shar: will not over-write existing file "'dos/host.h'"
else
cat << \SHAR_EOF > 'dos/host.h'
/* ibmpc/host.h */

#include <ctype.h>
#include <time.h>
#include <stddef.h>
#include <string.h>

#define MSDOS 1

#define TRUE 1
#define FALSE 0

#define SAME 0

#define TFILENAME "%.8d.Tmp"   /* nnnnnnnn.Tmp */
#define SFILENAME "SEQF"

#define SEPCHAR '/'
#define SIGFILE "Signatur.e"
#define COPYFILE "Mail/MailSent"

#define NEWSDIR "usr/spool/rnews/%02d%02d%02d/%02d%02d%02d.%03d"

#define CALLFILE "c_%.6s"
#define XQTFILE "x_%.6s"

#define CONSOLE "con"   /* "filename" of the console */

#define NAME "NAME"
#define NODENAME "NODENAME"

#define FILEMODE(type) filemode(type)

#define index strchr
#define rindex strrchr

extern char *strchr(), *strrchr;

extern char *maildir;
extern char *tempdir;
extern char *mailbox;
extern char *name;
extern char *device;
extern char *spooldir;
extern char *pubdir;
extern char *confdir;
extern char *home;
extern char *mailserv;
extern char *nodename;
extern char *domain;
extern char *speed;

extern void importpath();
extern void exportpath();

extern void mkfilename();
extern void loadenv();
extern FILE *hostfopen();
extern void filemode();


SHAR_EOF
chmod +x 'dos/host.h'
fi # end of overwriting check
if test -f 'dos/mlib.c'
then
       echo shar: will not over-write existing file "'dos/mlib.c'"
else
cat << \SHAR_EOF > 'dos/mlib.c'
/*		ibmpc/mlib.c
 
		mail system-dependent library
 
	Services to provide in mlib.c
 
		get a single character from the console
 
*/
 
#include <conio.h>
 
int get_one()
{
	return(getch());
} /*get_one*/


SHAR_EOF
fi # end of overwriting check
if test -f 'dos/ndir.c'
then
       echo shar: will not over-write existing file "'dos/ndir.c'"
else
cat << \SHAR_EOF > 'dos/ndir.c'

/* ndir.c for MS-DOS by SKL, June/87 */

/*
   Berkeley-style directory reading routine on MS-DOS
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <dos.h>
#include <assert.h>

#include "ndir.h"

/*
   Open a directory
*/

DIR *opendir(dirname)
char *dirname;
{
   union REGS inregs, outregs;
   struct SREGS segregs;
   char pathname[128];
   DTA far *dtaptr;
   char far *pathptr;
   DIR *dirp;

   /* build pathname to be scanned */
   (void)strcpy(pathname, dirname);
   (void)strcat(pathname, "/*.*");

   /* allocate control block */
   dirp = (DIR *)malloc(sizeof(DIR));

   /* set DTA address to our buffer */
   inregs.h.ah = 0x1a;
   dtaptr = (DTA far *)&(dirp->dirdta);
   segregs.ds = FP_SEG(dtaptr);
   inregs.x.dx = FP_OFF(dtaptr);
   intdosx(&inregs, &outregs, &segregs);

   /* look for the first file */
   inregs.h.ah = 0x4e;
   pathptr = (char far *)pathname;
   segregs.ds = FP_SEG(pathptr);
   inregs.x.dx = FP_OFF(pathptr);
   inregs.x.cx = 0;   /* attribute */
   intdosx(&inregs, &outregs, &segregs);

   /* bad directory name? */
   if (outregs.x.cflag && (outregs.x.ax == 2 || outregs.x.ax == 3)) {
      free((char *)dirp);
      return NULL;
   }

   dirp->dirfirst = outregs.x.cflag ? outregs.x.ax : 0;

   (void)strcpy(dirp->dirid, "DIR");
   return dirp;

} /*opendir*/


/*
   Get next entry in a directory
*/

struct direct *readdir(dirp)
DIR *dirp;
{
   int errcode;

   assert(strcmp(dirp->dirid, "DIR") == 0);

   if (dirp->dirfirst == -1) {
      union REGS inregs, outregs;
      struct SREGS segregs;
      DTA far *dtaptr;

      inregs.h.ah = 0x4f;
      dtaptr = (DTA far *)&(dirp->dirdta);
      segregs.ds = FP_SEG(dtaptr);
      inregs.x.dx = FP_OFF(dtaptr);
      intdosx(&inregs, &outregs, &segregs);
      errcode = outregs.x.cflag ? outregs.x.ax : 0;

   } else {

      errcode = dirp->dirfirst;
      dirp->dirfirst = -1;

   };

   /* no more files in directory? */
   if (errcode == 18)
      return NULL;
   assert(errcode == 0);

   dirp->dirent.d_ino = -1;   /* no inode information */
   {
      char *from, *to;
      
      for ( from = dirp->dirdta.filename, to = dirp->dirent.d_name;
            ;
            from++, to++ ) {
         *to = tolower(*from);
         if (*from == '\0') break;
      };
   };
   dirp->dirent.d_namlen = strlen(dirp->dirent.d_name);
   dirp->dirent.d_reclen = sizeof(struct direct) - (MAXNAMLEN + 1) +
      ((((dirp->dirent.d_namlen + 1) + 3) / 4) * 4);

   return &(dirp->dirent);

} /*readdir*/


/*
   Close a directory
*/

void closedir(dirp)
DIR *dirp;
{

   (void)strcpy(dirp->dirid, "XXX");
   free((char *)dirp);

} /*closedir*/

SHAR_EOF
fi # end of overwriting check
if test -f 'dos/ndir.h'
then
       echo shar: will not over-write existing file "'dos/ndir.h'"
else
cat << \SHAR_EOF > 'dos/ndir.h'

/* ndir.h for MS-DOS by SKL, June/87 */

#define MSDOS_MAXNAMLEN 12
#define MAXNAMLEN MSDOS_MAXNAMLEN

struct direct {
   long d_ino;
   short d_reclen;
   short d_namlen;
   char d_name[MAXNAMLEN + 1];
};

typedef struct {
   char filereserved[21];
   char fileattr;
   int  filetime, filedate;
   long filesize;
   char filename[MSDOS_MAXNAMLEN + 1];
} DTA;

typedef struct {
   char dirid[4];
   struct direct dirent;
   DTA dirdta;
   int dirfirst;
} DIR;

extern DIR *opendir();
extern struct direct *readdir();
extern void closedir();

SHAR_EOF
fi # end of overwriting check
if test -f 'dos/setup.bat'
then
       echo shar: will not over-write existing file "'dos/setup.bat'"
else
cat << \SHAR_EOF > 'dos/setup.bat'
set MAILBOX=mailbox
set NAME=Full Name
set HOME=C:/home
set MAILDIR=C:/usr/spool/mail
set CONFDIR=C:/usr/lib/uucp
set SPOOLDIR=C:/usr/spool/uucp
set PUBDIR=C:/usr/spool/uupublic
set TEMPDIR=C:/tmp
set DOMAIN=ibmpc.vnet.van-bc.uucp
set NODENAME=ibmpc
set MAILSERV=van-bc
set DEVICE=COM1
set SPEED=1200

SHAR_EOF
fi # end of overwriting check
if test -f 'dos/ulib.c'
then
       echo shar: will not over-write existing file "'dos/ulib.c'"
else
cat << \SHAR_EOF > 'dos/ulib.c'
/*	ibmpc/ulib.c
 
	DCP system-dependent library
 
	Services provided by ulib.c:

		serial I/O
		UNIX commands simulation
		login 
 
*/
 
#include <string.h>

#include "dcp.h"
 
/*
   login - login handler
*/

/* Currently a very dumb login handshake for PC in slave mode. */

login()
{
   char line[132];

   for ( ; ; ) {
      msgtime = 9999; /* make it very long */
      rmsg(line, 0); /* wait for a <CR> or <NL> */
      msgtime = 2 * MSGTIME;
      wmsg("Login:", 0);
      rmsg(line, 0);
      printmsg(0, "login: login=%s", line);
      wmsg("Password:", 0);
      rmsg(line, 0);
      printmsg(14, "login: password=%s", line);
      if (strcmp(line, "uucp") == SAME)
         break;
   };

   return('I');

} /*login*/
 
 
/*
   notimp - "perform" Unix commands which aren't implemented
*/
 
notimp(argc, argv)
int argc;
char *argv[];
{

	fprintf(stderr, "shell: command '%s' is not implemented.\n", *argv);

} /*notimp*/

 
/*
   shell - simulate a Unix command

   Only the 'rmail' and 'rnews' command are currently supported.
*/
 
shell(command, inname, outname, errname)
char *command;
char *inname;
char *outname;
char *errname;
{
 
	char	*argvec[50];
 
	int rmail();
	int rnews();
 
	char **argvp;
	char argcp;
 
	int	(*proto)();
 
	argcp = getargs(command, argvec);
	argvp = argvec;
 
	if ( debuglevel > 5 ) {
		int args;
		args = argcp;
		while ( args )
			fprintf(stderr, "shell: args: %d, %s\n", args--, *argvp++);
		argvp = argvec;
	}

	proto = notimp;
 
	if (strcmp(*argvp, "rmail") == SAME)
		proto = rmail;
	else if (strcmp(*argvp, "rnews") == SAME)
		proto = rnews;
	
	if (*inname != '\0') {
		char localname[64];
		importpath(localname, inname);
		if (freopen(localname, "rb", stdin) == NULL) {
			extern int errno;
			fprintf(stderr, "shell: couldn't open %s (%s), errno=%d.\n",
				inname, localname, errno);
		}
	}

	(*proto)(argcp, argvp);
 
	freopen("con", "r", stdin);
 
} /*shell*/
 
 
/* IBM-PC I/O routines */
 
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */

/*************** BASIC I/O ***************************/
/* Saltzers serial pkg */
/* Some notes: When pkts are flying in both directions, there seems to */
/* be some interupt handling problems as far as recieving. checksum errs*/
/* may therfore occur often even though we recover from them. This is */
/* especially true with sliding windows. Errors are very few in the VMS */
/* version. RH Lamb*/

#include "comm.h"

#define STOPBIT 1


/*
   swrite - write to the serial port
*/
 
swrite(data, num)
int num;
char *data;
{
   int i;

   for (i = 0; i < num; i++) send_com(*(data++));
   return(i);

} /*swrite*/


/*
   sread - read from the serial port
*/
 
/* Non-blocking read essential to "g" protocol.
   See "dcpgpkt.c" for description.
   This all changes in a multi-tasking system.  Requests for
   I/O should get queued and an event flag given.  Then the
   requesting process (e.g. gmachine()) waits for the event
   flag to fire processing either a read or a write.
   Could be implemented on VAX/VMS or DG but not MS-DOS. */

sread(buf, expected, timeout)
char *buf;
int expected, timeout;
{
   long start;

   start = time((long *)NULL);
   for ( ; ; ) {
      int pending;
      pending = r_count_pending();
      printmsg(20, "---> pending=%d expected=%d", pending, expected);
      if (pending >= expected) {
         int i;
         for (i = 0; i < expected; i++)
            *(buf++) = receive_com();
         return(pending);
      } else {
         int elapsed;
         elapsed = time((long *)NULL) - start;
         if (elapsed >= timeout)
            return(pending);
      }
   }

} /*sread*/
 

/*
   openline - open the serial port for I/O
*/
 
openline(name, baud)
char *name, *baud;
{
   int i;

   sscanf(name, "COM%d", &i);
   select_port(i);
   save_com();
   install_com();
   sscanf(baud, "%d", &i);
   open_com(i, 'D', 'N', STOPBIT, 'D');
   dtr_on();

   return(0);

} /*openline*/


/*
   closeline - close the serial port down
*/
 
closeline()
{

   dtr_off();
   close_com();
   restore_com();

} /*closeline*/
 

/*
   sleep() - wait n seconds

   Simply delay until n seconds have passed.
*/
 
void sleep(interval)
int interval;
{
   long start;
 
   start = time((long *)NULL);
   while ((time((long *)NULL) - start) < interval);

} /*sleep*/


/*
   SIOSpeed - re-specify the speed of an opened serial port
*/

void SIOSpeed(baud)
char *baud;
{
   int speed;

   dtr_off();
   close_com();
   sscanf(baud, "%d", &speed);
   open_com(speed, 'D', 'N', STOPBIT, 'D');
   dtr_on();

} /*SIOSpeed*/

SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

--
{ubc-vision,uunet}!van-bc!sl				Stuart.Lynne@van-bc.uucp