MODULE KERTRM (IDENT = '1.0.000'
		) =
BEGIN

!++
! FACILITY:
!
!	KERMIT-32 terminal processing.
!
! ABSTRACT:
!
!	This module will do all of the terminal processing for KERMIT-32.
!	It contains the output routines for the terminal to send and
!	receive messages as well as the routines to output text for debugging.
!
! ENVIRONMENT:
!
!	VAX/VMS user mode.
!
! AUTHOR: Robert C. McQueen, CREATION DATE: 25-March-1983
!--

%SBTTL 'Table of Contents'
!
! TABLE OF CONTENTS:
!
%SBTTL 'Revision History'

!++
!
! Start of version 1.	25-March-1983
!
! 1.0.000	By: Robert C. McQueen		On: 25-March-1983
!		Create this module.
!
!--

%SBTTL 'Forward routine definitions'

FORWARD ROUTINE
    TT_CHAR : NOVALUE,				! Process a single character
    TT_OUTPUT : NOVALUE;			! Output the buffer to SYS$OUTPUT

%SBTTL 'Library files'
!
! INCLUDE FILES:
!
!
! System definitions
!

LIBRARY 'SYS$LIBRARY:STARLET';

!
! KERMIT common definitions
!

REQUIRE 'KERCOM';

REQUIRE 'KERERR';

%SBTTL 'Structure definitions -- $GETDVI arguments'
!
! $GETDVI interface fields and structure definition
!

LITERAL
    DVI_SIZE = 3;				! Length of a DVI item list entry

!
! Fields for accessing the items in a DVI item list
!

FIELD
    DVI_FIELDS =
	SET
	DVI_BFR_LENGTH = [0, 0, 16, 0],
	DVI_ITEM_CODE = [0, 16, 16, 0],
	DVI_BFR_ADDRESS = [1, 0, 32, 0],
	DVI_RTN_LENGTH = [2, 0, 32, 0]
	TES;

!
! Structure definition for item list

STRUCTURE
    DVI_ITEM_LIST [I, O, P, S, E; N] =
	[(N + 1)*DVI_SIZE*4]
	(DVI_ITEM_LIST + ((I*DVI_SIZE) + O)*4)<P, S, E>;

%SBTTL 'Structures definitions -- Terminal characteristics'
!
! Terminal characteristics words
!

LITERAL
    TC$_CHAR_LENGTH = 12;

!
! Fields for accessing the items in a characteristic block
!

FIELD
    TC$_FIELDS =
	SET
	TC$_CLASS = [0, 0, 8, 0],
	TC$_TYPE = [0, 8, 8, 0],
	TC$_BFR_SIZE = [0, 16, 16, 0],
	TC$_PAGE_LEN = [1, 24, 8, 0],
	TC$_CHAR = [1, 0, 24, 0],
	TC$_CHAR_2 = [2, 0, 32, 0]
	TES;

!
! Structure definition for item list
!

STRUCTURE
    TC$_CHAR_STR [O, P, S, E; N] =
	[TC$_CHAR_LENGTH]
	(TC$_CHAR_STR + O*4)<P, S, E>;

%SBTTL 'Macro definitions'
!
! MACROS:
!
%(/*macro-decl*/)%
%SBTTL 'Symbol definitions'
!
! EQUATED SYMBOLS:
!

LITERAL
    TEXT_BFR_LENGTH = 256;			! Length of the text buffer

%SBTTL 'Storage'
!
! OWN STORAGE:
!
!
! TT_xxxxx routine storage
!

OWN
    TEXT_POINTER,				! Pointer to store characters
    TEXT_BUFFER : VECTOR [CH$ALLOCATION (TEXT_BFR_LENGTH)],	! Buffer of characters
    TEXT_DESC : BLOCK [8, BYTE];

!
! Communications routines storage
!

OWN
    TERM_CHAN,					! Channel the terminal is opened on
    OLD_PARITY : BLOCK [8, BYTE],			! Old IOSB information
    OLD_TERM_CHAR : TC$_CHAR_STR FIELD (TC$_FIELDS),	! Old terminal chars
    NEW_TERM_CHAR : TC$_CHAR_STR FIELD (TC$_FIELDS);	! New terminal chars

GLOBAL
    TERM_FLAG;					! Terminal open flag

%SBTTL 'External routines'
!
! EXTERNAL REFERENCES:
!
!
! System library routines
!

