Google
 

Trailing-Edge - PDP-10 Archives - bb-h138e-bm_tops20_v6_1_distr - language-sources/dap.bli
There are 21 other files named dap.bli in the archive. Click here to see a list.
MODULE DAP(			!DAP message processing routines
	IDENT='60(13)  9-Feb-84'
        %BLISS36(,
                 ENTRY(
                       D$GCFG, ! DAP$GET_CONFIG,     ! Get Config message
                       D$GATT, ! DAP$GET_ATTRIBUTES, ! Get Attributes -> FAB
                       D$PCFG, ! DAP$PUT_CONFIG,     ! Build CONFIG
                       D$PATT, ! DAP$PUT_ATTRIBUTES, ! Build ATTRIBUTES <- FAB
                       D$PACC, ! DAP$PUT_ACCESS,     ! Build ACCESS message
                       D$PNAM, ! DAP$PUT_NAME,       ! Build a NAME message
                       D$PCTL, ! DAP$PUT_CONTROL,    ! Build CONTROL message
                       D$GSTS  ! DAP$GET_STATUS      ! Process a STATUS message
                       ))
	)=
BEGIN

!
!  COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1981, 1985.
!  ALL RIGHTS RESERVED.
!  
!  THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED  AND
!  COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
!  THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS  SOFTWARE  OR
!  ANY  OTHER  COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
!  AVAILABLE TO ANY OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE
!  SOFTWARE IS HEREBY TRANSFERRED.
!  
!  THE INFORMATION IN THIS SOFTWARE IS  SUBJECT  TO  CHANGE  WITHOUT
!  NOTICE  AND  SHOULD  NOT  BE CONSTRUED AS A COMMITMENT BY DIGITAL
!  EQUIPMENT CORPORATION.
!  
!  DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF
!  ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.

!++
! FACILITY:	FTS-20
!
! ABSTRACT:	This is the System-independent part of the DAP protocol.
!
!
! ENVIRONMENT:	TOPS-20, Transportable BLISS DecNet Interface
!
! AUTHOR:	Andrew Nourse, CREATION DATE: 21-Dec-81
!
! 13    - Make losing old FAL-20 blocks into pages
! 12    - Handle ADT.  also put BDT and PDT in correct order
! 11    - Put nodeid in resultant name generated from 3-part name
! 10    - Send real byte size to 36-bit machines, no byte size to others
!         and include node name in remote resultant filespec.
! 07    - Set implied CRLF for ASCII FIXED
! 06    - Workaround RSTS not sending STATUS for file-not-found on directory
! 05    - Put in ENTRY points
! 04    - Fix default for BLS in DAP$PUT_ATTRIBUTES
!         and put in bitvectors for workarounds
!       - Fix RENAME name type
! 03    - Page mode
! 02    - Make the FOP go out
! 01	- The beginning
!--


!
! Conditionals
!

COMPILETIME
           FTPASSIVE=0;                 ! FAL can't use this package yet


!
! Libraries
!

LIBRARY 'DAP';
LIBRARY 'BLISSNET';
LIBRARY 'RMS';
LIBRARY 'CONDIT';

!
! Table of Contents
!
FORWARD ROUTINE
    DAP$GET_CONFIG,                         ! Get Config message
    DAP$GET_ATTRIBUTES,                     ! Get Attributes
    DAP$PUT_CONFIG: NOVALUE,                ! Build CONFIG
    DAP$PUT_ATTRIBUTES: NOVALUE,            ! Build ATTRIBUTES from FAB
    DAP$PUT_ACCESS: NOVALUE,                ! Build ACCESS message
    DAP$PUT_NAME: NOVALUE,                  ! Build a NAME message
    DAP$PUT_CONTROL: NOVALUE,               ! Build CONTROL message
    DAP$GET_STATUS;                         ! Process a STATUS message


!
! Literals
!

%IF %BLISS(BLISS36)
    %THEN 
    %IF %SWITCHES(TOPS20)
        %THEN
        LITERAL
               OUR_OSTYPE=DAP$K_TOPS20,
               OUR_BLOCK_SIZE=512,
               DEVICE_NAME_LENGTH=40,   ! Including punctuation
               DIRECTORY_NAME_LENGTH=41,!
               FILE_NAME_LENGTH=40;     !
        %ELSE
        %ERROR('Not implemented on TOPS-10')
        %FI

    LITERAL
           OUR_FILESYS=DAP$K_RMS20;
    %ELSE %ERROR('Not implemented for 16/32 bit architectures')
    %FI;


!
! External references
!
EXTERNAL ROUTINE CHAZAC,
                 S$STRDT,
                 DAP$GET_HEADER,
                 DAP$UNGET_HEADER,
                 DAP$GET_BYTE,
                 DAP$GET_2BYTE,
                 DAP$GET_DATE,
                 DAP$GET_VARIABLE_STRING,
                 DAP$SIZE_BITVECTOR,
                 DAP$GET_BITVECTOR,
                 DAP$PUT_BITVECTOR,
                 DAP$PUT_HEADER,
                 DAP$PUT_2BYTE,
                 DAP$PUT_BYTE,
                 DAP$PUT_STRING,
                 DAP$PUT_VARIABLE_COUNTED,
                 DAP$UNGET_BYTE,
                 DAP$EAT_MESSAGE;

!
! Macros
!
MACRO DAP_ERROR(DDESC,MAC,MIC)=SIGNAL(ERR_DS(MAC,MIC),DDESC) %;

!
! Canned Messages   (Global PLITS)
!

GLOBAL BIND	CFGMSG=UPLIT(CHAR8(
				DAP$K_CONFIG,	!Message type CONFIG
				0,              !Flags
				DAP$K_BUFFER_SIZE,      ! Buffer
                                DAP$K_BUFFER_SIZE/256,  !  length
				OUR_OSTYPE,	!Operating system type
				OUR_FILESYS,	!File system type
				6,		!DAP version 6
				0,		!ECO #  (DAP 6.0)
				0,		!Customer version #
				1,		!Release 1 of software
				0,		!User software ver #
				!SYSCAP fields follow
                                %O'243',%O'340',%O'361',%O'360',%O'206',%O'55'
						!Sequential organization
                                                !Relative organization
						!Sequential access

                                                !DAP message blocking
						!DAP message blocking over rsp
                                                !Len256 field

                                                !Directory list
						!DTM attr. ext. msg
						!PROT attr. ext. msg

                                                !FOP spool
                                                !FOP submit

                                                !BITCNT
                                                !RENAME
                                                !Wildcard
                                                !NAME message
			)):BYTE8VECTOR;

GLOBAL BIND CFGLEN=17;

GLOBAL D_CFG: $XPN_DESCRIPTOR(BINARY_DATA=(CFGLEN,CFGMSG,BYTES));
                                        ! Descriptor for config message
GLOBAL D_SKIP: $XPN_DESCRIPTOR(BINARY_DATA=(3,UPLIT(CHAR8(DAP$K_CONTINUE,
                                                          0,
                                                          DAP$K_CON_SKP))));
%IF %BLISS(BLISS36)
%THEN
GLOBAL D_CFGTAIL: $XPN_DESCRIPTOR(BINARY_DATA=(CFGLEN-4,CFGMSG+1,BYTES));
                  ! Descriptor for part of config message after buffer size
%ELSE
GLOBAL D_CFGTAIL: $XPN_DESCRIPTOR(BINARY_DATA=(CFGLEN-4,CFGMSG[4],BYTES));
                  ! Descriptor for part of config message after buffer size
%FI

GLOBAL BIND ACKMSG=PLIT(CHAR8(DAP$K_ACK,0));
		!Acknowledge
GLOBAL D_ACK: $XPN_DESCRIPTOR(BINARY_DATA=(2,CH$PTR(ACKMSG,0,8)));
                                        ! Descriptor for Ack message
%IF FTPASSIVE
%THEN
GLOBAL BIND ACCOMP_RESP=PLIT(CHAR8(DAP$K_ACCESS_COMPLETE,
                                   DAP$K_ACCOMP_RESPONSE));
GLOBAL BIND ACCOMP_RESP_LEN=3;
GLOBAL D_ACM: $XPN_DESCRIPTOR(STRING=(ACRLEN,CH$PTR(ACRMSG,0,8)));
%FI !FTPASSIVE

OWN D_NULL: $STR_DESCRIPTOR(STRING=%CHAR(0));


