Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 7/galaxy-sources/lptclu.mac
There are 4 other files named lptclu.mac in the archive. Click here to see a list.
TITLE	LPTCLU - LPTSPL Support for Cluster Printing
SUBTTL	Preliminaries		

;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1988.
;	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.

	SEARCH	GLXMAC			;SEARCH GLXLIB'S SYMBOLS
	SEARCH	LPTMAC			;SEARCH LPTSPL'S SYMBOLS
	SEARCH	LISMAC			;SEARCH LPTSPL'S LISTENER'S SYMBOLS
	SEARCH	QSRMAC			;SEARCH QUASAR'S SYMBOLS
	SEARCH	ORNMAC			;SEARCH ORION'S SYMBOLS
IFN FTACNT,< 
	SEARCH	ACTSYM			;SEARCH FOR ACCOUNTING SYMBOLS
>
	PROLOGUE(LPTCLU)		;GENERATE THE NECESSARY SYMBOLS

	CLUMAN==:0			;MAINTENANCE EDIT NUMBER
	CLUDEV==:11			;DEVELOPMENT EDIT NUMBER
	VERSIN (CLU)			;GENERATE EDIT NUMBER

	SALL				;CLEAN LISTINGS
	Subttl	Table of Contents

;		     Table of Contents for LPTCLU
;
;				  Section		      Page
;
;
;    1. Revision history . . . . . . . . . . . . . . . . . . .   4
;    2. Global Symbols . . . . . . . . . . . . . . . . . . . .   5
;    3. INILNK - INITIALIZE AND OPEN DCN: DECNET LINK  . . . .   6
;    4. BLDDCN - BUILD THE DCN: DECNET DEVICE NAME . . . . . .   7
;    5. OPNLNK - OPEN THE DCN: DECNET DEVICE . . . . . . . . .   8
;    6. GETSIZ - GET THE SIZE OF CLUSTER LPTSPL  . . . . . . .   9
;    7. STLIS - START UP THE CLUSTER LPTSPL LISTENER . . . . .  10
;    8. CLNCLU - RELEASE FILE TRANSFER BUFFER AND KILL LISTENE  11
;    9. FIXCLU - FIXUP CLUSTER LPT PARAMETERS FROM NXTJOB  . .  12
;   10. CLJOB - DO THE CLUSTER LPTSPL PRINT JOB  . . . . . . .  13
;   11. INTDAV - INTERRUPT ROUTINE FOR DECNET MESSAGE AVAILABL  14
;   12. XFERFI - TRANSFER FILES TO THE REMOTE SYSTEM . . . . .  15
;   13. SHULPT - SHUTDOWN DUE TO A FATAL INTERRUPT ROUTINE ERR  16
;   14. RESTAR - RESTART A NEXTJOB REQUEST . . . . . . . . . .  17
;   15. REPERR - REPORT FATAL ERROR TO QUASAR  . . . . . . . .  18
;   16. CHKSUM - CHECKSUM DECNET MESSAGES  . . . . . . . . . .  19
;   17. RESET - RESET THE STATE OF CLUSTER LPTSPL  . . . . . .  20
;   18. UPDMSG - UPDATE THE NEXTJOB MESSAGE  . . . . . . . . .  21
;   19. CFILES - CLOSE THE INACCESSIBLE FILE AND TEMPORARY FIL  22
;   20. DELTEM - DELETE AND EXPUNGE ANY TEMPORY FILES  . . . .  23
;   21. SENFAI - SEND A DECNET FAIL MESSAGE TO THE LISTENER  .  24
;   22. SNDINT - SEND A DECNET INTERRUPT MESSAGE TO THE LISTEN  25
;   23. RCVINT - PICK UP AN INTERRUPT MESSAGE RESPONSE FROM LI  26
;   24. ENDFRK - INFERIOR FORK TERMINATION INTERRUPT HANDLER .  27
;   25. DISINT - DEACTIVATE DATA AVAILABLE CHANNEL . . . . . .  28
;   26. ENAINT - ACTIVATE THE DATA AVAILABLE CHANNEL . . . . .  29
;   27. CHKLNK - CHECK THE STATUS OF THE SENDER DECNET LINK  .  30
;   28. REMREL - RELEASE A PRINT REQUEST FROM A REMOTE NODE  .  31
;   29. ADDACT - ADD ACCOUNTING INFORMATION TO A RELEASE MESSA  32
;   30. REMDIS - DELETE FILES AND PLACE FILE NAMES IN RELEASE   33
;   31. DELTFE - DELETE A FILE . . . . . . . . . . . . . . . .  34
;   32. SETFD - SETUP A TEMPORARY FILE'S FD IN THE FOB . . . .  35
;   33. LISTEN - MESSAGE SERVER FOR A REMOTE NODE  . . . . . .  36
;   34. BLDSRV - BUILD THE SRV: DEVICE NAME  . . . . . . . . .  37
;   35. LISSET - INITIALIZE THE LISTENER'S GLXLIB AND CAPABILI  38
;   36. LOPLNK - OPEN A DECNET SRV: DEVICE . . . . . . . . . .  39
;   37. LISINT - SET UP THE LISTENER'S INTERRUPT SYSTEM  . . .  40
;   38. ACCEPT - VALIDATE A DECNET CONNECTION REQUEST  . . . .  41
;   39. MSGFSN - DECNET MESSAGE FROM SENDER IS AVAILABLE . . .  42
;   40. LSSCS - TOPOLOGY CHANGE DECTECTED INTERRUPT HANDLER  .  43
;   41. LCKLNK - CHECK THE STATUS OF THE LISTENER'S LINK . . .  44
;   42. LABLNK - ABORT THE LISTENER'S DECNET LINK  . . . . . .  45
;   43. LISCHK - LISTENER CHECKSUM AND ACK MESSAGE . . . . . .  46
;   44. ACKSND - SEND A SUCCESS ACK TO THE SENDER  . . . . . .  47
;   45. INLCRH - ROUTINE TO INDICATE LISTENER CONTROLLED CRASH  48
;   46. LPTDDT - ROUTINE TO LOAD DDT IF DEBUGGING  . . . . . .  49
;   47. DOACT - DO ACCOUNTING FROM THE RELEASE MESSAGE . . . .  50
	Subttl	Table of Contents (page 2)

;		     Table of Contents for LPTCLU
;
;				  Section		      Page
;
;
;   48. ACTLIS - LISTENER ACCOUNTING RECORD  . . . . . . . . .  51
;   49. STOP CODE DEFINITIONS  . . . . . . . . . . . . . . . .  52
;   50. End of LPTCLU  . . . . . . . . . . . . . . . . . . . .  53
	SUBTTL	Revision history

COMMENT \

*****  Release 6.0 -- begin development edits  *****

1	6.1029		19-Oct-87
	Add LPTCLU as the Cluster printer handler for LPTSPL.

2	6.1036		21-Oct-87
	Split subroutines into LPTSUB for use by LPTDQS.

3	6.1052		3-Nov-87
	General cleanup of code as a result of unit and system testing.

4	6.1119		5-Dec-87
	If the listener detects that the DECnet link is no longer connected,
then in addition to aborting and re-opening the link, cause it also to
clear and re-setup the interrupt system.

5	6.1125		6-Dec-87
	If the attributes field contains %GENRC, then zero the units field.

6	6.1128		7-Dec-87
	Expand on edit 4 to include all cases of the listener detecting that
the DECnet link is no longer connected. Also, clear and reset the interrupt
system outside of interrupt context to prevent NIP ("no interrupt in progress")
crashes.

7	6.1215		4-Mar-88
	In a private GALAXY, use the first six characters of the user's name
rather than LISSPL and LPTSPL as part of the DCN: and SRV: name.

10	6.1220		6-Mar-88
	Transfer the contents of the page shared between LPTSPL and the
inaccessible file to another page. PMAP that page to the temporary file.

11	6.1225		8-Mar-88
	Update copyright notice.

\
	SUBTTL	Global Symbols


;Global symbols defined in LPTSPL

	EXTERN	CNTSTA,DETDEL,DIRNAM,DSCHD,ENDREQ,INPOPN,JOBACT
	EXTERN	JOBOBA,LEV1PC,LPTSIZ,LPTVNO,NXTFIL,RSETUP,SHUTIN,SNDQSR

;Global symbols defined in LPTSUB

	EXTERN	ABTLNK,CASTIM,GETLIK,FNDCER,PROTIM,SETIM

;Global symbols defined in LPTCLU

	INTERN	CLNCLU,CLUEDT,ENDFRK,FIXCLU,INILNK,INTDAV,REMREL,RCVINT,SETFD
	INTERN	CLJOB			;[2]
	SUBTTL	INILNK - INITIALIZE AND OPEN DCN: DECNET LINK

;INILNK is called during Cluster LPTSPL's SETUP to build the DECnet DCN:
;device name, to open the DECnet link and to allocate the buffer for any
;files that may need to be transferred to a remote node.
;If accounting is enabled, then a listener is also started. 
;If the DECnet DCN: JFN cannot be obtained or opened, or if the listener
;cannot be started, then a SETUP RESPONSE message is sent to QUASAR
;indicating that this LPTSPL is shutting down. The operator is also
;informed that this LPTSPL is being shutdown.
;
;Call is:       J/Job Context Pointer
;               M/Address of the SETUP message
;Returns true:  S1/SETUP response code
;               The DECnet link is connected and the listener (if any) is 
;               started
;Returns false: A fatal error occurred (the DECnet DCN: JFN could not be
;               obtained or opened, or the listener could not be started)

;ATTEMPT TO OPEN AND CONNECT THE DECNET LINK

INILNK:	$CALL	BLDDCN			;BUILD THE DCN: DECNET DEVICE NAME
	$CALL	OPNLNK			;OPEN THE DECNET LINK
	JUMPF	INILN3			;A FATAL ERROR WAS DETECTED

IFN FTACNT<
	SETOM	J$ACCT(J)		;INDICATE ACCOUNTING IS ENABLED
>
	SKIPL	J$ACCT(J)		;IF ACCOUNTING ENABLED, START LISTENER
	JRST	INILN2			;ELSE PICK UP THE FILE TRANSFER BUFFER
	$CALL	GETSIZ			;PICK UP LPTSPL'S SIZE IN PAGE
	$CALL	STLIS			;START UP THE LISTENER
	JUMPF	INILN3			;SHUTDOWN ON AN ERROR

;PICK UP THE MEMORY FOR THE FILE TRANSFER BUFFERS.

INILN2:	MOVEI	S1,2			;[10]NEED TWO FILE TRANSFER BUFFERS
	$CALL	M%AQNP			;[10]PICK UP THE PAGES
	MOVE	S2,S1			;[10]SAVE A COPY
	MOVEM	S1,J$FILB(J)		;[10]SAVE PAGE NUMBER IN THE DATA BASE
	PG2ADR	S1			;[10]CHANGE TO AN ADDRESS
	MOVEM	S1,J$FADR(J)		;[10]SAVE ADDRESS IN THE DATA BASE
	AOS	S2			;[10]POINT TO THE NEXT PAGE
	MOVEM	S2,J$FILO(J)		;[10]SAVE PAGE NUMBER OF 2ND XFER PAGE
	PG2ADR	S2			;[10]CHANGE TO AN ADDRESS
	MOVEM	S2,J$OADR(J)		;[10]SAVE ADDRESS IN THE DATA BASE

;PICK UP THE MEMORY FOR THE DECNET RESPONSE MESSAGES AND THE DECNET SEND 
;MESSAGES

	MOVEI	S1,2			;NEED TWO PAGES
	$CALL	M%AQNP			;PICK UP THE PAGES
	PG2ADR	S1			;CHANGE PAGE NUMBER TO PAGE ADDRESS
	HRLI	S1,(POINT 36)		;POINT TO DECNET RESPONSE MESSAGE ADR
	MOVEM	S1,J$DECR(J)		;SAVE POINTER IN THE DATA BASE
	ADDI	S1,PAGSIZ		;POINT TO DECNET SEND MESSAGE ADDRESS
	MOVEM	S1,J$DECS(J)		;SAVE POINTER IN THE DATA BASE
	$CALL	SETIM			;SET THE DECNET INACTIVITY TIMER
	MOVX	S1,%RSUOK		;PICK UP THE SETUP OK RESPONSE CODE
	$RETT				;RETURN TO THE CALLER

;AN ERROR HAS BEEN DETECTED. IF THE ERROR IS FATAL, THEN CLOSE THE DECNET
;DCN: DEVICE JFN AND INFORM QUASAR TO SHUT THIS LPTSPL DOWN. ALSO INFORM
;THE OPERATOR. IF THE ERROR IS NOT FATAL, THEN QUASAR WILL TEMPORARILY
;SHUT THE PRINTER DOWN.

INILN3:	SKIPE	S1			;[3]SKIP IF TEMPORARY SHUTDOWN
	$CALL	REPERR			;REPORT THE ERROR TO QUASAR AND ORION
	$RETF				;RETURN FALSE TO SETUP
	SUBTTL	BLDDCN - BUILD THE DCN: DECNET DEVICE NAME

;BLDDCN is called during Cluster LPTSPL SETUP to build the DECnet DCN: device
;name that Cluster LPTSPL will use in opening its DECnet link. The format of
;the DCN: device name is:
;DCN:RNODE-TASK-RNODE$LISSPL$LS.RNODE$LPTSPL$SN;BDATA:NNNNN;
;USERID:RNODE$LPTSPL$SN
;
;where RNODE is the remote node name
;      NNNNN comes from the listener's node name and is used by LISSPL's 
;      listener in accepting a connection
;
;Call is: J/Job Context Pointer
;Returns  The DCN: device name has been built and placed in the stream's
;         data base

BLDDCN:	$SAVE	<P1,P2,P3,P4>		;SAVE THESE AC

;BUILD THE OPTIONAL DATA FIELD USING THE SIXBIT REMOTE NODE NAME AS
;THE STARTING VALUE. CREATE 12 OCTAL CHARACTERS AND CONVERT THEM TO ASCII. 

	MOVE	S2,JOBOBA		;PICK UP THE OBJECT BLOCK ADDRESS
	MOVE	S2,OBJ.ND(S2)		;PICK UP THE LISTENER'S NODE NAME
	MOVEM	S2,J$RNOD(J)		;SAVE IN THE DATA BASE
	ROT	S2,3			;ROTATE BY HALF A CHARACTER
	MOVE	P1,[POINT 7,S1,35]	;POINTER TO BYTE TO PICK UP
	MOVE	P2,[POINT 7,J$NDAT(J)]	;POINTER TO WHERE BYTE IS TO BE PUT
	SETZ	S1,			;CLEAR RECEIVING WORD OF OCTAL VALUE
	MOVEI	P3,^D36/3		;NUMBER OF OCTAL CHARACTERS

BLDDC2:	LSHC	S1,3			;MOVE NEXT OCTAL VALUE OVER
	ADDI	S1,60			;MAKE IT ASCII
	LDB	P4,P1			;PICK UP ASCII VALUE
	IDPB	P4,P2			;PLACE IN ASCII STRING
	SETZ	S1,			;PREPARE FOR NEXT OCTAL VALUE
	SOJN	P3,BLDDC2		;PICK UP NEXT OCTAL VALUE
	IDPB	S1,P2			;MAKE INTO AN ASCIZ STRING

;BUILD THE DECNET DCN: DEVICE NAME

	SKIPE	DEBUGW			;[7]DEBUGGING?
	JRST	BLDDC6			;[7]YES, DO DIFFERENTLY

	$TEXT(<-1,,J$CDCN(J)>,<DCN:^I/@BLDDC3/^I/@BLDDC4/^I/@BLDDC5/>) 

	$RET				;RETURN TO THE CALLER

BLDDC3: [ITEXT(<^N/J$RNOD(J)/-TASK-^N/J$RNOD(J)/$LISSPL$LS.>)] ;LISTENER NAME
BLDDC4:	[ITEXT(<^N/J$RNOD(J)/$LPTSPL$SN;BDATA:^T/J$NDAT(J)/>)] ;THE SENDER NAME
BLDDC5: [ITEXT(<;USERID:^N/J$RNOD(J)/$LPTSPL$SN>)]	       ;[3]USERID

BLDDC6:	GJINF%					;[7]PICK UP THE USER'S NUMBER
	MOVE	S2,S1				;[7]SAVE NUMBER WHERE EXPECTED
	MOVEI	S1,J$SDBW(J)			;[7]WHERE TO PLACE USER NAME
	HRLI	S1,(POINT 7)			;[7]MAKE INTO A POINTER
	DIRST%					;[7]PICK UP THE USER NAME
	 JRST	S..COD				;[7]CRASH ON AN ERROR
	MOVEI	S1,J$SDBW(J)			;[7]PICK UP USER NAME ADDRESS
	HRLI	S1,(POINT 7,)			;[7]MAKE INTO A POINTER
	SETZ	T1,				;[7]NUMBER OF CHAR IN NAME
BLDDC7:	ILDB	S2,S1				;[7]PICK UP THE NEXT CHARACTER
	SKIPN	S2				;[7]IS THIS THE LAST ONE?
	JRST	BLDDC8				;[7]YES, BUILD THE DEVICE NAME
	AOS	T1				;[7]INCREMENT THE CHAR COUNT
	CAIG	T1,^D6				;[7]MAXIMUM COUNT?
	JRST	BLDDC7				;[7]NO, GET THE NEXT CHAR
	SETZ	S2,				;[7]PICK UP A NULL
	DPB	S2,S1				;[7]PLACE IN USER NAME
BLDDC8:	MOVEI	S1,J$SDBW(J) 			;[7]ADDRESS OF THE USER NAME

	$TEXT(<-1,,J$CDCN(J)>,<DCN:^I/@BLDDC9/^I/@BLDD10/^I/@BLDD11/^0>)
	$RET				;RETURN TO THE CALLER

BLDDC9: [ITEXT(<^N/J$RNOD(J)/-TASK-^N/J$RNOD(J)/$^T/0(S1)/$LS.>)]  ;[7]LISTENER NAME
BLDD10:	[ITEXT(<^N/J$RNOD(J)/$^T/0(S1)/$SN;BDATA:^T/J$NDAT(J)/>)]       ;[7]SENDER NAME
BLDD11:	[ITEXT(<;USERID:^N/J$RNOD(J)/$^T/0(S1)/$SN>)]		  ;[7]
	SUBTTL	OPNLNK - OPEN THE DCN: DECNET DEVICE

;OPNLNK is called during SETUP and also if it is detected that the link is
;no longer connected while processing a print request. OPNLNK opens a DECnet
;link to a remote LISSPL listener.
;If a connection cannot be obtained, then a check is made to see if the
;error is fatal. If the error is fatal, then Cluster LPTSPL shuts down.
;If the error is not fatal, then OPNLNK will re-attempt to open the
;connection after a specified amount of time. Initially, the time between
;retries is MINTIM seconds. If after MAXTIM seconds a connection is still
;not obtained, then OPNLNK informs ORION. The time between retries is
;increased by MINTIM seconds and a connection is again attempted. This will
;continue until either a connection is obtained or until the time between
;retries is MAXTIM seconds. At this point, OPNLNK attempts to obtain a 
;connection every MAXTIM seconds.
;It is possible for an operator to suppress OPNLNK from sending 
;connection failure messages (and to later re-enable OPNLNK to send
;connection failure messages) by giving the OPR command DISABLE OUTPUT-DISPLAY
;PRINTER-MESSAGE
;
;Call is:       J/Job Context Pointer
;Returns true:  The DECnet link is connected
;Returns false: A fatal DECnet error was detected
;		S1/Address of the error string
;		Unable to obtain the DECnet connection. QUASAR will temporarily
;               shut this printer down
;		S1/0

OPNLNK:	$SAVE	<T1,T2,T3,T4>		;SAVE THESE AC

;INITIALIZE THE ATTEMPT TO OBTAIN A DECNET CONNECTION TO THE LISTENER

	MOVEI	T3,MINTIM		;PICK UP TIME BETWEEN RETRIES
	SETOM	J$LCHN(J)		;NO DECNET JFN
	SETZ	T4,			;NUMBER OF ATTEMPTS TO OBTAIN THE LINK

;ATTEMPT TO OBTAIN THE DECNET CONNECTION. 

