;**********************************************************
;
;               USRDFLT2.CCP by R. L. Plouffe
;                      (703) 527-3215
;                       June 4, 1981
;
;               For CP/M 2.x systems only.
;
;       Changed the code that restricts access to
;       USER areas in order to take advantage of
;       routines already in the CCP. Reduces the
;       code that must be placed in your customiz-
;       ed bios considerably...........RLP 6/4/81
;
;       Originally written 5/26/81. This has been
;       re-written to clean it up and to add labels
;       and comments so it can be easily read.
;       ...............................RLP 5/31/81
;
;These routines are based on ideas and code found on the
;CALAMITY CLIFFS machine.  Authors are apparently Ron Fowler
;and Keith Peterson. What is done here is to integrate these
;ideas and to add two important new features.  First a new
;kind of CCP command is added that is a pseudo CCP transient.
;These commands reside on disk as a transient, but may be called
;from any user area and any logged drive as long as they reside
;on drive A and in a pre-designated USER area. Second, the newly
;defined pseudo CCP/transients as well as existing (or additional)
;CCP commands may be defined as either public or private with
;private commands being accessible only after becoming password
;privileged. It should be apparent that among other things, these
;integrated routines avoid the necessity of placing copies of
;transient routines that are included in the pseudo definition
;in multiple USER areas. Certainly a must for PIP at least.

;Add this code to your customized user or BIOS file and the
;CCP patches will be automatically overlayed when you put it
;in with DDT provided that your file contains an equate for
;the CCP beginning address for your system size. NOTE that the
;command address table and the command strings have been taken
;out of the CCP.  However, the code space that they occupied has
;been well stuffed with other patch code. An 18 byte spare area
;at the end of the BDOS is also used. Make sure that your version
;has this spare area still available and has not been used by some-
;ones customization.  If it has, then place the code at the label
;BRIDGE into your customized BIOS.

;Donated for the benefit of hobby computing.  This creation
;may not be sold.
;
;
CCP     EQU     YOUR CCP ADDRESS        ;BASE OF CCP
;
BDOS    EQU     CCP+800H                ;BASE OF BDOS
BIOS    EQU     CCP+1600H               ;BASE OF BIOS
DFCB    EQU     5CH             ;ADDR OF DEFAULT FILE CNTRL BLK
DRIVE   EQU     04H             ;LOC OF CURRENT DRIVE BYTE
CR      EQU     0DH
LF      EQU     0AH
;
LENCMD  EQU     5               ;LENGTH OF CCP CMD STRINGS
MAXUSER EQU     4               ;FOR EXAMPLE
BUFSIZE EQU     CCP+6H          ;LOC OF SIZE BYTE FOR CCP BUF
BDOSFNC EQU     BDOS+6H         ;BDOS FUNCTION
GETUSR  EQU     CCP+113H        ;GET USER #
SETUSR  EQU     CCP+115H        ;SET USER #
TSTUSR  EQU     CCP+692H        ;TEST USER #
USRSAV  EQU     CCP+118H
CCPPASS EQU     CCP+7EH         ;LOCATION OF CCP PASSWORD
UPATCH0 EQU     CCP+390H
UPATCH1 EQU     CCP+393H
HUH     EQU     CCP+209H        ;CCP HUH RESPONSE
CRLF    EQU     CCP+98H         ;CCP CR/LF FUNCTION
RETCCP  EQU     CCP+382H        ;RE-ENTRY TO CCP
CMDPTR  EQU     CCP+3B5H        ;POINTER TO COMMAND ADDR TBL
STRPTR  EQU     CCP+32FH        ;POINTER TO CCP CMD STRINGS
CMDCNT  EQU     CCP+335H        ;BYTE VALUE = # OF COMMANDS
CMDLEN  EQU     CCP+33BH        ;BYTE VALUE = LENGTH OF EACH
                               ;COMMAND STRING.
