	.title	'Print the list of current Network users'
	.sbttl	'WHO'
version	==	2
revision==	1
        .pabs
	.phex
	.loc	100h
	sspd	saveSP
	lxi	sp,stack	;stack at end of prog.
	jmp	START
saveSP:	.word	0
retCCP:
	lspd	saveSP
	ret
;
; BIOS Network jump addresses.  Filled in during START.
SENDNET:  jmp	0000h	; HiNET send 
RECVNET:  jmp	0000h	; HiNET receive 
Ackpoll:  jmp	0000h	; Acknowledge polls enable
Nackpoll: jmp	0000h	; Acknowledge polls disable
WBOOT	=	00h	; Bios entry point location
WBaddr	=	01h     ; Warm boot location
;
;Data Memory locations
numusr	=	32	; number of users
curdrive=	04	; current drive number
BIOSsec	=	41h	; BIOS maintained time
BIOSmin	=	42h
BIOShrs	=	43h	
usernum =	47h	; assigned user number loc
userlist=	4000h	; addr of user table
whoNET	=	10h	; Network 'who' command
NETcmd:	.byte	00h	; byte for Network Master

cr	=	0Dh	; Ascii carriage return
lf	=	0Ah	; Ascii line feed

LOGmsg: .ascii	[cr][lf]'Who version '
	.byte	version+'0','.'
	.byte	revision/10+'0',revision@10+'0'
	.asciz	[cr][lf]
TIMEmsg:.ascii	[cr][lf]
	.asciz	'            HiNet Users as of '
START:
; Print the log-on message
	lxi	H,LOGmsg ; Print log-on message
	call	prtmsg
	lxi	H,TIMEmsg; Print time message
	call	prtmsg
	lda	BIOShrs	 ; Get the current hour
	sta	hours	 ; and store for printing.
	lda	BIOSmin	 ; Get the current minute
	sta	minutes	 ; and store for printing.
	lda	BIOSsec	 ; Get the current second
	sta	seconds	 ; and store for printing.
	call	prttime	 ; Print the time.
; Initialize BIOS subroutine jump addresses.
	lded	WBaddr	; DE = Warm boot address

	lxi	H,6Ch
	dad	D
	shld	SENDNET+1  ; jump address to SENDNET

	lxi	H,6Fh
	dad	D
	shld	RECVNET+1  ; jump address to RECVNET

	lxi	H,75h
	dad	D
	shld	Ackpoll+1  ; jump address to Ackpoll

	lxi	H,72h
	dad	D
	shld	Nackpoll+1 ; jump address to Nackpoll
;----------
; Determine if this program is being executed on the
; Network Master.  If we are on the Master, then
; the user table is already in memory.  We copy
; it into our userlist and print it out.
; are on a Network Station, then send the whonet
; command, receive the userlist from the
; Network, and print out the userlist.
;					D. Stein
;					11/7/80
	lda	usernum
	cpi	00	; are we on the master?
	jrz	MASTER	; Yes.
	jnz	SLAVE	; No.
MASTER:
	lxi	H,0FC00h   ; HL = table addr in Bios
	lxi	D,userlist ; DE = our userlist addr
	lxi	B,numusr*16; BC = length of table
	ldir		; Copy from BIOS to userlist
	jmp	PRTTABL	; print out user list
SLAVE:
	call	NACKpoll
	bit	7,A	; is network operational?
	jrz	NETdead	; No. Die.

; The Network is up. Load in SENDNET parameters.
	mvi	A,0	; load Masters user number
	lxi	B,1	; length of our data
	lxi	H,NETcmd; Our data addr
	mvi	M,whoNET; Load the 'whoNET' byte
	call	SENDNET	; and send it over the network.

; Load in RECVNET parameters.
	lda	usernum	; get our user number
	lxi	H,userlist ; Our destination addr
	lxi	B,numusr*16; max num of bytes to recv
	call	RECVNET	; Get the user list from Master
	bit	7,A	; is network still operational?
	jrz	NETdead	; No. Die.
	call	ACKpoll	; Yes.Resume poll acknowledging
	jmp	PRTTABL	; and print out the user list
;----------
; Utility Exit Routine for Network down times.
NETdead:
	lxi	H,deadMSG
	call	prtmsg
	jmp	WBOOT	; Network is down so warm boot.
deadMSG:.asciz	[cr][lf]'The HiNet is not operational.'
	.page