OPNLN2:	SKIPL	J$LCHN(J)		;CURRENTLY HAVE A DECNET JFN?
	JRST	OPNLN3			;YES, GO CHECK ITS STATUS
	$CALL	GETLIK			;[3]NO, OBTAIN ONE AND OPENF
	JUMPF	OPNLN9			;QUIT ON A FATAL ERROR

;CHECK THE STATUS OF THE LINK. IF THERE IS A CONNECTION, THEN ENABLE
;FOR DATA AVAILABLE INTERRUPTS.

OPNLN3:	$CALL	CHKLNK			;CHECK THE LINK STATUS
	JUMPF	OPNLN4			;DON'T HAVE A CONNECTION
	MOVE	S1,J$LCHN(J)		;PICK UP THE DECNET DCN: DEVICE JFN
	MOVEI	S2,.MOACN		;PICK UP ACTIVATE FUNCTION
	MOVX	T1,<FLD(2,MO%DAV)+FLD(.MONCI,MO%CDN)+FLD(3,MO%INA)>
	MTOPR%				;ENABLE FOR DATA AVAILABLE INTERRUPTS
	 ERJMP	OPNLN8			;FATAL ERROR, SHUTDOWN PRINTER
	$RETT				;RETURN TO SENDER STARTUP

;UNABLE TO OBTAIN THE CONNECTION. DETERMINE IF THE RETRY SHOULD BE INCREASED.

OPNLN4:	JUMPG	S1,OPNLN9		;QUIT IF A FATAL ERROR OCCURRED
	AOS	T1,T4			;INCREMENT THE NUMBER OF OPEN ATTEMPTS
	IMUL	T1,T3			;TIME BEEN TRYING TO OBTAIN CONNECTION
	CAIGE	T1,MAXTIM		;TIME TO GIVE UP?
	JRST	OPNLN7			;NO, DISMISS AND TRY AGAIN

;REPORT THE CONNECTION FAILURE TO ORION. INFORM QUASAR TO TEMPORARILY 
;SHUT THIS PRINTER DOWN.

	$CALL	FNDCER			;GET THE CONNECTION ERROR
	$WTOJ	(<LPTSPL connection failure>,<^I/@OPNL10/^M^J^I/@OPNL11/>)
	MOVX	S1,%RSUNA		;[3]INDICATE TEMPORARY SHUTDOWN
	$CALL	RSETUP			;[3]INFORM QUASAR
	SETZ	1,			;[3]INDICATE TEMPORARY SHUTDOWN
	JRST	OPNLN9			;[3]RETURN TO THE CALLER

;DISMISS UNTIL INDICATED

OPNLN7:	MOVE	S1,T3			;PICK UP TIME TO DISMISS
	$CALL	I%SLP			;DISMISS OR WAIT% AS INDICATED
	JRST	OPNLN2			;ATTEMPT THE CONNECTION AGAIN

;A FATAL ERROR HAS BEEN DETECTED. CLOSE AND RELEASE THE DECNET DCN: LINK
;PICK UP ADDRESS OF THE ERROR STRING.


OPNLN8:	$CALL	S%ERR			;PICK UP THE ERROR STRING ADDRESS
	SKIPT				;UNABLE TO PICK UP ERROR STRING ADR?
	MOVEI	S1,[ASCIZ/Unable to set up DECnet interrupt channel/] ;YES
	MOVEM	S1,J$ERRA(J)		;SAVE ADDRESS OF THE ERROR STRING
	$CALL	ABTLNK			;CLOSE AND RELEASE THE DECNET JFN
	MOVE	S1,J$ERRA(J)		;RESTORE THE ERROR STRING ADDRESS
OPNLN9:	$RETF				;INDICATE AN ERROR TO THE CALLER

OPNL10:	[ITEXT(<LPTSPL to node ^N/J$RNOD(J)/ unable to obtain a DECnet connection>)]
OPNL11:	[ITEXT(<Reason for failure: ^T/0(S1)/>)]
	SUBTTL	GETSIZ - GET THE SIZE OF CLUSTER LPTSPL

;GETSIZ is called during Cluster LPTSPL startup to determine the size of
;Cluster LPTSPL in pages. This information is needed in starting up 
;Cluster LPTSPL's listener.
;
;Call is: No arguments
;Returns: Size of Cluster LPTSPL has been determined

GETSIZ:	SKIPE	DEBUGW			;ARE WE DEBUGGING?
	SKIPN	116			;YES, AND ARE SYMBOLS DEFINED?
	JRST	GETSI2			;NO TO EITHER, SKIP THIS
	HLRO	S1,116			;GET AOBJN LENGTH
	MOVMS	S1			;GET ABSOLUTE VALUE
	HRRZ	S2,116			;GET SYMBOL TABLE START ADDRESS
	ADDI	S1,-1(S2)		;CALCULATE THE SYMBOL TABLE LENGTH
	SKIPA				;SKIP OVER NORMAL CALCULATIONS
GETSI2:	HLRZ	S1,.JBSA##		;GET THE PROGRAM END ADDRESS
	ADDI	S1,777			;ROUND IT OFF
	ADR2PG	S1			;MAKE IT A PAGE NUMBER
	MOVEM	S1,LPTSIZ		;SAVE IT
	$RET				;RETURN TO SETUP
	SUBTTL	STLIS - START UP THE CLUSTER LPTSPL LISTENER

;STLIS is called to start up the Cluster LPTSPL listener.
;This routine is called at LPTSPL SETUP and also when it is detected
;that the listener has crashed.
;
;Call is:       J/Job Context Pointer
;Returns true:  The listener was successfully started
;Returns false: S1/Address of the ASCIZ error text
;               The listener cannot be started (i.e., a CFORK%, SFORK% or
;               PMAP% error has occurred).

;STLIS IS THE ENTRY POINT WHEN STARTING THE LISTENER FOR THE FIRST TIME.
;STLIS0 IS THE ENTRY POINT WHEN RESTARTING THE LISTENER AFTER IT HAS CRASHED.

STLIS:	TDZA	S1,S1			;[3]INDICATE NOT RESTARTING
STLIS0:	SETO	S1,			;[3]INDICATE RESTARTING
	$SAVE	<T1,T2,T3>		;[3]SAVE THESE AC

;CREATE THE LISTENER. PICK UP ITS DATA PAGES AND SET UP IT STACK

	SKIPE	S1			;[3]RESTARTING?
	JRST	STLIS1			;[3]NO, ALREADY HAVE THE DATA PAGES
	MOVEI	S1,DBSIZ		;[3]PICK UP NUMBER OF PAGES
	$CALL	M%AQNP			;[3]PICK UP THE DATA PAGES
	PG2ADR	S1			;[3]CHANGE PAGE NUMBER TO ADDRESS
	MOVEM	S1,J$LPGS(J)		;[3]SAVE THE ADDRESS
	SKIPA				;[3]DON'T PICK UP THE ADDRESS AGAIN

STLIS1:	MOVE	S1,J$LPGS(J)		;[3]PICK UP THE ADDRESS
	MOVEI	S2,.LSPDL-1(S1)		;[3]PICK UP LH OF STACK POINTER
	HRLI	S2,-PDSIZ		;[3]PICK UP RH OF STACK POINTER
	PUSH	S2,[EXP LISTEN]		;[3]PLACE STARTING ADDRESS ON THE STACK
	MOVEM	S2,.LSACS+P(S1)		;[3]PLACE IN THE LISTENER'S AC BLOCK
	MOVEM	S1,.LSACS+LIS(S1)	;[3]PLACE DATA BLOCK ADDRESS IN AC BLK
	MOVE	T3,S1			;[3]SAVE ADDRESS HERE ALSO
	ADDI	S1,PAGSIZ		;[3]ADDRESS OF THE MESSAGE PAGE
	MOVEM	S1,.LSMSG(T3)		;[3]PLACE IN THE DATA BLOCK

	MOVX	S1,<CR%CAP+CR%ACS>	;[3]SUPERIOR'S CAPABILITIES AND ACS
	MOVEI	S2,.LSACS(T3)		;[3]PICK UP AC BLOCK ADDRESS
	CFORK%				;CREATE A LISTENER
	 ERJMP	STLIS4			;QUIT ON AN ERROR
	MOVEM	S1,J$FRKH(J)		;SAVE THE LISTENER FORK HANDLE

;MAP LPTSPL'S PAGES INTO THE LISTENER

	HRLZ	S2,S1			;[3]GET THE LISTENER'S HANDLE
	MOVSI	S1,.FHSLF		;GET THE TOP FORK'S HANDLE
	HRR	T1,LPTSIZ		;GET THE LENGTH IN PAGES
	HRLI	T1,(PM%RWX!PM%CNT)	;COUNT+READ+EXECUTE
	PMAP%				;MAP THE PAGES
	 ERJMP	STLIS2			;QUIT ON AN ERROR

;MAP THE DATA PAGES INTO THE LISTENER

	MOVE	S1,T3			;[3]PICK UP THE DATA BLOCK ADDRESS
	ADR2PG	S1			;[3]CHANGE ADDRESS INTO A PAGE NUMBER
	MOVE	S2,S1			;[3]SAVE PAGE NUMBER HERE ALSO
	HRLI	S1,.FHSLF		;[3]PICK UP TOP FORK'S HANDLE
	HRL	S2,J$FRKH(J)		;[3]PICK UP LISTENER'S HANDLE
	MOVEI	T1,DBSIZ		;[3]PICK UP NUMBER OF PAGES IN DATA BLK
	HRLI	T1,(PM%RWX!PM%CNT)	;[3]COUNT+READ+EXECUTE
	PMAP%				;[3]MAP THE PAGES INTO LISTENER
	 ERJMP	STLIS2			;[3]CRASH ON AN ERROR

;START THE LISTENER

	MOVE	S1,J$FRKH(J)		;GET THE LISTENER'S HANDLE
	MOVEI	S2,LISTEN		;GET THE START ADDRESS
	SFORK%				;START THE LISTENER
	 ERJMP	STLIS2			;QUIT ON AN ERROR
	$RETT				;AND RETURN

;AN ERROR HAS OCCURRED. DELETE THE LISTENER FORK

STLIS2:	$CALL	S%ERR			;PICK UP THE ERROR STRING
	SKIPT				;ERROR STRING PICKED UP?
	MOVEI	S1,[ASCIZ/Fatal error in starting up the LPTSPL sender/] ;NO
	MOVEM	S1,J$ERRA(J)		;SAVE THE ERROR TEXT ADDRESS
	MOVE	S1,J$FRKH(J)		;PICK UP THE LISTENER'S HANDLE
	KFORK%				;KILL THE LISTENER
	 ERJMP	.+1			;IGNORE ANY ERRORS
	SETZM	J$FRKH(J)		;INDICATE NO INFERIOR FORK
	JRST	STLIS5			;GO CLOSE AND RELEASE THE DECNET JFN

;AN ERROR HAS OCCURRED. PICK UP THE ERROR TEXT, AND CLOSE AND RELEASE
;THE DECNET DCN: JFN

STLIS4:	$CALL	S%ERR			;PICK UP THE ERROR TEXT
	SKIPT				;SKIP IF THE ERROR TEXT WAS PICKED UP
	MOVEI	S1,[ASCIZ/Fatal error in starting up the LPTSPL listener/]
STLIS5:	SETZM	J$FRKH(J)		;INDICATE THERE IS NO LISTENER
	$RETF				;INDICATE AN ERROR TO THE CALLER
	SUBTTL	CLNCLU - RELEASE FILE TRANSFER BUFFER AND KILL LISTENER

;CLNCLU is called as part of the shutdown of a Cluster LPTSPL. It returns
;the file transfer buffer pages and the DECnet message receive and send 
;pages to the memory manager, closes any open files, aborts the DECnet
;link and kills the listener.
;
;Call is: J/Job Context Pointer
;Returns: The Cluster LPTSPL cleanup has been performed

CLNCLU:	$SAVE	<T1,T2>			;SAVE THESE AC, DESTROYED BY KFORK%
	SKIPN	S2,J$FILB(J)		;PICK UP FILE TRANSFER PAGES, IF ANY
	JRST	CLNCL2			;NO PAGES, CHECK FOR MESSAGE PAGES
	MOVEI	S1,2			;[10]PICK UP NUMBER OF PAGES TO RETURN
	$CALL	M%RLNP			;RETURN THE PAGES
	SETZM	J$FILB(J)		;[3]INDICATE NO MORE FILE TRANSFER PGS
	SETZM	J$FILO(J)		;[10]ZERO HERE ALSO

CLNCL2:	SKIPN	S2,J$LPGS(J)		;[3]ANY LISTENER PAGES?
	JRST	CLNCL3			;[3]NO, CHECK FOR MESSAGE PAGES
	ADR2PG	S2			;[3]CHANGE ADDRESS TO A PAGE NUMBER
	MOVEI	S1,DBSIZ		;[3]PICK UP NUMBER OF PAGES TO RELEASE
	$CALL	M%RLNP			;[3]RELEASE THE PAGES
	SETZM	J$LPGS(J)		;[3]INDICATE NO MORE FILE TRANSFER PGS

CLNCL3:	SKIPN	S2,J$DECR(J)		;[3]ANY MESSAGE PAGES ALLOCATED?
	JRST	CLNCL4			;[3]NO, CLOSE ANY FILES
	HRRZS	S2			;[3]CHANGE FROM POINTER TO AN ADDRESS
	ADR2PG	S2			;CHANGE ADDRESS TO A PAGE NUMBER 
	MOVEI	S1,2			;TWO PAGES TO RETURN
	$CALL	M%RLNP			;RETURN THE PAGES 

CLNCL4:	SKIPL	J$LCHN(J)		;[3]IS THERE A DECNET DCN: DEVICE JFN?
	$CALL	ABTLNK			;YES, RELEASE IT
	SETO	S1,			;[3]DELETE ANY TEMPORARY FILES
	$CALL	CFILES			;CLOSE ANY FILES THAT MAY BE OPEN
	TXZE	S,TEMFIL		;ANY TEMPORARY FILES CREATED?
	$CALL	DELTEM			;YES, DELETE THEM
	SKIPN	S1,J$FRKH(J)		;PICK UP THE LISTENER'S HANDLE
	JRST	CLNCL5			;THERE IS NO LISTENER
	KFORK%				;KILL THE LISTENER
	 ERJMP	.+1			;IGNORE ANY ERRORS
	SETZM	J$FRKH(J)		;INDICATE NO INFERIOR FORK
CLNCL5:	SETZM	J$CRNM(J)		;RESET NUMBER OF TIMES LISTENER CRASHED
	$RET				;RETURN TO THE SHUTDOWN 
	SUBTTL	FIXCLU - FIXUP CLUSTER LPT PARAMETERS FROM NXTJOB

;FIXCLU is PJRSTed from routine NXTJOB when NXTJOB determines that this is
;a Cluster LPTSPL. FIXCLU zeros out selected job data words.
;The operator is also informed that the print request has been started.
;
;Call is: Call from NXTJOB
;         J/Job Context Pointer
;
;Returns: Selected job data words have been zeroed and the print job's 
;stack has been changed to start at CLJOB
;
FIXCLU:	SETZM	J$CONF(J)		;ZERO OUT CONNECTION FAILURE DURING JOB
	SETZM	J$STAT(J)		;ZERO OUT THE STATUS WORD
	SETZM	J$TEM(J)		;ZERO OUT TEMPORARY FILE'S JFN
	SETZM	J$JFN(J)		;ZERO OUT FILE'S JFN
	SETZM	J$TNUM(J)		;ZERO OUT THE NUMBER OF TEMPORARY FILES
	MOVEI	S1,TFNLEN		;PICK UP LENGTH OF TEMP FILE NAMES TBL
	MOVEI	S2,J$TFIL(J)		;PICK UP ITS ADDRESS
	$CALL	.ZCHNK			;INITIALIZE THE TEMP FILE NAME TABLE
	$WTO	(Begin,<^R/.EQJBB(J)/>,@JOBOBA)
	$RET				;RETURN TO THE IPCF SCHEDULER
	SUBTTL	CLJOB - DO THE CLUSTER LPTSPL PRINT JOB

;CLJOB processes a NEXTJOB message that is to be routed to a remote node
;in the cluster that has a printer. CLJOB insures that the user has access
;to each file in the NEXTJOB message. If the user does not have access,
;then this is indicated in the file's FP so that the LPTSPL on the remote
;node will not print this file.
;Any files not accessible to the remote node will result in a temporary file
;being created in a directory that is shared between the remote and local
;systems. The contents of the inaccessible file will be copied to the
;temporary file. 
;
;Call is: This routine is started by the job processing dispatch scheduler
;Returns: The print request has been forwarded to the node where the files
;         in the print request are to be printed.

;CHECK IF THE USER HAS A VALID ACCOUNT. IF THE USER DOES NOT, THEN THE 
;REMOTE LPTSPL WILL NOT PRINT THE FILES. POINT TO THE FIRST FILE IN THE
;NEXTJOB MESSAGE.

CLJOB:	LOAD	S1,.EQSEQ(J),EQ.IAS	;GET INVALID ACCOUNT STRING BIT
	STORE	S1,S,ABORT		;SAVE IT AS THE ABORT BIT
	LOAD	E,.EQLEN(J),EQ.LOH	;GET LENGTH OF HEADER
	ADD	E,J			;POINT TO FIRST FILE

;CHECK THAT THE USER HAS ACCESS TO THE FILES IN THE PRINT REQUEST

	TXNE	S,ABORT			;IN THE ABORT STATE?
	JRST	CLJOB6			;YES, LET REMOTE LPTSPL TELL THE USER
CLJOB2:	$CALL	INPOPN			;CHECK IF USER HAS ACCESS TO THIS FILE
	JUMPF	CLJOB4			;NO, INDICATE IN THE FILE'S FP
	MOVE	S1,J$DIFN(J)		;YES, PICK UP THE FILE'S IFN
	$CALL	F%REL			;CLOSE AND RELEASE THE JFN
	MOVE	P1,.FPINF(E)		;PICK UP THE FILE PARAMETER INFO WORD
	TXNN	P1,FP.DEL		;IS THE FILE TO BE DELETED?
	JRST	CLJOB5			;NO, CHECK THE NEXT FILE
	MOVEI	S1,FOB.SZ		;PICK UP THE FILE OBJECT BLOCK SIZE
	MOVEI	S2,J$XFOB(J)		;PICK UP THE FILE OBJECT BLOCK ADDRESS
	$CALL	F%AOPN			;CHECK IF THE USER HAS WRITE ACCESS
	JUMPT	CLJOB3			;YES, GO CLOSE THE FILE
	TXZ	P1,FP.DEL		;NO, TURN OFF THE DELETE BIT
	MOVEM	P1,.FPINF(E)		;INDICATE NO DELETE IN THE FILE'S FP
	JRST	CLJOB5			;GO CHECK THE NEXT FILE
CLJOB3:	$CALL	F%REL			;RELEASE THE FILE
	JRST	CLJOB5			;GO CHECK THE NEXT FILE

;THE USER DOES NOT HAVE READ ACCESS TO THIS FILE. INDICATE THIS TO THE
;REMOTE LPTSPL. ALSO, TURN OFF THE DELETE BIT

CLJOB4:	MOVX	S1,FP.NRA		;INDICATE NO READ ACCESS 
	IORM	S1,.FPINF(E)		;PLACE IN THE FILE'S FP
	MOVX	S1,FP.DEL		;PICK UP THE DELETE THIS FILE BIT
	ANDCAM	S1,.FPINF(E)		;INDICATE DON'T DELETE THIS FILE
CLJOB5:	$CALL	NXTFIL			;PICK UP THE NEXT FILE
	JUMPT	CLJOB2			;AND LOOP

;CHECK IF THERE IS A DECNET DCN: JFN. THERE MAY NOT BE ONE DUE TO A TIME-OUT
;OR A PREVIOUS DECNET LINK LOST.
;CHECK STATUS OF THE LINK. IF THE LINK IS NO LONGER CONNECTED, THEN RE-OPEN IT