! Runtime conditionals for workarounds (to other systems' bugs)
GLOBAL
    T20BUG: BITVECTOR[16] INITIAL(-1),  ! Bit map for TOPS-20 workarounds
    VMSBUG: BITVECTOR[16] INITIAL(-1),  !         for VMS
    RSXBUG: BITVECTOR[16] INITIAL(-1),  !         for RSX
    RSTBUG: BITVECTOR[16] INITIAL(-1),  !         for RSTS
    RTBUG:  BITVECTOR[16] INITIAL(-1),  !         for RT11
    IASBUG: BITVECTOR[16] INITIAL(-1),  !         for IAS
    T10BUG: BITVECTOR[16] INITIAL(-1);  !         for TOPS-10
GLOBAL ROUTINE DAP$GET_CONFIG(DD,C)=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Process a CONFIG message and save the information contained therein
!       into the configuration block
!
! FORMAL PARAMETERS:
!
!       DD:     A DAP message descriptor
!       C:      A Configuration Block
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	Configuration block is set up
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	DAP Message type of message we got.
!
! SIDE EFFECTS:
!
!	NONE
!
!--
	BEGIN				
	LOCAL MTYPE;			!DAP message type
        MAP DD: REF $DAP_DESCRIPTOR,
            C: REF $CONFIG;

        IF (MTYPE=GET_HEADER(DD[$])) NEQ DAP$K_CONFIG
	THEN RETURN .MTYPE;

	C[CONFIG$H_BUFSIZ]=GET_2BYTE(DD[$]);	!Maximum DAP message size
	C[CONFIG$B_OSTYPE]=GET_BYTE(DD[$]);	!What are we talking to
	C[CONFIG$B_FILESYS]=GET_BYTE(DD[$]);	!File system type
	C[CONFIG$B_VERSION]=GET_BYTE(DD[$]);	!DAP Version # of remote system
	C[CONFIG$B_ECONUM]=GET_BYTE(DD[$]);	!DAP ECO #
	C[CONFIG$B_USRNUM]=GET_BYTE(DD[$]);	!Customer version # for DAP
	C[CONFIG$B_SOFTVER]=GET_BYTE(DD[$]);	!Version of cusp
	C[CONFIG$B_USRSOFT]=GET_BYTE(DD[$]);	!User cusp version #
	DAP$GET_BITVECTOR(DD[$],C[CONFIG$V_SYSCAP],12);	!SYSCAP bits
					!Message was longer than it should be
        .MTYPE                          !Return what we got
	END;				!End of GETCFG
GLOBAL ROUTINE DAP$GET_ATTRIBUTES(DD,FAB)=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Process ATTRIBUTES, ATTRIBUTES extensions, NAME and ACCESS messages
!	Returns on receipt of ACK or ACCESS (or NAME if DAP$K_RENAME)
!
! FORMAL PARAMETERS:
!
!	DD: A DAP message descriptor
!       FAB: A (RMS) FAB
!
! ROUTINE VALUE:
!
!	DAP Operator code if successful, Signal error otherwise
!
! SIDE EFFECTS:
!
!       Message(s) will have been read.
!
!--
BEGIN				!Expecting ATTRIBUTES, ACCESS, NAME, ACK,
				!or any of the Attributes extensions
MAP DD: REF $DAP_DESCRIPTOR,
    FAB: REF $FAB_DECL;

BIND DIB=.FAB[FAB$A_DIB]: $DIB;                 ! DAP information block
BIND CONFIG=.DIB[DIB$A_CONFIG]: $CONFIG;        ! Configuration block

LOCAL MTYPE: INITIAL(-1);               !DAP message type
LOCAL OMTYPE;

LOCAL NAMETYPES_SEEN: BITVECTOR[21] INITIAL(0); ! Types of Name messages seen

WHILE 1 DO
	BEGIN
        OMTYPE=.MTYPE;
        MTYPE=GET_HEADER(DD[$]);

	SELECTONE .MTYPE OF SET

	[DAP$K_ATTRIBUTES]:
		BEGIN
		LOCAL ATTMENU: BITVECTOR[42] INITIAL(0),
                      DATATYPE: BITVECTOR[14] INITIAL(0),
                      ORG: INITIAL(0),
                      RFM: INITIAL(0),
                      RAT: BITVECTOR[21] INITIAL(0),
                      BLS: INITIAL(0),
                      MRS: INITIAL(0),
                      ALQ: INITIAL(0),
                      BKS: INITIAL(0),
                      FSZ: INITIAL(0),
                      MRN: INITIAL(0),
                      RUNSYS: VECTOR[CH$ALLOCATION(40)]
                              INITIAL(REP CH$ALLOCATION(40) OF (0)),
                      DEQ: INITIAL(0),
                      FOP: BITVECTOR[42] INITIAL(0),
                      BSZ: INITIAL(0),
                      DEV: BITVECTOR[42] INITIAL(0),
                      SDC: BITVECTOR[42] INITIAL(0),
                      LRL: INITIAL(0),
                      HBK: INITIAL(0),
                      EBK: INITIAL(0),
                      FFB: INITIAL(0),
                      SBN: INITIAL(0);

		DAP$GET_BITVECTOR(DD[$],ATTMENU,6);	!Attributes menu bits

		IF .ATTMENU[DAP$V_ATTMENU_DAT]
                THEN DAP$GET_BITVECTOR(DD[$],DATATYPE,2);

		IF .ATTMENU[DAP$V_ATTMENU_ORG]    ! File Organization
                THEN
                    BEGIN
                    ORG=GET_BYTE(DD[$]);
                    FAB[FAB$Z_ORG]=$DAP_TRANSLATE_VALUE(.ORG,
                                                        DAP$K_ORG_,FAB$K_ORG_,
                                                        SEQ,REL,IDX,HSH);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_RFM]    ! Record Format
                THEN
                    BEGIN
                    RFM=GET_BYTE(DD[$]);
                    FAB[FAB$Z_RFM]=$DAP_TRANSLATE_VALUE(.RFM,
                                                        DAP$K_RFM_,FAB$K_RFM_,
                                                        UDF,FIX,VAR,
                                                        VFC,STM,LSA);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_RAT]    ! Record Attributes
                THEN
                    BEGIN
                    RAT=GET_BYTE(DD[$]);
                    $DAP_MOVE_BITS(RAT,DAP$V_RAT_,FAB,FAB$V_RAT_,
                                   FTN,CR,PRN,BLK,LSA);
                    END;

%BLISS36(
                IF .RAT[DAP$V_RAT_LSA] THEN FAB[FAB$Z_RFM]=FAB$K_RFM_LSA;
                                        ! Line-Sequenced Ascii
                                        ! is a Record Format on the 10 & 20
                                        ! and a Record Attribute elsewhere
) !End %BLISS36


		IF .ATTMENU[DAP$V_ATTMENU_BLS]
                THEN BLS=GET_2BYTE(DD[$])    ! Physical Block Size
                ELSE BLS=512;                ! default

		IF .ATTMENU[DAP$V_ATTMENU_MRS]
                THEN FAB[FAB$H_MRS]=GET_2BYTE(DD[$]);   ! Maximum Record Size

		IF .ATTMENU[DAP$V_ATTMENU_ALQ]            ! Allocation Quantity
		THEN
                    BEGIN                             ! in blocks
                    ALQ=GET_LONGWORD(DD[$]);          ! of (BLS) bytes

                    ! Convert blocks to pages if old TOPS-20 non-RMS FAL
                    !  New FAL has FILESYS of RMS-20                ![13]
                    IF .FAB[FAB$V_REMOTE]
                    AND (.CONFIG[CONFIG$B_FILESYS] EQL DAP$K_FILESYS_TOPS20)
                    THEN ALQ=.ALQ/4;

                    FAB[FAB$G_ALQ]=.ALQ;
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_BKS]            ! Bucket Size
		THEN FAB[FAB$Z_BKS]=GET_BYTE(DD[$]);

		IF .ATTMENU[DAP$V_ATTMENU_FSZ]  ! Fixed Header Size
		THEN	BEGIN                   ! (of VFC record)
                        FSZ=GET_BYTE(DD[$])
			END;

		IF .ATTMENU[DAP$V_ATTMENU_MRN]  ! Maximum Record Number
		THEN    FAB[FAB$G_MRN]=GET_LONGWORD(DD[$]);
                                        
		IF .ATTMENU[DAP$V_ATTMENU_RUN]  ! Runtime System
                THEN DAP$GET_VARIABLE_STRING(DD[$],CH$PTR(RUNSYS),40);

		IF .ATTMENU[DAP$V_ATTMENU_DEQ]  ! Default Extension Quantity
		THEN DEQ=GET_2BYTE(DD[$]);

		IF .ATTMENU[DAP$V_ATTMENU_FOP]            ! File Options
                THEN
                    BEGIN
                    DAP$GET_BITVECTOR(DD[$],FOP,6);
                    $DAP_MOVE_BITS(FOP,DAP$K_FOP_,FAB,FAB$V_FOP_,
                                   RWO,RWC,POS,DLK,LCK,
                                   CTG,SUP,NEF,TMP,MKD,DMO,
                                   WCK,RCK,CIF,LKO,SQO,MXV,SPL,
                                   SCF,DLT,CBT,WAT,DFW,TEF,DRJ);
                    END;
                                                 
		IF .ATTMENU[DAP$V_ATTMENU_BSZ]
                THEN
                    BEGIN
                    FAB[FAB$Z_BSZ]=BSZ=GET_BYTE(DD[$]);	!Byte size
                    END;

                IF .ATTMENU[DAP$V_ATTMENU_DEV]
                THEN
                    BEGIN
                    DAP$GET_BITVECTOR(DD[$],DEV,6);	!Device characteristics
                    $DAP_MOVE_BITS(DEV,DAP$V_DEV_,FAB,FAB$V_DEV_,
                                   REC,CCL,TRM,MDI,SDI,SQD,NUL,
                                   FOD,SHR,SPL,MNT,DMT,ALL,IDV,
                                   ODV,SWL,AVL,ELG,MBX,RTM,RAD,
                                   RCK,WCK,FOR,NET,GEN);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_SDC]
                THEN
                    BEGIN
		    DAP$GET_BITVECTOR(DD[$],SDC,6);	
                    $DAP_MOVE_BITS(SDC,DAP$V_DEV_,FAB,FAB$V_SHR_,
                                   REC,CCL,TRM,MDI,SDI,SQD,NUL,
                                   FOD,SHR,SPL,MNT,DMT,ALL,IDV,
                                   ODV,SWL,AVL,ELG,MBX,RTM,RAD,
                                   RCK,WCK,FOR,NET,GEN);
                    END;		! spooling device characteristics

		IF .ATTMENU[DAP$V_ATTMENU_LRL]
                THEN
                    BEGIN
                    LRL=GET_2BYTE(DD[$]);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_HBK]
                THEN
                    BEGIN
                    HBK=GET_LONGWORD(DD[$]);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_EBK]
                THEN
                    BEGIN
                    EBK=GET_LONGWORD(DD[$]);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_FFB]
                THEN
                    BEGIN
                    FFB=GET_2BYTE(DD[$]);
                    END;

		IF .ATTMENU[DAP$V_ATTMENU_SBN]
                THEN
                    BEGIN
                    SBN=GET_LONGWORD(DD[$]);
                    END;
		END;                    ! End of Attributes Message

	[DAP$K_DATE_TIME]:		!Date & time extension message
		BEGIN
		LOCAL DTMSTR: VECTOR[CH$ALLOCATION(18)];
                LOCAL D_DTMSTR: $STR_DESCRIPTOR();
		LOCAL DTMMENU: BITVECTOR[14];	!Menu for this message
                LOCAL XABDAT: REF $XABDAT_DECL; ! Address of Date/Time XAB
                LOCAL RVN;              ! Revision number

		CLEARV (DTMMENU);
                
                $STR_DESC_INIT(DESC=D_DTMSTR, STRING=(18,CH$PTR(DTMSTR)));

                ! Find the Date/Time XAB, if any
                XABDAT=.FAB[FAB$A_XAB]; ! Head of XAB chain

                WHILE .XABDAT[XABDAT$H_BID] NEQ XABDAT$K_BID
                DO (IF (XABDAT=.XABDAT[XABDAT$A_NXT]) EQL 0 THEN EXITLOOP);

                IF .XABDAT NEQ 0        ! If we found a Date/Time XAB
                THEN
                    BEGIN
                    DAP$GET_BITVECTOR(DD[$],DTMMENU,2);

                    IF .DTMMENU[DAP$V_DTM_CDT]  ! Creation date time
                    THEN    BEGIN
                            DAP$GET_DATE(DD[$],CH$PTR(DTMSTR));
                            XABDAT[XABDAT$G_CDT]=S$STRDT(D_DTMSTR);
                            END;

                    IF .DTMMENU[DAP$V_DTM_RDT]  ! Read date time
                    THEN    BEGIN
                            DAP$GET_DATE(DD[$],CH$PTR(DTMSTR));
                            XABDAT[XABDAT$G_RDT]=S$STRDT(D_DTMSTR); 
                            END;

                    IF .DTMMENU[DAP$V_DTM_EDT]  ! Scratch date time
                    THEN    BEGIN   
                            DAP$GET_DATE(DD[$],CH$PTR(DTMSTR));
                            XABDAT[XABDAT$G_EDT]=S$STRDT(D_DTMSTR);
                            END;
                    IF .DTMMENU[DAP$V_DTM_RVN]  ! Revision number
                    THEN RVN=DAP$GET_2BYTE(DD[$]);

                    IF .DTMMENU[DAP$V_DTM_BDT]  ! Backup date time
                    THEN    BEGIN   
                            DAP$GET_DATE(DD[$],CH$PTR(DTMSTR));
                            !When we put this in the RMS block we can save it
                            !XABDAT[XABDAT$G_BDT]=S$STRDT(D_DTMSTR);
                            END;

                    IF .DTMMENU[DAP$V_DTM_PDT]  ! Internal date time
                    THEN    BEGIN   
                            DAP$GET_DATE(DD[$],CH$PTR(DTMSTR));
                            !When we put this in the RMS block we can save it
                            !XABDAT[XABDAT$G_PDT]=S$STRDT(D_DTMSTR);
                            END;

                    IF .DTMMENU[DAP$V_DTM_ADT]  ! Access date time	![12]
                    THEN    BEGIN   
                            DAP$GET_DATE(DD[$],CH$PTR(DTMSTR));
                            !When we put this in the RMS block we can save it
                            !XABDAT[XABDAT$G_ADT]=S$STRDT(D_DTMSTR);
                            END;

                    END
                ELSE DAP$EAT_MESSAGE(DD[$]);           ! No place to put it
		END;