EXTERNAL ROUTINE
    LIB$SIGNAL : ADDRESSING_MODE (GENERAL),
    LIB$PUT_OUTPUT : ADDRESSING_MODE (GENERAL);

%SBTTL 'External storage'

!++
! The following is the various external storage locations that are
! referenced from this module.
!--

!
! KERMSG storage
!

EXTERNAL
    RCV_EOL,					! Receive EOL character
    RCV_TIMEOUT,				! Receive time out counter
    CONNECT_FLAG;				! Flag if communications line is TT:

!
! KERMIT storage
!

EXTERNAL
    TERM_NAME,					! Terminal name
    TERM_DESC : BLOCK [8, BYTE];		! Descriptor for terminal name

%SBTTL 'Terminal routines -- TT_INIT - Initialize this module'

GLOBAL ROUTINE TT_INIT : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will initialize the terminal processing module.  It will
!	initialize the various data locations in this module.
!
! CALLING SEQUENCE:
!
!	TT_INIT();
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN
!
! Initialize the text descriptor
!
    TEXT_DESC [DSC$B_CLASS] = DSC$K_CLASS_S;
    TEXT_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T;
    TEXT_DESC [DSC$A_POINTER] = TEXT_BUFFER;
    TEXT_DESC [DSC$W_LENGTH] = 0;
!
! Now initialize the various pointers
!
    TEXT_POINTER = CH$PTR (TEXT_BUFFER);
!
! Set up the terminal name descriptor
    TERM_DESC [DSC$B_CLASS] = DSC$K_CLASS_S;
    TERM_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T;
    TERM_DESC [DSC$A_POINTER] = TERM_NAME;
    TERM_DESC [DSC$W_LENGTH] = 12;
    CH$COPY (10, CH$PTR (UPLIT ('SYS$INPUT:')), 0, 11, CH$PTR (TERM_NAME));
!
! Initialize the flags
!
    TERM_FLAG = FALSE;
    END;					! End of TT_INIT

%SBTTL 'Terminal routines -- TT_TEXT - Output a text string'

GLOBAL ROUTINE TT_TEXT (ADDRESS) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will output text on the user's terminal.  It will
!	assume that it must check to determine if it can output the text
!	or not.
!
! CALLING SEQUENCE:
!
!	TT_TEXT(TEXT_ADDRESS);
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	CHARACTER,				! Character being processed
	ARG_POINTER;				! Pointer to the argument's text

!
! Construct a pointer to the argument.
!
    ARG_POINTER = CH$PTR (.ADDRESS);
!
! Get the first character that was passed.
!
    CHARACTER = CH$RCHAR_A (ARG_POINTER);
!
! Loop reading characters and calling the output routine to process
! them
!

    WHILE .CHARACTER NEQ CHR_NUL DO
	BEGIN
	TT_CHAR (.CHARACTER);
	CHARACTER = CH$RCHAR_A (ARG_POINTER);
	END;

    END;					! End of TT_TEXT

%SBTTL 'Terminal routines -- TT_NUMBER - Output a three digit number'

GLOBAL ROUTINE TT_NUMBER (NUMBER) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will store a three digit number into the text buffer.
!	It will just return if the number is greater than 999.
!
! CALLING SEQUENCE:
!
!	TT_NUMBER(Value);
!
! INPUT PARAMETERS:
!
!	Value - Value to output.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    IF .NUMBER LEQ 999
    THEN
	BEGIN
	TT_CHAR ((.NUMBER/100) + %C'0');
	TT_CHAR (((.NUMBER/10) MOD 10) + %C'0');
	TT_CHAR ((.NUMBER MOD 10) + %C'0');
	END;

    END;					! End of TT_NUMBER

%SBTTL 'Terminal routines -- TT_QCHAR - Output a single character'

GLOBAL ROUTINE TT_QCHAR (CHARACTER) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will output a quoted character to the terminal buffer.
!	It will convert control characters to printing characters.
!
! CALLING SEQUENCE:
!
!	TT_QCHAR(Character);
!
! INPUT PARAMETERS:
!
!	Character - Character to store into the text buffer.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	TEMP_CHAR;				! Temp holding place for the characters

!
! Copy the character first
!
    TEMP_CHAR = .CHARACTER;
!
! Determine if this is a control character.  If so then convert it to be
! a ^<Character>
!

    IF .TEMP_CHAR LSS CHR_SP
    THEN
	BEGIN
	TT_CHAR (%C'^');
	TEMP_CHAR = %C'A' - 1 + .TEMP_CHAR;
	END;

