	SUBROUTINE REMOTE_AST
C
C	This AST routine is entered when the read request for the remote
C	terminal completes.  It then writes the data read from the remote
C	to the local terminal and the log file (if any).
C
	INCLUDE 'COM.INC/NOLIST'

	EXTERNAL LOCAL_WRITE_AST

	STATUS = RIOSB(1)		! Copy the status code.
	NBYTES = RIOSB(2)		!   and the byte count.
	LAST_LOCAL_CHAR(1) = 0		! Show remote responded.
	IF (INTERRUPT_TYPED) GO TO 9999	! Don't write this buffer.
C
C	Check the I/O status.
C
	IF (STATUS .EQ. SS$_ABORT) GO TO 200
	IF (NBYTES .EQ. 0) GO TO 9900	! Nothing read, nothing to write.
	IF (.NOT. STATUS) THEN
	    IF (STATUS .NE. SS$_TIMEOUT) THEN
		CALL CHECK_STATUS ('REMOTE_READ_AST', STATUS)
		GO TO 9900		! Continue ...
	    ENDIF
	ENDIF
C
C	Save the maximum number of bytes read for debugging.
C
	IF (NBYTES .GT. REMOTE_MAXIMUM) THEN
	    REMOTE_MAXIMUM = NBYTES	! Save maximum bytes read.
	ENDIF
C
C	Copy incoming characters to the logfile buffer.
C
	CALL WRITE_LOGFILE (RBUFFER, NBYTES)
C
C	When running in slave mode (no local terminal), we simply set the
C	receiver not busy and wakeup the mainline to rearm the remote read.
C
	IF (SLAVE_MODE) GO TO 9900	! Set receiver not busy/wakeup mainline
C
C	If the STRIP_XOFF flag is enabled, we'll convert the CTRL/S character
C	to a null.  This prevents the local terminal from getting locked up.
C
	IF (STRIP_XOFF) THEN
	    DO 100 I=1,NBYTES
		IF  (RBUFFER(I) .EQ. XOFF) THEN
		    RBUFFER(I) = 0	! Convert the XOFF to a NULL.
		ENDIF
100	    CONTINUE
	ENDIF
C
C	Echo character(s) from the remote at the local terminal.
C
	STATUS = SYS$QIO(%VAL(LEFN_OUT),%VAL(LCHAN_OUT),
	1		%VAL(IO$_WRITELBLK + IO$M_NOFORMAT),
	1		XLIOSB,LOCAL_WRITE_AST,,RBUFFER,%VAL(NBYTES),,,,)
	IF (.NOT. STATUS) THEN
		CALL CHECK_STATUS ('LOCAL_WRITE_QIO', STATUS)
		GO TO 9900
	ENDIF		
200	RETURN
C
C	On errors, set the receiver not busy, and wakeup the mainline.
C
9900	RECEIVER_BUSY = .FALSE.		! Set receiver not busy.
9999	CALL WAKE_UP()			! Wakeup the mainline code.
	RETURN
	END

	SUBROUTINE LOCAL_AST