%(
	[DAP$K_PROTECT]:		!Protection extension message
		BEGIN
		LOCAL PROT;
		LOCAL PROMENU: BITVECTOR[14];	!Menu 
		LOCAL OWNER: VECTOR[CH$ALLOCATION(40)]; 
		CLEARV(PROMENU);
		DAP$GET_BITVECTOR(DD[$],PROMENU,2);	!Get the menu

		IF .PROMENU[PRO_OWNER]
		THEN	DAP$GET_VARIABLE_STRING(DD[$],CH$PTR(OWNER),40);

		IF .PROMENU[PRO_PROTSYS]
		THEN
                    BEGIN
                    PROT=0;
                    DAP$GET_BITVECTOR(DD[$],PROT,3);	!System protection
        	    %IF %DECLARED(XABPRO$Z_SYS)
		    %THEN XABPRO[XABPRO$Z_SYS]=PRO_DS(.PROT);
                    %FI
                    END;

		IF .PROMENU[PRO_PROTOWN]
		THEN
                    BEGIN
                    PROT=0;
                    DAP$GET_BITVECTOR(DD[$],T,3);	!Owner protection
		    XABPRO[XABPRO$Z_OWN]=PRO_DS(.T);
                    END;

		IF .PROMENU[PRO_PROTGRP]
		THEN
                    BEGIN
                    PROT=0;
                    DAP$GET_BITVECTOR(DD[$],T,3);	!Owner protection
		    XABPRO[XABPRO$Z_GRP]=PRO_DS(.T);
                    END;

		IF .PROMENU[PRO_PROTWLD]
		THEN
                    BEGIN
                    PROT=0;
                    DAP$GET_BITVECTOR(DD[$],T,3);	!Owner protection
		    XABPRO[XABPRO$Z_WLD]=PRO_DS(.T);
                    END;
		END;
)%
	[DAP$K_NAME]:
		BEGIN
                BIND NAM=.FAB[FAB$A_NAM]: $NAM_DECL;

		LOCAL FILESPEC: VECTOR[CH$ALLOCATION(255)];	!Store filespec
		LOCAL NAMETYPE: BITVECTOR[21];
                LOCAL NDS,              ! Length of nodeid
                      DVS,              ! Length of device
                      DIS,              ! Length of directory
                      NAS;              ! Length of name
                LOCAL DELIM;

                CLEARV(NAMETYPE);

                IF NAM EQL 0 THEN SIGNAL(RMS$_NAM,0,FAB[$]);
                ! Must have a NAM block

		DAP$GET_BITVECTOR(DD[$],NAMETYPE,3);

                IF (.NAMETYPE AND .NAMETYPES_SEEN) NEQ 0
                THEN RETURN DAP$UNGET_HEADER(DD[$]);
                ! If this is the second NAME message of this type for this call
                ! then it must be for the next file and should not be
                ! read until the next call (Directory List)

                NAMETYPES_SEEN=.NAMETYPES_SEEN OR .NAMETYPE;

                IF .NAMETYPE[DAP$K_NAMETYPE_STR]        ! Structure
                THEN
                    BEGIN
                    DAP$GET_VARIABLE_STRING(DD[$],CH$PTR(NAM[NAM$T_DVI]),
                                            DEVICE_NAME_LENGTH);
                    NAM[NAM$V_CHA_STR]=1;
                    NAM[NAM$V_FNB_WILDCARD]=1; ! Something is wildcarded
                                               ! (not necessarily this)
                                               ! (3-part name indicates this)
                    END;

                IF .NAMETYPE[DAP$K_NAMETYPE_DIR]        ! Directory
                THEN
                    BEGIN
                    NAM[NAM$V_CHA_DIR]=1;
                    DAP$GET_VARIABLE_STRING(DD[$],CH$PTR(NAM[NAM$T_DIR]),
                                            DIRECTORY_NAME_LENGTH);
                    NAM[NAM$V_FNB_WILDCARD]=1; ! Something is wildcarded
                    END;

                IF .NAMETYPE[DAP$K_NAMETYPE_NAM]        ! File name
                THEN
                    BEGIN
                    LOCAL D_FILESPEC: $STR_DESCRIPTOR(CLASS=DYNAMIC);
                    LOCAL BD_FILESPEC: $STR_DESCRIPTOR(CLASS=BOUNDED);
                    
                    $STR_DESC_INIT(DESC=D_FILESPEC, CLASS=DYNAMIC);
                    $XPO_GET_MEM(DESC=D_FILESPEC, CHARACTERS=255);
                                        
                    NAS=DAP$GET_VARIABLE_STRING(DD[$],  ! Get file name in temp
                                                .D_FILESPEC[STR$A_POINTER],
                                                255);
                    $STR_DESC_INIT(DESC=BD_FILESPEC, CLASS=BOUNDED,
                                   STRING=(.NAS,.D_FILESPEC[STR$A_POINTER]));

                    $STR_SCAN(REMAINDER=BD_FILESPEC, SUBSTRING=BD_FILESPEC,
                              DELIMITER=DELIM,
                              STOP='.;<');
                    $STR_COPY(STRING=$STR_CONCAT(BD_FILESPEC,D_NULL),
                              TARGET=(FILE_NAME_LENGTH,
                                      CH$PTR(NAM[NAM$T_NAM])));

                    IF .DELIM EQL %C'.'
                    THEN
                        BEGIN
                        BD_FILESPEC[STR$H_LENGTH]=
                         .BD_FILESPEC[STR$H_LENGTH]+1; ! skip delimiter
                        $STR_SCAN(REMAINDER=BD_FILESPEC,
                                  SUBSTRING=BD_FILESPEC,
                                  DELIMITER=DELIM,
                                  STOP='.;<');
                        $STR_COPY(STRING=
                                   $STR_CONCAT('.',BD_FILESPEC,D_NULL),
                                  TARGET=(FILE_NAME_LENGTH,
                                          CH$PTR(NAM[NAM$T_EXT])),
                                  OPTION=TRUNCATE);
                        END;
                    IF (.DELIM EQL %C';') OR (.DELIM EQL %C'.')
                    THEN                ! Version/Generation number
                        BEGIN
                        $STR_SCAN(REMAINDER=BD_FILESPEC,
                                  SUBSTRING=BD_FILESPEC,
                                  DELIMITER=.DELIM,
                                  SPAN=';.0123456789-*');  ! Generation number

                        ! Now Copy the generation number into the name block
                        ! if it really is a generation number,
                        ! i.e. .### or ;###.
                        ! If we really got ;T or ;Afoo or ;P#####, ignore it.

                        IF .BD_FILESPEC[STR$H_LENGTH] GTR 1
                        THEN $STR_COPY(STRING=$STR_CONCAT(BD_FILESPEC,D_NULL),
                                       TARGET=(RMS$K_VERSION_SIZE,
                                               CH$PTR(NAM[NAM$T_VER])),
                                       OPTION=TRUNCATE);
                        END;

                    DVS=ASCIZ_LEN(CH$PTR(NAM[NAM$T_DVI]));
                    DIS=ASCIZ_LEN(CH$PTR(NAM[NAM$T_DIR]));
                    NDS=ASCIZ_LEN(CH$PTR(NAM[NAM$T_NODE]));

                        BEGIN           ! Build resultant string
                        LOCAL D_RESULTANT: $STR_DESCRIPTOR(CLASS=BOUNDED);
                        $STR_DESC_INIT(DESC=D_RESULTANT, CLASS=BOUNDED,
                                       STRING=(.NAM[NAM$H_RSS],
                                               .NAM[NAM$A_RSA]));

                        IF (.NDS+.DVS+.DIS+.NAS) GTR .NAM[NAM$H_RSS]
                        THEN SIGNAL(RMS$_NAM, 0, FAB[$]);       ![11] Won't fit

                        ! Concatenate the Device, Directory, and filespec
                        $STR_COPY(STRING=
                                     $STR_CONCAT(
                                         (.NDS,CH$PTR(NAM[NAM$T_NODE])), ![11]
                                         (.DVS,CH$PTR(NAM[NAM$T_DVI])),
                                         (.DIS,CH$PTR(NAM[NAM$T_DIR])),
                                         (.NAS,.D_FILESPEC[STR$A_POINTER])),
                                  TARGET=D_RESULTANT,
                                  OPTION=TRUNCATE);

                        $XPO_FREE_MEM(STRING=D_FILESPEC);

                        NAM[NAM$H_RSL]=.D_RESULTANT[STR$H_LENGTH];
                        END;
                    END;

                IF .NAMETYPE[DAP$K_NAMETYPE_FSP]        ! Resultant filespec
                THEN
                    BEGIN                           ! Store resultant filespec
                    LOCAL ressize;                  ! Length of resultant
                    IF (ressize=DAP$GET_BYTE(DD[$])) GTR 0    ! if non-null
                    THEN
                        BEGIN
                        LOCAL nodedesc: $STR_DESCRIPTOR();
                        $STR_DESC_INIT
                             (DESC=nodedesc,
                              STRING=ASCIZ_STR(CH$PTR(NAM[NAM$T_NODE])));

                        IF .ressize+.nodedesc[STR$H_LENGTH] GEQ .NAM[NAM$H_RSS]
                        THEN            ! Make sure it will fit
                            SIGNAL(RMS$_NAM, 0, FAB[$]) ![11] Too big
                        ELSE
                            BEGIN
                            LOCAL rptr,
                                  rlen;
                            $STR_COPY(STRING=NODEDESC,
                                      TARGET=(.NODEDESC[STR$H_LENGTH],
                                              .NAM[NAM$A_RSA]));

                            rlen=.NAM[NAM$H_RSS]-.nodedesc[str$h_length];
                            rptr=CH$PLUS(.NAM[NAM$A_RSA],
                                         .nodedesc[str$h_length]);

                            DAP$UNGET_BYTE(DD[$]);      ! string getter needs count
                            NAM[NAM$H_RSL]=DAP$GET_VARIABLE_STRING
                                               (DD[$],.rptr,.rlen)
                                           +.nodedesc[STR$H_LENGTH];
                            END;
                        END;
                    END;

                %IF FTPASSIVE           ! FAL only
                %THEN
		IF .ACCFUNC EQL DAP$K_RENAME
		THEN	BEGIN		!This is for a new name
			ACCESS(FAB[$]);	        !Try to rename the file
			RETURN DAP$K_NAME;      !end of setup sequence
			END;
                %ERROR('Passive Rename not implemented')
                %FI


		END;

