Google
 

Trailing-Edge - PDP-10 Archives - tops10_tools_bb-fp64b-sb - 10,7/decnet/getnod/getnod.mac
There are no other files named getnod.mac in the archive.
	TITLE	GETNOD -- Get a network database from some other node
	SUBTTL	T. LITT/TL	5-Oct-87


	SEARCH	UUOSYM,MACTEN,SCNMAC

	.TEXT |/LOCALS/SYMSEG:HIGH|
	.REQUEST REL:SCAN
	.REQUIRE REL:WILD


;
;
;		COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
;				1987.
;			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  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.
;
	SUBTTL	Table of Contents

;               TABLE OF CONTENTS FOR GETNOD
;
;
;                        SECTION                                   PAGE
;    1. Table of Contents.........................................   2
;    2. Definitions...............................................   3
;    3. Revision History..........................................   4
;    4. HELP TEXT.................................................   5
;    5. Switch table definition...................................   6
;    6. MACROS....................................................   7
;    7. Main program starts here..................................   8
;    8. Loop reading node data....................................  11
;    9. Handle end of response message............................  13
;   10. File output routines......................................  14
;   11. RSPERR  Report NICE response error........................  15
;   12. GETCMD  Read a command line from the user.................  19
;   13. PSCAN   Handle prompting and @ files for the command scanner  21
;   14. REDNOD  Read node names for the command scanner...........  22
;   15. SCNSWT - Scan off any switches............................  24
;   16. SHONDS  Send a SHOW (or LIST) NODES command...............  25
;   17. NICE byte string manipulation routines....................  26
;   18. MAPIT   Map from node number to node name.................  27
;   19. OPNLNK & CLSLNK Open and close NICE links to a foreign NML  28
;   20. Close NICE link to foreign node...........................  29
;   21. Network send and receive routines.........................  30
;   22. Special typeout routines..................................  31
;   23. String conversion routines................................  32
;   24. Error handling routines...................................  33
;   25. NSP. Error handling.......................................  34
;   26. Pure data and Low segment.................................  37
	SUBTTL	Definitions

	SALL			;Clean listings
	.DIRECTIVE FLBLST

DEFINE	FLAG(SYL),<
	...FLG==1B0
	IRP SYL,<	F.'SYL==...FLG
			...FLG==...FLG_-1
		>
	>

	F=0
		FLAG	<TTYO,FILO>	;[6] Flag bits--TTY output, File output
	T1=1
	T2=2
	T3=3
	T4=4
	P1=5
	P2=6
	P3=7
	P4=10
	P=17
	N==P3
	C==P4

	;FILES
	FIL==1


	.HELPR==:.POPJ

	TWOSEG	640K		;Make us high and low

; Program version information

	GTNVER==1		;Major version
	GTNMIN==0		;Minor version
	GTNEDT==6		;Edit version
	GTNWHO==0		;Who last edited

	%%GTN==VRSN.(GTN)	;Full word version
IFDEF .MCRV.,<	.VERSION <%%GTN>>

	LOC	137
.JBVER::! EXP	%%GTN
	RELOC
	SUBTTL	Revision History


COMMENT	&

Edit	Description

1	22-Sep-87	TL
	Creation.  Minor debt owed NETPTH for network IO and command
	scanning, though a whole lot of fixing and upgrading of the latter
	was done.

2	24-Sep-87	TL
	Learn how to do connects by the numbers.

3	25-Sep-87	TL
	NTMAN. used in MAPIT returns junk when called unpriv'd.  Try to
	fake things out instead, so MJM can play.

4	1-Oct-87	RCB/TL
	Merge code from RCB which fools with flow control, segment size, and
	quotas to improve performance, as well as cleans up the command 
	scanner.  Accept switches on RH of "=", in reasonable places.  Default
	area number when 0.nnn numeric addressing is used.

5	1-OCT-87	TL
	Support indirect files, CCL RUN UUOs, GETNOD monitor command.

6	5-Oct-87	RCB
	Fix PSCAN logic.  Call .OSCAN at EOL.
	Fix node name parsing so '2B' works again.

	;Loose ends:
	None currently

&; End Revsion History
	SUBTTL	HELP TEXT

HLPSTR:	ASCIZ	|

			GETNOD %1(6)
			  5-Oct-87

GETNOD will establish a DECnet connection to the network management listener
of any DECnet node, and obtain a list of all defined network nodes and their
names.  GETNOD will interrogate either the volatile or the permanent database
of the remote node.  GETNOD writes a command file (suitable for input to
NCP or NODNAM) which, when executed by these utilities, will define the
network as viewed by the remote node.

Because the NICE network protocol is used, this method is relatively immune
to changes in the format of the remote node's database.

Command syntax:
	GETNOD>outputfilespec{/switch(es)}=remotenodespec
or
	GETNOD>@indirectfilespc

or, if DECLARed as a monitor command:

	.GETNOD outputfilespec{/switch(es)}=remotenodespec
or
	.GETNOD @indirectfilespc

Parameters:
	Outputfilespec	A standard TOPS-10 filespecification which describes
			where the command file is to be written.  Defaults
			to DSK:NODNAM.INI[-].

	Remotenodespec	A standard DECnet node identifier for the node whose
			database is to be obtained.  May be specified as
			{AREA.}nodenumber{"user pass acct"}{::} or as
			nodename{"user pass acct"}{::}.

	Indirectfilespc A standard TOPS-10 file specification which indicates
			where GETNOD commands are to be found.  Defaults to
			DSK:GETNOD.CCL/.CMD[-].  If started at the CCL entry, 
			GETNOD will process TMP:GTN or jjjGTN.TMP, if present.

Switches:
	/PERMANENT	Read the remote node's permanent database.  
	/VOLATILE	Read the remote node's volatile database (default).

	The normal SCAN switches (eg, /ERSUPERSEDE, /VERSION, /ESTIMATE, 
	/DENSITY ...) may also be specified.

|
	SUBTTL	Switch table definition

;KEYS	SWAR,<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
;21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
;41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,
;61,62,63>

	DEFINE	SWTCHS,<
;SL	AREA,U.AREA,SWAR,0,FS.OBV
SN	PERMAN,U.PERM,
SN	VOLATI,U.VOLAT,
	>

	DOSCAN(SWIT)
	SUBTTL	MACROS

; Handy macro for manipulating string blocks
	DEFINE	STRBLK(MAX<XX>,STRING)<
	XX==0
	IRPC	STRING,<XX==XX+1>
	XWD	XX,1+<MAX+3>/4
	IFB <STRING>,<BLOCK	<MAX+3>/4>
	CC==^D36-8
	XX==0
	IRPC	STRING,<
	XX==XX+"STRING"_CC
	CC==CC-8
	IFL CC,<CC==^D36-8
		XX
		XX==0>
			>
	IFN CC-<^D36-8>,XX
	>

	DEFINE	ERROR(PFX,TEXT)<
	JRST	[MOVX	T1,<SIXBIT |GTN'PFX|> ;; Get Prog name, error prefix
		 MOVE	T2,["?",,[ASCIZ |TEXT|]] ;; Get lead char, error text
		 JRST	ERRDIE]		;; And go croak
	>

	DEFINE	WARN(PFX,TEXT)<
	PUSHJ	P,WRNRTN		;; Call the warning routine
	JUMP	[SIXBIT |GTN'PFX|	;; Get Prog name, error prefix
		 "%",,[ASCIZ |TEXT|]]	;; Get lead char, error text
	>
	SUBTTL	Main program starts here

GETNOD:	PORTAL	.+2			;[6] Allow for protected entry
	 PORTAL	.+2			;[6] Even if CCL
	TDZA	T1,T1			;[5] Normal entry
	 MOVEI	T1,1			;[5] CCL entry
	MOVEM	T1,OFFSET		;[5] Save for SCAN
	RESET				;Blow away the world
	MOVX	F,F.TTYO		;[6] Initialize for TTY output
	MOVE	P,STKPTR		;Set up stack

	MOVEI	T1,^D9			;[4] Read our node number
	MOVEM	T1,NTREX+.NTBYT		;[4] NTMAN. will return max of 9 chars
	MOVEI	T1,NTREX		;[4] Now get my own node number
	NTMAN.	T1,			;[4] Ask the monitor
	 JRST	[SETO	T1,		;[4] Assume no privs
		 JRST	.+2]		;[4] And skip this
	LDB	T1,[POINT 6,X.NODE,7+8-2] ;[4] Fetch area number of our node
	MOVEM	T1,X.AREA		;[4] Save for later
	MOVE	T1,ISCARG		;Get arg for .ISCAN
	PUSHJ	P,.ISCAN##		;Init SCAN

	;Here, we scan the command line, and connect to the listener.

