Google
 

Trailing-Edge - PDP-10 Archives - tops10and20_integ_tools_v9_3-aug-86 - tools/phone20/phone.mac
There are 3 other files named phone.mac in the archive. Click here to see a list.
;MSC:<BUDNE.FONE>PHONE.MAC.1733 16-Aug-85 NM+1D.1H.50M.32S., by BUDNE
; Released to "integration tools clearinghouse"
;MSC:<BUDNE.FONE>PHONE.MAC.1719 26-Jun-85 FQ+1D.19H.38M.48S., by BUDNE
; Add more status info, and OUTSTR LUUO
;MSC:<BUDNE.FONE>PHONE.MAC.1706 26-Jun-85 FQ+1D.18H.37M.30S., by BUDNE
; Add code at .ERROR to check for lossage from DNCONN
;MSC:<BUDNE.FONE>PHONE.MAC.1700 26-Dec-84 NM+4D.10H.49M.6S., by BUDNE
; Remove PTYnnn stuff
;MSC:<BUDNE.FONE>PHONE.MAC.1698  1-Dec-84 FQ+1D.14H.19M.18S., by BUDNE
; Make sure zero ring flag gets sent in MAKMSG
;MSC:<BUDNE.FONE>PHONE.MAC.1680 24-Jul-84 LQ+4D.11H.17M.1S., by BUDNE
; USE DNCONN FROM TGRADY'S MS11 STUFF, IT RETURNS THE ROUTE, FLUSH PHCONN