TSTOPN  EQU     CCP+6DCH        ;TEST FILE OPEN FUNCTION
CMDDRV  EQU     CCP+7F0H        ;BYTE INDICATES DRV IN CMD
CMDERR  EQU     CCP+76BH        ;HUH RESPONSE IF DR #
XTNSN   EQU     CCP+7D6H        ;STORAGE LOC FOR FILE TYPE,
                               ;EXT #, AND RECORD COUNT
RELOOK  EQU     CCP+6CDH        ;RELOOK W/INDICATED DRIVE
TPASUB  EQU     CCP+75DH        ;LOC TO SUSTITUTE BEFORE
                               ;CALLING THE TPA
CONTINUE EQU    CCP+75FH        ;TO CONTINUE AFTER CALL TO TPA
GETRANS EQU     CCP+6A5H        ;GET TRANS OR CCP COMMAND
ERA     EQU     CCP+51FH        ;ADDR OF ERA ROUTINE
REN     EQU     CCP+610H        ;ADDR OF REN ROUTINE
SAVE    EQU     CCP+5ADH        ;ADDR OF SAVE ROUTINE
DIR     EQU     CCP+477H        ;ADDR OF DIR ROUTINE
TYPE    EQU     CCP+55DH        ;ADDR OF TYPE ROUTINE
USER    EQU     CCP+68EH        ;ADDR OF USER ROUTINE
TPA     EQU     100H            ;OR YOUR TPA ADDRESS
CCPSPARE EQU    CCP+7F2H        ;14 SPARE BYTES AT END OF CCP
BDOSPARE EQU    BDOS+0DEEH      ;18 SPARE BYTES AT END OF BDOS
       ;Addresses of holes left in CCP that are filled in
       ;with patches for transient user defaults
HOLE1   EQU     CCP+310H        ;EXACTLY 24 BYTES HERE
HOLE2   EQU     CCP+3C1H        ;   "     6   "     "
HOLE3   EQU     CCP+3C7H        ;   "     8   "     "
;
;**********************************************************
;       BEGINNING OF CODE THAT IS PATCHED INTO THE CCP
;**********************************************************
;This is the CCP password to obtain privilege to higher USER
;areas and privileged CCP or transient commands.  The password
;itself is ORGed at the very end of the CCP command buffer.
;The buffer is resized to permit this location. The advantage
;to this ORG is that any attempt to find it with DDT will be
;unsuccessful since DDT overlays the CCP, so this is an added
;measure of security. If you lengthen the password, reduce the
;value of the CCPPASS equate for each additional character in the
;password.  Password may be mixed upper and lower case characters.
;
       ORG     CCPPASS
PASSWD: DB      'URPASSWRD',CR
       ORG     BUFSIZE
       DB      75H             ;10 bytes less than original
;
;The CCP-included command 'PASS' routine is at CKCCPAS which
;is located in your customized BIOS.
;**********************************************************
; This patch is used to restrict access to the higher user
; areas while leaving the lower user areas public. The high-
; est available public user area is defined by MAXUSER.
;
       ORG     USRSAV
       DW      SAVUSR          ;ADDR TO JMP TO SO THAT
                               ;CALLING USER NUMBER IS RE-
                               ;TURNED TO AFTER EXECUTING
                               ;A TRANSIENT
;The routines are located in your customized BIOS.
;**********************************************************
; This patch causes user number to be reported at the cp/m
; prompt.....i.e. - A2>.  User 0 report is suppressed.
;
       ORG     UPATCH0
       MVI     C,USRFNC        ;VALUE FOR USER FNC CALL
       ORG     UPATCH1
       DW      UPATCH          ;ADDR OF PATCH TO CALL
;the routine UPATCH is located in the USER area of your
;customized BIOS
;**********************************************************
; This patch causes the CCP of a cp/m 2.x system to look on
; drive A when you are logged into a drive other than A and
; call for a .COM file that does not exist on that drive.
; Giving an explicit drive reference overrides this feature,
; so that you can always force the file to be loaded from a
; specific drive.
;
       ORG     TSTOPN
       DW      APATCH          ;REPLACES 'CMDERR'
;
       ORG     CCPSPARE