%IF FTPASSIVE %THEN
	[DAP$K_ACCESS]:
		BEGIN
		LOCAL FILESPEC: VECTOR[CH$ALLOCATION(200)];
		LOCAL	DISPLAY: BITVECTOR[28],	!DISPLAY field for attributes to return
			PASSWORD: VECTOR[CH$ALLOCATION(41)],
                        ACCFUNC,
                        ACCOPT: BITVECTOR[28],
                        FAC: BITVECTOR[28],
                        SHR: BITVECTOR[28];


		ACCFUNC=GET_BYTE(DD[$]);	!OPEN/CREATE/ERASE/RENAME

		DAP$GET_BITVECTOR(DD[$],N[ACCOPT],5);	!Access options

		DAP$GET_VARIABLE_STRING(DD[$],CH$PTR(FILESPEC),200);
                                        !Store remote filespec in temp

		IF .DD[DAP$H_LENGTH] GTR 0
		THEN
                    BEGIN
                    DAP$GET_BITVECTOR(DD[$],FAC,3);	!File access options
                    $DAP_MOVE_BITS(FAC,DAP$V_FAC_,FAB,FAB$V_FAC_,
                                   PUT,GET,DEL,UPD,TRN,
                                   BIO,BRO,APP);
                    END;

		IF .DD[DAP$H_LENGTH] GTR 0
		THEN
                    BEGIN
                    DAP$GET_BITVECTOR(DD[$],SHR,3);	!Shared operations
                    $DAP_MOVE_BITS(FAC,DAP$V_FAC_,FAB,FAB$V_SHR_,
                                   PUT,GET,DEL,UPD,TRN,
                                   BIO,BRO,APP);
    

		IF .DD[DAP$H_LENGTH] GTR 0
		THEN DAP$GET_BITVECTOR(DD[$],DISPLAY,4);
                !What attributes should we return?
                ! IGNORE FOR NOW

		IF .DD[DAP$H_LENGTH] GTR 0
		THEN DAP$GET_VARIABLE_STRING(DD[$],CH$PTR(PASSWORD),40);
                !Password for file access

		!If this is a RENAME, then get a NAME message
		!Otherwise, try to do the access
		IF .WAIT_FOR_NAME EQL 0
		THEN ACCESS(FAB[$]);		!Try to do it

		IF (.N[ACCFUNC] EQL DAP$K_OPEN)
                OR (.N[ACCFUNC] EQL DAP$K_CREATE)
		THEN
			BEGIN	!Return attributes of our file
			D$PATT(DD[$],FAB[$]);	!Build attributes & send
			DAP$PUT_MESSAGE(DD[$]);	!Force it out
			END;
		ACKNOWLEDGE;	!Otherwise just ACK
			!The documentation is ambiguous here
			!as to what response should occur for RENAME or DELETE
		N[GOT_ACC]=1;		!Remember we got it
		IF .WAIT_FOR_NAME EQL 0
		THEN RETURN DAP$K_ACCESS;
		END; !DAP_ACC