CONTIN:	HLRZ	T1,.JBSA##		;Make sure we don't grow forever
	MOVEM	T1,.JBFF##
	SETOM	BLKWRT			;No blocks written yet
	SETOM	U.PERM			;Make switches "not specified"
	SETOM	U.VOLAT			;...
	MOVX	F,F.TTYO		;[6] Make sure output is to TTY:
	PUSHJ	P,GETCMD		;Read a command line
	SKIPN	N.SPEC			;If null command
	 JRST	CONTIN			;Don't execute anything

	MOVEM	T1,REMNOD		;Save pointer to destination node
	PUSHJ	P,OPNLNK		;Go open link to foreign NML
	  JRST	NSPERR			;Can't open NICE link. Not NICE.
; Print out banner - Some of which is part of the [Connected to...] message.
; It's confusing, but we create both messages at once.

	TXC	F,F.TTYO!F.FILO		;[6] Switch to file output
	MOVEI	T1,[ASCIZ |;DECnet |]	;Output goes to file
	PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ |volatile |]
	SKIPE	U.VOLAT			;If /NOVOLATILE  [Default: /VOLATILE]
	SKIPLE	U.PERM			;Or /PERMANENT  [Both: /PERMANENT]
	 MOVEI	T1,[ASCIZ |permanent |]
	PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ |database obtained by GETNOD %|]
	PUSHJ	P,.TSTRG##
	MOVE	T1,.JBVER		;Version
	PUSHJ	P,.TVERW##
	MOVEI	T1,[ASCIZ | from |]
	PUSHJ	P,.TSTRG##
	TXC	F,F.TTYO!F.FILO		;[6] Switch back to terminal
	PUSHJ	P,.TCRLF##
	MOVEI	T1,[ASCIZ |[GTNCNN Connected to |]
	PUSHJ	P,.TSTRG##
	TXO	F,F.FILO		;[6] Write to both
	MOVEI	T1,[ASCIZ |node |]
	PUSHJ	P,.TSTRG##
	MOVE	T1,REMNOD		;Get end node name
	SETZ	T2,			;No enforced field length
	PUSHJ	P,.TNNAM		;Type it out too
	PUSHJ	P,.TSPAC##		;Space over
	MOVE	T1,REMNOD		;Get node address
	PUSHJ	P,.TNNAD		;Type it out
	TXZ	F,F.TTYO		;[6] Back to file
	PUSHJ	P,.TCRLF##
	MOVEI	T1,[ASCIZ |;on |]
	PUSHJ	P,.TSTRG##
	MOVX	T1,%CNDTM		;Time
	GETTAB	T1,
	 HALT	.
	PUSHJ	P,.TDTTM##
	MOVEI	T1,[ASCIZ | using |]
	PUSHJ	P,.TSTRG##
	TXC	F,F.TTYO!F.FILO		;[6] Terminal
	MOVEI	T1,[ASCIZ |, |]
	PUSHJ	P,.TSTRG##
	TXO	F,F.FILO		;[6] Both
	MOVEI	T1,[ASCIZ |NICE version |]
	PUSHJ	P,.TSTRG##
	LDB	T1,[POINT 8,VERFLG,7]	;Fetch major version
	PUSHJ	P,.TDECW##
	MOVEI	T1,"."
	PUSHJ	P,.TCHAR##
	LDB	T1,[POINT 8,VERFLG,7+8]	;Fetch DEC ECO version
	PUSHJ	P,.TDECW##
	MOVEI	T1,"."
	PUSHJ	P,.TCHAR##
	LDB	T1,[POINT 8,VERFLG,7+8+8] ;Fetch User ECO version
	PUSHJ	P,.TDECW##
	TXZ	F,F.FILO		;[6] Terminal only
	PUSHJ	P,.TRBRK##
	PUSHJ	P,.TCRLF##
	TXC	F,F.TTYO!F.FILO		;[6] Conintue with file output
	PUSHJ	P,.TCRLF##		;Type a crlf

	;Headers written.  Issue a command to the listener, and make sure
	;that it responds with a multi-part response introducer.

	PUSHJ	P,SHONDS		;Send SHOW/LIST KNOWN NODES command
	SETZM	NNODES			;[4] No responses processed yet
	PUSHJ	P,REDMSG		;Read first reply
	PUSHJ	P,NICSET		;Set up pointers
	PUSHJ	P,NICBYT		;Get first byte of message
	 HALT	 .			;!?!?
	TRNE	T1,200			;Error?
	 JRST	RSPERR			;Yes, report response error
	CAIE	T1,2			;Ought to be multi-part response
	 ERROR	(NMP,<NICE Listener didn't send expected response>)
	MOVEI	T1,FILOUT		;[6] Skip test overhead
	PUSHJ	P,.TYOCH##		;[6] During file construction
	SUBTTL	Loop reading node data

	;The listener is responding with a sequence of messages
	;each of which describes one node.  We validate and decode each
	;one, writing an output record for each valid node.  When we
	;get an "end of response" message, we stop.

LOOP:	PUSHJ	P,REDMSG		;Read next reply
	PUSHJ	P,NICSET		;Set up pointers
	PUSHJ	P,NICBYT		;Get first byte of message
	 HALT	 .			;!?!?
	CAIN	T1,200			;End of response?
	 JRST	ENDDAT			;Yes
	TRNE	T1,200			;Error?
	 JRST	RSPERR			;Yes, report response error
	CAIE	T1,1			;Better be single part response
	 ERROR	(NSR,<Expected single part response message, but got something else>)
	PUSHJ	P,NICBYT		;Read error detail
	 HALT	.
	PUSH	P,T1			;Save first
	PUSHJ	P,NICBYT		;...
	 HALT	.			;Both ought to be present
	POP	P,T2			;Fetch first
	CAIN	T1,377			;Better be -1
	 CAME	T1,T2			;...
	 ERROR	(BED,<Listener provided unexpected error detail>)
	PUSHJ	P,NICBYT		;Fetch entity ID
	 HALT	.
	SKIPE	T1			;Check for "Node"
	 ERROR	(ENN,<Listener returned non-node entity type>)
	;Message looks OK, fetch the node number and name fields.
	;A bunch of parameters follow, but we don't care what they say.

	PUSHJ	P,NICBYT		;Fetch low node address
	 HALT	.
	PUSH	P,T1
	PUSHJ	P,NICBYT		;Fetch high node address
	 HALT	.
	LSH	T1,^D8			;Shift into position
	IORM	T1,(P)			;Save result
	MOVE	T1,NICBPT		;Get pointer to name string
	MOVE	T2,T1			;Make copy
	ILDB	T3,T2			;Fetch length
	ANDI	T3,177			;Pitch "Executor" bit
	JUMPE	T3,LOOP.B		;[6] Skip this node if no name
	DPB	T3,T2			;Put length back

	MOVEI	T1,[ASCIZ |Set Node |]
	PUSHJ	P,.TSTRG##

	LDB	T1,[POINT 6,(P),25]	;Get area number
	JUMPE	T1,LOOP.A		;Skip if no area number
	PUSHJ	P,.TDECW##		;Type in decimal
	MOVEI	T1,"."			;Add delimiter
	PUSHJ	P,.TCHAR##		;...
LOOP.A:	LDB	T1,[POINT 10,(P),35]	;Get node address
	PUSHJ	P,.TDECW##		;Type in decimal

	MOVEI	T1,[ASCIZ | Name |]
	PUSHJ	P,.TSTRG##

	MOVE	T1,NICBPT		;[6] Fetch name pointer again
	SETZ	T2,			;No enforced field length
	PUSHJ	P,.TCASC		;Type it out
	PUSHJ	P,.TCRLF##		;Finish up with a <CRLF>
	AOS	NNODES			;[4] Count one more node

LOOP.B:	ADJSP	P,-1			;[6] Toss node number

	JRST	LOOP			;Try next message
	SUBTTL	Handle end of response message

	;Here at end of response.  All that's left is to close off
	;the output file, and log completion for the user.

ENDDAT:	PUSHJ	P,CLSLNK		;Close the network link
	MOVEI	T1,[ASCIZ |;[End of file on |]
	PUSHJ	P,.TSTRG##
	MOVX	T1,%CNDTM		;Include time so elapsed time 
	GETTAB	T1,			;can be computed if desired
	 HALT	.
	PUSHJ	P,.TDTTM##
	MOVEI	T1,[ASCIZ |, |]		;[4] Padding
	PUSHJ	P,.TSTRG##
	MOVE	T1,NNODES		;[4] How many nodes
	PUSHJ	P,.TDECW##		;[4] Stuff into file
	MOVEI	T1,[ASCIZ | nodes|]	;[4] Say what this is
	PUSHJ	P,.TSTRG##		;[4] To the file
	PUSHJ	P,.TRBRK##		;Right squarebracket
	PUSHJ	P,.TCRLF##		;End of line

	PUSHJ	P,FIXOUT		;[6] Restore top-level output routine
	MOVEI	T1,[ASCIZ |
[GTNWRT DECnet database received, |]
	PUSHJ	P,.TSTRG##		;[4] Type it
	MOVE	T1,NNODES		;[4] Get node count again
	PUSHJ	P,.TDECW##		;[4] Tell the user
	MOVEI	T1,[ASCIZ | nodes, |]	;[4] Some padding

	;You'd think this would be simple, but we are using large buffers.
	;Thus, we need to work to get the number of blocks written.

	PUSHJ	P,.TSTRG##
	MOVEI	T1,A.OPEN		;Point to OPEN block
	DEVSIZ	T1,			;See about buffer size
	 HALT	.			;Can't be that old
	HRRZS	T1			;Ignore number of buffers
	SUBI	T1,3			;Delete ring header size
	MOVE	T3,T1			;Copy buffer size (in words)
	ADDI	T1,177			;Round up (In case of (say) magtape)
	IDIVI	T1,200			;To standard blocks
	IMUL	T1,BLKWRT		;Compute blocks written
	IMULI	T3,5			;Make buffer size into bytes
	SUB	T3,A.BFR+.BFCTR		;Size-free - bytes written in last bufr
	ADDI	T3,<200*5>-1		;Round to blocks that CLOSE will write
	IDIVI	T3,200*5
	ADD	T1,T3			;Add CLOSE blocks to explict OUT blocks
	PUSHJ	P,.TDECW##		;Report
	MOVEI	T1,[ASCIZ | blocks written]|]
	PUSHJ	P,.TSTRG##
	PUSHJ	P,.TCRLF##

	CLOSE	FIL,			;Now, change ring header
	STATZ	FIL,IO.ERR		;Check for last-moment errors
	 JRST	OUTERR
	RELEASE	FIL,			;Drop the channel

	JRST	CONTIN			;No, go back to command mode
	SUBTTL	File output routines

FIXOUT:	MOVEI	T1,BTHOUT		;[6] Full-blown output routine
	PUSHJ	P,.TYOCH##		;[6] Make sure we use it
	TXZ	F,F.FILO		;[6] Suppress file output
	TXO	F,F.TTYO		;[6] Ensure TTY: output
	POPJ	P,			;[6] Done resetting output

BTHOUT:	TXNE	F,F.TTYO		;[6] Supposed to do TTY output?
	OUTCHR	T1			;[6] Yes--do it up ugly
	TXNN	F,F.FILO		;[6] Supposed to do file output?
	POPJ	P,			;[6] No--return now
					;[6] Yes--fall into FILOUT
FILOUT:	SOSL	A.BFR+.BFCTR		;Room?
	 JRST	FILOT1
	OUT	FIL,			;Get new buffer
	 AOSA	BLKWRT			;Another "block" written
	JRST	OUTERR			;Error doing output
	 JRST	FILOUT			;Look for space

	;Someday, report error bits
OUTERR:	ERROR	(FOE,<File output error>)

FILOT1:	IDPB	T1,A.BFR+.BFPTR		;Put this byte
	POPJ	P,			;Done
	SUBTTL	RSPERR	Report NICE response error

	;Here when we get an error response code from the listener.
	;Major error codes are negative in an 8 bit byte.  We report
	;the major error code, and if supplied, the error detail and/or
	;OS-generated text fields.  There's no point continuing, so we quit.

RSPERR:	TDO	T1,[-1,,777400]		;Sign extend error code
	MOVNS	T1			;Make more convenient
	CAILE	T1,MAXRSE		;Bigger than max known?
	 SETZ	T1,			;Hmmm
	MOVE	T1,RSETAB(T1)		;Fetch error descriptor
	PUSH	P,T1			;Save entry
	PUSHJ	P,FIXOUT		;[6] Make sure of TTY: output
	MOVEI	T1,[ASCIZ |
?GTNRNE NICE error from remote node - |]
	PUSHJ	P,.TSTRG##
	PUSHJ	P,NICBYT		;Fetch low error detail
	HALT	.			;HOPELESS
	PUSH	P,T1			;Save that
	PUSHJ	P,NICBYT		;Fetch high error detail
	HALT	.			;HOPELESS
	LSH	T1,^D8			;Shift over
	IORM	T1,(P)			;Merge and save
	HRRZ	T1,-1(P)		;Fetch string address
	PUSHJ	P,.TSTRG##		;Print Major error string
	POP	P,T2			;Fetch error detail
	POP	P,T1			;Fetch table entry
	HLRZS	T1			;Fetch aux routine
	SKIPE	T1			;If specified
	 PUSHJ	P,(T1)			;...Do it too
	PUSH	P,NICBPT		;Save start of string
	PUSHJ	P,NICBYT		;Fetch error string
	HALT	.			;HOPELESS
	JUMPE	T1,RSPER1		;No text available
	PUSHJ	P,.TCRLF##
	MOVE	T1,(P)			;Fetch pointer
	SETZ	T2,			;No minimum length
	PUSHJ	P,.TCASC		;Print counted string
RSPER1:	ADJSP	P,-1
	PUSHJ	P,.TCRLF##
	JRST	GETNOD
	;This is a table of ASCIZ error string by -<NICE return status code>
	;Code 0 is undefined in NICE, so we use it for out of range status.
	;The LH of each table entry points to an auxiliary routine which 
	;adds to the error string based on the error detail.

RSETAB:	XWD	0,[ASCIZ |Invalid or unrecognized NICE error returned|]
	XWD	0,[ASCIZ |Unrecognized function or option|] ;(1)
	XWD	0,[ASCIZ |Invalid message format|]	;(2)
	XWD	0,[ASCIZ |Privilege violation|]		;(3)
	XWD	0,[ASCIZ |Oversized Management command message|] ;(4)
	XWD	0,[ASCIZ |Management program error|]	;(5)
	XWD RSPPAR,[ASCIZ |Unrecognized parameter type|]	;(6)
	XWD	0,[ASCIZ |Incompatible Management version|] (7)
	XWD RSPENT,[ASCIZ |Uncrecognized component|]	;(8)
	XWD RSPent,[ASCIZ |Invalid identification|]	;(9)
	XWD	0,[ASCIZ |Line communication error|]	;(10)
	XWD RSPENT,[ASCIZ |Component in wrong state|]	;(11)
	XWD	0,[ASCIZ |Obsolete NICE error|]		;(12)
	XWD RSPFIL,[ASCIZ |File open error|]		;(13)
	XWD RSPFIL,[ASCIZ |Invalid file contents|]	;(14)
	XWD	0,[ASCIZ |Resource error|]		;(15)
	XWD RSPPAR,[ASCIZ |Invalid parameter value|]	;(16)
	XWD	0,[ASCIZ |Line protocol error|]		;(17)
	XWD RSPFIL,[ASCIZ |File I/O error|]		;(18)
	XWD RSPMIR,[ASCIZ |Mirror link disconnected|]	;(19)
	XWD	0,[ASCIZ |No room for new entry|]	;(20)
	XWD RSPMIR,[ASCIZ |Mirror connect failed|]	;(21)
	XWD RSPPAR,[ASCIZ |Parameter not applicable|]	;(22)
	XWD RSPPAR,[ASCIZ |Parameter value too long|]	;(23)
	XWD	0,[ASCIZ |Hardware failure|]		;(24)
	XWD	0,[ASCIZ |Operation failure|]		;(25)
	XWD	0,[ASCIZ |System-specific Management function not supported|]	;(26)
	XWD	0,[ASCIZ |Invalid parameter grouping|]	;(27)
	XWD	0,[ASCIZ |Bad loopback response|]	;(28)
	XWD RSPPAR,[ASCIZ |Parameter missing|]		;(29)
	MAXRSE==.-RSETAB-1		;[6]
	;This page contains routines to interpret error detail.
	;Implementations are free not to provide error detail, in which
	;case the error detail is supplied as 2^16-1.  When no error
	;detail is supplied, we add nothing.  Note that the text of these
	;messages is specified by the NICE spec, and is not to be changed
	;on a whim.

	;Each routine is called with the error detail code in T2, and
	;calls CHKDET to see if the error detail is present.

	;Error detail is a parameter number

RSPPAR:	PUSHJ	P,CHKDET			;See if detail is provided
	MOVEI	T1,[ASCIZ |, parameter number |]
	PUSHJ	P,.TSTRG##
	POP	P,T1			;Fetch parameter number
	PJRST	.TDECW##		;Print it

	;Error detail is an Entity type

RSPENT:	PUSHJ	P,CHKDET		;Check for detail
	MOVEI	T1,[ASCIZ |, entity is |]
	PUSHJ	P,.TSTRG##
	POP	P,T1
	CAILE	T1,5			;Be sure reasonable
	 SETO	T1,
	MOVE	T1,[[ASCIZ /UNKNOWN/]
			[ASCIZ	/NODE/]
			[ASCIZ	/LINE/]
			[ASCIZ	/LOGGING/]
			[ASCIZ	/CIRCUIT/]
			[ASCIZ	/MODULE/]
			[ASCIZ	/AREA/]]+1(T1)
	PJRST	.TSTRG##

	;Error detail is a file type

RSPFIL:	PUSHJ	P,CHKDET		;Detail present?
	POP	P,T1			;Fetch detail
	CAILE	T1,7			;Known?
	 POPJ	P,			;No, forget it
	MOVE	T1,[	[ASCIZ	/, Permanent database/]
			[ASCIZ /, Load file/]
			[ASCIZ /, Dump file/]
			[ASCIZ /, Secondary loader/]
			[ASCIZ /, Tertiary loader/]
			[ASCIZ /, Seconday dumper/]
			[ASCIZ /, Volatile database/]
			[ASCIZ /, Diagnostic file/]
		    ](T1)
	PJRST	.TSTRG##
	;Error detail is a mirror error

RSPMIR:	PUSHJ	P,CHKDET		;Detail present?
	POP	P,T1
	CAILE	T1,^D16			;Known?
	 POPJ	P,
	MOVE	T1,[	[ASCIZ /, No node name set/]
			[ASCIZ /, Invalid node name format/]
			[ASCIZ /, Unrecognized node name/]
			[ASCIZ /, Node unreachable/]
			[ASCIZ /, Network resources/]
			[ASCIZ /, Rejected by object/]
			[ASCIZ /, Invalid object name format/]
			[ASCIZ /, Unrecognized object/]
			[ASCIZ /, Access control rejected/]
			[ASCIZ /, Object too busy/]
			[ASCIZ /, No response from object/]
			[ASCIZ /, Remote node shut down/]
			[ASCIZ /, Node or object failed/]
			[ASCIZ /, Disconnect by object/]
			[ASCIZ /, Abort by object/]
			[ASCIZ /, Abort by Management/]
			[ASCIZ /, Local node shut down/]
		   ](T1)
	PJRST	.TSTRG##

	;Here with error detail code in T2.
	;If value is "none supplied", we return to the caller's caller,
	;to suppress detail reporting.  Otherwise, we return having
	;pushed the error detail code onto the stack.  This because
	;virtually all reporting routines want to output a prefix before
	;looking at the error detail.

CHKDET:	CAIN	T2,177777		;DETAIL PROVIDED?
	 JRST	CHKNDT			;NO
	EXCH	T2,(P)			;Yes, stack it
	JRST	(T2)			;Return

	;No detail is supplied, don't report this code.
CHKNDT:	ADJSP	P,-1			;Pitch return
	POPJ	P,			;Routine is a no-op
	SUBTTL	GETCMD	Read a command line from the user

; This routine will read in command lines of the form:
;
;	Filespec=Sourcenode
;
; Call:	PUSHJ	P,GETCMD		;Takes no arguments
;	<Only return>			;T1 contains a byte pointer to the
;					;node name in standard NML format.
;					;Ie: <Low#><High#><Length><Name>
;

GETCMD:	SETZM	N.SPEC			;Remember nothing yet
	MOVE	T1,PSCARG		;[6] Get arg for .PSCAN
	PUSHJ	P,PSCAN			;[6] Call our prompter
	SETZM	CBLK+.NSCUS		;DEFAULT TO NO ACCESS CTL
	SETZM	CBLK+.NSCPW
	SETZM	CBLK+.NSCAC
	PUSHJ	P,.FILIN##		;Read a filespec
	SKIPN	T1			;[4] If got no filespec,
	JUMPLE	C,GETCMD		;[6] Ignore this cruft
	MOVEI	T1,A.ZER		;POINT TO OUR AREA
	MOVEI	T2,A.EZER-A.ZER+1  	;..
	PUSHJ	P,.GTSPC##		;GO COPY SPEC
	SKIPN	T1,A.EXT		;SKIP IF EXT SPECIFIED
	HRLOI	T1,'INI'		;DEFAULT IS INI
	MOVEM	T1,A.EXT
	SKIPN	A.NAM			;SEE IF NAME
	SETOM	A.NAMM			;NO--DEFAULT TO NO WILD
	SKIPN	T1,A.NAM		;SKIP IF NAME SPECIFIED
	MOVE	T1,[SIXBIT/NODNAM/]	;Default
	MOVEM	T1,A.NAM
	SKIPN	T1,A.DEV
	 MOVSI	T1,'DSK'
	MOVEM	T1,A.DEV

	CAIE	C,"="
	 ERROR(NEQ,<No "=" in command line>)

	PUSHJ	P,REDNOD		;Read the node we talk to
	SKIPLE	C			;Did line terminate properly?
	 PUSHJ	 P,REDJEL		;No, go eat it up
REDEOL:	SKIPN	N.SPEC			;[6] If no node,
	JUMPLE	C,GETCMD		;[6] Just loop for the blank line

	MOVE	T1,OSCARG		;[6] Point to argument block
	PUSHJ	P,.OSCAN##		;[6] Read SWITCH.INI
	MOVEI	T1,A.ZER		;[6] Point to our filespec area
	MOVEI	T2,A.EZER-A.ZER+1	;[6] With its length
	PUSHJ	P,.OSDFS##		;[6] Apply any defaults

	MOVSI	T3,.RBEST		;[6] Length of lookup
	MOVSM	T3,A.LOOK
	MOVEI	T1,A.DEV		;[6] SCAN BLOCK
	MOVEI	T2,A.OPEN		;[6] OPEN BLOCK
	HRRI	T3,A.LOOK		;[6] LOOKUP BLOCK
	PUSHJ	P,.STOPN##		;[6] Convert SCAN to monitor
	 ERROR	(FWI,<Wildcard illegal in output filespec>)
	MOVSI	T1,A.BFR		;[6] Buffer hdr
	MOVEM	T1,A.OPEN+.OPBUF	;[6] Save
	MOVX	T1,UU.LBF
	IORM	T1,A.OPEN
	OPEN	FIL,A.OPEN
	 JRST	[PUSHJ	P,E.DFO##
		 MOVEI T1,A.DEV
		 PUSHJ	P,.TFBLK##
		 PUSHJ	P,.TCRLF##
		 JRST	GETNOD]
	ENTER	FIL,A.LOOK
	 JRST	[MOVEI	T1,A.LOOK
		 MOVE	T2,A.LOOK+.RBCNT
		 ANDI	T2,777
		 MOVEI	T3,A.DEV
		 PUSHJ	P,E.LKEN##
		 JRST	GETNOD]

	MOVE	T1,[POINT 8,N.SPEC]	;Get BP to source node name
	POPJ	P,			;And return happily

REDJEL:	JUMPLE	C,.POPJ			;Did line end properly??
	 WARN	 (JEL,Junk at end of line - ignored)
	PUSHJ	P,.TICHR##		;Read a char
	JUMPG	C,.-1			;Loop till we hit eol
	POPJ	P,
	SUBTTL	PSCAN	Handle prompting and @ files for the command scanner

PSCAN:	MOVEM	T1,PSCANA		;[6] Save arg pointer
	MOVEM	P,PSCANP		;[6] And calling pdl
	JRST	PSCAN1			;[6] Skip restart logic
PSCAN0:	MOVE	P,PSCANP		;[6] Restore PDL pointer
	PUSHJ	P,FIXOUT		;[6] Make sure of TTY: output
	MOVE	T1,PSCANA		;[6] Restore arg pointer
PSCAN1:	SETOM	REPARS			;[6] Init reparsing flag
	PUSH	P,.OPTN##		;[6] Save /OPTION
	PUSH	P,.FLVRB##		;[6] Save /MESSAGE
	PUSHJ	P,.PSCAN##		;[6] Set up partial line scanner
	 TDZA	T1,T1			;[6] Wants to prompt
	MOVEI	T1,1			;[6] Just parse
	POP	P,.FLVRB##		;[6] Restore /MESSAGE
	POP	P,.OPTN##		;[6] Restore /OPTION
	AOSE	REPARS			;[6] Did scan restart .PSCAN (/HELP ?)
	JRST	PSCAN0			;[6] Yes--take it from the top
	JUMPN	T1,PSCAN2		;[6] Jump if no prompt needed
	SKPINL				;[6] Clear ^O
	  JFCL				;[6] Ignore return
	MOVEI	T1,[ASCIZ |GETNOD>|]	;[6] Yes--get prompt string
	PUSHJ	P,.TSTRG##		;[6] And type it

PSCAN2:	PUSHJ	P,.TICHR##		;[6] Prime the pump - get a character
	CAIN	C," "			;[6] A space?
	 PUSHJ	P,.TICHR##		;[6] Get a real character
	CAIE	C,"@"			;[6] See if indirect file
	JRST	PSCAN3			;[6] It isn't
	PUSHJ	P,.GTIND##		;[6] Yes--set up for it
	JUMPG	C,E.ILSC##		;[6] Demand eol here
PSCAN3:	CAMN	C,[.CHEOF]		;[6] If found an EOF,
	PUSHJ	P,.ALDON##		;[6] Do the right thing with it
	JUMPLE	C,PSCAN0		;[6] Try again if not yet time to exit
	PJRST	.REEAT##		;[6] Return ready to eat this character
	SUBTTL	REDNOD	Read node names for the command scanner

; Read one node name or number, checking for validity, skipping spaces, etc.
; Return name in N.SPEC as a standard DECnet node name string.
;
; Call:	PUSHJ	P,REDNOD		;Go read a name or number
;	 Only return; node name in N.SPEC, terminating character in C.
;

REDNOD:	SETZM	N.SPEC			;Clear number and name length fields
	SETZM	N.ADDR			;Clear address mode flag
	PUSHJ	P,SWTSCN		;[4] See if any switches
	JUMPLE	C,.POPJ			;[5] EOL means stop
	PUSHJ	P,.SIXMW##		;[6] Read some characters
	SKIPE	.NMUL##+1		;[6] Did we get too many?
	 WARN	 (NLS,Node name longer than six characters)
	MOVE	T4,.NMUL##		;[6] Fetch the name
	TDNN	T4,['@@@@@@']		;[6] Any alphabetics seen?
	JRST	REDNO7			;[6] No--go handle address format

; Loop around gathering up node name.
	MOVE	T1,[POINT 8,N.SPEC,7+8+8] ;[6] Get BP to 1st byte of name
	SETZ	T2,			;[6] Set to count up length
REDNO1:	JUMPE	T4,REDNO2		;[6] Stop if no more characters
	SETZ	T3,			;[6] Clear character AC
	LSHC	T3,6			;[6] Get next character
	ADDI	T3," "			;[6] Convert to ASCII
	IDPB	T3,T1			;[6] Stuff into node spec
	AOJA	T2,REDNO1		;[6] Loop over all characters
REDNO2:	JUMPE	T2,REDRET		;[6] Skip out now if null name
	DPB	T2,[POINT 8,N.SPEC,7+8+8] ;[6] Set length in node spec
	JRST	REDNOA			;[6] Go map name & win

; Here if 1st char of node name is a digit.  User wants to use #
REDNO7:	SETZ	T1,			;[6] Clear accumulation AC
REDNO8:	JUMPE	T4,REDNO9		;[6] Finished if out of characters
	SETZ	T3,			;[6] Clear character AC
	LSHC	T3,6			;[6] Get next digit
	IMULI	T1,^D10			;[6] Shift to next decade
	ADDI	T1,-'0'(T3)		;[6] Include next digit
	JRST	REDNO8			;[6] Loop over all digits
REDNO9:	JUMPE	T1,REDNOB		;[6] Zero addresses are naughty
	CAIE	C,"."			;Area?
	 JRST	REDN7A			;No
	LSH	T1,^D10			;[6] Yes, position
	PUSH	P,T1			;[6] Save
	PUSHJ	P,.DECNW##		;Read next
	JUMPE	N,[ADJSP P,-1
		   JRST	REDNOB]		;Silly user
	POP	P,T1			;[6] Restore area
	TDNN	N,[-1_^D10]		;Invalid node?
	 TDNN	T1,[-1,,776000]		;Invalid area?
	JRST	REDNOB			;Naughty
	IOR	N,T1			;Add area

REDN7A:	DPB	N,[POINT 8,N.SPEC,7]	;Install the low order byte
	LSH	N,-8			;Get the high order byte
	MOVE	T1,X.AREA		;[4] Fetch home area for defaulting
	LSH	T1,2			;[4] Adjust area
	TRNN	N,77_2			;[4] Area specified?
	 IOR	N,T1			;[4] No, merge one
	DPB	N,[POINT 8,N.SPEC,7+8]	;Install the high order byte
	SKIPG	N			;[4] See if default used and invalid
	 ERROR	NPA,<Area must be specified in node address>
	SETOM	N.ADDR			;Remember address-mode connect used
;[6]	JRST	REDNOA			;Go map name and give skip return

; Here to map the name to a number, and determine reachability
REDNOA:	MOVE	T1,[POINT 8,N.SPEC]	;Get pointer to node spec
	PUSHJ	P,MAPIT			;Map number into name (or vice versa)
	 CAIA				;Failed
	JRST	REDRET			;OK, continue parse

	SKIPE	N.ADDR			;[6] OK if not address mode connect
	 JRST	 REDNOE			;Unknown component

	;Here, we've read the node name or number.  
	;We must now parse the optional access control string, and/or ::
REDRET:	CAIN	C,""""			;Start of access control?
	 PUSHJ	P,REDACC		;Yes
	CAIE	C,":"			;Node terminator?
	 JRST	REDRT0			;[4] No, possible switch
	PUSHJ	P,.TICHR##		;[6] Yes, get next char
	CAIE	C,":"			;Better be ::
	 JRST	REDRT1			;Nope
	PUSHJ	P,.TICHR##		;[6] Get next char

REDRT0:	SKIPLE	C			;[6] If needed,
	PUSHJ	P,.REEAT##		;[4] Re-stuff delimiter
	PUSHJ	P,SWTSCN		;[4] Scan any switches
	POPJ	P,

REDRT1:	SKIPLE	C			;[6] If not EOL
	PUSHJ	P,.REEAT##		;Not, re-stuff it
NODSYN:	ERROR	(NSY,<Invalid nodname syntax>)
	POPJ	P,			;And return

; Here when name to number mapping operation fails
REDNOE:	CAIN	P2,6			;Did user give a node number??
REDNOB:	 ERROR	 (INN,Illegal node number) ;Yes, give correct message
	ERROR	(UKN,Unknown node name)
;Here to read access control string

REDACC:	PUSHJ	P,.AS8QC##		;Read full string
	PUSHJ	P,.SAVE1##		;SAVE AN AC
	MOVE	P1,[POINT 8,.NMUL##]	;Point to data
	MOVEI	T1,CUSER		;Read user name
	PUSHJ	P,RDACS
	 JRST	RDACT			;None, check termination
	MOVEM	T1,CBLK+.NSCUS		;Tell NSP.
	MOVEI	T1,CPASS		;Read password
	PUSHJ	P,RDACS
	 JRST	RDACT			;None, check termination
	MOVEM	T1,CBLK+.NSCPW		;Tell NSP.
	MOVEI	T1,CACC			;Read account string
	PUSHJ	P,RDACS
	 JRST	RDACT			;None, check termination
	MOVEM	T1,CBLK+.NSCAC		;Tell NSP.
RDACT:	POPJ	P,			;Done

	;Helper routine to read an access control field into a DECnet
	;string block.  We are careful not to scribble past end of SB.

RDACS:	HRRZ	T2,.NSASL(T1)		;Fetch length of block
	SUBI	T2,.NSAST		;Subtract length of header
	IMULI	T2,4			;Compute longest string
	MOVEI	T3,.NSAST(T1)		;Address of string
	HRLI	T3,(POINT 8,,)		;Make into pointer
	SETZ	T4,			;Bytes in string
	PUSH	P,C			;Save SCAN's C

RDACS1:	CAMN	P1,[POINT 8,.NMUE##,31]	;Off end?
	 JRST	RDACSE			;Yes
	ILDB	C,P1			;Fetch next char
	SKIPE	C			;If off end, don't store
	CAIN	C," "			;Space?
	 JRST	RDACSE			;Yes, end of this field
	SOJL	T2,RDACS1		;No, include if space left in SB
	IDPB	C,T3			;Store it
	AOJA	T4,RDACS1		;Read next character

RDACSE:	POP	P,C			;Restore SCAN's C
	HRLM	T4,.NSASL(T1)		;Store string length
	SKIPE	T4			;Anything here?
	 AOS	(P)			;Yes
	POPJ	P,			;DONE
	SUBTTL	SCNSWT - Scan off any switches

SWTSCN:	SKIPLE	C			;[6] If not yet EOL,
	PUSHJ	P,.TICHR##		;[6] Get a character
SWTSC1:	CAIN	C," "			;[6] Is it a space?
	 PUSHJ	P,.TICHR##		;[6] Yes, get next character
	CAIE	C,"/"			;[4] Switch introducer?
	 JRST	SWTSCE			;[4] End of switches
	PUSHJ	P,.KEYWD##		;[4] Read the switch
	 ERROR	NSS,<No switch specified>
	JUMPG	C,SWTSC1		;[6] If not EOL, see if another switch
	POPJ	P,			;[6] EOL (?)

SWTSCE:	SKIPLE	C			;[6] Unless EOL
	PUSHJ	 P,.REEAT##		;[4] No, put it back
	POPJ	P,			;[4] Done
	SUBTTL	SHONDS	Send a SHOW (or LIST) NODES command


;	This routine will issue a NICE SHOW or LIST KNOWN NODES command to
;	the listener process on the other end of the link.
;
; Call:	PUSHJ	P,SHONDS
;	<Return +1 always>

SHONDS:	DMOVE	T1,[EXP SHWNLN		;Length of NICE SHOW command
		    POINT 8,SHWNIC]	;Pointer to command
	SKIPE	U.VOLAT			;If /NOVOLATILE  [Default: /VOLATILE]
	SKIPLE	U.PERM			;Or /PERMANENT  [Both: /PERMANENT]
	 DMOVE	T1,[EXP LSTNLN		;Length of NICE LIST command
		    POINT 8,LSTNIC]	;Pointer to command
	PUSHJ	P,SNDMSG		;Go send the message
	POPJ	P,			;Command issued
	SUBTTL	NICE byte string manipulation routines

; Call this to set up for calls to NICBYT

NICSET:	DMOVEM	T1,NICCNT		;Put BP and count in safe place
	POPJ	P,

; Call this for each byte to be read from NICE message

NICBYT:	SOSGE	NICCNT			;Any bytes left??
	 POPJ	 P,			;No, give skip return
	ILDB	T1,NICBPT		;Yes, get one
.POPJ1:	AOS	(P)			;And give
.POPJ:	POPJ	P,			;skip return

; Get current ILDB pointer to NICE string

NICPTR:	MOVE	T1,NICBPT		;Get current NICE pointer
	POPJ	P,
	SUBTTL	MAPIT	Map from node number to node name

; Call:	MOVx	T1,BP to node spec
;	PUSHJ	P,MAPIT
;	 <+1 return if node is unknown>
;	<+2 return if success>
; In either case T1/ original BP

MAPIT:	MOVEM	T1,NTMAP+.NTBPT		;Set up pointer to info to be mapped
	MOVEI	T2,9			;Get length of MAPBUF
	MOVEM	T2,NTMAP+.NTBYT		;Stuff it
	MOVEI	T2,NTMAP		;Get arg for NTMAN.
	NTMAN.	T2,			;Read mapping from monitor
	 JFCL				;Something went wrong
	;What NTMAN. returns on error is unpredictable.  NTMAN. is
	;a privileged UUO in any case.  There is no alternative.
	;In any case, if a null name string is returned, we want to
	;default it.  So the error doesn't much matter.
	MOVE	T2,T1			;Copy node spec
	ILDB	T3,T2			;Fetch address
	ILDB	T4,T2			;...
	IOR	T3,T4			;See if known
	SKIPN	N.ADDR			;Address mode connect?
	 POPJ	P,			;No, node number 0 is harmless
	JUMPE	T3,.POPJ		;Yes, return error if no number
	ILDB	T3,T2			;Have number, see if name
	JUMPN	T3,.POPJ1		;Wonder why we failed...pretend not

	MOVEI T3, 6			;Default name
	DPB T3,T2			;So
	MOVE T4,[POINT 7,[ASCII /....../]]
DEFNAM:	ILDB	T3,T4			;Fetch a char
	SKIPE	T3			;End?
	IDPB	T3,T2			;Copy to user
	JUMPN	T3,DEFNAM		;For entire string
	JRST	.POPJ1			;Pretend we Translated
	SUBTTL	OPNLNK & CLSLNK	Open and close NICE links to a foreign NML

	;Open a NICE link to the node whose description is passed in T1.
	;Read the connect confirm data to establish the NICE protocol version
	;being spoken by the listener.

OPNLNK:	ILDB	T2,T1			;Skip first byte
	ILDB	T3,T1			;Skip second byte of node number
	SKIPE	N.ADDR			;Address mode connect?
	 JRST	[PUSHJ	P,BLDNNA	;Yes, Build numeric node address
		 JRST	OPNLN2]		;Continue
	ILDB	T2,T1			;Get length of node name
	SKIPN	T2			;Is it legal?
	 HALT	 .			;!?! Zero node name?
	HRLM	T2,CNODE		;Save length of name in string block

	MOVE	T3,[POINT 8,CNODE+1]	;Get pointer to destination
OPNLN1:	ILDB	T4,T1			;Get byte from node name
	IDPB	T4,T3			;Stuff it into the NSP. block
	SOJG	T2,OPNLN1		;Loop till done

OPNLN2:	MOVEI	T1,ENTACT		;Get addr for NSP.
	NSP.	T1,			;Open up link to foreign node
	  JRST	[SKIPE	ENTACT+.NSAA3	;[4] Already been here?
		 CAIE	T1,NSPRV%	;[4] No, can we handle this error?
		 JRST	OPNLNE		;[4] Punt--print nice error message
		 SETZM	ENTACT+.NSAA3	;[4] Yes--give up on flow control
		 JRST	OPNLN2]		;[4] Try it again
	HRRZ	T1,ENTACT+.NSACH	;Get channel number
	MOVEM	T1,NETCHN		;Save it for SNDMSG and REDMSG
	MOVEM	T1,RCVBLK+.NSACH	;[6] Stuff it where REDMSG wants it

	MOVEM	T1,RCCBLK+.NSACH	;Install channel number in CC block
	MOVEM	T1,SLQBLK+.NSACH	;[4] Stuff into seq-quota block
	MOVEI	T1,SLQBLK		;[4] Get arg for NSP.
	NSP.	T1,			;[4] Change buffer quota and input %age
	  TRN				;[4] Ignore this error
	MOVEI	T1,RCCBLK		;Get arg for NSP.
	NSP.	T1,			;Read Connect Confirm Data
	  JRST	OPNLNE			;Report NSP. error
	MOVE	T1,CCDATA+.NSAST	;Get NSP VER.ECO.USR
	MOVEM	T1,VERFLG		;Remember which version of NML
	JRST	.POPJ1

OPNLNE:	POPJ	P,

	;Routine to build an undocumented descriptor for by-address connect.

BLDNNA:	LSH	T3,^D8			;Shift high byte to it's place
	IOR	T2,T3			;Build node number
	MOVE	T3,[POINT 6,T2]		;Pointer to fetch address with
	MOVE	T4,[POINT 8,CNODE+1]	;Pointer to string block data

BLDNN1:	ILDB	T1,T3			;Fetch 6 bits of address
	ADDI	T1,40			;Convert to pseudo-ASCII
	IDPB	T1,T4			;Store in string block
	TLNE	T3,770000		;done with block?
	 JRST	BLDNN1			;No

	MOVEI	T1,^D6			;Byte count for SB
	HRLM	T1,CNODE		;Store it
	POPJ	P,			;Done
	SUBTTL	Close NICE link to foreign node


CLSLNK:	MOVE	T1,NETCHN		;Get network channel number
	MOVEM	T1,DSCBLK+.NSACH	;Install it in NSP. block
	MOVEI	T1,DSCBLK		;Get pointer to NSP. arg block
	NSP.	T1,			;Do Synchronus Disconnect
	  JRST	NSPERR			;Report NSP. error
	MOVE	T1,NETCHN		;Get network channel number
	MOVEM	T1,RELBLK+.NSACH	;Install it in NSP. block
	MOVEI	T1,RELBLK		;Get arg for releasing channel
	NSP.	T1,			;Drop the channel
	  JRST	NSPERR			;Report NSP. error
	POPJ	P,
	SUBTTL	Network send and receive routines

; Call:	MOVEI	T1,length-of-message
;	MOVE	T2,[BP to message]
;	PUSHJ	P,SNDMSG
;	 <Return +1 Always>

SNDMSG:	DMOVEM	T1,SNDBLK+.NSAA1	;Install byte count and byte pointer
	MOVE	T1,NETCHN		;Get network channel number
	MOVEM	T1,SNDBLK+.NSACH	;Install it
	MOVEI	T1,SNDBLK		;Get address of arg block
	NSP.	T1,			;Send the data
	  JRST	NSPERR			;Report NSP. error
	POPJ	P,			;Return happily

; REDMSG will read data from the network.  It will return T1 with a byte count,
; and T2 with a byte pointer.  T1 and T2 will be supplied by me, and ignored
; if they are set up.


REDMSG:	DMOVE	T1,[MSGLEN		;[6] Length of my buffer
		    POINT 8,MSGBUF]	;Pointer to my buffer
	DMOVEM	T1,RCVBLK+.NSAA1	;Install in NSP. arg block
	MOVEI	T1,RCVBLK		;Get arg for NSP.
	NSP.	T1,			;Read data from network
	  JRST	NSPERR			;Report NSP. error
	MOVEI	T1,MSGLEN		;Get size of message buffer
	SKIPLE	RCVBLK+.NSAA1		;[6] Unless we truncated,
	SUB	T1,RCVBLK+.NSAA1	;Compute number of bytes received
	MOVE	T2,[POINT 8,MSGBUF]	;Get pointer to message buffer
	POPJ	P,
	SUBTTL	Special typeout routines

; .TNNAM  Type out the standard style node name pointed to by T1
.TNNAM:	IBP	T1
	IBP	T1
	PJRST	.TCASC

; .TNNAD  Type out standard node address pointed to by T1
.TNNAD:	PUSH	P,T1			;Save byte pointer
	ILDB	T1,(P)			;Get first byte of address
	ILDB	T2,(P)			;And second byte
	LSH	T2,^D8			;Combine in T1
	IOR	T1,T2			;...
	MOVEM	T1,(P)			;Save
	MOVEI	T1,"("			;Delimit node address
	PUSHJ	P,.TCHAR##		;...
	LDB	T1,[POINT 6,(P),25]	;Get area number
	JUMPE	T1,TNNAD1		;Skip if no area number
	PUSHJ	P,.TDECW##		;Type in decimal
	MOVEI	T1,"."			;Add delimiter
	PUSHJ	P,.TCHAR##		;...
TNNAD1:	LDB	T1,[POINT 10,(P),35]	;Get node address
	PUSHJ	P,.TDECW##		;Type in decimal
	MOVEI	T1,")"			;Add delimiter
	PUSHJ	P,.TCHAR##		;...
	ADJSP	P,-1			;Clean stack
	POPJ	P,			;And return


; .TCASC  Type out a counted ASCII string pointed to by BP in T1
; Enforced field length is in T2
.TCASC:	PUSHJ	P,.SAVE3##		;Save several Ps
	DMOVE	P1,T1			;Put BP and count in a safe place
	ILDB	P3,P1			;Get number of chars into P3
	SUB	P2,P3			;Calculate number of pad characters
TCASC1:	JUMPE	P3,TCASC2		;Jump if no more bytes
	ILDB	T1,P1			;Get another byte
	PUSHJ	P,.TCHAR##		;Type it out
	SOJA	P3,TCASC1		;Bop the count and start over
TCASC2:	JUMPLE	P2,.POPJ		;Return if no more pads needed
	PUSHJ	P,.TSPAC##		;Pad with a space
	SOJA	P2,TCASC2		;Loop for all needed pads
	SUBTTL	String conversion routines


; CASSIX - Convert counted ASCII to SIXBIT

CASSIX:	ILDB	T2,T1			;Get byte count
	CAILE	T2,6			;More than six bytes
	 MOVEI	 T2,6			;Yes, make it six
	SETZ	T3,			;Clear receiving buffer
CASSI1:	JUMPLE	T2,CASSI3		;Return when byte count hits zero
	LSH	T3,6			;Make room for next byte
	ILDB	T4,T1			;Get a byte from the string
	SUBI	T4," "			;Make it SIXBIT
	IOR	T3,T4			;Install new byte
	SOJA	T2,CASSI1		;Do it all over again

CASSI3:	MOVE	T1,T3			;Get data into right AC
CASSI2:	SKIPE	T1			;Prevent infinite loops
	TLNE	T1,770000		;Left justified yet??
	 POPJ	 P,			;Yes, we're all done
	LSH	T1,6			;No, try again
	JRST	CASSI2			;. . .
	SUBTTL	Error handling routines

WRNRTN:	PUSHJ	P,.PSH4T##		;Save all the important acs
	SETZ	T1,			;Fix output
	PUSHJ	P,.TYOCH##
	PUSH	P,T1
	MOVE	T3,@-5(P)		;Get the instruction after PUSHJ to us
	LDB	T4,[POINT 9,T3,8]	;Get the opcode
	CAIE	T4,JUMP_-^D27		;Is it a jump?
	 HALT	 .			;No, die horribly
	MOVE	T1,0(T3)		;Get first arg for .ERMSG
	MOVE	T2,1(T3)		;Get second arg for .ERMSG
	PUSHJ	P,.ERMSG##		;Call the processor
	PUSHJ	P,.TCRLF##		;Tie it off with a CRLF
	POP	P,T1
	PUSHJ	P,.TYOCH##		;RESTORE OUTPUT
	PUSHJ	P,.POP4T##		;Restore the world
	POPJ	P,

ERRDIE:	PUSHJ	P,FIXOUT		;[6] Make sure of TTY: output
	PUSHJ	P,.ERMSG##		;Issue the error message
	PUSHJ	P,.TCRLF##		;Followed by a CRLF
	PUSHJ	P,.CLRBF##		;Clear typeahead
	MOVEI	T1,FIL			;Point to file channel
	RESDV.	T1,			;Don't write new version
	 JFCL				;Maybe it wasn't open yet
	JRST	GETNOD			;And start over
	SUBTTL	NSP. Error handling

	;This routine reports NSP. UUO errors.
	;Enter with error code in T1

NSPERR:	PUSHJ	P,.SAVE1##		;Save an AC
	MOVE	P1,T1			;Save error from NSP. uuo
	PUSHJ	P,FIXOUT		;[6] Fix output
	MOVE	T1,['GTNNSP']		;Get message prefix
	MOVE	T2,["?",,[ASCIZ |NSP. error |]] ;Get error prefix
	PUSHJ	P,.ERMSG##		;Print message
	CAILE	P1,MAXERR		;Do we know this error code?
	 SETZ	 P1,			;No, use general unknown
	HRR	T1,NSPERC(P1)		;Get address of error text
	PUSHJ	P,.TSTRG##		;Type it out
	PUSHJ	P,.TCRLF##		;Type a <CRLF>
	JRST	GETNOD			;And restart gracefully
	;Table of NSP. error codes

DEFINE ERRMAC(code,text),<
	IF1,<IFN code-<.-NSPERC>,<
		PRINTX ?NSP. error code out of order in NSPERC table>>
	ERRMC1(\code,text)
>
DEFINE ERRMC1(code,text),<[ASCIZ |(code) text|]>

NSPERC:	ERRMAC 0,     <Unknown Error, code in AC 1>
	ERRMAC NSABE%,<Argument Block Format Error>
	ERRMAC NSALF%,<Allocation failure>
	ERRMAC NSBCN%,<Bad channel number>
	ERRMAC NSBFT%,<Bad format type in process block>
	ERRMAC NSCFE%,<Connect Block format error>
	ERRMAC NSIDL%,<Interrupt data too long>
	ERRMAC NSIFM%,<Illegal flow control mode>
	ERRMAC NSILF%,<Illegal function>
	ERRMAC NSJQX%,<Job quota exhausted>
	ERRMAC NSLQX%,<Link quota exhausted>
	ERRMAC NSNCD%,<No connect data to read>
	ERRMAC NSPIO%,<Percentage input out of bounds>
	ERRMAC NSPRV%,<No Privileges to Perform Function>
	ERRMAC NSSTB%,<Segment size too big>
	ERRMAC NSUKN%,<Unknown node name>
	ERRMAC NSUXS%,<Unexpected State: Unspecified>
	ERRMAC NSWNA%,<Wrong number of arguments>
	ERRMAC NSWRS%,<Function called in wrong state>

;New error codes (to be re-ordered):

	ERRMAC NSCBL%,<Connect block length error>
	ERRMAC NSPBL%,<Process block length error>
	ERRMAC NSSBL%,<String block length error>
	ERRMAC NSUDS%,<Unexpected State: Disconnect Sent>
	ERRMAC NSUDC%,<Unexpected State: Disconnect Confirmed>
	ERRMAC NSUCF%,<Unexpected State: No Confidence>
	ERRMAC NSULK%,<Unexpected State: No Link>
	ERRMAC NSUCM%,<Unexpected State: No Communication>
	ERRMAC NSUNR%,<Unexpected State: No Resources>
;Error codes which correspond to DECnet disconnect codes.

	ERRMAC NSRBO%,<Rejected by Object>
	ERRMAC NSDBO%,<Disconnected by Object>
	ERRMAC NSRES%,<No Resources at Remote Node>
	ERRMAC NSUNN%,<Unrecognized Node Name>
	ERRMAC NSRNS%,<Remote Node Shut Down>
	ERRMAC NSURO%,<Unrecognized Object>
	ERRMAC NSIOF%,<Invalid Object Name Format>
	ERRMAC NSOTB%,<Object Too Busy>
	ERRMAC NSABM%,<Abort by Management>
	ERRMAC NSABO%,<Abort by Object>
	ERRMAC NSINF%,<Invalid Node Name Format>
	ERRMAC NSLNS%,<Local Node Shut Down>
	ERRMAC NSACR%,<Access Control Rejection>
	ERRMAC NSNRO%,<No Response from Object>
	ERRMAC NSNUR%,<Node Unreachable>
	ERRMAC NSNLK%,<No Link>
	ERRMAC NSDSC%,<Disconnect Complete>
	ERRMAC NSIMG%,<Image Field Too Long>
	ERRMAC NSREJ%,<Unspecified Reject Reason>

	ERRMAC NSBCF%,<Bad combination of NS.EOM & NS.WAI flags>
	ERRMAC NSADE%,<Address Error>
MAXERR==.-NSPERC-1
	SUBTTL	Pure data and Low segment

STKPTR:	IOWD	STKLEN,STACK		;Set up stack from this word

	XLIST				;Turn off listing for a moment
	LIT				;Generate literals in hiseg
	LIST				;Turn on listing after lits

	RELOC	0

; Argument block for mapping node numbers into node names
NTMAP:	EXP	.NTLST
	EXP	0
	EXP	0
	EXP	.NTMAP
	EXP	0
	EXP	0
	POINT	8,MAPBUF
	EXP	0
	EXP	0

MAPBUF:	BLOCK	<9+3>/4

; Argument block for reading the executor node name
NTREX:	EXP	.NTMAX
	EXP	.NTNOD
	EXP	0
	EXP	.NTREX
	EXP	0
	EXP	0
	POINT	8,X.NODE
	EXP	0
	EXP	0

X.NODE:	BLOCK	3
; The following is an NSP. arg block for doing an Enter Active to another NML

ENTACT:	NS.WAI+.NSFEA_^D18+5		;[4] Enter Active, Please Wait
	EXP	0			;Channel number
	EXP	CBLK			;Connect Block pointer
	EXP	70			;[4] Empirically seems to be enough
	EXP	1			;[4] Small segment size & no flow control

;[4] The following block is used to set the buffer allocation

SLQBLK:	NS.WAI+.NSFSQ_^D18+4		;[4] Set link quotas
	EXP	0			;[4] Channel number
	EXP	^D100			;[4] A few buffers
	EXP	^D99			;[4] Almost all for input

; The following block is used to read the connect confirm data

RCCBLK:	XWD	.NSFRC,5		;Read connect data function
	EXP	0			;Channel number
	EXP	CCDATA			;Pointer to string block
	EXP	0
	EXP	0

CCDATA:	STRBLK	^D16			;Connect Confirm Data string block
; The next block is used for sending data over the network

SNDBLK:	NS.EOM+NS.WAI+.NSFDS_^D18+4	;Blocking data send and end of message
	EXP	0			;Channel number goes here
	EXP	0			;Byte count goes here
	EXP	0			;Byte pointer goes here

; This block is used for receiving data from the network (via NSP.)

RCVBLK:	NS.EOM+NS.WAI+.NSFDR_^D18+4	;[6] Blocking data receive & truncate
	EXP	0			;Channel number
	EXP	0			;Byte count
	EXP	0			;Byte pointer

; This is a disconnect block

DSCBLK:	XWD	.NSFSD,3		;Synchronus disconnect
	EXP	0			;Channel number goes here
	EXP	0			;No disconnect data

; This is a channel release block

RELBLK:	XWD	.NSFRL,2		;Release this channel
	EXP	0			;Channel number goes here

MSGBUF:	BLOCK	^D50			;Lotsa room for network data
	MSGLEN==<.-MSGBUF>*4		;[6] # of 8 bit bytes
; The following is a connect block for opening the network connections

CBLK:	EXP	CBLEN			;.NSCNL
	EXP	CNODE			;.NSCND
	EXP	CSOURC			;.NSCSD
	EXP	CDEST			;.NSCDD
	EXP	0;CUSER			;.NSCUS
	EXP	0;CPASS			;.NSCPW
	EXP	0;CACC			;.NSCAC
	EXP	CIDATA			;.NSCUD
	CBLEN==.-CBLK

CNODE:	STRBLK	6			;Max six chars for node names
CDEST:	EXP	3			;.NSDFL
	EXP	0			;.NSDFM
	EXP	.OBNIC			;.NSDOB
CSOURC:	EXP	5
	EXP	1,0,0			;Format 1, no object type or PPN
	EXP	SRCSTR			;Address of my name

CUSER:	STRBLK	^D39			;USER-ID

CPASS:	STRBLK	^D39			;PASSWORD

CACC:	STRBLK	^D39			;ACCOUNT

CIDATA:	XWD	3,CUDLEN		;Connect initiate user data
	BYTE	(8) 4,1,0		;Our Maj.ECO.Usr NICE protocol version
	CUDLEN==.-CIDATA

SRCSTR:	STRBLK	^D6,<GETNOD>		;My name
	;NICE message "SHOW KNOWN NODES SUMMARY"

	%%SHOW==0		;SHOW command
	%%LIST==200		;LIST command

SHWNIC:	BYTE	(8) ^D20, 0_4+.NTNOD+%%SHOW,	-1
	;FCN, OPT			,ENTITY

SHWNLN==3	;Number of bytes in this NICE message

	;NICE message "LIST KNOWN NODES SUMMARY"

LSTNIC:	BYTE	(8) ^D20, 0_4+.NTNOD+%%LIST,	-1
	;FCN, OPT			,ENTITY

LSTNLN==3	;Number of bytes in this NICE message
; The following two locations must be kept together
NICCNT:	BLOCK	1			;Remaining byte count for NICE message
NICBPT:	BLOCK	1			;NICE byte pointer

VERFLG:	BLOCK	1		;-1=Phase 2, 0=phase 3, 1=phase 4
NETCHN:	BLOCK	1			;Channel for NSP.'s
REMNOD:	BLOCK	1			;Name of current node

N.SPEC:	BLOCK	3			;Node name goes here
N.ADDR:	BLOCK	1			;-1 if address mode connect
STACK:	BLOCK	50
	STKLEN==.-STACK
; Control block for .ISCAN

ISCARG:	XWD	ISCLEN,ISCBLK		;T1 for call to .ISCAN

ISCBLK:	IOWD	CMDN,CMDTAB		;[6] Allowable monitor commands
	XWD	OFFSET,'GTN'		;[6] CCL flag,,TMPCOR name
	EXP	BTHOUT			;[6] Default input,,our output
	EXP	0			;[6] No indirect file
	EXP	0			;[6] Default prompt & monret
	EXP	FS.INC			;[6] No CORE UUOs
	ISCLEN==.-ISCBLK

CMDTAB:	SIXBIT	/GETNOD/
	SIXBIT	/GN/
	SIXBIT	/G/
	CMDN==.-CMDTAB

PSCARG:	XWD	PSCLEN,PSCBLK

PSCBLK:	IOWD	SWITL,SWITN
	XWD	SWITD,SWITM
	XWD	0,SWITP
	XWD	1,HLPSTR
	PSCLEN==.-PSCBLK

;[6] .OSCAN argument pointer

OSCARG:	XWD	OSCLEN,OSCBLK

OSCBLK:	IOWD	SWITL,SWITN
	XWD	SWITD,SWITM
	XWD	0,SWITP
	EXP	-1			;[6] Let SCAN do a GETTAB
	OSCLEN==.-OSCBLK

; Filespec parse data

A.ZER:!
A.DEV:	BLOCK	1		;DEVICE
A.NAM:	BLOCK	1		;NAME
A.NAMM:	BLOCK	1		;NAME MASK
A.EXT:	BLOCK	1		;EXTENSION AND MASK
A.MOD:	BLOCK	1		;MODIFIERS
A.MODM:	BLOCK	1		;MODIFIER MASK
A.DIR:	BLOCK	1		;DIRECTORY
A.DIRM:	BLOCK	2*.FXLND-1	;DIRECTORY MASK
	BLOCK	.FXLEN-<.-A.ZER> ;[6] Make sure it's long enough for STDSWC
A.EZER==.-1

A.OPEN:	BLOCK	3		;OPEN BLOCK
A.LOOK:	BLOCK	.RBEST+1	;LOOKUP BLOCK

A.BFR:	BLOCK	3		;BUFFER HEADERS FOR INDIRECT FILE
BLKWRT:	BLOCK	1		;Blocks written
NNODES:	BLOCK	1		;[4] Nodes written to file
X.AREA:	BLOCK	1		;[4] Our "home" area
OFFSET:	BLOCK	1		;[5] CCL entry flag
PSCANA:	BLOCK	1		;[6] PSCAN argument memory
PSCANP:	BLOCK	1		;[6] PSCAN PDL memory
REPARS:	BLOCK	1		;[6] PSCAN restart memory
U.PERM:	BLOCK 1
U.VOLAT:	BLOCK 1
;U.AREA:	BLOCK ^D<<64+35>/36>

	END	GETNOD