!
! Output the character after any conversion
!
    TT_CHAR (.TEMP_CHAR);
!
    END;					! End of TT_QCHAR

%SBTTL 'Terminal routines -- TT_CHAR - Output a single character'

GLOBAL ROUTINE TT_CHAR (CHARACTER) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will store a character into the text buffer.  It will
!	cause the text to be output if the character is a line terminator.
!
! CALLING SEQUENCE:
!
!	TT_CHAR(Character);
!
! INPUT PARAMETERS:
!
!	Character - Character to store into the text buffer.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN
!
! If this is a line feed then just output the text string and return
!

    IF .CHARACTER EQL CHR_LFD
    THEN
	TT_OUTPUT ()
    ELSE
	BEGIN
!
! Increment the count of the characters
!
	TEXT_DESC [DSC$W_LENGTH] = .TEXT_DESC [DSC$W_LENGTH] + 1;
!
! And store the character
!
	CH$WCHAR_A (.CHARACTER, TEXT_POINTER);

	IF .TEXT_DESC [DSC$W_LENGTH] EQL TEXT_BFR_LENGTH THEN TT_OUTPUT ();

	END;

!
    END;					! End of TT_CHAR

%SBTTL 'Terminal routines -- TT_CRLF - Output a CRLF'

GLOBAL ROUTINE TT_CRLF : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will cause the contents of the terminal buffer to be
!	output to SYS$OUTPUT:.
!
! CALLING SEQUENCE:
!
!	TT_CRLF();
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN
    TT_CHAR (CHR_LFD);
    END;					! End of TT_CRLF

%SBTTL 'Terminal routines -- TT_OUTPUT - Output the buffer'
ROUTINE TT_OUTPUT : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will dump the text buffer on the output device.
!
! CALLING SEQUENCE:
!
!	TT_OUTPUT();
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	None.
!
! OUPTUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	STATUS;					! Status returned by the library routine

!
! Output the text
!
    STATUS = LIB$PUT_OUTPUT (TEXT_DESC);
!
! Now reset the descriptor and the pointer to a virgin state
!
    TEXT_DESC [DSC$W_LENGTH] = 0;
    TEXT_POINTER = CH$PTR (TEXT_BUFFER);
!
    END;					! End of TT_OUTPUT
%SBTTL 'Communcations line -- TERM_OPEN'

GLOBAL ROUTINE TERM_OPEN =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will assign a channel that is used in the CONNECT
!	processing and to send/receive a file from.
!
! CALLING SEQUENCE:
!
!	TERM_OPEN();
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	TERM_NAME - Vector of ASCII characters that represent the name of
!	the terminal to use.
!
! OUTPUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	TERM_CHAN - Channel number of the terminal line we are using.
!
! COMPLETION CODES:
!
!	SS$_NORMAL or error condition.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    BIND
	SYS_OUTPUT = %ASCID'TT:';

    LOCAL
	STATUS,
	OUTPUT_ITM : DVI_ITEM_LIST [2] FIELD (DVI_FIELDS),
	OUTPUT_NAME : VECTOR [65, BYTE],
	OUTPUT_LENGTH,
	OUTPUT_CLASS,
	OUTPUT_STATUS,
	TERM_ITM : DVI_ITEM_LIST [2] FIELD (DVI_FIELDS),
	TERM_NAME : VECTOR [65, BYTE],
	TERM_LENGTH,
	TERM_CLASS,
	TERM_STATUS;

!
! Initialize the first character to be an underscore, incase we have a
! concealed device name
!
    OUTPUT_NAME [0] = %C'_';
    TERM_NAME [0] = %C'_';
!
! Initialize the GETDVI call for the TT:
!
    OUTPUT_ITM [0, DVI_ITEM_CODE] = DVI$_DEVCLASS;
    OUTPUT_ITM [0, DVI_BFR_LENGTH] = 4;
    OUTPUT_ITM [0, DVI_BFR_ADDRESS] = OUTPUT_CLASS;
    OUTPUT_ITM [0, DVI_RTN_LENGTH] = 0;
!
    OUTPUT_ITM [1, DVI_ITEM_CODE] = DVI$_DEVNAM;
    OUTPUT_ITM [1, DVI_BFR_LENGTH] = 64;
    OUTPUT_ITM [1, DVI_BFR_ADDRESS] = OUTPUT_NAME [1];
    OUTPUT_ITM [1, DVI_RTN_LENGTH] = OUTPUT_LENGTH;