%FI	!FTPASSIVE

	[DAP$K_STATUS]:			! Some sort of error from other end
		BEGIN
                BIND C=D$GSTS(DD[$]);
                SIGNAL(C);
                RETURN C
                END;

        [DAP$K_ACCESS_COMPLETE]:        ! Rename & Delete would return ACM
                BEGIN
                BIND DIB=.FAB[FAB$A_DIB]: $DIB;
                LOCAL CMPFUNC;
                LOCAL FOP: BITVECTOR[42];

                CMPFUNC=DAP$GET_BYTE(DD[$]);
                IF .CMPFUNC NEQ DAP$K_ACCOMP_RESPONSE
                THEN SIGNAL(RMS$_DPE,0,FAB[$]);

                DIB[DIB$V_ACCESS_ACTIVE]=0;     ! Access is no longer active

                !% FAL WORKAROUND
                ! If all we get is an ACCESS COMPLETE (without any attrs first)
                ! Then assume we cannot access the directory.
                ! For some reason TOPS-10 & TOPS-20 FALs do not give a status
                ! for this, but merely return immediate ACCESS COMPLETE!!!
                ! RSTS does exactly the same thing on file-not-found

                IF (.OMTYPE EQL -1)       ! First message of this call?
                AND (.T20BUG[T20_BUG_NO_DIR_PRV] ! And workaround enabled
                     OR .RSTBUG[RST_BUG_NO_DIR_FNF])
                THEN
                    BEGIN
                    SELECT .CONFIG[CONFIG$B_OSTYPE] OF
                       SET
                       [DAP$K_TOPS20]: FAB[FAB$H_STS]=RMS$_PRV;
                       [DAP$K_RSTS]:   FAB[FAB$H_STS]=RMS$_FNF;
                       [DAP$K_TOPS20, DAP$K_RSTS]:
                            SIGNAL(.FAB[FAB$H_STS],0,FAB[$]);
                       TES;
                    END;

                DAP$GET_BITVECTOR(DD[$],FOP,6);
                $DAP_MOVE_BITS(FOP,DAP$K_FOP_,FAB,FAB$V_FOP_,
                               RWO,RWC,POS,DLK,LCK,
                               CTG,SUP,NEF,TMP,MKD,DMO,
                               WCK,RCK,CIF,LKO,SQO,MXV,SPL,
                               SCF,DLT,CBT,WAT,DFW,TEF,
                               DRJ);

                IF .DD[DAP$H_BYTES_REMAINING] GTR 0
                THEN
                    BEGIN
                    LOCAL CHECKSUM;
                    CHECKSUM=DAP$GET_2BYTE(DD[$]);
                    !? Can check checksum here when we implement that stuff
                    END;

                RETURN DAP$K_ACCESS_COMPLETE;
                END;

	[DAP$K_ACK]:
                RETURN DAP$K_ACK;       ! Normal exit from this routine
	[OTHERWISE]:
		BEGIN
		DAP_ERROR(DD[$],DAP$K_MAC_SYNC,.DD[DAP$B_OPERATOR]);
                RETURN .DD[DAP$B_OPERATOR]
		END;
	TES;
	END;	!WHILE 1
.MTYPE                           ! Return message type if we ever get here
END;  !End of DAP$GET_ATTRIBUTES (D$GATT) (process ATTRIBUTES)
GLOBAL ROUTINE DAP$PUT_CONFIG(DD: REF $DAP_DESCRIPTOR, BUFSIZ): NOVALUE=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Build a CONFIG message, using specified buffer size
!
! FORMAL PARAMETERS:
!
!       DD:     A DAP message descriptor
!       BUFSIZ: Buffer size to send to other system
!
!--
    BEGIN				
    INIT_MESSAGE(DD[$]);                ! 
    DD[DAP$B_OPERATOR]=DAP$K_CONFIG;    ! Build header
    DAP$PUT_HEADER(DD[$]);              !
    DAP$PUT_2BYTE(DD[$],.BUFSIZ);       ! Put buffersize
    DAP$PUT_STRING(DD[$],D_CFGTAIL);    ! and rest of message
    END;                                ! DAP$PUT_CONFIG
GLOBAL ROUTINE DAP$PUT_ATTRIBUTES(DD,FAB): NOVALUE=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Build attributes message from associated file block & send it.
!
! FORMAL PARAMETERS:
!
!       DD: Address of a DAP descriptor
!       FAB: Address of RMS FAB
!
! IMPLICIT OUTPUTS:
!
!	An ATTRIBUTES message is put in the output buffer.
!
!--
BEGIN
MAP DD: REF $DAP_DESCRIPTOR,
    FAB: REF $FAB_DECL;
BIND TYP=.FAB[FAB$A_TYP]: $TYP_DECL;
BIND DIB=.FAB[FAB$A_DIB]: $DIB;
BIND CONFIG=.DIB[DIB$A_CONFIG]: $CONFIG;

LOCAL
	MLENGTH: INITIAL(0),		!Length of this message (data portion)
	ATTMENU: BITVECTOR[42] INITIAL(0),      !Attributes menu field
	DATATYPE: BITVECTOR[14] INITIAL(0),     !Data representation
	ORG: INITIAL(0),			!File organization
	RFM: INITIAL(0),			!Record format
	RAT: BITVECTOR[21] INITIAL(0),		!Record attributes
	BLS: INITIAL(512),     ![4] default=512	!Block size
	MRS: INITIAL(0),			!Record size
	ALQ: INITIAL(0),                        !File size
	BKS: INITIAL(0),			!Bucket size
	FSZ: INITIAL(0),			!Fixed portion size
	MRN: BYTE8VECTOR[6] INITIAL(0),         !Max record number
	RUNSYS: BYTE8VECTOR[41] INITIAL(0),     !Runtime system
	DEQ: INITIAL(0),			!Default extension quantity
	BSZ: INITIAL(0),			!Byte size
	DEV: BITVECTOR[42] INITIAL(0),		!Device characteristics
	SDC: BITVECTOR[42] INITIAL(0),		!Spooling dev characteristics
	NOK: INITIAL(0),
	NOA: INITIAL(0),
	NOR: INITIAL(0),
	CDT: BYTE8VECTOR[18] INITIAL(0),	!Create date
	RDT: BYTE8VECTOR[18] INITIAL(0),	!Update date
	EDT: BYTE8VECTOR[18] INITIAL(0),	!Scratch date
	OWNER: BYTE8VECTOR[40] INITIAL(0),
	PROTSYS: BITVECTOR[21] INITIAL(0),
	PROTOWN: BITVECTOR[21] INITIAL(0),
	PROTGRP: BITVECTOR[21] INITIAL(0),
	PROTWLD: BITVECTOR[21] INITIAL(0),
	FOP: BITVECTOR[42] INITIAL(0);


BSZ=.FAB[FAB$Z_BSZ];	!Byte size

! Set up DATATYPE
IF (TYP NEQ 0)
THEN CASE .TYP[TYP$H_CLASS] FROM 0 TO TYP$K_CLASS_MAX OF
    SET
    [0, TYP$K_CLASS_ASCII]:
	BEGIN
        DATATYPE[DAP$V_DATATYPE_ASCII]=1;
	BLS=OUR_BLOCK_SIZE*(%BPVAL/.BSZ);     ! Block size in bytes

        IF .FAB[FAB$Z_RFM] EQL FAB$K_RFM_VAR    ! If /ASCII/VARIABLE
        OR .FAB[FAB$Z_RFM] EQL FAB$K_RFM_FIX    ! or /ASCII/FIXED
        THEN RAT[DAP$V_RAT_CR]=1;               ! Assume implied CRLF 
        END;
    [TYP$K_CLASS_IMAGE]: DATATYPE[DAP$V_DATATYPE_IMAGE]=1;
    [TYP$K_CLASS_MACY11]:
        BEGIN
        DATATYPE[DAP$V_DATATYPE_IMAGE]=1;       ! Looks like image on remote
        !% RAT[DAP$V_RAT_MACY11]=1;
        !  Nobody supports this bit
        END;
    [OUTRANGE]: SIGNAL(DAP$_AOR,0,TYP);
    TES;


!% BSZ of other than 8 is not supported on non-36-bit systems
SELECT .CONFIG[CONFIG$B_OSTYPE] OF
SET
[DAP$K_TOPS20, DAP$K_TOPS10]: ;         ! OK
[OTHERWISE]: BSZ=0;                     ! Don't send byte size
TES;

! Device is a file-structured disk
DEV[DAP$V_DEV_MDI]=DEV[DAP$V_DEV_FOD]=DEV[DAP$V_DEV_SHR]
=DEV[DAP$V_DEV_MNT]=DEV[DAP$V_DEV_IDV]=DEV[DAP$V_DEV_ODV]
=DEV[DAP$V_DEV_AVL]=DEV[DAP$V_DEV_ELG]=DEV[DAP$V_DEV_RAD]=1;