;  *** WISH LIST ***
;TRY CONNECT W/O DNCONN FIRST; PUT LOCAL NODE FDB FIRST??? (NAH)
;SAVE/RESET PROGRAM NAME FOR PUSH/MAIL COMMANDS
;--
;HAVE STATUS SHOW TEMP LINK (IE; FROM A FOREIGN RINGER)
;MAKE EXIT DEMAND HANGUP, ADD QUIT COMMAND?
;CREATE ASSEMBLY FEATURE TESTS FOR NO NETWORK, OR JUST NO DNCONN??
;HANDLE ^L (REFRESH) @LKCTRL
;HAVE UNHOLD COMPLAIN IF NO USERS FOUND ON HOLD
;USER SELECTABLE SWITCH HOOK; QUOTE CHAR?
;READ MONNAM.TXT FOR LOCAL HOST NAME
;KEEP RING BUFFER OF LINES FOR EACH LINK/WINDOW??
;DON'T MOVE CURSOR UNTIL WE TYPE SOMETHING... (KEEP TRACK OF CURSOR!!)
;
;  *** BUGS ***
;AT XTEXT QUEUE PACKETS IF NOT CURRENTLY IN TALK CONTEXT
;DISABLE PAUSE ON END-OF-PAGE (AT LEAST WHILE TALKING (SAME TIME AS ECHO)
;LOCAL RING BLASTS EVERYONE, EVEN PERSON W/ PID!!
;3-WAY PRINTS TRASH, WRONG POS FOR CURSOR???
;SOMEONE DIALING A BUSY PERSON DOES NOT GET A BLOWOFF??? (RI.2???)
;WRAP IN ECHO IS CRUDE -- DO WORD WRAP?
;<LF> CODE IN ECHO IS CRUDE -- USE CURSOR ADDRESSING AND CEOL
;ALL OF ECHO IS CRUDE -- REWRITE
;REWRITE LOOK?
;
;WHAT HAPPENS TO TEXT WHEN YOU ARE AT "COMMAND" LEVEL? (TOSSED?)
;
	TITLE	PHONE -- Video Telephone Conversation Program
	SUBTTL	Robert A. Brown/Philip L. Budne

	SEARCH	MONSYM,MACSYM,CMD,DNCUNV,JOBDAT
	.REQUIRE SYS:CMD
	.REQUIRE DNCONN		;GET DNCONN FROM MS11
	.REQUEST SYS:MACREL
	.REQUIRE HLPR20
	.DIRECTIVE FLBLST
	SALL

ASCIZ "
Copyright (c) 1984, 1985 by Philip L. Budne and Digital Equipment Corp.
"
; This program may be copied for non profit use, with the inclusion of
; the above Copyright.  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 anyone.
;
; Neither Digital nor the Author assume responsibility for the use or
; reliability of this software anywhere.

;
; This program, along with PHNSRV  is a TOPS-20 implementation of  the
; PHONE protocol as  documented and implemented  by the VAX/VMS  PHONE
; program.
;
; I would like to thank  Robert Brown of CSSE  for the head start  his
; version  gave  me,  and  appologize  for  the  number  of   needless
; changes I have made.
;
; -Phil Budne
; DEC/LCG - SWE
;
	SUBTTL	TABLE OF CONTENTS

;
;			   Section			      Page
;   1. TABLE OF CONTENTS. . . . . . . . . . . . . . . . . . .    2
;   2. DEFINITIONS. . . . . . . . . . . . . . . . . . . . . .    3
;   3. PROTOCOL
;        3.1.   MESSAGE CODES . . . . . . . . . . . . . . . .    4
;        3.2.   STATUS CODES. . . . . . . . . . . . . . . . .    4
;   4. IMPURE STORAGE . . . . . . . . . . . . . . . . . . . .    6
;   5. CONSTANTS. . . . . . . . . . . . . . . . . . . . . . .    7
;   6. MAIN CODE. . . . . . . . . . . . . . . . . . . . . . .    9
;   7. COMMANDS
;        7.1.   EXIT. . . . . . . . . . . . . . . . . . . . .   10
;        7.2.   HANGUP. . . . . . . . . . . . . . . . . . . .   11
;        7.3.   ANSWER. . . . . . . . . . . . . . . . . . . .   12
;        7.4.   REJECT. . . . . . . . . . . . . . . . . . . .   13
;        7.5.   DIAL. . . . . . . . . . . . . . . . . . . . .   14
;        7.6.   PUSH AND MAIL . . . . . . . . . . . . . . . .   15
;        7.7.   DIRECTORY . . . . . . . . . . . . . . . . . .   16
;        7.8.   HOLD. . . . . . . . . . . . . . . . . . . . .   17
;        7.9.   UNHOLD. . . . . . . . . . . . . . . . . . . .   18
;        7.10.  BLANK AND REDRAW TEMPLATE . . . . . . . . . .   19
;        7.11.  STATUS. . . . . . . . . . . . . . . . . . . .   21
;   8. IPCF
;        8.1.   INITIALIZATION. . . . . . . . . . . . . . . .   22
;        8.2.   RECIEVE A PAGE FROM LOCAL OR SLAVE. . . . . .   23
;        8.3.   SEND A PAGE TO A LOCAL USER . . . . . . . . .   23
;        8.4.   RECEIVE A SHORT MESSAGE, BLOCKING (FROM INFO)   23
;        8.5.   SEND A SHORT MESSAGE. . . . . . . . . . . . .   23
;        8.6.   CHECK A PID . . . . . . . . . . . . . . . . .   23
;        8.7.   CREATE A PID. . . . . . . . . . . . . . . . .   23
;        8.8.   FIND PHONE PID (IF ANY) ASSOCIATED WITH A USER NUMBER   24
;        8.9.   FIND PID ASSOCIATED WITH A NAME . . . . . . .   24
;        8.10.  ASSIGN NAME TO OURPID . . . . . . . . . . . .   24
;        8.11.  Send message to <SYSTEM>INFO. . . . . . . . .   24
;   9. Initialization stuff . . . . . . . . . . . . . . . . .   25
;  10. PSI
;       10.1.   TURN PI OFF . . . . . . . . . . . . . . . . .   26
;       10.2.   TURN PI ON. . . . . . . . . . . . . . . . . .   26
;       10.3.   KILL IPCF INTERUPTS . . . . . . . . . . . . .   26
;       10.4.   ACTIVATE IPCF INTERUPTS . . . . . . . . . . .   26
;  11. INTERUPT LEVEL
;       11.1.   IPCF DISPATCH . . . . . . . . . . . . . . . .   27
;       11.2.   RING. . . . . . . . . . . . . . . . . . . . .   28
;       11.3.   HANGUP. . . . . . . . . . . . . . . . . . . .   29
;       11.4.   BUSY SIGNAL . . . . . . . . . . . . . . . . .   30
;       11.5.   ANSWERED. . . . . . . . . . . . . . . . . . .   31
;       11.6.   FORCED LINK . . . . . . . . . . . . . . . . .   32
;       11.7.   REJECT. . . . . . . . . . . . . . . . . . . .   33
;       11.8.   PUT ON HOLD . . . . . . . . . . . . . . . . .   34
;       11.9.   TAKEN OFF HOLD. . . . . . . . . . . . . . . .   35
;       11.10.  CONVERSATION TEXT . . . . . . . . . . . . . .   36
;  12. TTY
;       12.1.   SAVE CCOC WORD. . . . . . . . . . . . . . . .   39
;       12.2.   BLAST CCOC WORD . . . . . . . . . . . . . . .   39
;       12.3.   RESTORE CCOC WORD . . . . . . . . . . . . . .   39
;       12.4.   KILL ECHO . . . . . . . . . . . . . . . . . .   39
;       12.5.   RESTORE ECHO. . . . . . . . . . . . . . . . .   39
;       12.6.   SKIP IF INPUT BUFFER EMPTY. . . . . . . . . .   39
;  13. TEXT CONVERSATION INPUT. . . . . . . . . . . . . . . .   40
;  14. LOOK
;       14.1.   Get character . . . . . . . . . . . . . . . .   40
;       14.2.   Send off OURBUF to all of our windows user's.   40
;       14.3.   User typed something. . . . . . . . . . . . .   40
;       14.4.   Deposit a character to be sent. . . . . . . .   40
;       14.5.   Rubout was typed. . . . . . . . . . . . . . .   40
;       14.6.   Ignore extra rubouts. . . . . . . . . . . . .   40
;       14.7.   Some control character typed. . . . . . . . .   40
;  15. Position self. . . . . . . . . . . . . . . . . . . . .   41
;  16. PHONE ERROR MESSAGES . . . . . . . . . . . . . . . . .   41
;  17. GOTO ERROR LINE. . . . . . . . . . . . . . . . . . . .   41
;  18. GOTO PROMPT LINE . . . . . . . . . . . . . . . . . . .   41
;  19. PARSE
;       19.1.   ROUTE STRING. . . . . . . . . . . . . . . . .   42
;       19.2.   USER ID STRING. . . . . . . . . . . . . . . .   43
;  20. LINKS
;       20.1.   MAKE A CONNECTION . . . . . . . . . . . . . .   44
;       20.2.   MAKE A MESSAGE. . . . . . . . . . . . . . . .   45
;       20.3.   SEND A MESSAGE. . . . . . . . . . . . . . . .   45
;       20.4.   SEND HANGUP AND CLOSE . . . . . . . . . . . .   46
;       20.5.   SEND ANY MESSAGE AND CLOSE. . . . . . . . . .   46
;       20.6.   CREATE NEW LINK BLOCK . . . . . . . . . . . .   47
;       20.7.   CREATE A NEW LINK AND CONNECT IT. . . . . . .   47
;       20.8.   SAVE A LINK IN LINK TABLE . . . . . . . . . .   47
;       20.9.   SEARCH FOR A USER . . . . . . . . . . . . . .   47
;  21. DECNET
;       21.1.   COUNT AND SEND MESSAGE. . . . . . . . . . . .   48
;       21.2.   SEND COUNTED MESSAGE. . . . . . . . . . . . .   48
;       21.3.   GET TEXT WITH TIMEOUT . . . . . . . . . . . .   48
;       21.4.   GET MESSAGE W/O TIMEOUT . . . . . . . . . . .   48
;       21.5.   CONNECT TO REMOTE SLAVE FOR DIRECTORY . . . .   49
;       21.6.   SEND A MESSAGE. . . . . . . . . . . . . . . .   49
;  22. LOCAL
;       22.1.   SEND A MESSAGE. . . . . . . . . . . . . . . .   50
;       22.2.   CHECK FOR USER. . . . . . . . . . . . . . . .   51
;       22.3.   RING. . . . . . . . . . . . . . . . . . . . .   52
;       22.4.   SEND RING TEXT. . . . . . . . . . . . . . . .   53
;       22.5.   DIRECTORY . . . . . . . . . . . . . . . . . .   54
;  23. WINDOWS
;       23.1.   ECHO. . . . . . . . . . . . . . . . . . . . .   55
;       23.2.   FIND A USER . . . . . . . . . . . . . . . . .   56
;       23.3.   ADD A NEW USER. . . . . . . . . . . . . . . .   56
;       23.4.   REDIVIDE. . . . . . . . . . . . . . . . . . .   56
;       23.5.   REMOVE A USER . . . . . . . . . . . . . . . .   57
;       23.6.   SEND TO ALL . . . . . . . . . . . . . . . . .   57
;  24. SPECIAL. . . . . . . . . . . . . . . . . . . . . . . .   58
;  25. CORE ALLOCATOR . . . . . . . . . . . . . . . . . . . .   60
;  26. LUUO HANDLR. . . . . . . . . . . . . . . . . . . . . .   61
;  27. THE END. . . . . . . . . . . . . . . . . . . . . . . .   64
	SUBTTL	DEFINITIONS

;AC definitions
T0==0				;DON'T BLAME ME (IT USED TO BE NAMELESS!)
T1==1
T2==2
T3==3
T4==4
T5==5

.FPAC==6			;FIRST PRESERVED AC
.NPAC==4			;THIS MANY (6..11)

FL==12				;FLAGS
    F$DIAL==1B0			;  DIALING
    F$ANSW==1B1			;  ANSWERING
    F$TEXT==1B2			;  TEXT AVAILABLE TO SEND
    F$REF==1B3			;  REFRESH NEEDED
    F$FAX==1B4			;  IN FAX MODE
    F$DECN==1B5			;  DECNET IS AVAILABLE
    F$SERV==1B6			;  WE RUN THE DECNET SERVER (we may dial out)

W==13				;WINDOW PTR
I==14				;USER (LINK) PTR
;;;15				;USED BY MACREL (TRVAR ...)
.A16==16			;USED BY MACREL (ACVAR, STKVAR)
P==17				;PDL

;Feature tests
LOCALF==1			;TRUE TO ENABLE LOCAL LINKS

;Parameters
SLPTIM==^D80			;TIME FOR INPUT CHECK SLEEP (IN MS.)
PSETIM==^D850			;TIME TO PAUSE AFTER ERROR OUTPUT (IN MS.)
TXTLIN==3			;FIRST LINE OF TEXT IN WINDOW (DASHES, NAME)
OURSIZ==^D<50/5>		;OURBUF SIZE IN WORDS (TYPEIN BUFFER)
BUFSIZ==^D256			;SIZE OF BUFFERS (MAX MESSAGE SIZE IN BYTES)
MAXJOB==^D510			;MAX JOB TO LIST IN DIR...

MAXWND==5			;MAX NUMBER OF WINDOWS
MAXLNK==MAXWND*5		;MAX NUMBER OF ACTIVE LINKS

;Address Space
ENDCOR=477777			;LAST WORD FOR ALLOC

DATPAG==500			;PAGE FOR IPCF DATA RECIEVE
DATADR=DATPAG*1000		;ADDRESS FOR IPCF

SNDPAG==501			;PAGE FOR IPCF SEND
SNDADR=SNDPAG*1000		;ADDRESS

HSTPAG==520			;PAGE FOR LOCAL HOSTS
HSTADR=HSTPAG*1000
HSTTAB=HSTADR+5000

; PAGES 600+ USED BY HLPR20
DEFINE	RETSKP	<JRST	CPOPJ1>
OPDEF	PJRST	[JUMPA	13,]
OPDEF	TTY$	[1B8]		;TTY HACKING LUUO
OPDEF	OUTSTR	[2B8]		;OUTPUT LITTERAL STRING

.JBUUO==:40			;LUUO INSTR
.JB41==:41			;LUUO W/ EA CALC
.JBFF==:121			;LAST USED WORD IN CORE

;REL 6.0 SYMBOLS
IFNDEF .TT125,.TT125==:^D35	;VT125
IFNDEF .TT102,.TT102==:^D37	;VT102
IFNDEF .TTH19,.TTH19==:^D38	;H19 (ANSI)
IFNDEF .TT131,.TT131==:^D39	;VT131
IFNDEF .MORTF,.MORTF==:54	;READ TERMINAL FLAGS
IFNDEF MO%NUM,MO%NUM==:1B34	;  REFUSE USER-MESSAGES
IFNDEF MO%NTM,MO%NTM==:1B35	;  INHIBIT NON-JOB OUTPUT
	SUBTTL	PROTOCOL --  MESSAGE CODES

; CODES LOWER THAN 7. ARE VAX LOCAL QUEUEING CODES, NEVER SENT OVER THE NET.

MS$CHK==:^D7			;CHECK USER
MS$RNG==:^D8			;RING PHONE
MS$HUP==:^D9			;HANGUP
MS$BSY==:^D10			;TARGET IS BUSY
MS$ANS==:^D11			;TARGET HAS ANSWERED
MS$REJ==:^D12			;REJECT CALL
MS$DON==:^D13			;DONE WITH SLAVE
MS$TXT==:^D14			;CONVERSATION TEXT
MS$DIR==:^D15			;NEXT DIRECTORY LINE
				;16. IS A VAX INTERNAL CODE
MS$3RD==:^D17			;HANDLE FORCED LINK TO THIRD PARTY
MS$HLD==:^D18			;PUT ON HOLD
MS$OFF==:^D19			;TAKEN OFF HOLD

	SUBTTL	PROTOCOL -- STATUS CODES
ST$OTH==:^D0			;OTHER..
ST$AOK==:^D1			;OK
ST$IUS==:^D2			;INVALID USER SYNTAX
ST$FAI==:^D3			;SLAVE FAILED
ST$UID==:^D4			;UID MISSING
ST$SNP==:^D5			;SLAVE DOES NOT HAVE PRIVS
ST$UNE==:^D6			;USER DOES NOT EXIST
ST$TTY==:^D7			;PHONE CANNOT USE TTY (TTY CANNOT USE PHONE?)
ST$LOG==:^D8			;USER HAS LOGGED OFF
ST$OFF==:^D9			;"OFF THE HOOK" /NOBROAD, REFUSE LYNX, TTY GAG

;Control chars
BS==:"H"-100
TAB==:"I"-100
BEL==:"G"-100
CR==:"M"-100
LF==:"J"-100
FF==:"L"-100
DEL==:177
;Macros

;Opcodes for TTY$ LUUO
TT$MOV==:0			;ABS MOVE
TT$JMP==:1			;HOME
TT$JME==:2			;HOME AND ERASE
TT$ERL==:3			;ERASE TO EOL
TT$ERB==:4			;ERASE TO EOS
TT$SCR==:5			;SET SCROLL REGION
TT$NRM==:6			;NORMAL VIDEO
TT$REV==:7			;REVERSE VIDEO
TT$BRI==:10			;BRIGHT VIDEO
TT$IND==:400			;SET FOR INDIRECT ARGS
TT$MVX==:TT$IND+TT$MOV		;INDIRECT MOVE
TT$SCX==:TT$IND+TT$SCR		;INDIRECT SCROLL

DEFINE	TTY	(A,B<0>,C<0>) <
	.%.==10			;;SAVE RADIX
	RADIX	10		;;DECIMAL
	TTY$	[<BYTE (9)TT$'A,B,C>&-1]
	RADIX	.%.		;;RESTORE RADIX
	PURGE	.%.
> ;TTY

DEFINE	TMSG	(STR) <
	OUTSTR	[ASCIZ ~STR~]
> ;TMSG

DEFINE	FATAL	(STR) <
	JRST [	HRROI	T1,[ASCIZ ~STR~]
		JRST	.FATAL ]
> ;FATAL

DEFINE	ERROR	(STR) <
	JRST [	HRROI	T1,[ASCIZ ~?STR~]
		JRST	.ERROR ]
> ;ERROR

; NEW COMMAND MACROS

DEFINE	CONFRM	< JSR .CONF > ;CONFRM

DEFINE	NOISE	(STR) <
	HRROI	T1,[ASCIZ \STR\]
	JSR	.NOISE
> ;NOISE
	
DEFINE	T	(STR,DATA,FLGS<0>) <
 IFE FLGS,<
  IFB <DATA>,< [ASCIZ |STR|],,<.'STR> ;> [ASCIZ |STR|],,DATA
 > ;IFE FLGS
 IFN FLGS,<
  IFB <DATA>,<  [CM%FW!FLGS
		ASCIZ |STR|],,<.'STR> >
  IFNB <DATA>,< [CM%FW!FLGS
		ASCIZ |STR|],,DATA >
 > ;IFN FLGS
> ;T
	SUBTTL	IMPURE STORAGE

	CMDSTG			;CMD STORAGE

;CONNECT BLOCK FOR DNCONN
CONBLK:	DN%SPL			;Flags (WAIT LONGER)
	0			;Host string pointer
	^D29			;Remote object type
	0			;Local obj
	^D8			;Byte size
	0			;Opt data (Route file on .DNINI call)
	0			;Password
	0			;Account
	0			;User-id
	.NULIO			;Desc for ret op data
	0			;Length for above
	.NULIO			;Desc for errors
	.NULIO			;Desc for warnings
	.NULIO			;Desc for information

.CONF:	0			;JSR TO HERE
	MOVEI	T1,[FLDDB. .CMCFM]
	CALL	RFLDE
	 PJRST	ERRPNT
	JRST	@.CONF

.NOISE:	0			;JSR HERE
	MOVEM	T1,NOIFDB+.CMDAT
	MOVEI	T1,NOIFDB
	CALL	RFLDE
	 PJRST	ERRPNT
	JRST	@.NOISE
NOIFDB:	FLDDB.	.CMNOI,,0

SWHOOK:	EXP	"%"		;SWITCH HOOK CHAR
ERRPSE:	EXP	PSETIM		;AMMOUNT OF TIME TO PAUSE AFTER ERROR OUTPUT
OLDMOD:	BLOCK	1		;SAVED TTY MOD WORD
FAXJFN:	BLOCK	1		;FACSIMILE JFN
FAXFIL:	BLOCK	30		;FILE BEING FAX'ED
LSTCOD:	BLOCK	1		;LAST CODE SENT BY MAKMSG
NODBUF:	BLOCK	<NBFLEN==3>	;BUFFER FOR NODE NAME

ZERBEG:!			;START OF AREA TO ZERO ********************
LNKLST:	BLOCK	1		;LIST OF FREE LINK BLOCKS
WNDLST:	BLOCK	1		;LIST OF FREE WINDOW BLOCKS
NUMUSR:	BLOCK	1		;COUNT OF CURRENT USERS
LNKTAB:	BLOCK	MAXLNK		;TABLE OF "ACTIVE" LINKS
WNDTAB:	BLOCK	MAXWND		;TABLE OF WINDOWS (IN ORDER)
MAXHLD:	BLOCK	1		;MAXMUM HOLD LEVEL (NORMALLY -1)

LNKBLK:	PHASE	0		;**** START OF LINK BLOCK ****
LNKJFN:!BLOCK	1		;CONNECTION TO USER (SEE L$TYPE IN LNKFLG)
LNKHLD:!BLOCK	1		;HOLD LEVEL (-1 IS NORMAL, .GE. 0 IS HELD)
LNKFLG:!BLOCK	1		;FLAGS
    L$HELD==1B0			; HAS YOU ON HOLD
    L$TYPE==,,-1		;**MUST BE RIGHT HALF**
				; LINK TYPE    LNKJFN CONTAINS
	LT$DCN==0		;  DECNET	0,,JFN
	LT$LCL==1		;  LOCAL	PID
LNKSND:!BLOCK	BUFSIZ/4+1	;SEND BUFFER
LNKRCV:!BLOCK	BUFSIZ/4+1	;RECIEVE BUFFER
LNKUSR:!BLOCK	10		;USER'S FULL NAME
LNKUNO:!BLOCK	1		;LOCAL USER NUMBER
LNKJOB:!BLOCK	1		;LOCAL JOB ASSOC WITH PID IN LNKJFN
LNKRUT:!BLOCK	12		;ROUTE WE USED
LNKLEN==.-1
	DEPHASE			;**** END OF LINK BLOCK ****
;WINDOW BLOCK DEFN
WNDBLK:	PHASE	0		;**** START OF WINDOW BLOCK
WNDCOL:!BLOCK	1		;CURRENT COLUMN
WNDLIN:!BLOCK	1		;CURRENT LINE
WNDSIZ:!BLOCK	1		;WINDOW LENGTH (SIZE)
WNDORG:!BLOCK	1		;WINDOW ORIGIN
WNDLBP:!BLOCK	1		;LINE BUFFER POINTER
WNDLNK:!BLOCK	1		;CURRENT LINK
WNDLBF:!BLOCK	^D<<80+4>/5>	;LINE BUFFER
WNDLEN==.-1
	DEPHASE			;**** END OF WINDOW BLOCK ****

SCRSIZ:	BLOCK	1		;TERMINAL SCREEN SIZE
OURBUF:	BLOCK	OURSIZ		;OUR TEXT (INPUT BUFFER)
OURCNT:	BLOCK	1		;COUNT OF CHARS IN OURBUF
OURPNT:	BLOCK	1		;BP INTO OURBUF
A0:	BLOCK	1		;BP FOR INTERUPT TEXT

BSYLNK:	BLOCK	1		;LINK WE ARE RINGING/ANSWERING
US:	BLOCK	10		;OUR FULL USER ID STRING
RINGFL:	BLOCK	1		;VALUE OF LAST RING FLAG RCVD
EXCFRK:	BLOCK	1		;FORK HANDLE FOR EXEC
MSFRK:	BLOCK	1		;FORK HANDLE FOR MAILER (MS)
LSTERR:	BLOCK	1		;BP TO LAST ERROR
ZEREND==.-1			;********** END OF ZEROS

JOBNUM:	BLOCK	1		;LAST JOB LISTED IN DIR
GJIBLK:	BLOCK	.JIMAX+1	;BLOCK FOR GETJI
TMPSTR:	BLOCK	20		;BLOCK FOR LOCAL DIR
TEMP2:	BLOCK	20		;BLOCK FOR DIRST...
ERRSTR:	BLOCK	10		;BLOCK FOR LAST ERROR
;;;PTYPAR:	BLOCK	1		;GETAB
OPRUNO:	BLOCK	1		;WHO TO IGNORE

PIDNAM:	BLOCK	5		;BLOCK FOR PID NAME
ISNDBK:	BLOCK	10		;IPCF SEND BUFFER
IRCVBK:	BLOCK	10		;IPCF RCV BUFFER
OURPID:	BLOCK	1		;PROCESS PID
IPSND:	BLOCK	4		;MSEND BLOCK
IPRCV:	BLOCK	4		;MRECV BLOCK
L2SAVE:	BLOCK	17		;INTERUPT AC SAVE
SAVPOS:	BLOCK	1		;SAVED CURSOR POSN DURING IPCF
SAVCOC:	BLOCK	2		;SAVED CCOC FROM DURING IPCF

UUOACS:	BLOCK	17		;SAVED ACS FOR TTYSTF
VT10OT:	BYTE (7) 33,"[",0,0,0	;VT100 MOVE CURSOR
	BYTE (7) ";",0,0,0,"H",0
VT10ST:	BYTE (7) 33,"[",0,0,0	;VT100 SCROLL
	BYTE (7) ";",0,0,0,"r"
CMNOD:	FLDDB.	.CMKEY,CM%SDH,0,<Host name>,<DEF>,CMNOD2 ;FOR PARSING NODE
CMNOD2:	FLDDB.	.CMKEY,CM%SDH,HSTTAB,,,CMNOD3
CMNOD3:	FLDBK.	.CMFLD,CM%SDH,,,,NODBRK

	BRINI. (-1,-1,-1,-1)	;INITIALIZE BREAK MASK
	UNBRK. ("0","9")	;ALLOW DIGITS
	UNBRK. ("A","Z")	;ALLOW UPPER
	UNBRK. ("a","z")	;ALLOW LOWER

NODBRK:	EXP	W0.,W1.,W2.,W3.


OURJOB:	BLOCK	1		;OUR JOB NUMBER
OURNOD:	BLOCK	2		;OUR NODE NAME
OURNAM: BLOCK   15		;OUR USER NAME
OURPTR: BLOCK   1		;SAVED BP
JOBAOB:	BLOCK	1		;AOBJN FOR ALL JOBS
AC1:	BLOCK	1		;CRASH ACS
AC2:	BLOCK	1		;...
AC3:	BLOCK	1		;...
AC4:	BLOCK	1		;...
AREA:	BLOCK	10		;TEMP AREA

TTYTYP:	BLOCK	1		;GTTYP TERMINAL TYPE
TTYCOC:	BLOCK	2		;ORIGINAL TTY CCOC WORDS
PLIST:	BLOCK	<LPLIST==200>	;PDL sweet PDL
P1FLG:	BLOCK	1		;PSI LEVEL 1 PC
P2FLG:	BLOCK	1		;PSI LEVEL 2 PC
P3FLG:	BLOCK	1		;PSI LEVEL 3 PC
	SUBTTL	CONSTANTS

USRBRK:	EXP	USRB0.,USRB1.,USRB2.,USRB3. ;USER NAME BREAK SET

LEVTAB:	EXP	P1FLG,P2FLG,P3FLG ;PSI LEVEL TABLE

CHNTAB:	PHASE	0		;PSI CHANNEL TABLE
IPCCHN:!2,,IPCINT		;IPCF INTERRUPT
	DEPHASE			;END OF STRANGENESS

;Dispatch table for functions
DEFINE	ACTION (CODE,ADDR) <
	BLOCK	CODE-.
	EXP	ADDR
> ;ACTION

DSPTAB:	PHASE	0
	ACTION	MS$RNG,XRUNG	;BEING RUNG
	ACTION	MS$HUP,XHUNG	;SOMEONE HUNG UP
	ACTION	MS$BSY,XBUSY	;TARGET BUSY
	ACTION	MS$ANS,XANSWR	;TARGET ANSWERED
	ACTION	MS$REJ,XREJ	;TARGET REJECTED
	ACTION	MS$TXT,XTEXT	;TEXT FROM REMOTE
	ACTION	MS$3RD,XFORCE	;3RD PARTY JUST JOINED
	ACTION	MS$HLD,XHOLD	;PUT ON HOLD
	ACTION	MS$OFF,XUNHLD	;TAKEN OFF HOLD
DSPMAX==.
	DEPHASE
; Main command dispatch table

COMTAB:	XWD	COML,COML	;Lengths
	T	ANSWER		;ANSWER (last call)
        T	BLANK		;BLANK (screen)
	T	DIAL		;DIAL (user)
	T	DIRECTORY	;DIRECTORY (of users on)
	T	EXIT		;EXIT (to superior)
	T	F,$FACS,CM%INV!CM%ABR
	T	FA,$FACS,CM%INV!CM%ABR
$FACS:	T	FACSIMILE	;FACSIMILE (of file)
	T	FAXSIMILE,$FACS,CM%INV!CM%ABR
	T	HANGUP		;HANGUP (the phone)
	T	HELP		;HELP
	T	HOLD		;HOLD (current call)
	T	LAST		;LAST (error message)
	T	MAIL		;MAIL (using MS)
	T	PUSH		;PUSH (command level)
	T	REJECT		;REJECT (current call)
	T	STATUS		;STATUS (of PHONE)
	T	UNHOLD		;UNHOLD (previous call)
COML==.-COMTAB-1
	SUBTTL	MAIN CODE

EVEC:	JRST	START
	JRST	START
	-1,,377777

START:	RESET			;STOP THE WORLD!
	MOVE	P,[-LPLIST,,PLIST-1] ;GET THEE A PIDDLE
	HLRZ	T1,.JBSA	;GET INITIAL END
	MOVEM	T1,.JBFF	;STORE
	MOVE	T1,[CALL LUUOH]	;LUUO WORD
	MOVEM	T1,.JB41	;STORE
	MOVEI	I,LNKBLK	;POINT TO NORMAL LINK BLOCK
	CALL	INIT		;INITIALIZATION STUFF
	CALL	TPLATE		;PUT UP TEMPLATE
	CALL	PION		;ENABLE PI
	CALL	CMDINI		;INITIALIZE CMD (SET UP SBK)
	MOVSI	T1,(CM%XIF)	;ACCEPT "@"
	IORM	T1,SBK+.CMFLG	;SET IN STATE BLOCK

;Main command loop
MCOM:	CALL	PARSER		;PARSE AND EXECUTE A COMMAND
	SKIPE	NUMUSR		;HAVE A CONVERSATION?
	 CALL	TEXT		; YES, GO DO TEXT
	JRST	MCOM		;"MAY I PLEASE HAVE ANOTHER, SIR!"

;Parse one command
PARSER:	SETZ	W,		;NO CURRENT WINDOW
	CALL	PMTLIN		;ASSUME THE POSITION
	TTY	<ERB>		;ERASE TO EOS <
	PROMPT	(PHONE>)	;PROMPT
	CALL	IPON		;ENSURE PSI TURNED ON
	MOVEI	T1,[FLDDB. .CMKEY,,COMTAB,,,[ ;PARSE KEYWORD
		    FLDDB. .CMCFM]] ;OR SWALLOW CRLF
	CALL	RFLDE		;PARSE, RETURN ERRORS
	 JRST [	CALL	IPOFF	; PROTECT AGAINST IPCF
		PJRST	ERRPNT ] ; GO SCREAM ABOUT ERROR
	TSZ	T3,T3		;KEYWORD?
	JUMPN	T3,CPOPJ	; NO, MUSTA BEEN CONFIRM
	HRRZ	T1,(T2)		;GET RESULTS
	CALL	(T1)		;CALL ACTION ROUTINE
	 TRN			;...
	RET
	SUBTTL	COMMANDS -- EXIT

.EXIT:	NOISE	(to superior)	;EXIT command
	CONFRM			;BE SURE!!!
	TTY	<SCR,1,24>	;RESET SCROLL REGION
	TTY	<JME>		;CLEAR SCREEN
	MOVX	T1,CZ%ABT	;ABORT
	ADDI	T1,.FHSLF	;ALL OUR FILES
	CLZFF
	 ERJMP	.+1
	CALL	RESTTY		;RESTORE TTY SETTINGS
	RESET			;BLAM I/O AND PIDS
	HALTF
	JRST	START		;RESTART
	SUBTTL	COMMANDS -- FACSIMILE

.FACSIMILE:
	NOISE	(of file)
	MOVEI	T1,[FLDDB. .CMIFI]
	CALL	RFLDE
	 PJRST	ERRPNT
	MOVEM	T2,FAXJFN	;SAVE JFN
	CONFRM

	SKIPN	NUMUSR		;ANY TALKERS?
	 JRST [	CALL	RELFAX
		ERROR	(No current call)] ;SORRY
	MOVE	T1,FAXJFN
	MOVE	T2,[FLD(7,OF%BSZ)!OF%RD]
	OPENF
	 JRST [	CALL	RELFAX
		PJRST	ERRPNT ]
	HRROI	T1,FAXFIL	;GET BUFFER
	MOVE	T2,FAXJFN
	SETZ	T3,
	JFNS
	IDPB	T3,T1

	TLO	FL,(F$FAX)	;SET THE FLAG!!
	RET

RELFAX:	MOVE	T2,FAXJFN
	RLJFN
	 TRN
	RET
	SUBTTL	COMMANDS -- HANGUP

.HANGUP:
	ACVAR	<X1,X2>		;LOOP VARS
	NOISE	(on current call)
	CONFRM

	MOVN	X1,NUMUSR	;LOOP FOR ALL WINDOWS
	MOVSI	X1,(X1)		;-N,,0
	CAIN	X1,0		;ZERO?
	 ERROR	(No current call) ;SORRY
	PUSH	P,I		;SAVE LINK
HG.LOP:	MOVE	T1,WNDTAB(X1)	;GET WINDOW
	MOVE	I,WNDLNK(T1)	;GET LINK
	CALL	FREWND		;FREE UP WINDOW
	CALL	CLSHUP		;HANG UP

	MOVSI	X2,-MAXLNK	;FOR ALL LINKS
HG.LP2:	CAME	I,LNKTAB(X2)	;RIGHT LINK?
	 AOBJN	X2,HG.LP2	; NO, LOOP
	CAIGE	X2,0		;FOUND?
	 SETZM	LNKTAB(X2)	; YES, ZAP
	AOBJN	X1,HG.LOP	;LOOP
	SETZM	NUMUSR		;NO MORE USERS
	PJRST	POPIJ
	ENDAV.


	SUBTTL	COMMANDS -- HELP

.HELP:	HRROI	T1,[ASCIZ 'SYS:PHONE.HLP']
	CALL	HLPFIL##
	 PJRST	ERRPNT
	PJRST	TPLATE
	SUBTTL	COMMANDS -- ANSWER

.ANSWER:
	NOISE	(last call)
	CONFRM
	SKIPE	T1,BSYLNK	;GOT A LINK?
	 TLZN	FL,(F$ANSW)	; AND IN ANSWER MODE
	  ERROR	(No one is calling) ;NO
	SETZM	BSYLNK		;CLEAR BUSY LINK
	PUSH	P,I		;SAVE CURRENT LINK
	MOVE	I,T1		;SWITCH TO CALLER
	MOVEI	T1,MS$ANS	;ANSWER MESG
	SETZ	T2,		;NO DATA
	CALL	SNDMSG		;SEND MESS
	 JRST [	CALL SNDERR	; LOSE LOSE
		PJRST POPIJ ]	; RETURN
	MOVE	T1,I		;GET LINK
	CALL	NEWUSR		;ASSIGN THEM A VIEWPORT
	 TRN			; SIGH
	PJRST	POPIJ		;RETURN
	SUBTTL	COMMANDS -- REJECT

.REJECT:
	NOISE	(last call)	;REJECT COMMAND
	CONFRM			;ARE YOU SURE?
	SKIPE	T1,BSYLNK	;GOT A LINK?
	 TLZN	FL,(F$ANSW)	; AND IN ANSWER MODE
	  ERROR	(No one is calling) ;NO
	SETZM	BSYLNK		;CLEAR BUSY LINK
	PUSH	P,I		;SAVE CURRENT LINK
	MOVE	I,T1		;SWITCH TO CALLER
	MOVEI	T1,MS$REJ	;REJECT MESG
	SETZ	T2,		;NO DATA
	CALL	CLSMSG		;SEND MESS & CLOSE
	PJRST	POPIJ		;RETURN
	SUBTTL	COMMANDS -- DIAL

DIAFDB:	FLDDB.	.CMUSR,,,,,DIAFD2
DIAFD2:	FLDBK.	.CMFLD,CM%SDH,,,,USRBRK,DIAAT
DIAAT:	FLDDB.	.CMTOK,CM%SDH,<-1,,[ASCIZ /@/]>,<@<Host name>>,<@>

.DIAL:	STKVAR	<<USRNAM,20>>	;DIAL COMMAND
	NOISE	(user)
	HRROI	T1,OURNOD	;DEFAULT NODE
	MOVEM	T1,CONBLK+DN.HST ;DIAL NODE
	TLNN	FL,(F$SERV)	;NETWORK+SERVER?
	 IFSKP.
		MOVEI	T1,DIAFDB	;GET FDB
		SETZM	ATMBUF		;CLEAR ATOM BUFFER
		CALL	RFLDE		;TRY.. BUT RETURN ON ERROR
		 PJRST	ERRPNT
		HRRZ	T3,T3		;GET WINNING FDB
		CAIN	T3,DIAFD2	;FIELD?
		 JRST	.DIAL1		; YES
		CAIN	T3,DIAAT	;@?
		 JRST	.DIALN		; YES, GET NODE
	 ELSE.
		MOVEI	T1,[FLDDB. .CMUSR]
		CALL	RFLDE
		 PJRST	ERRPNT
	 ENDIF.	
	HRROI	T1,USRNAM	;GOT USER NUMBER
	DIRST			;CONVERT TO STRING
	 FATAL	(DIRST LOSSAGE)
	SETZ	T2,
	IDPB	T2,T1		;TERMINATE
	TLNE	FL,(F$SERV)	;NETWORK+SERVER?
	 JRST	.DIAL2		; YES, NOW PARSE HOST
	CONFRM
	JRST	.DIAL3

.DIAL1:	MOVE	T1,SBK+.CMABP	;FROM ATOM BUF
	HRROI	T2,USRNAM	;TO USER BUF
	CALL	CPYST0		;COPY
.DIAL2:	MOVEI	T1,[FLDDB. .CMTOK,CM%SDH,<-1,,[ASCIZ /@/]>,<@<Host name>>,<@>,[
		    FLDDB. .CMCFM] ]
	CALL	RFLDE		;PARSE
	 PJRST	ERRPNT
	TSZ	T3,T3		;"@"?
	JUMPN	T3,.DIAL3	;NOPE, WAS CONFIRM
.DIALN:	MOVEI	T1,CMNOD	;NOW PARSE NODE NAME
	CALL	RFLDE		;DO IT
	 PJRST	ERRPNT
	CALL	NODEBP		;GET BP TO NODE...
	MOVEM	T2,CONBLK+DN.HST ;SAVE NODE BP
	CONFRM			;GET CONFIRMATION
.DIAL3:	CALL	IPOFF		;AVOID PSI
	MOVE	T1,CONBLK+DN.HST ;GET NODE
	HRROI	T2,AREA		;TEMP AREA
	CALL	CPYSTR		;COPY NODE
	MOVEI	T1,":"		;GET A COLON
	IDPB	T1,T2		;TO TERMINATE
	IDPB	T1,T2		;NODE NAME
	HRROI	T1,USRNAM	;GET TARGET USER
	CALL	CPYST0		;COPY IN

	CALL	ERRLIN		;GOTO ERROR/STATUS LINE
	TTY	<ERL>		;CLEAR IT
	HRROI	T1,AREA		;GET NAME
	CALL	MAKLNK		;CREATE LINK
	 JRST [	TRNE	T1,-1	; GOT TEXT?
		 PSOUT		;  TELL 'EM
		PJRST	.ERROR]	; SIGH
	MOVEM	T1,BSYLNK	;SAVE DIALING LINK
	MOVE	I,T1		;SET LINK

	MOVSI	T1,(<BYTE(7)1>)	;FIRST RING FLAG
	MOVEM	T1,AREA		;STORE
	TLO	FL,(F$DIAL)	;DIALING OUT

;User exists, now ring them
.DIAL4:	TLNN	FL,(F$DIAL)	;STILL DIALING?
	 RET			;MUST HAVE BEEN ANSWERED/REJECTED
	CALL	ERRLIN		;GOTO ERROR/STATUS LINE
	TMSG	<Ringing user >	;SAY WHAT WE ARE DOING
	OUTSTR	LNKUSR(I)	;USER STRING
	TMSG	< (type any key to cancel)>
	CALL	ENDERR		;CLEAR AND WAIT

	CALL	IPON		;OPEN THE WINDOW
	MOVEI	T1,MS$RNG	;RING CODE
	HRROI	T2,AREA		;DATA
	CALL	SNDMSG		;SEND MESS
	 JRST [	TLZ FL,(F$DIAL)	; ERROR, CLEAR DIAL MODE
		PJRST SNDERR ]	; SHUT DOWN
	TMSG	<>		;BRRRING...
	MOVEI	T4,^D10		;10 SECONDS
.DIAL5:	TLNN	FL,(F$DIAL)	;GET AN ANSWER?
	 RET			; PERHAPS!!
	CALL	$SIBE		;ANYTHING TYPED?
	 JRST	.DIAL6		; YES, ABORT
	TLNN	FL,(F$DIAL)	;WAS A RING PENDING?
	 RET			; YES, DON'T EVEN SLEEP
	MOVEI	T1,^D1000	;NO, WAIT A SECOND AND CHECK AGAIN
	CALL	$HIBER		;SLEEP
	SOJG	T4,.DIAL5	;LOOP 10 TIMES
	SETZM	AREA		;CLEAR RING FLAG
	JRST	.DIAL4		;RING AGAIN

.DIAL6:	TLZ	FL,(F$DIAL)	;ABORTED, CLEAR DIAL MODE
	MOVEI	T1,.PRIIN	;OUR TTY
	CFIBF			;CLEAR INPUT BUFFER
	PJRST	CLSHUP		;HANG UP
	ENDSV.
	SUBTTL	COMMANDS -- PUSH AND MAIL

.PUSH:	NOISE	(command level)
	CONFRM
	SKIPE	NUMUSR		;Talking?
	 ERROR	(Must hold current call first)
	MOVEI   T4,EXCFRK	;Indicate an EXEC is wanted
	SKIPE	T1,EXCFRK	;Do we already have a fork handle?
	 JRST	STFORK		;Go start it
	MOVSI	T1,(GJ%OLD!GJ%SHT)
	HRROI	T2,[ASCIZ 'DEFAULT-EXEC:']
	GTJFN
	 IFJER.
		MOVSI	T1,(GJ%OLD!GJ%SHT)
		HRROI	T2,[ASCIZ "SYSTEM:EXEC.EXE"]
		GTJFN
		 ERJMP	ERRPNT
	 ENDIF.
	JRST	GTFORK		;Go start it

.MAIL:	NOISE	(using DEFAULT-MAILER:)	;I use BABYL.
	CONFRM			;Are you sure??
	SKIPE	NUMUSR		;Talking?
	 ERROR	(Must hold current call first)
	MOVEI	T4,MSFRK	;Say we want a mailer
	SKIPE	T1,MSFRK	;Do we have an old one?
	 JRST	STFORK		; Yes, just start it
	MOVSI	T1,(GJ%SHT!GJ%OLD) ;Get JFN on file
	HRROI	T2,[ASCIZ "DEFAULT-MAILER:"]
	GTJFN
	 IFJER.
		MOVSI	T1,(GJ%OLD!GJ%SHT)
		HRROI	T2,[ASCIZ "SYS:MS.EXE"]
		GTJFN
		 ERJMP	ERRPNT
	 ENDIF.
GTFORK:	STKVAR	<JFN>
	MOVEM	T1,JFN
	MOVSI	T1,(CR%CAP)	;Create fork w/ full caps
	CFORK
	 ERJMP	ERRPNT
        MOVEM   T1,(T4)		;Save fork handle in right place
	MOVSI	T1,(T1)		;Make Fork,,0
	HRR	T1,JFN		;Make Fork,,JFN
	GET			;Load the fork
	 ERJMP	ERRPNT

STFORK:	TTY	<JMP>		;HOME
	TTY	<ERB>		;CLEAR SCREEN
	MOVE	T1,(T4)		;Get handle
	RPCAP			;Get capabilities
	 ERJMP	ERRPNT		;Sigh
	TLZ	T2,(SC%LOG)	;DON'T ALLOW LOGOUT
	TLZ	T3,(SC%LOG)	;DON'T ALLOW LOGOUT
	EPCAP			;SET CAPABILITIES

	SETZ	T2,		;ENTRY 0
	SFRKV			;IN ENTRY VECTOR
	 ERJMP	STFOR2		; SIGH
	WFORK			;WAIT FOR TERMINATION
	 ERJMP	.+1		; HUH?
	CALL	SAVTTY		;SETUP TTY AGAIN
	PJRST	TPLATE		;REFRESH, AND RETURN

STFOR2:	CALL	TPLATE		;FIRST GET TEMPLATE
	PJRST	ERRPNT		;NOW TYPE LAST ERROR
	ENDSV.
	SUBTTL	COMMANDS -- DIRECTORY

.DIRECTORY:
	ACVAR	<X1>
	STKVAR	<HOSTBP>
	TLNN	FL,(F$DECN)	;GOT DECNET?
	 IFSKP.
		NOISE	(of users on) ;BE NOISY
		MOVEI	T1,CMNOD ;PARSE A NODE
		CALL	RFLDE
		 PJRST	ERRPNT	;ERROR IN PARSING
		CALL	NODEBP	;GET BP TO NODE
		MOVEM	T2,HOSTBP ;SAVE
	 ELSE.
		NOISE	(of users)
	 ENDIF.
	CONFRM
	MOVEI	I,LNKBLK	;GET STATIC LINK BLOCK
	CALL	IPOFF
	MOVEI	T1,LT$DCN
	HRRM	T1,LNKFLG(I)

IFN LOCALF,<
	TLNN	FL,(F$DECN)	;HAVE NETWORK?
	 JRST	LCLDIR		; NOPE
	HRROI	T1,OURNOD	;LOCAL
	MOVE	T2,HOSTBP	;TARGET
	CALL	CMPSTR
	 JRST	REMDIR		; NO MATCH
LCLDIR:	MOVEI	T1,LT$LCL	;LINK TYPE
	HRRM	T1,LNKFLG(I)	;LOCAL!!
	SETZM	JOBNUM		;STARTING LOCAL JOB
	JRST	DIR.AA
> ;LOCALF

REMDIR:	CALL	ERRLIN
	TTY	<ERL>
	MOVE	T1,HOSTBP	;GET HOST
	CALL	OPNCON		;OPEN DECNET CONNECTION
	 JRST [	TRNN	T1,-1	; GOT TEXT?
		 HRROI	T1,[ASCIZ 'Some error occured']
		PJRST	.ERROR ]
	TMSG	<Directory of >
	MOVE	T1,HOSTBP
	PSOUT
	CALL	ENDERR

DIR.AA:	CALL	PMTLIN		;PROMPT..
	TMSG	<Press any key to cancel>
	TTY	<ERB>		;ERASE TO EOS
	TTY	<MOV,5,1>
TMSG	<Process Name	User Name	Terminal	Phone Status
>
	SETZ	X1,		;CLEAR COUNTER

DIRLOP:	CALL	$SIBE		;SEE IF USER TYPED SOMETHING
	 JRST	DIRABT		;ABORT
	CALL	GETDIR		;GET NEXT LINE
	JUMPE	T3,DIRDON	;NULL TEXT? (LENGTH = 0)
	CAIE	X1,0		;ANY PRINTED YET?
	 TRNE	X1,17		;MULT OF SIXTEEN?
	  JRST	DIRTYP		; NO
	TMSG	<
--Type any character to continue--> ;YES
	PBIN			;WAIT
	CAIN	T1,CR		;CR?
	 PBIN			; SNARF LF
	TTY	<MOV,6,1>
DIRTYP:	TTY	<ERL>
	MOVE	T1,T2		;POINT TO BUFFER
	PSOUT			;TYPE IT OUT
	CALL	CRLF		;GO TO NEXT LINE
	TTY	<ERL>		;CLEAR IT
	AOJA	X1,DIRLOP	;LOOP

DIRDON:	TTY	<ERB>
	CALL	CRLF
	JUMPE	X1,[
		TMSG	<No users>
		JRST	DIRWAT ]
	MOVEI	T2,(X1)		;USER COUNT
	CALL	TDEC		;TYPE IT
	TMSG	< user>
	MOVEI	T1,"s"
	CAIE	X1,1		;MORE THAN ONE?
	 CALL	PUTC		; MAKE PLURAL

DIRWAT:	TMSG	< (--Type any character to continue--)>
	PBIN			;WAIT FOR A CHARACTER

DIRABT:	CALL	$CLRBFI		;CLEAR INPUT BUFFER
	CALL	TPLATE		;PUT UP FRESH TEMPLATE
	JRST	CLSDON		;CLOSE DOWN CONNECTION
	ENDAV.
	ENDSV.
;GET NEXT DIR LINE
GETDIR:	HRRZ	T1,LNKFLG(I)	;GET LINK TYPE
	PJRST @[NDIR		;  DECNET CONNECTION
		LDIR ](T1)	;  LOCAL CONNECTION (IPCF)

NDIR:	MOVEI	T1,MS$DIR	;ASK FOR DIRECTORY
	SETZ	T2,		;NO DATA
	CALL	MAKMSG		;CREATE MESSAGE
	CALL	DECOUT		;SEND IT OUT
	CALL	DECINW		;GET RESP. NO TIMEOUTS
	 TRN			; IGNORE STATUS
	RET
	SUBTTL	COMMANDS -- HOLD

.HOLD:	NOISE	(current call)
	CONFRM			;BE SURE...
	SKIPN	NUMUSR		;ANY USERS?
	 ERROR	(No current call)

DOHOLD:	ACVAR	<X1>		;LOOP VAR
	MOVSI	X1,-MAXLNK	;FOR ALL LINKS
HD.LOP:	SKIPN	I,LNKTAB(X1)	;GET LINK
	 JRST	HD.BOT		; NONE
	SKIPL	LNKHLD(I)	;CURRENT?
	 JRST	HD.AOS		; NO
	CALL	KILUSR		;YES, REMOVE FROM SCREEN
	MOVEI	T1,MS$HLD	;SEND HOLD MESS
	SETZ	T2,		;NO DATA
	CALL	SNDMSG		;SEND OFF
	 TRN			; IGNORE ERROR
HD.AOS:	AOS	LNKHLD(I)	;SEND DEEPER INTO HOLD
HD.BOT:	AOBJN	X1,HD.LOP	;..LOOP
	AOS	MAXHLD		;BUMP MAX HOLD LEVEL
	RET
	ENDAV.

	SUBTTL	COMMANDS -- LAST
.LAST:	NOISE	(error text)
	CONFRM
	SKIPN	T1,LSTERR
	 HRROI	T1,[ASCIZ "No errors yet!"]
	PJRST	.ERROR
	SUBTTL	COMMANDS -- UNHOLD

.UNHOLD:NOISE	(previous call)
	CONFRM

	SKIPE	NUMUSR		;ANY USERS?
	 ERROR	(Please hang up first) ;BE RUDE FOR NOW

UNHOLD:	ACVAR	<X1>		;LOOP VAR
	MOVSI	X1,-MAXLNK	;FOR ALL LINKS
UH.LOP:	SKIPN	I,LNKTAB(X1)	;GOT A LINK?
	 JRST	UH.BOT		; NOPE
	SOSL	LNKHLD(I)	;DECREMENT HOLD LEVEL
	 JRST	UH.BOT		; NOT READY YET

	MOVEI	T1,MS$OFF	;TAKE OFF HOLD
	SETZ	T2,		;NO MORE DATA
	CALL	SNDMSG		;SEND OFF
	 JRST	UH.BOT		; LOOOSER
	MOVE	T1,I		;GET LINK
	CALL	NEWUSR		;ADD TO SCREEN
	 TRN			; IT FIT LAST TIME!!

UH.BOT:	AOBJN	X1,UH.LOP	;LOOP...
	SOSGE	MAXHLD		;UP A LEVEL
	 SETOM	MAXHLD		;NOT TOO FAR!!
	CALL	IPON		;LET THE SUN SHINE
	MOVEI	T1,^D100	;PAUSE SO WE GET UNHELD!!
	CALL	$HIBER		;SLEEP
	RET
	ENDAV.
	SUBTTL	COMMANDS -- BLANK AND REDRAW TEMPLATE

.BLANK:	NOISE	(screen)
	CONFRM
TPLATE:	TTY	<JME>		;CLEAR SCREEN
	TTY	<MOV,1,28>	;HEADER LINE
	TTY	<REV>		;REVERSE VIDEO
	TMSG	<TOPS-20 Phone utility>	;TITLE
	TTY	<NRM>		;NORMAL VIDEO

	TTY	<MOV,1,67>
	MOVE	T1,SWHOOK	;SWITCH HOOK CHAR
	CALL	PUTC		;TYPE

	TTY	<MOV,1,70>
	MOVEI	T1,.PRIOU	;TO TTY
	SETO	T2,		;NOW
	MOVX	T3,OT%NTM	;JUST DATE
	ODTIM
	 ERJMP	.+1
	RET
BOXES:	ACVAR	<X1>
	PUSH	P,W		;SAVE WINDOW
	TTY	<MOV,3,1>
	TTY	<ERB>		;CLEAR TO EOS
	MOVEI	W,WNDBLK	;OUR WINDOW BLOCK
	MOVEI	T5,LNKBLK	;OUR LINK BLOCK
	CALL	DOBOX

	MOVN	X1,NUMUSR	;GET USER COUNT
	HRLZ	X1,X1		;AS -N,,0
BOXLOP:	MOVE	W,WNDTAB(X1)	;GET WINDOW
	MOVE	T5,WNDLNK(W)	;GET LINK
	CALL	DOBOX
BOXBOT:	AOBJN	X1,BOXLOP
	POP	P,W		;RESTORE WINDOW
	TLZ	FL,(F$REF)	;SAY WE ARE UP TO DATE
	RET
	ENDAV.

; W/	WINDOW
; T5/	LINK
DOBOX:	ACVAR	<X1>		;BP
	MOVE	T2,WNDORG(W)	;GET ORIGIN
	MOVEI	T3,1		;FIRST COL
	TTY	<MVX,T2,T3>	;GO THERE
	OUTSTR	TP		;GET DASHES

	AOJ	T2,		;NEXT LINE
	MOVEI	T3,^D33		;'MIDDLE'
	TTY	<MVX,T2,T3>	;GO THERE
	TTY	<BRI>		;BRIGHT VIDEO
	OUTSTR	LNKUSR(T5)	;GET USER
	TTY	<NRM>		;NORMAL VIDEO

	MOVE	T3,LNKFLG(T5)	;GET LINK FLAGS
	TLNN	T3,(L$HELD)	;HOLDING US?
	 JRST	BOX2		;NO
	MOVEI	T3,^D70		;GO NEAR END OF LINE
	TTY	<MVX,T2,T3>	;GO THERE
	TMSG	<On Hold>

BOX2:	CALL	CRLF
	MOVEI	T1,TXTLIN	;TOP OF TEXT
	MOVEM	T1,WNDLIN(W)	;STORE
	MOVEI	T1,1		;FIRST COLM
	MOVEM	T1,WNDCOL(W)	;STORE
	SETZ	T0,		;GET NULL
	MOVE	T1,WNDLBP(W)	;GET LINE BP
	IDPB	T0,T1		;STORE NULL
	MOVEI	X1,WNDLBF(W)	;GET LINE BUF
	HRLI	X1,(POINT 7,)	;GET BP
BOX3:	ILDB	T1,X1		;GET BYTE
	JUMPE	T1,CPOPJ	;DONE
	CALL	PUTC		;***** HACKLUDGEHACKLUDGEHACKLUDGEHACKLUDGE
	AOS	WNDCOL(W)	;***** HACKLUDGEHACKLUDGEHACKLUDGEHACKLUDGE
	JRST	BOX3		;LOOP
	ENDAV.

;WAS CAUSING WRAP PROBLEMS.. SHORTENED
TP:	ASCIZ/------------------------------------------------------------------------/
	SUBTTL	COMMANDS -- STATUS

.STATUS:
	ACVAR	<X1>		;CALL LEVEL
	NOISE	(of PHONE)
	CONFRM
	TTY	<MOV,5,1>
	TTY	<ERB>		;ERASE TO EOS
	TMSG	<Status of PHONE:>
	CALL	CRLF
	CALL	CRLF
	TMSG	<User: >
	OUTSTR	US
	CALL	CRLF

	TMSG	<Switch-hook: >
	MOVE	T1,SWHOOK	;SWITCH HOOK CHAR
	CALL	PUTC
	CALL	CRLF

	TLNN	FL,(F$SERV)	;SERVER AVAIL?
	 IFSKP.
	  TMSG	<System has PHONE server -- you may dial out>
	 ELSE.
	  TLNN	FL,(F$DECN)	;DECNET AVAIL?
	   IFSKP.
	    TMSG <System has DECnet, but no server -- you cannot dial out>
	   ELSE.
	    TMSG <System has no DECnet.>
	   ENDIF.
	 ENDIF.
	CALL	CRLF

	SKIPN	NUMUSR		;ANY LUSERS?
	 IFSKP.
	  TMSG	<Current calls:>
	  CALL	CRLF
	  SETO	T1,		;GET LEVEL
	  CALL	DMPLVL		;DUMP IT
	 ENDIF.
	SETZ	X1,
	DO.
	 CAMLE	X1,MAXHLD	;ANY PEOPLE HERE?
	  EXIT.
	 CALL	CRLF
	 TMSG	<Hold level >
	 MOVEI	T2,(X1)		;GET LEVEL
	 CALL	TDEC		;TYPE IT
	 MOVEI	T1,":"
	 CALL	PUTC
	 CALL	CRLF
	 MOVE	T1,X1		;GET LEVEL
	 CALL	DMPLVL
	 AOJA	X1,TOP.		;GET NEXT LEVEL
	OD.

	SKIPN	T4,BSYLNK	;TEMP LINK?
	 IFSKP.
	  TMSG	<Temp link to:>
	  CALL	CRLF
	  CALL	DMPLNK
	 ENDIF.

	CALL	CRLF
	CALL	CRLF
	TMSG	<--Type any char to continue-->
	PBIN
	CAIN	T1,"M"-100
	 PBIN
	RET
	ENDAV.
DMPLVL:	ACVAR	<X1>
	MOVEM	T1,X1		;SAVE LEVEL
	MOVSI	T5,-MAXLNK	;GET LOOP INDEX
DMPLOP:	SKIPE	T4,LNKTAB(T5)	;GET LINK IF ANY
	 CAME	X1,LNKHLD(T4)	; GOT ONE, ON RIGHT LEVEL?
	  JRST	DMPBOT		;  NOPE
	CALL	DMPLNK		;DUMP THIS LINK
DMPBOT:	AOBJN	T5,DMPLOP
	RET
	ENDAV.

; T4/	POINTER TO LINK
DMPLNK:	OUTSTR	LNKRUT(T4)	;GET ROUTE
	OUTSTR	LNKUSR(T4)	;GET USER
	HRRZ	T2,LNKFLG(T4)	;ANY FLAGS SET?
	TMSG	<	(via >
	OUTSTR	@[ [ASCIZ 'DECnet)']
		   [ASCIZ 'Local IPCF)'] ](T2)
	PJRST	CRLF
	SUBTTL	IPCF -- INITIALIZATION

IPCINI:	MOVEI	T1,.FHSLF	;CREATE FORK WIDE PID
	CALL	CREPID		;PID
	 RET			; MUMBLE
	MOVEM	T1,OURPID	;USE THIS ONE FOR NOW

	MOVE	T1,[POINT 7,PIDNAM]
	MOVEI	T2,"<"		;>START PID NAME
	IDPB	T2,T1		;STORE
	HRROI	T2,OURNAM	;USER
	CALL	CPYTXT		;<
	HRROI	T2,[ASCIZ ">PHONE"]
	CALL	CPYTXT
	SETZ	T2,
	IDPB	T2,T1		;TERMINATE

	HRROI	T1,PIDNAM	;NAVE TO GIVE PID
	CALL	NAMPID		;TRY TO ASSIGN
	 TRNA			; LOSE, FIND OWNER
	  JRST	IPCIN2		;  WIN, GO ADD PSI

	HRROI	T1,PIDNAM	;GET NAME
	CALL	FNDPID		;TRY TO LOOK UP
	 FATAL	(Could not get or find your PID)
	CALL	CHKPID		;GET OWNER
	 FATAL (Could not get your PID's owner)
	CAMN	T1,OURJOB	;THIS JOB??
	 FATAL	(Your job already has an active phone)
	FATAL	(Some other job of yours is using the phone)

IPCIN2:	MOVEI	T1,3		;LENGTH
	MOVEI	T2,T3		;ADDRESS
	MOVEI	T3,.MUPIC	;IPCF/PI FUNCTION
	MOVE	T4,OURPID	;PID
	MOVEI	T5,IPCCHN	;CHANNEL
	MUTIL
	 RET
	RETSKP
	SUBTTL	IPCF -- RECIEVE A PAGE FROM LOCAL OR SLAVE

RIPCF:	MOVE	T1,OURPID	;GET OUR PID
	MOVEM	T1,IPRCV+.IPCFR	;STORE RECIEVER
	MOVX	T1,IP%CFB!IP%CFV ;ONE PAGE, DO NOT BLOCK
	MOVEM	T1,IPRCV+.IPCFL	;STORE FLAGS
	MOVE	T1,[1000,,DATPAG] ;MESSAGE PAGE
	MOVEM	T1,IPRCV+.IPCFP	;STORE POINTER
	MOVEI	T1,4		;LENGTH OF BLOCK
	MOVEI	T2,IPRCV	;ADDR OF BLOCK
	MRECV			;GET PACKET
	 ERJMP	CPOPJ
	RETSKP

	SUBTTL	IPCF -- SEND A PAGE TO A LOCAL USER

; T1/	Target PID
;	CALL	SIPCF
;	<ok>
SIPCF:	MOVEM	T1,IPSND+.IPCFR	;STORE RECIEVER'S PID
	MOVX	T1,IP%CFV	;ONE PAGE
	MOVEM	T1,IPSND+.IPCFL	;STORE FLAGS
	MOVE	T1,OURPID	;GET OUR PID
	MOVEM	T1,IPSND+.IPCFS	;STORE SENDER'S PID
	MOVE	T1,[1000,,SNDPAG] ;POINT TO DATA
	MOVEM	T1,IPSND+.IPCFP	;STORE
	MOVEI	T1,4		;BLOCK LENGTH
	MOVEI	T2,IPSND	;BLOCK ADDRESS
	MSEND
	 ERJMP	CPOPJ
	RETSKP
	SUBTTL	IPCF -- RECEIVE A SHORT MESSAGE, BLOCKING (FROM INFO)

RIPCFS:	MOVX	T1,IP%TTL	;TRUNCATE
	MOVEM	T1,IPRCV+.IPCFL	;STORE FLAGS
	MOVE	T1,OURPID	;GET OUR PID
	MOVEM	T1,IPRCV+.IPCFR	;STORE RECIEVER
	MOVE	T1,[10,,IRCVBK] ;MESSAGE AREA
	MOVEM	T1,IPRCV+.IPCFP	;STORE POINTER
	MOVEI	T1,4		;LENGTH OF BLOCK
	MOVEI	T2,IPRCV	;ADDR OF BLOCK
	MRECV			;GET PACKET
	 ERJMP	CPOPJ
	RETSKP

	SUBTTL	IPCF -- SEND A SHORT MESSAGE

; T1/	Target PID
;	CALL	SIPCFS
;	 <lose>
;	<ok>
SIPCFS:	MOVEM	T1,IPSND+.IPCFR	;STORE RECIEVER'S PID
	SETZM	IPSND+.IPCFL	;CLEAR FLAGS
	MOVE	T1,OURPID	;GET OUR PID
	MOVEM	T1,IPSND+.IPCFS	;STORE SENDER'S PID
	MOVE	T1,[10,,ISNDBK] ;POINT TO DATA
	MOVEM	T1,IPSND+.IPCFP	;STORE
	MOVEI	T1,4		;BLOCK LENGTH
	MOVEI	T2,IPSND	;BLOCK ADDRESS
	MSEND
	 ERJMP	CPOPJ
	RETSKP
	SUBTTL	IPCF -- CHECK A PID

; T1/	PID
;	CALL	CHKPID
;	 <invalid>
;	<valid>
; T1/	owning job
CHKPID:	MOVEM	T1,T4		;STORE PID
	MOVEI	T3,.MUFOJ	;FUNCTION
	DMOVE	T1,[EXP 3,T3]	;LEN & ADDR
	MUTIL			;FIND THE PID'S JOB
	 ERJMP	CPOPJ		;RETURN ERROR
	MOVE	T1,T5		;GET JOB NUMBER
	RETSKP			;RETURN HAPPY


	SUBTTL	IPCF -- CREATE A PID

; T1/	Flags,,Fork
;	CALL	CREPID
;	 <lose>
;	<win>
; T1/	PID
CREPID:	MOVE	T4,T1		;PUT FLAGS IN PLACE
	DMOVE	T1,[EXP 3,T3]	;LEN & ADDR
	MOVEI	T3,.MUCRE	;CREATE PID
	MUTIL			;DOIT
	 ERJMP	CPOPJ		;RETURN ERROR
	MOVE	T1,T5		;GET PID
	RETSKP			;RETURN HAPPY
	SUBTTL	IPCF -- FIND PHONE PID (IF ANY) ASSOCIATED WITH A USER NUMBER

; (THIS IS FNDUSR IN PHNSRV)
;	CALL	FNDUNO
;	 <NO>
;	<YES>
; T1/	PID
FNDUNO:	STKVAR	<<BUFFER,^D9>>
	MOVEI	T1,BUFFER	;GET LOCAL BUFFER ADDR
	HRLI	T1,(POINT 7,)	;MAKE INTO BP
	MOVEI	T2,"<"		;> GET START OF PID NAME
	IDPB	T2,T1		;STORE IT
	MOVE	T2,LNKUNO(I)	;GET USER NUMBER
	DIRST			;GET USER STRING
	 RET			; SIGH <
	HRROI	T2,[ASCIZ '>PHONE'] ;TERMINATE PID NAME
	CALL	CPYTXT		;FILL IT OUT
	CALL	IPOFF		;SUPRESS IPCF PSI (MUST READ RESP)
	HRROI	T1,BUFFER	;GET PID NAME ADDR
	CALL	FNDPID		;LOOKUP THE PID
	 TRNA
	  AOS	(P)		;GIVE SKIP
	MOVEM	T1,BUFFER
	CALL	IPON		;RETURN W/ IPCF ENABLED
	MOVE	T1,BUFFER
	RET

	SUBTTL	IPCF -- FIND PID ASSOCIATED WITH A NAME
; T1/	BP TO NAME
;	CALL	FNDPID
;	 <NOPE>
;	<YEP>
; T1/	PID
FNDPID:	HRROI	T2,ISNDBK+.IPCI2 ;NAME OF PID
	CALL	CPYST0		;COPY PID NAME
	MOVEI	T1,.IPCIW	;LOOK FOR PID
	MOVEM	T1,ISNDBK+.IPCI0 ;STORE FUNCTION
	SETZM	ISNDBK+.IPCI1	;SEND RESULTS TO ME ONLY
	CALL	IPCSYS		;INTERACT W/ SYSINF
	 RET			; GRR
	MOVE	T1,IRCVBK+.IPCI1 ;GET PHNSRV PID
	RETSKP

	SUBTTL	IPCF -- ASSIGN NAME TO OURPID
; T1/	BP to name
;	CALL	NAMPID
;	 <loss>
;	<ok>
NAMPID:	HRROI	T2,ISNDBK+.IPCI2 ;NAME OF PID
	CALL	CPYST0		;COPY
	MOVEI	T1,.IPCII	;CREATE NAME
	MOVEM	T1,ISNDBK+.IPCI0 ;STORE FUNCTION
	SETZM	ISNDBK+.IPCI1	;RESULTS TO ME ONLY

	SUBTTL	IPCF -- Send message to <SYSTEM>INFO
IPCSYS:	SETZ	T1,		;PID FOR SYSINF
	CALL	SIPCFS		;SEND MESSAGE TO SYSINF
	 RET			; SIGH

	CALL	RIPCFS		;RECEIVE SHORT MESSAGE FROM SYSINF
	 RET			; MUMBLE..
	LDB	T1,[POINTR IPRCV,IP%CFC] ;GET PRIV FIELD
	CAIE	T1,.IPCCF	;FROM SYSTEM-WIDE <SYSTEM>INFO?
	 CAIN	T1,.IPCCP	; OR FROM MY <SYSTEM>INFO?
	  TRNA			;  YES!!
	   JRST	IPCSYS		;   NO, WAIT FOR IT THEN
	LDB	T2,[POINTR IPRCV,IP%CFE] ;GET SYSINF RETURN CODE
	JUMPN	T2,CPOPJ	;SOME ERROR?
	RETSKP			;NOPE.
	SUBTTL	Initialization stuff

INIT:	SETZB	FL,ZERBEG	;ZERO
	MOVE	T1,[ZERBEG,,ZERBEG+1]
	BLT	T1,ZEREND	;SMEAR

	CALL	CHKNET		;SET NETWORK FLAGS
	TLNN	FL,(F$DECN)	;DECNET?
	 JRST	INIT2		; NOPE
	CALL	GETLCL		;GET LOCAL NODES
	SKIPE	CMNOD+.CMDAT	;ALREADY READ NODE TABLE?
	 JRST	INIT2		;  YES, IGNORE
	MOVEI	T1,CONBLK	;GET CONNECT BLOCK
	CALL	.DNINI##	;INITIALIZE DNCONN
	 MOVEI	T1,[0,,0]	; GET PTR TO EMPTY TABLE
	MOVEM	T1,CMNOD+.CMDAT	;STORE TABLE OF NAMES

INIT2:	SETOM	MAXHLD		;SET UP MAX HOLD LEVEL

	MOVE	T1,['JOBTTY']
	SYSGT
	HLLZM	T2,JOBAOB	;SAVE JOB AOBJN WORD

;;;	MOVE	T1,['PTYPAR']
;;;	SYSGT
;;;	HRRZM	T1,PTYPAR	;STORE FIRST PTY

	MOVSI	T1,(RC%EMO)	;GET EXACT MATCH
	HRROI	T2,[ASCIZ 'OPERATOR']
	SETZ	T3,
	RCUSR			;GET OPERATOR USER NUMBER
	MOVEM	T3,OPRUNO	;SAVE

	CALL	SAVTTY		;SET TERMINAL CCOC WORDS
	MOVEI	T1,.PRIOU	;OUR TTY
	GTTYP			;GET TERMINAL TYPE
	 ERCAL	ERRHLT
	SKIPN	VTXDSP(T2)	;KNOWN?
       FATAL	(Unknown Terminal type)	;ONLY THE BEST TUNA....
	MOVEM	T2,TTYTYP	;SAVE

	MOVEI	T1,.PRIOU	;OUR TTY
	MOVEI	T2,.MORLL	;READ PAGE LEN
	MTOPR			;DO DEV OP
	CAIGE	T3,1		;LOOK REASONABLE?
	 MOVEI	T3,^D24		; NO, GET DEFAULT
	MOVEM	T3,SCRSIZ	;STORE
;Get our name and location
	HRROI	T1,[ASCIZ 'TOPS20'] ;DEFAULT NODE NAME (PERHAPS MONNAM.TXT?)
	HRROI	T2,OURNOD	;DEST
	CALL	CPYST0

	MOVEI	T1,.NDGLN	;GET NODE NAME FUCNTION
	MOVEI	T2,T3		;ARGBLOCK ADDR
	HRROI	T3,OURNOD	;STORE HERE
	MOVEM	T3,CMNOD+.CMDEF	;MAKE DEFAULT NODE NAME
	NODE			;GET NODE NAME
	 ERJMP	QQSV		;ON THE OTHER HAND..
	SETZ	T0,		;GET NULL
	IDPB	T0,T3		;TERMINATE

QQSV:	GJINF			;RANDOM JOB INFO
	MOVEM	T3,OURJOB	;SAVE JOB NUMBER
	MOVE	T2,T1		;PUT UID INTO T2
	HRROI	T1,OURNAM	;GET USER BUFFER
	DIRST			;MAKE USER STRING
	 FATAL	(BAD USER NUMBER)
	IDPB	T0,T1		;TERMINATE

;Get in form NODE::USER
	HRROI	T1,US		;POINT TO BUFFER
	HRROI	T2,OURNOD	;FROM OUR NODE
	CALL	CPYTXT		;COPY IT
	MOVEI	T2,":"		;TERMINATE NODE WITH ::
	IDPB	T2,T1
	IDPB	T2,T1
	HRROI	T2,OURNAM	;COPY FROM OUR NODE
	CALL	CPYTXT		;COPY

	HRROI	T1,LNKBLK+LNKUSR ;GET OUR LINK
	HRROI	T2,US		;GET OUR NAME
	CALL	CPYTXT		;COPY IN

	MOVE	T1,[POINT 7,WNDBLK+WNDLBF] ;GET BP TO OUR LINE BUFFER
	MOVEM	T1,WNDBLK+WNDLBP ;STORE

	MOVEI	T1,.FHSLF	;CURRENT PROCESS
	MOVE	T2,[LEVTAB,,CHNTAB] ;PI TABLES
	SIR			;SET UP TABLES
	MOVSI	T2,(1B<IPCCHN>) ;CHANNEL MASK
	AIC			;ACTIVATE

	CALL	IPCINI		;INITIALIZE IPCF
	 CALL	ERRHLT		;LEAVE A TRAIL
	RET
	SUBTTL	INIT -- GET LOCAL HOSTS

GETLCL:	SETZM	HSTTAB		;No Locals
	MOVEI	T1,5000		;5 pages
	MOVEM	T1,HSTADR	;Store count
	MOVEI	T2,HSTADR	;Get dest
	MOVEI	T1,.NDGNT	;Get node table
	NODE			;Load up table
	 ErJmp Cpopj		; Sigh
	Hlrz 1,HstAdr		;Get number returned
	Movem 1,HstTab		;Store as table max

	Movn 1,1		;Get  -count
	Hrlz 4,1		;-count,,0
	Hrri 4,HstAdr+.NDBK1	;Get start of blocks
GetHs1:	Movei 1,HstTab		;Get table addr
	Move 2,(4)		;Get addr of node block
	Hrlz 2,.NDNAM(2)	;Get addr of node name,,0
	Hlr 2,2			;Get name,,name
	TBADD			;Insert into table
	 ErJmp .+1		; Sigh
	Aobjn 4,GetHs1		;Loop for all hosts
	Ret
	SUBTTL	INIT -- CHECK FOR DECNET

CHKNET:	STKVAR	<TSTJFN>
	MOVSI	T1,(GJ%SHT)
	HRROI	T2,[ASCIZ 'DCN:-29.']
	GTJFN
	 RET
	MOVEM	T1,TSTJFN
	MOVE	T2,[FLD(10,OF%BSZ)!OF%RD!OF%WR]
	OPENF
	 IFJER.			;BAD DEVICE?
		MOVE	T1,TSTJFN
		RLJFN
		 TRN
		RET
	 ENDIF.			;BAD DEVICE?
	DVCHR
	HLRZ	T2,T2
	ANDI	T2,(DV%TYP)
	CAIE	T2,.DVDCN	;RIGHT DEVICE?
	 JRST	CLSTST		; NOPE

; NOW WE ARE SURE WE HAVE DECNET!!
; LOOK FOR THE SERVER.
	TLO	FL,(F$DECN)

	CALL	$UPTIME		;Get current uptime
	MOVE	T4,T1		;Copy
	ADDI	T4,^D<1000*5>	;Allow 5 seconds for connect
TSTLOP:	MOVE	T1,TSTJFN
	MOVEI	T2,.MORLS	;Read link status function
	MTOPR
	 ERJMP	CLSTST
	TLNE	T3,(MO%CON)	;Connected?
	 TLOA	FL,(F$SERV)	; Yes!!
	  TLNE	T3,(MO%ABT!MO%SYN) ;No, connect been rejected?
	   JRST	CLSTST		; Yes, close down
	CALL	$UPTIME		;Get uptime now
	CAML	T1,T4		;Time left?
	 JRST	CLSTST		; No, timed out
	MOVEI	T1,^D500	;Yes, sleep for 1/2 sec
	CALL	$HIBER		;Zzz
	JRST	TSTLOP		;Try again

CLSTST:	MOVE	T1,TSTJFN
	CLOSF
	 TRN
	RET
	ENDSV.

; HERE AFTER PARSING WITH CMNOD.

NODEBP:	HRRZ	T3,T3		;GET WINNER
	HLRO	T2,(T2)		;GET NODE STRING BP (IF TABLE)
	CAIE	T3,CMNOD3	;DID FIELD WIN?
	 RET			; NO, RETURN TABLE ENTRY
	HRROI	T1,NODBUF	;PLACE FOR NODE
	HRROI	T2,ATMBUF	;SOURCE
	MOVNI	T3,NBFLEN*5-1	;MAX LEN
	SETZ	T4,		;OR NULL
	SOUT
	HRROI	T2,NODBUF
	RET
	SUBTTL	PSI -- TURN PI OFF

PIOFF:
;;;	SETZM	PILVL		;SAY WE ARE OFF
.PIOFF:	MOVEI	T1,.FHSLF	;THIS FORK
	DIR			;DISABLE INTERUPTS
	RET

	SUBTTL	PSI -- TURN PI ON
PION:
;;;	SETOM	PILVL		;SAY WE ARE ON
.PION:	MOVEI	T1,.FHSLF	;THIS FORK
	EIR			;ENABLE INTERUPTS
	RET

	SUBTTL	PSI -- KILL IPCF INTERUPTS
IPOFF:	JRST	PIOFF
	MOVEI	T1,.FHSLF	;OUR FORK
	MOVSI	T2,(1B<IPCCHN>)	;IPCF CHAN
	DIC
	RET

	SUBTTL	PSI -- ACTIVATE IPCF INTERUPTS
IPON:	JRST	PION
	MOVEI	T1,.FHSLF	;OUR FORK
	MOVSI	T2,(1B<IPCCHN>)	;IPCF CHAN
	AIC
	RET
	SUBTTL	INTERUPT LEVEL -- IPCF DISPATCH

IPCINT:	MOVEM	16,L2SAVE+16	;STORE AC16
	MOVEI	16,L2SAVE	;SAVE AC0..15
	BLT	16,L2SAVE+15
	MOVEI	T1,.PRIOU	;OUR TTY
	RFPOS			;GET CURSOR POS
	MOVEM	T2,SAVPOS	;SAVE
	RFCOC
	DMOVEM	T2,SAVCOC
	CALL	SETTTY		;RE-BLAST CCOC (COMND PLAYS W/ IT!!)
	CALL	DOIPCF
IINT.3:	MOVEM	FL,L2SAVE+FL	;SATORE FLAGS BACK
	HRRZ	T1,SAVPOS	;GET COLM
	HLRZ	T2,SAVPOS	;GET LINE
	ADDI	T1,1		;MAKE ONE BASED
	ADDI	T2,3		;...
	SKIPE	L2SAVE+W	;HAVE A WINDOW?
	 JRST	IINT.4		; YES, DON'T WORRY
	TTY	<MVX,T2,T1>	;NO, RESTORE TO COMND% LINE
IINT.4:	MOVEI	T1,.PRIOU	;OUR TTY
	MOVE	T2,SAVPOS	;GET SAVED POSN
	SFPOS			;SET CURSOR POS
	DMOVE	T2,SAVCOC	;RESTORE CCOC
	SFCOC
	MOVSI	16,L2SAVE	;RESTORE ACS
	BLT	16,16		;0..16
	DEBRK

DOIPCF:	CALL	RIPCF		;GET MESSAGE (PAGE)
	 RET			; NO MORE
	LDB	T1,[POINT 8,DATADR,7] ;GET CODE
	CAIG	T1,DSPMAX	;IN RANGE?
	 SKIPN	T1,DSPTAB(T1)	; ANY ROUTINE?
	  TRNA			;  NO.
	   CALL	(T1)		;   GO TO ROUTINE
	    TRN			;    BE CAREFULL
	JRST	DOIPCF		;GET ANOTHER
	SUBTTL	INTERUPT LEVEL -- RING

XRUNG:	MOVE	T1,[POINT 8,DATADR,7] ;GET PEST
	HRROI	T2,US		;AND US
	CALL	CMPSTR		;ONE AND THE SAME?
	 JRST	RI.OTH		; NOPE, BE NORMAL

	SKIPN	I,BSYLNK	;USE SAME LINK TO ANSWER!!
	 RET			; YOU LOSE
	MOVEI	T1,MS$ANS	;ANSWER..
	SETZ	T2,		;NO DATA
	CALL	SNDMSG		;SEND MESSAGE
	 PJRST	CLSDON		; SIGH
	TLO	FL,(F$ANSW)	;PUT INTO ANSWER MODE
	RET			;GO HOME

;Here with a ring from someone who is not us
RI.OTH:	TLNE	FL,(F$DIAL)	;IN DIAL MODE?
	 PJRST	TMPBSY		; IF YES, RETURN BUSY

	MOVE	T2,[POINT 8,DATADR,7] ;GET SENDER
RI.LOP:	ILDB	T1,T2		;GET BYTE
	JUMPN	T1,RI.LOP	;TILL EOS
	ILDB	T1,T2		;GET RING FLAG
	MOVEM	T1,RINGFL	;SAVE

	TLNE	FL,(F$ANSW)	;ANSWERING ALREADY?
	 SKIPN	RINGFL		; AND THIS IS FIRST RING?
	  TRNA			;  NO.
	   PJRST TMPBSY		;   YES, SEND BACK BUSY

	TLNN	FL,(F$ANSW)	;ANSWERING?
	 SKIPN	RINGFL		; OR NOT FIRST RING?
	  JRST	RI.2		;  YES, HANDLE SUBSEQUENT RING.

; Here with first ring when not currently answering, and user is not
; us.  Silently establish link back to them, and set "answer mode".

	MOVE	T1,[POINT 8,DATADR,7] ;NO, NEW USER!!
	CALL	MAKLNK		;MAKE LINK BACK TO THEM
	 RET			; SIGH
				;NOTE: WE QUIT NOW SO THE USER DOESN'T
				;KNOW THIS B.S. WENT ON (OTHER THAN THE
				;DELAY) AS OPPOSED TO CRUFTY VAX VERSION

	PUSH	P,I		;SAVE LINK
	MOVE	I,T1		;SET LINK TO NEW ONE
	TLO	FL,(F$ANSW)	;PUT INTO ANSWER MODE
	MOVEM	I,BSYLNK	;SAVE BUSY LINK
	POP	P,I		;RESTORE LINK
	JRST	RI.MES		;GIVE "RING", NOW THAT BSYLNK IS SET UP!
; Answer mode, or not first ring

RI.2:	SKIPE	T1,BSYLNK	;HAVE A LINK?
	 TLNN	FL,(F$ANSW)	; AND IN ANSWER MODE?
	  RET			;  NO PUNT THE POOR LUSER (SEND TMPBSY?)
	HRROI	T1,LNKUSR(T1)	;GET OLD RINGER
	MOVE	T2,[POINT 8,DATADR,7] ;GET NEW RINGER
	SKIPN	RINGFL		;SUBSEQUENT RING
	 CALL	CMPSTR		; AND FROM SAME PERSON?
	  RET			;  YOU LOSE
	
RI.MES:	MOVE	T1,[POINT 8,DATADR,7] ;GET USER
	HRROI	T2,US		;GET US
	CALL	CMPSTR		;ONE AND THE SAME?
	 TRNA			;NO, KEEP TRUCK'N
	  RET			; YES, DON'T WAST BREATH
	CALL	ERRLIN		;GO TO MESSAGE LINE
	CALL	SAVTTY		;***********
	MOVE	T1,[POINT 8,DATADR,7] ;TELL THEM WHO
	PSOUT			;TYPE IT
	TMSG	< is ringing you!> ;BRRRING..
	PJRST	ENDERR

;Tell someone we are busy (called from RING interrupt)
TMPBSY:	PUSH	P,I		;SAVE CURRENT LINK
	MOVE	T1,[POINT 8,DATADR,7] ;THEIR NAME
	CALL	MAKLNK		;MAKE LINK
	 JRST	POPIJ		; FAILED
	MOVE	I,T1		;SWITCH TO NEW LINK
	MOVEI	T1,MS$BSY	;BUSY
	SETZ	T2,		;NO DATA
	CALL	SNDMSG		;SEND MESS
	 TRN			; IGNORE ERROR
	CALL	CLSDON		;SHUT DOWN THE LINK
POPIJ:	POP	P,I		;RESTORE LINK
	RET
	SUBTTL	INTERUPT LEVEL -- HANGUP

XHUNG:	ACVAR	<X1>		;LOOP VAR
	SKIPN	T1,BSYLNK	;GOT A BUSY LINK
	 JRST	HU.FND		; NOPE
	HRROI	T1,LNKUSR(T1)	;GET BUSY USER
	MOVE	T2,[POINT 8,DATADR,7] ;GET USER WHO HUNGUP
	CALL	CMPSTR		;SAME?
	 JRST	HU.FND		; NOPE
	TLNE	FL,(F$DIAL)	;ARE WE CALLING THEM?
	 JRST [	CALL BRKCAL	; YES, BREAK IT THEN
		JRST HU.MES ]	; GO GIVE MESS
	TLZN	FL,(F$ANSW)	;WERE THEY CALLING US?
	 JRST	HU.FND		; NO?????
	MOVE	I,BSYLNK	;YES
	SETZM	BSYLNK		;CLEAR LINK
	CALL	CLSHUP		;HANG UP & SHUT DOWN THE LINK
	JRST	HU.MES		;TELL THEM

HU.FND:	MOVSI	X1,-MAXLNK	;SEARCH *ALL* LINKS
HU.LOP:	SKIPN	I,LNKTAB(X1)	;GET LINK, IF ANY
	 JRST	HU.BOT		; NO LINK
	HRROI	T1,LNKUSR(I)	;GET USER
	MOVE	T2,[POINT 8,DATADR,7] ;GET REMOTE
	CALL	CMPSTR		;MATCH?
	 JRST	HU.BOT		; NO
	CALL	KILUSR		;KILL FROM SCREEN
	SETZM	LNKTAB(X1)	;FREE LINK SLOT
	CALL	CLSHUP		;SAY GOODBYE, KILL LINK BLOCK
HU.BOT:	AOBJN	X1,HU.LOP	;LOOP
	CALL	REFRSH		;RE-SPLIT SCREEN
	 TRN			; NEVER MIND...
HU.MES:	CALL	ERRLIN		;PUT ON ERROR LINE
	MOVE	T1,[POINT 8,DATADR,7] ;GET USER
	PSOUT			;TYPE THEM
	TMSG	< hung up>	;TELL WHAT THEY DID
	PJRST	ENDERR
	ENDAV.
	SUBTTL	INTERUPT LEVEL -- BUSY SIGNAL

XBUSY:	SKIPN	T1,BSYLNK	;CALLER/EE?
	 RET			; NOPE
	HRROI	T1,LNKUSR(T1)	;GET USER
	MOVE	T2,[POINT 8,DATADR,7] ;GET REMOTE
	CALL	CMPSTR		;RIGHT PERSON?
	 RET			; PHONEY PHONE CALL
	TLNN	FL,(F$DIAL)	;IN DIAL MODE?
	 JRST	XBUS.1		; NO, CHECK IF BEING RUNG
	CALL	BRKCAL		;BREAK THE CALL
	CALL	ERRLIN		;GO TO ERR LINE
	TMSG	<User is busy>	;SAY WHAT WE MEAN
	PJRST	ENDERR

XBUS.1:	TLZN	FL,(F$ANSW)	;IN ANSWER MODE?
	 RET			; NOPE, TOTAL LOSER
	MOVEI	T1,MS$BSY	;THAT'L SHOW UM!
	SETZ	T2,		;NO DATA
;Close BSYLNK
; T1/	MESSAGE
CLSBSY:	PUSH	P,I		;SAVE LINK
	MOVE	I,BSYLNK	;SET TO BUSY LINK
	SETZM	BSYLNK		;DESTROY BSYLNK
	CALL	CLSMSG		;SEND IT
	PJRST	POPIJ

;Break current call
BRKCAL:	TLZ	FL,(F$DIAL)	;CLEAR DIAL MODE
	MOVEI	T1,MS$HUP	;SAY WE HUNG UP
	SETZ	T2,		;NO DATA
	PJRST	CLSBSY		;CLOSE BUSYLINK
	SUBTTL	INTERUPT LEVEL -- ANSWERED

XANSWR:	ACVAR	<X1,X2>		;NEW LINK, LOOP VAR
	STKVAR	<<FULNAM,20>,<OLDNAM,20>> ;FULL ROUTE TO NEW PERSON, OLD PERSON
	TLNE	FL,(F$DIAL)	;IN DIAL MODE?
	 SKIPN	X1,BSYLNK	;HACKING A LINK?
	  RET			; NO, SPURIOUS
	HRROI	T1,LNKUSR(X1)	;GET TARGET USER
	MOVE	T2,[POINT 8,DATADR,7] ;GET REMOTE
	CALL	CMPSTR		;COMPARE
	 RET			; NOT WHO WE WANT
	TLZ	FL,(F$DIAL)	;GOT AN ANSWER!!
	MOVE	T1,BSYLNK	;GET LINK
	CALL	NEWUSR		;GET WINDOW, SAVE LINK
	 PJRST	BRKCAL		; ABANDON SHIP!!
	SETZM	BSYLNK		;CLEAR LINK (BRKCAL NEEDS IT)
	CALL	ERRLIN		;REPORT ON ERROR LINE
	MOVE	T1,[POINT 8,DATADR,7] ;GET USER
	PSOUT			;TYPE
	TMSG	< ANSWERed!>	;OH BLISS
	CALL	ENDERR

;; HERE TO FORCE LINKS TO NEW PERSON ETC..
	HRROI	T1,FULNAM	;PLACE FOR FULL USER NAME
	HRROI	T2,LNKRUT(X1)	;GET FULL ROUTE
	CALL	CPYTXT		;COPY IF ANY
	HRROI	T2,LNKUSR(X1)	;COPY NAME TOO

; LOOP FOR ALL ACTIVE WINDOWS
	MOVN	X2,NUMUSR	;GET USER COUNT
	HRLZ	X2,X2		;AS -N,,0
FRCLOP:	MOVE	T1,WNDTAB(X2)	;GET WINDOW
	MOVE	I,WNDLNK(T1)	;GET LINK
	CAMN	I,X1		;IS THIS THE NEW USER?
	 JRST	FRCBOT		; YES, DON'T SEND

;TELL OLDPERSON ABOUT NEWPERSON
	MOVEI	T1,MS$3RD	;GET MESSAGE TYPE
	MOVE	T3,LNKFLG(I)	;GET LINK FLAGS
	TLNN	T3,(L$HELD)	;HOLDING US?
	 CALL	SNDMSG		; NO, SEND
	  TRN			;  IGNORE ERRORS
;TELL NEWPERSON ABOUT OLDPERSON
	HRROI	T1,OLDNAM	;GET PLACE FOR FULL OLD NAME
	HRROI	T2,LNKRUT(I)	;GET OLDPERSON ROUTE
	CALL	CPYTXT		;COPY IN
	HRROI	T2,LNKUSR(I)	;GET OLDPERSON NAME
	CALL	CPYTXT		;COPY
	MOVE	I,X1		;SET LINK TO BE NEW PERSON
	MOVEI	T1,MS$3RD	;GET MESS TYPE
	HRROI	T2,OLDNAM	;GET ADDR OF OLD PERSON
	MOVE	T3,LNKFLG(I)	;GET FLAGS FOR NEW PERSON
	TLNN	T3,(L$HELD)	;HOLDING US? (ON THE FIRST DATE?) (SO SOON??)
	 CALL	SNDMSG		;SEND TO NEW PERSON
	  TRN			; SIGH
FRCBOT:	AOBJN	X1,FRCLOP	;LOOP FOR ALL WINDOWS
	RET			;WE SHOULD NOW BE IN TALK MODE
	ENDAV.
	SUBTTL	INTERUPT LEVEL -- FORCED LINK

XFORCE:	ACVAR	<X1>		;LOOP VAR
	STKVAR	<UID>		;BP TO USER ID.
	MOVE	T1,[POINT 8,DATADR,7] ;GET SOURCE USER
XFRC.1:	ILDB	T2,T1		;GET A BYTE
	JUMPN	T2,XFRC.1	;UNTIL END OF NAME
	CALL	GETUSR		;PARSE TARGET OF FORCE
	 RET			; FAILURE!!
	MOVEM	T3,UID		;SAVE BP TO NODE::USER

; SEARCH ALL LINKS FOR THIS USER
	MOVSI	X1,-MAXLNK	;SEARCH *ALL* LINKS
XFRC.L:	SKIPN	I,LNKTAB(X1)	;GET LINK, IF ANY
	 JRST	XFRC.B		; NO LINK
	HRROI	T1,LNKUSR(I)	;GET USER
	MOVE	T2,UID		;GET NEWPERSON
	CALL	CMPSTR		;MATCH?
	 TRNA			; NO, KEEP LOOKING
	  RET			;  YES, CANNOT CREATE NEW LINK
XFRC.B:	AOBJN	X1,XFRC.L	;LOOP
	MOVE	T1,UID		;GET NEW PERSON
	CALL	MAKLNK		;CREATE LINK
	 RET			; SIGH.
	MOVE	I,T1		;SAVE LINK
	CALL	NEWUSR		;ADD HIR
	 PJRST	CLSHUP		; NO!! HANGUP, AND CLOSE LINK!!

	CALL	ERRLIN		;RIGHT PLACE
	TMSG	<>		;BEEP!
	MOVE	T1,[POINT 8,DATADR,7] ;GET REMOTE
	PSOUT			;SAY WHO
	MOVE	X1,T1		;SAVE BP
	TMSG	< has set up a conference call with >
	MOVE	T1,X1		;GET BP BACK
	PSOUT
	RET
	ENDAV.
	ENDSV.
	SUBTTL	INTERUPT LEVEL -- REJECT

XREJ:	TLNE	FL,(F$DIAL)	;IN DIAL MODE?
	 SKIPN	T1,BSYLNK	;HACKING A LINK?
	  RET			; NO, SPURIOUS
	HRROI	T1,LNKUSR(T1)	;GET TARGET USER
	MOVE	T2,[POINT 8,DATADR,7] ;GET REMOTE
	CALL	CMPSTR		;COMPARE
	 RET			; NOT WHO WE WANT
	CALL	ERRLIN		;REPORT ON ERROR LINE
	MOVE	T1,[POINT 8,DATADR,7] ;GET USER
	PSOUT			;TYPE
	TMSG	< REJECTed!>	;OH BLISS
	CALL	ENDERR
	PJRST	BRKCAL		;CREAK THE CALL
	SUBTTL	INTERUPT LEVEL -- PUT ON HOLD

XHOLD:	MOVE	T1,[POINT 8,DATADR,7] ;GET USER
	CALL	FNDLNK		;FIND ANY LINK
	 RET			; NO SUCH ZONE
	MOVSI	T2,(L$HELD)	;GET HELD FLAG
	IORM	T2,LNKFLG(T1)	;SET FLAG IN LINK
	SKIPL	LNKHLD(T1)	;DO WE HAVE THEM ON HOLD?
	 RET			; YES, NO SCREEN CHANGE
	JUMPE	W,CPOPJ		;IF NOT IN A WINDOW, PUNT
	MOVE	T1,[POINT 8,DATADR,7] ;FIND USER
	CALL	FNDUSR		;GET WINDOW
	 RET			; HUH?
	MOVE	T2,WNDLIN(T1)	;GET ORIGIN
	ADDI	T2,1		;STATUS LINE
	MOVEI	T3,^D70		;COLUMN
	TTY	<MVX,T2,T3>	;GO THERE
	TMSG	<(Has you on hold)>	;MESS
	PJRST	POSION		;RESTORE POSION
	SUBTTL	INTERUPT LEVEL -- TAKEN OFF HOLD

XUNHLD:	MOVE	T1,[POINT 8,DATADR,7] ;GET USER
	CALL	FNDLNK		;FIND LINK BLOCK
	 RET			; ??
	MOVSI	T2,(L$HELD)	;GET FLAG
	ANDCAM	T2,LNKFLG(T1)	;CLEAR IN LINK
	JUMPE	W,CPOPJ		;IF NO WINDOW, PUNT
	SKIPL	LNKHLD(T1)	;WE HAVE THEM ON HOLD?
	 RET			; YES, NO SCREEN CHANGE (NOT ON SCREEN)
	MOVE	T1,[POINT 8,DATADR,7] ;FIND USER
	CALL	FNDUSR		;GET WINDOW
	 RET			; HUH?
	MOVE	T2,WNDLIN(T1)	;GET ORIGIN
	ADDI	T2,1		;STATUS LINE
	MOVEI	T3,^D70		;COLUMN
	TTY	<MVX,T2,T3>	;GO THERE
	TTY	<ERL>		;CLEAR TO END OF LINE
	TMSG	<>		;OH BOY!!
	PJRST	POSION		;RESTORE POSION
	SUBTTL	INTERUPT LEVEL -- CONVERSATION TEXT

XTEXT:	JUMPE	W,CPOPJ		;NO CURRENT WINDOW? PUNT!
	MOVE	T1,[POINT 8,DATADR,7] ;GET USER BP
	CALL	FNDUSR		;SEARCH ACTIVE USERS FOR A MATCH
	 RET			;SIGH
	PUSH	P,W		;SAVE WINDOW
	MOVE	W,T1		;SET WINDOW
	CALL	POSION		;POSITION CURSOR

	MOVE	T1,[POINT 8,DATADR,7] ;POINT TO USER
XTEXT0:	ILDB	T0,T1		;GET NEXT
	JUMPN	T0,XTEXT0	;UNTIL END
	MOVEM	T1,A0		;STORE BP

XTEXT1:	ILDB	T1,A0		;GET CHARACTER
	JUMPE	T1,XTEXT2	; EOS?
	CALL	ECHO		;ECHO IT
	JRST	XTEXT1		;LOOP

XTEXT2:	POP	P,W		;RESTORE WINDOW
	PJRST	POSION		;AND POSITION
	SUBTTL	STRINGS -- COPY FROM T1 TO T2 W/ NULL
CPYST0:	CALL	CPYSTR		;COPY
	SETZ	T0,		;GET NULL
	IDPB	T0,T2		;TERMINATE
	RET

	SUBTTL	STRINGS -- COPY FROM T1 TO T2 W/O NULL
CPYSTR:	CALL	CHKBPS
CPYST2:	ILDB	T0,T1
	JUMPE	T0,CPOPJ
	IDPB	T0,T2
	JRST	CPYST2

	SUBTTL	STRINGS -- COPY FROM T2 TO T1; BACKUP OVER NULL
CPYTXT:	CALL	CHKBPS
CPYTX2:	ILDB	T0,T2
	JUMPE	T0,CPYTX3
	IDPB	T0,T1
	JRST	CPYTX2
CPYTX3:	PUSH	P,T1		;SAVE DEST
	IDPB	T0,T1		;STORE ZERO BYTE
	POP	P,T1		;RESTORE BP
	RET

	SUBTTL	STRINGS -- COMPARE STRINGS FOR EQUALITY ONLY (IGNORE CASE)
; T1/	bp1
; T2/	bp2
;	CALL	CMPSTR
;	 <neq>
;	<eql>
CMPSTR:	CALL	CHKBPS
CMPST2:	ILDB	T3,T1
	TRZ	T3,40
	ILDB	T4,T2
	TRZ	T4,40
	CAIE	T3,(T4)		;EQUAL?
	 RET			; YOU LOSE
	JUMPN	T3,CMPST2	;AT END?
	RETSKP

	SUBTTL	STRINGS -- CHECK BYTE POINTERS
CHKBPS:	MOVEI	T4,T2		;CHECK T2
	CALL	CHKBYT		;DOIT
CHKBT1:	MOVEI	T4,T1		;CHECK T1
CHKBYT:	HLRZ	T0,(T4)		;GET BYTE POINTER
	CAIE	T0,0		;JUST AN ADDRESS
	 CAIN	T0,-1		; OR FROM HRROI?
	  MOVEI	T0,(POINT 7,)	;  YES, MAKE REAL BYTE POINTER
	HRLM	T0,(T4)		;PUT BACK
	RET
	SUBTTL	TYPE JSYS ERROR

ERRPNT:	CALL	ERRLIN		;GO TO ERROR LINE
	HRROI	T1,ERRSTR	;TYPE ON TTY
	MOVEI	T2,"?"		;A QUESTION MARK
	BOUT			;OUTPUT IT
	HRLOI	T2,.FHSLF	;THIS FORK, LAST ERROR
	SETZ	T3,		;NO LIMIT
	ERSTR			;TYPE ERROR
	 TRNA			; SIGH
	  TRN			;  SIGH
	SETZ	T2,
	IDPB	T2,T1
	HRROI	T1,ERRSTR

	SUBTTL	SUPPORT FOR ERROR MACRO
.ERROR:	CALL	CHKBT1		;MAKE INTO REAL BP
	MOVEM	T1,LSTERR	;(ERROR macro always adds a "?")
	ILDB	T2,T1		;CHECK FOR LEADING CRLF (FROM DNCONN)
	CAIE	T2,CR		; WAS CR?
	 JRST	.ERR1		;NOPE
	ILDB	T2,T1		;GET NEXT
	CAIN	T2,LF		;IS LF?
	 MOVEM	T1,LSTERR	; YES, SAVE WITHOUT CRUD
.ERR1:	CALL	ERRLIN
	MOVE	T1,LSTERR
	PSOUT
	PJRST	ENDERR

	SUBTTL	SUPPORT FOR FATAL MACRO
.FATAL:	ESOUT			;TYPE ERROR
	CALL	CRLF		;TYPE CRLF
	JRST	DOEXIT

	SUBTTL	JSYS ERROR AND DEATH
ERRHLT:	DMOVEM	T1,AC1
	DMOVEM	T3,AC3
	CALL	ERRPNT
DOEXIT:	HALTF
	JRST	DOEXIT
	SUBTTL	TTY -- SAVE CCOC WORD

SAVTTY:	MOVEI	T1,.PRIOU	;OUR TTY
	RFCOC			;GET CCOC WORD
	DMOVEM	T2,TTYCOC	;SAVE IT

	SUBTTL	TTY -- BLAST CCOC WORD

SETTTY:	MOVEI	T1,.PRIOU	;OUR TTY
	DMOVE	T2,[EXP 052532555125,252525452400] ;MAKE ^H, ^G, ^L, ESC
	SFCOC			;ECHO AS SELF
	RET

	SUBTTL	TTY -- RESTORE CCOC WORD
RESTTY:	MOVEI	T1,.PRIOU	;OUR TTY
	DMOVE	T2,TTYCOC	;GET OLD BITS
	SFCOC
	RET

	SUBTTL	TTY -- KILL ECHO
NOECHO:	MOVEI	T1,.PRIIN	;OUR TTY
	RFMOD			;GET MODE WORD
	TRZ	T2,TT%ECO	;CLEAR ECHO BIT
	SFMOD			;SET MODES
	RET

	SUBTTL	TTY -- RESTORE ECHO
YSECHO:	MOVEI	T1,.PRIIN	;OUR TTY
	RFMOD			;GET MODE WORD
	TRO	T2,TT%ECO	;SET ECHO BIT
	SFMOD			;SET MODES
	RET

	SUBTTL	TTY -- SKIP IF INPUT BUFFER EMPTY
$SIBE:	MOVEI	T1,.PRIIN	;CHECK OUR TTY
	SIBE			;INPUT BUFFER EMPTY
	 TRNA			; EMPTY
CPOPJ1:	  AOS	(P)
CPOPJ:	RET

$HIBER:	DISMS			;SLEEP
	RET

$UPTIME: TIME			;GET SYSTEM UPTIME IN MS.
	RET

$CLRBFI: MOVEI	T1,.PRIIN	;TTY
	CFIBF			;CLEAR INPUT BUFFER
	RET

PUTC:	PBOUT			;TYPE A CHAR
	RET

CRLF:	TMSG	<
>
	RET

; TYPE DECIMAL NUMBER IN T2
TDEC:	MOVEI	T1,.PRIOU	;TERMINAL
	MOVEI	T3,^D10		;DECIMAL
	NOUT			;TYPE NUMBER
	 ERJMP	.+1		;DISREGARD..
	RET
	SUBTTL	TEXT CONVERSATION INPUT

TEXT:	MOVEI	W,WNDBLK	;OUR WINDOW
	CALL	EC.RES		;RESET OUR LINE BUFFER
	MOVEI	T1,TXTLIN	;GOTO TOP OF WINDOW
	MOVEM	T1,WNDLIN(W)	;STORE
	MOVEI	T1,1		;AND FIRST COL
	MOVEM	T1,WNDCOL(W)	;STORE
	MOVE	T1,[POINT 7,OURBUF] ;TEXT BUFFER
	MOVEM	T1,OURPNT	;STORE
	MOVEI	T1,OURSIZ*5-1	;COUNT
	MOVEM	T1,OURCNT	;STORE
	CALL	IPOFF		;KILL INTERUPTS
	CALL	ERRLIN		;GOTO ERROR LINE
	TTY	<ERB>		;BLAST SCREEN
	CALL	BOXES		;SET UP BOXES FOR CONVERSATION
	CALL	NOECHO		;CLEAR TTY ECHO
	CALL	POSION		;SET CURSOR POSN
	CALL	DOLOOK		;GOTO INPUT LOOP
	CALL	YSECHO		;RESTORE ECHO
	RET

	SUBTTL	LOOK -- Get character
DOLOOK:	ACVAR	<X1>		;PERM AC
LOOK:	SKIPN	NUMUSR		;ANY MORE USERS?
	 RET			; NOPE
	TLNE	FL,(F$REF)	;REFRESH NEEDED?
	 CALL	BOXES		; YES, SET UP NEW BOXES
	TLNE	FL,(F$FAX)	;FACSIMILE?
	 JRST	LKFAX		; YES, HANDLE IT
	CALL	$SIBE		;CHECK FOR INPUT
	 JRST	LKGET		; YES! GO GET IT
	TLNE	FL,(F$TEXT)	;ANY TEXT TO SEND?
	 JRST	LOOK0		; YES, SEND IT
	CALL	IPON		;NO, INTERUPTS OK AGAIN
LKHANG:	PBIN			;WAIT FOR A CHAR
	PUSH	P,T1		;SAVE CHAR
	CALL	IPOFF		;PROHIBIT INTERUPTS AGAIN
	POP	P,T1		;RESTORE CHAR
	JRST	LKGOT		;PRINT IT

LOOK0:	CALL	LKSEND		;SEND BUFFER
	TLZ	FL,(F$TEXT)	;CLEAR TEXT FLAG
	JRST	LOOK		;CONTINUE

	SUBTTL	LOOK -- Send off OURBUF to all of our windows user's
LKSEND:	MOVE	T1,OURCNT	;GET COUNT
	SUBI	T1,OURSIZ*5-1	;GET CHARS PERSENT
	JUMPE	T1,CPOPJ	;IGNORE IF EMPTY
	SETZ	T0,		;NULL
	IDPB	T0,OURPNT	;TERMINATE TEXT
	MOVEI	T1,MS$TXT	;CONVERSATION TEXT
	HRROI	T2,OURBUF	;BUFFER
	CALL	SNDALL		;SEND TO ALL WINDOWS
	MOVE	T1,[POINT 7,OURBUF] ;TEXT BUFFER
	MOVEM	T1,OURPNT	;STORE
	MOVEI	T1,OURSIZ*5-1	;COUNT
	MOVEM	T1,OURCNT
	RET

	SUBTTL	LOOK -- Get a FAX character
LKFAX:	HRROI	T1,[ASCIZ '
**** Facsimile of ']
	CALL	FAXSTR
	TLNN	FL,(F$SERV)	;COULD THIS BE A DECNET CALL?
	 IFSKP.
	  HRROI	T1,OURNOD
	  CALL	FAXSTR
	  MOVEI	T1,":"
	  CALL	ECHO
	  MOVEI	T1,":"
	  CALL	ECHO
	 ENDIF.
	HRROI	T1,FAXFIL
	CALL	FAXSTR
	HRROI	T1,[ASCIZ ' ****
']
	CALL	FAXSTR
LKFAX0:	CALL	IPOFF		;KILL INTERUPTS
LKFAX1:	CALL	GETFAX		;GET A CHAR
	 JRST	FAXEOF		; EOF
	CAIN	T1,LF		;END OF LINE?
	 JRST	LKFAX2		; YES, SEND LINE, TOSS LF
	PUSH	P,T1		;SAVE IT
	CALL	ECHO		;ECHO IT
	POP	P,T1		;RESTORE THE CHAR
	CALL	LKPUT		;SEND IT
	JRST	LKFAX1		;LOOP

LKFAX2:	CALL	IPON		;BREATHE
	CALL	LKSEND		;SEND THE BUFFER
	CALL	$SIBE		;INPUT BUFFER EMPTY?
	 JRST	FAXCAN		; NO, CANCELED
	JRST	LKFAX0		;START AGAIN

FAXCAN:	HRROI	T1,[ASCIZ '
******************* FACSIMILE CANCELED *******************
']
	JRST	FAXDON

FAXEOF:	HRROI	T1,[ASCIZ '
******************* END OF FACSIMILE *******************
']

FAXDON:	CALL	FAXSTR
	CALL	IPON		;RESET IPCF INTERUPTS
	TLZ	FL,(F$FAX)	;CLEAR FAX MODE
	MOVE	T1,FAXJFN	;GET JFN
	CLOSF			;CLOSE IT
	 TRN			; SHHH
	JRST	LOOK		;START ANEW

; T1/	BP
FAXSTR:	CALL	CHKBT1		;CHECK FOR HRROI OR MOVEI
	MOVE	X1,T1		;SAVE BP
FXSTR1:	ILDB	T1,X1		;GET CHAR
	JUMPE	T1,LKSEND
	PUSH	P,T1		;SAVE THE CHAR
	CALL	ECHO
	POP	P,T1
	CALL	LKPUT
	JRST	FXSTR1

GETFAX:	MOVE	T1,FAXJFN	;GET FAXJFN
	BIN			;READ A CHAR (SLOWLY)
	 ERJMP	CPOPJ		; MUST BE END OF FILE!
	MOVE	T1,T2		;GET CHAR IN T1
	RETSKP			;HAPPY RETURN

	SUBTTL	LOOK -- User typed something
LKGET:	CALL	IPOFF		;KILL INTERUPTS
LKGET2:	PBIN			;GET CHARACTER
LKGOT:	CAIGE	T1," "		;PRINTABLE CHARACTER?
	 JRST	LKCTRL		; NO
	CAIN	T1,DEL		;RUBOUT?
	 JRST	LKDEL		; YES
	CAMN	T1,SWHOOK	;SWITCH-HOOK CHAR?
	 RET			; YES, RETURN
	PUSH	P,T1		;SAVE CHAR
	CALL	ECHO		;TYPE
	POP	P,T1		;RESTORE CHAR
	CALL	LKPUT		;AND STORE
LKGOT2:	CALL	$SIBE		;ANY MORE INPUT?
	 JRST	LKGET2		; YES
IFN SLPTIM,<
	MOVEI	T1,SLPTIM	;NO, SLEEP A LITTLE
	CALL	$HIBER		;ZZZ
	CALL	$SIBE		;ANY NOW?
	 JRST	LKGET2		;YES!
> ;IFN SLPTIM
	JRST	LOOK		;NO

	SUBTTL	LOOK -- Deposit a character to be sent
LKPUT:	TLO	FL,(F$TEXT)	;GOT SOME!!
	SOSGE	OURCNT		;KEEP COUNT
	 JRST [	PUSH  P,T1	;  SAVE CHAR
		CALL  LKSEND	;  SEND STUFF
		POP   P,T1	;  RESTORE
		JRST  LKPUT ]	;  TRY AGAIN
	IDPB	T1,OURPNT	;PUT IN BUFFER
	RET

	SUBTTL	LOOK -- Rubout was typed
LKDEL:	MOVE	T2,WNDCOL(W)	;GET COLM
	CAIG	T2,1		;NOT FIRST?
	 JRST	LKDINK		; IF TOO FAR, DINK THEM
	CALL	LKPUT		;SEND
	MOVEI	T1,DEL		;GET A NEW ONE
	CALL	ECHO		;TYPE IT
	JRST	LKGOT2

	SUBTTL	LOOK -- Ignore extra rubouts
LKDINK:	MOVEI	T1,1		;COLMN 1
	MOVEM	T1,WNDCOL(W)	;STORE
	MOVEI	T1,BEL
	CALL	PUTC		;DINK!
	JRST	LKGOT2		;CONTINUE

	SUBTTL	LOOK -- Some control character typed
; CONTROL-L SHOULD BE HANDLED HERE
LKCTRL:	CAIE	T1,CR		;CR?
	 IFSKP.
		PBIN		;YES, STEAL LF
		MOVEI	T1,CR	;GET A CR TO SEND
		JRST	LKCTR1	;DO STUFF
	 ENDIF.
	CAIE	T1,TAB
	 IFSKP.
		MOVE	X1,WNDCOL(W) ;GET COLM
		ADDI	X1,^D8	;ADD TAB
		TRZ	X1,7	;MODULO
		SUB	X1,WNDCOL(W) ;GET AMOUNT TO MOVE
		MOVEI	T1," "	;GET A SPACE
		DO.
			CALL	LKPECH
			SOJGE	X1,TOP.
		ENDDO.
		JRST	LOOK	;START ALL OVER
	 ENDIF.
	CAIN	T1,"W"-100	;^W ??
	 MOVEI	T1,LF		; SEND <LF> INSTEAD
; PERHAPS DUMP UNWANTED CHARACTERS HERE (IE; ^E ....)
LKCTR1:	CALL	LKPECH		;PUT AND ECHO
	JRST	LOOK

LKPECH:	PUSH	P,T1
	CALL	LKPUT
	POP	P,T1
	PJRST	ECHO
	ENDAV.			;{X1}
	SUBTTL	Position self

POSION:	ACVAR	<X1,X2>
	MOVE	X1,WNDLIN(W)	;GET LINE
	ADD	X1,WNDORG(W)	;ADD WINDOW ORIGIN
	SUBI	X1,1		;MAKE 1 BASED
	MOVE	X2,WNDCOL(W)	;AND COLM
	TTY	<MVX,X1,X2>	;MOVE, INDIRECT
	RET
	ENDAV.

	SUBTTL	PHONE ERROR MESSAGES

; T1/	PROTOCOL ERROR CODE
;	CALL	ERRPHN
;	<ALWAYS>

ERRPHN:	PUSH	P,T1		;SAVE CODE
	CALL	ERRLIN		;GOTO ERROR LINE
	POP	P,T2		;RESTORE CODE
	HRRO	T1,PHNTAB(T2)	;GET MESSAGE
	MOVEM	T1,LSTERR	;SAVE
	TRNE	T1,-1		;ANY MESSAGE?
	 PSOUT			; YES, TYPEIT

; MAKE CALL TO HERE AFTER DISPLAY OF ERROR
ENDERR:	TTY	<ERL>		;CLEAR REST OF LINE
	MOVE	T1,ERRPSE	;PAUSE INTERVAL
	CALL	$HIBER
	RET

	SUBTTL	GOTO ERROR LINE
ERRLIN:	TTY	<MOV,2,1>
	RET

	SUBTTL	GOTO PROMPT LINE
PMTLIN:	TTY	<MOV,3,1>
	RET

PHNTAB:	[ASCIZ '?Some error occured']
	[0]
	[ASCIZ '?User identification syntactically invalid']
	[ASCIZ '?Slave error']
	[ASCIZ '?Missing user name']
	[ASCIZ '?Slave is not privileged']
	[ASCIZ '?User does not exist']
	[ASCIZ '?User is not at a PHONE']
	[ASCIZ '?User has logged off']
	[ASCIZ "?User's PHONE is off the hook"]
	EXP	UNK,UNK,UNK

UNK:	ASCIZ	'?Illegal status code returned'
	SUBTTL	PARSE -- ROUTE STRING

;Take a route to a host, and fix so it looks like our route for it
;Assumes data of form {[_]NODE::}
; ie; converts	A::B::C::
; to		B::A::
;  C:: is dropped since it will be the target node of the link.
; T1/	BP to dest
; T2/	BP to source
REVRUT:	CALL	CHKBPS		;CONVERT -1,,N TO BP
	CALL	REVRU2
	 TRN
	SETZ	T3,
	IDPB	T3,T1
	RET

; Recursive helper
REVRU2:	STKVAR	<<BUF,5>>
	MOVEI	T4,BUF
	HRLI	T4,(POINT 7,)
	SETZM	BUF
	ILDB	T3,T2		;GET FIRST
	CAIN	T3,"_"		;VAX QUOTE CHAR?
REV.1:	 ILDB	T3,T2		; YES, GET NEXT CHAR
	JUMPE	T3,CPOPJ	;END OF STRING???
	CAIN	T3,":"		;END OF NODE?
	 JRST	REV.2
	IDPB	T3,T4
	JRST	REV.1
REV.2:	ILDB	T3,T2		;GET NEXT BYTE (SECOND COLON)
	SETZ	T3,
	IDPB	T3,T4		;TIE OFF BUFFER
	CALL	REVRU2		;PARSE NEXT NODE
	 RETSKP			; GOT EOS?
	SKIPN	BUF		;GOT A NODE?
	 RET			; NOPE.
	HRROI	T2,BUF		;GET PTR TO STRING
	CALL	CPYTXT		;COPY IN
	MOVEI	T2,":"
	IDPB	T2,T1
	IDPB	T2,T1
	RETSKP
	ENDAV.
	SUBTTL	PARSE -- USER ID STRING

;Parse user id string from another user
;Assumes data of form {[_]NODE::}[_]OURNODE::LUSER
; T1/	bp to user id
;	CALL	GETUSR
;	 <failed to parse>
;	<ok>
; T2/	BP to USER
; T3/	BP to last NODE::
; T4/	flag,,count
GETUSR:	CALL	CHKBT1		;CHECK BP IN T1
	MOVE	T3,T1		;SETUP BP TO BEFORE LAST NODE::
	MOVE	T2,T1		;SETUP BP TO AFTER END OF LAST NODE::
	SETZ	T4,		;ZERO COUNT
;Here to start field
GU.1:	ILDB	T0,T1		;GET NEXT CHAR
	CAIE	T0,"_"		;VAX QUOTE CHAR?
	 JRST	GU.2		; NO, CHECK IT OUT
	MOVSI	T4,1		;ZERO COUNT, SET NODE FLAG
;Here to parse text
GU.L:	ILDB	T0,T1		;GET ANOTHER
GU.2:	JUMPE	T0,GU.3		;END OF STRING
	CAIE	T0,":"		;A COLEN?
	 AOJA	T4,GU.L		; NO, KEEP LOOKING
	ILDB	T0,T1		;GET NEXT BYTE
	CAIN	T0,":"		;BETTER BE A ":"
	 TRNN	T4,-1		; YES, ANY COUNT?
	  RET			;  NO; NULL FIELD, OR ONLY ONE ":"
	MOVE	T3,T2		;SAVE START OF LAST NODE
	MOVE	T2,T1		;MIGHT BE LAST NODE IN LIST, SAVE BP TO USER
	SETZ	T4,		;ZERO COUNT
	JRST	GU.1		;START AGAIN

GU.3:	TLNN	T4,1		;LAST FIELD HAVE AN "_" ?
	 CAMN	T2,T3		; NO, PARSE ANYTHING?
	  RET			;  NOTHING PARSED OR USER BEGAN WITH "_"
	TRNN	T4,-1		;EMPTY FIELD?
	 RET			; YES. (FOO::)
	RETSKP
	SUBTTL	LINKS -- MAKE A CONNECTION

;Make a connection on current link
; T1/	user id
; I/	link ptr
;	CALL	MAKCON
;	 <lose, error string in T1>
;	<win, type and 'JFN' set up>
MAKCON:	STKVAR	<<TARGET,10>,SAVCON,SAVUSR,SAVUNO>; BUFFER, DN.HST, BP, USRBP
	MOVEM	T1,SAVUSR	;SAVE USER
	CALL	GETUSR		;PARSE
	 JRST	MK.BD		; BAD
	MOVEM	T2,SAVUNO	;SAVE BP TO USER
	MOVE	T1,[POINT 7,TARGET] ;TARGET NODE
MK.L:	ILDB	T0,T3		;GET BYTE
	CAIN	T0,":"		;END OF NODE
	 JRST	MK.E		; YES
	IDPB	T0,T1		;COPY
	JUMPN	T0,MK.L		;LOOP UNTIL EOS
MK.BD:	HRROI	T1,[ASCIZ "Bad user string"]
	RET			;ERROR

MK.E:	SETZ	T0,		;NULL
	IDPB	T0,T1

IFN LOCALF,<
	HRROI	T1,TARGET	;GET BP
	HRROI	T2,OURNOD	;OUR NODE
	CALL	CMPSTR		;MAKE LOCAL CONNECTION?
	 JRST	MK.DCN		; NO

	MOVSI	T1,(RC%EMO)	;GET EXACT MATCH
	MOVE	T2,SAVUNO	;GET BP
	SETZ	T3,
	RCUSR			;GET OPERATOR USER NUMBER
	 ERJMP	MK.UNK		; UNKNOWN
	JUMPE	T3,MK.UNK	;DITTO
	MOVEM	T3,LNKUNO(I)	;SAVE USER NUMBER

	MOVEI	T1,LT$LCL	;LINK TYPE
	HRRM	T1,LNKFLG(I)	;STORE
	SETZM	LNKJFN(I)	;NO PID AS YET
	RETSKP

MK.UNK: HRROI	T1,[ASCIZ 'User does not exist']
	RET
> ;IFN LOCALF

MK.DCN:	MOVEI	T1,LT$DCN	;DECNET
	HRRM	T1,LNKFLG(I)	;STORE
	HRROI	T1,TARGET
	PJRST	OPNCON
	ENDAV.
	SUBTTL	LINKS -- OPEN A DECNET CONNECTION
; T1/	BP TO HOST
; I/	PTR TO LINK
;	CALL	OPNCON
;	 <ERROR, BP IN T1>
;	<AOK, LINK JFN AND ROUTE SET UP>
;
OPNCON:	STKVAR	<HOSTBP,SAVEBP>	;HOST BP, SAVED HOST
	MOVEM	T1,HOSTBP	;SAVE BP

; Here to create DECnet link.  Node is in TARGET.
OP.DCN:	MOVE	T1,CONBLK+DN.HST ;SAVE OLD HOST PTR
	MOVEM	T1,SAVEBP	;SAVE
	MOVE	T1,HOSTBP	;GET TARGET NODE
	MOVEM	T1,CONBLK+DN.HST ;STORE FOR DNCONN
	MOVEI	T1,CONBLK	;GET CONNECT BLOCK
	SETZ	T2,
	CALL	.DNCON##	;TRY TO CONNECT
	 JRST [	MOVE	T2,SAVEBP ;GET OLD HOST
		MOVEM	T2,CONBLK+DN.HST ;RESTORE
		RET ]		;RETURN ERROR (STRING IN T1)

	MOVEM	T1,LNKJFN(I)	;SAVE JFN
	HRROI	T1,LNKRUT(I)	;WHERE TO STORE RETURN ROUTE
	CAIN	T2,0		;GET A ROUTE?
	 SKIPA	T2,[-1,,[0]]	;GET BOGUS ROUTE
	  HRROI	T2,2(T2)	;GET BP TO ROUTE

	CALL	REVRUT		;STORE INVERSE ROUTE
	MOVE	T2,SAVEBP	;GET OLD HOST
	MOVEM	T2,CONBLK+DN.HST ;RESTORE CONNECT BLOCK
	RETSKP
	ENDSV.
	SUBTTL	LINKS -- MAKE A MESSAGE

; T1/	Message code
; T2/	BP to data or 0
; I/	Link
;	CALL	MAKMSG
MAKMSG:	ACVAR	<COD>		;SAVE CODE
	MOVEM	T1,LSTCOD	;STORE LAST CODE SENT
	MOVE	COD,T1		;SAVE LAST CODE
	PUSH	P,T2		;SAVE DATA
	HRRZ	T2,LNKFLG(I)	;GET LINK TYPE
	MOVE	T2,[POINT 8,LNKSND(I) ;BP FOR DECNET
		    POINT 8,SNDADR    ;BP FOR IPCF
		   ](T2)	;GET BP
	IDPB	COD,T2		;STORE CODE

	HRROI	T1,LNKRUT(I)	;GET ROUTE BACK TO US
	CALL	CPYSTR		;COPY IT IN
	HRROI	T1,US		;STRING FOR US
	CALL	CPYST0		;COPY IN
	POP	P,T1		;RESTORE DATA, IF ANY
	JUMPE	T1,CPOPJ	;NONE? DONE!
	CAIE	COD,MS$RNG	;RING MESSAGE?
	 PJRST	CPYSTR		; NO, BE SLOPPY
	CALL	CHKBT1		;MAKE SURE WE HAVE A BP
	ILDB	T1,T1		;GET JUST ONE BYTE
	IDPB	T1,T2		;STORE IS MESSAGE
	RET			;DONE!
	ENDAV.			;{COD}

	SUBTTL	LINKS -- SEND A MESSAGE, W/ STATUS

;Send a message
; T1/	Code
; T2/	BP to data
; I/	Link
;	CALL	SNDMSG
;	 <error>
;	<ok>
; T1/	Status
; T2/	BP to data
; T3/	Count
SNDMSG:	PUSH	P,T1		;SAVE CODE
	CALL	MAKMSG		;CREATE MESS
	PUSH	P,T2		;SAVE BP
	CALL	IPOFF		;PROTECT AGAINST PI
	POP	P,T2
	POP	P,T1		;RESTORE CODE
	HRRZ	T5,LNKFLG(I)	;GET LINK TYPE
	CALL @[	SM.DCN		;  DECNET CONNECTION
		SM.LCL ](T5)	;  LOCAL CONNECTION (IPCF)
	PUSH	P,T1		;SAVE STATUE
	PUSH	P,T2		;SAVE BP
	CALL	IPON
	POP	P,T2
	POP	P,T1
	CAIN	T1,ST$AOK	;OK?
	 RETSKP
	RET
	SUBTTL	LINKS -- SEND HANGUP AND CLOSE

;Send hangup and Close link
; no args
CLSHUP:	MOVEI	T1,MS$HUP	;HANG UP
	SETZ	T2,		;NO DATA

	SUBTTL	LINKS -- SEND ANY MESSAGE AND CLOSE
;Close link with final message
; T1/	CODE
; T2/	DATA
CLSMSG:	PUSH	P,T1		;SAVE MESS
	CALL	SNDMSG		;SEND FINAL MESSAGE
	 TRN
	POP	P,T1		;RESTORE MESS
	CAIN	T1,MS$DON	; DONE?
	 PJRST	CLSDON		;YES, SO ARE WE
	MOVEI	T1,MS$DON	;SEND DONE
	SETZ	T2,		;NO DATA
	CALL	SNDMSG		;SHOVE IT OFF
	 TRN			; IGNORE
	TRNA
SNDERR:	 CALL	ERRPHN		;NO, TYPE ERROR
CLSDON:	HRRZ	T1,LNKFLG(I)	;GET LINK TYPE
	CAIE	T1,LT$DCN	;DECNET LINK?
	 JRST	CLS.1		; NO, JUST FREE THE BLOCK
	MOVE	T1,LNKJFN(I)	;GET LINK JFN
	TLO	T1,(CZ%ABT)	;ABORT LINK
	CLOSF
	 ERJMP	.+1

CLS.1:	SETZM	LNKJFN(I)	;CLEAR JFN / PID
	MOVE	T1,I
	PJRST	FRELNK
	SUBTTL	LINKS -- CREATE NEW LINK BLOCK

;Create a new Link block
; T1/	BP to user
;	CALL	NEWLNK
NEWLNK:	PUSH	P,T1		;SAVE USER
	CALL	GETLNK

	HRROI	T2,LNKUSR(T1)	;GET ADDR FOR USER
	EXCH	T1,(P)		;GET USER NAME
	CAIE	T1,0		;NULL?
	CALL	CPYST0		; NO, COPY IN
	POP	P,T1		;RESTORE LINK

	SETOM	LNKHLD(T1)	;CLEAR HOLD LEVEL
	RET

	SUBTTL	LINKS -- CREATE A NEW LINK AND CONNECT IT

;Create new link & connect to it
; T1/	BP to user
;	CALL	MAKLNK
;	 <nope>
;	<yep>
; T1/	^LINK
MAKLNK:	STKVAR	<USR,LNK>
	MOVEM	T1,USR		;SAVE USER NAME
	MOVEM	I,LNK		;SAVE CURRENT LINK
	CALL	NEWLNK		;MAKE LINK
	MOVE	I,T1		;GET NEW LINK
	MOVE	T1,USR		;GET USER
	CALL	MAKCON		;MAKE CONNECTION
	 JRST	MKL.ER		; SIGH
	MOVEI	T1,MS$CHK	;CHECK USER
	MOVE	T2,USR		;GET USER
	CALL	SNDMSG		;SEND IT OFF
	 JRST [	HRRO T1,PHNTAB(T1) ;GET ERROR
		JRST MKL.ER ]
	AOS	(P)		;HAPPY RETURN
	MOVE	T1,I		;RETURN LINK
	TRNA
MKL.ER:	 MOVEM	T1,LSTERR	;SAVE ERROR BP
	MOVE	I,LNK		;RESTORE LINK
	RET
	ENDSV.
	SUBTTL	LINKS -- SAVE A LINK IN LINK TABLE

; T1/	LINK
SAVLNK:	MOVSI	T2,-MAXLNK	;SEARCH ALL LINKS
SV.LP1:	SKIPE	T3,LNKTAB(T2)	;EMPTY?
	 CAME	T1,T3		; ALREADY EXISTS?
	  AOBJN	T2,SV.LP1	;KEEP LOOKING
	JUMPL	T2,SV.SKP	;FOUND!

	MOVSI	T2,-MAXLNK	;SEARCH ALL LINKS
SV.LOP:	SKIPE	LNKTAB(T2)	;EMPTY?
	 AOBJN	T2,SV.LOP	; NO
	JUMPGE	T2,CPOPJ	;NO FREE SLOTS
	MOVEM	T1,LNKTAB(T2)	;STORE
SV.SKP:	RETSKP

	SUBTTL	LINKS -- SEARCH FOR A USER

; T1/	user
FNDLNK:	ACVAR	<X1,X2>
	MOVE	X2,T1		;SAVE USER
	MOVSI	X1,-MAXLNK	;FOR ALL LINKS
FL.LOP:	SKIPN	T1,LNKTAB(X1)	;GET LINK, IF ANY
	 JRST	FL.BOT		; NONE
	HRROI	T1,LNKUSR(T1)	;GET USER
	MOVE	T2,X2		;GET TARGET
	CALL	CMPSTR		;NO, COMPARE
	 TRNA			; NO MATCH
	  JRST	FL.WIN		;  A WINNER!
FL.BOT:	AOBJN	X1,FL.LOP	;NO, GUESS AGAIN
	RET			;YOU LOSE
FL.WIN:	MOVE	T1,LNKTAB(X1)	;RETURN LINK
	RETSKP
	ENDAV.
	SUBTTL	DECNET -- COUNT AND SEND MESSAGE

;Output text in LNKSND(I) to DECnet
; T2/	updated BP
; I/	link index
;	CALL	DECOUT

DECOUT:	MOVEI	T1,@T2		;GET THE ADDRESS PART OF NEW BP
	SUBI	T1,LNKSND(I)	;GET THE DIFFERENCE
	ASH	T1,2		;MAKE IT INTO 8 BIT BYTE COUNT
	MOVE	T4,T2		;PRESERVE THE BYTE POINTER

	LDB	T2,[POINT 6,T4,6+5] ;GET S FIELD OF BYTE POINTER
	CAIE	T2,^D8		;IS IT EIGHT BITS?
	 FATAL	(BP not 8 bit)	; YOU LOSE

	LDB	T2,[POINT 6,T4,5] ;GET P FIELD OF BYTE POINTER
	SUBI	T2,4		;P STARTS AT THE RIGHT
	ASH	T2,-3		;DIVIDE BY EIGHT
	SUBI	T2,4		;REVERSE THE ORDER
	SUB	T1,T2		;FIGURE OUT THE FINAL COUNT
	MOVNI	T3,(T1)		;PREPARE FOR SOUT

	SUBTTL	DECNET -- SEND COUNTED MESSAGE

;Send counted text in LNKSND(I) via DECnet
; T3/	-count
; I/	link ptr
DECCNT:	SKIPN	T1,LNKJFN(I)	;DECNET JFN
	 RET			; IGNORE IF NO JFN
	MOVE	T2,[POINT 8,LNKSND(I)] ;SEND BUFFER
	SOUTR			;OUTPUT RECORD
	 ERJMP	.+1
	RET
	SUBTTL	DECNET -- GET TEXT WITH TIMEOUT

;Get text from DECnet
; I/	link
;	CALL	DECIN
; T1/	Status Code
; T2/	BP to data
; T3/	Byte count

WAIT4==^D10			;THIS MANY SECONDS TOTAL
WAITIN==^D100			;IN THIS INCREMENT (IN MS.)

DECIN:	MOVE	T1,LSTCOD	;GET LAST CODE FROM MAKMSG
	CAIE	T1,MS$CHK	;CHECK?
	 CAIN	T1,MS$RNG	; OR RING?
	  TRNA			;  OK
	   RET			;   HUH????
	CALL	$UPTIME		;GET UPTIME IN MS
	MOVE	T4,T1		;COPY
	ADDI	T4,WAIT4*^D1000	;WAIT TILL THEN
DECINC:	SKIPG	T1,LNKJFN(I)	;GET NET JFN
	 JRST	DECIER		; NONE!
	SIBE			;ANY DATA (0 LENGTH RECORD NEVER SEEN!!!)
	 JRST	DECINW		; YES, GOT IT!!
	CALL	$UPTIME		;GET SYSTEM UPTIME
	CAML	T1,T4		;TIME RUN OUT?
	 JRST	DECIER		; YES, TIMEOUT
	MOVEI	T1,WAITIN
	CALL	$HIBER
	JRST	DECINC		;LOOK AGAIN

	SUBTTL	DECNET -- GET MESSAGE W/O TIMEOUT

DECINW:	SKIPG	T1,LNKJFN(I)	;GET NET JFN
	 JRST	DECIER		; NONE!!!
	MOVE	T2,[POINT 8,LNKRCV(I)] ;PUT IN RECIEVE BUFFER
	MOVNI	T3,BUFSIZ	;COUNT
	SINR			;READ A RECORD
	 ERJMP	DECIER		; I/O ERROR
	  JRST	DECIOK

DECIER:	SETZM	LNKRCV(I)	;CLEAR BUFFER
	MOVEI	T1,ST$AOK	;ASSUME OK
	MOVEI	T2,LNKRCV(I)	;GET ADDR
	HRLI	T2,(POINT 8,)	;MAKE INTO BP
	SETZ	T3,		;PRETEND WE READ NADA
	RET

DECIOK:	SETZ	T1,		;GET NULL
	IDPB	T1,T2		;TIE OFF STRING
	MOVEI	T2,LNKRCV(I)	;GET ADDR
	HRLI	T2,(POINT 8,)	;MAKE INTO BP
	ADDI	T3,BUFSIZ	;GET COUNT
	MOVEI	T1,ST$OTH	;OTHER ERROR
	JUMPE	T3,CPOPJ	;RETURN ERROR STATUS
	LDB	T1,[POINT 8,LNKRCV(I),7] ;GET STATUS
	RET
	SUBTTL	DECNET -- SEND A MESSAGE, W/ STATUS

; SEND MESSAGE OVER DECNET
; T1/	MESSAGE CODE
SM.DCN:	PUSH	P,T1		;SAVE CODE
	CALL	DECOUT		;SEND
	POP	P,T1		;RESTORE CODE
	CAIE	T1,MS$CHK	;CHECK USER?
	 CAIN	T1,MS$RNG	; OR RING?
	  PJRST	DECIN		;GET STATUS W/ TIMEOUT???
	MOVEI	T1,ST$AOK	;ELSE RETURN FINE
	RET

	SUBTTL	LOCAL -- SEND A MESSAGE, W/ STATUS

; SEND MESSAGE (AT SNDADR) VIA IPCF
SM.LCL:	LDB	T1,[POINT 8,SNDADR,7] ;GET CODE
	SKIPN	T1,LCLTAB(T1)	;GET ROUTINE
	 PJRST	RETAOK		; RETURN AOK!
	PJRST	(T1)		;HANDLE LOCAL MESSAGE

LCLTAB:	PHASE	0		;*** FUNCTION DISPATCH ***
	ACTION	MS$CHK,LCHECK	;Check out user
	ACTION	MS$RNG,LRING	;Ring phone
	ACTION	MS$HUP,FORWRD	;Remote has hung up
	ACTION	MS$BSY,FORWRD	;Master is busy
	ACTION	MS$ANS,FORWRD	;Phone answered
	ACTION	MS$REJ,FORWRD	;Call rejected
	ACTION	MS$TXT,FORWRD	;Conversation text
	ACTION	MS$3RD,FORWRD	;Add third party
	ACTION	MS$HLD,FORWRD	;Put PHONE on hold
	ACTION	MS$OFF,FORWRD	;Take PHONE off hold
MAXDSP==.-1
	DEPHASE

; HERE TO SEND DATA IN SNDPAG
FORWRD:	SKIPE	T1,LNKJFN(I)	;GET PID
	 CALL	SIPCF		; SEND IPCF PAGE
RETOTH:	  TDZA	T1,T1		;  "SOME OTHER ERROR"
RETAOK:	   MOVEI T1,ST$AOK	;   "ALL OK"
	RET
	SUBTTL	LOCAL -- CHECK FOR USER

; I/	^LINK W/ USER# FILLED IN
LCHECK:	ACVAR	<X1,X2>		;LOOP VAR, ERROR REASON, IF ANY
	SKIPN	LNKUNO(I)	;CHECK FOR USER NUMBER
	 JRST	RETOTH		; SHOULD NEVER HAPPEN
	MOVE	X1,JOBAOB	;GET JOB AOBJN
	MOVEI	X2,ST$UNE	;DEFAULT REASON: USER DOES NOT EXIST
LCH.1:	MOVEI	T1,(X1)		;GET JOB
	MOVE	T2,[-2,,T4]	;RETURN IN T4, T5
	MOVEI	T3,.JITNO	;RETURN TTY, USER NUMBER
	GETJI			;GET JOB INFO
	 JRST	LCH.B		; NO JOB
	JUMPL	T4,LCH.B	;DETACHED?
	CAME	T5,LNKUNO(I)	;RIGHT STUFF?
	 JRST	LCH.B		; NOPE
	MOVEI	T1,.TTDES(T4)	;GET TTY DESC
	GTTYP			;GET TTY TYPE
	 IFJER.
		MOVEI	X2,ST$SNP ;SLAVE LACKS PRIVS
		JRST	LCH.B	;LOOP
	 ENDIF.
	SKIPE	VTXDSP(T2)	;CHECK IF GOOD TTY TYPE
	 IFSKP.
		MOVEI	X2,ST$TTY ;LOSING TTY TYPE
		JRST	LCH.B	;LOOP
	 ENDIF.
	MOVEI	T1,.TTDES(T4)	;GET TTY DESC
	CALL	CHKLNK		;CHECK IF OFF THE HOOK
	 SKIPA	X2,[ST$OFF]	; YES
	  JRST	LCH.U		;  NO!! WE HAVE A WINNER!
LCH.B:	AOBJN	X1,LCH.1	;LOOP
	MOVE	T1,X2		;GET REASON
	RET			;AND FAIL

; THERE EXISTS AT LEAST ONE GOOD JOB: DOES ONE HAVE THE PID?
LCH.U:	CALL	FNDUNO		;FIND PID
	 TRNA
	  MOVEM	T1,LNKJFN(I)	;FOUND! - SAVE IT (WHAT ABOUT OLD VALUE?)
	MOVEI	T1,ST$AOK
	RET
	ENDAV.
	SUBTTL	LOCAL -- RING

; I/	^LINK
; AREA IS NON-ZERO ON FIRST RING
LRING:	CALL	FNDUNO		;CHECK FOR A PID
	 JRST	RG.MES		; NONE, JUST SEND VIA TTMSG
	PUSH	P,T1		;SAVE NEW PID

	CALL	CHKPID		;FIND OWNER
	 SETO	T1,		; LOSER
	MOVEM	T1,LNKJOB(I)	;SAVE, TO AVOID DOING LOCAL SENDS TO OWNER

	POP	P,T1		;RESTORE PID
	CAMN	T1,LNKJFN(I)	;SAME PID AS LAST TIME?
	 JRST	RG.FWD		; YES, JUST FORWARD

;Here with a new PID
	MOVEM	T1,LNKJFN(I)	;NO, SAVE NEW PID
	SKIPN	T1,AREA		;WAS SOME PAST RING THE FIRST?
	 JRST	RG.FWD		; NO, THIS ONE *SHOULD* BE

;Here with a new PID, after first ring sent: forward with flag set
	MOVSI	T1,(<BYTE(7)1>)	;FIRST RING FLAG
	MOVEM	T1,AREA		;STORE

;Here to send an IPCF ring
RG.FWD:	CAIE	T1,0		;WAS THIS RING THE FIRST?
	 CALL	LCLRNG		; YES, DO LOCAL RING FIRST
	  TRN			;  NO+IGNORE ERROR
	MOVEI	T1,MS$RNG	;RING
	HRROI	T2,AREA		;NEW DATA
	CALL	MAKMSG		;CREATE MESS
	CALL	FORWRD		;SEND!
	 TRN
	RET

RG.MES:	CALL	LCLRNG		;DO LOCAL RING
	 TRN
	RET
	SUBTTL	LOCAL -- SEND RING TEXT

;Creates message text in TMPSTR buffer and send to all suitable users
;	CALL	LCLRNG
;	 <LOSS>
;	<AOK>
; T1/	STATUS
LCLRNG:	ACVAR	<X1,X2,X3>
	HRROI	T1,TMPSTR	;POINT TO BUFFER
	HRROI	T2,[BYTE(7)CR,LF,0]
	CALL	CPYTXT
	HRROI	T2,OURNAM	;OUR NAME
	CALL	CPYTXT
	MOVEI	T2,[ASCIZ/ is calling you at /]
	CALL	CPYTXT
	TLNN	FL,(F$DECN)	;HAVE NETWORK?
	 IFSKP.
		MOVEI	T2,OURNOD	;NODE NAME
		CALL	CPYTXT
		MOVEI	T2,[ASCIZ/ on /]
		CALL	CPYTXT
	 ENDIF.
	SETOB	T2,T3		;NOW, FANCY
	ODTIM			;OUTPUT
	 ERJMP	.+1		; FUEY!
	MOVEI	T2,[BYTE(7) BEL,BEL,BEL,CR,LF,0] ;DING**3, CRLF
	CALL	CPYTXT

;Now loop for all jobs, and blat the OK ones.
LR.BEG:	MOVE	X1,[1-MAXJOB,,1] ;AOBJN COUNT
	SETZB	X2,X3		;COUNT OF MATCHES, SENDS
LR.LOP:	MOVEI	T1,(X1)		;GET JOB
	MOVE	T2,[-.JISTM-1,,GJIBLK] ;BUFFER
	SETZ	T3,		;START AT JOB
	GETJI			;GET INFO
	 JRST	LR.BOT		; U LOSE

	MOVE	T2,LNKUNO(I)	;GET USER NUMBER
	CAME	T2,GJIBLK+.JIUNO ;MATCH
	 JRST	LR.BOT		; NO, KEEP LOOKIN

	SKIPG	T1,GJIBLK+.JITNO ;CHECK TERMINAL NUMBER
	 JRST	LR.BOT		; DETACHED
	ADDI	X2,1		;INCR MATCHES

	MOVE	T2,LNKJOB(I)	;GET JOB
	CAIN	T2,(X1)		;MATCH?
	 SKIPE	AREA		; FIRST RING?
	  TRNA			;  NO MATCH, OR FIRST RING
	   JRST	LR.BOT		;   MATCH, NOT FIRST RING, DON'T SEND

	MOVE	T1,GJIBLK+.JITNO ;GET TTY AGAIN
	MOVEI	T1,.TTDES(T1)	;MAKE DEVICE
	HRROI	T2,TMPSTR	;GET TEXT
	TTMSG			;SHOVE BELOW SPY LEVEL
	 ERJMP [SETZ	T3,	; TERMINATE ON ZERO.
		SOUT		; TRY WITH SOUT
		 ERJMP	.+1	; IGNORE ERROR
		JRST	.+1 ]	;KEEP GOING
	ADDI	X3,1		;INCR SENDS
LR.BOT:	AOBJN	X1,LR.LOP	;...LOOP FOR ALL JOBS
	MOVEI	T1,ST$AOK	;GET GOOD STS
	JUMPN	X3,CPOPJ1	;AOK IF ANY SENDS DONE
	MOVEI	T1,ST$TTY	;ASSUME BAD TTY
	CAIG	X2,0		;ANY MATCHES?
	 MOVEI	T1,ST$LOG	; NO, "USER LOGGED OFF"
	RET
	ENDAV.
	SUBTTL	LOCAL -- DIRECTORY

LDIR:	SETZ	T5,		;COLM
	MOVE	T4,[440700,,TMPSTR]
	AOS	T1,JOBNUM	;GET NEXT JOB NUMBER
	CAILE	T1,MAXJOB	;IN RANGE?
	 JRST [	SETZ	T3,	; ZERO LENGTH
		RET ]		;RETURN
	MOVE	T2,[-.JIBAT-1,,GJIBLK] ;WHAT TO STORE WHERE
	SETZ	T3,		;START AT BEGINING
	GETJI			;GET JOB INFO
	 JRST	LDIR		;NO JOB, GET NEXT
	SKIPE	T1,GJIBLK+.JIUNO ;LOGGED IN?
	 CAMN	T1,OPRUNO	; SKIP <OPERATOR>
	  JRST	LDIR		;  GET ANOTHER
	SKIPN	GJIBLK+.JIBAT	;BATCH?
	 SKIPGE	GJIBLK+.JITNO	; ATTACHED?
	  JRST	LDIR		;  RE-JECT

	MOVE	T2,GJIBLK+.JIPNM ;PROGRAM NAME?
	CALL	SIXTYP		;TYPE "PROCESS NAME"
	MOVEI	T1,"I"-100	;TAB
	CALL	COLTYP		;OUTPUT
	CALL	COLTYP		;AGAIN
	HRROI	T1,TEMP2	;BP
	MOVE	T2,GJIBLK+.JIUNO ;GET USER NUMBER AGAIN
	DIRST			;CONVERT TO STRING
	 ERJMP	LDIR		;SIGH!
	SETZ	T2,		;GET A NULL
	IDPB	T2,T1		;TIE OFF STRING
	MOVEI	T2,TEMP2	;GET NAME
	CALL	STRTYP		;OUTPUT IT
	MOVEI	T1," "		;TERMINATE WITH A SPACE
	CALL	COLTYP		;TA DAH
	MOVEI	T1,"I"-100	;GET A TAB
PADLOP:	CAIGE	T5,^D32		;THERE YET?
	 JRST [ CALL	COLTYP	;PAD WITH TABS
		JRST	PADLOP ] ;CONTINUE

	MOVE	T2,GJIBLK+.JITNO ;GET TERMINAL NUMBER
	MOVEI	T1,.TTDES(T2)	;GET DEVICE DESC
	GTTYP			;GET TYPE
	 ERJMP	UNUSE		; SIGH
	SKIPN	VTXDSP(T2)	;KNOWN?
UNUSE:	 JRST	[MOVEI	T2,[ASCIZ/unusable	---/]
		 JRST	DIRR2]

;;;	MOVE	T1,GJIBLK+.JITNO ;GET TERMINAL NUMBER
	MOVEI	T2,[ASCIZ /TTY/] ;ASS-U-ME IT IS A TTY
;;;	CAML	T1,PTYPAR	;IS IT A PTY?
;;;	 MOVEI	T2,[ASCIZ /PTY/] ; YES...
	CALL	STRTYP		;WRITE PREFIX
	MOVE	T2,GJIBLK+.JITNO ;GET TTY NUMBER
;;;	CAML	T2,PTYPAR	;A PTY?
;;;	 SUB	T2,PTYPAR	; YES, REMOVE OFFSET
	CALL	OCTTYP		;OUTPUT NUMBER
	MOVE	T1,GJIBLK+.JITNO ;GET TERMINAL NUMBER
	MOVEI	T1,.TTDES(T1)	;GET TERMINAL DEVICE DESC
	CALL	CHKLNK		;ALLOW LINKS ?
	 SKIPA	T2,[[ASCIZ "		refuse links/user messages"]]
	  MOVEI	T2,[ASCIZ  "		available"]
DIRR2:	CALL	STRTYP
DIRR3:	SETZ	T1,
	CALL	COLTYP
	MOVE	T2,[POINT 7,TMPSTR]
	MOVEI	T3,^D69		;RETURN W/ LENGTH
	RET

; T2/	ADDR OF ASCIZ STRING
STRTYP:	HRLI	T2,(POINT 7,)
STRTY2:	ILDB	T1,T2
	JUMPE	T1,CPOPJ
	CALL	COLTYP
	JRST	STRTY2

; T2/	SIXBIT
SIXTYP:	MOVEI	T3,6
SIXTY2:	SETZ	T1,
	LSHC	T1,6
	ADDI	T1," "
	CALL	COLTYP
	SOJG	T3,SIXTY2
	RET

; T2/	OCTAL
OCTTYP:	IDIVI	T2,10
	HRLM	T3,(P)
	CAIE	T2,0
	 CALL	OCTTYP
	HLRZ	T1,(P)
	ADDI	T1,"0"
COLTYP:	IDPB	T1,T4
	CAIE	T1,"I"-100
	 AOJA	T5,COLRET
	ADDI	T5,^D8
	TRZ	T5,^D8-1
COLRET:	RET

; CHECK IF TTY OFF THE HOOK
; T1/	TTY DES
;	CALL	CHKLNK
;	 <OFF THE HOOK>
;	<IN A SOCIABLE MOOD>
CHKLNK:	MOVEI	T2,.MORTF	;NEW FANGLED TERMINAL BITS
	MTOPR			;READ THEM
	 ERJMP	CHKLN2		; OLD MONITOR?
	TRNE	T3,MO%NUM+MO%NTM ;USER MESS/NON-JOB OUTPUT SUPRESS?
	 RET			; YES, THATS FINAL
	JRST	CPOPJ1		;** NO, IGNORE LINKS BIT

CHKLN2:	RFMOD			;GET TERMINAL JFN MODE WORD
	 ERJMP	CPOPJ		;WHOOPS!
	TRNE	T2,TT%ALK	;ALLOW LINKS ?
	 AOS	(P)		;YES.
	RET			;NO.
	SUBTTL	WINDOWS -- ECHO

;Add a character to a window in talk mode
; T1/	char
; W/	^window
;	CALL	ECHO
ECHO:	JUMPE	T1,CPOPJ	;IGNORE NULL
	CAIGE	T1," "		;PRINTABLE?
	 JRST	EC.CTL		; NO
	CAIN	T1,DEL		;RUBOUT?
	 JRST	EC.DEL		; YES
	CALL	PUTC		;NO, TYPE IT
	IDPB	T1,WNDLBP(W)	;STORE IN LINE BUF
	AOS	T2,WNDCOL(W)	;INCR COLMN (WHAT ABOUT EDGE?)
	CAIG	T2,^D75		;BEYOND COLM 75 ****** MAGIC NUMBER ******
	 RET			; NO, DONE
	MOVEI	T1,CR		;GET A <CR>
	JRST	ECHO		;SEND IT!

;Rubout
EC.DEL:	SETZ	T1,		;RETURN NULL
	MOVEI	T2,1
	SOSG	T3,WNDCOL(W)	;DECREMENT
	 MOVEM	T2,WNDCOL(W)	; TOO FAR?
	JUMPLE	T3,CPOPJ	;YEP.

	OUTSTR	[BYTE (7)BS," ",BS] ;ERASE

	LDB	T1,WNDLBP(W)	;GET CHAR DELETED
	SETO	T2,		;GET MINUS 1
	ADJBP	T2,WNDLBP(W)	;BACKUP LINE BP
	MOVEM	T2,WNDLBP(W)	;STORE
	RET			;DONE

;Got control character
EC.CTL:	CAIN	T1,"U"-100	;CONTROL-U?
	 JRST	EC.CTU		; YES.
	CAIN	T1,CR		;CR?
	 JRST	EC.CR		; YES
	CAIN	T1,LF		;LF?
	 JRST	EC.LF		; YES
	CAIN	T1,BEL
	 JRST	EC.BEL
	RET			;LOSER
EC.BEL:	CALL	PUTC		;HERE FOR BELL
	RET

EC.CTU:	MOVEI	T1,1		;CONTROL-U
	MOVEM	T1,WNDCOL(W)	;GO TO START OF LINE
	MOVEI	T1,CR		;GET A CR
	CALL	PUTC		;GO TO START OF LINE
	TTY	<ERL>		;CLEAR TO EOL
EC.RES:	MOVEI	T1,WNDLBF(W)	;GET BUFFER ADDR
	HRLI	T1,(POINT 7,)	;MAKE INTO BP
	MOVEM	T1,WNDLBP(W)	;RESET LINE BUFFER PTR
	RET			;DONE

EC.CR:	CALL	EC.RES		;RESET LINE BUF
	MOVEI	T1,1		;START OF LINE
	MOVEM	T1,WNDCOL(W)	;STORE
	AOS	T1,WNDLIN(W)	;STEP TO NEXT LINE
	CAMLE	T1,WNDSIZ(W)	;STILL IN RANGE?
	 JRST [	MOVEI	T1,TXTLIN ; NO, GET TOP OF TEXT
		MOVEM	T1,WNDLIN(W) ;STORE
		CALL	POSION	;FORCE POSITION
		JRST	EC.CR2 ] ;JOIN THE REST OF HUMANITY
	CALL	CRLF
EC.CR2:	TTY	<ERL>		;ERASE TO END OF NEW TEXT LINE
	MOVE	T1,WNDLIN(W)	;GET LINE AGAIN
	CAME	T1,WNDSIZ(W)	;BOTTOM?
	 JRST [	CALL	CRLF
		TTY	<ERL>	;CLEAR IT
		PJRST	POSION ] ;GOTO RIGHT POSN
	MOVE	T1,WNDORG(W)	;GET WINDOW ORIGIN
	ADDI	T1,2		;GET TOP LINE
	MOVEI	T2,1		;FIRST COLM
	TTY	<MVX,T1,T2>	;GO THERE
	TTY	<ERL>		;CLEAR IT
	PJRST	POSION		;RESTORE CURSOR

; HERE TO KILL A WORD
EC.LF:	LDB	T1,WNDLBP(W)	;GET LAST BYTE
	CAIE	T1," "		;SPACE?
	 JRST	EC.LF1		; NO, GOTO STATE 1
	CALL	EC.DEL		;KILL
	JUMPN	T1,EC.LF	;REPEAT
	RET

EC.LF1:	LDB	T1,WNDLBP(W)	;GET LAST BYTE
	CAIN	T1," "
	 RET			;  DONE!
	CALL	EC.DEL
	JUMPN	T1,EC.LF1
	RET
	SUBTTL	WINDOWS -- FIND A USER

; Find an active (ie; has a window) user.
; T1/	BP to user
;	CALL	FNDUSR
;	 <LOSS>
;	<WIN>
; T1/	^LINK
FNDUSR:	ACVAR	<X1,X2>
	MOVE	X2,T1		;SAVE USER
	MOVN	X1,NUMUSR	;GET NEG USR COUNT
	HRLZ	X1,X1		;GET -N,,0
FU.LOP:	MOVE	T1,WNDTAB(X1)	;GET WINDOW
	MOVE	T1,WNDLNK(T1)	;GET LINK
	HRROI	T1,LNKUSR(T1)	;GET USER
	MOVE	T2,X2		;GET TARGET
	CALL	CMPSTR		;NO, COMPARE
	 TRNA			; NO MATCH
	  JRST	FU.WIN		;  A WINNER!
	AOBJN	X1,FU.LOP	;NO, GUESS AGAIN
	RET			;YOU LOSE
FU.WIN:	MOVE	T1,WNDTAB(X1)	;GET LINK
	PJRST	CPOPJ1		;RETURN HAPPY
	ENDAV.
	SUBTTL	WINDOWS -- ADD A NEW USER
;Put a new user on the screen
; T1/	link
NEWUSR:	STKVAR	<LINK>
	MOVEM	T1,LINK		;SAVE LINK
	MOVE	T1,SCRSIZ	;GET SCREEN SIZE
	SUBI	T1,2		;MINUS TOP LINES
	MOVE	T2,NUMUSR	;GET CURRENT USERS
	IDIVI	T1,2(T2)	;SPLIT AMONG USERS + (US + NEW)
	CAIGE	T1,5		;AT LEAST FIVE LINES?
	 RET			; NOPE.

	MOVE	T1,LINK		;GET LINK
	CALL	SAVLNK		;STORE LINK
	 RET			;FAIL IF NOT

	CALL	GETWND		;ALLOCATE A WINDOW BLOCK
	MOVEI	T2,TXTLIN	;TOP LINE
	MOVEM	T2,WNDLIN(T1)	;STORE
	MOVEI	T2,1		;FIRST COL
	MOVEM	T2,WNDCOL(T1)	;STORE POSN

	MOVEI	T2,WNDLBF(T1)	;GET LINE BUFFER ADDR
	HRLI	T2,(POINT 7,)	;MAKE BP
	MOVEM	T2,WNDLBP(T1)	;STORE

	AOS	T3,NUMUSR	;GET NEW USER COUNT
	MOVEM	T1,WNDTAB-1(T3)	;SAVE IN SLOT
	MOVE	T2,LINK		;GET LINK
	MOVEM	T2,WNDLNK(T1)	;SAVE LINK
	PJRST	REFRSH
	ENDSV.
	SUBTTL	WINDOWS -- REDIVIDE
;No Args
;AC Usage
; T1/	size
; T2/	remainder
; T3/	scratch
; T4/	curr window
; T5/	prev window
REFRSH:	ACVAR	<X1>		;LOOP VAR
	MOVE	T1,SCRSIZ	;GET SCREEN SIZE
	SUBI	T1,2		;MINUS TOP LINES
	MOVE	T2,NUMUSR	;GET CURRENT USERS
	MOVNI	X1,(T2)		;GET NEG USR COUNT
	HRLZ	X1,X1		;GET -N,,0
	IDIVI	T1,1(T2)	;SPLIT AMONG USERS + US
	CAIGE	T1,5		;AT LEAST FIVE LINES?
	 RET			; NOPE.
	MOVEI	T4,WNDBLK	;GET OUR WINDOW
	MOVEI	T3,3		;ORIGIN
	MOVEM	T3,WNDORG(T4)	;FOR US
	MOVEM	T1,WNDSIZ(T4)	;GIVE US SMALLEST
RF.LOP:	MOVE	T5,T4		;SET PREV WINDOW
	MOVE	T4,WNDTAB(X1)	;GET CURR WINDOW
	MOVE	T3,WNDORG(T5)	;GET PREV ORIGIN
	ADD	T3,WNDSIZ(T5)	;ADD PREV SIZE
	MOVEM	T3,WNDORG(T4)	;STORE OUR ORIGIN
	MOVEI	T3,(T1)		;GET STD SIZE
	SOSL	T2		;ANY REMAINDER LEFT?
	 ADDI	T3,1		; YES, GIVE ONE TO US
	MOVEM	T3,WNDSIZ(T4)	;STORE OUR SIZE
	AOBJN	X1,RF.LOP	;LOOP
	TLO	FL,(F$REF)	;NEED REFRESH
	PJRST	CPOPJ1
	ENDAV.
	SUBTTL	WINDOWS -- REMOVE A USER

;Remove a user from screen
; I/	link
KILUSR:	SKIPL	LNKHLD(I)	;ON HOLD?
	 RET			; YES, NOT ON SCREEN
	MOVN	T2,NUMUSR
	MOVSI	T2,(T2)		;GET -N,,0
	JUMPE	T2,CPOPJ	;NO USERS!!
KU.LOP:	MOVE	T1,WNDTAB(T2)	;GET WINDOW
	CAME	I,WNDLNK(T1)	;THE RIGHT LINK?
	 AOBJN	T2,KU.LOP	; NO, LOOP
	JUMPGE	T2,CPOPJ	;NOT FOUND, RETURN
	PUSH	P,T2		;SAVE INDEX
	CALL	FREWND		;FREE WINDOW BLOCK
	POP	P,T2		;RESTORE LOOP INDEX
	JRST	KU.BOT		;MOVE UP THE REST
KU.MOV:	MOVE	T1,WNDTAB(T2)	;GET CURRENT
	MOVEM	T1,WNDTAB-1(T2)	;MOVE BACKWARDS
KU.BOT:	AOBJN	T2,KU.MOV	;LOOP
	SOS	NUMUSR		;ONE LITTLE INDIAN....
	TLO	FL,(F$REF)	;NEEDS REFRESH!!
	RET

	SUBTTL	WINDOWS -- SEND TO ALL
;Send to all active windows
; T1/	code
; T2/	data
SNDALL:	ACVAR	<X1,<X2,2>>
	DMOVE	X2,T1		;SAVE CODE & DATA
	MOVN	X1,NUMUSR	;GET USER COUNT
	HRLZ	X1,X1		;AS -N,,0
	PUSH	P,I		;SAVE LINK
SA.LOP:	MOVE	T1,WNDTAB(X1)	;GET WINDOW
	MOVE	I,WNDLNK(T1)	;GET LINK
	DMOVE	T1,X2		;GET CODE & DATA
	MOVE	T3,LNKFLG(I)	;GET LINK FLAGS
	TLNN	T3,(L$HELD)	;HOLDING US?
	 CALL	SNDMSG		; NO, SEND
	  TRN			;  IGNORE ERRORS
	AOBJN	X1,SA.LOP	;LOOP FOR ALL WINDOWS
	PJRST	POPIJ
	ENDAV.
	SUBTTL	SPECIAL	ACVAR SUPPORT

.SAV1:	PUSH P,.FPAC
	PUSHJ P,0(.A16)		;CONTINUE PROGRAM
	 SKIPA
	AOS -1(P)
	POP P,.FPAC
	POPJ P,

.SAV2:	PUSH P,.FPAC
	PUSH P,.FPAC+1
	PUSHJ P,0(.A16)
	 SKIPA
	AOS -2(P)
	POP P,.FPAC+1
	POP P,.FPAC
	POPJ P,

.SAV3:
.SAV4:	PUSH P,.FPAC
	PUSH P,.FPAC+1
	PUSH P,.FPAC+2
	PUSH P,.FPAC+3
	PUSHJ P,0(.A16)
	 SKIPA
	AOS -4(P)
	POP P,.FPAC+3
	POP P,.FPAC+2
	POP P,.FPAC+1
	POP P,.FPAC
	POPJ P,
	SUBTTL	CORE ALLOCATOR

GETWND:	MOVEI	T2,WNDLEN	;HERE TO ALLOCATE A FRESH WINDOW
	SKIPN	T1,WNDLST	;ANY HANGING OUT?
	 PJRST	GETWDS		; NOPE ALLOCATE ONE
	MOVE	T2,(T1)		;GET NEXT ON LIST
	MOVEM	T2,WNDLST	;SAVE
	MOVEI	T2,WNDLEN
	PJRST	ZERWDS

GETLNK:	MOVEI	T2,LNKLEN	;HERE TO ALLOCATE A FRESH WINDOW
	SKIPN	T1,LNKLST	;ANY HANGING OUT?
	 PJRST	GETWDS		; NOPE ALLOCATE ONE
	MOVE	T2,(T1)		;GET NEXT ON LIST
	MOVEM	T2,LNKLST	;SAVE
	MOVEI	T2,LNKLEN
	PJRST	ZERWDS

; T2/	COUNT
GETWDS:	MOVE	T1,T2		;COPY LENGTH
	ADD	T1,.JBFF	;GET NEW END OF CORE
	CAILE	T1,ENDCOR	;GONE TOO FAR?
	 FATAL	(Out of memory)	; I DON'T KNOW HOW YOU DID IT!
	EXCH	T1,.JBFF	;GET START OF BLOCK
ZERWDS:	ADDI	T2,-1(T1)	;GET LAST WORD
	MOVSI	T3,(T1)		;GET START,,0
	HRRI	T3,1(T1)	;GET START,,START+1
	SETZM	(T1)		;START THE BALL ROLLING
	BLT	T2,(T2)		;SMEAR!
	RET

FREWND:	PUSH	P,T1
	CALL	IPOFF
	POP	P,T1
	MOVE	T2,WNDLST	;GET WINDOW LIST
	MOVEM	T2,(T1)		;STORE IN FIRST WORD OF NEW BLOCK
	MOVEM	T1,WNDLST	;SAVE AS FREE LIST
	PJRST	IPON			;DONE

FRELNK:	PUSH	P,T1
	CALL	IPOFF
	POP	P,T1
	MOVE	T2,LNKLST	;GET LINK LIST
	MOVEM	T2,(T1)		;SAVE IN FIRST WORD OF NEW BLOCK
	MOVEM	T1,LNKLST	;STORE AS FREE LIST
	PJRST	IPON
	SUBTTL	LUUO HANDLR

LUUOH:	MOVEM	16,UUOACS+16	;SAVE AC16
	MOVEI	16,UUOACS	;COPY FROM ACS TO SAVE AREA
	BLT	16,UUOACS+15	;SAVE AC0..15
	LDB	T1,[POINT 9,.JBUUO,8] ;GET INDEX
	CAIG	T1,MAXUUO	;IN RANGE?
	 XCT	LUUTAB(T1)	; DOIT
LUUDON:	MOVSI	16,UUOACS	;COPY FROM SAVE TO ACS
	BLT	16,16
	RET			;GO HOME

LUUTAB:	HALT	.		;LUUO 0
	CALL	TTYSTF		;LUUO 1
	CALL	$OUTSTR		;LUUO 2
MAXUUO==.-LUUTAB-1

;Dependent terminal routines
TTYSTF:	MOVE	T1,@.JBUUO	;GET ARG WORD
	LDB	T3,[POINT 9,T1,8] ;GET CODE
	TRZE	T3,TT$IND	;INDIRECT?
	 CALL	GETIND		; YES, FETCH ARGS
	MOVE	T2,TTYTYP	;GET TTY TYPE
	SKIPN	T2,VTXDSP(T2)	;GET BASE
	 FATAL	<Unknown TTY type>
	ADD	T2,T3		;GET ADDR
	SKIPN	T2,(T2)		;GET ROUTINE
	 RET			; NONE.
	CALL	(T2)		;GO!
	 TRNA
	  PSOUT			;OUTPUT STRING
	MOVEI	T1,.PRIOU	;RESET POSITION COUNTER
	SETZ	T2,		;AVOID "WIDTH 0"
	SFPOS
	 ERJMP	.+1
	RET
VT1TBL:	EXP	MOV10,JMP10,JME10,ERL10,ERB10,SCL10,NRM10,REV10,BRI10
VT5TBL:	EXP	MOV52,JMP52,JME52,ERL52,ERB52,0,NRM62,REV62,0

DEFINE	XX	(NAM,ADDR) <
	BLOCK	.TT'NAM-.
	EXP	ADDR
> ;XX

VTXDSP:	PHASE	0
	XX	V52,VT5TBL	;(15) VT52
	XX	100,VT1TBL	;(16) VT100
	XX	125,VT1TBL	;(35) VT125
	XX	K10,VT1TBL	;(36) VK100 (GIGI IN VT100 COMPAT MODE)
	XX	102,VT1TBL	;(37) VT102
	XX	H19,VT1TBL	;(38) H19 (ANSI)
	XX	131,VT1TBL	;(39) VT131
	DEPHASE
;;;REGIS CLEAR SEQUENCE
;;;[BYTE (7)33,"P","p","s","(","e",")",33,"\"] ;(36) VK100


;Here to fetch indirect args into T1
; T1/	Indirect command word
GETIND:	LDB	T2,[POINT 9,T1,17] ;GET LINE AC
	MOVE	T2,UUOACS(T2)	;GET AC
	DPB	T2,[POINT 9,T1,17] ;STORE VALUE
	LDB	T2,[POINT 9,T1,26] ;GET COLM
	MOVE	T2,UUOACS(T2)	;GET AC
	DPB	T2,[POINT 9,T1,26] ;STORE VALUE
	RET

; Output an escape prefixed character
; T2/	Char
PUTESC:	MOVEI	T1,33
	CALL	PUTC
	MOVE	T1,T2
	CALL	PUTC
	RET
;*Move the cursor for a VT52 type terminal
MOV52:	PUSH	P,T1		;SAVE ARGS
	TLNE	T1,000777
	 TRNN	T1,777000
	  FATAL	<Bad call to MOV52>
	MOVEI	T2,"Y"
	CALL	PUTESC
	LDB	T1,[POINT 9,(P),17] ;Get line number
	ADDI	T1," "-1
	CALL	PUTC		;OUTPUT
	LDB	T1,[POINT 9,(P),26] ;GET COLUMN
	ADDI	T1," "-1
	CALL	PUTC
	POP	P,T1
	RET

;*Jump to home and clear the screen for VT52
JME52:	HRROI	T1,[BYTE (7)33,"H",33,"J",0]
	RETSKP

;*Jump to home
JMP52:	MOVEI	T2,"H"
	PJRST	PUTESC

;*Erase to end of line
ERL52:	MOVEI	T2,"K"
	PJRST	PUTESC

;*Erase to end of screen(page)
ERB52:	MOVEI	T2,"J"
	PJRST	PUTESC

REV62:	MOVEI	T2,"T"
	PJRST	PUTESC

NRM62:	MOVEI	T2,"U"
	PJRST	PUTESC
;****************************************
;* Here are the VT100 specific routines *
;****************************************

;Change to reverse video
REV10:	HRROI	T1,[BYTE (7)33,"[","7","m",0]
	RETSKP

;Change to bold
BRI10:	HRROI	T1,[BYTE (7)33,"[","1","m"]
	RETSKP

NRM10:	HRROI	T1,[BYTE (7)33,"[","0","m"]
	RETSKP

MOV10:	PUSH	P,T1		;SAVE LINE/COL
	MOVE	T1,[POINT 7,VT10OT,13] ;DESTINATION POINTER
	LDB	T2,[POINT 9,(P),17]
	CALL	MOV10A
	MOVEI	T2,";"
	IDPB	T2,T1
	LDB	T2,[POINT 9,(P),26]
	CALL	MOV10A
	MOVEI	T2,"H"
	IDPB	T2,T1
	POP	P,T1
	HRROI	T1,VT10OT	;Point to string
	RETSKP

MOV10A:	MOVE	T3,[NO%LFL!NO%ZRO!NO%OOV!FLD(2,NO%COL)!^D10]
	NOUT
	 TRN
	RET

;Scroll VT100
SCL10:	PUSH	P,T1		;SAVE LINE/COL
	MOVE	T1,[POINT 7,VT10ST,13] ;DESTINATION POINTER
	LDB	T2,[POINT 9,(P),17]
	CALL	MOV10A
	MOVEI	T2,";"
	BOUT
	LDB	T2,[POINT 9,(P),26]
	CALL	MOV10A
	MOVEI	T2,"r"
	BOUT
	POP	P,T1
	HRROI	T1,VT10ST	;Point to string
	RETSKP
;Jump to home
JMP10:	HRROI	T1,[BYTE (7)33,"[","0",";","0","H"]
	RETSKP

;Jump to home and erase the screen
JME10:	HRROI	T1,[BYTE (7)33,"[","0",";","0"
		    BYTE (7)"H",33,"[","2","J"
		    0]
	RETSKP

;Erase line
ERL10:	HRROI	T1,[BYTE (7)33,"[","0","K",0]
	RETSKP

;Erase to end of screen

ERB10:	HRROI	T1,[BYTE (7)33,"[","0","J",0]
	RETSKP

; TOPS-20 OUTSTR LUUO
$OUTSTR: HRROI	T1,@.JBUUO	;GET EA
	PSOUT			;OUTPUT IT
	RET
	SUBTTL	THE END
JUNK:	XLIST
	LIT
	LIST
ENDJNK:

DEFINE	SAY (A,B,C,D,E) <
PRINTX A'B'C'D'E
> ;SAY

IF1 <
SAY	<[END OF PASS1]>
SAY	<JUNK = >,\JUNK
SAY	\<ENDJNK-JUNK>,< WORDS LITTERALS>
> ;IF1

	END	<3,,EVEC>