APATCH: LXI     H,CMDDRV        ;GET DRIVE FROM CURRENT CMD.
       ORA     M               ;FETCHES DRIVE
       JNZ     CMDERR          ;GIVE ERROR IF CMD HAS DRIVE #
       INR     M               ;FORCE TO DRIVE A
       LXI     D,XTNSN         ;UNDO WHEN...
       JMP     RELOOK          ;REENTERING CCP
;
;**********************************************************
;This patch extends the CCP to include up to N additional
;commands that are user defined. The commands may be either
;CCP-included or transient, and may be either private or
;public depending on password privilege.
;
       ORG     CMDPTR
CMDPTR: DW      CMDTBL2         ;COMMAND TABLE ADDRESS (PUBLIC)
       ;
       ORG     STRPTR
STRPTR: DW      CMDSTR2         ;COMMAND STRING ADDRESS (PUBLIC)
       ;
       ORG     CMDCNT
CMDCNT: DB      (GETRAN0-CMDTBL2)/2 ;TO LIMIT PUBLIC ACCESS TO CCP
                                  ;COMMANDS. RESET TO ALL WHEN
                                  ;PASSWORD IS ENTERED FOR USER
                                  ;AREAS ABOVE MAXUSER.
       ORG     CMDLEN
CMDLEN: DB      LENCMD          ;LENGTH OF CCP COMMAND STRINGS

;The rest of this patch is in the USER area of your customized
;BIOS.
;
;**********************************************************
;This is the routine that cause those utilities which are in
;the CCP command table to be available from all user areas.
;They must be resident in USER 0 or 15 and named the same as in
;command string....i.e, 'EDIT' for 'WORDSTAR',  'STAT' for 'STAT',
;etc.. The names and addresses can be in either the public or
;private areas. Don't expand this code except to use indicated
;spare bytes because you will wipe out other good code if you
;do.
;
       ORG     HOLE2
TRDFLT0:
       MVI     E,0             ;VALUE FOR PUBLIC TRANSIENTS
       PUSH    D               ;SAVE IT ON THE STACK
       JMP     DFLT            ;TO DEFAULT TO USER VALUE
       ORG     HOLE1
TRDFLT15:
       MVI     E,15            ;VALUE FOR PRIVATE TRANSIENTS
       PUSH    D               ;SAVE IT ON THE STACK
DFLT:
       CALL    GETUSR          ;GET CALLING USER #
       STA     HOLDUSER        ;SAVE IT
       POP     D               ;GET DEFAULT USER VALUE IN E
       CALL    SETUSR          ;SET THE USER # IN BDOS
       LXI     H,RSTUSR        ;PUT ADDR OF RTNE IN HL
       SHLD    TPASUB          ;SET TO CALL IT INSTEAD OF TPA
       JMP     GETRANS         ;GET THE FILE TO THE TPA
       DB      0,0             ;SPARE BYTES
;
       ORG     HOLE3
RSTUSR: LDA     HOLDUSER        ;GET THE SAVED USER #
       MOV     E,A             ;PUT IT IN E
       JMP     BRIDGE
HOLDUSER:
       DB      0
       ORG     BDOSPARE        ;SPARE BYTES HERE IN BDOS
BRIDGE: CALL    SETUSR          ;SET USER #
       LXI     H,TPA           ;PUT ADDR OF TPA IN HL
       SHLD    TPASUB          ;SET TO CALL TPA NEXT TIME
       CALL    TPA             ;DO IT NOW
       JMP     CONTINUE        ;BACK TO CCP IN-LINE CODE
       DB      0,0,0           ;SPARES
;
;       END OF CODE THAT IS PATCHED INTO THE CCP (AND BDOS)
;                       *****
;
;**********************************************************
;       BEGINNING OF CODE THAT IS PUT IN YOUR BIOS.
;       SEE GENESYS AND GENEUSER FOR A TECHNIQUE TO
;       EXPAND YOUR USER AREA.
;**********************************************************

       ORG     BIOS+WHATEVER

