home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
nubye
/
nukmd111.ark
/
NUKMD111.FL1
< prev
next >
Wrap
Text File
|
1987-02-03
|
80KB
|
3,532 lines
; -------------------
; PROGRAM STARTS HERE
; -------------------
;
; Save CP/M stack, initialize new one for NUKMD and check to see if
; NUBYE is available before continuing.
;
BEGIN: LXI H,0
DAD SP
SHLD STACK ; Save current return to CCP address
LXI SP,STACK ; Reset the stack
;
; Show program name and version number
;
CALL ILPRT
DB CR,LF,'NUKMD v',MAIN+'0','.'
DB VERS/10+'0',VERS MOD 10+'0',' - '
DB MONTH/10+'0',MONTH MOD 10+'0','/'
DB DAY/10+'0',DAY MOD 10+'0','/'
DB YEAR/10+'0',YEAR MOD 10+'0',' '
DB CR,LF,0
;
MVI C,32
MVI E,241
CALL BDOS ; See if NUBYE is running
CPI 77
JZ BEGIN1 ; We're ok
CALL ILPRT
DB CR,LF,BELL
DB '** NUBYE Unavailable -- Initiating Test Mode **'
DB CR,LF,0
JMP OPTERR
;
; Save the current d/u area
;
BEGIN1: MVI E,0FFH
CALL USRSET
STA OLDUSR ; Save for now
MVI C,CURDRV
CALL BDOS
STA OLDDRV
;
IF WRTLOC ; Set write lock?
MVI C,75
MVI E,1
CALL BDOS ; Set the WRTLOC flag
ENDIF
;
IF RESUSR
MVI C,85 ; Access flags byte
MVI E,255
CALL BDOS ; Byte returned in 'A'
STA AFBYTE ; Store it
ENDIF
;
IF TIMEON OR CLOCK
CALL TIME ; Get user's time and status from NUBYE
ENDIF
;
; Gobble up garbage characters from the line prior to receive or send
;
CALL CATCH
;
; Check option for send or receive
;
LXI H,FCB+1
MOV A,M ; Get the main option
STA OPTSAV ; Save it for later use
STA CRCFLG ; Insure in CRC mode now
;
IF LOGCAL
STA LOGOPT ; Save for the station's log file
ENDIF
;
CPI 'L' ; Download an .LBR member?
JZ SETLAM
CPI 'A' ; Download an .ARK/.ARC member?
JZ SETLAM
CPI 'S' ; Download a normal file?
JZ CHKSND
CPI 'R' ; Upload a file?
JNZ OPTERR ; None of these, show help guide
;
LDA MSPEED
CPI 5 ; <1200 bps?
JC CKROPT ; Skip 1k stuff if so
STA KFLG ; Set the 1k flag for now
;
; Check for possible receive options
;
CKROPT: INX H
MOV A,M ; Get the receive option, if any
CPI 'P' ; Want a private upload?
JZ SETPRV
;
IF RESUSR AND PUPOPT
CPI 'W' ; Special privileged xfr request?
JNZ CKROP1 ; No, continue
MVI A,1
STA PUPFLG ; Show privileged xfr requested
JMP CKROP2 ; Check for more options
ENDIF
;
CKROP1: IF MSGFIL
CPI 'M' ; Message file?
ENDIF
;
JNZ CKROP3 ; None of these, it's not special
;
IF MSGFIL
STA MSGFLG ; Else set the message flag
MVI A,'P' ; ...and...
ENDIF
;
SETPRV: STA PRVTFL ; Set the private flag
;
CKROP2: INX H
JMP CKROP4
;
CKROP3: IF DESCRIB OR SETAREA
PUSH H
CALL WHAT ; Get category and/or drive/user area now
POP H
ENDIF
;
CKROP4: MOV A,M ; Get additional receive option, if any
CPI ' ' ; Next column a space character?
JZ RCKBCH ; If yes, see if requesting batch
CPI 'B' ; For batch mode
JZ RCKBCH
CPI 'C' ; Want checksum?
JZ RCKSM
CPI 'X' ; Want 128-character blocks?
JNZ RK ; No, so check for Ymodem request
;
R128: XRA A ; Reset the 1k block flag
STA KFLG
JMP RCRC
;
RK: LDA MSPEED
CPI 5 ; <1200 bps?
JC R128 ; Skip 1k stuff if so
MOV A,M ; ...else, get it back
CPI 'K' ; Want Ymodem?
JNZ OPTERR ; None of these, it's an error
CALL YMDMSG ; Show protocol
JMP RCVFL
;
; -----
;
SETLAM: STA LBRARC ; Set .LBR/.ARK/.ARC extraction flag
;
CHKSND: INX H ; Point to next command line character
MOV A,M ; Get it
CPI ' ' ; Anything?
JZ SNDFL ; No, finished checking
CPI 'X' ; 'X'modem protocol?
JNZ CHKSND1 ; No, continue checking
CALL XMDMSG ; Show protocol
JMP SNDFL
;
CHKSND1:CPI 'K' ; Force 1k transmissions?
JNZ CHKSND2 ; No, continue checking
LDA MSPEED ; Check speed being used
CPI 5
JC SNDFL ; Don't allow 1k blocks if 300 bps
STA KFLG ; Else set the 1k flag
CALL YMDMSG ; Show protocol
JMP SNDFL
;
CHKSND2:LDA LBRARC
ORA A ; Member extraction?
JNZ SNDFL ; Yes, ignore 'S'pecial and 'B'atch
MOV A,M ; Get character back
CPI 'B' ; Batch request?
JNZ CHKSND3 ; No, continue checking
STA YMODEM ; Prep for Ymodem batch send
JMP SBCH ; Go send batch
;
CHKSND3: IF ALTSEC
CPI 'S' ; 'S'pecial download?
JNZ CHKSND4 ; No, continue checking
STA SPLFL1 ; Set "special send" flag
STA SPLFL ; Set "private download" flag
JMP CHKSND ; Loop for more options
ENDIF
;
CHKSND4:CPI 'P' ; 'P'rivate?
JNZ CHKSND ; No, loop for more options
STA SPLFL ; Set the "private download" flag
JMP CHKSND ; Loop for more options
;
; Allows batch mode to private area if R, RB or RPB is typed
;
RCKBCH: LDA FCB1+1
CPI ' ' ; File requested?
JNZ RCRC ; Yes, can't use filename request in batch
INR A ; Will set batch flag to non-zero
STA INBTCH ; For MSGDSC
CALL BCHMSG ; Show batch enabled message
JMP RCVFL
;
RCRC: MVI A,1
STA CRCFLG ; Show in CRC mode
CALL XMDMSG ; Show protocol
JMP RCVFL
;
RCKSM: XRA A
STA CRCFLG
STA KFLG ; Can't use 1k blocks with checksum
CALL ILPRT
DB CR,LF,'(Xmodem Checksum / 128-byte packets)',CR,LF,0
JMP RCVFL
;
; Displays the Batch enabled message for send
;
SBCH: LDA SPLFL ; Sending from the private area?
ORA A
JNZ SNDFL ; If yes, skip batch message
INR A ; To set the batch flag to non-zero
CALL BCHMSG ; Display the batch message
JMP SNDFL
;
BCHMSG: STA BCHFLG ; Set the batch flag
LDA MSPEED ; Check speed being used
CPI 5
JC XMDMSG ; 1k packets not used at 300 bps
CALL ILPRT
DB CR,LF,'(Ymodem Batch CRC / 1k packets)',CR,LF,0
RET
;
XMDMSG: CALL ILPRT
DB CR,LF,'(Xmodem CRC / 128-byte packets)',CR,LF,0
RET
;
YMDMSG: CALL ILPRT
DB CR,LF,'(Ymodem CRC / 1k packets)',CR,LF,0
RET
;
; -----
;
; Show user available upload space when KMD A is entered
;
SPACE: IF NOT SETAREA
CALL ILPRT
DB CR,LF
DB 'Public uploads received on any disk/user area.',CR,LF
DB 'Use DIR to determine available free space.....',CR,LF,0
ENDIF
;
IF SETAREA AND USEMENU
CALL WHAT ; Give area/description options
ENDIF
;
IF SETAREA
CALL ILPRT
DB CR,LF,LF
DB 'Normal Uploads > ',0
LDA XDRV
CALL CTYPE
LDA XUSR
MVI H,0
MOV L,A
CALL DECOUT
MVI A,':'
CALL CTYPE
CALL ILPRT
DB ' (',0
LDA XDRV
STA KDRV
CALL KSHOW
MVI A,')'
CALL CTYPE
ENDIF
;
CALL ILPRT
DB CR,LF
DB 'Private Uploads > ',0
LDA XPRDRV
CALL CTYPE
LDA XPRUSR
MVI H,0
MOV L,A
CALL DECOUT
MVI A,':'
CALL CTYPE
;
IF SETAREA
LDA XPRDRV
MOV B,A
LDA XDRV
CMP B ; Both drives the same?
JZ NOSHO1 ; Yes, don't show free space twice
ENDIF
;
CALL ILPRT
DB ' (',0
LDA XPRDRV
STA KDRV
CALL KSHOW
MVI A,')'
CALL CTYPE
;
NOSHO1: CALL ILPRT
DB CR,LF,0
RET
;
; -----
;
; Help guide
;
; NUKMD entered by itself or incorrect command was given...
;
OPTER0: CALL MORE
OPTERR: CALL ILPRT
DB CR,LF,LF
DB ' << NUKMD HELP/INFORMATION MENU >>',CR,LF,LF
DB ' 1) Downloading',CR,LF
DB ' 2) Uploading',CR,LF
DB ' 3) Downloading .LBR/.ARK/.ARC file members',CR,LF
DB ' 4) General Information',CR,LF
DB ' 5) Check Available Disk Space',CR,LF
DB ' 6) EXIT to system',CR,LF,LF
DB ' Your choice : ',0
;
OPTER1: CALL INPUT ; Get a character
CPI '1' ; <1?
JC OPTER1
JNZ OPTER2 ; Not 1, so continue
CALL TYPE
;
; This section displays examples for DOWNLOAD.
;
HELP1: CALL ILPRT
DB CR,LF,LF
DB 'DOWNLOADS (from this system to you)'
DB CR,LF,LF
DB ' NUKMD S EXAMPLE.LBR Normal file download'
DB CR,LF
DB ' NUKMD S B1:EXAMPLE.DQC From a named d/u area'
DB CR,LF
DB ' NUKMD SB EXAMPLE.* 1k Ymodem Batch mode'
DB CR,LF
DB ' NUKMD SK EXAMPLE.LBR Force 1k Ymodem protocol'
DB CR,LF
DB ' NUKMD SX EXAMPLE.LBR Force Xmodem protocol'
DB CR,LF,0
JMP OPTER0
;
OPTER2: CPI '6'+1 ; >5?
JNC OPTER1 ; Wait for correct input
CALL TYPE ; Echo character typed
CPI '2'
JNZ OPTER3
;
; This section displays examples for UPLOAD.
;
HELP2: CALL ILPRT
DB CR,LF,LF
DB 'UPLOADS (from you to this system)'
DB CR,LF,LF
DB ' NUKMD R EXAMPLE.OBJ Normal file upload'
DB CR,LF
DB ' NUKMD RC EXAMPLE.LBR Force checksum'
DB CR,LF
DB ' NUKMD RP EXAMPLE.AQM Private upload'
DB CR,LF
DB ' NUKMD RPC EXAMPLE.DQC Force checksum'
DB CR,LF
DB ' NUKMD R 1k Ymodem Batch mode'
DB CR,LF
;
; This section displays example for special message file upload.
;
IF MSGFIL
DB LF
DB 'MESSAGE FILE UPLOAD (special function)'
DB CR,LF,LF
DB ' NUKMD RM UPLOAD.MSG Pre-formatted msg file xfr'
DB CR,LF
ENDIF
;
DB 0
JMP OPTER0
;
OPTER3: CPI '3'
JNZ OPTER4
;
; This section displays examples for downloading individual .LBR members,
; as well as a miscellaneous example for determining available upload space.
;
HELP3: CALL ILPRT
DB CR,LF,LF
DB 'DOWNLOADS (Special Command Option)'
DB CR,LF,LF
DB ' The "L" and "A" options are used to download single'
DB CR,LF
DB ' file members from within .LBR/.ARK/.ARC files. The'
DB CR,LF
DB ' .LBR/.ARK/.ARC extensions are not required.'
DB CR,LF,LF
DB 'EXAMPLES:'
DB CR,LF,LF
DB ' NUKMD L NUBYE101 NUBYE101.AQM {.LBR file}'
DB CR,LF
DB ' NUKMD LX NUBYE101 NUBYE.HQS Force Xmodem protocol'
DB CR,LF,LF
DB ' NUKMD A LIST556 L.DOC {.ARC/.ARK file}'
DB CR,LF
DB ' NUKMD AK LIST556 L.DOC Force 1k Ymodem protocol'
DB CR,LF,0
JMP OPTER0
;
OPTER4: CPI '4'
JNZ OPTER5
;
; This section displays general features and comments about KMD.
;
HELP4: CALL ILPRT
DB CR,LF,LF
DB 'General Features/Comments:'
DB CR,LF,LF
DB ' 1) NUKMD provides 100% support for Xmodem and'
DB CR,LF
DB ' Ymodem protocols.'
DB CR,LF
DB ' 2) NUKMD uses automatic protocol detection and will'
DB CR,LF
DB ' determine which mode to use for a transfer:'
DB CR,LF
DB ' Xmodem = 128-byte records (CRC or checksum)'
DB CR,LF
DB ' Ymodem = 1k-byte records (CRC only)'
DB CR,LF
DB ' 3) Ymodem BATCH transfers are also supported.'
DB CR,LF
DB ' 4) Individual file members may be extracted from'
DB CR,LF
DB ' .ARK (CP/M) and .ARC (MS-DOS) file collections'
DB CR,LF
DB ' via the "A" download option and from .LBR (both'
DB CR,LF
DB ' CP/M and MS-DOS) files via the "L" option.'
DB CR,LF,0
JMP OPTER0
;
OPTER5: CPI '5'
JZ OPTER6
CALL ILPRT
DB CR,LF,0
JMP EXIT ; Wants to exit
;
OPTER6: CALL SPACE ; Show free space
JMP OPTER0
;
; ===============================
; ---> SNDFL -- DOWNLOAD
; (from RCP/M system TO USER)
; ===============================
;
; The file specified in the NUKMD command line is transferred over the
; phone from the RCP/M system to another computer via modem using
; the "S" (send) option. The data is sent one record at a time, with
; headers and checksums and retransmissions on errors.
;
SNDFL: IF (MBBS OR PBBS) AND RESUSR
LDA SPLFL ; Requesting private download?
ORA A
JNZ SNDOK ; Yes, so ignore access level
LDA AFBYTE
ANI 20H ; Test bit 5 for download access
JZ DENIED
ENDIF
;
SNDOK: XRA A
STA SNDFLG ; Show in send mode
LDA BCHFLG ; Batch mode requested?
ORA A
JNZ SBTCH ; If yes, go handle batch mode
CALL LOGDU
;
SNDFL1: LDA LBRARC
ORA A ; Member extraction?
CZ CNREC ; No, compute record count
;
SNDFL2: CALL OPNFIL ; Open the file
CALL RDBLK1 ; Put up to 16k from file into buffer
CALL CATCH ; Clear the decks
MVI E,60 ; Wait up to 1 minute for initial 'NAK'
CALL WAITNAK
CALL SETFLG ; Can't use 1k if not 8 records in file
;
; Loops back to this point after a successful transmission for next one
;
SNDLP: CALL GTRATIO ; Check the ACK ratio if using 1k blocks
CALL RDRECD ; Read a record
JC SNDEOF ; Send 'EOF' if done
CALL INCRNO ; Bump record number if sent ok
CALL SNDABT ; Check for local abort
XRA A ; Initialize error count to zero
STA ERRCT
;
; Comes back here to repeat previous transmission if no ACK was received
;
SNDRPT: CALL CKABORT ; Check for remote abort
CALL FUNCHK ; Check the function keys
CALL SNDABT ; Check for local abort
CALL SNDHDR ; Send a header
CALL SNDREC ; Send data record
CALL SNDCHK ; Send CRC or checksum value
CALL GTACK ; Get the 'ACK'
JC SNDRPT ; No 'ACK', repeat transmission
CALL SETPTR ; Successful record so increase pointers
LDA LBRARC
ORA A ; Member extraction?
JZ SNDLP ; No, exit
;
SNDRP1: CALL SETLBR ; Set library pointers and size left
LHLD RCNT ; See if anything was actually sent
MOV A,H
ORA L ; See if L and H both zero now
JNZ SNDLP ; Not done, yet
;
; File sent, send EOT but do local log-keeping first
;
SNDEOF: IF LOGLDS
LDA DNLDS ; Get Downloads Counter
INR A ; One more download since log in
STA DNLDS ; And update counter
ENDIF
;
IF LOGCAL
CALL LOGCALL ; Write log entries first
ENDIF
;
EOF1: CALL EOFSND
;
IF TIMEON AND (NOT CLOCK)
CALL ADDTON ; Update NUBYE's time-on-system byte
ENDIF
;
CALL ALLDON
JMP DONE
;
; Sends batch mode
;
SBTCH: LDA FSTFLG ; If first time through
ORA A
JNZ SBTCH1 ; If not first time, exit
CALL ILPRT
DB CR,LF
DB 'Locating selection(s)...',0
CALL LOGDU ; Check disk, user
CALL TNMBUF ; Put all requested files into NAMBUF
;
; Total number of files, total records and total length is shown, user
; then gets up to 5 seconds to abort.
;
CALL ILPRT
DB CR
DB 'Number of files found > ',0
LDA FILCNT ; Get total files
STA SHOCNT
PUSH PSW
MOV L,A
MVI H,0
CALL DECOUT ; Show remote # of files
POP PSW
ORA A ; Abort if no files to send
JZ NOFILE
CALL ILPRT
DB CR,LF
DB 'Xmodem 128-byte packets > ',0
LHLD TOTREC ; Get total records - all files
PUSH H
CALL DECOUT ; Show remote
CALL ILPRT
DB CR,LF
DB 'Ymodem 1k packets > ',0
POP H
CALL DIVREC ; Divide number of records by 8
CALL DECOUT ; Show # of k
CALL ILPRT
DB CR,LF
DB 'Disk space you need > ',0
LHLD BLOKK ; Get k required on remote disk for 2k
XCHG ; Block size
LHLD BLOKK
DAD D ; Double the size for 2k blocks
CALL DECOUT ; Print it
CALL ILPRT
DB 'k (2k blocks)',0
;
SBTCH1: LDA FILCNT
ORA A
JZ SBTCH2
LDA FSTFLG
ORA A ; Past first batch file?
JZ SHOREM ; No, else show local
;
IF CLRSCR
CALL PRINTL
DB CLRCH1,CLRCH2,CLRCH3,CLRCH4,CLRCH5,CLRCH6,'$'
ENDIF
;
CALL ILPRTL ; Local display from here on...
DB CR,LF
DB 'Remaining transfer time > ',0
JMP SKPREM
;
SHOREM: CALL ILPRT
DB CR,LF,LF
DB 'Total transfer time > ',0
;
SKPREM: LXI H,KTABLE
LDA MSPEED ; Get speed indicator
MVI D,0
MOV E,A ; Set up for table access
DAD D ; Index to proper factor
DAD D
MOV E,M
INX H
MOV D,M
LHLD TOTREC ; Get number of records
CALL FILTIM1
CALL OPNOK4
CALL ILPRT
DB CR,LF,0
LDA FSTFLG
ORA A ; Past first batch file?
JZ NOXTRA ; No, else give extra CR, LF
CALL ILPRT
DB CR,LF,0
CALL CATCH ; Get stray garbage
;
NOXTRA: LDA FSTFLG
ORA A
JNZ SBTCH2
INR A ; Now show we have been this way
STA FSTFLG
CALL ILPRT
DB CR,LF,'Your selection(s) ready to Download'
DB CR,LF,' Abort: CTRL-X <pause> CTRL-X'
DB CR,LF,LF,0
CALL ILPRTL ; Local display from here on...
DB '[ waiting ]',0
;
SBTCH2: CALL CKABORT
CALL FUNCHK ; Check the function keys
CALL SNDABT ; Check for local abort
CALL SNDFN ; Sends file name to user
JC SBTCH4 ; No more files, exit
CALL SHOWFIL ; Show the batch filename
JMP SNDFL1 ; Send the file
;
SBTCH4: LDA GOTONE ; Did we actually send at least one?
ORA A
JZ ABORT ; If not, don't act like we did
CALL EOFSND ; No more files so send EOT to finish
CALL XFRDON
CALL WAIT1
JMP EXIT
;
NOFILE: CALL ERXIT
DB CR,LF,'++ No matching filename(s) ++','$'
;
EOFSND: MVI A,EOT ; Send an 'EOT'
CALL SEND
LDA CHKEOT ; Did not get an ACK, try again
INR A
STA CHKEOT ; Limit number of retries to 10
CPI 10 ; (to prevent possible 'lock-up')
RNC ; Quit if already sent 10 or more
CALL GTACK ; Get the ACK
JC EOFSND ; Resend if carry is set
RET
;
ALLDON: LDA BCHFLG ; In batch mode?
ORA A
RNZ ; If yes, ignore message
;
XFRDON: CALL ILPRT
DB CR,LF,LF
DB '[ Transfer Completed ]',CR,LF,0
RET
;
SNDABT: LDA SYSABT
ORA A ; Local abort?
JNZ ABORT ; Yes, else return
RET
;
; ================================
; ---> RCVFL -- UPLOAD
; (from USER to RCP/M System)
; ================================
;
; The file specified in the NUKMD command line is transferred over the
; phone from the user's computer to the RCP/M system via modem using
; the "R" (receive) option. The data is sent one record at a time,
; with headers and checksums and retransmissions on errors.
;
RCVFL: IF MBBS AND MSGFIL
LDA MSGFLG
ORA A ; Message file upload?
JZ RCVOK1 ; No, so skip the rest
ENDIF
;
IF MBBS AND RESUSR AND MSGFIL
LDA AFBYTE
ANI 8 ; Test for write access (bit 3)
JZ DENIED
ENDIF
;
IF MBBS AND ZCPR AND MSGFIL
LDA WHEEL
ORA A ; WHEEL set?
JZ RCVOK4 ; No, so skip next
XRA A
STA WHEEL ; Turn off WHEEL
CALL ILPRT
DB 'The WHEEL has been turned OFF for "RM" function....'
DB CR,LF,0
ENDIF
;
IF MBBS AND RESUSR AND MSGFIL
JMP RCVOK4
ENDIF
;
RCVOK1: IF RESUSR AND PUPOPT
LDA PUPFLG
ORA A ; Privileged xfr option request?
JZ RCVOK2 ; No
ENDIF
;
IF (MBBS OR PBBS) AND RESUSR AND PUPOPT
LDA AFBYTE
ANI 80H ; Test for privileged user access (bit 7)
ENDIF
;
IF (NOT MBBS) AND (NOT PBBS) AND ZCPR AND RESUSR AND PUPOPT
LDA WHEEL
ORA A ; WHEEL set?
ENDIF
;
IF RESUSR AND PUPOPT
JZ DENIED
ENDIF
;
RCVOK2: IF (MBBS OR PBBS) AND RESUSR
LDA AFBYTE
ANI 40H ; Test bit 6 for upload access
JZ DENIED
ENDIF
;
RCVOK3: LDA BCHFLG ; Requesting batch mode?
ORA A
JNZ RCVBCH ; If yes, exit
;
RCVOK4: CALL RCVFL1 ; Find drive/user/filetype permitted
CALL RCVFL6 ; Display drive/user area
CALL CONTIN ; Display drive/user area
CALL MAKEFIL ; Open the file, ready to receive
;
RCVLP: CALL RCVRECD ; Get a record
JC RCVEOT ; Exit if 'EOT' for end of current file
CALL INCRNO ; Bump record number, if received ok
CALL WRRECD ; Write the record
CALL SNDACK ; Ack the record
JMP RCVLP ; Loop until 'EOF'
; -----
;
; Using batch so reset flags
;
RCVBCH: XRA A
STA FRSTIM ; Needs to be reset for each new file
MVI A,1
STA SNDFLG ; Shows we are in receive batch mode
LDA FSTFLG
ORA A ; First file received, yet?
JNZ RCVBC1 ; Yes, so skip next section
INR A
STA FSTFLG ; Show past first file
CALL ILPRT
DB CR,LF
DB 'Batch uploads limit > ',0
LXI H,0
MVI A,BLIMIT
MOV L,A
CALL DECOUT ; Show BLIMIT
CALL ILPRT
DB ' files',0
CALL RCVFL1 ; Find drive/user/filetype permitted
CALL CONTIN ; Display drive/user area
LXI H,NAMBUF
SHLD NBSAVE
;
RCVBC1: CALL RCVFN ; Get the batch file name and display
JC RCVBC2 ; If all done, exit
CALL RCVFL6 ; Change file extent if needed
CALL CHEKFIL ; Already have a file with that name?
CALL MAKEFIL
CALL BCHINR
CALL ILPRTL ; Display local from here on...
DB CR,LF,LF,'[ waiting ]',0
MVI A,CRC
CALL SEND
MVI A,KSND ; Request 1k blocks
CALL SEND
JMP RCVLP ; Start receiving the file
;
RCVBC2: XRA A ; Zero the batch mode flag
STA BCHFLG
LDA GOTONE ; Were there any files received?
ORA A
JZ ABORT
CALL XFRDON ; Show transmission is finished
CALL WAIT1 ; Delay to let remote get into ter. mode
JMP CRED3 ; Ask for descriptions
;
; -----
;
; Check on what drive/user area the file(s) will go into
;
RCVFL1: CALL LOGDU ; Select drive/user for upload
;
IF RESUSR AND PUPOPT
LDA PUPFLG ; Place "RW" file as needed
ORA A ; Can only be set if user is privileged
JNZ RCVFLA ; Privileged, else check if Sysop...
ENDIF
;
IF ZCPR
LDA WHEEL ; Let Sysop put file wherever he wants
ORA A
JZ RCVFL5 ; If WHEEL byte not set, stay normal
ENDIF
;
RCVFLA: IF ZCPR
LDA RCVDRV
ORA A
JZ RCVFL2
SUI 'A' ; Convert ASCII drive to binary
JMP RCVFL3
;
RCVFL2: LDA OLDDRV
;
RCVFL3: INR A
STA FCB
ADI 'A'-1 ; Convert binary to ASCII
STA XDRV ; Drive
LDA RCVDRV
ORA A ; Drive requested?
LDA OLDUSR ; Current user
JZ RCVFL4 ; No, use current user
LDA RCVUSR ; Else get requested user
;
RCVFL4: STA XUSR ; User
INR A ; Make sure it is a positive number
STA RWHEEL
RET
ENDIF ; ZCPR
;
RCVFL5: IF SETAREA
LDA XDRV
SUI 40H
STA FCB
ENDIF
;
LDA PRVTFL ; Receiving to a private area?
ORA A
RZ ; If not, exit
LDA XPRDRV ; Private area takes precedence
SUI 40H ; Convert to binary
STA FCB ; Store drive to be used
RET
;
; Changes the name of certain type of files such a .COM to .OBJ, ect.
;
RCVFL6: LDA RWHEEL ; Wheel byte set for SYSOP?
ORA A
RNZ ; Yes, don't change any file extents
;
IF CHGNAM
LXI H,FCB+9 ; Point to filetype
MVI A,'C' ; 1st letter
CMP M ; Is it 'C' ?
JNZ RCVFL7 ; If not, continue normally
INX H ; Get 2nd letter
MVI A,'O' ; 2nd letter
CMP M ; Is it 'O' ?
JNZ RCVFL7 ; If not, continue normally
INX H ; Get 3rd letter
MVI A,'M' ; 3rd letter
CMP M ; Is it 'M' ?
JNZ RCVFL7 ; If not, continue normally
CALL ILPRT
DB 'Renaming file to ".OBJ"',CR,LF,0
LXI H,FCB+9
MVI M,'O'
INX H
MVI M,'B'
INX H
MVI M,'J'
RET
;
RCVFL7: LXI H,FCB+9 ; Point to filetype
MVI A,'P' ; 1st letter
CMP M ; Is it 'P' ?
JNZ RCVFL8 ; If not, continue normally
INX H ; Get 2nd letter
MVI A,'R' ; 2nd letter
CMP M ; Is it 'R' ?
JNZ RCVFL8
INX H ; Get 3rd letter
MVI A,'L' ; 3rd letter
CMP M ; Is it 'L' ?
JNZ RCVFL8
CALL ILPRT
DB 'Renaming file to ".OBP"',CR,LF,0
LXI H,FCB+9
MVI M,'O'
INX H
MVI M,'B'
INX H
MVI M,'P'
RET
ENDIF ; NOCMR
;
RCVFL8: IF ZCPR
LXI H,FCB+9 ; Point to filetype
MVI A,'N' ; 1st letter
CMP M ; Is it 'N' ?
JNZ RCVFL9 ; If not, continue normally
INX H ; Get 2nd letter
MVI A,'D' ; 2nd letter
CMP M ; Is it 'D' ?
JNZ RCVFL9 ; If not, continue normally
INX H ; Get 3rd letter
MVI A,'R' ; 3rd letter
CMP M ; Is it 'R' ?
JZ RCVFL11 ; If yes, print error message and abort
;
RCVFL9: LXI H,FCB+9 ; Point to filetype
MVI A,'R' ; 1st letter
CMP M ; Is it R ?
JNZ RCVFL10 ; If not, continue normally
INX H ; Get 2nd letter
MVI A,'C' ; 2nd letter
CMP M ; Is it C ?
JNZ RCVFL10 ; If not, continue normally
INX H ; Get 3rd letter
MVI A,'P' ; 3rd letter
CMP M ; Is it P ?
JZ RCVFL11 ; Else play error message
;
RCVFL10:LXI H,FCB+9 ; Point to filetype
MVI A,'S' ; 1st letter
CMP M ; Is it S ?
RNZ ; If not, continue normally
INX H ; Get 2nd letter
MVI A,'Y' ; 2nd letter
CMP M ; Is it Y ?
RNZ ; If not, continue normally
INX H ; Get 3rd letter
MVI A,'S' ; 3rd letter
CMP M ; Is it S ?
JZ RCVFL11 ; Else play error message
RET ; If not, continue normally
;
RCVFL11:CALL ERXIT ; Print renaming message
DB CR,LF,'++ Select a different filename extension ++','$'
ENDIF ; ZCPR
;
RET ; Just in case ZCPR not used, etc.
;
; Displays where the file(s) will go, opens the file and shows the name
;
CONTIN: CALL ILPRT ; Print the message
DB CR,LF
DB 'Uploads received on > ',0
LDA PRVTFL ; Going to store in the private area?
ORA A
JZ CONT1 ; If not, exit
LDA XPRDRV ; Get private drive
SUI 40H ; Convert ASCII to binary
STA FCB
LDA XPRDRV
JNZ CONT2 ; If yes, it takes priority
;
CONT1: IF RESUSR AND PUPOPT
LDA PUPFLG ; Get privileged upload status
ORA A ; Privileged xfr option request?
LDA XDRV
JNZ CONT2 ; Yes, exit, takes next priority
ENDIF
;
IF ZCPR
LDA WHEEL ; Get WHEEL status
ORA A ; Set?
LDA XDRV
JNZ CONT2 ; Yes, exit, takes next priority
ENDIF
;
IF SETAREA
LDA XDRV ; Setarea uses a specified drive
ENDIF
;
IF NOT SETAREA
LDA OLDDRV ; Otherwise get current drive
ADI 'A' ; Convert to ASCII
;
NOTDRV: DB 0,0 ; Filled in by 'GETDU' if requested
ENDIF
;
CONT2: STA KDRV ; Save drive for KSHOW
CALL CTYPE ; Print the drive to store on
LDA PRVTFL ; Going to store in the private area?
ORA A
JZ NOPRVL ; If nope, skip ahead
;
IF LOGCAL
MVI A,'P' ; If private upload
STA LOGOPT ; Show "P" as option
ENDIF
;
LDA XPRUSR ; Get private user area
JMP CONT3 ; It takes priority
;
NOPRVL: IF SETAREA
LDA XUSR ; Setarea takes next precedence
ENDIF
;
IF NOT SETAREA
LDA OLDUSR ; Get current drive for default
;
NOTUSR: DB 0,0 ; Filled in by 'GETDU' if requested
ENDIF
;
CONT3: MVI H,0
MOV L,A
CALL DECOUT ; Print the user area
CALL ILPRT
DB ':',0
CALL ILPRT
DB CR,LF
DB 'Disk space available > ',0
CALL KSHOW ; Show available space remaining
CALL ILPRT
DB CR,LF,0
CALL CHEKFIL ; See if file exists
CALL ILPRT
DB CR,LF
DB 'Ready to receive your Upload',CR,LF
DB 'Abort: CTRL-X <pause> CTRL-X',CR,LF,0
LDA PRVTFL ; To the private area?
ORA A
RNZ ; Yes, don't mention descriptions
;
IF (MSGDSC OR DESCRIB) AND RESUSR AND PUPOPT
LDA PUPFLG
ORA A ; Privileged xfr option request?
JZ CONT5 ; No
;
CONT4: CALL ILPRT
DB CR,LF,'No description - PRIVILEGED upload mode',CR,LF,0
JMP CONT6
ENDIF
;
IF MSGDSC OR DESCRIB
CONT5: CALL ILPRT
DB CR,LF,'Description(s) required after upload',CR,LF,0
ENDIF
;
CONT6: CALL ILPRTL ; Display local from here on...
DB CR,LF,LF,'[ waiting ]',0
RET
;
; Got EOT on record so flush buffers then done
;
RCVEOT: LHLD RECDNO ; Check for zero length file
MOV A,H ; If no records, no file
ORA L
JZ RCVSABT ; Abort and erase the zero length file
CALL SNDACK ; Ack the record
CALL WRBLOCK ; Write the last block
CALL CLOSFIL ; Close the file
;
; Write record to log file if LOGCAL is YES
;
RCVEO1: IF LOGCAL
LHLD RECDNO ; If yes, get # of records
SHLD RCNT ; And stuff in RCNT
CALL XTIM ; Calculate appoximate transfer time
CALL STORTIM ; Store the time
ENDIF
;
IF MSGDSC OR MSGFIL OR LOGCAL
CALL LOGCALL
ENDIF
;
IF LOGLDS
LDA UPLDS ; Get Upload Counter
INR A ; One more upload since log in
STA UPLDS ; Update Counter
ENDIF
;
CALL ALLDON ; If not batch, print xfer complete
;
; --------------------------------------
;
; Credit routine
;
IF CREDIT
LDA BCHFLG ; In batch mode now?
ORA A
JNZ CRED1 ; Yes, so skip the rest
ENDIF
;
IF MBBS AND CREDIT AND MSGFIL
LDA MSGFLG
ORA A ; Message file uploaded?
JNZ CRED4 ; Yes, so skip thanks, credit and description
ENDIF
;
IF CREDIT AND RESUSR AND PUPOPT
LDA PUPFLG ; Get privileged xfr option flag
ORA A ; Requested?
JNZ CRED4 ; Else, skip thx, credit and description
ENDIF
;
IF CREDIT AND ZCPR
LDA WHEEL
ORA A ; Sysop?
JNZ CRED3 ; Yes, skip the thanks and credit, only
ENDIF
;
IF CREDIT
CALL ILPRTB ; Switch remote display on
DB CR,LF,'Thank you for the upload!',CR,LF,0
LDA TLIMIT
ORA A ; Special user?
JZ CRED3 ; Yes, else say...
;
CRED0: CALL ILPRT
DB CR,LF,'The time you took to upload has been added'
DB CR,LF,'to your remaining system time for today.'
DB CR,LF,0
;
CRED1: LDA TLIMIT ; Get user status/MXTIME
ORA A
JZ CRED2 ; Special user -- don't credit
LDA TLIMIT ; Get MXTIME once more
PUSH PSW ; Set aside for now
LHLD RECDNO
SHLD RCNT
CALL XTIM ; Determine upload time
POP PSW ; Get MXTIME back
INR A ; Round up 1 minute
ADD C ; Credit the upload time
STA TLIMIT ; Save new MXTIME
;
CRED2: MVI A,1 ; Set to local display only
STA CONONL
ENDIF
;
; If not still in batch mode, ask for file description
;
LDA BCHFLG ; In batch receive?
ORA A
JNZ CRED4 ; If yes, skip asking for a description
;
; end of credit routine
; ---------------------
;
CRED3: IF MSGDSC OR DESCRIB
LHLD 1
DCX H
MOV D,M
DCX H
MOV E,M
LXI H,12
DAD D
XRA A
MOV M,A
CALL ASK ; If yes, ask for description of file
ENDIF
;
CRED4: IF TIMEON AND (NOT CLOCK)
CALL ADDTON ; Update NUBYE's time-on-system byte
ENDIF
;
JMP DONE
;
; ===================
; BATCH MODE ROUTINES
; ===================
;
; If in batch receive, gets a file name from the buffer then asks for a
; description.
;
BCHDCR: LDA FILCNT
DCR A
STA FILCNT
;
BCHD1: LHLD NBSAVE ; Get address of next batch filename
LXI D,FCB ; Where to put it
MVI B,12
CALL MOVE
SHLD NBSAVE ; Store address for next filename
RET
;
; If receiving batch, increment the file count, store the filename so we
; can later ask for a description.
;
BCHINR: LHLD NBSAVE ; Where to put the name
LXI D,FCB ; Where to get the name
XCHG
MVI B,12 ; Move the current file name into buffer
CALL MOVE
XCHG
SHLD NBSAVE ; Store address for next filename
LDA FILCNT ; Increment the file count
INR A
STA FILCNT
RET
;
BCHINR1:LDA FILCNT
CPI BLIMIT ; Reached batch xfr limit?
RC
CALL ILPRTL
DB CR,LF
DB '++ Batch uploads limit has been reached ++',CR,LF,0
XRA A
STA BCHFLG ; Reset the batch mode flag to zero
POP H ; Reset stack from "CALL BCHINR"
JMP CRED4 ; Update TOS byte and exit
;
; Loads a command line addressed by 'DE' registers (max # characters in
; line in 'DE', number of characters in line in DE+1, line starts in
; DE+2) into FCB addressed by 'HL' registers. The FCB should be at
; least 33 bytes in length. The command line buffer must have a maxi-
; mum length at least one more than the greatest number of characters
; that will be needed.
;
CMDLINE:PUSH PSW
PUSH B
PUSH D
PUSH H
CALL INITIAL ; Fills FCBs with blanks and nulls
XCHG ; Get start of command line in HL
INX H ; Address # bytes in command line
MOV E,M ; Load DE pair with # bytes
MVI D,0
INX H
DAD D ; Point to byte after last character
MVI M,CR ; In command line and store delimiter
POP H ; Restore HL and DE
POP D
PUSH D
PUSH H
INX D ; Address start of command
INX D
CALL DRIVEX
MVI C,8 ; Transfer first filename to FCB
CALL TRANS
CPI CR
JZ DONEL
CPI ' ' ; If space, then start of 2nd filename
JZ NAME1
POP H ; Filetype starts after 8th byte
PUSH H
LXI B,9
DAD B
MVI C,3 ; Transfer type of first file
CALL TRANS
CPI CR
JZ DONEL
;
NAME1: LDAX D ; Eat multiple spaces between names
CPI ' '
JNZ NAME2
INX D
JMP NAME1
;
NAME2: POP H ; Second name starts in 16th byte
PUSH H ; Point HL to this byte
LXI B,16
DAD B
CALL DRIVEX
MVI C,8
CALL TRANS
CPI CR
JZ DONEL
POP H ; Second file type starts in 25th byte
PUSH H
LXI B,25
DAD B
MVI C,3
CALL TRANS
;
DONEL: POP H
PUSH H
INX H ; Point to 1st char of 1st name in FCB
CALL SCANL ; Check for * (ambiguous names)
POP H
PUSH H
LXI B,17 ; To 1st character of second name in FCB
DAD B
CALL SCANL
POP H
POP D
POP B
POP PSW
RET
;
; Subroutines for CMDLINE section
;
INITIAL:PUSH H ; Initializes FCB with 1 null for first
PUSH B ; drive with 11 blanks, 4 nulls, 1
MVI M,0 ; null for second drive with 11 blanks
INX H ; and 4 nulls
MVI B,11
MVI A,' '
CALL INITFILL
MVI B,5
XRA A
CALL INITFILL
MVI B,11
MVI A,' '
CALL INITFILL
MVI B,4
XRA A
CALL INITFILL
POP B
POP H
RET
;
INITFILL:
MOV M,A
INX H
DCR B
JNZ INITFILL
RET
;
; Show batch files remaining after this one is sent
;
CUMSTS: CALL ILPRTL
DB CR,LF
DB 'Files remaining > ',0
LDA SHOCNT ; Get cumulative files
DCR A
STA SHOCNT ; Less one
MOV L,A
MVI H,0
CALL DECOUT
CALL ILPRT
DB CR,LF
DB 'Xmodem packets remaining > ',0
LHLD RCNT ; Get this file's record count again
XCHG ; Put in DE
LHLD TOTREC ; Total records remaining
MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
JNC $+6
LXI H,0 ; In case of a slightly negative number
SHLD TOTREC
PUSH H
CALL DECOUT ; Show remaining records
CALL ILPRT
DB CR,LF
DB 'Ymodem packets remaining > ',0
POP H
CALL DIVREC ; Divide number of records by 8
CALL DECOUT
CALL ILPRT
DB CR,LF,0
RET
;
; -----
;
DRIVEX: INX D ; Check 2nd byte of filename. if it..
LDAX D ; Is a ":", then drive was specified..
DCX D
CPI ':'
JNZ DEFDR ; Else zero for default drive
LDAX D ; ('INIT' put zero)
ANI 5FH
SUI 40H ; Calculate drive (A=1, B=2,...)
MOV M,A ; Place it in FCB
INX D ; Address first byte in command line
INX D
;
DEFDR: INX H ; And name field in FCB
RET
;
; -----
;
; Clears the FCB area
;
INITFCB:MVI M,0 ; Clears the drive
;
INITFCB1:
INX H
MVI B,11 ; Clears the filename and extent area
;
LOOP11: MVI M,' '
INX H
DCR B
JNZ LOOP11
MVI B,21 ; Clears the rest with zeros
;
LOOP21: MVI M,0
INX H
DCR B
JNZ LOOP21
RET
;
; Finished with the file transfer
;
DONE: LDA BCHFLG ; In batch mode now?
ORA A
JZ EXIT ; If not, all done so go finish up
LDA OLDDRV ; Restore the original drive
CALL RECDRX
LDA OLDUSR ; Restore the original number
CALL RECARE
CALL RSTDMA ; Reset to default DMA
MVI B,12 ; Zero out DONE6
LXI H,DONE6
;
; Null the batch file name buffer
;
DONE1: MVI M,0 ; Zero the memory location
INX H
DCR B
JNZ DONE1 ; Zero all 12 locations
;
; Now fill in the batch file name
;
MVI B,12 ; Put file name in DONE6
LXI H,FCB+1
LXI D,DONE6
;
DONE2: MVI A,4 ; Start of file type?
CMP B
JZ DONE4 ; Put in period if so
MOV A,M
CPI ' ' ; Don't put in space
JZ DONE3
STAX D ; Store in DONE6
INX D
;
DONE3: INX H
DCR B
MOV A,B
ORA A ; End of file name?
JZ DONE5 ; Display file name
JMP DONE2 ; Loop for another character
;
DONE4: MOV A,M
CPI ' ' ; Is file type empty?
JZ DONE5 ; Go if so
MVI A,'.' ; Else put period in message
STAX D
INX D
DCR B
JMP DONE2
;
DONE5: MVI A,1 ; Display filename locally only
STA GOTONE ; Indicates there was a file handled
CALL ILPRTL ; Display the file name locally only
DB CR,LF
;
DONE6: DB 0,0,0,0,0,0,0
DB 0,0,0,0,0,0
CALL ILPRTL
DB ' transferred',CR,LF,LF,0
;
; Now reset some flags for another possible batch file
;
XRA A
STA EOFLG ; Clear end of file flag
STA EOTFLG ; And end of transmission flag
STA CHKEOT ; And the "resend EOT" flag
LXI H,0
SHLD ACCERR ; Reset the accumulate error count
SHLD RECNBF ; Zero number of records in the buffer
SHLD RECDNO ; Zero the current record number
SHLD RCDCNT ; Zero the transmit record counter
LXI H,DBUF ; Reset buffer pointers
SHLD RECPTR
LDA SNDFLG ; Goes to either send or
ORA A ; Receive file, depending
JZ SNDFL ; Upon which routine set
CALL BCHINR1 ; Store filename, increment count, chk limit
JMP RCVFL ; The flag in multi-file mode
;
; -----
;
; Multi-file access subroutine. Allows processing of multiple files
; (i.e., *.ASM) from disk. Builds the correct name in the FCB each time
; it is called. The command is used in programs to process single or
; multiple files. The FCB is set up with the next name, ready to do
; normal processing (open, read, etc.) when routine is called. Carry is
; set if no more names are found.
;
MFNAM: PUSH B
PUSH D
PUSH H
CALL RSTDMA ; Reset to default DMA
POP H
POP D
POP B
XRA A
STA FCBEXT
LDA MFFLG1
ORA A
JNZ MFNAM1
MVI A,1
STA MFFLG1
LXI H,FCB
LXI D,MFNAM5
LXI B,12
CALL MOVER
LDA FCB
STA MFNAM6 ; Save disk in current FCB
LXI H,MFNAM5
LXI D,FCB
LXI B,12
CALL MOVER
PUSH B
PUSH D
PUSH H
CALL FILSCH
POP H
POP D
POP B
JMP MFNAM2
;
MFNAM1: LXI H,MFNAM6
LXI B,12
LXI D,FCB
CALL MOVER
PUSH B
PUSH D
PUSH H
CALL FILSCH
POP H
POP D
POP B
LXI H,MFNAM5
LXI B,12
LXI D,FCB
CALL MOVER
PUSH B
PUSH D
PUSH H
MVI C,SRCHN
CALL FCBSET
POP H
POP D
POP B
;
MFNAM2: INR A
STC
JNZ MFNAM3
STA MFFLG1
RET
;
MFNAM3: DCR A
ANI 3
ADD A
ADD A
ADD A
ADD A
ADD A
ADI 81H
MOV L,A
MVI H,0
PUSH H ; Save name pointer
LXI D,MFNAM6+1
LXI B,11
CALL MOVER
POP H
LXI D,FCB+1
LXI B,11
CALL MOVER
XRA A
STA FCBEXT
STA FCBRNO
RET
;
MOVER:
MFNAM4: MOV A,M ; Used if an 8080 CPU is active
STAX D
INX H
INX D
DCX B
MOV A,B
ORA C
JNZ MFNAM4
RET
;
; end of multi-file access routine
; --------------------------------
;
; NUKMD receive batch mode
;
RCVFN: LXI H,FCB
CALL INITFCB1 ; Does not initialize drive
XRA A
STA RCVTRY
INR A ; Set to local display only
STA CONONL
;
RNUK1: CALL CKABORT ; Check for user abort
MVI B,3 ; Wait up to 3 sec. for SOH from remote
CALL RECV
JC RNUK2 ; No character, decrement counter
CPI CANCEL ; ^X?
JZ ABORTX ; Abort if yes
CPI SOH
JZ RNUK4 ; Got SOH
JMP RNUK1 ; None of these, wait some more
;
RNUK2: MVI A,CRC ; Send a 'C'
CALL SEND
;
RNUK3: LDA RCVTRY
INR A
STA RCVTRY
CPI 33
JC RNUK1
JMP ABORT ; Quit and try to force him to quit also
;
RNUK4: MVI B,5 ; 5 seconds to get sector number
CALL RECV
JC NUKTOT
MOV D,A ; Save sector number in D
ORA A ; Must be a 0 if sending batch
JNZ NUKHDR
MVI B,5 ; 5 seconds to get reciprocal
CALL RECV
JC NUKTOT
CMA ; Invert it and compare to sector #
CMP D
JNZ NUKCRC ; Bad match
LXI H,0
SHLD CRCVAL ; Clear CRC counter
MVI E,128 ; Expecting a 128 character block
LHLD RECPTR ; Point to the buffer address
;
RNUK5: MVI B,5 ; 5 seconds to get 128 byte header block
CALL RECV ; Get the character
JC NUKTOT ; Exit if no character
MOV M,A ; Store the character
INX H ; Point to next buffer location
DCR E ; One less to go
JNZ RNUK5 ;
MVI E,2 ; Number of CRC bytes to get
;
RNUK6: MVI B,5
CALL RECV ; Get CRC bytes
JC NUKTOT
DCR E ; Done?
JNZ RNUK6 ; No
CALL CRCCHK ; Compare CRC received against ours
ORA A ; Ok?
JNZ NUKCRC ; No
CALL SNDACK ; Yes, acknowledge to remote
;
; Decode pathname into CPM format
;
LXI D,FCB+1 ; Where to put it
LHLD RECPTR ; Where to get it
MVI B,8 ; Filename length
;
RNUK7: MOV A,M ; Get the character from the buffer
ORA A ; 0?
JZ RNUK12 ; If yes, all done
CPI '.' ; Delimiter?
JZ RNUK9 ; Yes
;
RNUK8: CALL UCASE ; Insure name is in upper case
CPI '_' ; Underline?
JNZ RNUK8A ; No, else...
MVI A,'-' ; Change to dash for CP/M
;
RNUK8A: STAX D ; Store filename character in FCB
INX D ; Increment pointers
INX H
DCR B ; One less to go
JNZ RNUK7 ; If not 8, keep going
MOV A,M ; Get the character back
ORA A ; 0?
JZ RNUK11 ; Yes, all done
JMP RNUK10 ; Else must be a '.'
;
RNUK9: MVI A,' ' ; Spaces to make up 8 spaces for name
STAX D ; Store space character in FCB
INX D ; Increment pointers
DCR B ; One less to go
JNZ RNUK9 ; Keep going until in extent area
;
RNUK10: INX H ; Skip the '.' position
MVI B,3 ; Extent length
;
RNUK11: MOV A,M ; Get the character from the buffer
ORA A ; 0?
JZ RNUK12 ; Yes, all done
CALL UCASE ; Insure extent is in upper case
STAX D ; Store extent character
INX D ; Increment pointers
INX H
DCR B ; One less to go
JNZ RNUK11 ; Keep going until finished
;
RNUK12: LDA FCB+1
CPI ' ' ; Any filename?
STC ; Set carry flag
RZ ; No, all done, no more files
CALL ILPRTL
DB CR,'Name of this file > ',0
LHLD RECPTR ; Print filename
;
RNUK13: MOV A,M
ORA A
JZ RNUK14
CALL UCASE
CALL CTYPE
INX H
JMP RNUK13
;
RNUK14: LHLD BUFSTR ; Get the file length, if provided
MOV A,H
ORA L
JZ RNUK15 ; If both zero, length not provided
SHLD RCNT ; Store the file length
CALL OPNOK3
CALL ILPRT
DB CR,LF
DB 'Ymodem transfer time > ',0
CALL KTIM
CALL OPNOK4
;
RNUK15: CALL ILPRT
DB CR,LF,0 ; Finish the filename line
XRA A ; Reset the carry flag
STA RCVTRY ; Reset the error counter
RET
;
NUKCRC: CALL ILPRTL
DB '++ CRC error ++',CR,LF,0
JMP NUKXFR
;
NUKHDR: CALL ILPRTL
DB '++ Wrong header type ++',CR,LF,0
JMP NUKXFR
;
NUKTOT: CALL ILPRTL
DB ' ++ Timeout receiving filename ++',CR,LF,0
;
NUKXFR: CALL WAIT1 ; Make sure sender has stopped
CALL WAIT1
MVI A,NAK
CALL SEND ; Tell sender not successful
LDA RCVTRY ; Get error counter
INR A ; Increment it
STA RCVTRY ; Store it
CPI 33
JC RNUK3 ; Send a NAK and tell him to try again
JMP ABORT ; Else abort
;
; end of get batch file name
; --------------------------
;
; NUKMD send batch mode
;
SNDFN:
SNDNUK: LXI H,FCB
CALL INITFCB1 ; Does not initialize drive
XRA A
STA ERRCT ; Reset the error count
CALL CATCH ; Clear the decks for action
MVI E,60 ; Wait up to 60 seconds to abort
;
CCHECK: CALL CKABORT ; Manually requesting an abort?
MVI B,1 ; Wait up to 1 second for a character
CALL RECV
JC CCHECK1 ; No character, decrement counter
CPI CANCEL ; If they sent a ^X, abort now
JZ ABORT
CPI CRC ; If they sent a CRC, go to work
JZ SNUK0
JMP CCHECK ; None of these, wait some more
;
CCHECK1:DCR E ; One less to go
JNZ CCHECK
JMP ACKMSG ; Abort if timed out and no character
;
SNUK0: MVI A,1
STA CRCFLG ; Make sure in CRC mode
LDA FILCNT ; Get the file count
DCR A ; Decrement it for this one
STA FILCNT
JM NUKEND ; If no more files, abort
CALL BCHD1 ; Get the name into FCB
LHLD RECPTR ; Where to load the 0 block
XCHG ; Put into DE
LXI H,FCB+1 ; Get the start of the filname in HL
MVI B,8
;
SNUK1: MOV A,M
ANI 7FH ; Strip any high bit set
ORA A
JZ SNUK6 ; Null pathname
CPI ' '
JZ SNUK3
;
SNUK2: CALL LCASE ; Put file name in lower case for UNIX
STAX D
INX H
INX D
DCR B
JNZ SNUK1
JMP SNUK4
;
SNUK3: INX H ; Skip over spaces if short name
DCR B
JNZ SNUK3
;
SNUK4: MOV A,M
CPI ' '
JZ SNUK6 ; Missing file type field
MVI A,'.' ; Send name-type seperator
STAX D
INX D
MVI B,3
;
SNUK5: MOV A,M
ANI 7FH ; Strip any high bit set
CPI ' '
JZ SNUK6
CALL LCASE ; Put in lower case for UNIX
STAX D
INX H
INX D
DCR B
JNZ SNUK5
;
SNUK6: XCHG ; Get the address back to HL
;
SNUK7: MVI M,0 ; Fill rest of block with zeroes
INR L
JNZ SNUK7
CALL CNREC ; Get number of records in this file
LHLD RCNT
SHLD BUFSTR ; Store the file length at end of block
XRA A ; Make sure the header starts with Zero
STA RCDCNT
;
; Now send the 128-byte file name record
;
SNUK8: XRA A
STA KFLG
MVI A,SOH ; Send SOH
CALL SEND
CALL SNDHNM ; Send header (record number, inverse)
CALL SNDREC ; Send a 128 byte record
CALL SNDCRC ; Send a two byte CRC
MVI B,5
CALL RECV ; Get acknowledgement of good send
CPI ACK
JNZ NUKBAD ; Bad name send
LDA MSPEED ; Check speed being used
CPI 5
JC SNUK9 ; Don't allow 1k blocks if 300 bps
LDA NOISY
ORA A ; Has noise caused a step-down?
JNZ SNUK9 ; Yes, else
MVI A,1
STA KFLG ; Change to 1k for Ymodem
;
SNUK9: XRA A ; Clear the carry flag
STA ERRCT ; Start fresh for the main file
RET
;
NUKBAD: CPI CANCEL ; Cancel (^X)?
JZ ABORT ; Yes, abort
CALL ILPRTL ; Bad name block
DB '++ CRC error ++',CR,LF,0
LDA ERRCT ; Increment the error counter
INR A
STA ERRCT
CPI 10 ; Timed out?
JC SNUK8 ; No, try again
JMP ACKMSG ; Else abort
;
NUKEND: XRA A ; Reset the pointers
LHLD RECPTR
MOV M,A
STA RCDCNT ; Reset the record counter
STA KFLG ; Show in 128 size now
MVI A,SOH ; Send a start of header
CALL SEND
CALL SNDHNM ; This header is a zero count
CALL SNDREC ; Send an empty record
CALL SNDCRC ; Send the CRC for the empty record
STC ; Set the carry flag to show all done
RET
;
; end of send batch name
; ----------------------
;
; Scans CMDBUF counting names and putting delimiter (space) after last
; name
;
SCAN: LXI D,CMDBUF ; Save original TBUF contents in CMDBUF
LXI H,TBUF
MVI B,128
CALL MOVE
LXI H,CMDBUF
MOV C,M
MVI B,0
INX H
DAD B ; Now pointing at space after last char
MVI M,' ' ; Put in the space
LXI H,CMDBUF ; Get the count again
MOV B,M
INX H ; Skip the first space
INR B
;
SCAN1: INX H ; On first entry HL points to 1st char
DCR B ; 1st go-thru B is count to last space
JZ SCAN5
MOV A,M ; Look for the first space
CPI ' '
JNZ SCAN1
;
SCAN2: INX H ; Eat extra spaces
DCR B
JZ SCAN5
MOV A,M
CPI ' '
JZ SCAN2
SHLD BGNMS ; Save start of names in TBUFF
INR B
DCX H
;
SCAN3: INX H
DCR B
JZ SCAN5
MOV A,M
CPI ' '
JNZ SCAN3
LDA NAMECT ; Counts names
INR A
STA NAMECT
;
SCAN4: INX H ; Eat spaces
DCR B
JZ SCAN5
MOV A,M
CPI ' '
JZ SCAN4
JMP SCAN3
;
SCAN5: LDA NAMECT ; Were there any names?
ORA A
RNZ ; Yes
POP H ; Remove calls from stack
POP H
JMP OPTERR ; Bail out to avoid BDOS error
;
SCANL: MVI B,8 ; Scan file name addressed by HL
;
TSTNAM: MOV A,M
CPI '*' ; If '*' found, fill in rest of field
JZ FILL1 ; With '?' for ambiguous name.
INX H
DCR B
JNZ TSTNAM
JMP FILL2
;
FILL1: CALL FILL4
;
FILL2: MVI B,3 ; Scan and fill name 'type' field
;
FILL3: MOV A,M ; Specified above
CPI '*'
JZ FILL4
INX H
DCR B
JNZ FILL3
RET
;
FILL4: MVI M,'?' ; Routine transfers '?'
INX H
DCR B
JNZ FILL4
RET
;
; -----
;
; Show the file name (locally) as stored in the FCB but in CP/M format
;
SHOWFIL:CALL ILPRTL
DB CR,'Name of this file > ',0
LXI H,FCB+1
XRA A
STA FTYCNT
MVI C,11
;
PRNAM: CALL FTYTST
INX H
DCR C
JNZ PRNAM
RET
;
FTYTST: LDA FTYCNT
INR A
STA FTYCNT
CPI 9 ; Are we at the file type?
JZ SPCTST ; Go if so
;
ENDSPT: MOV A,M
CPI ' ' ; Test for space
CNZ CTYPE ; Type if not
RET
;
SPCTST: MOV A,M
CPI ' ' ; Test for space in 1st file type byte
RZ ; Do not output period if space
MVI A,'.'
CALL CTYPE
JMP ENDSPT ; Output 1st file type byte
;
; -----
;
; Loads the batch file names into the storage buffer
;
TNMBUF: XRA A
STA FILCNT ; Reset the file count
CALL SCAN
LXI H,NAMBUF ; Start of buffer into NBSAVE
SHLD NBSAVE ; Save address of 1st name
;
TNLP1: CALL TRTOBUF ; Move a filename into FCBBUF
LXI H,FCB
LXI D,FCBBUF
CALL CMDLINE ; Parse name to CP/M format
;
TNLP2: CALL MFNAM ; Search for names (wildcard format)
JC NEXTNM
MVI C,FILSIZ
CALL FCBSET
LHLD RANDOM ; Get number of records in this file
MOV A,H
ORA L
JZ TNLP2 ; If no records, don't copy this file
SHLD DIRSIZ ; Save temporarily
;
IF ZCPR
LDA WHEEL
ORA A ; WHEEL byte set for SYSOP use?
JNZ TNLP3 ; If yes, let him transfer any file
ENDIF
;
LDA FCB+1 ; Tagged library file to not send?
ANI 80H
JNZ TNLP2 ; If set, do not send
LDA FCB+2 ; Special tag?
ANI 80H
JNZ TNLP2 ; If set, do not send
LDA FCB+10 ; It is a .SYS file?
ANI 80H
JNZ TNLP2 ; If set, do not send
;
IF SNDWILD OR SNDCOM
LXI H,FCB+11 ; Last character in the file extent
MOV A,M
ANI 7FH ; Strip off the high bit
ENDIF
;
IF SNDWILD
CPI '#' ; Wildcard designator (? or *)?
JZ TNLP2 ; Yes, so don't send
ENDIF
;
IF SNDCOM
CPI 'M' ; M?
JNZ TNLP3 ; If not, file is ok to send
DCX H
MOV A,M
ANI 7FH ; strip any high bit
CPI 'O' ; O?
JNZ TNLP3 ; If not, file is ok to send
DCX H
MOV A,M
ANI 7FH ; Strip off any high bit set
CPI 'C' ; C?
JZ TNLP2 ; If yes, ignore file
ENDIF
;
TNLP3: LHLD NBSAVE ; Get the filename
LXI D,FCB ; Move it to FCB
XCHG
MVI B,12
CALL MOVE
XCHG
SHLD NBSAVE ; Address of next name
LDA FILCNT ; Count files found
INR A
STA FILCNT
;
; Add up the total records for all files to be sent
;
LHLD DIRSIZ ; Get number of records in this file
PUSH H ; Save for later
XCHG ; Put record count into 'DE'
LHLD TOTREC ; Get record count up to this file
DAD D ; Add this file to previous total
SHLD TOTREC ; New total record count
POP H ; Get the length of this file
LXI D,15 ; Bring up to closest 2k size
DAD D
INX D ; Divide result by 16
CALL DVHLDE ; Divide HL by DE
MOV H,B
MOV L,C
;
NOREM: XCHG
LHLD BLOKK ; Current number of 2k blocks needed
DAD D
SHLD BLOKK
JMP TNLP2
;
NEXTNM: LXI H,NAMECT ; Count names found
DCR M
JNZ TNLP1
LXI H,NAMBUF ; Save start of buffer
SHLD NBSAVE
RET
;
; -----
;
TRANS: LDAX D ; Transfer from command line to FCB
INX D ; up to number of chars specified
CPI CR ; by 'C' reg. Keep scanning field
RZ ; without transfer until a delimiting
CPI '.' ; field char such as '.', blank, or
RZ ; CR (for end of commmand line).
CPI ' '
RZ
DCR C
JM TRANS ; Once C-reg is less than zero, keep
MOV M,A ; reading command line but do not
INX H ; transfer to FCB.
JMP TRANS
;
; -----
;
; Places next name in buffer so 'CMDLINE' may parse it
;
TRTOBUF:LHLD BGNMS
MVI B,0
LXI D,FCBBUF+2
;
TBLP: MOV A,M
CPI ' '
JZ TRBFEND
STAX D
INX H
INX D
INR B ; Count chars in name
JMP TBLP
;
TRBFEND:INX H
MOV A,M ; Eat extra spaces
CPI ' '
JZ TRBFEND
SHLD BGNMS
LXI H,FCBBUF+1 ; Put # chars before name
MOV M,B
RET
;
; -----
;
LCASE: CPI 41H ; If less than capital 'A' ignore
RC
CPI 5AH+1 ; If more than capital Z' ignore
RNC
ORI 20H ; Change to lower case
RET
;
UCASE: CPI 61H ; Changes lower case character..
RC ; In 'A'reg. to upper case.
CPI 7AH+1 ; See if more than small 'Z'
RNC
ANI 5FH
RET
;
; ===========
; SUBROUTINES
; ===========
;
; Sets drive/user area (if SETAREA is YES) according to user input and your
; setting of MAXDUS and DRVx/USRx EQUates.
;
; MENU #1
;
WHAT: IF (DESCRIB OR SETAREA) AND USEMENU AND (NOT ALTMENU)
XRA A
STA CHOICE ; Clear for loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU
STA KIND
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
LXI D,MENU4 ; Load alternate menu
CALL PRTSET ; Show it
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND (NOT ALTMENU)
LXI D,MENU1 ; Load category/area uploads table
CALL PRTSET ; Show it
CALL WELL ; Wait for response
ENDIF
;
WHAT0: IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
XRA A
STA CHOICE ; Clear for loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU
CALL INPUT ; Get a character
CALL UCASE ; Upper case if alpha
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND (NOT ALTMENU)
CPI 'B' ; Menu #2?
JZ WHAT2 ; Yes, else continue
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND (NOT ALTMENU)
CPI 'C' ; Menu #3?
JZ WHAT4 ; Yes, else continue
ENDIF
;
WHAT0A: IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
CPI '1' ; Quit?
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND (NOT ALTMENU)
CPI 'Q' ; Quit?
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU
JNZ WHAT0B ; No
CALL TYPE
JMP EXIT
ENDIF
;
WHAT0B: IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
CPI 'A' ; <?
JC WHAT0 ; Yes
CPI 5BH ; >'Z'?
JNC WHAT0 ; Yes
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
CPI 'K' ; >'J'?
JNC WHAT2 ; Yes
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
SUI 11H ; 0-9 only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU
CPI '0' ; <0?
JC WHAT0 ; Yes, so loop
STA KIND
JNZ WHAT1 ; Not 0, so skip
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
ADI 11H ; Alpha only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU
CALL TYPE ; Show response
LDA XDRV1
STA XDRV
LDA XUSR1
STA XUSR
RET
;
WHAT1: CPI MAXDU1+1 ; >MAXDU1?
JNC WHAT0 ; Yes, so loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
PUSH PSW ; Save A
ADI 11H ; Alpha only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU
CALL TYPE
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND ALTMENU
POP PSW
ENDIF
;
IF DESCRIB AND (NOT SETAREA) AND USEMENU
RET
ENDIF
;
IF SETAREA AND USEMENU
CALL WHAT8 ; Get d/u offset
LXI H,DUTBL1 ; Point to the d/u table
JMP WHAT7 ; Set drive/user
ENDIF
;
; MENU #2
;
WHAT2: IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
PUSH PSW ; Save A
MVI A,'B'
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1
STA CHOICE
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
POP PSW ; Restore A
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND (NOT ALTMENU)
CALL TYPE
LXI D,MENU2 ; Load category/area uploads table
CALL PRTSET ; Show it
CALL WELL ; Wait for response
;
WHAT2A: CALL INPUT ; Get a character
CALL UCASE ; Upper case if alpha
CPI 'A' ; Menu #1?
JNZ WHAT2B ; No
CALL TYPE
JMP WHAT ; Menu #1
ENDIF
;
WHAT2B: IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND (NOT ALTMENU)
CPI 'C' ; Menu #3?
JZ WHAT4 ; Yes, else continue
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND (NOT ALTMENU)
CPI 'Q' ; Quit?
JNZ WHAT2C ; No
CALL TYPE
JMP EXIT
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND ALTMENU
CPI 'U' ; >'T'?
JNC WHAT4 ; Yes
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
SUI 1BH ; 0-9 only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1
WHAT2C: CPI '0' ; <0?
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND (NOT ALTMENU)
JC WHAT2A ; Yes, so loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1
STA KIND
JNZ WHAT3 ; Not '0', so continue
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
ADI 1BH ; Alpha only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1
CALL TYPE
LDA XDRV2
STA XDRV
LDA XUSR2
STA XUSR
RET
;
WHAT3: CPI MAXDU2+1 ; >MAXDU2?
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
JNC WHAT0 ; Yes, so loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND (NOT ALTMENU)
JNC WHAT2A ; Yes, so loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
PUSH PSW ; Save A
ADI 1BH ; Alpha only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1
CALL TYPE
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
POP PSW ; Restore A
ENDIF
;
IF DESCRIB AND (NOT SETAREA) AND USEMENU AND XTRA1
RET
ENDIF
;
IF SETAREA AND USEMENU AND XTRA1
CALL WHAT8 ; Get d/u offset
LXI H,DUTBL2 ; Point to the d/u table
JMP WHAT7 ; Set drive/user
ENDIF
;
; MENU #3
;
WHAT4: IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
PUSH PSW ; Save A
MVI A,'C'
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2
STA CHOICE
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA1 AND ALTMENU
POP PSW ; Restore A
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND (NOT ALTMENU)
CALL TYPE
LXI D,MENU3 ; Load category/area uploads table
CALL PRTSET ; Show it
CALL WELL ; Wait for response
;
WHAT4A: CALL INPUT ; Get a character
CALL UCASE ; Upper case if alpha
CPI 'A' ; Menu #1?
JNZ WHAT4B ; No
CALL TYPE
JMP WHAT ; Menu #1
;
WHAT4B: CPI 'B' ; Menu #2?
JNZ WHAT4C ; No
CALL TYPE
JMP WHAT2 ; Menu #2
;
WHAT4C: CPI 'Q' ; Quit?
JNZ WHAT4D ; No
CALL TYPE
JMP EXIT
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND ALTMENU
SUI 25H ; 0-5 only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2
WHAT4D: CPI '0' ; <0?
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND (NOT ALTMENU)
JC WHAT4A ; Yes, so loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2
STA KIND
JNZ WHAT6 ; Not '0', so continue
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND ALTMENU
ADI 25H ; Alpha only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2
CALL TYPE
LDA XDRV3
STA XDRV
LDA XUSR3
STA XUSR
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2
RET
;
WHAT6: CPI MAXDU3+1 ; >MAXDU2?
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND ALTMENU
JNC WHAT0 ; Yes, so loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND (NOT ALTMENU)
JNC WHAT4A ; Yes, loop
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND ALTMENU
PUSH PSW ; Save A
ADI 25H ; Alpha only
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2
CALL TYPE
ENDIF
;
IF (DESCRIB OR SETAREA) AND USEMENU AND XTRA2 AND ALTMENU
POP PSW
ENDIF
;
IF DESCRIB AND (NOT SETAREA) AND USEMENU AND XTRA2
RET
ENDIF
;
IF SETAREA AND USEMENU AND XTRA2
CALL WHAT8 ; Get d/u offset
LXI H,DUTBL3 ; Point to the d/u table
ENDIF
;
IF SETAREA AND USEMENU
WHAT7: DAD D
MOV A,M
STA XDRV ; Set drive
INX H
MOV A,M
STA XUSR ; Set user
CALL ILPRT
DB CR,LF,0
RET
;
; Set d/u area
;
WHAT8: SUI '1' ; Get offset for d/u table
RAL
MVI D,0
MOV E,A
RET
ENDIF
;
; Display DE and ask for input
;
IF (DESCRIB OR SETAREA) AND USEMENU AND (NOT ALTMENU)
WELL: CALL ILPRT
DB CR,LF
DB 'Your choice : ',0
RET
ENDIF
;
;
; Add the time of the last up/download to NUBYE's time-on-system byte
;
IF TIMEON AND (NOT CLOCK)
ADDTON: MVI C,79
CALL BDOS ; Get value of TON and RTC address
LXI D,7 ; Offset from RTC to TON
DAD D ; HL now contains TON address
PUSH H ; Save for now
LHLD RECDNO
SHLD RCNT
CALL XTIM ; Calculate transfer time
POP H ; Get TON address
MOV A,M ; And current value
INR A ; Bump it one
ADD C ; Add transfer time
MOV M,A ; And put it in NUBYE
RET
ENDIF
;
; Catches anything on the modem input and ignores, so can wait for what
; we expect to receive
;
CATCH: CALL MDINST ; Check modem status for any characters
RZ ; If none, all checked
CALL MDINP ; Else get the garbage character
JMP CATCH ; Keep going until none remaining
;
; Check next character to see if a space or non-space, file name error
; if no ASCII character.
;
CHKFSP: LDA BCHFLG ; Requesting batch mode now?
ORA A
JZ CHKFSP2 ; Exit if not
LDA SNDFLG ; Sending batch?
ORA A
JZ CHKFSP2 ; If yes, exit
DCR B
JZ CHKFSP1
INR B
JMP CHKFSP2
;
CHKFSP1:POP H ; Do not return to LOGDU
RET ; Return instead to SNDFL
;
CHKFSP2:DCR B
JZ NFN ; Error if end of chars.
MOV A,M
CPI ' '+1
RNC ; Ok if valid character so return
INX H
LDA BCHFLG ; Requesting batch mode?
ORA A
JZ CHKFSP2 ; If not, loop
LDA SNDFLG ; Sending batch mode now?
ORA A
JZ CHKFSP2 ; If yes, loop
DCR B ; Else look at next character
JZ CHKFSP1
INR B
JMP CHKFSP2
;
; Check next character to see if a space or non-space, go to menu if a
; command error.
;
CHKSP: LDA BCHFLG ; Requesting batch mode?
ORA A
JZ CHKSP2 ; Exit if not
LDA SNDFLG ; Sending in batch mode now?
ORA A
JZ CHKSP2 ; If yes, exit
DCR B
JZ CHKSP1
INR B
JMP CHKSP2
;
CHKSP1: POP H ; Don't return to LOGDU
RET ; Return to SNDFIL
;
CHKSP2: DCR B
JZ OPTERR
INX H
MOV A,M ; Get the character there
CPI ' ' ; Space character?
RET ; JZ = space, JNZ = non-space
;
; -----
;
****
; Assorted BDOS functions
;
CLOSEF: MVI C,CLOSE ; Close file
JMP BDSRET
;
DELDES: LXI D,DEST ; Destination file
DELFIL: MVI C,DELET ; Delete
JMP BDSRET
;
DRVSET: MVI C,SELDSK ; Select drive
JMP BDSRET
;
FILSCH: MVI C,SRCHF
LXI D,FCB
JMP BDSRET
;
OPENIT: MVI C,OPEN
JMP BDSRET
;
PRTSET: MVI C,PRINT
JMP BDSRET
;
REDFCB: MVI C,READ
FCBSET: LXI D,FCB
JMP BDSRET
;
RRANDM: MVI C,RRDM
JMP BDSRET
;
RSTDMA: LXI D,TBUF ; Default buffer
DMASET: MVI C,STDMA ; Set to DMA
JMP BDSRET
;
USRSET: MVI C,SETUSR
JMP BDSRET
;
BDSRET: CALL BDOS
RET
;
; I/O drivers using NUBYE's extended BDOS calls
;
CONIN: PUSH B
PUSH D
PUSH H ; Save the registers
MVI C,67 ; Console input call
CALL BDOS ; Character returned in 'A'
CPI CANCEL ; Local abort requested?
JNZ CONIN1 ; No, else
STA SYSABT ; Store it
;
CONIN1: JMP BDOSX1 ; Restore registers
;
CONOUT: PUSH B
PUSH D
PUSH H
MVI C,68 ; Console output call (char is in 'E')
JMP BDOSEX
;
CONSTAT:PUSH B
PUSH D
PUSH H
MVI C,66 ; Console status call
JMP BDOSEX
;
MDCARCK:PUSH B
PUSH D
PUSH H
MVI C,65 ; Carrier check
JMP BDOSEX
;
MDINP: PUSH B
PUSH D
PUSH H
MVI C,64 ; Modem input
JMP BDOSEX
;
MDINST: PUSH B
PUSH D
PUSH H
MVI C,61 ; Modem input status
JMP BDOSEX
;
MDOUTP: PUSH B
PUSH D
PUSH H
MVI C,63 ; Modem output
MOV E,A ; Put character in 'E'
JMP BDOSEX
;
MDOUTST:PUSH B
PUSH D
PUSH H
MVI C,62 ; Modem output status
;
BDOSEX: CALL BDOS
;
BDOSX1: POP H
POP D
POP B
RET ; Restore registers and return
;
LSTCLR: PUSH B ; Save the registers
PUSH D
MVI C,80 ; LCDATA BDOS call in NUBYE
CALL BDOS
POP D ; Restore the registers
POP B
RET
;
; -----
;
; Finished, clean up and return to CP/M (via MBBS/MFMSG if necessary).
;
EXIT: IF WRTLOC ; Did we set the WRTLOC?
MVI C,75
MVI E,0
CALL BDOS ; Reset wrtloc flag
ENDIF
;
IF TIMEON AND CLOCK AND DTOS
CALL MDCARCK ; Still have a carrier?
JZ EXIT1 ; If not can't use "RECV:"
CALL WAIT1 ; Insures other end is finished
MVI C,83
CALL BDOS ; Tell NUBYE to print time-on-system
ENDIF
;
EXIT1: LDA OLDDRV ; Restore the original drive
CALL RECDRX
LDA OLDUSR ; Restore the original number
CALL RECARE
CALL RSTDMA ; Reset to default DMA
;
EXIT2: IF TIMEON
LDA TLIMIT ; Restore MXTIME/status
MVI C,81
MOV E,A
CALL BDOS
ENDIF
;
EXIT3: XRA A ; Clear the register and carry bit
LHLD STACK ; Get original return adress back
SPHL ; Put on the stack pointer
;
IF MSGDSC OR MSGFIL
LDA DSCFLG
ORA A ; Normal file with description?
JNZ EXIT4 ; Yes, so skip next check
LDA MSGFLG
ORA A ; Message file upload?
RZ ; No
;
EXIT4: CALL ILPRTB ; Show to remote also
DB CR,LF,LF
DB '++ Loading special message/description file handler ++'
DB CR,LF,LF,0
STA CONONL ; Set to local display only
ENDIF
;
IF MSGFIL
LDA MSGFLG
ORA A ; Message file upload?
JNZ EXIT6 ; Yes, skip rest
ENDIF
;
IF MSGDSC
LDA INBTCH ; Batch?
ORA A
JNZ EXIT6 ; Yes, so skip next section
ENDIF
;
IF MSGDSC AND RESUSR AND PUPOPT
LDA PUPFLG
ORA A ; Privileged xfr option request?
JZ EXIT5 ; No
LDA AFBYTE
ANI 80H ; Test for privileged user access (bit 7)
RNZ ; Return, privileged user ok'd
ENDIF
;
EXIT5: IF MSGDSC
LDA PRVTFL ; Upload status (Public or Private)
STA TBUF ; Stuff into page zero (80H)
MVI C,0 ; Number of characters (stuff at TBUF)
LXI D,TBUF+2 ; Buffer starts at 82H
LXI H,MBDSH ; "NEW UPLOAD:" heading
;
MBDSHP: MOV A,M ; Get character
ORA A ; End?
JZ MBDFS ; Yes, else...
CALL MBDPUT ; Stuff it into DE
INX H ; Increment to next position
JMP MBDSHP ; Loop until done
;
MBDFS: CALL MBDFIL ; Get du: info
STA TBUF+1 ; Save number of characters in 81H
MVI A,0CAH ; Stuff JZ instruction
STA 0
XRA A
JMP 0
ENDIF
;
IF MSGDSC OR MSGFIL
EXIT6: MVI C,0 ; Number of characters (stuff at TBUF)
LXI D,TBUF+1 ; Start of buffer
CALL MBDFIL
STA TBUF ; Save number of characters in TBUF
MVI A,0C2H ; Stuff JNZ instruction
STA 0 ; ..in 0, so NUBYE loads/runs MFMSG utility
ORA A ; Make sure NZ flag set so JNZ will jump
JMP 0
ENDIF
;
IF (NOT MSGFIL) AND (NOT MSGDSC)
RET
ENDIF
;
IF MSGDSC OR MSGFIL
MBDFIL: LDA DSKSAV ; Get current drive
INR A
;
MWDRV: ADI 'A'-1
CALL MBDPUT ; Stuff in command line buffer
LDA USRSAV ; Get current user
CPI 10 ; <10?
JC US0 ; Yes
ORA A ; Clear flags
DAA ; Decimal adjust
RAR ; Shift down tens digit
RAR
RAR
RAR
ANI 0FH ; Mask out tens digit
ADI '0' ; Make it ASCII
CALL MBDPUT
LDA USRSAV
ORA A ; Clear flags
DAA ; Decimal adjust
ANI 0FH ; Mask out singles digit
;
US0: ADI '0' ; Make it ASCII
CALL MBDPUT
MVI A,':' ; Put in a colon
CALL MBDPUT
LDA DSCFLG
ORA A ; Normal file with description?
JZ US1 ; No, so skip next lines
LDA INBTCH ; Batch?
ORA A
JZ US1 ; Normal upload, use its filename, else...
LXI H,FILE+1 ; Stuff in UPLOADS filename
JMP $+6 ; ...and skip next line
US1: LXI H,FCB+1 ; Stuff in filename
MVI B,8
;
DESNM: MOV A,M
CPI ' '
CNZ MBDPUT
INX H
DCR B
JNZ DESNM
MVI A,'.'
CALL MBDPUT
MVI B,3
;
DESNM3: MOV A,M
CPI ' '
JZ DESGO
CPI 0
JZ DESGO
CALL MBDPUT
INX H
DCR B
JNZ DESNM3
;
DESGO: MOV A,C
RET
;
MBDPUT: STAX D ; Short routine to stuff A in (DE) and
INX D ; Increment pointer and character count
INR C
RET
ENDIF ; MSGFIL OR MSGDSC
;
; Check to see if SYSOP has typed a function key
;
FUNCHK: PUSH PSW
CALL CONSTAT ; See if SYSOP has typed a key
ORA A
CNZ CONIN ; Yes, treat as function key
POP PSW
RET
;
; Get Disk and User from DUSAVE and log in if valid.
;
GETDU: LDA BCHFLG ; Requesting batch mode?
ORA A
JZ GETDU1 ; If not, exit
LDA SNDFLG ; Sending batch?
ORA A
JNZ GETDU2 ; If not, exit
;
GETDU1: CALL CHKFSP ; See if a file name is included
SHLD SAVEHL ; Save location of the filename
;
GETDU2: LDA PRVTFL ; Uploading to a private area?
ORA A
JNZ TRAP1 ; If yes, going to a specified area
LXI H,DUSAVE ; Point to drive/user
LDA OLDDRV ; Get current drive
STA DUD
ADI 'A'
STA RCVDRV
MOV A,M ; Get 1st character
CPI '0'
JC GETDU3
CPI '9'+1
JC NUMER1
;
GETDU3: STA RCVDRV ; Allows Sysop/Privileged user any drive
CPI 'A'-1
JC NUMER ; Satisfied with current drive
SUI 'A'
STA DUD
;
IF RESUSR AND PUPOPT
LDA PUPFLG ; Privileged user upload request?
ORA A
LDA DUD ; Get value back
JNZ GETDU4 ; Yes
ENDIF
;
IF ZCPR
LDA WHEEL ; Sysop using the system?
ORA A
LDA DUD ; Get the value back
JNZ GETDU4
ENDIF
;
IF NOT USEMAX
CPI MAXDRV
JNC ILLDU ; Drive selection not available
ENDIF
;
IF USEMAX
PUSH H
LXI H,DRIVMAX ; Point to max drive byte
INR M
CMP M ; And check it
PUSH PSW ; Save flags from the CMP
DCR M ; Restore max drive to normal
POP PSW ; Restore flags from the CPM
JNC ILLDU
POP H
ENDIF
;
GETDU4: INX H ; Get 2nd character
;
NUMER: MOV A,M
CPI ':'
JZ OK4 ; Colon for drive only, no user number
CALL CKNUM ; Check if numeric
MOV B,A ; Save character
LDA BCHFLG ; Using batch mode?
ORA A
JZ NUMER1 ; Skip next part if not using batch
LDA SNDFLG ; Receiving in batch?
ORA A
JNZ NUMER1 ; Yes, can use normal drive/user
;
NODU: CALL ERXIT
DB '++ Batch downloads only from this d/u area ++','$'
;
NUMER1: MOV A,B ; Get the value back
SUI '0' ; Convert ASCII to binary
STA DUU ; Save it
INX H ; Get 3rd character if any
MOV A,M
CPI ':'
JZ OK1
LDA DUU
CPI 1 ; Is first number a '1'?
JNZ ILLDU
MOV A,M
CALL CKNUM
SUI '0'-10
STA DUU
INX H ; Get 4th (and last character) if any
MOV A,M
CPI ':'
JNZ ILLDU
;
OK1: LDA OPTSAV ; Get the option back
CPI 'R' ; Receiving a file?
LDA DUU ; Get desired user area
JZ OK2 ; Yes, can not use special download area
LDA DUD ; Get desired drive
CPI SPLDRV-'A' ; Special download drive requested?
LDA DUU ; Get user area requested
JNZ OK2 ; If none, exit
CPI SPLUSR ; Special download area requested?
JZ OK3 ; If yes, process request
;
OK2: IF ZCPR
LDA WHEEL ; SYSOP using the system?
ORA A
LDA DUU ; Restore desired user area
STA RCVUSR ; Allows SYSOP to upload anywhere
JNZ OK3 ; If yes, let him have all user areas
ENDIF
;
IF NOT USEMAX
CPI MAXUSR+1 ; Check for maximum user download area
JNC ILLDU ; Error if more (and not special area)
ENDIF
;
IF USEMAX
PUSH H
LXI H,USRMAX ; Point at maximum user byte
CMP M ; And check it
JNC ILLDU
POP H
ENDIF
;
OK3: MOV E,A
;
IF NOT SETAREA
STA NOTUSR+1 ; Store requested user area
MVI A,3EH ; 'MVI A,--' instruction
STA NOTUSR
ENDIF
;
CALL USRSET ; Set to requested user area
;
OK4: LDA DUD ; Get drive
MOV E,A
;
IF NOT SETAREA
ADI 'A'
STA NOTDRV+1 ; Store requested drive
MVI A,3EH ; 'MVI A,--' instruction
STA NOTDRV
ENDIF
;
OK5: CALL DRVSET ; Set to requested drive
PUSH B
CALL WAIT1 ; 1 sec delay
POP B
JMP TRAP1 ; Now find file selected
;
; Set drive/user for special download request
;
SETSPL: IF ALTSEC
LDA SPLFL1
ORA A ; Special download request (alternate)
JNZ SETSP1 ; Yes
ENDIF
;
MVI E,SPLUSR ; Get the special download user area
CALL USRSET ; Set to it
MVI C,SELDSK
MVI E,SPLDRV-'A' ; Get the special download drive
JMP BDOS ; Set to requested drive, return
;
IF ALTSEC
SETSP1: MVI E,ALTUSR ; Get the special alternate download user area
CALL USRSET ; Set to it
MVI C,SELDSK
MVI E,ALTDRV-'A' ; Get the special alternate download drive
JMP BDOS ; Set to requested drive, return
ENDIF
;
; Shows available space on upload disk/area. Uses KDRV data area which
; must be loaded before calling this routine. (So KSHOW will work with
; user specified disk if SETAREA equate is not set YES.)
;
; Print the free space remaining for the received file
;
CPMVER EQU 0CH
CURDPB EQU 1FH
GALLOC EQU 1BH
SELDSK EQU 0EH
GETFRE EQU 46
;
KDRV: DB 0 ; Drive stored here before calling KSHOW
;
KSHOW: LDA KDRV ; Get drive ('A','B','C',etc.)
SUI 41H ; Convert to numeric (0,1,2,etc.)
MOV E,A ; Stuff in E for BDOS call
CALL DRVSET ; Set to proper drive
MVI C,CURDPB ; It's 2.X or MP/M...request DPB
CALL BDOS
INX H
INX H
MOV A,M ; Get block shift
STA BLKSHF
INX H ; Bump to block mask
MOV A,M
INX H
INX H
MOV E,M ; Get max block #
INX H
MOV D,M
XCHG
SHLD BLKMAX ; Save it
XCHG
INX H
MOV E,M ; Get directory size
INX H
MOV D,M
XCHG
;
; Calculate # of K free on selected drive now so that the FREE figure
; will not reflect either the creation or additions to the SD.DIR file
; (which we would probably erase or move anyway).
;
MVI C,CPMVER ; Get CP/M version number
CALL BDOS
MOV A,L ; Get returned version number
CPI 30H ; 3.0?
JC FREE20 ; Use old method if not
LDA KDRV ; Get drive #
SBI 'A' ; Change from ASCII to binary
MVI C,GETFRE
MOV E,A ; Use new Compute Free Space BDOS call
CALL BDOS
MVI C,3 ; Answer is a 24-bit integer
;
FRE3L1: LXI H,80H+2 ; Answer is in 1st 3 bytes of DMA adr
MVI B,3 ; Convert it from sectors to K
ORA A ; By dividing by 8
;
FRE3L2: MOV A,M
RAR
MOV M,A
DCX H
DCR B
JNZ FRE3L2 ; Loop for 3 bytes
DCR C
JNZ FRE3L1 ; Shift 3 times
LHLD 80H ; Now get result in K
JMP SAVFRE ; Go store it
;
FREE20: MVI C,GALLOC ; Get address of allocation vector
CALL BDOS
XCHG
LHLD BLKMAX ; Get its length
INX H
LXI B,0 ; Init block count to 0
;
GSPBYT: PUSH D ; Save alloc address
LDAX D
MVI E,8 ; Set to process 8 blocks
;
GSPLUP: RAL ; Test bit
JC NOTFRE
INX B
;
NOTFRE: MOV D,A ; Save bits
DCX H ; Count down blocks
MOV A,L
ORA H
JZ ENDALC ; Quit if out of blocks
MOV A,D ; Restore bits
DCR E ; Count down 8 bits
JNZ GSPLUP ; Do another bit
POP D ; Bump to next byte..
INX D ; Of alloc. vector
JMP GSPBYT ; Process it
;
ENDALC: POP D ; Clear stack of allocation vector ptr.
MOV L,C ; Copy block to HL
MOV H,B
LDA BLKSHF ; Get block shift factor
SUI 3 ; Convert from sectors to K
JZ SAVFRE ; Skip shifts if 1K blocks...
; ; Return free in HL
FREKLP: DAD H ; Multiply blocks by K/BLK
DCR A
JNZ FREKLP
;
; Print the amount of free space remaining on the selected drive
;
SAVFRE: CALL DECOUT
CALL ILPRT
DB 'k free',0
RET
;
; Log into drive and user (if specified). If none mentioned, it falls
; through to 'TRAP' routine for normal use.
;
LOGDU: LXI H,TBUF ; Point to default buffer command line
MOV B,M ; Store number of characters in command
INR B ; Add in current location
;
LOG1: CALL CHKSP ; Skip spaces to find 1st command
JZ LOG1
;
LOG2: CALL CHKSP ; Skip 1st command (non-spaces)
JNZ LOG2
INX H
CALL CHKFSP ; Skip spaces to find 2nd command
SHLD SAVEHL ; Save start address of the 2nd command
;
; Now point to the first byte in the argument, i.e., if it was of format
; similar to: B6:HELLO.DOC then we point at the drive character 'B'.
;
LXI D,DUSAVE
MVI C,4 ; Drive/user is 4 characters maximum
;
CPLP: MOV A,M
CPI ' '+1 ; Space or return, finished
JC TRAP
STAX D
INX H
INX D
CPI ':'
JZ GETDU ; If colon, get drive/user and log in
DCR B ; One less position to check
DCR C ; One less to go
JNZ CPLP
;
; Check for no file name or ambiguous name
;
TRAP: LDA SPLFL ; Downloading from a private area?
ORA A
CNZ SETSPL ; If yes, set special drive/user area
;
TRAP1: CALL MOVEFCB ; Move the filename into the file block
LXI H,FCB+1 ; Point to file name
MOV A,M ; Get first character of file name
CPI ' ' ; Any there?
JZ NFN ; If not, display error messagename
MVI B,11 ; 11 characters to check
;
TRLOOP: MOV A,M ; Get char from FCB
CPI '?' ; Ambiguous?
JZ TRERR ; Yes, exit with error message
CPI '*' ; Even more ambiguous?
JZ TRERR ; Yes, exit with error message
INX H ; Point to next character
DCR B ; One less to go
JNZ TRLOOP ; Not done, check some more
RET
;
NFN: CALL ERXIT ; Print message, exit
DB '++ Specify a filename ++','$'
;
TRERR: LDA BCHFLG
ORA A
RNZ ; Wildcards are ok in batch mode
CALL ERXIT ; Print message, exit
DB '++ Wild-cards accepted in batch mode only ++','$'
;
CKNUM: CPI '0'
JC ILLDU ; Error if less than ascii '0'
CPI '9'+1
RC ; Error if more than ascii '9'
;
ILLDU: CALL ERXIT
DB '++ Improper drive/user combination ++','$'
;
; Receive a record - returns with carry bit set if EOT received
;
RCVRECD:XRA A ; Initialize error count to zero
STA ERRCT
;
RCVRPT: CALL FUNCHK ; Check function keys
LDA SYSABT
ORA A ; Local abort?
JNZ RCVSABT ; Yes, else...
MVI B,10 ; 10-seconds to get first character
LDA FRSTIM ; Have we started, yet?
ORA A
JNZ NOCHR ; No, so skip next line
MVI B,3+1 ; Check every 4 seconds until started
;
NOCHR: CALL RECV ; Get any character received
JC RCVSTOT ; Timeout error if no character received
CPI SOH ; See if it is SOH
JZ RCVSOH ; Got SOH, get record
CPI STX ; See if it is STX for 1k blocks
JZ RCVSTX ; Got STR, get record
CPI CANCEL ; ^X to abort?
JZ CKCAN ; Yes, check for aborting
ORA A ; Null?
JZ RCVRPT ; Yes, get another character
CPI 7BH ; V.22 synch character?
JZ RCVRPT ; Yes, ignore
CPI 0FBH ; V.22 synch character with high bit set?
JZ RCVRPT ; Yes, ignore
CPI EOT ; End of transmission?
JNZ RCVRP1 ; No, continue
LDA EOTFLG ; Get EOT flag status
ORA A ; Second EOT?
STC ; Set carry, in case second EOT received
RNZ ; Yes, so all done
MVI A,NAK
STA EOTFLG ; Show EOT received
CALL SEND ; Send NAK for double check of EOT
JMP RCVLP ; Continue with receive
;
RCVRP1: CPI CRC ; Ignore our own character coming back
JZ RCVRPT
CPI KSND ; Ignore our own character coming back
JZ RCVRPT
CPI NAK ; Ignore our own character coming back
JZ RCVRPT
CALL ILPRTL ; Show locally only
DB CR,LF,0
MOV A,B
CALL HEXO
CALL ILPRT
DB 'H received not SOH ',CR,LF,0
;
; Didn't get SOH or EOT or did not get valid header so purge the line,
; then send NAK.
;
RCVSR: CALL WAIT1 ; Get anything coming in and discard
CALL CKABORT ; Want to quit now?
LDA FRSTIM ; Get first time switch
ORA A ; Has first 'SOH' been received?
MVI A,NAK
JNZ RCVSR1 ; Yes, then send 'NAK'
LDA CRCFLG ; Get the 'CRC' flag
ORA A ; 'CRC' in effect?
MVI A,NAK ; Put 'NAK' in 'A' register
JZ RCVSR1 ; No, send the 'NAK' for checksum
MVI A,CRC ; Tell sender we have 'CRC'
CALL SEND
LDA KFLG ; Requesting 1k transmissions?
ORA A
JZ RCVSR1 ; If not, exit
MVI A,KSND ; Tell sender we also have 1k capability
;
RCVSR1: CALL SEND ; Checksum (NAK) or CRC (X/Ymodem) request
LDA ERRCT ; Get the error count
INR A ; Increment error count
STA ERRCT ; Store new value
MOV B,A ; Keep the error count for now
LDA FRSTIM ; Have we gotten under way yet?
ORA A
MOV A,B ; get the value back
JZ RCVSR2 ; If not, exit
CPI 10 ; 10 errors the limit, once under way
JNC RCVSABT ; Abort if over the limit
CALL RDCOUNT ; Display record count before repeating
JMP RCVRPT ; Less than 10, keep going
;
RCVSR2: CPI 10 ; 10 times for 1k/CRC yet? (40 seconds)
JC RCVRPT ; Keep trying if less
XRA A ; Else flip to checksum mode
STA CRCFLG
MOV A,B ; Get the count back
CPI 15 ; Another 5 times for checksum?
JC RCVRPT ; If less, try again, quit at 60 seconds
;
; Error limit exceeded, so abort
;
RCVSABT:XRA A
STA CONONL ; Clear the console-only flag
LXI SP,STACK ; Clear the stack just in case
CALL CLOSFIL ; Keep whatever we got
CALL ILPRT
DB CR,LF,LF
DB ' ++ Upload has been cancelled ++',0
CALL DELFILE ; Delete received file
CALL ERXIT ; Print second half of message
DB '++ Incomplete file has been deleted ++','$'
;
; Deletes the received file (used if receive aborts)
;
DELFILE:LXI D,FCB ; Point to file
CALL DELFIL ; Delete it
INR A ; Delete ok?
RNZ ; Yes, return
CALL ERXIT ; No, abort
DB CR,LF
DB '++ No file or can''t delete received file ++','$'
;
; Aborts with 1 ^X if first time flag is not set, two otherwise
;
CKCAN: LDA FRSTIM ; First time flag set yet?
ORA A
JZ RCVSABT ; If not, Abort and close file
MVI B,2 ; Maximum of 2 seconds for extra ^X
CALL RECV
JC RCVRPT ; No additional character, ignore ^X
CPI CANCEL ; If a 2nd ^X, abort and close file
JZ RCVSABT
JMP RCVRPT ; Else wait for a STX, SOH or timeout
;
; Timed out on receive
;
RCVSTOT:CALL EOTCHK ; See if EOT has been received
LDA FRSTIM ; First time flag set yet?
ORA A
JZ RCVSR ; If not, don't show an error
CALL ILPRTL ; Show locally only
DB '++ Timeout waiting for character ++',CR,LF,0
JMP RCVSR ; Bump error count, etc.
;
; Got a STX - set KFLG for 1k
;
RCVSTX: STA KFLG ; Set the 1k flag
STA CRCFLG ; Insure in CRC mode for 1k blocks
JMP RCVS1
;
; Got SOH - get block number, block number complemented
;
RCVSOH: XRA A
STA KFLG ; If SOH, clear the 1k flag
;
RCVS1: MVI B,5 ; Timeout = 5 seconds
MOV A,B ; Get something to store
STA FRSTIM ; Indicate first 'SOH' or 'STX' recvd.
CALL RECV ; Get block number
JC RCVSTOT ; Got timeout
MOV D,A ; Save block number
MVI B,5 ; Timeout = 5 seconds
CALL RECV ; Get complimented record number
JC RCVSTOT ; Timeout
CMA ; Get the complement
CMP D ; Same as original block number?
JZ RCVDATA ; Yes, get data
;
; Got bad record number in header
;
CALL ILPRTL ; Show locally only
DB '++ Error in header ++',CR,LF,0
JMP RCVSR ; Go check error limit and send NAK
;
RCVDATA:MOV A,D ; Get record number
STA RCVCNT ; Save it
MVI C,0 ; Initialize checksum
LXI H,0 ; Initialize CRC
SHLD CRCVAL ; Clear CRC counter
LXI D,128 ; For 128 character blocks
LDA KFLG ; Using 1k blocks?
ORA A
JZ $+6 ; If not, skip next line
LXI D,1024 ; If using 1k blocks
LHLD RECPTR ; Get buffer address
;
RCVCHR: MVI B,5 ; 5 sec timeout
CALL RECV ; Get the character
JC RCVSTOT ; Timeout
MOV M,A ; Store the character
INX H ; Point to next character
DCX D ; One less to go
MOV A,D ; See if 'D' and 'E' are both empty
ORA E
JNZ RCVCHR ; No, get next character
LDA CRCFLG ; Using 'CRC'?
ORA A
JNZ RCVCRC ; If yes go get 'CRC'
;
; Verify checksum
;
MOV D,C ; Save checksum
MVI B,5 ; Timeout length
CALL RECV ; Get checksum
JC RCVSTOT ; Timeout
CMP D ; Checksum ok?
JZ CHKSNUM ; Yes, exit
CALL ILPRTL ; Show locally only
DB '++ Checksum error ++',CR,LF,0
JMP RCVSR ; Go check the error limit and send NAK
;