ALQ=.FAB[FAB$G_ALQ];                    ! Allocation quantity


	!Turn on extension bits where needed & count # of bytes
	BEGIN
	LOCAL T;
	T=DAP$SIZE_BITVECTOR(DATATYPE,2,0);
	IF (.T GTR 0) THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_DAT]=1;	!Remember to send it
	   MLENGTH=.MLENGTH+.T;	!Add approprioate # of bytes
	   END;

        ORG=$DAP_TRANSLATE_VALUE(.FAB[FAB$Z_ORG],
                                 FAB$K_ORG_,DAP$K_ORG_,
                                 SEQ,REL,IDX,DIR);

	IF .ORG NEQ DAP$K_ORG_SEQ THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_ORG]=1;
	   MLENGTH=.MLENGTH+1;
	   END;

        RFM=$DAP_TRANSLATE_VALUE(.FAB[FAB$Z_RFM],
                                 FAB$K_RFM_,DAP$K_RFM_,
                                 UDF,FIX,VAR,VFC,STM,LSA);

	IF .RFM NEQ DAP$K_RFM_FIX THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_RFM]=1;
	   MLENGTH=.MLENGTH+1;
	   END;

        $DAP_MOVE_BITS(FAB,FAB$V_RAT_,RAT,DAP$V_RAT_,
                       FTN,CR,BLK,EFC,CBL,LSA);

	T=DAP$SIZE_BITVECTOR(RAT,3,0);
	IF .T GTR 0 THEN
            BEGIN
            ATTMENU[DAP$V_ATTMENU_RAT]=1;
            MLENGTH=.MLENGTH+.T;
            END;

        !
        ! BLS field
        !

	IF .BLS NEQ 512
        THEN ATTMENU[DAP$V_ATTMENU_BLS]=1;

        IF .RSXBUG[RSX_BUG_NOT_WANT_BLS]
        THEN
            BEGIN
            IF (.CONFIG[CONFIG$B_FILESYS] EQL DAP$K_FILESYS_FCS11)
            THEN ATTMENU[DAP$V_ATTMENU_BLS]=0;  ! Don't send BLS to this
            END;

        IF .ATTMENU[DAP$V_ATTMENU_BLS]  ! If we are sending BLS
	THEN MLENGTH=.MLENGTH+2;        ! allow 2 bytes for it
        
        !
        ! MRS field
        !

        MRS=.FAB[FAB$H_MRS];            ! Max record size

	IF .MRS NEQ 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_MRS]=1;
	   MLENGTH=.MLENGTH+2;
	   END;

	IF .ALQ NEQ 0 THEN
            BEGIN
	    ATTMENU[DAP$V_ATTMENU_ALQ]=1;
	    MLENGTH=.MLENGTH+5;
	    END;

	IF .BKS NEQ 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_BKS]=1;
	   MLENGTH=.MLENGTH+1;
	   END;

	IF .FSZ NEQ 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_FSZ]=1;
	   MLENGTH=.MLENGTH+1;
	   END;

	IF (T=.MRN[0]) NEQ 0 THEN
            BEGIN
	    ATTMENU[DAP$V_ATTMENU_MRN]=1;
	    MLENGTH=.MLENGTH+.T;
	    END;

	IF (T=.RUNSYS[0]) NEQ 0 THEN
            BEGIN
	    ATTMENU[DAP$V_ATTMENU_RUN]=1;
	    MLENGTH=.MLENGTH+.T;
	    END;

	IF .DEQ NEQ 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_DEQ]=1;
	   MLENGTH=.MLENGTH+2;
	   END;

        $DAP_MOVE_BITS(FAB,FAB$V_FOP_,FOP,DAP$V_FOP_,
                       RWO,RWC,POS,DLK,LCK,
                       CTG,SUP,NEF,TMP,MKD,DMO,
                       WCK,RCK,CIF,LKO,SQO,MXV,SPL,
                       SCF,DLT,CBT,WAT,%(DFW)% ,TEF,DRJ);  ! DFW not supported
                                                           ! by most FALs

	T=DAP$SIZE_BITVECTOR(FOP,6,0);
	IF .T GTR 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_FOP]=1;
	   MLENGTH=.MLENGTH+.T;
	   END;

	IF (.BSZ NEQ 0) THEN      ! Send BSZ unless 0
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_BSZ]=1;
	   MLENGTH=.MLENGTH+1;
	   END;

	T=DAP$SIZE_BITVECTOR(DEV,6,0);
	IF .T GTR 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_DEV]=1;
	   MLENGTH=.MLENGTH+.T;
	   END;

	T=DAP$SIZE_BITVECTOR(SDC,6,0);
	IF .T GTR 0 THEN
           BEGIN
	   ATTMENU[DAP$V_ATTMENU_SDC]=1;
	   MLENGTH=.MLENGTH+.T;
	   END;

	END;

MLENGTH=.MLENGTH+$DAP_SIZE_BITVECTOR(ATTMENU,6);

INIT_MESSAGE(DD[$]);
DD[DAP$B_OPERATOR]=DAP$K_ATTRIBUTES;    ! This is attributes message
DD[DAP$V_MFLAGS_LENGTH]=1;              ! We will send length field
DD[DAP$H_LENGTH]=.MLENGTH;              ! Set up message length in header

DAP$PUT_HEADER(DD[$]);                  ! Build the message header

DAP$PUT_BITVECTOR(DD[$],ATTMENU,6);			!Menu field

IF .ATTMENU[DAP$V_ATTMENU_DAT] THEN DAP$PUT_BITVECTOR(DD[$],DATATYPE,2);
IF .ATTMENU[DAP$V_ATTMENU_ORG] THEN PUT_BYTE(DD[$],.ORG);
IF .ATTMENU[DAP$V_ATTMENU_RFM] THEN PUT_BYTE(DD[$],.RFM);
IF .ATTMENU[DAP$V_ATTMENU_RAT] THEN DAP$PUT_BITVECTOR(DD[$],RAT,3);
IF .ATTMENU[DAP$V_ATTMENU_BLS] THEN PUT_2BYTE(DD[$],.BLS);
IF .ATTMENU[DAP$V_ATTMENU_MRS] THEN PUT_2BYTE(DD[$],.MRS);
IF .ATTMENU[DAP$V_ATTMENU_ALQ] THEN PUT_LONGWORD(DD[$],.ALQ);
IF .ATTMENU[DAP$V_ATTMENU_BKS] THEN PUT_BYTE(DD[$],.BKS);
IF .ATTMENU[DAP$V_ATTMENU_FSZ] THEN PUT_BYTE(DD[$],.FSZ);
IF .ATTMENU[DAP$V_ATTMENU_MRN] THEN PUT_LONGWORD(DD[$],.MRN);
IF .ATTMENU[DAP$V_ATTMENU_RUN]
THEN DAP$PUT_VARIABLE_COUNTED(DD[$],CH$PTR(RUNSYS,0,8));
IF .ATTMENU[DAP$V_ATTMENU_DEQ] THEN PUT_2BYTE(DD[$],.DEQ);
IF .ATTMENU[DAP$V_ATTMENU_FOP] THEN DAP$PUT_BITVECTOR(DD[$],FOP,6);
IF .ATTMENU[DAP$V_ATTMENU_BSZ] THEN PUT_BYTE(DD[$],.BSZ);
IF .ATTMENU[DAP$V_ATTMENU_DEV] THEN DAP$PUT_BITVECTOR(DD[$],DEV,6);
IF .ATTMENU[DAP$V_ATTMENU_SDC] THEN DAP$PUT_BITVECTOR(DD[$],SDC,6);

!Now send the DATE & TIME message if needed

%(
IF .C[CONFIG$V_DTM]
AND ((.CDT NEQ 0) OR (.RDT NEQ 0) OR (.EDT NEQ 0))
 THEN	BEGIN
	LOCAL DTMMENU: BITVECTOR[42];	!Menu for this message
	CLEARV(DTMMENU);	!initially 0
        INIT_MESSAGE(DD[$]);

	DD[DAP$H_MLENGTH]=1;		!The menu field is always sent
	IF .CDT NEQ 0 THEN
            BEGIN
            DTMMENU[DTM_CDT]=1;
            DD[DAP$H_MLENGTH]=19;
            END;

	IF .RDT NEQ 0 THEN
            BEGIN
            DTMMENU[DTM_RDT]=1;
            DD[DAP$H_MLENGTH]=.DD[DAP$H_MLENGTH]+18;
            END;

	IF .EDT NEQ 0 THEN
            BEGIN
            DTMMENU[DTM_EDT]=1;
            DD[DAP$H_MLENGTH]=.DD[DAP$H_MLENGTH]+18;
            END;

	DD[DAP$V_MFLAGS_LENGTH]=1;      !Length field present
        DAP$PUT_HEADER(DD[$]);

	DAP$PUT_BITVECTOR(DD[$],DTMMENU,6);	!Send the menu

	!Dates are always 18-character fields
	IF .DTMMENU[DTM_CDT] THEN PUT_18BYTE(CDT);	!Creation date
	IF .DTMMENU[DTM_RDT] THEN PUT_18BYTE(RDT);	!Access date
	IF .DTMMENU[DTM_EDT] THEN PUT_18BYTE(EDT);	!Scratch date
	END;	!of code to send DATE & TIME message

!
! Send PROTECTION message if needed
!
	BEGIN			!Send PROTECTION message if needed
	LOCAL	PROMENU: BITVECTOR[42];

	CLEARV	(PROMENU);
	DD[DAP$H_MLENGTH]=
                (1		!The menu is 1 byte long
		 +(IF (.OWNER[0] NEQ 0)
		   THEN	(PROMENU[PRO_OWNER]=1;.OWNER[0]+1)
		   ELSE 0)
		 +(LOCAL BC;	!Byte count for field
		   BC=DAP$SIZE_BITVECTOR(PROTSYS,3,0);
		   IF .BC GTR 0
		   THEN (PROMENU[PRO_PROTSYS]=1;.BC)
		   ELSE 0)
		 +(LOCAL BC;	!Byte count for field
		   BC=DAP$SIZE_BITVECTOR(PROTOWN,3,0);
		   IF .BC GTR 0
		   THEN (PROMENU[PRO_PROTOWN]=1;.BC)
		   ELSE 0)
		 +(LOCAL BC;	!Byte count for field
		   BC=DAP$SIZE_BITVECTOR(PROTGRP,3,0);
		   IF .BC GTR 0
		   THEN (PROMENU[PRO_PROTGRP]=1;.BC)
		   ELSE 0)
		 +(LOCAL BC;	!Byte count for field
		   BC=DAP$SIZE_BITVECTOR(PROTWLD,3,0);
		   IF .BC GTR 0
		   THEN (PROMENU[PRO_PROTWLD]=1;.BC)
		   ELSE 0));

	IF (.MLENGTH GTR 1) AND .CONFIG[CONFIG$V_PROTECTION]
	 THEN	BEGIN	!We need to send it
                INIT_MESAGE(DD[$]);
		DD[DAP$B_OPERATOR]=DAP$K_PROTECTION;    !Message type
		DD[DAP$V_MFLAGS_LENGTH]=1;              !Length field present
                DAP$PUT_HEADER(DD[$]);

		DAP$PUT_BITVECTOR(DD[$],PROMENU,6);     !Menu

		IF .PROMENU[PRO_OWNER]                  ! OWNER field
                THEN DAP$PUT_VARIABLE_COUNTED(DD[$],CH$PTR(OWNER,0,8));

		IF .PROMENU[PRO_PROTSYS]
                THEN DAP$PUT_BITVECTOR(DD[$],PROTSYS,3);	!SYSTEM

		IF .PROMENU[PRO_PROTOWN]
                THEN DAP$PUT_BITVECTOR(DD[$],PROTOWN,3);	!OWNER

		IF .PROMENU[PRO_PROTGRP]
                THEN DAP$PUT_BITVECTOR(DD[$],PROTGRP,3);	!GROUP

		IF .PROMENU[PRO_PROTWLD]
                THEN DAP$PUT_BITVECTOR(DD[$],PROTWLD,3);	!WORLD
		END;
	END;	!of code to send PROTECTION message
)%