!
    OUTPUT_ITM [2, DVI_ITEM_CODE] = 0;
    OUTPUT_ITM [2, DVI_BFR_LENGTH] = 0;
!
! Initialize the GETDVI call for the terminal name given
!
    TERM_ITM [0, DVI_ITEM_CODE] = DVI$_DEVCLASS;
    TERM_ITM [0, DVI_BFR_LENGTH] = 4;
    TERM_ITM [0, DVI_BFR_ADDRESS] = TERM_CLASS;
    TERM_ITM [0, DVI_RTN_LENGTH] = 0;
!
    TERM_ITM [1, DVI_ITEM_CODE] = DVI$_DEVNAM;
    TERM_ITM [1, DVI_BFR_LENGTH] = 64;
    TERM_ITM [1, DVI_BFR_ADDRESS] = TERM_NAME [1];
    TERM_ITM [1, DVI_RTN_LENGTH] = TERM_LENGTH;
!
    TERM_ITM [2, DVI_ITEM_CODE] = 0;
    TERM_ITM [2, DVI_BFR_LENGTH] = 0;
!
! Get the device information
!
    OUTPUT_STATUS = $GETDVI (EFN = 2, DEVNAM = SYS_OUTPUT, ITMLST = OUTPUT_ITM);

    IF NOT .OUTPUT_STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.OUTPUT_STATUS);
	RETURN .OUTPUT_STATUS;
	END;

    STATUS = $WAITFR (EFN = 2);

    IF NOT .STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

!
! For both of the device names
!
    TERM_STATUS = $GETDVI (EFN = 2, DEVNAM = TERM_DESC, ITMLST = TERM_ITM);

    IF NOT .TERM_STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.TERM_STATUS);
	RETURN .STATUS;
	END;

    STATUS = $WAITFR (EFN = 2);

    IF NOT .STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

!
! Make sure that they are terminals
!

    IF .TERM_CLASS EQL DC$_TERM AND .OUTPUT_CLASS EQL DC$_TERM
    THEN
	BEGIN

	IF .OUTPUT_STATUS EQL SS$_CONCEALED
	THEN
	    BEGIN
	    OUTPUT_LENGTH = .OUTPUT_LENGTH + 1;
	    OUTPUT_ITM [1, DVI_BFR_ADDRESS] = .OUTPUT_ITM [1, DVI_BFR_ADDRESS] - 1;
	    END;

	IF .TERM_STATUS EQL SS$_CONCEALED
	THEN
	    BEGIN
	    TERM_LENGTH = .TERM_LENGTH + 1;
	    TERM_ITM [1, DVI_BFR_ADDRESS] = .TERM_ITM [1, DVI_BFR_ADDRESS] - 1;
	    END;

	IF CH$NEQ (.OUTPUT_LENGTH, CH$PTR (.OUTPUT_ITM [1, DVI_BFR_ADDRESS]), .TERM_LENGTH,
		CH$PTR (.TERM_ITM [1, DVI_BFR_ADDRESS]), CHR_NUL)
	THEN
	    CONNECT_FLAG = FALSE
	ELSE
	    CONNECT_FLAG = TRUE;

	END
    ELSE
	BEGIN
	RETURN KER_LINTERM;
	END;

    STATUS = $ASSIGN (DEVNAM = TERM_DESC, CHAN = TERM_CHAN);

    IF NOT .STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

    STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_SENSEMODE, P1 = OLD_TERM_CHAR, P2 = TC$_CHAR_LENGTH, IOSB = OLD_PARITY);

    IF NOT .STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

    NEW_TERM_CHAR [TC$_BFR_SIZE] = .OLD_TERM_CHAR [TC$_BFR_SIZE];
    NEW_TERM_CHAR [TC$_TYPE] = .OLD_TERM_CHAR [TC$_TYPE];
    NEW_TERM_CHAR [TC$_CLASS] = .OLD_TERM_CHAR [TC$_CLASS];
    NEW_TERM_CHAR [TC$_PAGE_LEN] = .OLD_TERM_CHAR [TC$_PAGE_LEN];
    NEW_TERM_CHAR [TC$_CHAR] = (.OLD_TERM_CHAR [TC$_CHAR] OR TT$M_EIGHTBIT OR TT$M_NOBRDCST) AND NOT (
    TT$M_CRFILL OR TT$M_LFFILL OR TT$M_WRAP);
    NEW_TERM_CHAR [TC$_CHAR_2] = .OLD_TERM_CHAR [TC$_CHAR_2];

    STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_SETMODE, P1 = NEW_TERM_CHAR, P2 = TC$_CHAR_LENGTH, P5 = TT$M_ALTRPAR);

    IF NOT .STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

    TERM_FLAG = TRUE;				! Terminal now open
    RETURN KER_NORMAL;
    END;					! End of TERM_OPEN

