name msxgen ; File MSXGEN.ASM include mssdef.h ; Copyright (C) 1982,1991, Trustees of Columbia University in the ; City of New York. Permission is granted to any individual or ; institution to use, copy, or redistribute this software as long as ; it is not sold for profit and this copyright notice is retained. ; Generic MS DOS Kermit module, does i/o via DOS calls. ; Use with file MSUGEN.ASM (Generic keyboard translator) ; Edit history ; 8 Sept 1991 version 3.11 ; Last edit 8 Sept 1991 ; ; Note: the biggest difficulty using this Generic Kermit is loss of one ; or two incoming characters when the screen must scroll. IBM PC's and ; relatives do this. If possible, replace the DOS screen write with faster ; calls specific to your system. Port i/o is polled through DOS. public serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel public ctlu, cmblnk, locate, lclini, prtchr, baudst, clearl public getbaud, beep, trnprs, pcwait, termtb, trnmod, setnbios public count, xofsnt, puthlp, putmod, clrmod, poscur public sendbr, sendbl, term, machnam, setktab, setkhlp, showkey public ihosts, ihostr, dtrlow, serhng, dumpscr, comptab public chrout, cstatus, cquit, cquery, chang ; kbd action verbs public snull, kdos, klogof, klogon, shomodem, getmodem, mdmhand public portval, bdtab, setchtab, extmacro, vtmacname, vtmaclen public fcsrtype, parmsk, flowon, flowoff, peekcom public sescur, sesdisp false equ 0 true equ 1 instat equ 6 prtscr equ 1 ; screen printing active data segment extrn flags:byte, trans:byte, comand:byte, dmpname:byte extrn npages:word, kbdflg:byte, rxtable:byte, rdbuf:byte extrn prnhand:word, taklev:byte, takadr:word, mcctab:byte extrn param:word, nparam:word machnam db 'Generic$' erms41 db cr,lf,'?Warning: Cannot open COM port$' erms50 db cr,lf,'Error reading from device$' hnd1 db cr,lf,'Enter a file handle. Check your DOS manual if you are ' db cr,lf,'not certain what value to supply (generally 3).$' hnd2 db 'Handle: ',0 hnderr db cr,lf,'Warning: Handle not known.' deverr db cr,lf,'Any routine using the communications port will' db cr,lf,'probably not work.$' hndhlp db cr,lf,'A one or two digit file handle $' devhlp db cr,lf,'Name for your systems auxillary port $' badbd db cr,lf,'Unimplemented baud rate$' noimp db cr,lf,'Command not implemented.$' hngmsg db cr,lf,' The phone should have hungup.',cr,lf,'$' hnghlp db cr,lf,' The modem control lines DTR and RTS for the current' db ' port are forced low (off)' db cr,lf,' to hangup the phone. Normally, Kermit leaves them' db ' high (on) when it exits.' db cr,lf,'$' msmsg1 db cr,lf,' Communications port is not ready.$' msmsg2 db cr,lf,' Communications port is ready.$' shkmsg db 'Not implemented' shklen equ $-shkmsg setktab db 0 setkhlp db 0 anspflg db 0 ; printing active status vtmacname dw 0 ; pointer to selected macro name vtmaclen dw 0 sescur dw 0 crlf db cr,lf,'$' delstr db BS,BS,' ',BS,BS,'$' ; Delete string ; If delete code moves cursor then BS over code, BS over bad char, space ; over both to erase from screen, BS twice to restore cursor position. argadr dw ? ; address of arg blk from msster.asm parmsk db 0ffh ; 8/7 bit parity mask, for reception flowoff db 0 ; flow-off char, Xoff or null (if no flow) flowon db 0 ; flow-on char, Xon or null captrtn dw 0 ; routine to call for captured output xofsnt db 0 ; Say if we sent an XOFF xofrcv db 0 ; Say if we received an XOFF count dw 0 ; Number of chars in int buffer fairness dw 0 mdmhand db 0 ; Modem status register, current prthnd dw 0 ; Port handle prttab dw com1,com2 com1 db 'COM1',0 com2 db 'COM2',0 temp dw 0 prtstr db 20 dup(0) ; Name of auxiliary device portmax equ 4 ; number of predefined ports port1 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon> port2 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon> port3 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon> port4 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon> rept portmax-4 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon> endm portval dw port1 ; Default is to use port 1 ; Entries for choosing communications port comptab db 6 ; Number of options mkeyw '1',1 mkeyw '2',2 mkeyw 'COM1',1 mkeyw 'COM2',2 mkeyw 'Device',3 mkeyw 'File-handle',4 setchtab db 1 ; Set File Character-Set table mkeyw 'CP437',437 ; hardware default Code Page bdtab db 0 ; baud rate table, number of entries ourarg termarg <> termtb db tttypes ; entries for Status, not Set mkeyw 'Heath-19',ttheath mkeyw 'none',ttgenrc mkeyw 'Tek4014',tttek mkeyw 'VT102',ttvt100 mkeyw 'VT52',ttvt52 oldsp dw 0 ; offset to longjmp to for i/o failure endconptr dw offset endcon,seg endcon ; FAR pointer vtmacroptr dw offset vtmacro,seg vtmacro ; FAR pointer data ends code1 segment ; Control text cursor. AL = 0 for off, 1 for on (nominally underline) fcsrtype proc far ret ; can't do this from DOS fcsrtype endp code1 ends code segment extrn comnd:near, dopar:near, atoi:near, prompt:near extrn msuinit:near, keybd:near, pntchr:near, pntflsh:near extrn dec2di:near assume cs:code, ds:data, es:nothing ; Clear the input buffer. This throws away all the characters in the ; serial interrupt buffer. This is particularly important when ; talking to servers, since NAKs can accumulate in the buffer. ; Do nothing since we are not interrupt driven. Returns normally. CLRBUF PROC NEAR cmp prthnd,0 ; got a port handle yet? jne clrbu1 ; ne = yes ret ; else just return clrbu1: call prtchr ; read from comms port jnc clrbu1 ; nc = char available ret ; no data CLRBUF ENDP ; Clear to the end of the current line. Returns normally. CLEARL PROC NEAR push ax push dx mov ah,prstr mov dx,offset crlf int dos pop dx pop ax ret CLEARL ENDP shomodem proc near mov ah,cmeol ; get a confirm call comnd jc shmodx ; c = no confirm cmp prthnd,0 ; got a handle yet? jne shmod0 ; ne = yes, just go on call opnprt ; else 'open' the port shmod0: mov dx,offset msmsg1 ; say port is not ready mov bx,prthnd mov al,7 ; output status command mov ah,ioctl ; ask DOS to look for us int dos jc shmod1 ; c = call failed, device not ready or al,al jz shmod1 ; z = not ready mov dx,offset msmsg2 ; say port is ready shmod1: mov ah,prstr int dos clc shmodx: ret shomodem endp getmodem proc near mov al,0 clc ret getmodem endp ; Put the char in AH to the serial port. This assumes the port has been ; initialized. Returns carry clear if success, else carry set if the ; character cannot be written. OUTCHR PROC NEAR push cx ; save regs or ah,ah ; sending a null? jz outch2 ; z = yes xor cx,cx ; clear counter cmp ah,flowoff ; sending xoff? jne outch1 ; ne = no mov xofsnt,false ; supress xon from chkxon buffer routine outch1: cmp xofrcv,true ; are we being held? jne outch2 ; ne = no, it's OK to go on loop outch1 ; held, try for a while mov xofrcv,false ; timed out, force it off and fall thru outch2: push dx ; save register mov al,ah ; parity routine works on AL call dopar ; set parity appropriately mov byte ptr temp,al ; put data there cmp prthnd,0 ; got a handle yet? jne outch3 ; ne = yes call opnprt ; else 'open' the port outch3: push bx mov bx,prthnd ; port handle mov cx,1 ; one byte to write mov dx,offset temp ; place where data will be found mov ah,write2 ; write to file/device int dos pop bx pop dx pop cx clc ret OUTCHR ENDP ; This routine blanks the screen. Returns normally. CMBLNK PROC NEAR push ax ; save some registers push dx mov ah,prstr mov dx,offset crlf ; carriage return plus line feed pop dx pop ax ret CMBLNK ENDP ; Homes the cursor. Returns normally. LOCATE PROC NEAR mov dx,0 ; Go to top left corner of screen jmp poscur LOCATE ENDP ; Write a line at the bottom of the screen ; the line is passed in dx, terminated by a $. Returns normally. putmod proc near push dx ; preserve message mov dx,1800h ; now address line 24 call poscur pop dx ; get message back mov ah,prstr int dos ; write it out ret ; and return putmod endp ; clear the mode line written by putmod. Returns normally. clrmod proc near mov dx,1800h call poscur ; Go to bottom row call clearl ; Clear to end of line ret clrmod endp ; Put a help message on the screen. ; Pass the message in ax, terminated by a null. Returns normally. puthlp proc near push dx ; save regs push si push ax ; preserve this mov ah,prstr mov dx,offset crlf int dos pop si ; point to string again cld puthl3: lodsb ; get a byte cmp al,0 ; end of string? je puthl4 ; yes, stop mov dl,al mov ah,dconio int dos ; else write to screen jmp puthl3 ; and keep going puthl4: mov ah,prstr mov dx,offset crlf int dos pop si pop dx ret puthlp endp ; Set the baud rate for the current port, based on the value ; in the portinfo structure. Returns normally. BAUDST PROC NEAR mov ah,prstr mov dx,offset noimp ; Say it's not implemented int dos push bx ; save reg mov bx,portval mov [bx].baud,0FFFFH ; So it's not a recognized value pop bx ret BAUDST ENDP ; Get the current baud rate from the serial card and set it ; in the portinfo structure for the current port. Returns normally. ; This is used during initialization. GETBAUD PROC NEAR stc ret ; Can't do this GETBAUD ENDP ; Use for DOS 2.0 and above. Check the port status. If no data, return ; carry set; else read a char into AL and return carry clear. ; Note added by [jrd]: The test for char-at-input-port is int 21h function ; 44h (ioctl) sub function 6 (get input status). On many systems an FFH will ; be reported (meaning Ready) even though no char is available; the Ready ; indication is misleading. In such cases the system will wait for a char ; and will appear to be hung. A preferrable method is to use the ROM Bios ; call int 14H function 3 (get port status) and if the lsb of the returned ; 8 bits in AH is 1 then a char is availble at the port; this assumes that ; the machine emulates this ROM Bios operation. ; Lastly, if the current code is used and the system hangs then reboot ; and say ECHO Hello >COM1 before running Kermit; this should make MSDOS ; truely aware of the port's actual status. Dark grey magic. Good luck! [jrd] PRTCHR PROC NEAR push bx push cx cmp prthnd,0 ; got a handle yet? jne prtch0 ; ne = yes call opnprt ; else 'open' the port prtch0: call chkxon mov bx,prthnd mov al,instat ; input status command mov ah,ioctl ; see note above int dos jc prtch4 ; c = call failed, device not ready or al,al jz prtch4 ; not ready mov bx,prthnd ; the file handle mov ah,readf2 ; read file/device mov cx,1 ; want just one character mov dx,offset rdbuf ; where to store it int dos jnc prtch1 ; nc = no error cmp al,5 ; Error condition je prt3x cmp al,6 ; Error condition je prt3x jmp prtch4 ; else report no char present prtch1: mov dx,ax ; needed to obey rules or ax,ax ; reading from end of file? jz prtch4 ; z = yes mov al,rdbuf ; recover char prtch3: pop cx pop bx clc ret ; return success (char is in al) prt3x: mov ah,prstr mov dx,offset erms50 int dos prtch4: pop cx pop bx stc ; no chars ret PRTCHR ENDP ; Examine incoming communications stream for a packet SOP character. ; Return CX= count of bytes starting at the SOP character (includes SOP) ; and carry clear. Return CX = 0 and carry set if SOP is not present. ; Destroys AL. peekcom proc far xor cx,cx ; return count of zero stc ; say no data ret peekcom endp ; Local routine to see if we have to transmit an xon chkxon proc near push bx mov bx,portval cmp [bx].floflg,0 ; doing flow control? je chkxo1 ; no, skip all this cmp xofsnt,false ; have we sent an xoff? je chkxo1 ; no, forget it mov ax,[bx].flowc ; ah gets xon call outchr ; send it mov xofsnt,false ; remember we've sent the xon chkxo1: pop bx ; restore register ret ; and return chkxon endp ; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the ; cycle of clear input buffer, wait 1 second, test if buffer empty then exit ; else repeat cycle. Requires that the port be initialized before hand. ; Ihosts is used by the local send-file routine just after initializing ; the serial port. ; 22 March 1986 [jrd] IHOSTS PROC NEAR push ax ; save the registers push bx push cx push dx mov bx,portval ; port indicator mov ax,[bx].flowc ; put Go-ahead flow control char in ah or ah,ah ; don't send null if flow = none jz ihosts1 ; z = null call outchr ; send it (release Host's output queue) ihosts1:call clrbuf ; clear out interrupt buffer call prtchr ; check for char at port jnc ihosts1 ; nc=have a char in al, repeat wait/read cycle pop dx ; empty buffer. we are done here pop cx pop bx pop ax ret IHOSTS ENDP ; IHOSTR - initialize the remote host for our reception of a file by ; sending the flow-on character (XON typically) to release any held ; data. Called by receive-file code just after initializing the serial ; port. 22 March 1986 [jrd] IHOSTR PROC NEAR push ax ; save regs push bx push cx mov bx,portval ; port indicator mov ax,[bx].flowc ; put Go-ahead flow control char in ah or ah,ah ; don't send null if flow = null jz ihostr1 ; z = null call outchr ; send it (release Host's output queue) ihostr1:pop cx pop bx pop ax ret IHOSTR ENDP DTRLOW PROC NEAR ; Global proc to Hangup the Phone by making ; DTR and RTS low mov ah,cmline ; allow text to be able to display help mov bx,offset rdbuf ; dummy buffer mov dx,offset hnghlp ; help message call comnd ; get a confirm jc dtrlowx ; not yet imp. call serhng ; drop DTR and RTS mov ah,prstr ; give a nice message ; not yet imp. mov dx,offset hngmsg mov dx,offset noimp ; for now int dos clc dtrlowx:ret DTRLOW ENDP ; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low ; to terminate the connection. 29 March 1986 [jrd] ; Calling this twice without intervening calls to serini should be harmless. ; Returns normally. ; SERHNG is Not Yet Implemented. SERHNG PROC NEAR clc ret SERHNG ENDP ; Wait for the # of milliseconds in ax, for non-IBM compatibles. ; Based on 4.77 Mhz 8088 processor speeds. ; Thanks to Bernie Eiben for this one. pcwait proc near mov cx,240 ; inner loop counter for 1 millisecond pcwai1: sub cx,1 ; inner loop takes 20 clock cycles jnz pcwai1 dec ax ; outer loop counter jnz pcwait ; wait another millisecond ret pcwait endp ; Send a break out the current serial port. Returns normally. SENDBR PROC NEAR ; Normal Break clc ret SENDBR ENDP SENDBL PROC NEAR ; Long Break clc ret SENDBL ENDP ; Position the cursor according to contents of DX: ; DH contains row, DL contains column. Returns normally. POSCUR PROC NEAR clc ret POSCUR ENDP ; Delete a character from the terminal. This works by printing ; backspaces and spaces. Returns normally. DODEL PROC NEAR mov ah,prstr mov dx,offset delstr ; Erase character int dos ret DODEL ENDP ; Move the cursor to the left margin, then clear to end of line. ; Returns normally. CTLU PROC NEAR push ax push cx push dx mov ah,conout mov dl,cr ; cursor to left margin int dos mov cx,79 mov dl,' ' ; send 79 spaces to clear line ctlu1: int dos loop ctlu1 mov dl,cr ; cursor to left margin again int dos pop dx pop cx pop ax ret CTLU ENDP ; Set the current port. COMS PROC NEAR mov dx,offset comptab ; the table to examine xor bx,bx ; use keywords as help mov ah,cmkey ; parse keyword from comptab call comnd jc comsx ; c = no match cmp bl,3 ; set device name? je coms3 ; e = yes, go get name jbe coms1a ; be = 1 or 2 jmp coms4 ; a = pick up file handle coms1a: push bx mov ah,cmeol call comnd pop bx jc comsx ; failure mov flags.comflg,bl ; set the comm port flag cmp bl,1 ; using Com 1? jne coms2 ; ne = no mov portval,offset port1 ret coms2: cmp flags.comflg,2 ; using Com2? jne coms3 ; ne = no mov portval,offset port2 clc comsx: ret coms3: mov ah,cmword ; parse string, returns asciiz string mov dx,offset prtstr ; put name here mov bx,offset devhlp ; help message if question mark call comnd jc comsx ; c = error mov ah,cmeol call comnd jc comsx mov dx,offset prtstr ; point to string mov ah,open2 ; open port as a file mov al,2 ; for reading and writing int dos jc coms31 ; c = failure mov portval,offset port3 ; port info structure mov flags.comflg,3 ; set port ident jmp short coms32 ; success coms31: mov ah,prstr mov dx,offset erms41 int dos mov dx,offset deverr int dos clc ret coms32: mov prthnd,ax ; save handle mov ah,ioctl mov al,00h ; get device info xor dx,dx mov bx,prthnd ; port's handle int dos jc coms41 ; c = error or dl,20h ; set binary mode in device info mov dh,0 mov ah,ioctl mov al,01h ; set device info int dos jc coms41 ; c = error ret coms4: mov ah,cmword mov dx,offset rdbuf ; where to put input mov bx,offset hndhlp ; in case user wants help call comnd jc coms42 push ax mov ah,cmeol call comnd pop ax jc coms42 ; failure mov si,offset rdbuf call atoi ; convert to real number in ax jc coms42 ; c = failure mov portval,offset port4 ; port info structure mov flags.comflg,4 ; set port ident jmp coms32 ; go complete processing coms41: mov ah,prstr ; else, issue a warning mov dx,offset hnderr int dos clc coms42: ret COMS ENDP ; Set heath emulation on/off. VTS PROC NEAR jmp notimp ; not implemented VTS ENDP VTSTAT PROC NEAR ; for Status display ret ; no emulator status to display VTSTAT ENDP ; Save the screen to a buffer and then append buffer to a disk file. [jrd] ; Default filename is Kermit.scn; actual file can be a device too. Filename ; is determined by mssset and is passed as pointer dmpname. DUMPSCR PROC NEAR ; Dumps screen contents to a file. Just Beeps here call beep clc ret DUMPSCR ENDP notimp: mov ah,prstr mov dx,offset noimp int dos stc ret ; Initialize variables to values used by the generic MS DOS version. lclini: mov flags.vtflg,0 ; don't do terminal emulation mov prthnd,0 ; no handle yet mov flags.remflg,dserial ; set serial display mode ;; call opnprt ; get file handle for comm port call msuinit ; declare keyboard translator present ret ; Get a file handle for the communications port. Use DOS call to get the ; next available handle. If it fails, ask user what value to use (there ; should be a predefined handle for the port, generally 3). The open ; will fail if the system uses names other than "COM1" or "COM2". opnprt: mov al,flags.comflg dec al ; com1 is 1, com2 is 2, etc xor ah,ah push si mov si,ax shl si,1 ; double index mov dx,prttab[si] ; table of port names pop si mov ah,open2 ; open file/device mov al,2 ; for reading/writing int dos jnc opnpr2 ; nc = no error so far mov ah,prstr ; It didn't like the string mov dx,offset erms41 int dos mov dx,offset hnd1 int dos mov dx,offset hnd2 ; ask user for the handle call prompt mov ah,cmline mov bx,offset rdbuf ; where to put input mov dx,offset hndhlp ; in case user wants help call comnd jc opnpr1 ; c = error mov si,offset rdbuf xchg ah,al ; count to ah call atoi ; convert to real number jc opnpr1 ; c = error mov prthnd,ax ; value returned in AX clc ; carry clear for success opnpr1: ret opnpr2: mov prthnd,ax ; call succeeded mov ah,ioctl mov al,00h ; get device info xor dx,dx mov bx,prthnd ; port's handle int dos or dl,20h ; set binary mode in device info mov dh,0 mov ah,ioctl mov al,1 ; set device info int dos clc ret ; carry clear for success showkey:mov ax,offset shkmsg mov cx,shklen ret ; Initialization for using serial port. Returns normally. ; Attempts to put port device in binary mode. [jrd] SERINI PROC NEAR cmp prthnd,0 ; got a handle yet? jne serin0 ; ne = yes, just go on push bx call opnprt ; else 'open' the port pop bx jc serin2 ; c = failure serin0: push bx mov bx,portval ; get port mov parmsk,0ffh ; parity mask, assume parity is None cmp [bx].parflg,parnon ; is it None? je serin1 ; e = yes mov parmsk,07fh ; no, pass lower 7 bits as data serin1: mov bx,[bx].flowc ; get flow control chars mov flowoff,bl ; xoff or null mov flowon,bh ; xon or null pop bx clc ; carry clear for success serin2: ret SERINI ENDP ; Reset the serial port. This is the opposite of serini. Calling ; this twice without intervening calls to serini should be harmless. ; Returns normally. SERRST PROC NEAR clc ret SERRST ENDP ; Produce a short beep. The PC DOS bell is long enough to cause a loss ; of data at the port. Returns normally. BEEP PROC NEAR mov dl,bell mov ah,dconio int dos clc ret BEEP ENDP ; Dumb terminal emulator. Doesn't work too well above 1200 baud (and ; even at 1200 baud you sometimes lose the first one or two characters ; on a line). Does capture (logging), local echo, debug display, tests ; for printer/logging device not ready. Uses keyboard translator ; 20 March 1987 [jrd]. term proc near mov argadr,ax ; save argument ptr mov si,ax ; this is source mov oldsp,sp ; remember stack for i/o failure, mov di,offset ourarg ; place to store arguments mov ax,ds mov es,ax ; address destination segment mov cx,size termarg cld rep movsb ; copy into our arg blk mov ax,ourarg.captr mov captrtn,ax ; buffer capture routine mov parmsk,0ffh ; parity mask, assume parity = None cmp ourarg.parity,parnon ; is parity None? je term1 ; e = yes, keep all 8 bits mov parmsk,07fh ; else keep lower 7 bits term1: call portchr ; get char from port, apply parity mask jnc short term3 ; nc = char term2: mov fairness,0 ; say kbd was examined call keybd ; call keyboard translator in msu jnc term1 ; nc = no char or have processed it call pntflsh ; flush printer buffer stc ret ; carry set = quit connect mode term3: and al,parmsk ; apply 8/7 bit parity mask call outtty ; print on terminal inc fairness ; say read port but not kbd, again cmp fairness,200 ; this many port reads before kbd? jb term1 ; b = no, read port again call pntflsh ; flush printer buffer jmp short term2 ; yes, let user have a chance too quit: ret term endp ; keyboard translator action routines, system dependent, called from msugen. ; These are invoked by a jump instruction. Return carry clear for normal ; processing, return carry set exit Connect mode (kbdflg has transfer char). chrout: call outprt ; put char in al to serial port clc ; stay in Connect mode ret trnprs: push ax ; toggle Copy screen to printer test anspflg,prtscr ; should we be printing? jnz trnpr2 ; nz = yes, its on and going off mov ah,ioctl mov al,7 ; get output status of printer push bx mov bx,prnhand ; file handle for system printer int dos pop bx jc trnpr1 ; c = printer not ready cmp al,0ffh ; Ready status? je trnpr2 ; e = Ready trnpr1: call beep ; Not Ready, complain jmp short trnpr3 ; and ignore request trnpr2: xor anspflg,prtscr ; toggle print flag trnpr3: pop ax clc ret ; toggle Connect mode status line trnmod proc near ret trnmod endp klogon proc near ; resume logging (if any) test flags.capflg,logses ; session logging enabled? jz klogn ; z = no, forget it or ourarg.flgs,capt ; turn on capture flag klogn: clc ret klogon endp klogof proc near ; suspend logging (if any) and ourarg.flgs,not capt ; stop capturing klogo: clc ret klogof endp snull: mov ah,0 ; send a null call outchr ; send without echo or logging clc ret kdos: mov al,'P' ; Push to DOS jmp short cmdcom cstatus:mov al,'S' ; these commands exit Connect mode jmp short cmdcom cquit: mov al,'C' jmp short cmdcom cquery: mov al,'?' jmp short cmdcom chang: mov al,'H' ; Hangup, drop DTR & RTS ;;; jmp short cmdcom cmdcom: mov kbdflg,al ; pass char to msster.asm via kbdflg stc ; say exit Connect mode ret ;; end of action routines ; put the character in al to the screen, do capture and printing, ; does translation for Set Input command. ; Adapted from msyibm.asm outtty proc near test flags.remflg,d8bit ; keep 8 bits for displays? jnz outnp8 ; nz = yes, 8 bits if possible and al,7fh ; remove high bit outnp8: cmp rxtable+256,0 ; is translation off? je outnp7 ; e = yes, off push bx ; Translate incoming char mov bx,offset rxtable ; address of translate table xlatb ; new char is in al pop bx outnp7: test ourarg.flgs,capt ; capturing output? Can be shut off jz outnoc ; no, forget this part call captrtn ; give it captured character outnoc: test anspflg,prtscr ; should we be printing? jz outnop ; no, keep going call pntchr ; queue char for printer jnc outnop ; nc = successful print push ax call beep ; else make a noise and call trnprs ; turn off printing pop ax outnop: cmp flags.vtflg,0 ; emulating a terminal? jnz outnop1 ; nz = yup, go do something smart test ourarg.flgs,trnctl ; debug? if so use dos tty mode jz outnp4 ; z = no mov ah,conout cmp al,7fh ; Ascii Del char or greater? jb outnp1 ; b = no je outnp0 ; e = Del char push ax ; save the char mov dl,7eh ; output a tilde for 8th bit int dos pop ax ; restore char and al,7fh ; strip high bit outnp0: cmp al,7fh ; is char now a DEL? jne outnp1 ; ne = no and al,3fH ; strip next highest bit (Del --> '?') jmp outnp2 ; send, preceded by caret outnp1: cmp al,' ' ; control char? jae outnp3 ; ae = no add al,'A'-1 ; make visible outnp2: push ax ; save char mov dl,5eh ; caret int dos ; display it pop ax ; recover the non-printable char outnp3: mov dl,al int dos ret outnp4: cmp al,bell ; bell (Control G)? jne outnp5 ; ne = no jmp beep ; use short beep, avoid char loss outnop1: outnp5: test flags.remflg,d8bit ; keep 8 bits for displays? jnz outnp9 ; nz = yes, 8 bits if possible and al,7fh ; remove high bit outnp9: mov ah,conout ; dostty screen mode mov dl,al ; write without intervention int dos ; else let dos display char ret ; and return outtty endp ; send the character in al out to the serial port; handle echoing. ; Can send an 8 bit char while displaying only 7 bits locally. outprt proc near test ourarg.flgs,lclecho ; echoing? jz outpr1 ; z = no, forget it push ax ; save char call outtty ; print it pop ax ; restore outpr1: mov ah,al ; outchr expects char in ah jmp outchr ; output to the port outprt endp ; Get a char from the serial port manager, return it in al ; returns with carry clear if a character is available, else carry set portchr proc near call prtchr ; character at port? jnc portc1 ; nc = yes portc0: stc ; carry -> no character ret portc1: and al,parmsk ; apply 8/7 bit parity mask or al,al ; catch nulls jz portc0 ; z = null, ignore it cmp al,del ; catch dels je portc0 ; e = del, ignore it portc2: clc ; have a character, in AL ret portchr endp ; Invoked by keyboard translator when an unknown keyboard verb is used as ; a string definition, such as {\ktest}. Enter with vtmacname pointing to ; uppercased verb name, asciiz, and vtmaclen set to its length. extmacro proc near call dword ptr vtmacroptr ; FAR pointer ret extmacro endp fdec2di proc far call dec2di ret fdec2di endp code ends code1 segment assume cs:code1 ; ; Reference Macro structure for db number of entries (mac names) ; is file table mcctab |-> dw length of macroname ; mssset.asm each entry |-> db 'macroname' ; where these |-> dw segment:0 of definition string ; are stored. (offset part is always 0) ; Definition string in db length of ; buffer macbuf db 'string with trailing null' ; vtmacro proc far ; common code for external macro push bx push cx push si push di push es mov ax,ds mov es,ax mov di,offset rdbuf+2 ; macro def buffer starts here mov si,vtmacname ; pointer to macro name mov cx,vtmaclen ; length of macro nametext mov [di-2],cx ; counted string field cld rep movsb ; copy to rdbuf mov byte ptr [di],0 ; null terminator mov si,offset rdbuf+2 ; look for name-text separator mov cx,vtmaclen vtmac1: lodsb cmp al,' ' ; space separator? je vtmac1a ; e = yes, stop here or al,al ; null terminator? jz vtmac1a ; e = yes, stop here loop vtmac1 inc si ; to do null length correctly vtmac1a:sub si,offset rdbuf+2+1 ; compute length of macro name mov cx,si mov vtmaclen,cx ; save a macro name length ; check for existence of macro mov bx,offset mcctab ; table of macro names mov cl,[bx] ; number of names in table xor ch,ch jcxz vtmacx ; z = empty table, do nothing inc bx ; point to length of first name vtmac2: mov ax,[bx] ; length of this name cmp ax,vtmaclen ; length same as desired keyword? jne vtmac3 ; ne = no, search again mov si,bx add si,2 ; point at first char of name push cx ; save name counter push di ; save reg mov cx,vtmaclen ; length of name mov di,vtmacname ; point at desired macro name push es ; save reg push ds pop es ; make es use data segment cld repe cmpsb ; match strings pop es ; need current si below pop cx pop di ; recover saved regs je vtmac4 ; e = matched vtmac3: add bx,ax ; step to next name, add name length add bx,4 ; + count and def word ptr loop vtmac2 ; try next name vtmacx: pop es pop di pop si ; no macro, return to Connect mode pop cx pop bx ret vtmac4: cmp taklev,maxtak ; room in Take level? jge vtmacx ; ge = no, exit with no action inc taklev ; increment take level add takadr,size takinfo ; make a new Take entry/macro mov bx,takadr ; point to current macro structure mov ax,ds ; segment of rdbuf mov [bx].takbuf,ax ; segment of definition string struc mov cx,word ptr rdbuf ; length of count + string mov [bx].takcnt,cx ; number of chars in definition mov [bx].takargc,0 ; our argument count mov [bx].takptr,offset rdbuf+2 ; where to read next command char mov [bx].taktyp,0ffh ; flag as a macro pop es pop di pop si pop cx pop bx jmp dword ptr endconptr ; exit Connect mode vtmacro endp code1 ends code segment assume cs:code ; Error recovery routine used when outchr reports unable to send character ; or when vtmacro requests exiting Connect mode. ; Exit Connect mode cleanly, despite layers of intermediate calls. endcon proc near mov kbdflg,'C' ; report 'C' to TERM's caller mov sp,oldsp ; recover startup stack pointer ; TERM caller's return address is now ; on the top of stack. A longjmp. jmp quit ; exit Connect mode cleanly endcon endp ; Service SET NETBIOS-NAME name command at Kermit prompt level setnbios proc near ret setnbios endp sesdisp proc near ret sesdisp endp code ends end