; NEW05.ASM - Displays KMD.LOG in reverse order - 05/04/86
;
;			    NEW.ASM
;			       by
;			  Irvin M. Hoff
;	     copyrighted for use with public domain
;			 (17 July 1985)
;
	ASEG			; For M80 and RMAC, ignore if using MAC
;
;
; This program is really two-in-one.  It is for use with RCPM systems
; having a KMD.LOG of all file transfers created by the KMD file pgm.
;
;    Program 1 = shows the KMD.LOG in reverse order, newest first
;    Program 2 = shows only uploads in reverse, ignoring downloads
;
;=======================================================================
;		              Revisions
;
; 05/10/86  Sorry for another release, but an error came up when the
;    v06    file got to big.  Now it will be able to read up to
;           65000, 128 byte records.  I tested it on at 130+k file and
;           it work fine.
;	                       Joubert Berger
;
; 05/04/86  Rewrote the entire read file section so it would read the
;    v05    the file backwards.  Now, there is no more wait while it
;           reads the entire file into memory.  On most RCPM's, users
;           only read the first few enteries anyway, so why bother
;           reading the entire file.  This was quit anoying.  So now it
;           will read the file one line at a time, backwards, and display
;           it like it is supposed to.  At the lable FILE: put in whatever
;	    your up/download log file is called.
;
;           It struck me that one could use this program to read the
;           CALLER file of BBS systems.  This has come in handy many times
;           when I wanted to see who has called latley, and not have to
;           use TYPE or WS.  I renamed it to CALL.COM and changed the file
;	    name at the lable FILE: to whatever my BBS caller file was called.
;	    I set all options to zero and it worked great....
;						Joubert Bergere
;						Atlanta Kaypro MBBS
;						(404) 923-258 [300/1200]
;
; 08/20/85  Redated for use with KMD04	- Irv Hoff
; 07/17/85  Original version for KMDxx	- Irv Hoff
;
;=======================================================================
;
; SHOWAL set to 0 - gives Program 1
; ---------------------------------
; When the SHOWAL option is set to "0", all files in the KMD.LOG are
; shown in reverse order.  This is particularly useful to SYSOPs to see
; who has most recently uploaded/downloaded any files and what they are.
; It can be placed in A15: with other private .COM files or A0: for all
; to use, if desired.  Call this program ALL.COM for easy reference.
;
; SHOWAL set to 1, gives Program 2
; --------------------------------
; This program displays the "R" (new files) entries entered by KMD.COM
; into the KMD.LOG file, in inverse order.  It replaces the WHATSNEW
; files used in the past for RCPM systems.  (If the wheel byte is set
; for the SYSOP's use, it includes any "P" private uploads.  These are
; shown with an "*" after the drive/user number.)  This program is de-
; signed to work with KMD.COM.	It may need to be customized slightly,
; depending on how your LASTCALR file is arranged.  It goes in the A0:
; area and can be called from any drive/user area.  It is essentially
; self-maintaining, which makes it quite different from WHATSNEW pro-
; grams previously used (made via D-29), etc.  It is 1k long and fully
; secure.  (Change equates below if your KMD.LOG isn't in A14: area.)
;
;	NOTE:  You can use DDT to set the following byte:
;
;		0103H 00 program 1, shows all file transfers
;		      01 program 2, uploads only, for NEW.
;
;		Then  A>SAVE 5 NEW.COM
;
;		Suggestion:  Make one of each, call one ALL.COM
;		ahd put it on A15: for easy use by the SYSOP and
;		the other NEW.COM and put on A0: for all to use.
;
;-----------------------------------------------------------------------
;
; INFO:
; ----
;	A companion program currently called KMDEL automatically
;	deletes all downloaded files from KMD.LOG, keeping the
;	uploads for NEW.  This minimimizes the length of the KMD.LOG
;	file, since "most" of the lines are for downloads.  The com-
;	bination of NEW and KMDEL make the entire new file display
;	almost fully self-maintaining.
;
;-----------------------------------------------------------------------
;
; OPTIONS:
; -------
;    SHOWAL  0 = Shows all files in the KMD.LOG in reverse manner
;		    Makes this into a second program, see below
;	     1 = Allows options above to work normally
;
;    OPTION  0 = No header, shows "R" lines of KMD.LOG "as is".
;	     1 = Header, uses example 1 below  (OxGate 001 system)
;	     2 = Header, uses example 2 below  (Potpourri system)
;
;    HEADER  0 = No header, regardless of option below
;	     1 = use header selected by option below
;
;---------------
;
; Example 0:  (no header, no changes, before and after the same.  Picks
;	      out the "R" lines from the KMD.LOG and displays in re-
;	      verse order (newest uploads, first).
;
;---------------
;
; Example 1:  OxGate 001
;
;		(before)
;
; R6 02:22 B00>M7DATA-1LBR		26k Irv Hoff 08/20/85
;
;		(after)
;
; D/U	 Filename   Size   Speed    Uploaded by
;
; B00: M7DATA-1.LBR  26k  1200 bps  Irv Hoff 08/20/85
;
;---------------
;
; Example 2:  Potpourri
;
;		(before)
;
; R6 02:22 B00>M7DATA-1LBR		26k 08/20/85 16:44 Irv Hoff
;
;		(after)
;
; D/U	 Filename   Size   Speed      Date    Time   Uploaded by
;
; B00: M7DATA-1.LBR  26k  1200 bps  08/20/85  16:44  Irv Hoff
;
;-----------------------------------------------------------------------
;
; Features:
; ---------
;	1) Should be placed in A0: so any user can call the program
;	2) Should be renamed to NEW.COM at that time
;	3) Automatically remembers current drive/user area
;	4) Jumps to A14: to read the KMD.LOG file, with full security
;	5) Opens the KMD.LOG file, if empty says "NO NEW FILES"
;	6) Copies each line starting with "R" into a one-line buffer
;	7) Customizes that line, if OPTION 1 or 2 is selected
;	8) Stores the line in a memory buffer
;	9) When all lines are read, displays them in inverse order,
;		thus showing most recent files first.
;      10) CTL-C, CTL-K, CTL-X, C, K, X, c, k, x all will abort after
;		finishing the current line.
;      11) Can be called from any drive/user area
;      12) Returns to original drive/user area from which it was called
;
; The SYSOP can readily customize this program to suit his preferences.
; The area around HEAD: would be the sections to customize if
; selection 1 or 2 is not sufficient.
;					- Notes by Irv Hoff W6FFC
;
;-----------------------------------------------------------------------
;
; 07/17/85  First version based on my WHATSNEW, version 03.
;					- Irv Hoff
;
;-----------------------------------------------------------------------
;
; User choices
;
SHOWAL	EQU	1		; 0=all file transfers, 1=uploads only
OPTION	EQU	2		; Must be 0, 1 or 2 (see above)
HEADER	EQU	1		; 0=no header, regardless of option
;
DRIVE	EQU	'A'		; KMD.LOG stored here in your system
USER	EQU	14		; KMD.LOG stored here in your system
;
WHEEL	EQU	003EH		; Location of wheel byte for RCPM use
;-----------------------------------------------------------------------
;
; Equates
;
CR	EQU	0DH		; Carriage return
EOF	EQU	1AH		; End of file - ^Z
LF	EQU	0AH		; Line feed
TBUF	EQU	0080H		; Default buffer address
;
;-----------------------------------------------------------------------
;
; BDOS equates
;
BDOS	EQU	0005H		; CP/M BDOS entry address
RDCON	EQU	1		; Get character from console
WRCON	EQU	2		; Write character to console
PRINT	EQU	9		; Print string (DE) until '$'
CONST	EQU	11		; Get console status function
SELDSK	EQU	14		; Select requested disk drive
OPEN	EQU	15		; Open disk file
CLOSE	EQU	16		; Close disk file
READ	EQU	33		; Read random file
STDMA	EQU	26		; Set DMA address
SETUSR	EQU	32		; Set user area on disk
;
;-----------------------------------------------------------------------
;
; Program starts here
;
;
	ORG	100H