;This is the command string which is divided into private
;and public sections. Do not use more than five letters for
;the name of any command or transient and fill out each string
;to exactly five characters by using spaces below. Each string
;must occur at 5 character intervals.  If you wish to use some
;other string length such as 4 as in the original CCP, just
;change the string lengths below and change the LENCMD equate
;from 5 to 4.  I use 5 below so that MODEM can fit.
;
CMDSTR1:
       DB      'ERA  REN  SAVE STAT PIP  DDT  ASM  LOAD COPY EDIT '
CMDSTR2:
       DB      'SRD  DIR  TYPE USER PASS MODEMBYE  CRCK '
;
;**********************************************************
;This is the command address table which is divided into
;private and public areas. The address of the routine to be
;jumped to must be here for any CCP-included code as well as
;any that you add and put in your customized BIOS. For private
;and public transients, use TRDFLT15 AND TRDFLT0 respectively
;and put private transients in USER 15 on your system disk (A).
;Similarly, put public transients in USER 0 on 'A'. These trans-
;ients will now be available from any drive and from any USER #
;depending on password privilege.  You can expand the table to
;any extent that you have space and the command string above
;must be expanded in synchronism.
;
;Put the private transients in USER 15
CMDTBL1:
       DW      ERA             ;ERA....PRIVATE COMMANDS
       DW      REN             ;REN
       DW      SAVE            ;SAVE
       DW      TRDFLT15        ;STAT...THE FOLLOWING UTILITIES
       DW      TRDFLT15        ;PIP....WILL BE TREATED AS CCP
       DW      TRDFLT15        ;DDT....COMMANDS. THEY MUST BE ON
       DW      TRDFLT15        ;ASM....DISK AS TRANSIENTS AT USER 15
       DW      TRDFLT15        ;LOAD...AND WILL NOW BE AVAILABLE AT
       DW      TRDFLT15        ;COPY...ALL USER #'S
       DW      TRDFLT15        ;EDIT (RENAME WORDSTAR TO EDIT),
                               ;or whatever your favorite editor is.
;Put the public transients below in USER 0
CMDTBL2:
       DW      TRDFLT0         ;SRD ....PUBLIC COMMANDS
       DW      DIR             ;DIR
       DW      TYPE            ;TYPE
       DW      USER0           ;USER
       DW      CKCCPAS         ;PASS(WORD)
       DW      TRDFLT0         ;MODEM for Ward's MODEM program.
                               ;I use this command for either
                               ;XMODEM or MODEM7 depending on
                               ;which one I have on drive A.
       DW      TRDFLT0         ;BYE  for Ward's BYE program
       DW      TRDFLT0         ;CRCK does a CRC 16 check on file
GETRAN0:                        ;This must be last entry in table.
       DW      GETRANS         ;Get the transient and execute or
                               ;return to CCP w/HUH message if not
                               ;on disk.
;
;**********************************************************
;This patch which is called from the CCP provides for a
;report of USER number at the prompt....i.e. A2> for USER 2,
;'A' drive.
;
UPATCH: LDA     PASSFLG         ;GET PASSWORD FLAG
       INR     A               ;SEE IF SET
       JNZ     UPATCH2         ;SKIP IF NOT
       LXI     H,CMDSTR1       ;SET CMDSTRING POINTER TO
                               ;BEGINNING OF ALL COMMANDS
       SHLD    STRPTR          ;STORE IT IN STRING POINTER
       LXI     H,CMDTBL1       ;SET CMDTABLE POINTER TO
                               ;BEGINNING OF ALL CMD ADDRESSES
       SHLD    CMDPTR          ;STORE IT IN COMMAND TABLE POINTER
       MVI     A,(GETRAN0-CMDTBL1)/2 ;CALC # OF COMMANDS
       STA     CMDCNT          ;STORE VAL IN SCAN ROUTINE IN CCP
UPATCH2:
       CALL    GETUSR          ;GET USER NUMBER
       ANI     0FH             ;KILL UNWANTED BITS
       JZ      UPA2            ;IF USER 0, DON'T REPORT
       CPI     10
       JC      UPA1            ;JIF USER NUM = 0 THRU 9
       SUI     10              ;USER NUM = 10 THRU 15
       PUSH    PSW
       MVI     E,'1'
       MVI     C,CONSOUT       ;VAL FOR CONSOLE OUT FNC
       CALL    BDOSFNC         ;PRINT A '1'
       POP     PSW