;----------
; Routine: PRTTABL
;
; Print the userlist table.
; Print up to 16 lines, skipping any non-active users.
; Jump to the Console Command Processor when finished.
;
unit:	.byte	00h	; unit number of entry in table
status:	.byte	00h	; status of entry in stable
HEADmsg:.ascii	[cr][lf]'Name       Login Time   '
	.ascii	'Last HiNet Request   Status'
	.ascii	[cr][lf]'----       ----------   '
	.asciz	'------------------   ------'
actMSG:	.asciz	'active'
nactMSG:.asciz	'******'
crlf:	.asciz	[cr][lf]
;
prtTABL:
	mvi	A,0
	sta	unit		; re-initialize 
	lxi	H,crlf
	call	prtmsg
	lxi	H,HEADmsg
	call	prtmsg		; print table header

..1:	lxi	H,userlist	; HL = addr of table
	mvi	B,16		; B = bytes per line
	lda	unit		; A = line to find
	call	ADDRfind	; HL returns with addr
	call	prtline		; Print a line in table
	lda	unit
	inr	A		; increment the line
	sta	unit
	cpi	numusr		; All users checked?
	jrc	..1		; No.  Loop back.
	lxi	H,crlf		; Yes.
	call	prtmsg		; space down a line
	lxi	H,crlf
	call	prtmsg		; space down a line
	jmp	retCCP		; ALL FINISHED
	.page
;----------
;Subroutine:	prtline
; Regs  in:	HL=addr in the name/pass  table
; Regs out:	HL=next addr in the name/pass  table
; Destroyed:	A,B,C
;
;Used by prtname to print one line in the table.
;Halt print out if a console chr is found.
;Resume print out when 2nd console chr is found.
prtline:
	push	H	; save name/pass  table address
	call	CONSTAT	; is console chr ready?
	jrnc	..4	; NO.
	call	CONIN	; eat the chr
..3:	call	CONSTAT ; is 2nd console chr ready?
	jrnc	..3	; wait for it
	call	CONIN	; eat the chr, and proceed
;----------
; Test the first byte in each line of the table.
; Halt print and return immediately if the size is 0.
..4:	pop	H	; restore name/pass  tabl addr
	mov	A,M		; get the status
	sta	status		; store the status
	cpi	0		; Entry on this line?
	rz			; No. Return
;Table line is assumed ok.  Print it
	push	H
	lxi	H,crlf		; space down a line
	call	prtmsg
	pop	H		; HL = status byte addr
	inx	H		; HL = 8 chr name addr
prtN:	mvi	B,8
	call	prtchr		; print 8 chr name
	inx	H		; next addr in table
	mvi	B,4
	call	spaces	; skip 4 spaces
	lxi	D,seconds
	lxi	B,3
	ldir
	call	prttime	; print login time
	mvi	B,5
	call	spaces	; skip 5 spaces
	lxi	D,seconds
	lxi	B,3
	ldir
	call	prttime	; print last request time
	mvi	B,2
	call	spaces	; skip 2 spaces
	mov	A,M
	sbi	10h
	jrc	..unknown
	cpi	0Bh
	jrc	..ok
..unknown:
	mvi	A,4
..ok:
	lxi	H,reqtab
	mvi	D,0
	mov	E,A
	dad	D
	dad	D
	dad	D
	dad	D
	dad	D
	dad	D	; address of request name
	mvi	B,6
	call	prtchr	; print request name
	mvi	B,4
	call	spaces	; skip 4 spaces
	lda	status		; Get the entry status
	lxi	H,actMSG	; Load active message
	cpi	0FFh		; Is it active?
	jrz	..1		; Yes. Print active msg
	lxi	H,nactMSG	; No. Load inactive msg
..1:	call	prtmsg		; and print the message.
	ora	A		; Clear A,
	ret			; and return
;----------
; Request name table
reqtab:
	.ascii	'who   '
	.ascii	'read  '
	.ascii	'write '
	.ascii	'login '
	.ascii	'??????'
	.ascii	'??????'
	.ascii	'??????'
	.ascii	'assign'
	.ascii	'hog   '
	.ascii	'lock  '
	.ascii	'unlock'
	.ascii	'clrlck'
;----------
; Print variable number of spaces
spaces:
	push	H	; save callers HL
	lxi	H,blanks
	call	prtchr	; B = number of spaces to print
	pop	H
	ret