;
	JMP	START
;
;
SHOL:	DB	SHOWAL		; Shows complete KMD.LOG in reverse
OPTN:	DB	OPTION		; Simple selection without assembling
HDR:	DB	HEADER		; Selects header option
;
;
START:	LXI	H,0
	DAD	SP		; Get 'CCP' stack
	SHLD	STACK		; Save it for exit
	LXI	SP,STACK	; Set stack pointer
;
	LDA	0004H		; Get current drive/user
	STA	DRUSER		; Store
;
;
; Set drive/user to the KMD.LOG area listed above
;
	MVI	E,USER		; Set user to KMD.LOG area
	MVI	C,SETUSR
	CALL	BDOS
;
	MVI	A,DRIVE		; Set drive to KMD.LOG area
	SUI	41H
	MOV	E,A
	MVI	C,SELDSK
	CALL	BDOS
;
;
; Open source file
;
	CALL	ILPRT
	DB	CR,LF,0
	LXI	D,FILE
	MVI	C,OPEN
	CALL	BDOS
	INR	A		; Check for no open
	JZ	NONE		; No file, exit
;
	CALL	ILPRT
	DB	'NEW Type ^S to pause, ^C, ^X or ^K to abort'
	DB	CR,LF,LF,0
;
	LXI	D,FILE
	MVI	C,35		; Determine end-of-file
	CALL	BDOS
	LXI	D,BUFFER+81	; Stick a CR so it will get by the first time
	MVI	A,CR
	STAX	D		; Save it now
	DCR	E
	CALL	HEAD