CLJOB6:	SETZM	J$DIFN(J)		;[3]INDICATE ALL FILES ARE CLOSED
	SKIPGE	J$LCHN(J)		;IS THERE A DECNET DCN: JFN?
	JRST	CLJOB7			;NO, GET ONE AND ATTEMPT TO OPEN A LINK
	$CALL	CHKLNK			;CHECK IF THE DECNET LINK IS CONNECTED
	JUMPT	CLJOB9			;THE LINK IS CONNECTED, CHECKSUM MSG
	SKIPLE	S1			;WAS THERE A FATAL ERROR?
	JRST	CLJO15			;YES, GO SHUTDOWN
CLJOB7:	$CALL	OPNLNK			;OPEN THE DECNET LINK
	JUMPF	CLJO15			;A FATAL ERROR WAS DETECTED, SHUTDOWN

REPEAT 0,<
;IF CHECKSUMMING IS ENABLED, THEN CHECKSUM THE MESSAGE.

CLJOB8:
;	SETZM	.MSCHS(J)		;ASSUME CHECKSUMMING NOT ENABLED
	SKIPN	CHECKS			;IS CHECKSUMMING ENABLED?
	JRST	CLJOB9			;NO, GO SEND MESSAGE
	MOVE	S1,J			;YES, PICK UP ADDRESS OF THE MESSAGE
	$CALL	CHKSUM			;CHECKSUM THE MESSAGE
>
;INDICATE IN THE MESSAGE THAT THIS IS A REMOTE PRINT REQUEST AND INDICATE
;WHETHER ACCOUNTING IS ENABLED OR NOT. ALSO INDICATE THE NODE THE MESSAGE
;ORIGINATED FROM.

CLJOB9:	$CALL	UPDMSG			;UPDATE THE MESSAGE

;SET THE STATE TO "NEXTJOB MESSAGE RESPONSE" AND SEND THE MESSAGE.

CLJO10:	MOVX	S1,.JSNMR		;NEXTJOB MESSAGE RESPONSE
	MOVEM	S1,J$STAT(J)		;[3]REMEMBER THE STATE
	MOVE	S1,J$LCHN(J)		;PICK UP THE DECNET DCN: DEVICE JFN	
	MOVE	S2,J			;PICK UP THE ADDRESS OF THE MESSAGE
	HRLI	S2,(POINT 36)		;MAKE IT INTO A POINTER
	LOAD	T1,.MSTYP(J),MS.CNT	;PICK UP THE MESSAGE LENGTH
	MOVNS	T1			;MAKE IT NEGATIVE
	TXO	S,INJOB			;LET LINK DISCONNECT HANDLER KNOW 
	SOUTR%				;SEND THE MESSAGE
	 ERJMP	CLJO13			;DETERMINE THE ERROR,  CHECK FOR RETRY

CLJO11:	SETZ	S1,			;DON'T WAKE UP UNTIL INTERRUPTED
	$CALL	I%SLP			;WAIT FOR THE NEXT INTERRUPT

;IF A SENDER IS AT INTERRUPT LEVEL AND THE DECNET LINK BECOMES DISCONNECTED,
;THEN WHEN THE SENDER DEBRKS FROM THE INTERRUPT LEVEL, IT WILL NOT BE 
;INTERRUPTED TO BE INFORMED THAT ITS LINK IS NO LONGER CONNECTED. THEREFORE,
;THE SENDER MUST CHECK THE STATUS OF THE LINK WHEN IT DEBRKS.

	$CALL	CHKLNK			;CHECK THE LINK STATUS
	JUMPT	CLJO11			;THE LINK IS STILL CONNECTED
	SKIPLE	S1			;DID A FATAL ERROR OCCUR?
	JRST	CLJO15			;YES, GO SHUTDOWN
	$CALL	RESET			;NO, ATTEMPT TO RESET THE STATE
	JUMPT	CLJO10			;RE-ATTEMPT TO PROCESS THE NEXTJOB MSG
	MOVEI	S1,[ASCIZ/Too many DECnet errors/] ;PICK UP ERROR TEXT
	JRST	CLJO15			;GO SHUTDOWN

;A SOUTR HAS FAILED. IF THE LINK IS STILL CONNECTED, THEN ASSUME THE
;LISTENER HAS CRASHED AND RE-ATTEMPT TO OPEN THE LINK.
;IF THE LINK IS NO LONGER CONNECTED, THEN RE-ATTEMPT TO OPEN THE LINK.
;ONCE THE LINK IS OPEN, RESET THE STATE TO PRIOR TO SENDING THE NEXTJOB
;MESSAGE.

CLJO13:	$CALL	RESTAR			;CAN THE NEXTJOB REQUEST BE RESTARTED?
	JUMPF	CLJO15			;NO, GO SHUTDOWN 
CLJO14:	$CALL	OPNLNK			;ATTEMPT TO CONNECT THE LINK
	JUMPT	CLJO10			;ATTEMPT TO SEND THE NEXTJOB MESSAGE

;AN ERROR HAS BEEN DETECTED. IF THE ERROR IS FATAL, THEN CLOSE THE DECNET
;DCN: DEVICE JFN AND INFORM QUASAR TO SHUT THIS LPTSPL DOWN. ALSO INFORM
;THE OPERATOR. IF THE ERROR IS NOT FATAL, THEN QUASAR WILL TEMPORARILY
;SHUT THE PRINTER DOWN.

CLJO15:	SKIPE	S1			;[3]SKIP IF TEMPORARY SHUTDOWN
	$CALL	REPERR			;REPORT FATAL ERROR TO QUASAR AND ORION
	PJRST	SHUTIN			;SHUT DOWN THIS LPTSPL
	SUBTTL	INTDAV - INTERRUPT ROUTINE FOR DECNET MESSAGE AVAILABLE

;INTDAV is invoked when a "data available or disconnect pending"
;interrupt occurs. INTDAV determines the reason for the interrupt.
;If the interrupt is a spurious interrupt, then INTDAV DEBRKs.
;If the interrupt is due to a message from the listener having arrived,
;then INTDAV picks up the message, determines the message type and
;processes it.
; If the interrupt is due to the link connection being broken, then
;INTDAV determines if a job stream is active or not. If a job stream
;is not active (or if a job stream is active, but the NEXTJOB message
;has not yet been sent to the remote node), then INTDAV DEBRKs.
; If there is an active job stream which has forwarded the NEXTJOB message
;to the listener, then INTDAV aborts the link and resets the job stream
;status to that prior to sending the NEXTJOB message.

INTDAV:	$BGINT	1,			;SAVE THE PREVIOUS CONTEXT

;CHECK IF THE INTERRUPT IS DUE TO A MESSAGE BEING AVAILABLE FROM THE
;LISTENER OR NOT. IF THERE IS A MESSAGE, THEN PROCESS IT. IF THERE IS NO
;MESSAGE, THEN CHECK IF THE INTERRUPT IS SPURIOUS OR IS DUE TO THE DECNET 
;LINK NO LONGER BEING CONNECTED.

	SKIPGE	S1,J$LCHN(J)		;IS THERE A DECNET DCN: DEVICE JFN?
	JRST	INTD15			;NO, TREAT AS A SPURIOUS INTERRUPT
	SIBE%				;CHECK FOR A MESSAGE
	JRST	INTDA1			;THERE IS A MESSAGE, PICK IT UP

;IF CHKLNK RETURNS FALSE, THEN THERE ARE 3 POSSIBILITIES:
; 1. CHKLNK ENCOUNTERED A FATAL ERROR: SHUT THE PRINTER DOWN
; 2. WAITING FOR A CONNECTION (THIS SHOULD NEVER HAPPEN): TREAT AS A SPURIOUS
;    INTERRUPT.
; 3. CONNECTION HAS BEEN LOST: IF NO ACTIVE JOB (OR AN ACTIVE JOB BUT HAS NOT
;     YET SENT THE NEXTJOB MESSAGE), THEN DEBRK. IF THE NEXTJOB MESSAGE HAS
;     BEEN SENT, THEN RESTORE STATE TO PRIOR TO SENDING NEXTJOB MESSAGE AND
;     ATTEMPT TO RE-CONNECT THE LINK

	$CALL	CHKLNK			;NO MESSAGE, CHECK LINK STATUS
	JUMPT	INTD15			;[3]LINK IS CONNECTED, SO SPURIOUS
	SKIPLE	S1			;[3]DID A FATAL ERROR OCCUR?
	JRST	INTD13			;[3]YES, THEN SHUTDOWN
	SKIPE	S1			;[3]WAITING FOR A CONNECTION?
	JRST	INTD15			;[3]YES, TREAT AS SPURIOUS
	JRST	INTDA9			;[3]LOST THE LINK, CHECK CONTEXT

;PICK UP THE MESSAGE FROM THE LISTENER

INTDA1:	MOVE	S1,J$LCHN(J)		;PICK UP THE DCN: DEVICE JFN
	MOVE	S2,J$DECR(J)		;PICK UP THE POINTER TO MESSAGE
	MOVNI	T1,PAGSIZ		;[3]PICK UP MAXIMUM MESSAGE SIZE
	SINR%				;PICK UP THE MESSAGE
	 ERJMP	INTD11			;ABORT THE LINK AND RE-OPEN

	MOVE	S1,J$STAT(J)		;PICK UP STATE LPTSPL IS IN
	JFFO	S1,.+1			;PICK UP DISPATCH OFFSET
	CAIL	S2,VALMIN		;IS THIS A VALID OFFSET?
	CAILE	S2,VALMAX		;YES, IS THIS A VALID OFFSET?
	$STOP	(IFM,Illegally formatted message from the listener)
	JRST	@INTDA2(S2)		;PROCESS ACCORDING TO STATE

INTDA2:	EXP 0				;[3]FIRST WORD NOT USED
	INTDA3				;NEXTJOB MESSAGE RESPONSE
	INTDA7				;[3]TRANSFER FILE MESSAGE RESPONSE

;THE STATE OF LPTSPL IS "NEXTJOB MESSAGE RESPONSE". CHECK IF THE RESPONSE
;IS SUCCESS. IF IT IS, THEN CLEAR THE STATE, CLEAR THE DECNET INACTIVITY
;COUNTER AND RESET THE PC TO PROCESS THE END OF JOB.

INTDA3:	ADDI	T1,PAGSIZ		;[3]CALCULATE NUMBER OF WORDS IN MSG
	CAIG	T1,1			;[3]IS THIS AN ACK MESSAGE?
	JRST	INTDA7			;YES, GO END THIS REQUEST

;THE PRINT REQUEST CONTAINED ONE OR MORE FILES NOT ACCESSIBLE ON THE
;REMOTE NODE. COPIES OF THESE FILES WILL BE PLACED IN A SHARED
;DIRECTORY WITH THE REMOTE SYSTEM. THE NAMES OF THESE FILES WILL
;BE PASSED TO THE LISTENER.

INTDA4:	$CALL	DISINT			;DEACTIVATE DISCONNECT CHANNEL
	MOVEI	S1,XFERFI		;FORCE OUT OF THE WAIT
	MOVEM	S1,LEV1PC		;STORE THE NEW PC HERE
	JRST	INTD15			;GO RESTORE THE CONTEXT

REPEAT 0,<
;THE STATE OF CLUSTER LPTSPL IS "TRANSFER FILE MESSAGE RESPONSE. CHECK IF
;THE RESPONSE IS A SUCCESS ACK OR IF THE TRANSFER FILE RESPONSE MESSAGE
;MUST BE RESENT.

INTDA5:	CAIN	S1,1			;IS THIS A SUCCESS MESSAGE?
	JRST	INTDA7			;YES, SO FINISH UP
	MOVE	S2,J$DECR(J)		;NO, SO RESEND RESPONSE MESSAGE

;LISTENER'S CHECKSUM OF MESSAGE SENT TO IT DOES NOT EQUAL CHECKSUM CALCULATED
;LOCALLY. RESEND THE MESSAGE.

INTDA6:	HRLI	S2,(POINT 36)		;MAKE IT INTO A POINTER
	MOVE	S1,J$LCHN(J)		;PICK UP THE DECNET DCN: DEVICE JFN	
	LOAD	T1,.MSTYP(J),MS.CNT	;PICK UP THE MESSAGE LENGTH
	MOVNS	T1			;MAKE IT NEGATIVE
	SOUTR%				;SEND THE MESSAGE
	 ERJMP	INTD11			;RE-OPEN THE LINK
	JRST	INTD15			;GO RESTORE THE CONTEXT
>

;THE NEXTJOB REQUEST HAS BEEN PROCESSED, END THIS REQUEST

INTDA7:	SETZM	J$STAT(J)		;CLEAR THE STATE
	TXZ	S,INJOB!TEMFIL		;NO LONGER PROCESSING NEXTJOB MESSAGE
	TXO	S,GOODBY		;INDICATE LEAVING THIS JOB
	SETZM	J$TNUM(J)		;NO TEMPORARY FILES
	$CALL	CASTIM			;CLEAR AND RESET DECNET INACTIVITY TIMER
	MOVEI	S1,ENDREQ		;FORCE OUT OF THE WAIT
	MOVEM	S1,LEV1PC		;STORE THE NEW PC HERE
	JRST	INTD15			;GO RESTORE THE CONTEXT

;THE LINK IS NO LONGER CONNECTED. CHECK THE CONTEXT

INTDA9:	SKIPE	JOBACT			;[3]IS THERE AN ACTIVE JOB?
	TXNN	S,INJOB!WAITIR		;YES, NEXTJOB MSG SENT/WAITING RESP?
	JRST	INTD15			;NO TO EITHER, RETURN TO PREVIOUS CONTEXT

;CHECK IF WAITING FOR AN INTERRUPT MESSAGE RESPONSE FROM THE LISTENER.
;IF SO, THEN END THIS PRINT REQUEST

	TXZN	S,WAITIR		;WAITING FOR INTERRUPT MSG RESPONSE?
	JRST	INTD11			;NO, GO RESET THE STATE
	MOVEI	S1,ENDREQ		;CHANGE PC TO END THIS REQUEST
	MOVEM	S1,LEV1PC		;SAVE THE PC
	JRST	INTD15			;RETURN TO THE NEW CONTEXT

;THE NEXTJOB MESSAGE HAS BEEN SENT. RESTORE THE JOB STREAM STATE TO PRIOR
;TO SENDING THE NEXTJOB MESSAGE.

INTD11:	$CALL	RESET			;RESET THE STATE
	JUMPF	INTD12			;SHUTDOWN ON A FATAL ERROR
	MOVEI	S1,CLJO14		;SET PC TO PRIOR TO SENDING NEXTJOB MSG
	MOVEM	S1,LEV1PC		;SAVE THE CHANGED PC
	JRST	INTD15			;RETURN TO CLJOB

;A FATAL ERROR HAS OCCURRED. SHUTDOWN LPTSPL

INTD12:	MOVEI	S1,[ASCIZ/Too many DECnet errors/]
INTD13:	MOVEM	S1,J$ERRA(J)		;SAVE THE ERROR TEXT ADDRESS
INTD14:	MOVEI	S1,SHULPT		;CHANGE THE PC TO SHUTDOWN LPTSPL
	MOVEM	S1,LEV1PC		;SAVE THE CHANGED PC

INTD15:	$DEBRK				;RESTORE THE CONTEXT
	SUBTTL	XFERFI - TRANSFER FILES TO THE REMOTE SYSTEM

;XFERFI is invoked by the DECnet interrupt handler INTDAV after it
;receives a TRANSFER FILE message from the remote system. XFERFI
;copies the contents of the files that are inaccessible to the
;remote system into temporary files in a directory that is shared
;between the remote system and the local system. 
;When all the files have been copied, XFERFI sends a TRANSFER FILE
;RESPONSE message to the remote listener.
;
;Call is: Invoked from DECnet interrupt handler INTDAV
;         J/Job Context Pointer
;Returns: The inaccessible files have been copied to a shared directory
;         and a TRANSFER FILE RESPONSE message has been sent. Goes into
;         WAIT state.


;CHECK IF CHECKSUMMING IS ENABLED. IF IT IS, THEN CHECKSUM THE MESSAGE. 
;IF THE CHECKSUMS DO NOT AGREE, THEN SEND A FAIL ACK.

XFERFI:	HRRZ	P1,J$DECR(J)		;PICK UP THE XFER FILE MESSAGE ADDRESS
REPEAT 0,<
;	SKIPE	P2,.MSCHS(P1)		;PICK UP ITS CHECKSUM WORD
;	SETZM	.MSCHS(P1)		;ZERO OUT IN CASE NEED TO DO A CHECKSUM
	MOVEM	P2,J$RCSM(J)		;REMEMBER CHECKSUM WORD FOR LATER
	SKIPN	P2			;REMOTE NODE DOING CHECKSUMS?
	JRST	XFERF1			;NO, SO DON'T CHECKSUM LOCALLY
	SKIPN	CHECKS			;IS CHECKSUMMING ENABLED LOCALLY?
	JRST	XFERF1			;NO, SO GO PROCESS THE RESPONSE
	MOVE	S1,P1			;PICK UP MESSAGE ADDRESS
	$CALL	CHKSUM			;CHECKSUM THE MESSAGE
	CAMN	P2,S1			;DO THE CHECKSUMS EQUAL?
	JRST	XFERF1			;YES, DETERMINE FILES TO BE XFERRED
	$CALL	ENAINT			;ACTIVATE DATA AVAILABLE CHANNEL
	JUMPF	S..CAC			;CRASH IF CAN'T ACTIVATE
	$CALL	SENFAI			;SEND A FAIL ACK
	JUMPF	XFER10			;GO PROCESS THE ERROR
	JRST	CLJO11			;GO WAIT FOR A RESPONSE
>	
;SET UP FOR DETERMINING WHICH FILES NEED TO BE SENT TO THE REMOTE NODE

XFERF1:	MOVE	P2,.OHDRS+.TFNUM(P1)	;PICK UP NUMBER OF FILES
	LOAD	P4,.EQSPC(J),EQ.NUM	;PICK UP NUMBER OF FILES IN NEXTJOB MSG
	CAMLE	P2,P4			;NUMBER XFER FILES CAN'T EXCEED FILES
	$STOP	(TMI,TRANSFER FILE MESSAGE INCONSISTENCY)
	MOVEM	P4,J$RFLN(J)		;SAVE NUMBER OF FILES FOR LATER
	HRRZ	P3,J$DECS(J)		;[3]ADDRESS OF MESSAGE TO SEND BACK
	MOVEI	S1,.OHDRS		;PICK UP RESPONSE MESSAGE HEADER SIZE
	MOVE	S2,P3			;PLACE RESPONSE MESSAGE ADDRESS HERE
	$CALL	.ZCHNK			;ZERO OUT THE RESPONSE MESSAGE HEADER 
	MOVEM	P2,.OHDRS+.TSNUM(P3)	;PLACE # OF FILES IN THE RESPONSE MSG
	ADDI	P3,.OHDRS+.TSHSZ	;POINT TO FIRST FILE STATUS BLOCK
	ADDI	P1,.OHDRS+.TFHSZ	;POINT TO FIRST FP POSITION BLOCK

	LOAD	E,.EQLEN(J),EQ.LOH	;PICK UP THE EQ HEADER LENGTH
	ADD	E,J			;POINT TO 1ST FP IN NEXTJOB MESSAGE
	MOVEI	P4,1			;INDICATE CURRENT FP NUMBER
	TXO	S,TEMFIL		;INDICATE TEMP FILES BEING CREATED

XFERF2:	MOVE	S1,.TFFPP(P1)		;PICK UP RELATIVE FP POSITION
	CAMLE	S1,J$RFLN(J)		;MUST BE LESS OR EQUAL # FILES 
	JRST	S..TMI			;CRASH ON AN INCONSISTENCY
	SUB	S1,P4			;FIND THE DIFFERENCE OF FP POSITIONS
	JUMPE	S1,XFERF3		;IF THE SAME, THEN CHECK FILE ACCESS
XFER2A:	LOAD	S2,.FPLEN(E),FP.LEN	;GET THE FP LENGTH
	ADD	E,S2			;BUMP TO THE FD
	LOAD	S2,.FDLEN(E),FD.LEN	;GET THE FD LENGTH
	ADD	E,S2			;BUMP TO THE NEXT FP
	SOJG	S1,XFER2A		;POSITION TO THE NEXT FP

;CHECK IF THE USER STILL HAS ACCESS TO THIS FILE. IF SO, THEN OPEN
;THE FILE. IF NOT, THEN INDICATE IN THE TRANSFER FILE STATUS MESSAGE
;BY ZEROING THE TEMPORARY FILE NAME WORD.