END;	!DAP$PUT_ATTRIBUTES
GLOBAL ROUTINE DAP$PUT_ACCESS (DD,FAB,ACCFUNC,ACCOPT,DISPLAY,NFAB): NOVALUE=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	build ACCESS message & put in output buffer
!
! FORMAL PARAMETERS:
!
!	DD: Address of DAP descriptor
!       FAB:  "      " RMS FAB
!       ACCFUNC: Access Function to perform
!       ACCOPT: Access option bits (DAP)
!       DISPLAY: Display Bits (DAP)
!       NFAB: FAB with New name for rename
!
! IMPLICIT OUTPUTS:
!
!	An ACCESS msg will be put in the output buffer
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR,
    FAB: REF $FAB_DECL,
    NFAB: REF $FAB_DECL,
    ACCOPT: REF BITVECTOR,
    DISPLAY: REF BITVECTOR;

BIND NAM=.FAB[FAB$A_NAM]: $NAM_DECL;    ! Name block (if any)

LOCAL
      C,
      NPTR,
      TNPTR,
      FAC: BITVECTOR[21],
      SHR: BITVECTOR[21];

LOCAL REMOTEFILE: VECTOR[256/(%BPVAL/8)];
CLEARV(FAC,SHR);

INIT_MESSAGE(DD[$]);
DD[DAP$B_OPERATOR]=DAP$K_ACCESS;
DD[DAP$V_MFLAGS_LENGTH]=1;              ! Length field present always

!Make sure we request enough access to do what we want
CASE .ACCFUNC FROM DAP$K_OPEN TO DAP$K_ACCFUNC_MAX OF SET
[DAP$K_OPEN]:		FAB[FAB$V_FAC_GET]=1;	!Ask for GET access
[DAP$K_CREATE,DAP$K_SUBMIT]:
                        FAB[FAB$V_FAC_PUT]=1;	!Ask for PUT access
[INRANGE]: ;                            ! Not needed
[OUTRANGE]: SIGNAL(DAP$_AOR,DD[$]);
TES;

$DAP_MOVE_BITS(FAB,FAB$V_FAC_,FAC,DAP$V_FAC_,
               GET,PUT,BIO,TRN,UPD,BRO);        ! Massage RMS FAC bits into DAP

$DAP_MOVE_BITS(FAB,FAB$V_SHR_,SHR,DAP$V_FAC_,
               GET,PUT,BIO,TRN,UPD,BRO);        ! Massage RMS SHR bits into DAP


! If we have a resultant name string, use it.
! If not, try expanded name string.
! If we have neither of those, or no name block at all, use the original string

IF NAM NEQ 0
THEN
    BEGIN
    IF .NAM[NAM$H_RSL] NEQ 0
    THEN NPTR=.NAM[NAM$A_RSA]
    ELSE IF .NAM[NAM$H_ESL] NEQ 0
         THEN NPTR=.NAM[NAM$A_ESA]
         ELSE NPTR=.FAB[FAB$A_FNA]
    END
ELSE NPTR=.FAB[FAB$A_FNA];

TNPTR=.NPTR;                            ! Copy pointer

! Scan off nodeid if any
INCR I FROM 0 TO 255
DO IF ((C=CH$RCHAR_A(NPTR)) EQL %C':') AND ((C=CH$RCHAR_A(NPTR)) EQL %C':')
   THEN EXITLOOP
   ELSE IF .C EQL 0
        THEN (NPTR=.TNPTR; EXITLOOP);               ! Look for ::

!Find out how long the message will be (and build a few fields in the process)
DD[DAP$H_LENGTH]=(1                     !Length so far=1 
                  +$DAP_SIZE_BITVECTOR(.ACCOPT,5)  ! +# of bytes of ACCOPT
                  +CHAZAC(.NPTR,CH$PTR(REMOTEFILE,0,8))+1
                  !Add length of the file name +1 for count byte
                  +$DAP_SIZE_BITVECTOR(FAC,3,
                                       SHR,3,
                                       .DISPLAY,4)
                 );


!Now build the message a field at a time
DAP$PUT_HEADER(DD[$]);                        ! First, the message header

PUT_BYTE(DD[$],.ACCFUNC);                     !Access function

DAP$PUT_BITVECTOR(DD[$],.ACCOPT,5);           !Access options

PUT_VARIABLE_COUNTED(DD[$],CH$PTR(REMOTEFILE,0,8)); !Remote file spec

DAP$PUT_BITVECTOR(DD[$],FAC,3);         !FAC

DAP$PUT_BITVECTOR(DD[$],SHR,3);         !SHR

DAP$PUT_BITVECTOR(DD[$],.DISPLAY,4);    !DISPLAY

IF .ACCFUNC EQL DAP$K_RENAME
THEN
    BEGIN                               ! [4] Pass address of bitvector
    LOCAL NAMETYPE: BITVECTOR[24] PRESET([DAP$K_NAMETYPE_FSP]=1);
    D$PNAM(DD[$],NFAB[$],NAMETYPE);  ! New name for rename
    END;
END;	!D$PACC
GLOBAL ROUTINE D$PNAM(DD,FAB,NAME_TYPE): NOVALUE=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Send a NAME message
!
! FORMAL PARAMETERS:
!
!	DD:		addr of DAP descriptor
!       FAB:            addr of RMS FAB
!       NAME_TYPE:      name type (DAP) address of bitvector
!--
MAP  DD: REF $DAP_DESCRIPTOR;
MAP  FAB: REF $FAB_DECL;
MAP NAME_TYPE: REF BITVECTOR;
LOCAL NPTR;
LOCAL TNPTR;
LOCAL C;
LOCAL
	CFILESPEC: VECTOR[200/(%BPVAL/8)];	!Store ASCIC filespec here
    
NPTR=.FAB[FAB$A_FNA];                   ! Scan off nodeid
TNPTR=.NPTR;

! Scan off nodeid if any
INCR I FROM 0 TO 255
DO IF ((C=CH$RCHAR_A(NPTR)) EQL %C':') AND ((CH$RCHAR_A(NPTR)) EQL %C':')
   THEN EXITLOOP
   ELSE IF .C EQL 0
   THEN (NPTR=.TNPTR; EXITLOOP);               ! Look for ::

INIT_MESSAGE(DD[$]);

DD[DAP$B_OPERATOR]=DAP$K_NAME;
DD[DAP$V_MFLAGS_LENGTH]=1;	!LENGTH field present
DD[DAP$H_LENGTH]=$DAP_SIZE_BITVECTOR(.NAME_TYPE,3)
                  +CHAZAC(.NPTR,CH$PTR(CFILESPEC,0,8))+1;
                  !Convert filespec to ASCIC, & compute length of message
                  ! add 1 for count byte

DAP$PUT_HEADER(DD[$]);

DAP$PUT_BITVECTOR(DD[$],.NAME_TYPE,3);		       ! NAMETYPE field
DAP$PUT_VARIABLE_COUNTED(DD[$],CH$PTR(CFILESPEC,0,8)); ! FILESPEC field

END;
GLOBAL ROUTINE D$PCTL(DD,RAB,CFUN,DISPLAY) :NOVALUE=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Build CONTROL message
!
! FORMAL PARAMETERS:
!
!       DD:     Address of DAP descriptor
!       RAB:    Address of RMS RAB
!	CFUN:	Control message function code
!       DISPLAY:Address of display bitvector
!
! IMPLICIT INPUTS:
!
!
! IMPLICIT OUTPUTS:
!
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR,            ! Descriptor for message
    RAB: REF $RAB_DECL;                 ! RAB

LOCAL
	CTLMENU: BITVECTOR[7],
	RAC,
	KEY: BYTE8VECTOR[255],
        KRF,
        ROP: BITVECTOR[42],
        ROP_SIZE,
        HSH: BITVECTOR[35],
        HSH_SIZE,
        DISPLAY_SIZE;


BIND FAB=.RAB[RAB$A_FAB]: $FAB_DECL;               ! Find our FAB

CLEARV(CTLMENU,KEY,KRF,ROP,HSH);

INIT_MESSAGE(DD[$]);
DD[DAP$B_OPERATOR]=DAP$K_CONTROL;       ! This is a CONTROL message
DD[DAP$V_MFLAGS_LENGTH]=1;              ! Always a length field

CTLMENU[DAP$V_CTL_RAC]=1;               ! Always have to send a RAC

RAC=$DAP_TRANSLATE_VALUE(.RAB[RAB$Z_RAC],
                         RAB$K_RAC_,DAP$K_RAC_,
                         SEQ,REL,IDX,TRA,BLK,BFT);