;
READX:	PUSH	D
	LXI	H,RECORD	; Decrement record counter
	MOV	E,M		; Get 16 bit number into DE
	INX	H
	MOV	D,M
	DCX	D		; Now that we have the number, decrement
	MOV	M,D		; And now store it again
	DCX	H
	MOV	M,E
	MOV	A,E		; Now lets see if we are at the end
	CPI	0FFH		; First check high #
	JNZ	READLP		; Ok, go on - else,, check low number
	MOV	A,D
	CPI	0FFH		; One past zero, so we can get the last record
	JZ	TDONE		; We are at the end, so now finished with job
;
;
; Read sector from source file
;
READLP: LXI	D,TBUF		; Set the DMA for our read
	MVI	C,STDMA
 	CALL	BDOS		; And do it now
;
	LXI	D,FILE		; Now read the record
	MVI	C,READ
	CALL	BDOS
	POP	D		; Restore register
;
	ORA	A		; Read ok?
	JZ	GOAHEAD		; Yes, procede
	CALL	EXIT
	DB	CR,LF,'++ SOURCE FILE READ ERROR ++','$'
;
GOAHEAD:LXI	H,TBUF+127	; Set up end of buffer
	MVI	B,128		; The buffer will be filed up backwards
ONEMORE:MOV	A,M		; Get character
	ANI	7FH
	CPI	LF		; Check for end of line -- LF is our marker
	JZ	WRDISK		;  that we will use to determine each line
	CPI	7FH
	JZ	NEXTONE
	CPI	1AH		; Check for CTRL-Z, end-of-file marker
	JZ	NEXTONE
	XCHG
	MOV	M,A		; Store character in our working buffer
	XCHG
	DCR	E		; Decrement counters (DE=work buffer)
NEXTONE:DCR	L		;              (HL=DMA)
	DCR	B		;              (B=Counter for number of char.)
	JZ	READX		; If zero, go read another record
	JMP	ONEMORE
;
; Write sector to output file (with buffering)
;
WRDISK:	DCR	B		; Decrement our counter
	PUSH	PSW		; As well as the flags
	DCR	L		; Decrement our DMA buffer
	PUSH	H		; Save it
	PUSH	B		; Save counter
	XCHG			; HL will now be our working buffer
	MOV	M,A		; Go save CR
	LDA	SHOL		; Check options
	ORA	A
	JZ	WRDLOP		; If show all, go show all now
	INR	L		; If not, go see if it is a uploaded file
	MOV	A,M
	STA	STORE2		; Store this away for later
	DCR	L
	CPI	'S'		; Was this a "Send" file
	JZ	SENDX		; Yes, so go on
	CPI	'L'		; A "Library" file
	JZ	SENDX		; Yes, so go on
	LDA	WHEEL		; Check wheel for private files
	ORA	A
	JNZ	WRDLOP		; Ok, cheeck if it was a private file
	LDA	STORE2
	CPI	'P'		; It was Private, and wheel was not set, 
	JZ	SENDX		; So goodbye