%SBTTL 'Communications line -- TERM_CLOSE'

GLOBAL ROUTINE TERM_CLOSE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will deassign the channel that was assigned by
!	TERM_OPEN.
!
! CALLING SEQUENCE:
!
!	TERM_CLOSE();
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	TERM_CHAN - Channel number to deassign.
!
! OUTPUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	SS$_NORMAL or error condition.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	PAR,					! Parity being set
	STATUS;					! Status returned by system service

    CONNECT_FLAG = FALSE;

    PAR = .OLD_PARITY [1, 8, 8, 0] OR TT$M_ALTRPAR;

    STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_SETMODE, P1 = OLD_TERM_CHAR, P2 = TC$_CHAR_LENGTH, P5 = .PAR);

    IF NOT .STATUS
    THEN
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

    STATUS = $DASSGN (CHAN = .TERM_CHAN);

    IF .STATUS
    THEN
	BEGIN
	TERM_FLAG = FALSE;
	RETURN KER_NORMAL
	END
    ELSE
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

    END;					! End of TERM_CLOSE

%SBTTL 'Communications line -- SEND'

GLOBAL ROUTINE SEND (ADDRESS, LENGTH) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will send a stream of 8-bit bytes over the terminal
!	line to the remote KERMIT.  This routine is called from KERMSG.
!
! CALLING SEQUENCE:
!
!	SEND(Address-of-msg, Length-of-msg);
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	TERM_CHAN - Channel number to deassign.
!
! OUTPUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	SS$_NORMAL or error condition.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	STATUS;					! Status returned by $QIOW

    STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_WRITEVBLK + IO$M_NOFORMAT, P1 = .ADDRESS, P2 = .LENGTH);

    IF .STATUS EQL SS$_NORMAL
    THEN
	RETURN KER_NORMAL
    ELSE
	BEGIN
	LIB$SIGNAL (.STATUS);
	RETURN .STATUS;
	END;

    END;					! End of SEND

%SBTTL 'Communications line -- RECEIVE'

GLOBAL ROUTINE RECEIVE (ADDRESS, LENGTH) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine will receive a stream of 8-bit bytes over the terminal
!	line to the remote KERMIT.  This routine is called from KERMSG.
!	The text that is stored will always contain the control-A as the
!	first character.
!
! CALLING SEQUENCE:
!
!	RECEIVE(Address-of-msg);
!
! INPUT PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	TERM_CHAN - Channel number to deassign.
!
! OUTPUT PARAMETERS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! COMPLETION CODES:
!
!	SS$_NORMAL or error condition.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	TERMINATOR : VECTOR [2, LONG],
	IO_STATUS : VECTOR [4, WORD],
	POINTER,				! Pointer into the message
	STATUS;					! Status returned by $QIO

    TERMINATOR [0] = 0;
    TERMINATOR [1] = 1^.RCV_EOL;
    STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_TTYREADALL + IO$M_NOECHO, IOSB = IO_STATUS, P1 = .ADDRESS,
	P2 = MAX_MSG, P3 = .RCV_TIMEOUT, P4 = TERMINATOR);
    .LENGTH = .IO_STATUS [1] + 1;

    POINTER = CH$FIND_CH(.IO_STATUS [1] + 1, CH$PTR(.ADDRESS, 0, CHR_SIZE), CHR_CTL_Y);
    IF CH$FAIL(POINTER) THEN RETURN KER_ABORTED;

    IF .STATUS EQL SS$_TIMEOUT THEN RETURN KER_TIMEOUT;

    IF .STATUS EQL SS$_NORMAL THEN RETURN KER_NORMAL;
!    LIB$SIGNAL(KER_RECERR, .STATUS);
    RETURN KER_RECERR;

    END;					! End of RECEIVE

%SBTTL 'End of KERTRM'
END						! End of module

ELUDOM
