-; CPSTT.ASM
-; KERMIT - (Celtic for "FREE")
-;
-; This is the CP/M-80 implementation of the Columbia University
-; KERMIT file transfer protocol.
-;
-; Version 4.0
-;
-; Copyright June 1981,1982,1983,1984,1985
-; Columbia University
-;
-; Originally written by Bill Catchings of the Columbia University Center for
-; Computing Activities, 612 W. 115th St., New York, NY 10025.
-;
-; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
-; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
-; others.
-;
-; This file contains the code for the TRANSMIT and CONNECT commands,
-; which communicate with a host which is not running KERMIT.
-;
-; revision history:
-;
-;edit 12, 31-Jan-1991 by MF. Delete call to "inbuf" after "xmit1" in
-; the TRANSMIT command. "getfil" initializes various counters so that
-; when "in1chr" is first called, "inbuf" will be called immediately
-; and will read sectors of the file to be transmitted from disk.
-; This, along with a fix to "in1chr" in CPSUTL.ASM, fixes a bug
-; discovered by Lance Tagliapietra of the University of Wisconsin at
-; Platteville wherein the TRANSMIT command was failing to transmit some
-; characters in files over one sector in length. See CPSUTL.ASM,
-; edit 29.
-; edit 11, 10 September, a987, by OBSchou. Modified TRANSMIT command
-; to TRANSMIT <file> <string>
-;
-; edit 10, 27 August, 1987 by OBSchou. Fixed bugs in Transmit, but I may
-; be introducing problems for IBM/CMS or half duplex systems. What
-; does this combination do??
-;
-; edit 9 30 March, 1987 by OBSchou to replace the TRANSMIT routine.
-; Syntax is now TRANSMIT file after a previous
-; INPUT <wait time> <string to wait for>
-;
-; edit 8 19 June, 1986 by OBSchou. Modified the interupt testing routine
-; to see if the command was a 'D' (Drop the line), in which case also
-; do a 'C', ie disconnect. This is really a little too much of a
-; system dependent thing.
-; For now, Ill leave it here, and possibly move it later.
-;
-; edit 7 30 May 1986 OBSchou. Moved xon/xoff control (ie XON/OFF sent to host)
-; out to CPSUTL so that ther printer routine can use it too.
-;
-; edit 6 30 April, 1986 by OBSchou.
-; Fixed transmit bug, so as soon as the protocol character is
-; received from the host is received then another line is sent.
-; added in a comchr (ds 1) to save the character read from the comm
-; line in prtchr, and is restored in a on return.
-;
-; edit 5 7 March, 1986 by OBSchou Loughborough University.
-; Need to save the E register before calling outmdm (in CPSSYS.ASM)
-; if doing Half duplex. Push/pop DE should sort this problem
-;
-; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809
-;
-;pcc002 28-Dec-84 modules:cp4tt,cp4utl
-; Add connect mode <esc>P command to toggle printer on
-; and off. Conflicts with "official" recommended commands
-; in protocol manual, but I don't think CP/M will ever get
-; a PUSH command.
-;
-;pcc003-pcc005 2-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl
-; These edits must all be installed together and change the way
-; logging is handled. The log file spec is moved to a separate
-; fcb, and not opened until an actual CONNECT command is given.
-; This takes care of a NASTY bug that if you used any other file
-; command between the LOG and CONNECT, the log file would get
-; written over the last file used. This also allows logging to
-; be "permanently" enabled until an CLOSE (new command) for all
-; CONNECT sessions, like most other kermits do. If a log file
-; already exists, it will be appended to. Also add two new
-; CONNECT mode commands <esc>Q to suspend logging and <esc>R to
-; resume. <esc>R means something else during TRANSMIT, but
-; logging is never on then, so there shouldn't be any conflict.
-; I also changed the write code, so that it can handle one more
-; character after the XOFF is send to stop the host. This allows
-; a little "slop" for systems that don't stop immediately (such
-; as TOPS10), but it didn't help much.
-;
-;pcc008 2-Jan-85 vjc modules:cp4def,cp4tt,cp4utl
-; Keyboard input during CONNECT mode can get locked out if
-; there is enough input from the modem port to keep prtchr
-; busy. This can happen for example, if the printer is running
-; at the same speed as the modem line, leaving you helpless to
-; turn it off or abort the host. Add a fairness count, so that
-; at least every prfair characters we look at console input.
-;
-;pcc012 4-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl
-; Use the big buffer for the log file. Move the log file back
-; into the common fcb and only save the drive, name, and
-; extension between connects. Add new routines to cp4utl to
-; create or append to an existing file, and to conditionally
-; advance buffers only if in memory. Remove edit pcc003 that
-; allows one more character after the xoff, since it didn't
-; really work very well and does not fit in well with the way
-; the buffer advancing routines are set up. If someone still
-; thinks this would be useful, it could be put back in with a
-; little more work.
-;
-; While testing this edit, I also noticed another bug that
-; the command parsing routines do not limit or check the
-; length of command lines or file specs, trashing what ever
-; comes after them. Currently because of where the fcb and
-; command buffer are located, this does not usually cause a
-; problem, but could if an extremely long line was typed in,
-; or in the future multiple fcbs defined elsewhere in memory
-; were used. Maybe this should be put on the bug list
-; somewhere.
-;
-; edit 3: July 27, 1984
-; Allow assembly with LASM: to CP4TT is linked by CP4PKT, and links
-; to CP4CPM; remove exclamation points so as not to confuse LASM.
-; Add Toad Hall TACtrap to TRANSMIT command (TAC intercept character
-; is only doubled if it's data; when typed by the user, they're not
-; automatically doubled)
-;
-; edit 2: June 7, 1984
-; formatting and documentation; add module version number; make sure
-; console is selected when leaving intchr.
-;
-; edit 1: May, 1984
-; extracted from CPMBASE.M80 version 3.9; modifications are described
-; in the accompanying .UPD file.
-
-ttver: db 'CPSTT.ASM (12) 31-Jan-1991$'
-
-; This is the TRANSMIT command. It attempts to send a file, even
-; though there is no KERMIT on the other side.
-; here from: kermit
-;
-; [OBS] I have replaced the routine, so that TRANSMIT <filename> <wait string>
-; will send a line at a time to the host in a manner similar to MSKERMIT
-;
-;
-xmit: mvi a,cmofi ;Parse an input file spec (non-wild).
- lxi d,fcb ;Give the address for the FCB.
- call comnd
- jmp kermit ;Give up on bad parse.
-;
- lxi d,stbuff ; where to put the string
- mvi a,cmtxt ; get text
- call comnd
- jmp kermit ; not quite correct...
- sta strcnt ; string count returned in a
- ana a ; if its zero, make it 1 character (CR)
- jnz xmit0
- mvi a,1
- sta strcnt
- mvi a,cr
- sta stbuff
-;
-xmit0: call cfmcmd
- call getfil ;Open file.
- cpi 0FFH ;Succeed?
- jnz xmit1
- lxi d,erms15
- call prtstr ;Display error msg.
- jmp kermit
-
-;
-; New TRANSMIT routine - transmit a file, line by line, to a remote host
-; waiting each time for one or more characters to be returned
-; as a remote host prompt. It could be as simple as a CR or LF
-; character. Repeat until the complete file has been sent, then
-; close the transmitted file, and drop into the connect state so the
-; user can tidy up at the host end.
-;get the file to send, open it up, and read first sector from disk
-
-xmit1: lxi d,inms19 ; say we are send a file to the host
- call prtstr
-
- xra a
- sta repcnt ; clear the host prompt chars. counter
- sta starc ; clear star count
-;[MF][12]Delete the following call to "inbuf" as the call to "getfil"
-;[MF][12]above will have initialized counters and flags so that when
-;[MF][12]"in1chr" is called, "inbuf" will be called immediately and will
-;[MF][12]immediately read from disk. Counters and flags will then be
-;[MF][12]properly set up to read all characters of the file to be
-;[MF][12]transmitted.
-; call inbuf ; read one sector from disk
-; jmp xmtex ; exit if error
-
-
-xmt10: xra a ; clear retransmit flag and count etc
- sta rexbfl ; retransmit flag (1=> retransmit)
- sta rexcnt ; character counter
-
-xmt1: call xmt1ch ; send a character
- ani 7fh ; strip any parity
- cpi cr ; have we reached the end of the line
- jnz xmt1 ; nope, loop around again
-
-; Now wait for a string back from the host. Compare with STRING buffer
-;
- xra a ; clear the character count
- sta rexcnt
-;
- call selcon ; sent a line, send a star to console
- mvi e,'*'
- call outcon
- lda starc ; update star count
- inr a
- sta starc
- cpi 60 ; sent 60 stars?
- jnz xmt1a ; nope...
- xra a
- sta starc
- call prcrlf
-xmt1a:
-
-xmt3: lda eoflag ; have we hit end of file?
- ana a
- jnz xmtex ; yup, so quit.
- xra a
- sta repcnt ; clear the host prompt chars.counter
-xmt2: call rd1chl ; read a character from the line
- ani 7fh ; set flags
- jnz xmt4 ; Not zero => we have a character from host
- call ckchr ; see if *WE* have a character from console
- push psw ; restore to modem
- call selmdm
- pop psw
- ani 7fh ; stip parity (should not be there)
- jnz xmt2a ; if a null, try again
- lda strcnt ; if the string length is zero, dont wait.
- ana a
- jz xmt1 ; so loop back again
- jmp xmt4 ; else test for xon/off and incomming string
-
-xmt2a: cpi cntlc ; do we want to abort?
- jz xmtex ; in which case drop through to connect mode
- cpi cntlz ; if control z exit back to command loop
- jnz xmt2b ; else try for other characters
- lxi d,fcb ; close file before exiting to command loop
- mvi c,closf
- call bdos
- jmp kermit
-
-xmt2b: cpi cr ; a cr => resend last line
- jnz xmt2 ; nope, then ignore it
- mvi a,1
- sta rexbfl ; else we want to resend the line.
- jmp xmt1
-
-xmt4: jmp xmt6 ; skit xoff test for now...*****************
-
- cpi xoff ; xoff from host?
- jnz xmt6
-xmt5: call rd1chl ; else see if XOFF comming
- ani 7fh
- jnz xmt6 ; assume an xoff
- call ckchr ; anything at console?
- push psw
- call selmdm
- pop psw
- ani 7fh
- cpi cntlc ; control-c == abort & play terminal
- jz xmtex
- ana a ; anything else?
- jz xmt5 ;loop again
-
-xmt6: mov e,a ; save it for a while
- lda repcnt ; see if this character matches with one in buffer
- lxi h,stbuff ; point to string buffer
- add l ; make hl = hl + a
- mov l,a
- mvi a,0
- adc h
- mov h,a ; not using xra, as that clears the Carry flag
- mov a,e ; get the character back again
- cmp m ; is it = to what we expect?
- jnz xmt3 ; no, clear counter and try again
- lda repcnt ; yes, then update the pointer, and ...
- inr a ; ... see if we have received all ...
- sta repcnt ; ... we should have received
- mov e,a ; save length into E again
- lda strcnt ; get the length to compare
- sub e ; if (e) > string length, we have it
- jz xmt10 ; so send next line (clear counters etc)
- jmp xmt2 ; else wait for a little longer
-
-
-;
-; Routine below sends a character to the line. It sends up to a CR, and then
-; it waits for a reply. This routine is called from xmt1, so if at
-; end of file, return. Then XMT1 will drop through
-; to connect.
-xmt1ch: ; send a character from the xmtbuf to the line
- call selmdm ; just in case it uses it
- lda eoflag ; have we hit end of file
- ana a ; set flags
- jnz xmt1c1 ; no, so dont...
- mvi a,cr ; load up a carriage return
-xmt1c1: call get1xc ; get the character to send
- cpi lf ; dont send line feeds
-; jz xmt1c1
- cpi cntlz ; if control z, then we are at end of the file
- jz xmtex ; so close the file and drop into telcon
- cpi 20h ; control character?
- jp xmt11 ; no, so ok
- cpi cr ; cr, and tabs ok to send
- jz xmt11
- cpi tab
- jz xmt11
- jmp xmt1c1 ; else try for another character
-
-xmt11: call setpar ; else set parity etc
- push psw ; we want to keep this for a while
- mov e,a ; we need character in e
- call outmdm
- pop psw ; restore the character we sent
- mov e,a ; now, if a TAC is set on..
- lda tacflg
- ana a
- mov a,e ; (return must have sent character in a)
- jz xmt1c2 ; test for xon/off
- lda tacchr ;... get the tac character
- cmp e ; do we send it again?
- jnz xmt1c2 ; test for xon/off
- push psw ; save character for return. Already set E...
- call outmdm
- pop psw
-
-xmt1c2: ret
-
-get1xc: ; get a character from the sector or re-transmit buffer read
-; into a. Read a new sector if we run out.
-;
-; First, see if we do a retransmit
- lda rexbfl
- ana a ; if zero, a genuine line
- jz get1x1
-; have to retransmit a line
- lxi h,rexbuf
- lda rexcnt ; add counter to buffer base
- mvi d,0
- mov e,a
- dad d
- inr a ; update pointer
- sta rexcnt
- mov a,m ; get next character to send
- ret ; and exit
-
-get1x1: call in1chr ; get a character from the file.
- mov c,a ; save it to the retransmit buffer
- lda rexcnt
- mov e,a
- mvi d,0
- lxi h,rexbuf
- dad d ; point to next position
- inr a
- sta rexcnt ; update the character pointer
- mov a,c ; restore character to a
- mov m,c ; get character to c
- ret
-
-
-
-; read a character from the line.
-rd1chl:
- call selmdm ; select the modem
- call inpmdm ; get input from the modem
- ani 7fh ; strip parity
- ; may UPPERCASE-ify if case sensitivity off
- ret ; return to caller
-
-; End of transmit routine. Close input file name, and say we are dropping
-; throught to telnet. Note that if eof not found, it is assumed that
-; this is the ABORT exit.
-
-xmtex:
- lxi d,fcb ; close the transmitted file
- mvi c,closf
- call bdos
- call selcon ; make sure we are talking to the console
-
- lda eoflag ; end of file or abort exit?
- lxi d,inms22 ; assume eof...
- ana a
- jz xmtex1
- lxi d,inms29 ; we were wrong, its an abort.
-xmtex1: jmp telnt1 ; and drop through to connect mode
- ; telnet does the printing
-
-
-
-;\f
-; telnet - the CONNECT command.
-; here from: kermit
-; telnt1 - entry to connect mode from TRANSMIT command
-; here from: xend
-
-telnet: call cfmcmd
- lxi d,infms7 ;Output start of message
-; enter here from TRANSMIT command.
-telnt1: call prtstr
- call escpr ;Print the escape char.
- lxi d,infms8 ;Output some more of the message
- call prtstr
- call escpr ;Print the escape char again.
- lxi d,inms8a ;Print the remainder of the message
- call prtstr
- call syscon ;do system-dependent stuff
- lda logflg ;[pcc005] Want a log?
- ora a ;[pcc005]
- cnz logopn ;[pcc005] Open if so
-
-chrlup: call prtchr ;See if char at port (send to console).
- call conchr ;See if char at console (send to port).
- jmp kermit ;requested to end session - go to command loop.
- jmp chrlup ;Go do it again.
-;\f
-;
-; prtchr - copy characters from comm line to console
-; returns: nonskip, console selected.
-; called by: xnext, rexmit, telnet
-;
-
-prtchr: call selmdm ; select modem port
- call inpmdm ; try to get a character from it
- push psw ; restore to console
- call selcon ; select console
- pop psw ; restore the (possible character) read
- ora a ; test character
- jnz prtch0 ; if non-zero, process it.
- sta prtcnt ;[pcc008] zero out prt fairness count
- ret ; return.
-
-prtch0: ani 7FH ; drop parity bit.
- sta comchr ;[6] save it in case we need it again
- lda vtflg ;[9] get the vt52 emulation flag
- cpi vtdefe ;[9] are we doing external emulation?
- lda comchr ;[9] collect character again
- jz extern ;[9] jup, go do it.
-
- ana a ; set flags. it may be a null
- jz prtchr ; ignore null (filler)
- cpi del ; ignore delete, too
- jz prtchr
- cpi xon ;Is it an XON?
- jz prtxon ;yes
- cpi xoff ;Is it an XOFF?
- jz prtxof ;yes
- mov e,a ;Set the char aside.
- lda vtflg ;Get the VT52 emulation flag.
- cpi vtdefv ;Is the flag set for VT52 (ie 1)
- ;0 = none
- ;1 = VT52
- ;2 = external
- ;3 = dumb (traps non printing chars)
- ;0ffh not possible by local code (Will change)
- jnz prtch1 ;If not, don't do this stuff.
- lda escflg ;Get the escape flag.
- ora a ;Are we working on an escape sequence?
- jz prtch2 ;If not, continue.
- call vt52 ;If so, work on it some more
- jmp prtchr ;try for more characters.
-
-prtch2: mov a,e ;normal text.
- cpi esc ;Is the char an escape?
- jnz prtch1 ;If not skip on.
- mvi a,1
- sta escflg ;Set the escape flag: escape seen.
- jmp prtchr ;Get another char...
-
-prtch1: cpi vtdefe ; are we doing external emulation?
- jnz prtch3 ; assume we continue on
- lxi h,extern+1 ; get address of external emulator
- mov a,h ; se if address = 0 (not implemented)
- ora l
- jz prtch3 ; not external, assume we just carry on
- pchl ; go do external emulation. RET back to caller
-
-prtch3: cpi vtdefd ; are we trapping all non printing characters?
- jnz prtch4 ; nope, something else
- lda comchr ; Dumb terminal. Lets test the character
- cpi cr ; cr then ok
- jz prtch4 ; its ok
- cpi lf ; lf then ok
- jz prtch4
- cpi tab
- jz prtch4 ; assume tabs are expanded
- cpi space ; if less than 20H ignore it
- rm ; return if a control character
-
-prtch4: call sysflt ; ok to print this character (in E)?
- ora a
- jz prtchr ; no, skip it.
- lda logflg ;Get the log flag.
- cpi 81H ;[pcc003] Are we logging
- cz logit ;[pcc003] Do so if needed
- call selcon ; select console
- lda prnflg ;Get Print parallel flag
- ora a
- cnz outlpt ; output to printer if flag set
- call outcon ; output to console.
- lxi h,prtcnt ;[pcc008] point to prt fairness count
- inr m ;[pcc008] bump
- mov a,m ;[pcc008] get it in a
- cpi prfair+1 ;[pcc008] time to be fair?
- jm prtchr ;[pcc008] no, go around again.
- mvi m,0 ;[pcc008] reset count
- lda comchr ;[6] restore that character read from comm line
- ret ;[pcc008] and return
-
-; I don't think we want to print xon/xoff - this should be
-; flow control only across the link between us and the host.
-; (besides, IBM host xon's don't make sense to most micros)
-; remember xon/xoff state in xofflg (zero = xon, non-zero = xoff)
-prtxon: xra a ;Yes, reset XOFF flag
-prtxof: sta xofflg
- jmp prtchr ; look for another character
-;\f;[pcc005] Log file routines
-
-;[pcc005]
-; logopn - open the log file
-; Open the log file and append to it if it already exists
-; or create one if not.
-
-logopn:
- mvi a,ctrlz ;[9] ignore control-z in log files
- cmp e ;[9] well, was it?
- rz ;[9] yes, to ignore it.
- lxi h,lognam ;[pcc012] copy name
- lxi d,fcb ;[pcc012] to fcb
- lxi b,12 ;[pcc012] 12 bytes
- call mover ;[pcc012] copy it
- call appfil ;[pcc012] open file for appending
- jmp logerr ;[pcc012] error
- lxi h,logflg ;[pcc005] point to log flag
- mvi a,80H ;[pcc005] file open flag
- ora m ;[pcc005] or in contents of logflg
- mov m,a ;[pcc005] and store back
- lxi d,inms28 ;[pcc005] assume logging is on
- cpi 81H ;[pcc005] check
- jz prtstr ;[pcc005] print msg if true
- lxi d,inms27 ;[pcc005] no, must be suspended
- jmp prtstr ;[pcc005] print and return
-
-;
-; logit - output character in E to log file.
-; we assume the host recognizes xon/xoff. (we probably shouldn't)
-; modem port is selected.
-; preserves de
-; called by: prtchr
-
-logit: lxi h,chrcnt ;[pcc012] point to buffer count
- dcr m ;[pcc012] and decrement
- jp logit1 ;[pcc012] continue if ok
- push d ;[pcc012] save de
- call outadv ;[pcc012] advance buffer if in memory
- call logwrt ;[pcc012] sigh, time to write to disk
- pop d ;[pcc012] restore de
- lda logflg ;[pcc012] get logging flag
- ora a ;[pcc012] Did we quit because of an error
- rz ;[pcc012] return now if so
-logit1: lhld bufpnt ;[pcc012] get buffer pointer
- mov m,e ;Store the char.
- inx h
- shld bufpnt
- ret ;[pcc012] and return
-
-;[pcc012]
-; logwrt - write to log file with XON/XOFF since it may take a while.
-
-logwrt: call sndxoff ;[7] send and xoff to host
- call outbuf ;[pcc012] output the buffer and advance
- call logerr ;[pcc005] quit if error
- call sndxon ;[send an xon to host
- ret ;[pcc012]
-
-;[pcc005]
-; logcls - Close the log file and reset the flag
-
-logcls: lxi d,infms6 ;[pcc005] Tell user we are closing file.
- call prtstr ;[pcc005]
- call clofil ;[pcc012] and do it
- jmp logerr ;[pcc005] jump if error
- lxi h,logflg ;[pcc005] point to flag
- mov a,m ;[pcc005] get it
- ani 7FH ;[pcc005] clear the open bit
- mov m,a ;[pcc005] and store back
- ret ;[pcc005]
-
-;[pcc005]
-; logerr - here on a variety of logging errors
-; just close the file and disable logging
-; called from logopn,logptr,logcls
-
-logerr: lxi d,erms22 ;[pcc005] Error message
- call prtstr ;[pcc005] print it
- mvi c,closf ;[pcc005] Close the file.
- lxi d,fcb ;[pcc012]
- call bdos ;[pcc005]
- xra a ;[pcc005] clear logflg
- sta logflg ;[pcc005] so don't try again
- ret ;[pcc005]
-;\f
-;
-; VT52 emulation.
-; called by: prtchr
-; A/ contents of escflg (guaranteed non-zero)
-; E/ current character
-; modem is selected.
-;
-vt52: cpi 1 ; first character after escape?
- jnz vt52y ; no, must be doing cursor positioning.
-;
-; E contains the character that followed the escape.
-; valid characters are:
-; A - cursor up
-; B - cursor down
-; C - cursor right
-; D - cursor left
-; F - enter graphics mode (hard to do on a non-vt52)
-; G - exit graphics mode
-; H - home
-; I - reverse linefeed
-; J - erase to end of screen
-; K - erase to end of line
-; Y - cursor positioning leadin
-; Z - identify terminal as VT52
-; [ - enter hold-screen mode (not supported)
-; \ - exit hold-screen mode (not supported)
-; > - enter alternate-keypad mode? (not supported)
-; = - exit alternate-keypad mode? (not supported)
-;
-; Invalid sequences are handled as the VT52 does - the escape and
-; the following character are swallowed, never to be seen again.
-; For <esc>E, the translation table may contain just '$' (no action),
-; or may be used as clear-and-home, as in the Heath/Zenith H19.
-;
- mov a,e ; get the second character of the sequence.
- cpi 'Y' ; if cursor lead-in handle it.
- jnz vt52a ; if not, go on.
- mvi a,2 ; state = 2: row follows.
- sta escflg ; update the flag.
- ret ; back for another character
-
-vt52a: cpi 'Z' ; VT52 ID query?
- jz vt52id ; yes. claim to be one.
- cpi 'A' ;Less than an 'A'?
- jm vtig ;Yes - ignore.
- cpi 'K'+1 ;Greater than 'K'?
- jp vtig ;Yes - ignore.
- sui 'A' ;Else make into index.
- rlc ;Multiply by four.
- rlc ;(Shift left twice.)
- lhld pttab ;Load base addr of table.
- mov e,a ;Move a into de pair.
- mvi d,00H ;Zero out high byte.
- dad d ;Double add index+offset.
- xchg ;Exchange de with hl.
- call selcon ; select console
- call prtstr ;and syscall.
-vtig: ;Ignore escape sequence.
- xra a ;Reset the ol' escape flag.
- sta escflg
- ret ;Return home.
-
-; here for <esc>Z. Tell the host we're a VT52. (Sure we are...)
-vt52id: mvi a,esc ; response is escape...
- call setpar ; (need correct parity)
- mov e,a
- call outmdm ; (console already selected)
- mvi a,'/' ; ... slash ...
- call setpar ; (with parity)
- mov e,a
- call outmdm
- mvi a,'K' ; ... K.
- call setpar
- mov e,a
- call outmdm
- jmp vtig ; clear escape-sequence flag and return.
-
-; here when escflg isn't 0 or 1 - processing cursor positioning sequence.
-vt52y: cpi 2 ; looking for row? (y-coordinate)
- jnz vt52x ; no, must be column.
- mov a,e ; yes. get coordinate
- sui (' '-1) ; convert from ascii (1 = top line)
- sta vtyval ; store for later
- mvi a,3 ; advance to next state (x coord)
- sta escflg ; store it
- ret ; try for another character
-
-; here when escflag isn't 0, 1, or 2 - it must be 3. (right?)
-; E holds the last character of the cursor positioning sequence.
-vt52x: xra a ; end of escape sequence, reset state.
- sta escflg
- mov a,e ; get column (' ' is left margin)
- sui (' '-1) ; make left margin be one
- mov c,a ; stash column in c
- lda vtyval ; get row number
- mov b,a ; in b
- call selcon ; select console
- call csrpos ; call system-dependent cursor positioner
- ret ; all through.
-;\f
-;
-; conchr - copy character from console to comm line, processing
-; (kermit's) escape sequences.
-; Enter and exit with console selected.
-; nonskip return: transparent mode terminated.
-; skip return: still in transparent mode.
-; called by: rexmit, telnet
-
-conchr: call inpcon ;Try to get a character from the console
- ani 07FH ;Keep only 7 bits
- jz rskp ;Null means nothing there.
- mov e,a ;Move the char for comparison.
- sta lstchr ;Save it
- lda escchr ;Get the escape char.
- cmp e ;Is it an escape char?
- jz intchr ;If so go process it.
- call selmdm ; select the modem
- mov a,e ;Get the char.
- call setpar ;Set parity (if any).
- mov e,a ;Restore it.
- push d ; need to save e in case we are half dplx [5]
- call outmdm ;Output the char to the port.
- pop d ; Just in case we are half dplx [5]
- call selcon ; reselect console
- lda ecoflg ;Get the echo flag.
- ora a ;Is it turned on?
- jz rskp ;If not we're done here.
- mov a,e ;Get the char.
- ani 7FH ;Turn off the parity bit.
- mov e,a
- call outcon ; echo the character.
- jmp rskp ; use skip return
-;\f
-; transparent escape character has been typed. dispatch on second
-; character. (console is still selected)
-; here from: conchr
-
-intchr: call inpcon ; get another character from the console
- ora a ; zero means no character available yet.
- jz intchr ; If so, loop until we get a char.
- mov b,a ;Save the actual char.
- cpi ctrlc ;is it Control-C?
- jz contc ;yes
- ani 137O ;Convert to upper case.
- cpi 'C' ;Is it close?
- jnz intch0 ;If not proceed.
-contc: lxi d,infms9 ;Say we are back.
- call prtstr
- call syscls ; call system-dependent close routine
- lda logflg ;Get the log flag.
- ora a ;[pcc005] Check if open
- cm logcls ;[pcc005] Close if needed
- ret
-
-;Here if not a 'C' or '^C'
-
-intch0: cpi 'S' ;Is it status?
- jnz inch01 ;If not, proceed.
- call stat01 ;Print out the status stuff.
- call prcrlf ;[pcc011] add a crlf
- jmp rskp ;return from conchr
-
-inch01:
-inch03: mov a,b ;Get the char.
- cpi '?' ;Is it a help request?
- jnz intch1 ;If not, go to the next check.
-inch3a: lda logflg ;[pcc003] Logging flag
- ora a ;[pcc003] see if active
- jp inch04 ;[pcc005] jump if no file open
- lxi d,loghlp ;[pcc003] yes, tell about R AND Q
- call prtstr ;[pcc003]
-inch04: lxi d,inthlp ;If so, get the address of the help message.
- call prtstr
- call sysinh ; print system-dependent help message
- lxi d,inhlp1 ; Tell about doubling the escape character
- call prtstr
- call escpr ;Print escape character
- lxi d,inhlp2 ;Print the rest
- call prtstr
- jmp intchr ;Get another char.
-
-intch1: mov a,b ;Get the character.
- cpi '0' ;Is it '0', to send a null?
- jnz intch3 ;No.
- xra a ;Yes, send an ASCII zero.
- call setpar ; with the correct parity
- mov e,a
- call selmdm ; (to the modem...)
- call outmdm
- call selcon ; return with console selected
- jmp rskp
-
-intch3: lda escchr ;Get the escape char.
- cmp b ;Is it the escape char?
- jnz intch4 ;[pcc002] jump if not
- mov a,b ;Get the char.
- call setpar
- mov e,a ;Restore it.
- call selmdm
- call outmdm ;Output it.
- call selcon ;We promised console would be selected...
- jmp rskp ;Return, we are done here.
-intch4: mov a,b ;[pcc002] get it again
- ani 137o ;[pcc002] in upper case
- cpi 'P' ;[pcc002] toggle printer?
- jnz intch5 ;[pcc003] nope
- lda prnflg ;[pcc002] get printer flag
- xri 01h ;[pcc002] complement it
- sta prnflg ;[pcc002] and put back
- jmp rskp ;[pcc002]
-intch5: lda logflg ;[pcc003] get log flag
- ora a ;[pcc003] See if open
- jp intch7 ;[pcc003] no, skip R and Q
- mov a,b ;[pcc003] get back chr
- ani 137o ;[pcc003] make upper case
- cpi 'R' ;[pcc003] Is it R
- jnz intch6 ;[pcc003] Jump if not
- mvi a,81H ;[pcc003] set flag for logging
- sta logflg ;[pcc003] put it back
- lxi d,inms28 ;[pcc003] message
- call prtstr ;[pcc003]
- jmp rskp ;[pcc003] done
-intch6: cpi 'Q' ;[pcc003] Quit logging?
- jnz intch7 ;[pcc003] no
- mvi a,82H ;[pcc003] flag for open, but suspended
- sta logflg ;[pcc003] store away
- lxi d,inms27 ;[pcc003] keep them informed
- call prtstr ;[pcc003]
- jmp rskp ;[pcc003]
-intch7: ;[pcc003]
-
-intchz: mov a,b ; not recognized. get saved copy back.
- push psw ;[8] save as we will want to test for 'D'
- call sysint ; interpret system-dependent sequences
- jmp intchy ; done. [10] Now see if D. If so, do a C.
- pop psw ;[10] tidy stack
- mvi e,'G'-100O ;Otherwise send a beep.
- call outcon ; to the console.
- jmp rskp
-
-intchy: pop psw ;[10] adjust stack
- ani 5fh ;[10] strip parity, make it upper case
- cpi 'D' ;[10] was it a D?
- jz contc ;[10] yup, so to the equivalent of an escape-C
- jmp rskp
-;\f
-; Little code to allow some expansion of code without changing
-; every futher address, only up to the end of this file.
-; TO BE REMOVED FOR RELEASE!
-
-; org ($+100h) AND 0FF00H
-IF lasm
- LINK CPSCPM
-ENDIF;lasm
+; CPSTT.ASM\r
+; KERMIT - (Celtic for "FREE")\r
+;\r
+; This is the CP/M-80 implementation of the Columbia University\r
+; KERMIT file transfer protocol.\r
+;\r
+; Version 4.0\r
+;\r
+; Copyright June 1981,1982,1983,1984,1985\r
+; Columbia University\r
+;\r
+; Originally written by Bill Catchings of the Columbia University Center for\r
+; Computing Activities, 612 W. 115th St., New York, NY 10025.\r
+;\r
+; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,\r
+; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many\r
+; others. \r
+;\r
+; This file contains the code for the TRANSMIT and CONNECT commands,\r
+; which communicate with a host which is not running KERMIT.\r
+;\r
+; revision history:\r
+;\r
+;edit 12, 31-Jan-1991 by MF. Delete call to "inbuf" after "xmit1" in\r
+; the TRANSMIT command. "getfil" initializes various counters so that\r
+; when "in1chr" is first called, "inbuf" will be called immediately\r
+; and will read sectors of the file to be transmitted from disk.\r
+; This, along with a fix to "in1chr" in CPSUTL.ASM, fixes a bug\r
+; discovered by Lance Tagliapietra of the University of Wisconsin at\r
+; Platteville wherein the TRANSMIT command was failing to transmit some\r
+; characters in files over one sector in length. See CPSUTL.ASM,\r
+; edit 29.\r
+; edit 11, 10 September, a987, by OBSchou. Modified TRANSMIT command\r
+; to TRANSMIT <file> <string>\r
+;\r
+; edit 10, 27 August, 1987 by OBSchou. Fixed bugs in Transmit, but I may\r
+; be introducing problems for IBM/CMS or half duplex systems. What\r
+; does this combination do??\r
+;\r
+; edit 9 30 March, 1987 by OBSchou to replace the TRANSMIT routine.\r
+; Syntax is now TRANSMIT file after a previous \r
+; INPUT <wait time> <string to wait for>\r
+;\r
+; edit 8 19 June, 1986 by OBSchou. Modified the interupt testing routine\r
+; to see if the command was a 'D' (Drop the line), in which case also\r
+; do a 'C', ie disconnect. This is really a little too much of a\r
+; system dependent thing.\r
+; For now, Ill leave it here, and possibly move it later.\r
+;\r
+; edit 7 30 May 1986 OBSchou. Moved xon/xoff control (ie XON/OFF sent to host)\r
+; out to CPSUTL so that ther printer routine can use it too.\r
+;\r
+; edit 6 30 April, 1986 by OBSchou.\r
+; Fixed transmit bug, so as soon as the protocol character is \r
+; received from the host is received then another line is sent.\r
+; added in a comchr (ds 1) to save the character read from the comm \r
+; line in prtchr, and is restored in a on return.\r
+;\r
+; edit 5 7 March, 1986 by OBSchou Loughborough University. \r
+; Need to save the E register before calling outmdm (in CPSSYS.ASM)\r
+; if doing Half duplex. Push/pop DE should sort this problem\r
+;\r
+; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809\r
+;\r
+;pcc002 28-Dec-84 modules:cp4tt,cp4utl\r
+; Add connect mode <esc>P command to toggle printer on\r
+; and off. Conflicts with "official" recommended commands\r
+; in protocol manual, but I don't think CP/M will ever get\r
+; a PUSH command.\r
+;\r
+;pcc003-pcc005 2-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl\r
+; These edits must all be installed together and change the way\r
+; logging is handled. The log file spec is moved to a separate\r
+; fcb, and not opened until an actual CONNECT command is given.\r
+; This takes care of a NASTY bug that if you used any other file\r
+; command between the LOG and CONNECT, the log file would get\r
+; written over the last file used. This also allows logging to\r
+; be "permanently" enabled until an CLOSE (new command) for all\r
+; CONNECT sessions, like most other kermits do. If a log file\r
+; already exists, it will be appended to. Also add two new\r
+; CONNECT mode commands <esc>Q to suspend logging and <esc>R to\r
+; resume. <esc>R means something else during TRANSMIT, but\r
+; logging is never on then, so there shouldn't be any conflict.\r
+; I also changed the write code, so that it can handle one more\r
+; character after the XOFF is send to stop the host. This allows\r
+; a little "slop" for systems that don't stop immediately (such\r
+; as TOPS10), but it didn't help much.\r
+;\r
+;pcc008 2-Jan-85 vjc modules:cp4def,cp4tt,cp4utl\r
+; Keyboard input during CONNECT mode can get locked out if\r
+; there is enough input from the modem port to keep prtchr\r
+; busy. This can happen for example, if the printer is running\r
+; at the same speed as the modem line, leaving you helpless to\r
+; turn it off or abort the host. Add a fairness count, so that\r
+; at least every prfair characters we look at console input.\r
+;\r
+;pcc012 4-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl\r
+; Use the big buffer for the log file. Move the log file back\r
+; into the common fcb and only save the drive, name, and\r
+; extension between connects. Add new routines to cp4utl to\r
+; create or append to an existing file, and to conditionally\r
+; advance buffers only if in memory. Remove edit pcc003 that\r
+; allows one more character after the xoff, since it didn't\r
+; really work very well and does not fit in well with the way\r
+; the buffer advancing routines are set up. If someone still\r
+; thinks this would be useful, it could be put back in with a\r
+; little more work.\r
+; \r
+; While testing this edit, I also noticed another bug that\r
+; the command parsing routines do not limit or check the\r
+; length of command lines or file specs, trashing what ever\r
+; comes after them. Currently because of where the fcb and\r
+; command buffer are located, this does not usually cause a\r
+; problem, but could if an extremely long line was typed in,\r
+; or in the future multiple fcbs defined elsewhere in memory\r
+; were used. Maybe this should be put on the bug list\r
+; somewhere.\r
+;\r
+; edit 3: July 27, 1984\r
+; Allow assembly with LASM: to CP4TT is linked by CP4PKT, and links\r
+; to CP4CPM; remove exclamation points so as not to confuse LASM.\r
+; Add Toad Hall TACtrap to TRANSMIT command (TAC intercept character\r
+; is only doubled if it's data; when typed by the user, they're not\r
+; automatically doubled)\r
+;\r
+; edit 2: June 7, 1984\r
+; formatting and documentation; add module version number; make sure\r
+; console is selected when leaving intchr.\r
+;\r
+; edit 1: May, 1984\r
+; extracted from CPMBASE.M80 version 3.9; modifications are described\r
+; in the accompanying .UPD file.\r
+\r
+ttver: db 'CPSTT.ASM (12) 31-Jan-1991$'\r
+\r
+; This is the TRANSMIT command. It attempts to send a file, even\r
+; though there is no KERMIT on the other side.\r
+; here from: kermit\r
+;\r
+; [OBS] I have replaced the routine, so that TRANSMIT <filename> <wait string>\r
+; will send a line at a time to the host in a manner similar to MSKERMIT\r
+;\r
+;\r
+xmit: mvi a,cmofi ;Parse an input file spec (non-wild).\r
+ lxi d,fcb ;Give the address for the FCB.\r
+ call comnd\r
+ jmp kermit ;Give up on bad parse.\r
+;\r
+ lxi d,stbuff ; where to put the string\r
+ mvi a,cmtxt ; get text\r
+ call comnd\r
+ jmp kermit ; not quite correct...\r
+ sta strcnt ; string count returned in a\r
+ ana a ; if its zero, make it 1 character (CR)\r
+ jnz xmit0\r
+ mvi a,1\r
+ sta strcnt\r
+ mvi a,cr\r
+ sta stbuff\r
+;\r
+xmit0: call cfmcmd\r
+ call getfil ;Open file.\r
+ cpi 0FFH ;Succeed?\r
+ jnz xmit1\r
+ lxi d,erms15\r
+ call prtstr ;Display error msg.\r
+ jmp kermit\r
+\r
+;\r
+; New TRANSMIT routine - transmit a file, line by line, to a remote host\r
+; waiting each time for one or more characters to be returned\r
+; as a remote host prompt. It could be as simple as a CR or LF\r
+; character. Repeat until the complete file has been sent, then\r
+; close the transmitted file, and drop into the connect state so the\r
+; user can tidy up at the host end.\r
+;get the file to send, open it up, and read first sector from disk\r
+\r
+xmit1: lxi d,inms19 ; say we are send a file to the host\r
+ call prtstr\r
+\r
+ xra a\r
+ sta repcnt ; clear the host prompt chars. counter \r
+ sta starc ; clear star count\r
+;[MF][12]Delete the following call to "inbuf" as the call to "getfil"\r
+;[MF][12]above will have initialized counters and flags so that when\r
+;[MF][12]"in1chr" is called, "inbuf" will be called immediately and will\r
+;[MF][12]immediately read from disk. Counters and flags will then be\r
+;[MF][12]properly set up to read all characters of the file to be\r
+;[MF][12]transmitted.\r
+; call inbuf ; read one sector from disk\r
+; jmp xmtex ; exit if error\r
+\r
+\r
+xmt10: xra a ; clear retransmit flag and count etc\r
+ sta rexbfl ; retransmit flag (1=> retransmit)\r
+ sta rexcnt ; character counter\r
+\r
+xmt1: call xmt1ch ; send a character\r
+ ani 7fh ; strip any parity\r
+ cpi cr ; have we reached the end of the line\r
+ jnz xmt1 ; nope, loop around again\r
+\r
+; Now wait for a string back from the host. Compare with STRING buffer\r
+;\r
+ xra a ; clear the character count\r
+ sta rexcnt\r
+;\r
+ call selcon ; sent a line, send a star to console\r
+ mvi e,'*'\r
+ call outcon\r
+ lda starc ; update star count\r
+ inr a\r
+ sta starc\r
+ cpi 60 ; sent 60 stars?\r
+ jnz xmt1a ; nope...\r
+ xra a\r
+ sta starc\r
+ call prcrlf\r
+xmt1a:\r
+\r
+xmt3: lda eoflag ; have we hit end of file?\r
+ ana a\r
+ jnz xmtex ; yup, so quit.\r
+ xra a\r
+ sta repcnt ; clear the host prompt chars.counter\r
+xmt2: call rd1chl ; read a character from the line\r
+ ani 7fh ; set flags\r
+ jnz xmt4 ; Not zero => we have a character from host\r
+ call ckchr ; see if *WE* have a character from console\r
+ push psw ; restore to modem\r
+ call selmdm\r
+ pop psw\r
+ ani 7fh ; stip parity (should not be there)\r
+ jnz xmt2a ; if a null, try again\r
+ lda strcnt ; if the string length is zero, dont wait.\r
+ ana a\r
+ jz xmt1 ; so loop back again\r
+ jmp xmt4 ; else test for xon/off and incomming string\r
+\r
+xmt2a: cpi cntlc ; do we want to abort?\r
+ jz xmtex ; in which case drop through to connect mode\r
+ cpi cntlz ; if control z exit back to command loop\r
+ jnz xmt2b ; else try for other characters\r
+ lxi d,fcb ; close file before exiting to command loop\r
+ mvi c,closf\r
+ call bdos\r
+ jmp kermit\r
+\r
+xmt2b: cpi cr ; a cr => resend last line\r
+ jnz xmt2 ; nope, then ignore it\r
+ mvi a,1\r
+ sta rexbfl ; else we want to resend the line.\r
+ jmp xmt1\r
+\r
+xmt4: jmp xmt6 ; skit xoff test for now...*****************\r
+\r
+ cpi xoff ; xoff from host?\r
+ jnz xmt6\r
+xmt5: call rd1chl ; else see if XOFF comming\r
+ ani 7fh\r
+ jnz xmt6 ; assume an xoff\r
+ call ckchr ; anything at console?\r
+ push psw\r
+ call selmdm\r
+ pop psw\r
+ ani 7fh\r
+ cpi cntlc ; control-c == abort & play terminal\r
+ jz xmtex\r
+ ana a ; anything else?\r
+ jz xmt5 ;loop again\r
+\r
+xmt6: mov e,a ; save it for a while\r
+ lda repcnt ; see if this character matches with one in buffer\r
+ lxi h,stbuff ; point to string buffer\r
+ add l ; make hl = hl + a\r
+ mov l,a\r
+ mvi a,0\r
+ adc h\r
+ mov h,a ; not using xra, as that clears the Carry flag\r
+ mov a,e ; get the character back again\r
+ cmp m ; is it = to what we expect?\r
+ jnz xmt3 ; no, clear counter and try again\r
+ lda repcnt ; yes, then update the pointer, and ...\r
+ inr a ; ... see if we have received all ...\r
+ sta repcnt ; ... we should have received\r
+ mov e,a ; save length into E again\r
+ lda strcnt ; get the length to compare\r
+ sub e ; if (e) > string length, we have it\r
+ jz xmt10 ; so send next line (clear counters etc)\r
+ jmp xmt2 ; else wait for a little longer\r
+\r
+\r
+;\r
+; Routine below sends a character to the line. It sends up to a CR, and then\r
+; it waits for a reply. This routine is called from xmt1, so if at \r
+; end of file, return. Then XMT1 will drop through\r
+; to connect.\r
+xmt1ch: ; send a character from the xmtbuf to the line\r
+ call selmdm ; just in case it uses it\r
+ lda eoflag ; have we hit end of file\r
+ ana a ; set flags\r
+ jnz xmt1c1 ; no, so dont...\r
+ mvi a,cr ; load up a carriage return\r
+xmt1c1: call get1xc ; get the character to send\r
+ cpi lf ; dont send line feeds\r
+; jz xmt1c1\r
+ cpi cntlz ; if control z, then we are at end of the file\r
+ jz xmtex ; so close the file and drop into telcon\r
+ cpi 20h ; control character?\r
+ jp xmt11 ; no, so ok\r
+ cpi cr ; cr, and tabs ok to send\r
+ jz xmt11\r
+ cpi tab\r
+ jz xmt11\r
+ jmp xmt1c1 ; else try for another character\r
+\r
+xmt11: call setpar ; else set parity etc\r
+ push psw ; we want to keep this for a while\r
+ mov e,a ; we need character in e\r
+ call outmdm\r
+ pop psw ; restore the character we sent\r
+ mov e,a ; now, if a TAC is set on..\r
+ lda tacflg\r
+ ana a \r
+ mov a,e ; (return must have sent character in a)\r
+ jz xmt1c2 ; test for xon/off\r
+ lda tacchr ;... get the tac character\r
+ cmp e ; do we send it again?\r
+ jnz xmt1c2 ; test for xon/off\r
+ push psw ; save character for return. Already set E...\r
+ call outmdm\r
+ pop psw\r
+\r
+xmt1c2: ret\r
+\r
+get1xc: ; get a character from the sector or re-transmit buffer read \r
+; into a. Read a new sector if we run out.\r
+;\r
+; First, see if we do a retransmit\r
+ lda rexbfl\r
+ ana a ; if zero, a genuine line\r
+ jz get1x1\r
+; have to retransmit a line\r
+ lxi h,rexbuf\r
+ lda rexcnt ; add counter to buffer base\r
+ mvi d,0\r
+ mov e,a\r
+ dad d\r
+ inr a ; update pointer\r
+ sta rexcnt\r
+ mov a,m ; get next character to send\r
+ ret ; and exit\r
+\r
+get1x1: call in1chr ; get a character from the file. \r
+ mov c,a ; save it to the retransmit buffer\r
+ lda rexcnt\r
+ mov e,a\r
+ mvi d,0\r
+ lxi h,rexbuf\r
+ dad d ; point to next position\r
+ inr a\r
+ sta rexcnt ; update the character pointer\r
+ mov a,c ; restore character to a\r
+ mov m,c ; get character to c\r
+ ret\r
+\r
+\r
+\r
+; read a character from the line.\r
+rd1chl: \r
+ call selmdm ; select the modem\r
+ call inpmdm ; get input from the modem\r
+ ani 7fh ; strip parity\r
+ ; may UPPERCASE-ify if case sensitivity off\r
+ ret ; return to caller\r
+\r
+; End of transmit routine. Close input file name, and say we are dropping\r
+; throught to telnet. Note that if eof not found, it is assumed that\r
+; this is the ABORT exit.\r
+\r
+xmtex:\r
+ lxi d,fcb ; close the transmitted file\r
+ mvi c,closf\r
+ call bdos\r
+ call selcon ; make sure we are talking to the console\r
+\r
+ lda eoflag ; end of file or abort exit?\r
+ lxi d,inms22 ; assume eof...\r
+ ana a\r
+ jz xmtex1\r
+ lxi d,inms29 ; we were wrong, its an abort.\r
+xmtex1: jmp telnt1 ; and drop through to connect mode\r
+ ; telnet does the printing\r
+\r
+\r
+\r
+;\f\r
+; telnet - the CONNECT command.\r
+; here from: kermit\r
+; telnt1 - entry to connect mode from TRANSMIT command\r
+; here from: xend\r
+\r
+telnet: call cfmcmd\r
+ lxi d,infms7 ;Output start of message\r
+; enter here from TRANSMIT command.\r
+telnt1: call prtstr\r
+ call escpr ;Print the escape char.\r
+ lxi d,infms8 ;Output some more of the message\r
+ call prtstr\r
+ call escpr ;Print the escape char again.\r
+ lxi d,inms8a ;Print the remainder of the message\r
+ call prtstr\r
+ call syscon ;do system-dependent stuff\r
+ lda logflg ;[pcc005] Want a log?\r
+ ora a ;[pcc005]\r
+ cnz logopn ;[pcc005] Open if so\r
+\r
+chrlup: call prtchr ;See if char at port (send to console).\r
+ call conchr ;See if char at console (send to port).\r
+ jmp kermit ;requested to end session - go to command loop.\r
+ jmp chrlup ;Go do it again.\r
+;\f\r
+;\r
+; prtchr - copy characters from comm line to console\r
+; returns: nonskip, console selected.\r
+; called by: xnext, rexmit, telnet\r
+;\r
+\r
+prtchr: call selmdm ; select modem port\r
+ call inpmdm ; try to get a character from it\r
+ push psw ; restore to console\r
+ call selcon ; select console\r
+ pop psw ; restore the (possible character) read\r
+ ora a ; test character\r
+ jnz prtch0 ; if non-zero, process it.\r
+ sta prtcnt ;[pcc008] zero out prt fairness count\r
+ ret ; return.\r
+\r
+prtch0: ani 7FH ; drop parity bit.\r
+ sta comchr ;[6] save it in case we need it again\r
+ lda vtflg ;[9] get the vt52 emulation flag\r
+ cpi vtdefe ;[9] are we doing external emulation?\r
+ lda comchr ;[9] collect character again\r
+ jz extern ;[9] jup, go do it.\r
+\r
+ ana a ; set flags. it may be a null\r
+ jz prtchr ; ignore null (filler)\r
+ cpi del ; ignore delete, too\r
+ jz prtchr\r
+ cpi xon ;Is it an XON?\r
+ jz prtxon ;yes\r
+ cpi xoff ;Is it an XOFF?\r
+ jz prtxof ;yes\r
+ mov e,a ;Set the char aside.\r
+ lda vtflg ;Get the VT52 emulation flag.\r
+ cpi vtdefv ;Is the flag set for VT52 (ie 1)\r
+ ;0 = none\r
+ ;1 = VT52\r
+ ;2 = external\r
+ ;3 = dumb (traps non printing chars)\r
+ ;0ffh not possible by local code (Will change)\r
+ jnz prtch1 ;If not, don't do this stuff.\r
+ lda escflg ;Get the escape flag.\r
+ ora a ;Are we working on an escape sequence?\r
+ jz prtch2 ;If not, continue.\r
+ call vt52 ;If so, work on it some more\r
+ jmp prtchr ;try for more characters.\r
+\r
+prtch2: mov a,e ;normal text.\r
+ cpi esc ;Is the char an escape?\r
+ jnz prtch1 ;If not skip on.\r
+ mvi a,1\r
+ sta escflg ;Set the escape flag: escape seen.\r
+ jmp prtchr ;Get another char...\r
+\r
+prtch1: cpi vtdefe ; are we doing external emulation?\r
+ jnz prtch3 ; assume we continue on\r
+ lxi h,extern+1 ; get address of external emulator\r
+ mov a,h ; se if address = 0 (not implemented)\r
+ ora l\r
+ jz prtch3 ; not external, assume we just carry on\r
+ pchl ; go do external emulation. RET back to caller\r
+\r
+prtch3: cpi vtdefd ; are we trapping all non printing characters?\r
+ jnz prtch4 ; nope, something else\r
+ lda comchr ; Dumb terminal. Lets test the character\r
+ cpi cr ; cr then ok\r
+ jz prtch4 ; its ok\r
+ cpi lf ; lf then ok\r
+ jz prtch4\r
+ cpi tab\r
+ jz prtch4 ; assume tabs are expanded\r
+ cpi space ; if less than 20H ignore it\r
+ rm ; return if a control character\r
+\r
+prtch4: call sysflt ; ok to print this character (in E)?\r
+ ora a\r
+ jz prtchr ; no, skip it.\r
+ lda logflg ;Get the log flag.\r
+ cpi 81H ;[pcc003] Are we logging\r
+ cz logit ;[pcc003] Do so if needed\r
+ call selcon ; select console\r
+ lda prnflg ;Get Print parallel flag\r
+ ora a\r
+ cnz outlpt ; output to printer if flag set\r
+ call outcon ; output to console.\r
+ lxi h,prtcnt ;[pcc008] point to prt fairness count\r
+ inr m ;[pcc008] bump\r
+ mov a,m ;[pcc008] get it in a\r
+ cpi prfair+1 ;[pcc008] time to be fair?\r
+ jm prtchr ;[pcc008] no, go around again.\r
+ mvi m,0 ;[pcc008] reset count\r
+ lda comchr ;[6] restore that character read from comm line\r
+ ret ;[pcc008] and return\r
+\r
+; I don't think we want to print xon/xoff - this should be\r
+; flow control only across the link between us and the host.\r
+; (besides, IBM host xon's don't make sense to most micros)\r
+; remember xon/xoff state in xofflg (zero = xon, non-zero = xoff)\r
+prtxon: xra a ;Yes, reset XOFF flag\r
+prtxof: sta xofflg\r
+ jmp prtchr ; look for another character\r
+;\f;[pcc005] Log file routines\r
+\r
+;[pcc005]\r
+; logopn - open the log file\r
+; Open the log file and append to it if it already exists\r
+; or create one if not.\r
+\r
+logopn: \r
+ mvi a,ctrlz ;[9] ignore control-z in log files\r
+ cmp e ;[9] well, was it?\r
+ rz ;[9] yes, to ignore it.\r
+ lxi h,lognam ;[pcc012] copy name\r
+ lxi d,fcb ;[pcc012] to fcb\r
+ lxi b,12 ;[pcc012] 12 bytes\r
+ call mover ;[pcc012] copy it\r
+ call appfil ;[pcc012] open file for appending\r
+ jmp logerr ;[pcc012] error\r
+ lxi h,logflg ;[pcc005] point to log flag\r
+ mvi a,80H ;[pcc005] file open flag\r
+ ora m ;[pcc005] or in contents of logflg\r
+ mov m,a ;[pcc005] and store back\r
+ lxi d,inms28 ;[pcc005] assume logging is on\r
+ cpi 81H ;[pcc005] check\r
+ jz prtstr ;[pcc005] print msg if true\r
+ lxi d,inms27 ;[pcc005] no, must be suspended\r
+ jmp prtstr ;[pcc005] print and return\r
+\r
+;\r
+; logit - output character in E to log file.\r
+; we assume the host recognizes xon/xoff. (we probably shouldn't)\r
+; modem port is selected.\r
+; preserves de\r
+; called by: prtchr\r
+\r
+logit: lxi h,chrcnt ;[pcc012] point to buffer count\r
+ dcr m ;[pcc012] and decrement\r
+ jp logit1 ;[pcc012] continue if ok\r
+ push d ;[pcc012] save de\r
+ call outadv ;[pcc012] advance buffer if in memory\r
+ call logwrt ;[pcc012] sigh, time to write to disk\r
+ pop d ;[pcc012] restore de\r
+ lda logflg ;[pcc012] get logging flag\r
+ ora a ;[pcc012] Did we quit because of an error\r
+ rz ;[pcc012] return now if so\r
+logit1: lhld bufpnt ;[pcc012] get buffer pointer\r
+ mov m,e ;Store the char.\r
+ inx h\r
+ shld bufpnt\r
+ ret ;[pcc012] and return\r
+\r
+;[pcc012]\r
+; logwrt - write to log file with XON/XOFF since it may take a while.\r
+\r
+logwrt: call sndxoff ;[7] send and xoff to host\r
+ call outbuf ;[pcc012] output the buffer and advance\r
+ call logerr ;[pcc005] quit if error\r
+ call sndxon ;[send an xon to host\r
+ ret ;[pcc012]\r
+\r
+;[pcc005]\r
+; logcls - Close the log file and reset the flag\r
+\r
+logcls: lxi d,infms6 ;[pcc005] Tell user we are closing file.\r
+ call prtstr ;[pcc005]\r
+ call clofil ;[pcc012] and do it\r
+ jmp logerr ;[pcc005] jump if error\r
+ lxi h,logflg ;[pcc005] point to flag\r
+ mov a,m ;[pcc005] get it\r
+ ani 7FH ;[pcc005] clear the open bit\r
+ mov m,a ;[pcc005] and store back\r
+ ret ;[pcc005]\r
+\r
+;[pcc005]\r
+; logerr - here on a variety of logging errors\r
+; just close the file and disable logging\r
+; called from logopn,logptr,logcls\r
+\r
+logerr: lxi d,erms22 ;[pcc005] Error message\r
+ call prtstr ;[pcc005] print it\r
+ mvi c,closf ;[pcc005] Close the file.\r
+ lxi d,fcb ;[pcc012]\r
+ call bdos ;[pcc005] \r
+ xra a ;[pcc005] clear logflg\r
+ sta logflg ;[pcc005] so don't try again\r
+ ret ;[pcc005]\r
+;\f\r
+;\r
+; VT52 emulation.\r
+; called by: prtchr\r
+; A/ contents of escflg (guaranteed non-zero)\r
+; E/ current character\r
+; modem is selected.\r
+;\r
+vt52: cpi 1 ; first character after escape?\r
+ jnz vt52y ; no, must be doing cursor positioning.\r
+;\r
+; E contains the character that followed the escape.\r
+; valid characters are:\r
+; A - cursor up\r
+; B - cursor down\r
+; C - cursor right\r
+; D - cursor left\r
+; F - enter graphics mode (hard to do on a non-vt52)\r
+; G - exit graphics mode\r
+; H - home\r
+; I - reverse linefeed\r
+; J - erase to end of screen\r
+; K - erase to end of line\r
+; Y - cursor positioning leadin\r
+; Z - identify terminal as VT52\r
+; [ - enter hold-screen mode (not supported)\r
+; \ - exit hold-screen mode (not supported)\r
+; > - enter alternate-keypad mode? (not supported)\r
+; = - exit alternate-keypad mode? (not supported)\r
+;\r
+; Invalid sequences are handled as the VT52 does - the escape and\r
+; the following character are swallowed, never to be seen again.\r
+; For <esc>E, the translation table may contain just '$' (no action),\r
+; or may be used as clear-and-home, as in the Heath/Zenith H19.\r
+;\r
+ mov a,e ; get the second character of the sequence.\r
+ cpi 'Y' ; if cursor lead-in handle it.\r
+ jnz vt52a ; if not, go on.\r
+ mvi a,2 ; state = 2: row follows.\r
+ sta escflg ; update the flag.\r
+ ret ; back for another character\r
+\r
+vt52a: cpi 'Z' ; VT52 ID query?\r
+ jz vt52id ; yes. claim to be one.\r
+ cpi 'A' ;Less than an 'A'?\r
+ jm vtig ;Yes - ignore.\r
+ cpi 'K'+1 ;Greater than 'K'?\r
+ jp vtig ;Yes - ignore.\r
+ sui 'A' ;Else make into index.\r
+ rlc ;Multiply by four.\r
+ rlc ;(Shift left twice.)\r
+ lhld pttab ;Load base addr of table.\r
+ mov e,a ;Move a into de pair.\r
+ mvi d,00H ;Zero out high byte.\r
+ dad d ;Double add index+offset.\r
+ xchg ;Exchange de with hl.\r
+ call selcon ; select console\r
+ call prtstr ;and syscall.\r
+vtig: ;Ignore escape sequence.\r
+ xra a ;Reset the ol' escape flag.\r
+ sta escflg\r
+ ret ;Return home.\r
+\r
+; here for <esc>Z. Tell the host we're a VT52. (Sure we are...)\r
+vt52id: mvi a,esc ; response is escape...\r
+ call setpar ; (need correct parity)\r
+ mov e,a\r
+ call outmdm ; (console already selected)\r
+ mvi a,'/' ; ... slash ...\r
+ call setpar ; (with parity)\r
+ mov e,a\r
+ call outmdm\r
+ mvi a,'K' ; ... K.\r
+ call setpar\r
+ mov e,a\r
+ call outmdm\r
+ jmp vtig ; clear escape-sequence flag and return.\r
+\r
+; here when escflg isn't 0 or 1 - processing cursor positioning sequence.\r
+vt52y: cpi 2 ; looking for row? (y-coordinate)\r
+ jnz vt52x ; no, must be column.\r
+ mov a,e ; yes. get coordinate\r
+ sui (' '-1) ; convert from ascii (1 = top line)\r
+ sta vtyval ; store for later\r
+ mvi a,3 ; advance to next state (x coord)\r
+ sta escflg ; store it\r
+ ret ; try for another character\r
+\r
+; here when escflag isn't 0, 1, or 2 - it must be 3. (right?)\r
+; E holds the last character of the cursor positioning sequence.\r
+vt52x: xra a ; end of escape sequence, reset state.\r
+ sta escflg\r
+ mov a,e ; get column (' ' is left margin)\r
+ sui (' '-1) ; make left margin be one\r
+ mov c,a ; stash column in c\r
+ lda vtyval ; get row number\r
+ mov b,a ; in b\r
+ call selcon ; select console\r
+ call csrpos ; call system-dependent cursor positioner\r
+ ret ; all through.\r
+;\f\r
+;\r
+; conchr - copy character from console to comm line, processing\r
+; (kermit's) escape sequences.\r
+; Enter and exit with console selected.\r
+; nonskip return: transparent mode terminated.\r
+; skip return: still in transparent mode.\r
+; called by: rexmit, telnet\r
+\r
+conchr: call inpcon ;Try to get a character from the console\r
+ ani 07FH ;Keep only 7 bits\r
+ jz rskp ;Null means nothing there.\r
+ mov e,a ;Move the char for comparison.\r
+ sta lstchr ;Save it\r
+ lda escchr ;Get the escape char.\r
+ cmp e ;Is it an escape char?\r
+ jz intchr ;If so go process it.\r
+ call selmdm ; select the modem\r
+ mov a,e ;Get the char.\r
+ call setpar ;Set parity (if any).\r
+ mov e,a ;Restore it.\r
+ push d ; need to save e in case we are half dplx [5]\r
+ call outmdm ;Output the char to the port.\r
+ pop d ; Just in case we are half dplx [5]\r
+ call selcon ; reselect console\r
+ lda ecoflg ;Get the echo flag.\r
+ ora a ;Is it turned on?\r
+ jz rskp ;If not we're done here.\r
+ mov a,e ;Get the char.\r
+ ani 7FH ;Turn off the parity bit.\r
+ mov e,a\r
+ call outcon ; echo the character.\r
+ jmp rskp ; use skip return\r
+;\f\r
+; transparent escape character has been typed. dispatch on second\r
+; character. (console is still selected)\r
+; here from: conchr\r
+\r
+intchr: call inpcon ; get another character from the console\r
+ ora a ; zero means no character available yet.\r
+ jz intchr ; If so, loop until we get a char.\r
+ mov b,a ;Save the actual char.\r
+ cpi ctrlc ;is it Control-C?\r
+ jz contc ;yes\r
+ ani 137O ;Convert to upper case.\r
+ cpi 'C' ;Is it close?\r
+ jnz intch0 ;If not proceed.\r
+contc: lxi d,infms9 ;Say we are back.\r
+ call prtstr\r
+ call syscls ; call system-dependent close routine\r
+ lda logflg ;Get the log flag.\r
+ ora a ;[pcc005] Check if open\r
+ cm logcls ;[pcc005] Close if needed\r
+ ret\r
+\r
+;Here if not a 'C' or '^C'\r
+\r
+intch0: cpi 'S' ;Is it status?\r
+ jnz inch01 ;If not, proceed.\r
+ call stat01 ;Print out the status stuff.\r
+ call prcrlf ;[pcc011] add a crlf\r
+ jmp rskp ;return from conchr\r
+\r
+inch01:\r
+inch03: mov a,b ;Get the char.\r
+ cpi '?' ;Is it a help request?\r
+ jnz intch1 ;If not, go to the next check.\r
+inch3a: lda logflg ;[pcc003] Logging flag\r
+ ora a ;[pcc003] see if active\r
+ jp inch04 ;[pcc005] jump if no file open\r
+ lxi d,loghlp ;[pcc003] yes, tell about R AND Q\r
+ call prtstr ;[pcc003]\r
+inch04: lxi d,inthlp ;If so, get the address of the help message.\r
+ call prtstr\r
+ call sysinh ; print system-dependent help message\r
+ lxi d,inhlp1 ; Tell about doubling the escape character\r
+ call prtstr\r
+ call escpr ;Print escape character\r
+ lxi d,inhlp2 ;Print the rest\r
+ call prtstr\r
+ jmp intchr ;Get another char.\r
+\r
+intch1: mov a,b ;Get the character.\r
+ cpi '0' ;Is it '0', to send a null?\r
+ jnz intch3 ;No.\r
+ xra a ;Yes, send an ASCII zero.\r
+ call setpar ; with the correct parity\r
+ mov e,a\r
+ call selmdm ; (to the modem...)\r
+ call outmdm\r
+ call selcon ; return with console selected\r
+ jmp rskp\r
+\r
+intch3: lda escchr ;Get the escape char.\r
+ cmp b ;Is it the escape char?\r
+ jnz intch4 ;[pcc002] jump if not\r
+ mov a,b ;Get the char.\r
+ call setpar\r
+ mov e,a ;Restore it.\r
+ call selmdm\r
+ call outmdm ;Output it.\r
+ call selcon ;We promised console would be selected...\r
+ jmp rskp ;Return, we are done here.\r
+intch4: mov a,b ;[pcc002] get it again\r
+ ani 137o ;[pcc002] in upper case\r
+ cpi 'P' ;[pcc002] toggle printer?\r
+ jnz intch5 ;[pcc003] nope\r
+ lda prnflg ;[pcc002] get printer flag\r
+ xri 01h ;[pcc002] complement it\r
+ sta prnflg ;[pcc002] and put back\r
+ jmp rskp ;[pcc002]\r
+intch5: lda logflg ;[pcc003] get log flag\r
+ ora a ;[pcc003] See if open\r
+ jp intch7 ;[pcc003] no, skip R and Q\r
+ mov a,b ;[pcc003] get back chr\r
+ ani 137o ;[pcc003] make upper case\r
+ cpi 'R' ;[pcc003] Is it R\r
+ jnz intch6 ;[pcc003] Jump if not\r
+ mvi a,81H ;[pcc003] set flag for logging\r
+ sta logflg ;[pcc003] put it back\r
+ lxi d,inms28 ;[pcc003] message\r
+ call prtstr ;[pcc003]\r
+ jmp rskp ;[pcc003] done\r
+intch6: cpi 'Q' ;[pcc003] Quit logging?\r
+ jnz intch7 ;[pcc003] no\r
+ mvi a,82H ;[pcc003] flag for open, but suspended\r
+ sta logflg ;[pcc003] store away\r
+ lxi d,inms27 ;[pcc003] keep them informed\r
+ call prtstr ;[pcc003]\r
+ jmp rskp ;[pcc003]\r
+intch7: ;[pcc003]\r
+\r
+intchz: mov a,b ; not recognized. get saved copy back.\r
+ push psw ;[8] save as we will want to test for 'D'\r
+ call sysint ; interpret system-dependent sequences\r
+ jmp intchy ; done. [10] Now see if D. If so, do a C.\r
+ pop psw ;[10] tidy stack\r
+ mvi e,'G'-100O ;Otherwise send a beep.\r
+ call outcon ; to the console.\r
+ jmp rskp\r
+\r
+intchy: pop psw ;[10] adjust stack\r
+ ani 5fh ;[10] strip parity, make it upper case\r
+ cpi 'D' ;[10] was it a D?\r
+ jz contc ;[10] yup, so to the equivalent of an escape-C\r
+ jmp rskp\r
+;\f\r
+; Little code to allow some expansion of code without changing\r
+; every futher address, only up to the end of this file.\r
+; TO BE REMOVED FOR RELEASE!\r
+\r
+; org ($+100h) AND 0FF00H\r
+IF lasm\r
+ LINK CPSCPM\r
+ENDIF;lasm\r