;
WRDLOP:	MOV	A,M		; Get byte from read buffer
	MOV	B,A		; Save the character for now
	CPI	CR
	JZ	SENDLF		; Go send a CR and start all over again
	CPI	LF		; If LF then just send it to output
	JZ	SEND
;
; Will show entire KMD.LOG in reverse if requested
;
 	LDA	SHOL		; Check to see if show entire file
	ORA	A
	JZ	SEND
	LDA	COLUMN		; See if in first column
	ORA	A
	JNZ	WRDL3		; If not, exit
	INR	A
	STA	COLUMN		; Won't be in first column any longer
;
;
; Shows "P" entries only if wheel byte is set for SYSOP's use
;
	MOV	A,B		; Get the character back
	CPI	'P'		; This line a private upload?
	JNZ	WRDL1		; If not, exit
	LDA	WHEEL
	ORA	A
	JZ	WRD2		; "P" lines not shown without wheel byte
	STA	PRIVT		; To distinguish "P" lines when shown
	STA	STORE		; Just in case it is
	JMP	WRDL4
;
WRDL1:	CPI	'S'
	JNZ	WRDL11
	XRA	A
	STA	STORE
	STA	COLUMN
	JMP	SENDX
;
WRDL11:	CPI	'R'		; This a "received file"?
	STA	STORE		; Set the flag just in case
	JZ	WRDL4		; If 'R', keep the flag set
;
WRD2:	XRA	A
	STA	STORE		; Otherwise reset flag to zero
;
WRDL3:	LDA	STORE		; Storing into memory?
	ORA	A
	JZ	NEXT		; If not, exit
;
WRDL4:	LDA	COLUMN		; Increment the column counter
	INR	A
	STA	COLUMN
;
;
; The following retains original format of KMD "R" lines
;
	LDA	OPTN		; Get option
	ORA	A
	JZ	SEND		; If not customizing, exit
	LDA	COLUMN		; Get the column count back
	CPI	3		; User's modem speed is in column 2
	JNZ	WR1		; If not column 2, continue
	MOV	A,B		; Otherwise get the character
	STA	STORE		; Store it for conversion to baud rate
	JMP	NEXT		; Do not print the "MSPEED" number
;
WR1:	CPI	11
	JC	NEXT		; Skip everything through column 9
	CPI	14
	JC	SEND		; Print everything through column 12
	JNZ	WR4
	LDA	PRIVT		; Going to distinguish a "P" line?
	ORA	A
	JZ	WR2
	XRA	A
	STA	PRIVT
	MVI	B,'*'
	CALL	SEND1
	JMP	WR3

;
WR2:	MVI	B,':'		; Stick in a colon after column 12
	CALL	SEND1
;
WR3:	MVI	B,' '		; Send a space
	JMP	SEND
;
WR4:	CPI	22		; Print through column 20
	JC	SEND
	JNZ	WR5
	CALL	SEND1		; Send character in colum 21
	MVI	B,'.'		; Add a period after the file name
	JMP	SEND
;
WR5:	CPI	27
	JC	SEND		; Print file type and some spaces
	CPI	39
	JC	NEXT		; Ignore the "big gap"
	CPI	43
	JC	SEND		; Print the file size
	JZ	WR6
;
;
; Customizes area after the file size
;
	LDA	OPTN
	CPI	1
	JZ	SEND		; If option 2, exit
	LDA	COLUMN		; Get the column count back again
	JMP	WR7		; If not column 42, continue
;
WR6:	CALL	SEND1		; Print first space
	CALL	SEND1		; Add two extras
	CALL	BAUD		; Print the baud rate and two spaces
	JMP	NEXT