SELECT .RAB[RAB$Z_RAC] OF 
SET
[RAB$K_RAC_BFT]:                        ! Block mode file transfer
    BEGIN
    LOCAL KEYVAL;

    CTLMENU[DAP$V_CTL_KEY]=1;           ! We will send the KEY
    KEYVAL=RMS_VBN_TO_DAP(.RAB[RAB$G_BKT]);
    KEY[0]=%BPVAL/8;                    ! Key is converted bucket number
    INCR I FROM 1 TO %BPVAL/8           ! 
    DO (KEY[.I]=.KEYVAL; KEYVAL=.KEYVAL^-8);
    END;
[RAB$K_RAC_KEY]:                        ! Key access
    BEGIN
    CTLMENU[DAP$V_CTL_KEY]=1;           ! We will send the key

    SELECT .FAB[FAB$Z_ORG] OF
    SET
    [FAB$K_ORG_REL]:                    ! Relative file
        BEGIN                           ! Key is Record number
        LOCAL KEYVAL;                   ! KBF is address of record number

        KEYVAL=..RAB[RAB$A_KBF];
        KEY[0]=%BPVAL/8;
        INCR I FROM 1 TO %BPVAL/8
        DO (KEY[.I]=.KEYVAL; KEYVAL=.KEYVAL^-8)
        END;
    [FAB$K_ORG_IDX]:                    ! Indexed file
        BEGIN                           ! Key is a string
        LOCAL KEYPTR;
        KEY[0]=.RAB[RAB$Z_KSZ];         ! KSZ is length of string
        KEYPTR=.RAB[RAB$A_KBF];         ! Character pointer to key
        INCR I FROM 1 TO .KEY[0]        ! Copy the string
        DO (KEY[.I]=CH$RCHAR_A(KEYPTR));!
        END;
    TES;
    END;
TES;
    
$DAP_MOVE_BITS(RAB,RAB$V_ROP_,ROP,DAP$V_ROP_,
               EOF,FDL,UIF,HSH,LOA,ULK,TPT,
               RAH,WBH,KGE,KGT,NLK,RLK,BIO,
               LIM,NXR);                ! Translate the RMS ROP to a DAP one

ROP_SIZE=DAP$SIZE_BITVECTOR(ROP,6,0);   ! Remember the size of this now
IF .ROP_SIZE NEQ 0 THEN CTLMENU[DAP$V_CTL_ROP]=1; !Remember to send if needed

!HSH is reserved as of DAP 6.0
HSH_SIZE=0;

DISPLAY_SIZE=DAP$SIZE_BITVECTOR(.DISPLAY,4,0); ! Remember the size of this now
IF .DISPLAY_SIZE NEQ 0 THEN CTLMENU[DAP$V_CTL_DISPLAY]=1; ! send if needed


DD[DAP$H_LENGTH]=(1                                     ! Length of CTLFUNC
                  +DAP$SIZE_BITVECTOR(CTLMENU,4,0)      ! Length of menu
                  +.CTLMENU[DAP$V_CTL_RAC]              ! Length of RAC
                  +(IF .CTLMENU[DAP$V_CTL_KEY]
                    THEN .KEY[0]+1 ELSE 0)              ! Length of KEY
                  +(.CTLMENU[DAP$V_CTL_KRF])            ! Length of KRF = 1
                  +.ROP_SIZE                            ! Length of ROP
                  +.HSH_SIZE                            ! Length of HSH
                  +.DISPLAY_SIZE                        ! Length of DISPLAY
                 );

DAP$PUT_HEADER(DD[$]);                      ! Send the header

DAP$PUT_BYTE(DD[$],.CFUN);                  !Function code

DAP$PUT_BITVECTOR(DD[$],CTLMENU,4);     !Send the menu

IF .CTLMENU[DAP$V_CTL_RAC]                    !RAC field
THEN	DAP$PUT_BYTE(DD[$],.RAC);             !

IF .CTLMENU[DAP$V_CTL_KEY]                    !Key field
THEN	PUT_VARIABLE_COUNTED(DD[$],CH$PTR(KEY,0,8));

IF .CTLMENU[DAP$V_CTL_KRF]
THEN    PUT_BYTE(DD[$],.KRF);                 ! KRF field

IF .CTLMENU[DAP$V_CTL_ROP]
THEN    DAP$PUT_BITVECTOR(DD[$],ROP,6);           ! ROP field

IF .CTLMENU[DAP$V_CTL_HSH]
THEN    DAP$PUT_BITVECTOR(DD[$],HSH,5);           ! HSH field

IF .CTLMENU[DAP$V_CTL_DISPLAY]
THEN    DAP$PUT_BITVECTOR(DD[$],.DISPLAY,4);       ! DISPLAY field

END;	!D$PCTL
GLOBAL ROUTINE D$GSTS(DD)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Routine to process a (usually unexpected) STATUS message
!	Note that the message header must have already been eaten
!	Signals error condition & returns code
!
! FORMAL PARAMETERS:
!
!	DD: Addr of DAP descriptor
!
! IMPLICIT INPUTS:
!
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	System-dependent error code (but we SIGNAL first)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP	DD:	REF $DAP_DESCRIPTOR;
LOCAL
        CODE,
	MACCODE,
	MICCODE,
	RFA: BYTE8VECTOR[9],
	RECNUM: BYTE8VECTOR[9],
	STV: BYTE8VECTOR[9];

CLEARV(RFA,RECNUM,STV);
CODE=GET_2BYTE(DD[$]);                  !Put both here for now
MACCODE=.CODE AND DAP$M_MACCODE;         !Pick out MACCODE
MICCODE=.CODE AND DAP$M_MICCODE;         !and MICCODE

IF .DD[DAP$H_LENGTH] GTR 0 THEN RFA=GET_VBN(DD[$]);
IF .DD[DAP$H_LENGTH] GTR 0 THEN RECNUM=GET_LONGWORD(DD[$]);
IF .DD[DAP$H_LENGTH] GTR 0 THEN STV=GET_LONGWORD(DD[$]);

ERR_DS(.MACCODE,.MICCODE)
END; !DOSTS
GLOBAL ROUTINE DAP$GET_ACK(DD)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Routine to expect and process an ACK message,
!       or a STATUS message if we aren't lucky
!
! FORMAL PARAMETERS:
!
!	DD: Addr of DAP descriptor
!
! IMPLICIT INPUTS:
!
!	Input buffer & pipeline
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! COMPLETION CODES:
!
!       STS$K_NORMAL if we get an ACK,
!       error code otherwise
!
! SIDE EFFECTS:
!
!	The accessed file, if any, will be closed or flushed
!
!--
MAP DD: REF $DAP_DESCRIPTOR;

SELECT GET_HEADER(DD[$])
OF  SET
    [DAP$K_ACK]:     STS$K_NORMAL;
    [DAP$K_STATUS]:  D$GSTS(DD[$]);
    [OTHERWISE]:     SIGNAL(DAP$_SYNC,DD[$]);
    TES
END;	!DAP$GET_ACK
%IF FTPASSIVE
%THEN
GLOBAL ROUTINE DAP$GET_ACCESS_COMPLETE(DD)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Routine to process an ACCESS COMPLETE message
!	Note that the message header has already been eaten
!
! FORMAL PARAMETERS:
!
!	DD: Addr of DAP descriptor
!
! IMPLICIT INPUTS:
!
!	Input buffer & pipeline
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	CMPFUNC: the ACCESS COMPLETE function code
!
! SIDE EFFECTS:
!
!	The accessed file, if any, will be closed or flushed
!
!--
LOCAL	FOP: BITVECTOR;
LOCAL CMPFUNC;

CMPFUNC=GET_BYTE(DD[$]);	!Save ACCOMP function
IF .DD[DAP$H_LENGTH] GTR 0
THEN DAP$GET_BITVECTOR(DD[$],FOP,6);	!Get a FOP field if any
CASE .CMPFUNC FROM 1 TO 4 OF SET
[DAP$K_ACCOMP_COMMAND]:
                BEGIN
                SELECT .NB[NDB$ACCFUNC] OF
                    SET
		    [DAP$K_OPEN,DAP$K_CREATE]: CLOSE(FB);	!Close the file
		    TES;

                IF .FOP[FB$DLC] THEN DELETE(FB);        !Delete on close

		DAP$PUT_STRING(DD[$],D_ACCOMP_RESP);
                DAP$PUT_MESSAGE(DD[$]);

		RETURN DAP$K_ACCOMP_COMMAND	!We won & we're done
		END;
[DAP$K_ACCOMP_RESPONSE]:
                DAP_ERROR(DD[$],DAP$K_MAC_INVALID,DAP$K_ACCOMP_CMPFUNC);
		!They're not supposed to send us this!!
[DAP$K_ACCOMP_PURGE]:
                BEGIN
		IF (FB NEQ 0) THEN RESETF(FAB);
		DAP$PUT_STRING(DD[$],D_ACCOMP_RESP);
                DAP$PUT_MESSAGE(DD[$]);

		SIGNAL(DAP$_LINK_ABORT,DD[$]); !Remote system aborted transfer
		RETURN DAP$K_ACCOMP_PURGE	!They gave up on us
		END;
[DAP$K_ACCOMP_EOS]:
                BEGIN
		DAP_ERROR(DD[$],DAP$K_MAC_UNSUPPORTED,
                          DAP$K_MIC_ACCOMP_CMPFUNC);
		END;
[OUTRANGE]:	BEGIN
		DAP_ERROR(DD[$],DAP$K_MAC_INVALID,
                          DAP$K_MIC_ACCOMP_CMPFUNC);
		END;
TES;
END;	!DOACM
%FI !FTPASSIVE
END ELUDOM