XFERF3:	$CALL	INPOPN			;OPEN THE FILE
	JUMPF	XFERF7			;ON ERROR, ASSUME FILE INACCESSIBLE
	MOVE	S1,J$DIFN(J)		;PICK UP THE IFN OF THE FILE
	MOVX	S2,FI.CHN		;WANT TO PICK UP THE JFN OF THE FILE
	$CALL	F%INFO			;PICK UP THE FILE'S JFN
	MOVEM	S1,J$JFN(J)		;[10]SAVE THE JFN FOR LATER
	MOVSI	S2,2			;WANT TWO WORDS FROM THE FDB
	HRRI	S2,.FBBYV		;WANT FILE I/O INFO AND NUMBER OF BYTES
	MOVEI	T1,J$FDB(J)		;WHERE TO PLACE THE FILE I/O INFO
	GTFDB%				;PICK UP THE FILE I/O INFO
	 ERJMP	XFERF6			;ASSUME FILE IS NOT ACCESSIBLE

;CREATE A TEMPORARY FILE.

XFERF4:	$CALL	I%NOW			;GET CURRENT UDT
	AND	S1,[070707,,070707]	;MAKE IT SIXBIT NUMBERIC OFFSET FROM 0
	TDO	S1,[SIXBIT/000000/]	;MAKE SIXBIT NUMBERS FROM 0 THROUGH 7
	MOVEM	S1,J$SIXB(J)		;SAVE THE SIXBIT PART OF THE NAME
	$TEXT	(<-1,,J$TNAM(J)>,<^T/DIRNAM/:^N/CNTSTA/-^N/J$RNOD(J)/^W/S1/.LPT;P770000^0>) ;[10]
	MOVX	S1,GJ%SHT!GJ%NEW	;MUST BE A NEW FILE
	HRROI	S2,J$TNAM(J)		;POINT TO THE FILE
	GTJFN%				;PICK UP THE JFN
	 ERJMP	[CAIN S1,GJFX27		 ;DOES THE FILE ALREADY EXIST?
		 JRST XFERF4 		 ;YES, TRY A DIFFERENT FILE NAME
		 JRST XFERF6 ]		 ;NO, INDICATE THE FILE IS INACCESSIBLE
	HRRZS	S1			;ISOLATE THE JFN
	MOVEM	S1,J$TEM(J)		;SAVE THIS FILE'S JFN
	
	LOAD	S2,J$FDB(J),FB%BSZ	;PICK UP THE BYTE SIZE
	LSH	S2,^D30			;PLACE WHERE OPENF% EXPECTS IT
	TXO	S2,OF%WR		;OPEN FOR WRITE
	OPENF%				;OPEN THE TEMPORARY FILE
	 ERJMP	XFERF6			;INDICATE THE FILE IS INACCESSIBLE

;COPY THE FILE INTO THE TEMPORARY FILE

	LOAD	T3,J$FDB(J),FB%PGC	;PICK UP THE NUMBER OF PAGES IN FILE
	SETZ	T4,			;CURRENT PAGE NUMBER OF FILE
XFERF5:	MOVE	S1,T4			;PICK UP THE PAGE NUMBER TO BE MAPPED
	HRL	S1,J$JFN(J)		;PICK UP THE JFN OF THE FILE
	MOVE	S2,J$FILB(J)		;PICK UP THE TRANSFER PAGE NUMBER
	HRLI	S2,.FHSLF		;PICK UP THE HANDLE
	MOVX	T1,PM%RD		;WANT READ ACCESS
	PMAP%				;MAP THIS PAGE
	 ERJMP XFERF6			;ASSUME CAN'T ACCESS THIS FILE

	HRL	S1,J$FADR(J)		;[10]PICK UP XFER PAGE ADDRESS
	MOVE	S2,J$OADR(J)		;[10]PICK UP OUTGOING XFER PAGE ADR
	HRR	S1,S2			;[10]SOURCE,,DESTINATION
	BLT	S1,777(S2)		;[10]COPY FILE PAGE TO OUTGOING BUFFER
	MOVE	S1,J$FILO(J)		;[10]PICK UP PAGE NUMBER TO PMAP
	HRLI	S1,.FHSLF		;PICK UP FORK HANDLE
	MOVE	S2,T4			;PAGE NUMBER TO MAP PAGE TO IN TEMP 
	HRL	S2,J$TEM(J)		;PICK UP TEMP FILE'S JFN
	MOVX	T1,PM%RD		;WANT READ ACCESS
	PMAP%				;MAP THE PAGE TO THE TEMP FILE
	 ERJMP	XFERF6			;ASSUME CAN'T ACCESS THIS FILE

	SETO	S1,			;INDICATE UNMAP THE PAGE FROM PROCESS
	MOVE	S2,J$FILB(J)		;PICK UP PAGE NUMBER
	HRLI	S2,.FHSLF		;PICK UP FORK HANDLE
	MOVEI	T1,1			;UNMAP ONLY ONE PAGE
	PMAP%				;UNMAP THE PAGE
	 ERJMP	XFERF6			;ASSUME CAN'T ACCESS THIS FILE

	$DSCHD(0)			;FORCE A SCHEDULING PASS

;IF THIS JOB HAS BEEN ABORTED, CANCELLED OR REQUEUED, THEN END THIS PRINT
;REQUEST, OTHERWISE, GO MAP THE NEXT PAGE OF THE FILE

	TXNE	S,ABORT!RQB		;TIME TO QUIT?
	JRST	XFER14			;YES, GO CLEAN UP
	AOS	T4			;INCREMENT THE PAGE NUMBER
	SOJG	T3,XFERF5		;MAP THE NEXT PAGE OF THE FILE

;UPDATE THE TEMPORARY'S FILE FDB TO REFLECT THE BYTE SIZE AND NUMBER OF
;BYTES OF THE FILE THAT WAS INACCESSIBLE TO THE REMOTE SYSTEM.

	MOVE	S1,J$TEM(J)		;PICK UP TEMP FILE'S JFN
	HRLI	S1,.FBBYV		;CHANGE THE FILE I/O WORD
	TXO	S1,CF%NUD		;DO NOT WAIT FOR DISK COPY UPDATE
	SETO	S2,			;UPDATE THE ENTIRE WORD
	MOVE	T1,J$FDB(J)		;NEW FILE I/O WORD
	CHFDB%				;UPDATE THE FILE I/O WORD
	 ERJMP	XFERF6			;ON ERROR ASSUME CAN'T ACCESS FILE

	MOVE	S1,J$TEM(J)		;PICK UP TEMP FILE'S JFN
	HRLI	S1,.FBSIZ		;CHANGE THE NUMBER OF BYTES
	SETO	S2,			;UPDATE THE ENTIRE WORD
	MOVE	T1,J$FDB+1(J)		;NEW BYTE COUNT IN TEMP FILE
	CHFDB%				;UPDATE THE BYTE COUNT OF TEMP FILE
	 ERJMP	XFERF6			;ON ERROR ASSUME CAN'T ACCESS FILE

;PLACE THE 6 CHARACTER NUMBERIC PART OF THE TEMPORARY FILE NAME INTO THE
;TRANSFER FILE RESPONSE MESSAGE.

	SETZ	S1,			;CLOSE, BUT DON'T DELETE, THE TEMP FILE
	$CALL	CFILES			;CLOSE THE FILE AND TEMPORARY FILE
	MOVE	S2,J$TNUM(J)		;PICK UP OFFSET INTO TEMP FILE NAME BLK
	AOS	J$TNUM(J)		;INCREMENT THE NUMBER OF TEMP FILES
	MOVE	S1,J$SIXB(J)		;PICK UP SIXBIT PART OF TEMP FILE NAME
	MOVEM	S1,.TSTFN(P3)		;PLACE IN THE RESPONSE MESSAGE
	ADD	S2,J			;POINT TO CURRENT TEMP FILE NAME
	MOVEM	S1,J$TFIN(S2)		;PLACE TEMP FILE NAME IN BLOCK
	JRST	XFERF8			;GO PLACE IN RESPONSE MESSAGE


;HERE IF THE FILE IS INACCESSIBLE. INDICATE THIS IN THE TRANSFER FILE RESPONSE
;MESSAGE. ALSO CLOSE AND RELEASE ANY JFNS. IF A TEMPORARY FILE HAS BEEN
;CREATED, THEN DELETE IT.

XFERF6:	SETO	S1,			;DELETE THE TEMPORARY FILE
	$CALL	CFILES			;CLOSE THE FILE AND TEMPORARY FILE
XFERF7:	SETZM	.TSTFN(P3)		;INDICATE CAN'T ACCESS THIS FILE
XFERF8:	MOVE	S1,.TFFPP(P1)		;PICK UP RELATIVE FP POSITION
	MOVEM	S1,.TSFPP(P3)		;PLACE IN RESPONSE MESSAGE

;UPDATE THE COUNTERS

	MOVE	P4,.TFFPP(P1)		;CURRENT FP IN THE NEXTJOB MESSAGE
	ADDI	P1,.TFFPS		;POINT TO NEXT RELATIVE FP BLOCK
	ADDI	P3,.TSSIZ		;POINT TO NEXT BLOCK IN RESPONSE MSG
	SOJG	P2,XFERF2		;COPY THE NEXT UNACCESSIBLE FILE

;FIND THE LENGTH OF TRANSFER FILES RESPONSE MESSAGE AND STORE IT IN THE MESSAGE

	HRRZ	P1,J$DECS(J)		;PICK UP THE ADDRESS OF THE MESSAGE
	MOVE	S1,.OHDRS+.TSNUM(P1)	;PICK UP THE NUMBER OF FILE STATUS BLKS
	IMULI	S1,.TSSIZ		;MULTIPLY BY SIZE OF THE BLOCKS
	ADDI	S1,.OHDRS+.TSHSZ	;ADD IN THE HEADER SIZES
	STORE	S1,.MSTYP(P1),MS.CNT	;PLACE MESSAGE LENGTH IN MESSAGE
	MOVN	T1,S1			;[3]SAVE THE LENGTH FOR THE SOUTR%

REPEAT 0,<
;CHECKSUM THE MESSAGE IF NECESSARY

	SKIPN	CHECKS			;CHECKSUMMING ENABLED ON LOCAL SYSTEM?
	JRST	XFERF9			;NO, SO JUST SEND THE MESSAGE
	SKIPN	J$RCSM(J)		;CHECKSUMMING ENABLED ON REMOTE SYSTEM?
	JRST	XFERF9			;NO, SO JUST SEND THE MESSAGE
	MOVE	S1,P1			;PICK UP ADDRESS OF RESPONSE MESSAGE
	$CALL	CHKSUM			;CHECKSUM THE MESSAGE
>
;SET STATE OF LPTSPL TO TRANSFER FILE MESSAGE RESPONSE. SEND THE MESSAGE

XFERF9:	MOVX	S1,.JSTMR		;TRANSFER FILE MESSAGE RESPONSE
	MOVEM	S1,J$STAT(J)		;UPDATE CLUSTER LPTSPL'S STATE
	MOVE	S1,J$LCHN(J)		;PICK UP DECNET DCN: DEVICE JFN
	MOVE	S2,J$DECS(J)		;PICK UP RESPONSE MESSAGE ADDRESS
	SOUTR%				;SEND THE MESSAGE TO THE LISTENER
	 ERJMP	XFER10			;GO DETERMINE THE ERROR
	$CALL	ENAINT			;ACTIVATE THE DISCONNECT CHANNEL
	JUMPT	CLJO11			;GO WAIT FOR A RESPONSE
	JRST	S..CAC			;CAN'T ACTIVATE CHANNEL

;A SOUTR% HAS FAILED. CHECK IF THE LINK IS STILL CONNECTED. IF IT IS,
;THEN TREAT AS A FATAL ERROR AND CONSEQUENTLY SHUTDOWN. 

XFER10:	$CALL	RESTAR			;CAN THIS JOB BE RESTARTED?
	JUMPF	XFER12			;NO, GO ACTIVATE DATA AVAILABLE CHANNEL
	$CALL	ENAINT			;YES, ACTIVATE DATA AVAILABLE CHANNEL
	JUMPT	CLJO14			;ATTEMPT TO OPEN LINK AND TRY AGAIN
	JRST	S..CAC			;CAN'T ACTIVATE THE CHANNEL

XFER12:	MOVEM	S1,J$ERRA(J)		;SAVE THE ERROR TEXT ADDRESS
	$CALL	ENAINT			;ACTIVATE THE DATA AVAILABLE CHANNEL
	JUMPF	S..CAC			;CAN'T ACTIVATE THE CHANNEL
	MOVE	S1,J$ERRA(J)		;PICK UP THE ERROR TEXT ADDRESS
XFER13:	$CALL	REPERR			;NO, REPORT ERROR TO QUASAR AND ORION
	PJRST	SHUTIN			;SHUTDOWN 


;A CANCEL, ABORT, OR REQUEST MESSAGE HAS BEEN GIVEN FOR THIS PRINT JOB.
;CLOSE ANY FILES, DELETE ANY TEMPORARY FILES, RE-ENABLE THE DATA AVAILABLE/
;DISCONNECT PENDING CHANNEL, AND SEND AN INTERRUPT MESSAGE TO THE LISTENER
;INDICATING THAT IT SHOULD CEASE PROCESSING THIS PRINT REQUEST. END THIS
;PRINT REQUEST.

XFER14:	SETO	S1,			;DELETE THE OPEN TEMPORARY FILE
	$CALL	CFILES			;DELETE THE TEMPORARY FILE
	TXZ	S,TEMFIL!INJOB		;INDICATE NO TEMPORARY FILES
	$CALL	DELTEM			;DELETE THE TEMPORARY FILES
	$CALL	SNDINT			;SEND THE INTERRUPT MSG TO LISTENER
	JUMPT	XFER15			;GO WAIT FOR THE LISTENER RESPONSE
	SKIPN	S1			;DID A FATAL ERROR OCCUR?
	PJRST	ENDREQ			;NO, SO JUST END THIS JOB
	$CALL	REPERR			;YES, TELL QUASAR AND ORION
	PJRST	SHUTIN			;SHUT DOWN THE PRINTER

XFER15:	WAIT%				;WAIT FOR THE LISTENER RESPONSE
	SUBTTL	SHULPT - SHUTDOWN DUE TO A FATAL INTERRUPT ROUTINE ERROR