;
UPA1:   ADI     '0'
       MOV     E,A
       MVI     C,CONSOUT       ;VAL FOR CONSOLE OUT FNC
       CALL    BDOSFNC         ;PRINT DIGIT
;
UPA2:   MVI     E,'>'
       MVI     C,CONSOUT       ;VAL FOR CONSOLE OUT FUNCTION
       JMP     BDOSFNC         ;PRINT '>', EXIT
;
;**********************************************************
;These are the routines which provide for limited USER area
;access.  USER0 is jumped to before jumping from the CCP com-
;and parser to the CCP-included USER routine.  SAVUSR is jumped
;to whenever resetting the user code and guarantees that the
;same user area will be returned to as was in effect before
;executing a transient command.
;
USER0:  LDA     PASSFLG         ;SEE IF PRIVILEGED
       INR     A               ;YES?
       JZ      USER            ;TO USER CODE IF SO
       MVI     A,MAXUSER+1     ;RESTRICT ACCESS
       STA     TSTUSR          ;DO IT HERE
       JMP     USER            ;GOTO CCP USER CODE
;
SAVUSR: MOV     A,E             ;SEE IF GET OR SET USER
       CPI     0FFH            ;IS IT GET USER?
       JZ      BDOSFNC
       MOV     A,E             ;GET USER #
       RLC
       RLC
       RLC
       RLC                     ;MOVE TO UPPER NIBBLE
       MOV     B,A             ;SAVE REQUESTED USER #
       LDA     DRIVE           ;GET CURRENT USER/DRIVE
       ANI     0FH             ;STRIP OFF OLD USER #
       ORA     B               ;GET NEW USER #
       STA     DRIVE           ;SET NEW USER #
       JMP     BDOSFNC         ;SET IT AND EXIT
;
PASSFLG:
       DB      0               ;STORE FOR PASSWORD FLAG
CKCCPAS:
       LXI     H,PASSWD        ;POINT TO PASSWORD
CKPASS: LDA     PASSFLG         ;GET PASSWORD FLAG
       INR     A               ;SEE IF SET
       JZ      RETCCP          ;IF SO, RET TO CCP
       CALL    CRLF            ;DO A CR/LF
       MVI     D,0             ;NO MISSED LETTERS
PWMLP:  PUSH    D
       PUSH    H
PWMLP1: MVI     C,DIRCONIO      ;GET A CHAR
       MVI     E,0FFH          ;SET TO CONSOLE IN
       CALL    BDOSFNC         ;DO IT
       ORA     A               ;SEE IF CHAR ENTERED
       JZ      PWMLP1           ;LOOP IF NOT
       POP     H
       POP     D
       CMP     M               ;MATCH PASSWORD?
       JZ      PWMAT           ;..YES
       MVI     D,1             ;..NO, SHOW MISS
       CPI     CR
       JNZ     PWMLP           ;..NO, WAIT FOR C/R
       JMP     HUH             ;RETURN TO CCP WITH A HUH
;
PWMAT:
       INX     H
       CPI     CR              ;SEE IF END OF PASSWORD
       JNZ     PWMLP           ;GET ANOTHER CHAR IF NOT
       MOV     A,D             ;ERROR INDICATOR TO A
       ORA     A               ;ERROR?
       JNZ     HUH             ;IF SO, SAY HUH
       MVI     A,0FFH          ;VAL FOR PASSWORD FLAG
       STA     PASSFLG         ;SET IT
       MVI     A,16            ;RESTORE
       STA     TSTUSR          ;ALL USER AREAS
       JMP     RETCCP          ;AND RETURN TO CCP
;
;
;BDOS FUNCTION CALL EQUATES
;
CONSOUT EQU     2               ;CONSOLE OUTPUT
DIRCONIO EQU    6               ;DIRECT CONSOLE INPUT OUTPUT
USRFNC  EQU     32              ;USER FUNCTION CODE
;
;       the
       END
;       for now