blanks:	.ascii	'      '
;---------
;		Subroutine: ADDRfind
; Regs  in:    A = A line in table whose addr is needed
;	       B = Bytes per line of the table
;	       HL= addr of the start of the table
; Regs out:    HL= Addr of that line
;	          in the table 
;Destroyed:    A,B
;Find an addr of a line in a table
ADDRfind:
; A = line in table to find \  HL= start addr of table
	cpi	0	  ; first line of table?
	rz		  ; then were done
..1:	push	PSW	  ; save table line number
	mov	A,B	  ; incr table <Reg B> times 
..2:	inx	H
	dcr	A
	cpi	0	  ; Are we through this line?
	jrnz	..2	  ; No. continue incrementing
	pop	PSW	  ; Yes. Restore line counter
	dcr	A	  ; decr table line number
	cpi	0	  ; Are we all done?
	jrnz	..1	  ; No.incr to next line
	ret		  ; Yes. Return.

;----------
; Subroutine: PRTTIME
;
; Print the time as represented by these bytes.
;
seconds:.byte	00h
minutes:.byte	00h
hours:	.byte	00h
;----------
; Print the time as represented by the above bytes.
; This program is used in conjunction with the TIMERopt
; option of the BIOS on the DSC/3 and DSC/4.
; The BIOS maintains the time in locations 40h-43h.
;
PRTTIME:
; Print the hours
	lda	hours
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	bb1
	push	PSW
	mvi	A,'0'
	call	CONOUT
	pop	PSW
	;
bb1:	call	prtbyt
	mvi	A,':'
	call	CONOUT	
;
; Print the minutes
prtmin:	lda	minutes
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	bb2
	push	PSW
	mvi	A,'0'
	call	CONOUT
	pop	PSW
	;
bb2:	call	prtbyt
	mvi	A,':'
	call	CONOUT
;
; Print the seconds
prtsec:	lda	seconds
	call	cvtbcd
	;is leading 0 necessary?
	cpi	10
	jp	bb3
	push	PSW
	mvi	A,'0'
	call	CONOUT
	pop	PSW
	;
bb3:	call	prtbyt
	ret		; date and time printed out.

;----------
; SUBROUTINES
;----------
; Print a message on the console
;  Regs in:   HL = address of string (ended by null)
;  Regs out:  none
;  Destroyed: A, HL
prtmsg:
	mov	A,M
	ora	A
	rz
	call	CONOUT
	inx	H
	jmpr	prtmsg
;----------
;		Subroutine: prtchr
; Regs  in:	B =length of string
;		HL=addr of string
; Regs out:	HL=addr of last chr printed
;Destroyed:	B,A
;Print a specified number of chrs to the console
prtchr:
	mov	A,M
	push	B
	push	H
	call	CONOUT
	pop	H
	pop	B
	dcr	B
	mov	A,B
	cpi	0	; all B chrs printed?
	rz
	inx	H	; next chr addr
	jmpr	prtchr	

;----------
; Print a byte on the console
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
prtbyt:
	push	PSW
	rrc
	rrc
	rrc
	rrc
	ani	0Fh	; don't print leading zeros
	jrz	..1
	call	prtnbl
..1:	pop	PSW
prtnbl:	ani	0Fh
	adi	'0'
	cpi	'9'+1
	jrc	CONOUT
	adi	'A'-('9'+1)
	jmpr	CONOUT
;----------
; Convert binary to BCD
;  Regs in:   A = byte to be converted
;  Regs out:  A = byte, in BCD format
;  Destroyed: B
cvtbcd:
	ora	A
	rz
	mov	B,A
	xra	A
..1:	inr	A
	daa
	djnz	..1
	ret
;----------
; Print a character on the console
;  Regs in:   A = character to be printed
;  Regs out:  none
;  Destroyed: C
CONOUT:
	mov	C,A
	lxi	D,09h
	lixd	WBOOT+1
	dadx	D
	pcix
;----------
;		Subroutine: CONIN
;Fetch a character from the console.
CONIN:	lded	WBaddr
	lxi	H,06h
	dad	D
	pchl

;----------
;		Subroutine: CONSTAT
; Regs  in:	none
; Regs out:	carry bit set if chr ready
; Destroyed:	
CONSTAT:
	lxi	H,..1
	push	H	; return to ..1
	lded	WBaddr
	lxi	H,03h
	dad	D
	pchl
..1:	rrc		; set parity bit if
	ret		;chr is ready.

	.blkb	30
stack:
.end