;
WR7:	CPI	52
	JC	SEND		; Print the date
	JNZ	WR8
	CALL	SEND1		; Print first space after date
	JMP	SEND		; Add a space
;
WR8:	CPI	58
	JC	SEND		; Print the time program was sent
	JNZ	SEND		; If not column 57, continue
	CALL	SEND1		; Print the first space
	CALL	SEND1		; Add two spaces
	JMP	NEXT		; Continue with rest of line (name)
;
SEND:	PUSH	H		; Keep buffer address
	MOV	A,B		; Get the character back
	CALL	OUTCHR
	POP	H		; Get input buffer address back
;
NEXT:	INR	L		; Done with sector?
	JMP	WRDLOP		; No, get another byte
;...
;
;
SEND1:	PUSH	H		; Keep buffer address
	MOV	A,B		; Get the character back
	CALL	OUTCHR
	POP	H		; Get input buffer address back
	RET
;.....
;
;
SENDLF:	XRA	A
	STA	COLUMN		; Othewise in column 0 now
	CALL	ABORT		; Want to quit already?
;
SENDL1:	LDA	COUNT
	INR	A		; Just to get a positive value
	STA	COUNT		; Have at least one line to show
	CALL	ILPRT
	DB	CR,0
SENDX:	XRA	A		; Now restore everything so 
	STA	COLUMN		; We can get on with our business
	LXI	D,BUFFER+80
	POP	B
	POP	H
	POP	PSW
	JZ	READX		; If we out of character in DMA buffer, 
	JMP	ONEMORE		;  go read  a sector
;.....
;
;
;-----------------------------------------------------------------------
;
;			  SUBROUTINES
;
;-----------------------------------------------------------------------
;
; Aborts the display when requested, but only at end of line
;
ABORT:	PUSH	H		; Save the TBUF address
	PUSH	D
	PUSH	B
	MVI	C,CONST		; Check to see if key pressed
	CALL	BDOS
	ORA	A
	JZ	ABORT3		; If no key pressed, then continue
	MVI	C,RDCON		; If key pressed, then check for abort
	ANI	7FH		; Remove parity, insure upper-case
	CALL	BDOS
	CPI	'S'-40H		; CTL-S to pause?
	JNZ	ABORT1		; If not, exit
	MVI	C,RDCON		; Otherwise wait for another character
	CALL	BDOS
	ANI	7FH		; Remove parity, insure upper-case
;
ABORT1:	CPI	'C'-40H		; Is it CTL-C?
	JZ	ABORT2
	CPI	'K'-40H		; Is it CTL-K?
	JZ	ABORT2		; If no, then continue
	CPI	'X'-40H		; Is it CTL-X?
	JZ	ABORT2
	ANI	5FH		; Convert to upper-case
	CPI	'C'
	JZ	ABORT2
	CPI	'K'
	JZ	ABORT2
	CPI	'X'
	JNZ	ABORT3
;
ABORT2:	POP	B		; Reset the stack
	POP	D
	POP	H
	POP	H		; Clear "CALL ABORT" from stack
	CALL	EXIT		; If yes, then print abort message
	DB	CR,LF,LF,'++ ABORTED ++','$'
;
ABORT3:	POP	B
	POP	D
	POP	H
	RET
;.....
;
;
; Shows the received baud rate
;
BAUD:	LDA	STORE
	CPI	'0'
	JZ	B110
	CPI	'1'
	JZ	B300
	CPI	'5'
	JZ	B1200
	CPI	'6'
	JZ	B2400
	MVI	B,' '
	CALL	SEND1
	CALL	SEND1
	CALL	SEND1
	CALL	SEND1
	JMP	BFIN2
;...
;
;
B110:	MVI	B,' '
	CALL	SEND1
	MVI	B,'1'
	CALL	SEND1
	MVI	B,'1'
	CALL	SEND1
	JMP	BFIN1
;
B300:	MVI	B,' '
	CALL	SEND1
	MVI	B,'3'
	JMP	BFINSH
;
B1200:	MVI	B,'1'
	CALL	SEND1
	MVI	B,'2'
	JMP	BFINSH
;
B2400:	MVI	B,'2'
	CALL	SEND1
	MVI	B,'4'