C
C	This AST routine is entered when the local read completes.
C	The character(s) read are then written to the remote system.
C	If local echo is enabled, the characters are also written to
C	the log file (if any).
C
	INCLUDE 'COM.INC/NOLIST'

	LOGICAL CHECK_MODEM
	CHARACTER*(*) MODEM_HANGUP

	PARAMETER (MODEM_HANGUP = DS//
	1 '*** The modem has gone to NOT READY, upon returning to the ***'
	2 //SS//
	3 ' *** command prompt you may either DIAL, REDIAL, or EXIT. ***'
	4 //BELL//SS)

	XMITTER_BUSY = .FALSE.		! Set transmitter not busy.
	STATUS = LIOSB(1)		! Copy the status code.
	NBYTES = LIOSB(2)		!   and the byte count.
C
C	If the read failed, don't write to the remote.
C
	IF (STATUS .EQ. SS$_ABORT) GO TO 500
	IF (NBYTES .EQ. 0) GO TO 500	! Nothing read, nothing to write.
	IF (.NOT. STATUS) THEN
	    IF (STATUS .NE. SS$_TIMEOUT) THEN
		CALL CHECK_STATUS ('LOCAL_QIO', STATUS)
		GO TO 500		! And continue ..
	    ENDIF
	ENDIF
C
C	Save the maximum number of bytes read for debugging.
C
	IF (NBYTES .GT. LOCAL_MAXIMUM) THEN
	    LOCAL_MAXIMUM = NBYTES	! Save maximum bytes read.
	ENDIF
C
C	The next section has added to check for the modem not being
C	ready.  If the user types the RETURN key twice without the
C	remote responding, then we check the dataset ready signal.
C	We don't want to check on every key stroke to save overhead.
C
C	We only do the check if an autodial modem has been selected
C	so the user isn't prevented from talking to an autodial modem
C	which isn't online.
C
	IF (MODEM_CHECK .AND. AUTODIAL) THEN	! Only check autodial modems.
	    IF ( (LBUFFER(1) .EQ. CR) .AND.
	1	(LAST_LOCAL_CHAR(1) .EQ. CR) ) THEN
	      IF ( .NOT. CHECK_MODEM() ) THEN
		CALL WRITE_USER (MODEM_HANGUP)	! Tell user about hangup.
		CALL PHONE_LOG ('NOCARRIER')	! Log lost of modem carrier.
		REMOTE = .FALSE.		! Show modem is offline (VMS).
		MODEM_ONLINE = .FALSE.		! Show the modem is offline.
		INTERRUPT_TYPED = .TRUE.	! Set to return to command mode.
		GO TO 500			! Now wakeup the mainline.
	      ENDIF
	    ENDIF
	ENDIF
	LAST_LOCAL_CHAR(1) = LBUFFER(1)		! Save the last character.
C
C	Next we check for the interrupt character to escape to Vaxnet
C	command level.  When the interrupt character is detected, the
C	INTERRUPT_TYPED flag is set, and we wake up the mainline which
C	then detects the interrupt character has been typed.
C
C	If BREAK character detection is enabled and we detect the BREAK
C	character, we send the BREAK signal to the remote system.
C
C	We also check for the XOFF/XON characters used to stop/resume
C	output to the terminal.  If the SUSPEND_OUTPUT flag is .TRUE.
C	then REMOTE_READ routine will not issue any reads to prevent
C	the terminal from being overrun.
C
	DO 100 I=1,NBYTES
	IF     (LBUFFER(I) .EQ. INTERRUPT_CHAR(1)) THEN
		INTERRUPT_TYPED = .TRUE.	! Show interrupt was typed.
		GO TO 500			! And continue ...
	ELSEIF (BREAK_IS_ENABLED) THEN
		IF (LBUFFER(I) .EQ. BREAK_CHAR(1)) THEN
		    CALL SEND_BREAK()		! Send the BREAK signal.
		    GO TO 500			! And continue ...
		ENDIF
	ELSEIF (LBUFFER(I) .EQ. XOFF) THEN
		SUSPEND_OUTPUT = .TRUE.		! Stop output to the terminal.
	ELSEIF (LBUFFER(I) .EQ. XON) THEN
		SUSPEND_OUTPUT = .FALSE.	! Resume output to the terminal.
	ENDIF
100	CONTINUE
C
C	If doing local echoing, all incoming characters from the local
C	terminal are copied to the logfile buffer to simulate echoing
C	from the remote system.
C
	IF (LOCAL_ECHO) CALL WRITE_LOGFILE(LBUFFER,NBYTES)
C
C	Write the characters read to the remote system.
C
	STATUS = SYS$QIO(%VAL(REFN_OUT),%VAL(RCHAN_OUT),
	1		%VAL(IO$_WRITELBLK + IO$M_NOFORMAT),
	1		XRIOSB,,,LBUFFER,%VAL(NBYTES),,,,)
	CALL CHECK_STATUS ('REMOTE_WRITE_QIO', STATUS)
C
C	Wake up the main line to reactivate the local read.
C
500	CALL WAKE_UP()			! Wake up the mainline.
	RETURN
	END

	SUBROUTINE LOCAL_WRITE_AST
C
C	This AST routine is entered when the write request to the local
C	terminal completes.  This routine was added to synchonize the
C	remote reads.  Without this routine, remote reads were completing
C	faster than local writes which eventually exceeded the buffered
C	I/O quota.  Now, the next remote read will not be issued until
C	the local write completes.
C
	INCLUDE 'COM.INC/NOLIST'

	RECEIVER_BUSY = .FALSE. 	! Set receiver not busy.
	STATUS = XLIOSB(1)		! Copy the status code.
C
C	If interrupt not typed, check the I/O status return.
C
	IF (.NOT. INTERRUPT_TYPED) THEN
	    IF (STATUS .NE. SS$_ABORT) THEN
		CALL CHECK_STATUS ('LOCAL_WRITE_AST', STATUS)
	    ENDIF
	    CALL WAKE_UP()		! Wakeup the mainline code.
	ENDIF
	RETURN
	END