;SHULPT is invoked if routine INTDAV (the "data available or disconnect
;pending" interrupt routine) detects a fatal error. SHULPT informs QUASAR
;that the printer is shutting down. SHULPT informs ORION the reason why
;the printer is shutting down. The printer is then shut down.
;
;Call is: Invoked from INTDAV
;         J/Job Context Pointer
;Returns: Returns through routine SHUTIN

SHULPT:	MOVE	S1,J$ERRA(J)		;PICK UP THE ERROR TEXT ADDRESS
	$CALL	REPERR			;REPORT THE ERROR TO QUASAR AND ORION
	PJRST	SHUTIN			;GO SHUT THE PRINTER DOWN
	SUBTTL	RESTAR - RESTART A NEXTJOB REQUEST

;RESTAR is called after a SOUTR% fails to the remote listener. RESTAR
;checks if the DECnet link is still connected. If it is, then the
;error is assumed to be fatal and the Cluster LPTSPL will be shut down.
;If the link is no longer connected, then the state of the Cluster
;LPTSPL is reset to the state prior to sending the NEXTJOB request to
;the remote listener.
;
;Call is:       J/Job Context Pointer
;Returns true:  The link is no longer connected. The state has been reset
;Returns false: The link is no longer connected and too many DECnet errors
;               have occurred
;               S1/Address of the error text

RESTAR:	$CALL	RESET			;RESET THE STATE
	JUMPF	RESTA2			;SHUTDOWN ON A FATAL ERROR
	$RETT				;INDICATE OPEN LINK AND TRY AGAIN
RESTA2:	MOVEI	S1,[ASCIZ/Too many DECnet errors/]
	$RETF				;INDICATE SHUTDOWN
	SUBTTL	REPERR - REPORT FATAL ERROR TO QUASAR

;REPERR is called by Cluster LPTSPL when it has detected a fatal DECnet error
;or if accounting is enabled and the listener cannot be started.
;REPERR sends a SETUP RESPONSE message to QUASAR indicating that this LPTSPL
;is to be shut down. It also sends a message to ORION indicating that a fatal
;error has occurred and that it is being shut down.
;
;Call is: J/Job Context Pointer
;         S1/Address of ASCIZ error text
;Returns: The SETUP RESPONSE message has been sent to QUASAR and a WTO
;         message has been sent to ORION

REPERR:	$WTO	(<Fatal LPTSPL error detected>,<^T/0(S1)/>,@JOBOBA)
	MOVX	S1,%RSUDE		;NEVER AVAILABLE
	$CALL	RSETUP			;SEND SETUP RESPONSE TO QUASAR
	$RET				;RETURN TO THE CALLER

REPEAT 0,<
	SUBTTL	CHKSUM - CHECKSUM DECNET MESSAGES

;CHKSUM checksums messages that Cluster LPTSPL sends to the listener.
;The checksum is stored in the checksum word. The listener, upon
;receipt of the message, also checksums it. If the checksums agree,
;then the listener sends a success ACK back to the sender, otherwise,
;it sends an error ACK.
;If the sender's node does not have checksumming enabled, then the
;sender sends a zero as the checksum value. The listener, in this
;case, always returns a success ACK.
;If the listener's node does not have checksumming enabled, then it
;always sends a success ACK back.
;(Note: 1. If the calculated checksum equals zero, then CHKSUM changes
;          it to -1.
;       2. CHKSUM, when calculating the checksum, assumes that the checksum
;          word contains zero.)
;
;Call is: S1/Address of the message
;Returns: The checksum has been calculated and placed in the message
;         checksum word (.MSCHS).
;         S1/Contains the checksum

CHKSUM:	$SAVE	<P1>			;SAVE THIS AC

;INITIALIZE THE CHECKSUM PARAMETERS

	LOAD	S2,.MSTYP(S1),MS.CNT	;PICK UP LENGTH OF THE MESSAGE
	MOVSS	S2			;PLACE LENGTH FOR AOBJN
	MOVNS	S2			;MAKE THE COUNTER
	HRR	S2,S1			;COMPLETE THE AOBJN COUNTER
	SETZ	P1,			;SET CHECKSUM TO ZERO
	JCRY0	.+1			;CLEAR THE CARRY 0 BIT

;COMPUTE THE CHECKSUM

COMCH1:	ADD	P1,0(S2)		;ADD THE NEXT MESSAGE WORD TO CHECKSUM
	JCRY0	[AOJA P1,.+1]		;ADD ONE IF CARRY 0 BIT IS SET
	AOBJN	S2,COMCH1		;GO ADD IN THE NEXT MESSAGE WORD

;IF CHECKSUM IS 0, THEN MAKE -1

	SKIPN	P1			;IF CHECKSUM NOT 0, THEN FINISHED
	SETO	P1,			;MAKE THE CHECKSUM -1
;	MOVEM	P1,.MSCHS(S1)		;PLACE CHECKSUM IN THE MESSAGE
	MOVE	S1,P1			;PLACE CHECKSUM IN RETURN AC
	$RET				;RETURN TO THE CALLER
>
	SUBTTL	RESET - RESET THE STATE OF CLUSTER LPTSPL

;RESET is called if Cluster LPTSPL detects that the DECnet link is no
;longer connected while it is processing a print request. Cluster LPTSPL
;assumes that the remote listener did not receive or did not complete
;processing the NEXTJOB request. Cluster LPTSPL will, therefore, attempt
;to resend the NEXTJOB request. RESET resets the state of Cluster LPTSPL
;to just prior to its sending the NEXTJOB request. RESET does the following:
; 1. Closes and releases the DECnet DCN: device JFN.
; 2. If a file to be printed is open, then it is closed.
; 3. If temporary files are being created and they have not all yet been
;    created, then any temporary files are deleted and expunged.
;RESET also determines if too many DECnet errors (i.e., losing DECnet
;connections) have occurred while processing the current job request.
;If so, then Cluster LPTSPL is shut down.
;
;Call is:       J/Job Context Pointer
;Returns true:  The state of Cluster LPTSPL has been successfully reset
;Returns false: Too many DECnet connection losts have occurred while
;               processing the current job request

RESET:	SKIPL	J$LCHN(J)		;IS THERE A DECNET DCN: DEVICE JFN?
	$CALL	ABTLNK			;YES, CLOSE AND RELEASE DECNET DCN: JFN
	SETO	S1,			;DELETE ANY OPEN TEMPORARY FILE
	$CALL	CFILES			;CLOSE ANY OPEN FILES
	TXZE	S,TEMFIL		;HAVE TEMPORARY FILES BEEN CREATED?
	$CALL	DELTEM			;YES, DELETE ANY TEMPORARY FILES
	SETZM	J$STAT(J)		;CLEAR STATE WORD
	TXZ	S,INJOB			;INDICATE PRIOR TO NEXTJOB SEND

	AOS	S1,J$CONF(J)		;INCREMENT # OF CONNECTION FAILURES
	CAILE	S1,MAXFAI		;TIME TO SHUTDOWN?
	$RETF				;YES, INDICATE TO CALLER TO SHUTDOWN
	$RETT				;INDICATE TRY OPEN LINK AGAIN
	SUBTTL	UPDMSG - UPDATE THE NEXTJOB MESSAGE

;UPDMSG is called by Cluster LPTSPL to update the NEXTJOB message before
;it is sent to the remote node. The updating consists of:
; 1. Indicate the NEXTJOB message is from a different node than the node
;    it is to be printed on.
; 2. Indicate if accounting is enabled on the node the message came from
; 3. Indicate in word .EQNOD the node the message has come from
; 4. If a generic LPT object is specified, then ensure that the units
;    field is zero.
;
;Call is: J/Job Context Pointer
;Returns: The NEXTJOB message has been updated


UPDMSG:	MOVE	S1,CNTSTA		;PICK UP THE LOCAL NODE NAME
	MOVEM	S1,.EQNOD(J)		;PLACE IN THE NEXTJOB MESSAGE
IFN FTACNT<
	MOVX	S1,EQ.RLT!EQ.RAI	;REMOTE LPT AND ACCOUNTING ENABLED
>
IFE FTACNT<
	MOVX	S1,EQ.RLT		;CAME FROM A REMOTE LPT
>
	IORM	S1,.EQSEQ(J)		;INDICATE IN THE MESSAGE
	MOVX	S1,.CLLPT		;[3]PICK UP THE CLUSTER LPT BIT
	ANDCAM	S1,.EQROB+.ROBTY(J)	;[3]TURN OFF FOR THE REMOTE QUASAR

	SETZ	S2,			;[5]ASSUME %GENRC 
	LOAD	S1,.EQROB+.ROBAT(J),RO.ATR ;[5]PICK UP THE ATTRIBUTES
	CAIN	S1,%GENRC		;[5]GENERIC?
	STORE	S2,.EQROB+.ROBAT(J),RO.UNI ;[5]YES, ZERO THE UNITS FIELD
	$RET				;RETURN TO THE CALLER
	SUBTTL	CFILES - CLOSE THE INACCESSIBLE FILE AND TEMPORARY FILE.

;CFILES is called to close a file that has had its contents copied to a
;temporary file on a structure that is shared between the remote system
;and the local system. 
;If the caller has detected an error condition, then the temporary file
;is also deleted
;
;Call is: J/Job Context Pointer
;         S1/0  Just close the temporary file
;         S1/-1 Close and delete the temporary file
;Returns: The files have been closed

;CLOSE A FILE SPECIFIED IN THE NEXTJOB REQUEST

CFILES:	$SAVE	<T1,T2,T3>		;SAVE THESE AC
	MOVE	T3,S1			;SAVE THE FLAG WORD
	SKIPE	S1,J$DIFN(J)		;IS A FILE OPENED?
	$CALL	F%REL			;YES, CLOSE IT
	JUMPT	CFILE3			;ON SUCCESS, CLOSE TEMP FILE
					
;CHECK IF THE ERROR IS "FILE STILL MAPPED". IF SO, THEN UNMAP PAGE 

	CAIE	S1,ERFSM$		;IS THE FILE STILL MAPPED?
	JRST	CFILE2			;NO, ATTEMPT TO RELEASE THE JFN
	SETO	S1,			;INDICATE UNMAP THE PAGE FROM PROCESS
	MOVE	S2,J$FILB(J)		;PICK UP PAGE NUMBER
	HRLI	S2,.FHSLF		;PICK UP FORK HANDLE
	MOVEI	T1,1			;UNMAP ONLY ONE PAGE
	PMAP%				;UNMAP THE PAGE
	 ERJMP	CFILE2			;ATTEMPT TO RELEASE JFN ON AN ERROR
	MOVE	S1,J$JFN(J)		;PICK UP THE FILE'S JFN
	CLOSF%				;CLOSE AND RELEASE THE JFN
	 ERJMP	CFILE2			;ATTEMPT TO RELEASE JFN ON AN ERROR

CFILE2:	MOVE	S1,J$JFN(J)		;PICK UP THE JFN
	RLJFN%				;RELEASE THE JFN
	 ERJMP	.+1			;IGNORE ANY ERRORS

;CLOSE AND, IF INDICATED, DELETE THE CURRENT TEMPORARY FILE

CFILE3:	SKIPN	S1,J$TEM(J)		;IS A TEMPORARY FILE OPEN?
	JRST	CFILE7			;NO, INDICATE ALL FILES CLOSED
	TXO	S1,CO%NRJ		;DO NOT RELEASE THE JFN
	CLOSF%				;CLOSE THE TEMPORARY FILE
	 ERJMP	CFILE4			;CHECK IF FILE IS NOT OPENED
	JRST	CFILE5			;YES, DELETE THE TEMPORARY FILE
CFILE4:	CAIE	S1,CLSX1		;IS THE ERROR BECAUSE FILE NOT OPENED?
	JRST	CFILE6			;NO, JUST RELEASE THE JFN
CFILE5:	SKIPL	T3			;DELETE THE TEMPORARY FILE?
	JRST	CFILE6			;NO, RELEASE THE JFN
	MOVE	S1,J$TEM(J)		;[3]PICK UP THE JFN
	TXO	S1,DF%EXP		;[3]INDICATE EXPUNGE THIS FILE
	DELF%				;DELETE AND EXPUNGE THE FILE
	 ERJMP	CFILE6			;RELEASE THE JFN
 	JRST	CFILE7			;INDICATE NO FILES OPENED
CFILE6:	MOVE	S1,J$TEM(J)		;PICK UP THE JFN
	RLJFN%				;RELEASE THE JFN
	 ERJMP	.+1			;IGNORE ANY ERRORS

;IT IS POSSIBLE THAT A JFN WAS OBTAINED, BUT BEFORE ITS VALUE COULD
;BE SAVED, THE LINK LOST ITS CONNECTION. THEREFORE, RELEASE ANY UNOPENED
;JFN

CFILE7:	SKIPN	T3			;[3]WAS THE FILE ONLY TO BE CLOSED?
	JRST	CFILE8			;[3]YES, SO DON'T RELEASE UNOPENED JFNS
	MOVX	S1,CZ%NIF!CZ%NCL	;INDICATE RELEASE ONLY UNOPENED JFNS
	CLZFF%				;RELEASE ANY UNOPENED JFNS
	 ERJMP	.+1			;IGNORE ANY ERRORS
CFILE8:	SETZM	J$DIFN(J)		;[3]INDICATE NO FILE IS OPENED
	SETZM	J$JFN(J)		;AND HERE ALSO
	SETZM	J$TEM(J)		;INDICATE NO TEMP FILE OPENED
	$RET				;RETURN TO THE CALLER
	SUBTTL	DELTEM - DELETE AND EXPUNGE ANY TEMPORY FILES

;DELTEM is called as part of resetting a Cluster LPTSPL's state to just
;prior to sending a NEXTJOB message to the remote node. The resetting of
;the state occurs after LPTSPL has detected the link is no longer
;connected while processing a NEXTJOB request.
;If the link became disconnected while Cluster LPTSPL was creating
;temporary files, then these files are deleted and expunged.
;
;Call is: J/Job Context Pointer
;Returns: The temporary files associated with the current NEXTJOB
;         message have been deleted and expunged.

DELTEM:	$SAVE	<T1,T2,T3,T4>		;SAVE THESE AC
	
	SKIPN	T3,J$TNUM(J)		;PICK UP THE NUMBER OF TEMP FILES
	JRST	DELTE6			;QUIT NOW IF THERE ARE NONE
	MOVEI	T4,J$TFIN(J)		;PICK UP ADDRESS OF THE FIRST TEMP FILE
DELTE2:	SKIPN	S1,0(T4)		;ANY MORE TEMPORARY FILES?
	JRST	DELTE5			;NO, SO QUIT

;DELETE AND EXPUNGE THE TEMPORARY FILE

	$TEXT	(<-1,,J$TNAM(J)>,<^T/DIRNAM/:^N/CNTSTA/-^N/J$RNOD(J)/^W/S1/.LPT;P770000^0>)
	MOVX	S1,GJ%SHT		;WANT A SHORT JFN 
	HRROI	S2,J$TNAM(J)		;POINT TO THE FILE
	GTJFN%				;PICK UP THE JFN
	 ERJMP	DELTE4			;TRY THE NEXT FILE
	HRRZS	S1			;ISOLATE THE JFN
	MOVEM	S1,J$TEM(J)		;SAVE IN THE EVENT OF AN ERROR
	TXO	S1,DF%EXP		;INDICATE WANT TO EXPUNGE THIS FILE
	DELF%				;DELETE AND EXPUNGE THE FILE
	 ERJMP	DELTE3			;RELEASE THE JFN
	JRST	DELTE4			;GO CHECK FOR ANY MORE FILES
DELTE3:	MOVE	S1,J$TEM(J)		;PICK UP THE JFN
	RLJFN%				;RELEASE THE JFN
	 ERJMP	.+1			;IGNORE ANY ERRORS
DELTE4:	AOS	T4			;POINT TO THE NEXT TABLE ENTRY
	SOJG	T3,DELTE2		;GO CHECK FOR ANOTHER TEMP FILE
DELTE5:	MOVE	S1,J$TNUM(J)		;PICK UP SIZE OF TEMP FILE NAMES BLOCK
	MOVEI	S2,J$TFIN(J)		;PICK UP ADDRESS OF TEMP FILE NAMES BLK
	$CALL	.ZCHNK			;RESTORE THE STATE OF THE BLOCK
	SETZM	J$TNUM(J)		;INDICATE NO TEMPORARY FILES EXIST
DELTE6:	SETZM	J$TEM(J)		;RESTORE THE STATE OF TEMP JFN HOLDER
	$RET				;RETURN TO THE CALLER
	SUBTTL	SENFAI - SEND A DECNET FAIL MESSAGE TO THE LISTENER

REPEAT 0,<

;SENFAI is called if checksumming is enabled both on the local system
;and the remote system and the checksum of the message received from
;the remote system does not agree with the checksum calculated on the
;local system. A Failure ACK is sent to the remote system indicating
;it to resend its message.
;
;Call is:       J/Job Context Pointer
;Returns true:  The Failure ACK was sent to the listener
;Returns false: The Failure ACK could not be sent to the listener

SENFAI:	$SAVE	<T1,T2>			;SAVE THESE AC
	MOVE	S1,J$LCHN(J)		;PICK UP THE DCN: DEVICE JFN
	MOVEI	S2,T1			;ADDRESS OF THE MESSAGE
	HRLI	S2,(POINT 36,)		;MAKE IT INTO A POINTER
	MOVNI	T1,2			;INDICATE A FAILURE MESSAGE
	SOUTR%				;SEND THE MESSAGE TO THE SENDER
	 ERJMP	.RETF			;INDICATE AN ERROR TO THE CALLER
	$RETT				;INDICATE SUCCESS TO THE CALLER
>;END OF REPEAT 0
	SUBTTL	SNDINT - SEND A DECNET INTERRUPT MESSAGE TO THE LISTENER

;SNDINT is called if an ABORT, CANCEL or REQUEUE message is received while
;Cluster LPTSPL is copying temporary files to the shared directory. SNDINT
;sends an interrupt message to the listener. The interrupt message indicates
;to the listener to cease processing the print request.
;If a previous response to an interrupt message has not yet been received
;from the listener, then the link is aborted.
;
;Call is:       J/Job Context Pointer
;Returns true:  An interrupt message was successfully sent
;Returns false: The interrupt message was not successfully sent
;               S1/0 The connection has been lost
;               S1/Address of fatal error text
;Crashes:       Cannot activate the data available channel

SNDINT:	$SAVE	<T1,T2>			;SAVE THESE AC
	TXO	S,WAITIR		;INDICATE WAITING FOR INTERRUPT MSG RES
	$CALL	ENAINT			;ACTIVATE THE DATA AVAILABLE CHANNEL
	JUMPF	S..CAC			;CAN'T ACTIVATE THE CHANNEL
	MOVE	S1,J$LCHN(J)		;PICK UP THE DCN: DEVICE JFN
	MOVEI	S2,.MOSIM		;INDICATE SEND AN INTERRUPT MESSAGE
	MOVEI	T1,T3			;DON'T CARE ABOUT THE CONTENTS OF MSG
	HRLI	T1,(POINT 8,)		;[3]MAKE INTO A POINTER
	MOVEI	T2,1			;MESSAGE LENGTH IS ONE BYTE
	MTOPR%				;SEND THE INTERRUPT MESSAGE
	 ERJMP	SNDIN2			;ERROR - FATAL OR LINK IS LOST
	$RETT				;INDICATE MESSAGE WAS SENT

SNDIN2:	$CALL	S%ERR			;PICK UP THE ERROR TEXT ADDRESS
	SKIPT				;SKIP IF HAVE THE ERROR TEXT
	MOVEI	S1,[ASCIZ/Can't send interrupt message/] ;NO, MAKE ONE UP
	MOVEM	S1,J$ERRA(J)		;SAVE THE ERROR TEXT ADDRESS

	$CALL	CHKLNK			;CHECK IS THE LINK IS STILL AROUND
	JUMPT	SNDIN3			;YES IT IS, THEN CONSIDER A FATAL ERROR
	SKIPN	S1			;A FATAL ERROR DETECTED BY CHKLNK?
	$RETF				;NO, INDICATE THE LINK IS NOT CONNECTED
SNDIN3:	MOVE	S1,J$ERRA(J)		;PICK UP THE FATAL ERROR TEXT ADDRESS
	$RETF				;RETURN TO THE CALLER
	SUBTTL	RCVINT - PICK UP AN INTERRUPT MESSAGE RESPONSE FROM LISTENER

;RCVINT is the interrupt handler for interrupt messages from the listener in
;response to an interrupt message previously sent by Cluster LPTSPL. RCVINT
;picks up the interrupt message and indicates that Cluster LPTSPL is no
;longer expecting an interrupt message response from the listener.
;
;Call is: J/Job Context Pointer
;Returns: The interrupt message was picked up from the listener

RCVINT:	$BGINT	1,			;SAVE THE ENVIRONMENT
	MOVE	S1,J$LCHN(J)		;PICK UP THE DCN: DEVICE JFN
	MOVEI	S2,.MORIM		;PICK UP THE FUNCTION CODE
	MOVEI	T1,T3			;WHERE TO PLACE THE MESSAGE
	HRLI	T1,(POINT 8,)		;[3]MAKE INTO A POINTER
	MTOPR%				;PICK UP THE MESSAGE
	 ERJMP	RCVIN2			;ON AN ERROR, ABORT THE LINK
	SKIPA				;DON'T ABORT THE LINK
RCVIN2:	$CALL	ABTLNK			;ABORT THE LINK, RELEASE THE DCN: JFN
	TXZ	S,WAITIR		;NO LONGER WAITING FOR INTERRUPT RES
	MOVEI	S1,ENDREQ		;INDICATE END THE PRINT REQUEST
	MOVEM	S1,LEV1PC		;SAVE THE NEW PC VALUE
	$DEBRK				;GO TO THE NEW CONTEXT
	SUBTTL	ENDFRK - INFERIOR FORK TERMINATION INTERRUPT HANDLER

;ENDFRK is invoked if Cluster LPTSPL's remote accounting inferior fork
;crashes. ENDFRK determines if the listener has crashed MAXCRH times.
;If it has, then ENDFRK considers this to be a fatal error and shuts
;down Cluster LPTSPL. If it has not, then ENDFRK restarts the listener.
;
;Call is: Invoked by the inferior fork crashing
;Returns: To previous context is no fatal error is detected, else returns
;         context to Cluster LPTSPL shutdown

ENDFRK:	$BGINT	1,			;SAVE THE PREVIOUS CONTEXT

	MOVE	S1,J$FRKH(J)		;PICK UP THE LISTENER'S HANDLE
	KFORK%				;KILL THE LISTENER
	 ERJMP	.+1			;IGNORE ANY ERRORS
	AOS	S1,J$CRNM(J)		;INCREMENT THE NUMBER OF CRASHES
	CAILE	S1,MAXCRH		;HAS LISTENER CRASHED TOO MANY TIMES?
	JRST	ENDFR2			;YES, GO SHUTDOWN THIS PRINTER		
	$CALL	STLIS0			;[3]START UP A NEW LISTENER
	JUMPT	ENDFR3			;RETURN TO THE PREVIOUS CONTEXT
	SKIPA				;ALREADY HAVE AN ERROR TEXT ADDRESS
ENDFR2:	MOVEI	S1,[ASCIZ/Cluster LPTSPL accounting listener encountered a fatal error/]
	MOVEM	S1,J$ERRA(J)		;SAVE THE ERROR TEXT ADDRESS
	MOVEI	S1,SHULPT		;PICK UP SHUTDOWN ROUTINE ADDRESS
	MOVEM	S1,LEV1PC		;CHANGE THE PC ON RETURN
ENDFR3:	$DEBRK				;LEAVE THE INTERRUPT ROUTINE
	SUBTTL	DISINT - DEACTIVATE DATA AVAILABLE CHANNEL

;DISINT is called to deactivate the data available or disconnect pending
;channel. DISINT is called when one or more files in a print request are
;not accessible to the remote system. The files are copied to a directory
;shared between the remote and local systems. After a page of a file is
;copied to the shared directory, $DSCHD is called to check if the print 
;request has been cancelled, aborted or requeued. The file transferrals
;are not done at interrupt level. If the link is lost while this transferral
;takes place, then it is desirable that the transferral not be interrupted.
;To insure this, the data available or disconnect pending channel is
;deactivated.
;
;Call is: No arguments
;Returns: The channel has been deactivated

DISINT:	$SAVE	<T1,T2>			;SAVE THESE AC
	MOVEI	S1,.FHSLF		;PICK UP THE FORK HANDLE
	MOVX	S2,1B2			;CHANNEL TO DEACTIVATE
	DIC%				;DEACTIVATE THE CHANNEL
	 ERJMP	.+1			;IGNORE ANY ERRORS
	$RET				;RETURN TO THE CALLER
					
	SUBTTL	ENAINT - ACTIVATE THE DATA AVAILABLE CHANNEL

;ENAINT is called to activate the data available and disconnect pending
;channel. ENAINT is called after all the files have been copied into
;temporary files in the shared directory or as part of error processing if
;an error was detected in copying the files into temporary files in the
;shared directory.
;
;Call is:       No arguments
;Returns true:  Channel has been activated
;Returns false: Channel could not be activated

ENAINT:	$SAVE	<T1,T2>			;SAVE THESE AC
	MOVEI	S1,.FHSLF		;PICK UP THE FORK HANDLE
	MOVX	S2,1B2			;CHANNEL TO ACTIVATE
	AIC%				;ACTIVATE THE CHANNEL
	 ERJMP	.RETF			;INDICATE ERROR IN ACTIVATING CHANNEL
	$RETT				;INDICATE CHANNEL IS ACTIVATED
	SUBTTL	CHKLNK - CHECK THE STATUS OF THE SENDER DECNET LINK

;CHKLNK is called to check the status of the Cluster LPTSPL sender's DECnet
;link to the LISSPL listener. If there is no connection (or there is no longer
;a connection), then the DECnet link is closed and the DECnet JFN released.
;CHKLNK assumes that the DECnet link was previously (or still is connected).
;
;Call is:       J/Job Context Pointer
;Returns true:  The DECnet link is connected 
;Returns false: S1/-1 The DECnet link is waiting for a connection
;               S1/0  There is no DECnet link connection
;                     The DECnet link has been aborted
;               S1/Error text address. A fatal error has occured
;                     The DECnet link has been aborted

CHKLNK:	$SAVE	<T1,T2>			;SAVE THESE AC, DESTROYED BY JSYS

;OBTAIN THE DECNET LINK STATUS.

	MOVE	S1,J$LCHN(J)		;PICK UP THE DECNET JFN
	MOVEI	S2,.MORLS		;WANT THE STATUS OF THE LINK
	MTOPR%				;OBTAIN THE STATUS OF THE LINK
	 ERJMP	CHKLN2			;CANNOT OBTAIN THE LINK STATUS
	MOVEM	T1,J$LSTS(J)		;SAVE THE LINK STATUS IN SENDER BLOCK

;DETERMINE IF THE LINK IS CONNECTED. IF IT IS NOT, THEN CLOSE AND RELEASE
;THE JFN.

	TXNE	T1,MO%CON		;IS THE LINK CONNECTED?
	$RETT				;YES, RETURN TRUE
	TXNE	T1,MO%WCC		;WAITING FOR A LINK?
	JRST	CHKLN3			;YES, GO RETURN TO THE CALLER
	$CALL	ABTLNK			;CLOSE AND RELEASE THE JFN
	SETZ	S1,			;INDICATE ERROR NOT FATAL
	JRST	CHKLN4			;GO RETURN TO THE CALLER
CHKLN2:	$CALL	S%ERR 			;PICK UP ADDRESS OF FATAL ERROR TEXT
	SKIPT				;UNABLE TO PICK UP ERROR TEXT ADR?
	MOVEI	S1,[ASCIZ/Unable to obtain link status/] ;YES
	MOVEM	S1,J$ERRA(J)		;SAVE THE ERROR TEXT ADDRESS
	$CALL	ABTLNK			;CLOSE AND RELEASE THE JFN
	MOVE	S1,J$ERRA(J)		;PICK UP THE ERROR TEXT ADDRESS
	$RETF				;INDICATE ERROR TO THE CALER
CHKLN3:	SETO	S1,			;INDICATE WAITING FOR A CONNECTION
CHKLN4:	$RETF				;INDICATE ERROR TO THE CALLER
	SUBTTL	REMREL - RELEASE A PRINT REQUEST FROM A REMOTE NODE

;REMREL is called after a print request that originated from a remote
;node has been printed. REMREL builds a release message. If accounting
;is enabled on the node where the print request originated, then
;accounting information is included in the print request. If any files
;specified in the print request were requested to be deleted, but are
;not accessible to this system, then the file names of any such files
;are included in the release message.
;After building the RELEASE message, REMREL sends it to QUASAR.
;
;Call is: J/Job Context Pointer
;Returns: The RELEASE message has been built and sent to QUASAR.
;Crashes: The RELEASE message could not be sent to QUASAR.

REMREL:	$SAVE	<P1>			;SAVE THIS AC

	$CALL	M%GPAG			;GET A PAGE FOR THE RELEASE MESSAGE
	MOVE	P1,S1			;REMEMBER THE PAGE ADDRESS
	MOVX	S1,RF.REM		;INDICATE REQUEST ORIGINATED REMOTELY
	STORE	S1,REL.FL(P1),RF.DEC	;SAVE IN THE RELEASE MESSAGE
	MOVE	S1,.EQITN(J)		;PICK UP THE PRINT REQUEST'S ITN
	MOVEM	S1,REL.IT(P1)		;PLACE IN THE RELEASE MESSAGE

;CHECK IF ACCOUNTING IS ENABLED ON THE NODE THE PRINT REQUEST ORIGINATED
;FROM. ALSO CHECK IF THE PRINT REQUEST CONTAINS AN INVALID ACCOUNT STRING.

	MOVE	S1,.EQSEQ(J)		;PICK UP THE JOB REQUEST INFO WORD
	TXNE	S1,EQ.IAS		;INVALID ACCOUNT STRING?
	JRST	REMRE1			;YES, DON'T INCLUDE ACCOUNTING INFO
	TXNN	S1,EQ.RAI		;ACCOUNTING ON THE REQUESTING NODE?
	JRST	REMRE1			;NO, DON'T INCLUDE ACCOUNTING INFO	
	MOVX	S1,RF.ACT		;RELEASE MSG CONTAINS ACCOUNTING INFO
	IORM	S1,REL.FL(P1)		;INDICATE IN THE MESSAGE

	MOVX	S1,.FHSLF		;PICK UP THE FORK HANDLE
	RUNTM%				;CALCULATE THE RUN TIME
	 ERJMP	[SETZ S1,		; THIS SHOULD NEVER HAPPEN
		 JRST .+1 ]		; CONTINUE PROCESSING
	ADDM	S1,J$ARTM(J)		;PLACE IN THE MESSAGE
	$CALL	ADDACT			;ADD THE ACCOUNTING INFORMATION TO MSG

;DELETE ANY FILES SPECIFIED TO BE DELETED IN THE PRINT REQUEST. ANY FILE
;THAT IS SPECIFIED TO BE DELETED, BUT IS NOT ACCESSIBLE TO THIS SYSTEM,
;ADD THE FILE'S NAME TO THE RELEASE MESSAGE.

REMRE1:	MOVE	S1,.EQNOD(J)		;[3]PICK UP NODE PRINT REQUEST WAS FROM
	MOVEM	S1,REL.NN(P1)		;[3]LET QUASAR KNOW WHERE TO SEND TO
	$CALL	REMDIS			;TAKE CARE OF FILES TO BE DELETED
	JUMPF	REMRE2			;NO DELETED FILE NAMES IN THIS MSG
	MOVX	S2,RF.DEL		;INDICATE FILES ARE INCLUDED IN MSG
	IORM	S2,REL.FL(P1)		;INDICATE IN THE RELEASE MESSAGE

;FINISH BUILDING THE RELEASE MESSAGE AND SEND IT OFF TO QUASAR

REMRE2:	MOVSI	S2,PAGSIZ		;[3]PICK UP MESSAGE SIZE
	HRRI	S2,.QOREL		;INCLUDE RELEASE MESSAGE FUNCTION CODE
	MOVEM	S2,.MSTYP(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	T1,P1			;PICK UP THE MESSAGE ADDRESS
	$CALL	SNDQSR			;SEND THE MESSAGE TO QUASAR
	$RET				;RETURN TO THE CALLER
	SUBTTL	ADDACT - ADD ACCOUNTING INFORMATION TO A RELEASE MESSAGE

;ADDACT is called during the building of a RELEASE message for a print
;request that originated from a remote node in the cluster that has
;accounting enabled. ADDACT adds to the release message the accounting
;information that will be used by the remote system when it performs
;the USAGE% JSYS.
;
;Call is: J/Job Context Pointer
;         P1/RELEASE message address
;Returns: The accounting information has been added to the release message

ADDACT:	MOVE	S1,J$ARTM(J)		;PICK UP THE RUN TIME
	MOVEM	S1,REL.RT(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$ADRD(J)		;PICK UP THE DISK READS
	MOVEM	S1,REL.DR(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,.EQJOB(J)		;PICK UP THE SIXBIT JOB NAME
	MOVEM	S1,REL.JN(P1)		;PLACE IN THE RELEASE MESSAGE	
	MOVE	S1,J$LDEV(J)		;PICK UP THE DEVICE NAME
	MOVEM	S1,REL.DN(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$ASEQ(J)		;PICK UP THE JOB SEQUENCE NUMBER
	MOVEM	S1,REL.SN(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$APRT(J)		;PICK UP THE TOTAL PAGES PRINTED
	MOVEM	S1,REL.PP(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$AFXC(J)		;PICK UP THE TOTAL FILES PROCESSED
	MOVEM	S1,REL.FP(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,.EQAFT(J)		;PICK UP CREATION DATE/TIME OF REQUEST
	MOVEM	S1,REL.CD(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$RTIM(J)		;PICK UP SCHEDULED DATE/TIME
	MOVEM	S1,REL.SD(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$FORM(J)		;PICK UP THE FORMS TYPE
	MOVEM	S1,REL.FT(P1)		;PLACE IN THE RELEASE MESSAGE
	MOVE	S1,J$APRI(J)		;PICK UP THE JOB'S PRIORITY
	MOVEM	S1,REL.FP(P1)		;PLACE IN THE RELEASE MESSAGE

;PLACE THE USER NAME IN THE RELEASE MESSAGE

	MOVEI	S1,REL.UN(P1)		;WHERE TO PLACE USER NAME IN MESSAGE
	MOVE	S2,S1			;REMEMBER STARTING DESTINATION ADDRESS
	HRLI	S1,.EQOWN(J)		;PICK UP USER NAME ADDRESS
	ADDI	S2,EQNMSZ-1		;CALCULATE THE END DESTINATION ADDRESS
	BLT	S1,0(S2)		;COPY THE USER NAME INTO RELEASE MSG

;PLACE THE ACCOUNT STRING IN THE RELEASE MESSAGE

	MOVEI	S1,REL.AS(P1)		;WHERE TO PLACE ACCOUNT STRING IN MSG
	MOVE	S2,S1			;REMEMBER STARTING DESTINATION ADDRESS
	HRLI	S1,.EQACT(J)		;PICK UP ACCOUNT STRING ADDRESS
	ADDI	S2,EQASSZ-1		;[3]CALCULATE THE END DESTINATION ADR
	BLT	S1,0(S2)		;COPY ACCOUNT STRING INTO RELEASE MSG

	$RET				;RETURN TO THE CALLER
	SUBTTL	REMDIS - DELETE FILES AND PLACE FILE NAMES IN RELEASE MESSAGE

;REMDIS is called during the creation of the RELEASE message for a print
;request that orginated on a remote node in the cluster. REMDIS deletes
;any files that were indicated in the print request to be deleted. If a
;file specified to be deleted is not accessible to the system, then its
;name is placed in the release message.
;Any temporary files associated with the print request are also deleted.
;
;Call is:       J/Job Context Pointer
;               P1/RELEASE message address
;Returns true:  One or more files need to be deleted on the requesting node
;Returns false: No files need to be deleted on the requesting node

REMDIS:	$SAVE	<T1,T2,T3,T4>		;SAVE THESE AC

;SET UP THE SEARCH FOR THE FILES TO BE DELETED AND FILE NAMES TO BE PLACED
;IN THE RELEASE MESSAGE.

	MOVEI	T3,REL.RS(P1)		;[3]POINT TO THE END OF THE RELEASE MSG
	LOAD	E,.EQLEN(J),EQ.LOH	;PICK UP THE LENGTH OF THE EQ
	ADD	E,J			;POINT TO THE FIRST FP
	LOAD	T1,.EQSPC(J),EQ.NUM	;PICK UP # OF FILES IN PRINT REQUEST
	SETZ	T4,			;LENGTH OF FD BLOCKS IN RELEASE MESSAGE

;CHECK IF THERE IS A TEMPORARY FILE ASSOCIATED WITH THE FILE. IF THERE IS,
;THEN DELETE IT.

REMDI1:	MOVE	T2,.FPINF(E)		;PICK UP THIS FILE'S INFORMATION WORD
	TXNN	T2,FP.CPY		;IS THERE A TEMP FILE WITH THIS FILE?
	JRST	REMDI2			;NO, CHECK IF FILE SHOULD BE DELETED
	$CALL	SETFD			;PLACE THE TEMP FILE'S FD IN THE FOB
	$CALL	DELTFE			;DELETE THE TEMP FILE

;CHECK IF THE USER SPECIFIED THIS FILE TO BE DELETED. IF SO, THEN PLACE THE
;FILE'S NAME IN THE RELEASE MESSAGE

	LOAD	S1,.FPLEN(E),FP.LEN	;PICK UP THE FP LENGTH
	ADD	E,S1			;POINT TO THE FD
	$CALL	DETDEL			;DETERMINE IF THE FILE IS TO BE DELETED
	JUMPF	REMDI3			;NO, GO CHECK THE NEXT FILE
	MOVE	S1,T3			;PICK UP WHERE TO PLACE FD IN MESSAGE
	HRLI	S1,.FDLEN(E)		;PICK UP WHERE FD IS IN DATA BASE
	LOAD	S2,.FDLEN(E),FD.LEN	;[3]PICK UP THE LENGTH OF THE FD
	ADD	T4,S2			;ADD TO TOTAL FD BLOCK SIZE IN MESSAGE
	ADD	S2,T3			;[3]DESTINATION END ADDRESS + 1
	MOVE	T3,S2			;[3]ADDRESS OF THE NEXT BLOCK
	BLT	S1,-1(S2)		;COPY THIS FILE'S FD TO RELEASE MESSAGE
	AOS	REL.ND(P1)		;INCREMENT FILE COUNT IN RELEASE MSG
	JRST	REMDI3			;GO CHECK THE NEXT FILE

;THERE IS NOT A TEMPORARY FILE ASSOCIATED WITH THIS FILE. CHECK IF THE FILE
;IS TO BE DELETED. IF IT IS, THEN DELETE IT.

REMDI2:	LOAD	S1,.FPLEN(E),FP.LEN	;[3]PICK UP THE FP LENGTH
	ADD	E,S1			;[3]POINT TO THE FD
	$CALL	DETDEL			;DETERMINE IF THE FILE IS TO BE DELETED
	JUMPF	REMDI3			;NO, GO CHECK THE NEXT FILE
	MOVEM	E,J$XFOB+FOB.FD(J)	;YES, PLACE FILE'S FD IN THE FOB
	$CALL	DELTFE			;DELETE THE FILE

;POINT TO THE NEXT FILE TO BE LOOKED AT FOR DELETION

REMDI3:	LOAD	S1,.FDLEN(E),FD.LEN	;PICK UP THE FILE'S FD LENGTH
	ADD	E,S1			;POINT TO THE NEXT FILE'S FP
	SOJG	T1,REMDI1		;CHECK THE NEXT FILE, IF ANY

	SKIPN	S1,T4			;ANY FILE NAMES IN THE RELEASE MSG?
	$RETF				;NO, INDICATE TO THE CALLER
	$RETT				;YES, INDICATE TO THE CALLER
	SUBTTL DELTFE - DELETE A FILE

;DELTFE is called during the creation of a RELEASE message for a print
;request that originated on a remote node in the cluster. DELTFE deletes
;a file that was specified in the print request to be deleted.
;
;Call is: J/Job Context Pointer
;Returns: The file has been deleted

DELTFE:	SETZM	J$XFOB+FOB.US(J)	;NO ACCESS CHECKING
	SETZM	J$XFOB+FOB.CD(J)	;NO ACCESS CHECKING
	MOVEI	S1,FOB.SZ		;PICK UP THE FOB SIZE
	MOVEI	S2,J$XFOB(J)		;PICK UP THE FOB ADDRESS
	$CALL	F%DEL			;DELETE THE FILE
	$RET				;RETURN TO THE CALLER
	SUBTTL	SETFD - SETUP A TEMPORARY FILE'S FD IN THE FOB

;SETFD is called to create a FD for a temporary file associated with
;a print request that originated from a remote node in the cluster.
;The address of the FD is placed in the FOB
;
;Call is: J/Job Context Pointer
;         E/Address of the file's FP
;Returns: The temporary file's FD has been created and is pointed to 
;         by the temporary file's FOB

SETFD:	$SAVE	<P1,P2>			;SAVE THIS AC

;BUILD THE TEMPORARY FILE'S NAME

	$TEXT(<-1,,J$TNAM(J)>,<^T/DIRNAM/:^N/.EQNOD(J)/-^N/CNTSTA/^W/.FPTEM(E)/.LPT;P770000^0>)

;FIND THE LENGTH OF THE TEMPORARY FILE NAME

	MOVEI	S1,J$TNAM(J)		;ADDRESS OF THE TEMPORARY FILE NAME
	HRLI	S1,(POINT 7,)		;MAKE IT INTO A POINTER
	SETZ	P1,			;LENGTH OF THE TEMPORARY FILE NAME

SETFD1:	ILDB	S2,S1			;PICK UP THE NEXT CHARACTER OF NAME
	AOS	P1			;COUNT IT
	SKIPE	S2			;FINISHED COUNTING CHARACTERS?
	JRST	SETFD1			;NO, GO GET THE NEXT CHARACTER

;BUILD THE TEMPORARY FILE'S FD HEADER

	IDIVI	P1,5			;CALCULATE THE NUMBER OF WORDS
	SKIPE	P2			;SKIP IF NO FRACTIONAL WORDS
	AOS	P1			;INCLUDE ANY FRACTIONAL WORDS
	AOS	P1			;INCLUDE HEADER WORD IN FD LENGTH
	STORE	P1,J$FDHR(J),FD.LEN	;STORE FD LENGTH IN FD HEADER WORD
	LOAD	S1,.FPLEN(E),FP.LEN	;PICK UP ORIGINAL FILE'S FP LENGTH
	ADD	S1,E			;POINT TO ORIGINAL FILE'S FD
	MOVEM	S1,J$ORFD(J)		;SAVE ORIGINAL FILE'S FD ADDRESS
	LOAD	S2,.FDLEN(S1),FD.TYP	;PICK UP TYPE FIELD FROM FD HEADER
	STORE	S2,J$FDHR(J),FD.TYP	;PLACE IN TEMPORARY FILE'S FD

;SAVE THE TEMPORARY FILE'S FD IN THE FOB AND THE JOB DATA BASE

	MOVEI	S1,J$FDHR(J)		;PICK UP TEMP FILE'S FD ADDRESS
	MOVEM	S1,J$DFDA(J)		;PLACE IN EXPECTED FD ADDRESS WORD
	STORE	S1,J$XFOB+FOB.FD(J)	;PLACE IN THE FOB
	$RET				;RETURN TO THE CALLER
	SUBTTL	LISTEN - MESSAGE SERVER FOR A REMOTE NODE

;LISTEN exists as an inferior fork in LPTSPL. LPTSPL receives RELEASE
;messages from nodes in the cluster where print requests originating
;on the local node were sent to be processed. LISTEN performs accounting
;for those print requests.

;INITIALIZATION BLOCK AND PID BLOCK

LIB:	$BUILD	IB.SZ
	  $SET	(IB.PRG,,%%.MOD)	;PROGRAM 'LPTSPL'
	  $SET  (IB.FLG,IP.STP,1)	;STOPCODES TO ORION
	  $SET	(IB.PIB,,0)		;[3]SET UP PIB ADDRESS
	$EOB				;

LPIB:	$BUILD	PB.MNS			;
	  $SET	(PB.HDR,PB.LEN,PB.MNS)	;PIB LENGTH,,0
	  $SET	(PB.FLG,IP.RSE,1)	;RETURN ON SEND ERROR
	  $SET	(PB.SYS,IP.BQT,-1)	;MAXIMUM SEND/RECEIVE IPCF QUOTA
	  $SET	(PB.SYS,IP.MNP,^D1)	;NUMBER OF PIDS
	$EOB				;

LISCHN:	XWD	1,ACCEPT		;A DECNET CONNECTION REQUEST OCCURRED
	XWD	1,MSGFSN		;MESSAGE FROM A SENDER IS AVAILABLE
	XWD	1,LSSCS			;SCS% DETECTED A CLUSTER TOPOLOGY CHANGE
	BLOCK	^D33			;THESE CHANNELS ARE NOT USED

SCSCHN:	EXP	.SIPAN,2		;ASSOCIATE SCS EVENTS WITH CHAN 2

;SET UP DATA BASE, SET UP GLXLIB, ENABLE CAPABILITIES, AND SET UP THE INTERRUPT
;SYSTEM

LISTEN:	SKIPE	DEBUGW			;[3]DEBUGGING?
	$CALL	LPTDDT			;[3]YES, SET UP FOR DEBUGGING
	$CALL	LISSET			;SET UP GLXLIB AND CAPABILITIES
	$CALL	BLDSRV			;[3]BUILD THE DECNET SRV: DEVICE NAME
	$CALL	LOPLNK			;OPEN A SRV: DEVICE
	$CALL	LISINT			;SET UP THE INTERRUPT SYSTEM

;WAIT FOR A CONNECTION REQUEST, FOR INCOMING DECNET MESSAGES AND FOR
;REQUESTS FROM THE TOP FORK FOR A MESSAGE.

LISTE2:	SETZ	S1,			;INDEFINITE TIME TO WAIT
	$CALL	I%SLP			;WAIT% UNTIL NEEDED
	JRST	LISTE2			;WAIT% FOR THE NEXT EVENT

LISTE3:	MOVE	P,.LSACS+P(LIS)		;[6]PICK UP THE NEW STACK POINTER
	$CALL	LOPLNK			;[6]RE-OPEN THE LINK
	$CALL	LISINT			;[6]RE-INITIALIZE INTERRUPT SYSTEM
	JRST	LISTE2			;[6]WAIT% FOR THE NEXT EVENT
	SUBTTL	BLDSRV - BUILD THE SRV: DEVICE NAME

;BLDSRV builds the listener's DECnet SRV: device name and places it in the
;listener block. It also builds the name of LISSPL's sender that will attempt
;to establish a DECnet connection with the listener. The sender name is
;used by the listener as part of validating the link request.
;
;Call is: LIS/Address of the listener block
;Returns: The SRV: device name and the sender name have been built and
;         placed in the listener block

BLDSRV:	SKIPE	DEBUGW				;[7]DEBUGGING?
	JRST	BLDS.1				;[7]YES, SET UP DIFFERENTLY
	$TEXT	(<-1,,.LSSRV(LIS)>,<SRV:TASK.^N/CNTSTA/$LPTSPL$LS>)
	$TEXT	(<-1,,.LSSNE(LIS)>,<^N/CNTSTA/$LISSPL$SN^0>) ;[3]SENDER NAME
	$RET					;RETURN TO THE CALLER

BLDS.1:	$SAVE	<T1,T2>				;[7]SAVE THESE AC
	GJINF%					;[7]PICK UP THE USER'S NUMBER
	MOVE	S2,S1				;[7]SAVE NUMBER WHERE EXPECTED
	MOVEI	S1,.LSDBW(LIS)			;[7]WHERE TO PLACE USER NAME
	HRLI	S1,(POINT 7)			;[7]MAKE INTO A POINTER
	DIRST%					;[7]PICK UP THE USER NAME
	 JRST	S..COD				;[7]CRASH ON AN ERROR
	MOVEI	S1,.LSDBW(LIS)			;[7]PICK UP USER NAME ADDRESS
	HRLI	S1,(POINT 7,)			;[7]MAKE INTO A POINTER
	SETZ	T1,				;[7]NUMBER OF CHAR IN NAME
BLDS.2:	ILDB	S2,S1				;[7]PICK UP THE NEXT CHARACTER
	SKIPN	S2				;[7]IS THIS THE LAST ONE?
	JRST	BLDS.3				;[7]YES, BUILD THE DEVICE NAME
	AOS	T1				;[7]INCREMENT THE CHAR COUNT
	CAIG	T1,^D6				;[7]MAXIMUM COUNT?
	JRST	BLDS.2				;[7]NO, GET THE NEXT CHAR
	SETZ	S2,				;[7]PICK UP A NULL
	DPB	S2,S1				;[7]PLACE IN USER NAME

BLDS.3:	MOVEI	S1,.LSDBW(LIS)			;[7]ADDRESS OF THE USER NAME
	$TEXT	(<-1,,.LSSRV(LIS)>,<SRV:TASK.^N/CNTSTA/$^T/0(S1)/$LS^0>)
	$TEXT	(<-1,,.LSSNE(LIS)>,<^N/CNTSTA/$^T/0(S1)/$SN^0>) ;SENDER NAME
	$RET					;[7]RETURN TO THE CALLER
	SUBTTL	LISSET - INITIALIZE THE LISTENER'S GLXLIB AND CAPABILITIES

;LISSET is called by the listener at listener startup. This routine sets up
;GLXLIB, the listener's capabilities and disables the listener from receiving
;any IPCF messages.
;
;Call is: LIS/Address of the listener block
;Returns: GLXLIB setup and capabilities enabled
;Crashes: Unable to set up capabilities

LISSET:	$SAVE	<T1,T2>			;SAVE THESE AC, DESTROYED BY JSYS

;SET UP THE GLXLIB INITIALIZATION BLOCK IN THE LISTENER BLOCK

	MOVSI	S1,LIB			;PICK UP ADDRESS OF THE IB BLOCK
	HRRI	S1,.LSIBK(LIS)		;ADDRESS OF WHERE TO PLACE THE IB BLOCK
	MOVEI	S2,.LSIBK+IB.SZ(LIS)	;END ADDRESS + 1
	BLT	S1,-1(S2)		;MOVE THE IB BLOCK TO LISTENER BLOCK
	MOVEI	S1,.LSPIB(LIS)		;[3]PICK UP PID BLOCK ADDRESS
	MOVEM	S1,.LSIBK+IB.PIB(LIS)	;[3]PLACE IN THE IB BLOCK

	MOVSI	S1,.LSLEV(LIS)		;ADDRESS OF THE INTERRUPT LEVEL TABLE
	HRRI	S1,LISCHN		;ADDRESS OF THE CHANNEL TABLE
	MOVEM	S1,.LSIBK+IB.INT(LIS)	;PLACE IN THE INITIALIZATION BLOCK

;SET UP THE PID BLOCK AND THE INTERRUPT LEVEL TABLE IN THE LISTENER BLOCK

	MOVSI	S1,LPIB			;PICK UP ADDRESS OF THE PID BLOCK
	HRRI	S1,.LSPIB(LIS)		;DESTINATION IS IN THE LISTENER BLOCK
	MOVEI	S2,.LSPIB+PB.MNS(LIS)	;END ADDRESS + 1
	BLT	S1,-1(S2)		;MOVE PID TABLE TO LISTENER BLOCK

	MOVEI	S1,.LSLEV(LIS)		;PICK UP ADR OF INTERRUPT LEVEL TABLE
	MOVEI	S2,.LS1PC(LIS)		;PICK UP ADR OF FIRST PC WORD
	MOVEM	S2,0(S1)		;PLACE PC ADR IN INTERRUPT LEVEL TABLE
	AOS	S1			;[3]POINT TO NEXT INTERRUPT TABLE ENTRY
	AOS	S2			;[3]POINT TO NEXT PC WORD ADDRESS
	MOVEM	S2,0(S1)		;PLACE PC ADR IN INTERRUPT LEVEL TABLE
	AOS	S1			;[3]POINT TO NEXT INTERRUPT TABLE ENTRY
	AOS	S2			;[3]POINT TO NEXT PC WORD ADDRESS
	MOVEM	S2,0(S1)		;PLACE PC ADR IN INTERRUPT LEVEL TABLE

;SET UP GLXLIB 

	MOVEI	S1,IB.SZ		;PICK UP SIZE OF THE INITIALIZATION BLK
	MOVEI	S2,.LSIBK(LIS)		;[3]PICK UP INITIALIZATION BLOCK ADR
	$CALL	I%INIT			;INITIALIZE GLXLIB


;ENABLE THE LISTENER'S CAPABILITIES TO BE THOSE OF THE TOP FORK.

	MOVX	S1,.FHSLF		;PICK UP THE LISTENER'S HANDLE
	RPCAP%	
	 ERJMP	[$CALL INLCRH		  ;INDICATE A CONTROLLED CRASH
		 $STOP(LCC,Listener can't obtain capabilities) ]
	MOVE	T1,S2			;ENABLE ALL CAPABILITIES
	MOVEI	S1,.FHSLF		;PICK UP THE LISTENER'S HANDLE
	EPCAP%				;ENABLE THE CAPABILITIES
	 ERJMP	[$CALL INLCRH		  ;INDICATE A CONTROLLED CRASH
		 $STOP(LCE,Listener can't enable capabilities) ]

;DISABLE RECEIVING IPCF MESSAGES

	MOVEI	S1,.MUDIS		;DISABLE RECEIVING IPCF MESSAGES
	MOVEM	S1,.LSMUT(LIS)		;PLACE IN THE ARGUMENT BLOCK
	MOVE	S1,.LSPIB+PB.PID(LIS)	;PICK UP LISTENER'S PID
	MOVEM	S1,.LSMUT+1(LIS)	;PLACE IN THE ARGUMENT BLOCK
	MOVEI	S1,2			;PICK UP SIZE OF ARGUMENT BLOCK
	MOVEI	S2,.LSMUT(LIS)		;PICK ADDRESS OF THE ARGUMENT BLOCK
	MUTIL%				;DISABLE RECEIVING IPCF MESSAGES
	 ERJMP	.+1			;SHOULDN'T HAPPEN, BUT DON'T CARE
	$RET				;RETURN TO STARTUP
	SUBTTL	LOPLNK - OPEN A DECNET SRV: DEVICE

;LOPLNK is called during the listener's initialization to open a SRV:
;device.
;
;Call is: LIS/Address of the listener block
;Returns: The SRV: device has been open
;Crashes: Unable to obtain a JFN or open the SRV: device

LOPLNK:	$SAVE	<T1,T2>			;SAVE THESE AC

;PICK UP THE SRV: JFN AND OPEN THE SRV: DEVICE

	MOVX S1,GJ%SHT			;SHORT JFN
	HRROI	S2,.LSSRV(LIS)		;POINT TO THE DEVICE NAME
	GTJFN%
	 ERJMP	LOPLN3			;CRASH IF CAN'T GET JFN
	HRRZS	S1			;ISOLATE THE JFN
	MOVEM S1,.LSJFN(LIS)		;SAVE THE JFN FOR LATER
	MOVX S2,<FLD(^D36,OF%BSZ)+OF%WR+OF%RD> ;OPEN FOR READ AND WRITE
	OPENF%
	 ERJMP	LOPLN3			;CRASH IF CAN'T OPEN THE DEVICE
	$RET				;RETURN TO THE CALLER

LOPLN3:	$CALL	INLCRH			;INDICATE A CONTROLLED CRASH
	$STOP	(LOD, LISTENER CAN'T OPEN DECNET DEVICE)
	SUBTTL	LISINT - SET UP THE LISTENER'S INTERRUPT SYSTEM

;LISINT is called by the listener during listener startup. LISINT sets up
;the listener's interrupt system.
;
;Call is: LIS/Address of the listener block
;Returns: The interrupt system has been set up
;Crashes: The interrupt system could not be set up


LISINT:	$SAVE	<T1,T2>			;SAVE THESE AC
	MOVEI	S1,.FHSLF		;PICK UP THE LISTENER'S HANDLE
	SETO	S2,			;INDICATE DISABLE ALL 36 CHANNELS
	DIC%				;DISABLE THE CHANNELS
	 ERJMP	.+1			;SHOULDN'T HAPPEN, BUT IGNORE
	CIS%				;CLEAR THE INTERRUPT SYSTEM
	 ERJMP	.+1			;SHOULDN'T HAPPEN, BUT IGNORE
	MOVEI	S1,.FHSLF		;PICK UP THE LISTENER'S HANDLE
	HRLI	S2,.LSLEV(LIS)		;PICK UP INTERRUPT LEVEL TABLE ADDRESS
	HRRI	S2,LISCHN		;PICK UP CHANNEL TABLE ADDRESS
	SIR%				;SET UP THE INTERRUPT TABLE ADDRESSES
	 ERJMP	LISIN2			;CRASH IF CAN'T SET UP 
	MOVEI	S1,.FHSLF		;PICK UP THE LISTENER'S HANDLE
	EIR%				;ENABLE THE INTERRUPT SYSTEM
	 ERJMP	LISIN2			;CRASH IF CAN'T ENABLE INTERRUPT SYSTEM
	MOVEI	S1,.FHSLF		;PICK UP THE LISTENER'S HANDLE
	MOVX	S2,1B0+1B1+1B2		;PICK UP CHANNELS TO ACTIVATE
	AIC%				;ACTIVATE THE CHANNELS
	 ERJMP	LISIN2			;CRASH IF CAN'T ACTIVATE THE CHANNELS

	MOVE	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JFN
	MOVEI	S2,.MOACN		;PICK UP THE FUNCTION CODE
	MOVX	T1,<FLD(0,MO%CDN)+FLD(1,MO%DAV)+FLD(.MONCI,MO%INA)>
	MTOPR%				;ACTIVATE THE DECNET CHANNELS
	 ERJMP	LISIN2			;CRASH ON AN ERROR

	MOVEI	S1,2			;PICK UP INTERRUPT ENABLED BLOCK SIZE
	MOVEM	S1,.LSSBK(LIS)		;PLACE IN THE INTERRUPT ENABLED BLOCK
	MOVE	S1,SCSCHN		;ASSOCIATE SCS% EVENTS WITH CHANNEL 2
	MOVEM	S1,.LSSBK+1(LIS)	;PLACE IN THE INTERRUPT ENABLED BLOCK
	MOVEI	S1,.SSAIC		;PICK UP THE FUNCTION CODE
	MOVEI	S2,.LSSBK(LIS)		;PICK UP INTERRUPT ENABLED BLOCK ADR
	SCS%				;ACTIVATE THE SCS% EVENT CHANNEL
	 ERJMP	LISIN2			;CRASH ON AN ERROR
	$RET				;RETURN TO LISTENER STARTUP

LISIN2:	$CALL	INLCRH			;INDICATE CONTROLLED CRASH
	JRST	$STOP(CSI,Can't set up interrupt system)
	SUBTTL	ACCEPT - VALIDATE A DECNET CONNECTION REQUEST

;ACCEPT is the listener's interrupt handler for DECnet connection requests.
;ACCEPT validates a sender's request for a DECnet connection. The following
;two checks are made:
;1. The sender's name must be in the form expected by the listener. The
;   expected form is:
;   LNODE$LISSPL$SN
;   where LNODE is the local node's name
;3. The optional data (BDATA) field must contain the value that results from
;   the following algorithm:
;   a. The listener's node name expressed in SIXBIT is rotated left by 3 bits
;   b. This value is then converted into 4 octal 8 bit bytes
;If the sender fails to pass these two checks, then the sender's DECnet
;connection request is rejected with reason "Reject or disconnect by
;object" (error .DCX0). ORION is informed of the rejection.
;If the sender passes the two checks, then its connection request is 
;accepted.
;
;Call is: LIS/Address of the listener block
;Returns: The connecton request has been accepted or rejected
;Crashes: Cannot obtain the information to validate the connection request
;         or cannot interrupt the top fork

ACCEPT:	$BGINT	1,
	

;CHECK IF THE SENDER'S NAME IS VALID

	MOVE	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JFN
	MOVEI	S2,.MORUS		;WANT THE SENDER'S USER NAME
	HRROI	T1,.LSUSR(LIS)		;WHERE TO PLACE THE USER NAME
	MTOPR%				;PICK UP THE USER NAME
	 ERJMP	ACCEP5			;CRASH IF CAN'T OBTAIN INFORMATION
	
	HRROI	S1,.LSSNE(LIS)		;POINT TO THE EXPECTED SENDER'S NAME
	HRROI	S2,.LSUSR(LIS)		;POINT TO THE SENDER'S NAME
	$CALL	S%SCMP			;COMPARE THE TWO NAMES
	SKIPE	S1			;ARE THE NAMES THE SAME?
	JRST	ACCEP3			;NO, SO REJECT THIS REQUEST

;CHECK THE OCTAL DATA FIELD

repeat 0,<
	MOVE	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JFN
	MOVEI	S2,.MORDA		;WANT THE OCTAL DATA FIELD
	HRROI	T1,.LSOPT(LIS)		;WHERE TO PLACE THE OCTAL DATA
	MTOPR%				;PCIK UP THE OCTAL DATA
	 ERJMP	ACCEP5			;CRASH IF CAN'T OBTAIN INFORMATION

	MOVE	S2,CNTSTA		;PICK UP THE LOCAL SIXBIT NODE NAME
	ROT	S2,3			;ROTATE BY 3
	MOVE	T1,[POINT 8,T3]		;WHERE TO PLACE OCTAL VALUE
	SETZ	T3,			;INITIALIZE OCTAL VALUE TO ZERO
	MOVEI	T2,4			;PICK UP NUMBER OF BYTES TO BUILD

ACCEP2:	LSHC	S1,^D9			;PICK UP THE NEXT BYTE
	IDPB	S1,T1			;STORE AS AN EIGHT BIT BYTE
	SOJN	T2,ACCEP2		;PICK UP THE NEXT BYTE

	CAME	T3,.LSOPT(LIS)		;SAME OCTAL VALUE AS THE SENDER'S?
	JRST	ACCEP3			;NO, SO REJECT THIS REQUEST
>;end of temp repeat 0

;THE SENDER HAS PASSED THE VALIDITY CHECKS. SAVE THE SENDER'S NODE NAME AND
;ACCEPT THE DECNET CONNECTION REQUEST.

	MOVE	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JFN
	MOVEI	S2,.MORHN		;WANT THE SENDER'S NODE NAME
	HRROI	T1,.LSANN(LIS)		;WHERE TO PLACE THE NODE NAME
	MTOPR%				;PICK UP THE SENDER'S NODE NAME
	 ERJMP	ACCEP5			;CRASH IF CAN'T OBTAIN INFORMATION
	
	HRROI	S1,.LSANN(LIS)		;PICK UP THE SENDER'S NODE NAME
	$CALL	S%SIXB			;CHANGE IT TO SIXBIT
	MOVEM	.LSNME(LIS)		;SAVE THE SIXBIT NODE NAME

	MOVE	S1,.LSJFN(LIS)		;PICK UP SRV: DEVICE JFN
	MOVEI	S2,.MOCC		;THE CONNECTION WILL BE ACCEPTED
	SETZB	T1,T2			;NO OPTIONAL DATA
	MTOPR%				;ACCEPT THE CONNECTION
	 ERJMP	ACCEP5			;CRASH ON AN ERROR
	JRST	ACCEP4			;[3]RETURN TO THE PREVIOUS CONTEXT


;THE SENDER'S DECNET CONNECTION REQUEST HAS BEEN DENIED. REJECT THE 
;CONNECTION, INDICATE THAT THE CONNECTION HAS BEEN REJECTED IN THE LISTENER'S
;STATUS WORD IN THE NODE TABLE ENTRY AND INFORM ORION OF THE REJECTION.

ACCEP3:	MOVE	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JFN
	MOVEI	S2,.MOCLZ		;WILL REJECT THIS REQUEST
	SETZB	T1,T2			;NO OPTIONAL DATA
	MTOPR%				;REJECT THE REQUEST
	 ERJMP	ACCEP5			;CRASH ON AN ERROR

	$LOG	(<DECnet connection rejected>,<LPTSPL's listener has rejected a DECnet connection from node ^N/.LSNME(LIS)/>)

ACCEP4:	$DEBRK				;RETURN TO THE PREVIOUS CONTEXT

;A FATAL ERROR HAS BEEN ENCOUNTERED. INDICATE A CONTROLLED CRASH AND CRASH

ACCEP5:	$CALL	INLCRH			;INDICATE A CONTROLLED CRASH
	$STOP	(CVC, SENDER CAN'T VALIDATE A CONNECTION REQUEST)
	SUBTTL	MSGFSN - DECNET MESSAGE FROM SENDER IS AVAILABLE

;MSGFSN is the interrupt handler for processing DECnet messages from LISSPL.
;
;Call is: LIS/Address of the listener block
;Returns: The message has been processed
;Crashes: The link status cannot be obtained, the link is no longer connected,
;         or the message cannot be picked up.

MSGFSN:	$BGINT	1,

;CHECK IF THE INTERRUPT IS DUE TO A MESSAGE BEING AVAILABLE FROM THE SENDER.
;IF IT IS, THEN PICK IT UP AND PROCESS IT. IF THERE IS NO MESSAGE AVAILABLE,
;THEN CHECK THE LINK STATUS. IF THE LINK IS STILL CONNECTED, THEN IT IS A
;SPURIOUS INTERRUPT. IF THE LINK IS NO LONGER CONNECTED AND THERE IS NOT A
;FATAL ERROR, THEN ATTEMPT TO RE-OPEN THE LINK.

	SKIPG	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JFN
	JRST	MSGFS6			;THERE IS NONE, TREAT AS SPURIOUS
	SIBE%				;CHECK FOR A MESSAGE
	JRST	MSGFS1			;THERE IS ONE, PICK IT UP
	$CALL	LCKLNK			;NO MESSAGE, CHECK THE LINK STATUS
	JUMPT	MSGFS6			;LINK CONNECTED, TREAT AS SPURIOUS
	JRST	MSGFS5			;ATTEMPT TO RE-OPEN THE LINK

;PICK UP THE MESSAGE

MSGFS1:	MOVE	S1,.LSJFN(LIS)		;PICK UP THE SRV: DEVICE JRN
	MOVE	S2,.LSMSG(LIS)		;PICK UP THE MESSAGE BUFFER ADDRESS
	HRLI	S2,(POINT 36)		;MAKE IT INTO A POINTER
	MOVNI	T1,PAGSIZ		;ASSUME MAXIMUM (DON'T TRUST SIBE%)
	SINR%				;PICK UP THE MESSAGE
	 ERJMP	MSGFS4			;ABORT THE LINK AND RE-OPEN

REPEAT 0,<
;CHECK IF CHECKSUMMING IS ENABLED. IF IT IS NOT, THEN SEND A SUCCESS ACK
;BACK TO LISSPL. IF IT IS ENABLED, THEN CALCULATE THE CHECKSUM. IF
;THE CHECKSUMS DO NOT AGREE, THEN SEND A FAILURE ACK MESSAGE BACK TO 
;LISSPL, OTHERWISE SEND A SUCCESS ACK BACK TO LISSPL.

	MOVE	S1,.LSMSG(LIS)		;PICK UP THE MESSAGE ADDRESS
	$CALL	LISCHK			;CHECKSUM THE MESSAGE IF NECESSARY
	JUMPF	MSGFS3			;CHECKSUMS DO NOT AGREE
>
;PROCESS THE RELEASE MESSAGE. DO THE ACCOUNTING AND SEND A SUCCESS ACK
;TO THE SENDER

	$CALL	DOACT			;DO THE ACCOUNTING, DELETE ANY FILES
	JUMPT	MSGFS2			;ACCOUNTING WAS SUCCESSFULLY PERFORMED
;	$WTO	(System Accounting Failure,<^R/.EQJBB(J)/>,)
MSGFS2:	$CALL	ACKSND			;SEND THE ACK MESSAGE
	JUMPT	MSGFS6			;ACK MESSAGE SUCCESSFULLY SENT
	JRST	MSGFS4			;ABORT AND RE-OPEN THE LINK

;THE CHECKSUMS DO NOT AGREE, SEND A FAILURE ACK TO THE SENDER

REPEAT 0,<
MSGFS3:	$CALL	ACKFAI			;SEND THE FAILURE ACK
	JUMPT	MSGFS6			;MESSAGE SUCCESSFULLY SENT
>

;A DECNET I/O ERROR HAS OCCURRED. ABORT THE LINK AND RE-OPEN IT.

MSGFS4:	$CALL	LABLNK			;[3]ABORT THE LINK
MSGFS5:	MOVEI	S1,.LSPDL(LIS)		;[6]SET UP THE LISTENER CONTEXT
	HRLI	S1,-<PDSIZ-1>		;[6]STACK POINTER
	MOVEM	S1,.LSACS+P(LIS)	;[6]SAVE AS THE NEW STACK POINTER
	MOVEI	S1,LISTE3		;[6]ADDRESS TO RESUME EXECUTION FROM	
	TXO	S1,1B5			;[6]
	MOVEM	S1,.LS1PC(LIS)		;[6]STORE AS THE NEW PC
MSGFS6:	$DEBRK				;RETURN TO THE PREVIOUS CONTEXT

;A FATAL ERROR HAS OCCURRED

MSGFS7:	$CALL	INLCRH			;RESET THE FORK
	$STOP	(FED, FATAL ERROR DETECTED)
	
	SUBTTL LSSCS - TOPOLOGY CHANGE DECTECTED INTERRUPT HANDLER

;LSSCS processes interrupts that occur as a consequence of a cluster
;topology change. If LSSCS detects that a node has left the cluster,
;then it checks the link status. If the link is no longer connected,
;then an attempt is made to re-open the link.
;
;Call is: Invoked when a cluster topology change has occurred
;DEBRKs:  The link has been re-opened if it was detected that the link
;         had become disconnected.
;Crashes: If the SCS% JSYS returns an error other than "event queue empty"

LSSCS:	$BGINT	1,			;INITIALIZE INTERRUPT LEVEL
	SETZM	.LSSCS(LIS)		;ASSUME NO NODES HAVE LEFT THE CLUSTER

;PICK UP THE NEXT EVENT FROM THE EVENT QUEUE

LSSC2:	MOVEI	S1,SCSLEN		;LENGTH OF THE ARGUMENT BLOCK
	MOVEM	S1,.LSSEB+.SQLEN(LIS)	;PLACE IN THE ARGUMENT BLOCK
	SETOM	.LSSEB+.SQCID(LIS)	;GET THE NEXT EVENT

	MOVEI	S1,.SSEVT		;RETRIEVE NEXT ENTRY FROM EVENT QUEUE
	MOVEI	S2,.LSSEB(LIS)		;ADDRESS OF THE ARGUMENT BLOCK
	SCS%				;PICK UP THE NEXT EVENT QUEUE ENTRY
	 ERJMP	LSSC4			;CHECK IF THE EVENT QUEUE IS NOW EMPTY

;CHECK THE TYPE OF EVENT THAT HAS OCCURRED

	MOVE	S1,.LSSEB+.SQEVT(LIS)	;PICK UP THE EVENT CODE
	CAIN	S1,.SENCO		;HAS A NODE COME ONLINE?
	JRST	LSSC2			;YES, DON'T CARE ABOUT THIS EVENT
	CAIE	S1,.SEPBC		;HAS A NODE GONE OFFLINE?
	JRST	LSSC2			;NO, DON'T CARE ABOUT THIS EVENT

;INDICATE THAT A NODE HAS LEFT THE CLUSTER

LSSC3:	SETOM	.LSSCS(LIS)		;A CLUSTER TOPOLOGY CHANGE OCCURRED
	JRST	LSSC2			;CHECK FOR ANOTHER EVENT QUEUE ENTRY

;THE SCS% JSYS RETURNED AN ERROR. CHECK IF THE EVENT QUEUE IS EMPTY.
;IF SO, RETURN. ON OTHER ERRORS, CRASH. THIS IS BECAUSE IT CANNOT JUST BE
;ASSUMED THAT A TOPOLOGY CHANGE HAS OCCURRED, SINCE IF THE ROUTINE EXITS ON
;THIS ASSUMPTION AND THERE ARE MORE EVENTS IN THE EVENT QUEUE, THEN THE
;LISTENER WILL NOT BE INTERRUPTED AGAIN IF A CLUSTER TOPOLOGY CHANGE OCCURS.

LSSC4:	MOVEI	S1,.FHSLF		;GET LATEST ERROR OF LISSPL
	GETER%				;PICK UP THE ERROR
	 ERJMP	S..SFE			;FATAL ERROR IN SCS% INTERRUPT HANDLER
	HRRZS	S2			;ISOLATE THE ERROR CODE
	CAIE	S2,SCSQIE		;EVENT QUEUE EMPTY?
	JRST	S..SFE			;NO, CONSIDER TO BE A FATAL ERROR
	SKIPL	.LSSCS(LIS)		;DID A NODE LEAVE THE CLUSTER?
	JRST	LSSC5			;NO, SO GO RETURN TO PREVIOUS CONTEXT
	$CALL	LCKLNK			;CHECK THE LINK STATUS
	JUMPT	LSSC5			;LINK STILL CONNECTED
	MOVEI	S1,.LSPDL(LIS)		;[6]SET UP THE LISTENER CONTEXT
	HRLI	S1,-<PDSIZ-1>		;[6]STACK POINTER
	MOVEM	S1,.LSACS+P(LIS)	;[6]SAVE AS THE NEW STACK POINTER
	MOVEI	S1,LISTE3		;[6]ADDRESS TO RESUME EXECUTION FROM	
	TXO	S1,1B5			;[6]
	MOVEM	S1,.LS1PC(LIS)		;[6]STORE AS THE NEW PC
LSSC5:	$DEBRK

	$STOP	(SFE, SCS% FATAL ERROR)
	SUBTTL	LCKLNK - CHECK THE STATUS OF THE LISTENER'S LINK

;LCKLNK is called to check the status of the listener's DECnet link to
;the sender. If there is no connection, then the DECnet link is
;closed and the DECnet JFN released
;
;Call is:       LIS/Address of the listener block
;Returns true:  The DECnet link is connected 
;Returns false: The DECnet link has been aborted
;Crashes:       Unable obtain the link status

LCKLNK:	$SAVE	<T1,T2>			;SAVE THESE AC, DESTROYED BY JSYS

;OBTAIN THE DECNET LINK STATUS.

	SKIPG	S1,.LSJFN(LIS)		;PICK UP THE DECNET JFN
	$RETF				;NO JFN, NO LINK
	MOVEI	S2,.MORLS		;WANT THE STATUS OF THE LINK
	MTOPR%				;OBTAIN THE STATUS OF THE LINK
	 ERJMP	LCKLN1			;[3]ON AN ERROR, ABORT THE LINK
	MOVEM	T1,.LSLNK(LIS)		;SAVE THE LINK STATUS IN LISTENER BLOCK

;DETERMINE IF THE LINK IS CONNECTED. IF IT IS NOT, THEN CLOSE AND RELEASE
;THE JFN.

	TXNE	T1,MO%CON		;IS THE LINK CONNECTED?
	$RETT				;YES, RETURN TRUE
LCKLN1:	$CALL	LABLNK			;[3]CLOSE AND RELEASE THE JFN
	$RETF				;INDICATE DON'T HAVE A LINK
	SUBTTL	LABLNK - ABORT THE LISTENER'S DECNET LINK

;LABLNK is called to abort the listener's DECnet link by closing the
;DECnet link with ABORT and releasing its JFN if necessary.
;
;Call is: LIS/Address of the listener block
;Returns: The listener's DECnet link has been aborted

LABLNK:	$SAVE	<T1,T2>			;SAVE THESE AC, DESTROYED BY JSYS
	MOVE	S1,.LSJFN(LIS)		;PICK UP THE DECNET JFN
	TXO	S1,CZ%ABT		;CLOSE WITH ABORT
	CLOSF%				;CLOSE THE DECNET LINK
	 ERJMP	LABLN2			;SHOULDN'T HAPPEN
	JRST	LABLN3			;GO RETURN
LABLN2:	MOVE	S1,.LSJFN(LIS)		;PICK UP THE DECNET JFN AGAIN
	RLJFN%				;RELEASE THE JFN
	 ERJMP	.+1			;SHOULDN'T HAPPEN
LABLN3:	SETZM	.LSJFN(LIS)		;INDICATE NO LONGER HAVE A JFN
	$RET				;INDICATE DON'T HAVE A LINK

REPEAT 0,<
	SUBTTL	LISCHK - LISTENER CHECKSUM AND ACK MESSAGE

;LISCHK is called when the listener has picked up a message. If checksumming
;is enabled on the sender's node and the listener's node, then a checksum of
;the message is performed. 
;If checksumming is disabled, either on the sender's node or the listener's
;node, then a checksum is not performed.
;
;Call is:       S1/Address of the message
;Returns true:  The checksums match or checksumming not enabled 
;Returns false: The checksums do not match and a failure ACK has been sent
;               to the sender.

LISCHK:	$SAVE	<P1>			;SAVE THIS AC
	SKIPN	CHKSUMO			;CHECKSUMMING ENABLED ON LOCAL NODE?
	JRST	LISCH2			;NO, JUST RETURN
;	SKIPN	P1,.MSCHS(S1)		;YES, CHECKSUMMING ENABLED REMOTELY?
	JRST	LISCH2			;NO, JUST RETURN
;	SETZM	.MSCHS(S1)		;ZERO OUT THE CHECKSUM WORD
	$CALL	CHKSUM			;CALCULATE THE CHECKSUM
	CAME	P1,S1			;DO THE CHECKSUMS AGREE?
	JRST	LISCH3			;NO, SEND FAILURE ACK TO SENDER
LISCH2:	$RETT				;INDICATE MESSAGE IS VALID
LISCH3:	$RETF				;INDICATE MESSAGE IS INVALID
>
	SUBTTL	ACKSND - SEND A SUCCESS ACK TO THE SENDER

;ACKSND is called to send an ACK message to the sender indicating that
;the RELEASE message has been picked up.
;
;Call is        LIS/Address of the listener block
;Returns true:  The ACK message was sent
;Returns false: The ACK message was not sent

ACKSND:	$SAVE	<T1,T2>			;SAVE THESE AC
	MOVE	S1,.LSJFN(LIS)		;PICK UP SRV: DEVICE JFN
	MOVEI	S2,T1			;ADDRESS OF THE MESSAGE
	HRLI	S2,(POINT 36,)		;MAKE IT INTO A POINTER
	SETO	T1,			;[3]NEGATIVE LENGTH OF THE MESSAGE
	SOUTR%				;SEND THE MESSAGE TO THE SENDER
	 ERJMP	.RETF			;INDICATE FAILURE TO THE CALLER
	$RETT				;INDICATE SUCCESS TO THE CALLER
					
	SUBTTL	INLCRH - ROUTINE TO INDICATE LISTENER CONTROLLED CRASH

;INLCRH is called by the listener when it has detected a fatal error.
;A RESET is performed to break the DECnet link.
;
;Call is: LIS/Address of the listener block

INLCRH:	DMOVEM	S1,.LSERR(LIS)		;SAVE THE CONTEXT OF S1 AND S2
	RESET%				;BREAK THE DECNET LINK
	DMOVE	S1,.LSERR(LIS)		;RESTORE CONTEXT OF S1 AND S2
	$RET				;RETURN TO THE CALLER
	SUBTTL	LPTDDT - ROUTINE TO LOAD DDT IF DEBUGGING

;LPTDDT is called if LPTSPL is running in a DEBUG environment.
;LPTDDT maps in and starts DDT.
;
;Call is: No arguments
;Returns: DDT has been loaded
;Crashes: If unable to load DDT


LPTDDT:	$SAVE	<T1,T2>			;SAVE THESE AC, DESTROYED BY JSYS
	MOVX	S1,GJ%OLD+GJ%SHT	;OLD FILE+SHORT JFN
	HRROI	S2,[ASCIZ/SYS:SDDT.EXE/] ;POINT TO DDT
	GTJFN%				;GET DDT'S JFN
	 ERJMP	LPTDD2			;CRASH IF CAN'T GET DDT'S JFN
	HRLI	S1,.FHSLF		;PICK UP HANDLE
	GET%				;LOAD DDT
	 ERJMP	LPTDD2			;CRASH IF CAN'T LOAD DDT
	MOVE	S1,116			;GET CONTENTS OF .JBSYM
	HRRZ	S2,770001		;GET ADDRESS OF WHERE TO PUT IT
	MOVEM	S1,0(S2)		;POINT DDT AT LPTSPL'S SYMBOL TABLE
	JRST	770000			;AND ENTER DDT
GO:	$RET				;RETURN

LPTDD2:	$STOP	(DDE, DDT ERROR)	;CRASH, IF CAN'T GET DDT
	SUBTTL	DOACT - DO ACCOUNTING FROM THE RELEASE MESSAGE

;DOACT is called when processing a RELEASE message sent by LISSPL. 
;DOACT deletes any files that were specified by the user to be deleted
;but which are not accessible to the remote system. DOACT also does
;accounting using information supplied in the RELEASE message. 
;
;Call is:       LIS/Address of the listener block
;Returns true:  The accounting was successfully done
;Returns false: The accounting was not done

DOACT:	$SAVE	<P1,P2>			;SAVE THIS AC

;FIRST CHECK FOR ANY FILES TO BE DELETED AND THEN DELETE THEM

	MOVE	P1,.LSMSG(LIS)		;[3]PICK UP THE MESSAGE ADDRESS
	SKIPN	P2,REL.ND(P1)		;[3]PICK UP NUMBER OF FILES TO DELETED
	JRST	DOACT2			;NO FILES TO DELETE
	MOVEI	P1,REL.RS(P1)		;[3]POINT TO THE FIRST FILE'S FD
DOACT1:	MOVEM	P1,.LSFOB+FOB.FD(LIS)	;SAVE THE FD ADDRESS IN THE FOB
	LOAD	S2,.FDLEN(P1),FD.LEN	;GET THE FD LENGTH.
	ADD	P1,S2			;POINT TO THE NEXT FILE'S FD
	SETZM	.LSFOB+FOB.US(LIS)	;NO ACCESS CHECKING
	SETZM	.LSFOB+FOB.CD(LIS)	;HERE ALSO
	MOVEI	S1,FOB.SZ		;GET THE FOB LENGTH
	MOVEI	S2,.LSFOB(LIS)		;AND THE FOB ADDRESS
	$CALL	F%DEL			;DELETE THE FILE
	SOJG	P2,DOACT1		;GO PROCESS THE NEXT FILE

;CHECK IF ACCOUNTING IS TO BE PERFORMED

DOACT2:	MOVE	P1,.LSMSG(LIS)		;PICK UP THE MESSAGE ADDRESS
	MOVE	S1,REL.FL(P1)		;PICK UP THE FLAG WORD
	TXNN	S1,RF.ACT		;IS THERE ACCOUNTING INFORMATION?
	$RETT				;NO, RETURN NOW
	MOVEI	S1,.USENT		;WRITE AN ENTRY
	MOVEI	S2,ACTLIS		;POINT TO THE LIST
	USAGE%				;DO THE JSYS
	 ERJMP	.RETF			;INDICATE ERROR TO THE CALLER
	$RETT				;INDICATE SUCCESS TO THE CALLER
	SUBTTL	ACTLIS - LISTENER ACCOUNTING RECORD

ACTLIS:	
IFN FTACNT,< 
	USENT.	(.UTOUT,1,1,0)
	USTAD.	(-1)			;CURRENT DATE/TIME
	USPNM.	(<SIXBIT/LPTSPL/>,US%IMM) ;PROGRAM NAME
	USPVR.	(LPTVNO)		;PROGRAM VERSION
	USAMV.	(-1)			;ACCOUNTING MODULE VERSION
	USNOD.	(REL.NN(P1))		;NODE NAME
	USSRT.	(REL.RT(P1))		;RUN TIME
	USSDR.	(REL.DR(P1))		;DISK READS
	USSDW.	(0,US%IMM)		;DISK WRITES
	USJNM.	(REL.JN(P1))		;JOB NAME
	USQNM.	(<SIXBIT /LPT/>,US%IMM)	;QUEUE NAME
	USSDV.	(REL.DN(P1))		;DEVICE NAME
	USSSN.	(REL.SN(P1))		;JOB SEQUENCE NUMBER
	USSUN.	(REL.PP(P1))		;TOTAL PAGES PRINTED
	USSNF.	(REL.FP(P1))		;TOTAL FILES PROCESSED
	USCRT.	(REL.CD(P1))		;CREATION DATE/TIME OF REQUEST
	USSCD.	(REL.SD(P1))		;SCHEDULED DATE/TIME
	USFRM.	(REL.FT(P1))		;FORMS TYPE
	USDSP.	(<SIXBIT/NORMAL/>,US%IMM) ;DISPOSITION
	USPRI.	(REL.JP(P1))		;JOB PRIORITY
	USJNO.	(-1)			;JOB NUMBER
	USTRM.	(-1)			;TERMINAL DESIGNATOR
	USLNO.	(-1)			;TTY LINE NUMBER
	USTXT.	(<-1,,[ASCIZ / /]>)	;SYSTEM TEXT
	USNM2.	(<POINT 7,REL.UN(P1) >)  ;USER NAME (TOPS20)
	USACT.	(<POINT 7,REL.AS(P1) >)	;ACCOUNT STRING POINTER
	0				;END OF LIST
>
	ACTLEN==.-ACTLIS		;ACCOUNTING BLOCK LENGTH
	SUBTTL	STOP CODE DEFINITIONS

	$STOP	(CAC,CAN'T ACTIVATE DECNET DATA AVAILABLE CHANNEL)
	$STOP	(COD, CAN'T SETUP DEBUGGING DECNET DEVICE NAME)	;[10]
	SUBTTL	End of LPTCLU

	END