;
BFINSH:	CALL	SEND1
	MVI	B,'0'
	CALL	SEND1
;
BFIN1:	MVI	B,'0'
	CALL	SEND1
;
BFIN2:	MVI	B,' '
	CALL	SEND1
	MVI	B,'b'
	CALL	SEND1
	MVI	B,'p'
	CALL	SEND1
	MVI	B,'s'
	CALL	SEND1
	MVI	B,' '
	CALL	SEND1
	MVI	B,' '
	JMP	SEND1
;.....
;
;
; Print message then exit to CP/M
;
EXIT:	POP	D		; Get message address
	MVI	C,PRINT		; Print message
	CALL	BDOS
	CALL	ILPRT		; Print CRLF before quitting
	DB	CR,LF,0
;
	LDA	DRUSER		; Get original drive/user area back
	RAR
	RAR
	RAR
	RAR
	ANI	0FH		; Just look at the user area
	MOV	E,A
	MVI	C,SETUSR	; Restore original user area
	CALL	BDOS
;
	LDA	DRUSER		; Get the original drive/user back
	ANI	0FH		; Just look at the drive for now
	MOV	E,A
	MVI	C,SELDSK	; Restore original drive
	CALL	BDOS
;
	LHLD	STACK
	SPHL
	RET
;.....
;
;
; Inline print routine - prints string pointed to by stack until a zero
; is found.  Returns to caller at the next address after the zero ter-
; minator.
;
ILPRT:	XTHL			; Save HL, get message address
;
ILPLP:	MOV	A,M		; Get the character
	CALL	TYPE		; Show on the CRT
	INX	H		; Next character location
	MOV	A,M		; Get the character
	ORA	A		; If Zero, all done
	JNZ	ILPLP		; Else keep going
	XTHL			; Restore HL, ret address
	RET			; Return past the end of the message
;.....
;
;
; Output a character to the new file buffer - first, see if there is
; room in the buffer for this character.
;
OUTCHR:	PUSH	PSW		; Store the character for now
	CALL	TYPE
	POP	PSW
	RET
;.....
;
;
; Transfer is done - close destination file
;
TDONE:	MVI	C,CLOSE
	LXI	D,FILE
	CALL	BDOS
TDONE2:	CALL	EXIT
	DB	CR,LF,LF,CR,'[End of listing]','$'
;.....
;
;
;  Show the header at the beginning
;
HEAD:	LDA	HDR		; Using a header?
	ORA	A
	RZ			; If not skip header
	LDA	SHOL		; Showing entire KMD.LOG?
	ORA	A
	RZ			; If yes, don't bother with header
;
;
; Customizes header
;
	LDA	OPTN
	ORA	A
	RZ
	CALL	ILPRT
	DB	CR,'D/U    Filename   Size   Speed    ',0
	LDA	OPTN
	CPI	1
	JZ	TDONE1
	CALL	ILPRT
	DB	'  Date    Time   Uploaded by',0
	RET
;
TDONE1:	CALL	ILPRT
	DB	'Uploaded by  Date',0
	RET
;.....
;
;
; Send character in A register to console
;
TYPE:	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A		; Character to 'E' for CP/M
	MVI	C,WRCON		; Write to console
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;.....
;
;
NONE:	CALL	EXIT
	DB	CR,'++ NO NEW FILES ++','$'
;
;
; 'Declare' output file
;
FILE:	DB	0
	DB	'LOG     SYS'
	DB	0,0,0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0,0,0,0
RECORD:	DB	0,0,0
;
COLUMN:	DB	0		; Column of KMD.LOG line
COUNT:	DB	0
DRUSER:	DB	0		; Original drive/user, for return
LENGTH:	DB	0		; Maximum length of useable memory
PRIVT:	DB	0		; Distinguishes "P" lines if shown
STORE:	DB	0
STORE2:	DB	0
;
	DS	100		; Room for 50-level stack
;
;
; Set write buffer to even page boundry
;
;
BUFFER	DS	81		; Write buffer starts here
STACK	EQU	BUFFER-2
;
;
	END	START
; Set