NAME mssser ; File MSSSER.ASM ; Edit history: ; Last edit: 1 Jan 1988 ; 1 Jan 1988 version 2.30 ; 26 Dec 1987 Telescope Bye, Fin, Logout commands, clean up. [jrd] ; 12 Dec 1987 Add TEK denyflg to defeat automatic invokation of Tek graphics ; by ESC Control-L when in Connect mode. [jrd] ; 24 Oct 1987 Ignore received Naks in Server idle loop ; 21 Sept 1987 Add error exit in GET for filenames too long for packet. [jrd] ; 26 Aug 1987 Add Remote Send to remote help response. [jrd] ; 19 Aug 1987 Correct local override name for files sent to/from server. [jrd] ; 31 July 1987 Redo Logo, Bye, Fin to not shift block check when repeating. ; 25 July 1987 Add global word denyflg to control server restrictions, ; and revise server functions accordingly. [jrd] ; 6 July 1987 Correct Server mode ACKs to use 1 char checksum throughout.[jrd] ; 25 June 1987 Add exit to DOS for LOGO and exit to Kermit prompt for ; FIN command reception, for use with CTTY operation of server. [jrd] ; 7 June 1987 Add DOS errlev of 4 when REMOTE commands to Server fail. [jrd] ; 16 April 1987 Clear local filename in Server idle loop, from Jack Bryans. ; 5 April 1987 Set flags.xflg around Generic I-pkt sends to suppress on-screen ; display of retry counts. Put cursor on line 25 at end of Server cmds. [jrd] ; 25 March 1987 Add Disable/Enable Delete/Host commands. [jrd] ; 9 March 1987 Add calls to statistics functions. [jrd] ; 6 March 1987 Respond to FIN, LOGO, BYE while in server mode ; with 1 byte checksums. Thanks to Jack Bryans. ; Triple waiting time in Server idle loop (fewer NAKs/minute). [jrd] ; 22 Feb 1987 Add Server SEND and WHO commands (both directions). [jrd] ; 1 Oct 1986 Version 2.29a ; 10 Sept 1986 Add display of ACK pkt in LOGO and FIN. Remove forced output ; to screen for REMOTE cmds; thanks to Bill Porteous. ; Add ACK message for received Bye, Logo, Fin commands. [jrd] ; 6 Sept 1986 Output cr/lf for REMote commands before rcving 1st pkt. [jrd] ; 14 August 1986 Allow changing EOL chars. [jrd] ; Modify Srvsnd to handle Set Dest Screen properly. [jrd] ; Correct negotiation on 8 bit quoting, fix checksum resetting. [jrd] ; 26 July 1986 Change ref to ext symbol rpack5 to be rpack. [jrd] ; 16 June 1986 Clear packet counters at start of Get command. ; Also correct use of wrong block check type in Server mode. [jrd] ; 26 May 1986 Revise code to permit serial display. [jrd] ; 14 May 86 - Modify action routine for reception of 'E' packets in server ; mode to be rskp rather than serv1. From Tad Marshall. ; Insert tests for Remote Kermit commands in proc genric to avoid counted ; strings. [jrd] ; [2.29] code frozen on 6 May 1986 [jrd] public logout, bye, finish, remote, get, server, srvdsa, srvena public denyflg include mssdef.h datas segment public 'datas' extrn data:byte, flags:byte, trans:byte, pack:byte, curchk:byte extrn curdsk:byte, diskio:byte, locfil:byte, comand:byte, rptq:byte extrn filtst:byte, maxtry:byte, imxtry:byte, dtrans:byte,fmtdsp:byte extrn inichk:byte, errlev:byte, portval:word scrser equ 0023H ; place for server state display line scrsrm equ 1000H ; place for messages and dos echoes cwdflg equ 1 ; deny remote cwd delflg equ 2 ; deny remote del dirflg equ 4 ; deny remote dir hostflg equ 8 ; deny remote host spcflg equ 10H ; deny remote space finflg equ 20H ; deny fin, bye, logo to server getsflg equ 40H ; deny paths in get cmds to server sndflg equ 80H ; deny paths in send cmds to server typflg equ 100H ; deny paths in type tekxflg equ 200h ; deny automatic Tektronix invokation remcmd db 0 ; Remote command to be executed. rempac db 0 ; Packet type: C (host) or G (generic). cmer05 db cr,lf,'?Filename must be specified$' ermes6 db '?Filename too long for packet$' erms18 db cr,lf,'?Unable to get response from host$' erms21 db cr,lf,'?Unable to tell host to execute command$' infms1 db 'Server mode',cr,lf,'$' remms1 db 'Kermit-MS Server: Unknown server command$' remms2 db 'Kermit-MS Server: Illegal file name$' remms3 db 'Kermit-MS Server: Could not create help file$' remms4 db 'Kermit-MS Server: Unable to change directories$' remms5 db 'Kermit-MS Server: No such file(s)$' remms6 db 'Kermit-MS Server: Could not create directory listing$' remms7 db 'Kermit-MS Server: Could not create space listing$' remms8 db 'Kermit-MS Server: Protected or no such file(s)$' remms9 db 'Kermit-MS Server: Command is Disabled$' remms10 db 'Kermit-MS Server: Could not create work file$' byemsg db 'Kermit-MS Server: Goodbye!',0 whomsg db 'Kermit-MS Server: Just this Server',0 sdshlp db cr,lf,'Server restricts access of selected commands:',cr,lf db ' CWD, DEL, DIR, FIN (incl BYE & LOGO), GET, SEND, SPACE,' db ' TYPE, and ALL.' db cr,lf,'Also TEK (automatic invokation of Tek4010 graphics);' db ' not a member of ALL.$' senhlp db cr,lf,'Server permits full access of selected commands:',cr,lf db ' CWD, DEL, DIR, FIN (incl BYE & LOGO), GET, SEND, SPACE,' db ' TYPE, and ALL.' db cr,lf,'Also TEK (automatic invokation of Tek4010 graphics);' db ' not a member of ALL.$' pass db lf,cr,' Password: $' ; When change directory srvtmp db ' >$kermit$.tmp ',0 ; asciiz, kermit's temp output file delstr db 'del ',0 dirstr db 'dir ',0 spcstr db 'chkdsk.com ',0 crlf db cr,lf,'$' curstim db ? ; normal waiting time for packets denyflg dw 0 ; bit field of denied commands temp dw 0 inpbuf dw 0 ; Pointer to input buffer. cnt dw 0 srvchr db 'SRGIEC' ; server cmd characters srvfln equ $-srvchr ; length of tbl srvfun dw srvsnd,srvrcv,srvgen,srvini,rskp,srvhos ; order as in srvchr remhlp db cr,lf,'CWD change working directory' ; Answer to db cr,lf,'Delete a file' ; local db cr,lf,'Directory filespec' ; REM HELP db cr,lf,'Help' db cr,lf,'Host command' db cr,lf,'Kermit command' db cr,lf,'Send short one line message' db cr,lf,'Space in a directory' db cr,lf,'Type a file' db cr,lf,'Who user spec$' ; Answer from Server to REMOTE HELP hlprem db cr,lf,'Kermit-MS Server commands:',lf db cr,lf,'GET filespec REMOTE DELETE filespec ' db 'REMOTE SEND message' db cr,lf,'SEND filespec REMOTE DIRECTORY filespec ' db 'REMOTE SPACE' db cr,lf,'FIN, LOGO, and BYE REMOTE HELP ' db 'REMOTE TYPE filespec' db cr,lf,'REMOTE CWD directory REMOTE HOST command ' db 'REMOTE WHO',0 ; null terminated remtab db 10 ; 10 entries mkeyw 'CWD',remcwd mkeyw 'Delete',remdel mkeyw 'Directory',remdir mkeyw 'Help',remhel mkeyw 'Host',remhos mkeyw 'Kermit',remker mkeyw 'Send',remsen mkeyw 'Space',remdis mkeyw 'Type',remtyp mkeyw 'Who',remwho srvtab db 11 ; Server Enable/Disable list mkeyw 'All',01ffh mkeyw 'Cwd',cwdflg mkeyw 'Delete',delflg mkeyw 'Dir',dirflg mkeyw 'Fin',finflg mkeyw 'Get',getsflg mkeyw 'Host',hostflg mkeyw 'Send',sndflg mkeyw 'Space',spcflg mkeyw 'Tek4010',tekxflg ; for automatic Tektronix invokation mkeyw 'Type',typflg remfnm db ' Remote Source File: $' lclfnm db ' Local Destination File: $' filhlp db ' File name to use locally$' filmsg db ' Remote filename or confirm with carriage return $' frem db ' Name of file on remote system $' genmsg db ' Enter text to be sent to remote server $' srvbuf db 80H dup (0) rdbuf db 20 dup (0) datas ends code segment public 'code' extrn comnd:near, serrst:near, spack:near, rpack:near, init:near extrn read12:near, serini:near, read2:near, rpar:near, spar:near extrn rin21:near, rfile3:near, error1:near, clrfln:near extrn dodel:near, clearl:near, dodec: near, doenc:near extrn packlen:near, send11:near, errpack:near, pktsize:near extrn nak:near, rrinit:near, cmblnk:near, poscur:near extrn erpos:near, rprpos:near, clrmod:near, crun:near extrn prompt:near, updrtr:near, cmgetc:near, prtfn:near, prtscr:near extrn strcat:near, strlen:near, strcpy:near, fparse:near, isfile:near extrn prtasz:near, ihosts:near, begtim:near, endtim:near assume cs:code, ds:datas, es:nothing ; BYE command - tell remote KERSRV to logout & exits to DOS. BYE PROC NEAR mov ah,cmcfm ; Parse a confirm. call comnd jmp r mov remcmd,'L' ; Logout command letter call logo ; Tell the mainframe to logout. jmp rskp ; Failed - don't exit. mov flags.extflg,1 ; Set exit flag. jmp rskp BYE ENDP ; FINISH - tell remote KERSRV to exit. FINISH PROC NEAR mov ah,cmcfm ; Parse a confirm. call comnd jmp r mov remcmd,'F' ; Finish command letter call logo jmp rskp jmp rskp FINISH ENDP ; LOGOUT - tell remote KERSRV to logout. LOGOUT PROC NEAR mov ah,cmcfm call comnd ; Get a confirm. jmp r mov remcmd,'L' ; Logout command letter call logo jmp rskp ; Go get another command whether we jmp rskp ; succeed or fail. LOGOUT ENDP ; Common routine for FIN, LOGOUT, BYE LOGO PROC NEAR mov pack.numtry,0 ; Initialize count. mov pack.numrtr,0 ; No retries yet. call serini ; Initialize port. call ihosts ; initialize the host mov ah,trans.chklen ; Don't forget the checksum length. mov curchk,ah mov trans.chklen,1 ; Use one char for server functions. call begtim ; start statistics logo1: cmp pack.state,'A' ; Did user type a ^C? je log2x ; e = yes, leave in failure state for Bye. mov ah,pack.numtry cmp ah,maxtry ; Too many times? jl logo3 ; No, try it. logo2: mov ah,prstr mov dx,offset erms18 int dos log2x: call serrst ; Reset port mov ax,1 ; tell statistics this was a send operation call endtim ; finish statistics mov ah,curchk mov trans.chklen,ah ; Restore value. ret ; and exit in failure state for Bye logo3: inc pack.numtry ; Increment number of tries. mov pack.argblk,0 ; Packet number zero. mov pack.argbk1,1 ; One piece of data. mov ah,remcmd ; get command letter ('L' or 'F') mov data,ah ; Logout the remote host. mov cx,1 ; One piece of data. call doenc ; Do encoding. mov ah,'G' ; Generic command packet. call spack jmp logo2 ; Tell user and die. nop call rpack ; Get ACK (w/o screen msgs.) jmp logo1 ; Go try again. nop push ax call dodec ; Decode packet. pop ax cmp ah,'Y' ; ACK? jne logo4 cmp pack.argbk1,0 ; Any data in the ACK? je logo6 ; Nope - just return. mov ah,prstr ; output a cr/lf mov dx,offset crlf int dos mov di,offset data ; Where the reply is. mov cx,pack.argbk1 ; How much data we have. call prtscr ; Print it on the screen. jmp logo6 ; and exit logo4: cmp ah,'E' ; Error packet? je logo5 ; e = yes jmp logo1 ; try sending again logo5: call error1 logo6: call serrst ; Reset port mov ax,1 ; tell statistics this was a send operation call endtim ; finish statistics mov ah,curchk mov trans.chklen,ah ; Restore value. jmp rskp ; use rskp so Bye succeeds LOGO ENDP ; GET command. Ask remote server to send the specified file(s). ; Queries for remote filename and optional local override path/filename. GET PROC NEAR mov flags.nmoflg,0 ; Reset flags from fn parsing. mov byte ptr locfil,0 ; clear, for safety mov byte ptr srvbuf,0 ; ditto mov flags.cxzflg,0 ; no Control-C typed yet mov cnt,0 ; count of filename chars mov bx,offset srvbuf ; Where to put text. mov byte ptr [bx],0 ; clear for safety mov dx,offset filmsg ; In case user needs help. mov ah,cmtxt ; filenames with embedded whitespace call comnd ; Get text or confirm. jmp r ; Fail. mov al,ah mov ah,0 mov cnt,ax ; Remember number of chars we read. cmp al,0 ; Read in any chars? je get1 ; e = no. jmp get3 ; yes, now check for override name. ; if empty line, ask for file names get1: mov dx,offset remfnm ; ask for remote name first call prompt mov bx,offset srvbuf ; place for remote filename mov dx,offset frem ; the help message mov ah,cmtxt ; use this for embedded spaces call comnd ; get a filename jmp r cmp flags.cxzflg,0 ; ^X, ^Z, or ^C typed? je get2 ; e = no, continue jmp rskp ; yes, quit get2: mov al,ah mov ah,0 mov cnt,ax ; remember number of chars read. mov bx,offset srvbuf ; look at string again. push es push di push si mov ax,ds ; use segment 'datas' for es: mov es,ax mov si,bx ; look at start of string, remove whitespace get2c: cmp byte ptr [si],0 ; at terminator? je get2d ; e = yes cmp byte ptr [si],' ' ; text (greater than space)? ja get2d ; a = yes. inc si ; look at next char jmp get2c ; look some more get2d: cmp bx,si ; did we find leading whitespace? je get2e ; e = no mov di,bx ; place to copy chars call strcpy ; from ds:si to ds:di get2e: mov dx,bx ; address of string call strlen ; get its new length (returned in cx) mov cnt,cx ; store it pop si pop di pop es cmp cnt,0 ; count of entered chars jne get2f ; ne = got some jmp rskp ; empty so abort this command get2f: mov dx,offset lclfnm ; prompt for local filename call prompt get3: mov flags.nmoflg,0 ; assume no local override name mov bx,offset filhlp mov dx,offset locfil ; complete local filename mov byte ptr locfil,0 ; clear, for safety mov ah,cmfile ; allow paths call comnd jmp r mov bx,offset locfil cmp byte ptr [bx],'#' ; Is first char a replacement for '?' jne get3a ; ne = no mov byte ptr [bx],'?' ; yes. Replace '#' by '?' get3a: mov al,ah ; number of chars in locfil according to cmd mov flags.nmoflg,al ; 0 = no override mov ah,0 add bx,ax mov byte ptr [bx],0 ; force a termination null mov bx,offset srvbuf ; get remote filename address again cmp byte ptr [bx],'#' ; Is first char a replacement for '?' ? jne get4 ; ne = no. mov byte ptr [bx],'?' ; yes. Replace '#' by '?' get4: cmp flags.cxzflg,0 ; ^X, ^Z, or ^C typed? je get5 ; e = no, keep going mov flags.cxzflg,0 ; clear the interrupt flag or errlev,2 ; say cannot receive jmp rskp get5: call begtim ; start statistics cmp flags.destflg,2 ; receiving to screen? je get5a ; e = yes, skip screen stuff mov flags.xflg,0 ; no, reset x flag call init ; init screen get5a: call ipack ; Send Initialize, 'I', packet. jmp get8 ; Sorry can't do it. nop mov cx,cnt ; Get back remote filename size. mov pack.argbk1,cx ; Need it here to send packet. mov si,offset srvbuf ; Move from here mov di,offset data ; to here. call strcpy ; copy from srvbuf to data test flags.remflg,dquiet ; quiet display mode? jnz get6 ; nz = yes, don't print anything cmp flags.remflg,dserial ; serial mode display? je get6 ; e = yes, skip extra display item. cmp flags.destflg,2 ; Receiving to screen? je get6 ; Yes skip screen stuff. call prtfn ; print filename in data get6: call rrinit ; clear pack.xxx counters mov pack.numrtr,-1 ; No retries yet (gets incremented below). mov pack.state,'R' ; this is what state will be soon mov cx,pack.argbk1 ; Data size. call doenc ; Encode data. jnc get6a ; nc = success jmp get12 ; c = data could not all fit into packet get6a: mov ah,trans.chklen ; Don't forget the checksum length. mov curchk,ah mov trans.chklen,1 ; Use one char for server functions. get7: call updrtr cmp pack.state,'A' ; Did user type a ^C? je get9 ; Yes - just return to main loop. mov ah,pack.numtry cmp ah,maxtry ; Too many times? jbe get10 ; Nope, try it. get8: test flags.remflg,dquiet ; quiet display mode? jnz get9 ; nz = yes, no printing call erpos mov ah,prstr mov dx,offset erms18 ; Can't get init packet. int dos or errlev,2 ; set DOS error level to cannot rcv. get9: test flags.remflg,dquiet+dserial ; quiet or serial display? jnz get9a ; nz = yes call clrmod call rprpos get9a: call serrst ; Reset port. mov ah,curchk mov trans.chklen,ah ; Restore value. xor ax,ax ; say this was a receive operation call endtim ; do statistics jmp rskp get10: inc pack.numtry ; Increment number of tries. mov pack.argblk,0 ; Start at packet zero. call pktsize ; report packet size mov ah,'R' ; Receive init packet. call spack ; Send the packet. jmp get8 ; Tell user we can't do it. nop call rpack ; Get ACK jmp get7 ; Got a NAK - try again. nop push ax mov ah,curchk mov trans.chklen,ah ; Restore value. pop ax mov pack.argbk2,ax ; where rinit wants pkt type if GET mov flags.getflg,1 ; note this is a GET mov pack.state,'R' ; Set the state to receive initiate jmp read12 ; go join read code get11: mov ah,prstr ; Complain if no filename. mov dx,offset cmer05 int dos jmp rskp get12: mov dx,offset ermes6 ; Complain if filename is too long for pkt test flags.remflg,dquiet ; quiet display mode? jnz get13 ; nz = yes, no printing call erpos ; position cursor on formatted screen mov ah,prstr int dos get13: mov bx,dx ; point to message, for errpack call errpack ; tell the host we are quiting test flags.remflg,dserial ; serial display mode? jnz get14 ; nz = yes call clrmod ; clear mode line call rprpos ; Put prompt here. get14: or errlev,2 ; set DOS error level to cannot rcv jmp rskp GET ENDP ; server command SERVER PROC NEAR mov ah,cmcfm call comnd jmp r push es mov ax,ds mov es,ax ; address data segment mov al,flags.remflg ; get display mode flag push ax ; preserve for later ; Enable the line below if the server screen is to be quiet (clear), ; or make the line a comment if the server screen is to show file transfers. ;===> mov flags.remflg,dquiet ; set quiet display flag if server ; or flags.remflg,dserver ; signify we are a server now mov ax,0 ; simulate empty parameter packet call spar ; and thus set our params to defaults mov ah,drpt ; force default repeat prefix char mov rptq,ah ; char be our active one test flags.remflg,dquiet ; quiet display? jnz serv1c ; nz = yes mov ah,prstr mov dx,offset crlf int dos test flags.remflg,dserial ; serial display? jnz serv1a ; nz = yes mov fmtdsp,1 ; say using formatted display call cmblnk ; clear screen mov dx,scrser ; move cursor to top of screen call poscur serv1a: mov ah,prstr mov dx,offset infms1 ; say now in server mode int dos serv1c: mov ah,inichk ; set default checksum length mov curchk,ah ; save it here serv1: test flags.remflg,dquiet+dserial ; quiet or serial display? jnz serv1b ; nz = yes mov fmtdsp,1 ; say using formatted display mov dx,scrsrm ; move cursor to server message area add dx,0100H ; look at line below (DOS does CR/LF first) call poscur call clearl ; and clear the line mov dx,scrsrm ; back to message line call poscur serv1b: mov flags.nmoflg,0 ; clear, say no local override filenames mov flags.cxzflg,0 ; clear ^X, ^Z, ^C seen flag mov flags.xflg,0 ; reset X packet flag mov locfil,0 ; say no local filename [JB] mov ah,dtrans.seol ; restore default end-of-line char mov trans.seol,ah mov byte ptr srvbuf,0 ; plant terminator to clear call serini ; init serial line (send & receive reset it) mov ax,1 ; assume previous operation was a send call endtim ; do end of statistics, for loop back mov trans.chklen,1 ; checksum len = 1 mov pack.pktnum,0 ; pack number resets to 0 mov pack.numtry,0 ; no retries yet. mov al,trans.stime ; get current timeout interval mov curstim,al ; save current timeout interval add al,al ; triple it for server idle loop add al,curstim ; times three mov trans.stime,al ; use this longer interval in the idle loop call rpack ; get a packet jmp short serv2 ; no good, nak and continue nop call begtim ; start statistics push ax mov al,curstim ; get original timeout interval mov trans.stime,al ; restore timeout interval pop ax cmp ah,'I' ; never "decode" S, I, and A packets je serv3 ; its an I packet cmp ah,'S' je serv3 cmp ah,'A' je serv3 call dodec ;decode packet; protocol error if omitted jmp short serv3 ; try to figure this out serv2: push ax mov al,curstim ; get original timeout interval mov trans.stime,al ; restore timeout interval pop ax cmp flags.cxzflg,'C' ; Control-C? je serv5 ; yes, stop this. call nak ; nak the packet mov al,curchk ; restore checksum length mov trans.chklen,al jmp serv1 ; and keep readiserv2 packets serv3: mov al,curchk ; restore checksum length mov trans.chklen,al push ds pop es ; set es to datas segment mov di,offset srvchr ; server characters mov cx,srvfln ; length of striserv2 mov al,ah ; packet type cld repne scasb ; hunt for it je serv4 ; we know this one, go handle it cmp al,'N' ; received a Nak? je serv3a ; e = yes, ignore it mov bx,offset remms1 ; else give a message call errpack ; back to local kermit serv3a: jmp serv1 ; and keep lookiserv2 for a cmd serv4: sub di,offset srvchr+1 ; find offset, +1 for pre-increment shl di,1 ; convert to word index. call srvfun[di] ; call the appropriate handler jmp serv5 ; someone wanted to exit... jmp serv1 ; else keep goiserv2 for more cmds. serv5: mov al,curchk ; restore checksum length mov trans.chklen,al pop ax ; get this off stack test flags.remflg,dserial+dquiet ; serial or quiet display? jnz serv5a ; nz = yes call rprpos ; Put prompt here. serv5a: mov flags.remflg,al ; restore old flag call serrst ; reset serial handler mov ax,1 ; tell statistics this was a send operation call endtim ; stop statistics mov fmtdsp,0 ; end of formatted display pop es ; restore register jmp rskp ; and return SERVER ENDP ; server commands. ; srvsnd - receives a file that a remote kermit is sending. srvsnd proc near mov bx,offset data mov ax,pack.argbk1 ; get number of data bytes call spar ; parse the send-init packet mov al,trans.chklen ; get negotiated checksum length mov curchk,al ; and remember it here call packlen ; figure max packet mov bx,offset data call rpar ; make answer for them mov al,ah ; length of packet mov ah,0 mov pack.argbk1,ax ; store length for spack mov trans.chklen,1 ; reply with 1 char checksum call pktsize ; report packet size mov ah,'Y' ; ack call spack ; answer them jmp rskp ; can't answer, forget this mov al,curchk ; restore checksum length mov trans.chklen,al call rrinit ; init variables for init cmp flags.destflg,2 ; file destination = screen? jne srvsnd0 ; ne = no mov flags.xflg,1 ; say receiving to screen jmp srvsnd1 srvsnd0:call init ; setup display form srvsnd1:test denyflg,sndflg ; is command enabled? jz srvsnd2 ; z = yes mov si,offset srvbuf ; work buffer mov byte ptr[si],5ch ; backslash inc si mov ah,gcd ; get current directory (path really) xor dl,dl ; use current drive int dos ; returns ds:si with asciiz path (no drive) mov si,offset srvbuf mov di,offset locfil ; destination is local override name call strcpy ; copy the path to local filename mov dx,di call strlen ; get length of string into cx mov di,cx ; length of local path mov locfil[di],5ch ; add backslash mov locfil[di+1],0 ; null terminator mov flags.nmoflg,1 ; say have override name (zaps external path) srvsnd2:inc pack.pktnum ; count the send-init packet. mov pack.state,'F' ; expecting file name about now call read12 ; join read code. changed from read2 nop nop nop ; ignore errors mov flags.xflg,0 jmp rskp ; and return for more srvsnd endp ; srvrcv - send a file to a distant kermit srvrcv proc near mov si,offset data ; received filename, asciiz from rpack test denyflg,getsflg ; command enabled? jz srrcv2 ; z = yes mov di,offset srvbuf ; local path mov si,offset rdbuf ; local filename mov dx,offset data ; local string call fparse ; split string mov si,offset rdbuf ; copy local filename to srrcv2: mov di,offset diskio.string ; destination call strcpy ; copy data to diskio.string mov pack.state,'R' ; remember state. call send11 ; this should send it jmp rskp jmp rskp ; return in any case srvrcv endp ; srvgen - G generic server command dispatcher. ; srvgen proc near mov al,data ; get 1st packet char srvge2: cmp al,'T' ; Type a file? jne srvge3 ; ne = no call srvtyp ; do the typing jmp rskp srvge3: cmp al,'D' ; do a directory? jne srvge4 call srvdir ; do the directory command jmp rskp srvge4: cmp al,'E' ; do a file erase (delete)? jne srvge5 call srvdel ; do the delete command jmp rskp srvge5: cmp al,'C' ; change working dir? jne srvge6 ; ne = no call srvcwd ; do it jmp rskp srvge6: cmp al,'U' ; do a space command? jne srvge7 call srvspc ; do the space command jmp rskp srvge7: cmp al,'F' ; FIN? jne srvge8 ; ne = no jmp srvfin srvge8: cmp al,'L' ; LOGO or BYE? jne srvge9 ; ne = no call srvfin jmp short srvge8a ; permitted to exit Kermit nop jmp rskp ; stay active (command denied) srvge8a:mov flags.extflg,1 ; set exit flag. ret ; leave server mode and Kermit. srvge9: cmp al,'M' ; one line Message? jne srvge10 ; ne = no call srvsen jmp rskp srvge10:cmp al,'W' ; WHO? jne srvge11 ; ne = no call srvwho jmp rskp srvge11:cmp al,'H' ; Help? jne srvgex ; ne = no jmp srvhlp srvgex: mov bx,offset remms1 ; reply Unknown server command mov trans.chklen,1 ; reply with 1 char checksum call errpack jmp rskp srvgen endp ; srvfin - respond to remote host's Fin command. [jrd] srvfin proc near test denyflg,finflg ; command enabled? jz srfin1 ; z = yes mov bx,offset remms9 ; else give a message mov trans.chklen,1 ; reply with 1 char checksum call errpack ; back to local kermit jmp rskp ; stay in server mode srfin1: mov si,offset byemsg ; add brief msg of goodbye mov di,offset data ; packet's data field call strcpy ; copy msg to pkt mov dx,si ; strlen works on dx call strlen mov ah,'Y' ; reply with an ack mov pack.argbk1,cx ; length mov trans.chklen,1 ; reply with 1 char checksum call pktsize ; report packet size call spack ; send it, expect no response nop ; ignore errors nop nop ret ; ret exits server mode srvfin endp ; srvcwd - handle other side's Remote CWD dirspec [jrd] srvcwd proc near test denyflg,cwdflg ; is command enabled? jz srcwd4 ; z = yes mov bx,offset remms9 ; else give a message mov trans.chklen,1 ; reply with 1 char checksum call errpack ; back to local kermit ret srcwd4: cmp pack.argbk1,1 ; any data? je srcwd3 ; e = no mov cl,data+1 ; get the filename byte count sub cl,' ' ; ascii to numeric mov ch,0 ; set up counter cmp cl,0 ; anything there? jle srcwd3 ; le = no, an error mov si,offset data+2 ; received dir spec, from rpack mov di,offset srvbuf ; destination push es ; save es push ds pop es ; make es:di point to datas segment cld rep movsb ; copy data to srvbuf, cx chars worth pop es mov byte ptr [di],0 ; plant terminator mov dx,offset srvbuf ; for DOS mov ax,dx ; dir spec pointer for isfile cmp byte ptr [di-1],':' ; did user just type A: or similar? je srcwd1 ; e = yes, so skip directory part mov ah,chdir ; want to do change dir int dos jnc srcwd1 ; nc = ok srcwd3: mov bx,offset remms4 ; an error. mov trans.chklen,1 ; reply with 1 char checksum call errpack ; send the bad news ret srcwd1: mov dl,data+3 ; see if drive given (look for :) cmp dl,':' jne srcwd2 ; ne = no drive mov dl,data+2 and dl,5fH ; convert to upper case sub dl,'A' ; count A = 0 for seldsk call mov ah,seldsk int dos ; change disks jc srcwd3 ; c = an error inc dl ; now make A = 1 etc internally mov curdsk,dl ;and update internal current disk code srcwd2: mov ah,'Y' ; return an ack mov pack.argbk1,0 ; no data mov trans.chklen,1 ; reply with 1 char checksum call pktsize ; report packet size call spack nop nop nop ret srvcwd endp ; srvtyp - handle other side's Remote Type filename request [jrd] ; expects "data" to hold Tcfilename where c = # bytes in filename. srvtyp proc near cmp pack.argbk1,1 ; any data in packet je srtyp2 ; e = no mov cl,data+1 ; get the filename byte count sub cl,' ' ; ascii to numeric mov ch,0 ; set up counter mov si,offset data+2 ; received filename, asciiz from rpack mov di,si add di,cx mov byte ptr [di],0 ; make string asciiz test denyflg,typflg ; paths permitted? jz srtyp1 ; z = yes, else use just filename part mov di,offset srvbuf ; local path mov si,offset rdbuf ; local filename mov dx,offset data+2 ; local string call fparse ; split string mov si,offset rdbuf ; copy local filename to srtyp1: mov di,offset diskio.string ; destination call strcpy ; do the copy mov ax,offset diskio.string ; pointer to filename, for isfile call isfile ; does it exist? jnc srtyp3 ; nc = yes srtyp2: mov bx,offset remms5 ; "No such file(s)" mov trans.chklen,1 ; reply with 1 char checksum call errpack ; send error message ret ; and exit srtyp3: mov flags.xflg,1 ; say use X packet rather than F pkt mov pack.state,'R' ; remember state. call send11 ; this should send it nop nop nop mov flags.xflg,0 ; clear flag ret ; return in any case srvtyp endp ; serdir - handle other side's Remote Dir filespec(optional) request [jrd] srvdir proc near mov cx,0 ; assume no data in packet cmp pack.argbk1,1 ; any data in the packet? je srdir4 ; e = no mov cl,data+1 ; get the filename byte count sub cl,' ' ; ascii to numeric mov ch,0 ; set up counter srdir4: mov di,offset data+2 ; received filespec, asciiz from rpack add di,cx mov byte ptr [di],0 ; make string asciiz test denyflg,dirflg ; paths permitted? jz srdir1 ; z = yes, else use just filename part mov di,offset srvbuf ; local path mov si,offset rdbuf ; local filename mov dx,offset data+2 ; local string call fparse ; split string mov si,offset rdbuf ; copy local filename to mov di,offset data+2 ; final filename call strcpy ; do the copy mov ax,di call isfile ; is/are there any such file? jc srdir1 ; c = there is none test byte ptr filtst.dta+21,1EH ; attr bits: is file protected? jz srdir1 ; z = not protected. mov bx,offset remms8 ; "Protected or no such file(s)" mov trans.chklen,1 ; reply with 1 char checksum call errpack ; send error message ret ; and exit srdir1: mov di,offset srvbuf ; work area mov si,offset dirstr ; prepend "dir " call strcpy mov si,offset data+2 ; directory spec, asciiz mov di,offset srvbuf call strcat mov si,offset srvtmp ; add redirection tag of " >$kermit$.tmp" mov di,offset srvbuf call strcat mov si,offset srvbuf ; command pointer for crun call crun nop nop nop mov si,offset srvtmp+2 ; get name of temp file mov di,offset diskio.string ; destination call strcpy ; copy it there mov ax,di ; filename pointer for isfile call isfile ; did we make the temp file? jnc srdir3 ; nc = yes mov bx,offset remms6 ; "Could not create directory listing" mov trans.chklen,1 ; reply with 1 char checksum call errpack ; send the error message ret ; and exit srdir3: mov flags.xflg,1 ; say use X rather than F packet mov pack.state,'R' ; remember state. call send11 ; this should send it nop nop nop mov flags.xflg,0 ; clear flag mov dx,offset diskio.string mov ah,del2 ; delete the file int dos ret ; return in any case srvdir endp ; serdel - handle other side's request of Remote Del filespec [jrd] srvdel proc near test denyflg,delflg ; command enabled? jz srvdel4 ; z = yes mov bx,offset remms9 ; else give a message mov trans.chklen,1 ; reply with 1 char checksum call errpack ; back to local kermit ret srvdel4:cmp pack.argbk1,1 ; any data? je srdel1 ; e = no mov di,offset srvbuf ; work area mov si,offset delstr ; prepend "del " call strcpy mov dx,offset srvbuf call strlen add di,cx ; di points at terminator mov ax,di ; save pointer to incoming filespec mov cl,data+1 ; get the filename byte count sub cl,' ' ; ascii to numeric mov ch,0 ; set up counter cmp cl,0 ; anything there? jle srdel3 ; le = no mov si,offset data+2 ; received filespec, asciiz from rpack push es ; save es push ds pop es ; set es to datas segment cld rep movsb ; append data to srvbuf pop es ; restore es mov byte ptr [di],0 ; plant terminator call isfile ; is/are there any to delete? jc srdel1 ; c = there is none test byte ptr filtst.dta+21,1EH ; attr bits: is file protected? jz srdel2 ; z = not protected. srdel1: mov bx,offset remms8 ; "Protected or no such file(s)" mov trans.chklen,1 ; reply with 1 char checksum call errpack ; send error message ret ; and exit srdel2: mov si,offset srvbuf ; set pointer for crun call crun nop nop nop srdel3: mov ah,'Y' ; return an ack mov pack.argbk1,0 ; no data mov trans.chklen,1 ; reply with 1 char checksum call pktsize ; report packet size call spack nop nop nop ret srvdel endp ; serspc - handle other side's request of Remote Space [jrd] srvspc proc near test denyflg,spcflg ; is command enabled? jz srspc1 ; z = yes mov bx,offset remms9 ; else give a message mov trans.chklen,1 ; reply with 1 char checksum call errpack ; back to local kermit ret srspc1: mov di,offset srvbuf ; work area mov si,offset spcstr ; prepend "chkdsk.com " call strcpy mov si,offset srvtmp ; add redirection tag of " >$kermit$.tmp" call strcat mov si,offset srvbuf ; command pointer for crun call crun nop nop nop mov si,offset srvtmp+2 ; get name of temp file mov di,offset diskio.string ; destination call strcpy ; copy it there mov ax,di ; filename pointer for isfile call isfile ; did we make the temp file? jnc srspc2 ; nc = yes mov trans.chklen,1 ; reply with 1 char checksum mov bx,offset remms7 ; "Could not create space listing" call errpack ; send the error message ret ; and exit srspc2: mov flags.xflg,1 ; say use X rather than F packet mov pack.state,'R' ; remember state. call send11 ; this should send it nop nop nop mov flags.xflg,0 ; clear flag mov dx,offset diskio.string mov ah,del2 ; delete the file int dos ret ; return in any case srvspc endp ; srvwho - respond to remote host's WHO command. [jrd] srvwho proc near mov si,offset whomsg ; add brief msg of just us chickens mov di,offset data ; packet's data field call strcpy ; copy msg to pkt mov dx,si ; strlen works on dx call strlen mov trans.chklen,1 ; reply with 1 char checksum mov ah,'Y' ; reply with an ack mov pack.argbk1,cx ; length call pktsize ; report packet size call spack ; send it, expect no response nop ; ignore errors nop nop ret srvwho endp ; srvmsg - respond to remote host's Message (Send) command ; show message on our screen. [jrd] srvsen proc near cmp pack.argbk1,1 ; Any data in the packet? jbe srvsen1 ; e = no, just ack the message. call dodec ; Decode data. mov di,offset data+2 ; Where the reply is. (skip M and byte cnt) cmp byte ptr [di-2],'M' ; Message packet? jne srvsen1 ; ne = no, ack and forget mov cl,byte ptr [di-1] ; How much data we have. sub cl,' ' ; remove ascii bias cbw ; make a whole word jle srvsen1 ; le = nothing call prtscr ; Print it on the screen. srvsen1:mov ah,'Y' ; reply with an ack mov pack.argbk1,0 ; length mov trans.chklen,1 ; reply with 1 char checksum call pktsize ; report packet size call spack ; send it, expect no response nop ; ignore errors nop nop ret srvsen endp ; srvhos - handle other side's request of REM Host command-line. [jrd] ; We execute the command with STDOUT redirected to $kermit$.tmp and then ; read and transmit that file to the other end. No such file results in ; returning just an error msg ACK packet. srvhos proc near test denyflg,hostflg ; command enabled? jz srvhos2 ; z = yes mov trans.chklen,1 ; reply with 1 char checksum mov bx,offset remms9 ; else give a message call errpack ; back to local kermit jmp rskp srvhos2:mov si,offset data ; received filename, asciiz from rpack mov di,offset srvbuf ; destination call strcpy ; copy data to srvbuf mov si,offset srvtmp ; add redirection tag of " >$kermit$.tmp" call strcat mov si,offset srvbuf ; si = pointer for crun call crun ; go do the command nop nop nop mov si,offset srvtmp+2 ; get name of temp file mov di,offset diskio.string ; destination call strcpy ; copy it to diskio.string mov ax,di ; filename pointer for isfile call isfile ; did we make the temp file? jnc srhos1 ; nc = yes mov si,offset remms10 ; say could not create work file mov di,offset data ; packet's data field call strcpy ; copy msg to pkt mov dx,si ; strlen works on dx call strlen mov trans.chklen,1 ; reply with 1 char checksum mov ah,'Y' ; reply with an ack mov pack.argbk1,cx ; length mov trans.chklen,1 ; reply with 1 char checksum call pktsize ; report packet size call spack nop nop nop jmp rskp ; and exit srhos1: mov flags.xflg,1 ; say use X rather than F packet mov pack.state,'R' ; remember state. call send11 ; this should send it nop nop nop mov flags.xflg,0 ; clear flag mov dx,offset diskio.string mov ah,del2 ; delete the temp file int dos jmp rskp ; return in any case srvhos endp ; Respond to other side's request of Remote Help. Write & read $kermit$.tmp. ; Return rskp. [jrd] srvhlp proc near mov si,offset srvtmp+2 ; use filename of $kermit$.tmp mov di,offset diskio.string ; put name here call strcpy mov ah,creat2 ; create the file mov cx,0 ; attributes r/w mov dx,offset diskio.string ; use $kermit$.tmp name int dos jc srvhlp4 ; c = could not open mov diskio.handle,ax ; file handle mov dx,offset hlprem ; data to be sent, strlen uses dx call strlen ; put string length in cx mov ah,write2 ; write to file mov bx,diskio.handle int dos ; write the info, ignore errors mov ah,close2 ; close the file so we can reread it below mov bx,diskio.handle int dos ; Send temporary file to remote screen mov flags.xflg,1 ; say use X rather than F packet mov pack.state,'R' ; remember state. call send11 ; this should send it nop nop nop mov flags.xflg,0 ; clear flag mov dx,offset diskio.string ; filename mov ah,del2 ; delete the temp file int dos jmp rskp ; and return srvhlp4:mov si,offset remms3 ; say could not create help file mov di,offset data ; packet's data field call strcpy ; copy msg to pkt mov dx,si ; strlen works on dx call strlen mov trans.chklen,1 ; reply with 1 char checksum mov ah,'Y' ; reply with an ack mov pack.argbk1,cx ; length call pktsize ; report packet size call spack nop nop nop jmp rskp ; and exit srvhlp endp srvdsa proc near ; DISABLE Server commands mov dx,offset srvtab mov bx,offset sdshlp mov ah,cmkey ; parse key word call comnd jmp r ; bad parse mov temp,bx ; save key value mov ah,cmcfm ; get a confirm call comnd jmp r ; no confirm mov bx,temp ; get selected item or denyflg,bx ; turn on bit (deny) for that item jmp rskp ; return successfully srvdsa endp srvena proc near ; ENABLE Server commands mov dx,offset srvtab ; keyword table mov bx,offset senhlp ; help on keywords mov ah,cmkey ; parse key word call comnd jmp r ; bad parse mov temp,bx ; save key value mov ah,cmcfm ; get a confirm call comnd jmp r ; no confirm mov bx,temp ; item to be enabled not bx ; invert bits and denyflg,bx ; turn off (enable) selected item jmp rskp srvena endp ; srvini - init parms based on init packet srvini proc near mov bx,offset data mov ax,pack.argbk1 ; get number of data bytes call spar ; parse info call packlen ; this should really be part of spar, but... mov bx,offset data call rpar ; setup info about our reception push ax mov al,trans.chklen ; checksum length negotiated mov curchk,al ; use as new working length pop ax mov al,ah mov ah,0 mov pack.argbk1,ax ; set size of return info mov trans.chklen,1 ; reply with 1 char checksum mov ah,'Y' call pktsize ; report packet size call spack ; send the packet off nop nop nop mov al,curchk ; restore checksum length before proceeding mov trans.chklen,al jmp rskp ; and go succeed srvini endp ; This is the REMOTE command. REMOTE PROC NEAR mov dx,offset remtab ; Parse a keyword from the REMOTE table. mov bx,offset remhlp mov ah,cmkey call comnd jmp r call bx ; Call the appropriate routine. jmp r ; Command failed. jmp rskp REMOTE ENDP ; REMDIS - Get disk usage on remote system. REMDIS PROC NEAR mov remcmd,'U' ; Disk usage command. mov rempac,'G' ; Packet type = generic. jmp genric ; Execute generic Kermit command. REMDIS ENDP ; REMHEL - Get help about remote commands. REMHEL PROC NEAR mov remcmd,'H' ; Help mov rempac,'G' ; Packet type = generic. jmp genric ; Execute generic Kermit command. REMHEL ENDP ; REMTYP - Type a remote file. REMTYP PROC NEAR mov remcmd,'T' ; Type the file. mov rempac,'G' ; Packet type = generic. jmp genric REMTYP ENDP ; REMHOS - Execute a remote host command. REMHOS PROC NEAR mov remcmd,' ' ; Don't need one. mov rempac,'C' ; Packet type = remote command. jmp genric REMHOS ENDP ; REMKER - Execute a remote Kermit command. REMKER PROC NEAR mov remcmd,' ' ; Don't need one. mov rempac,'K' ; Packet type = remote Kermit command. jmp genric REMKER ENDP ; REMDIR - Do a directory. REMDIR PROC NEAR mov remcmd,'D' mov rempac,'G' ; Packet type = generic. jmp genric REMDIR ENDP ; REMDEL - Delete a remote file. REMDEL PROC NEAR mov remcmd,'E' mov rempac,'G' ; Packet type = generic. jmp genric REMDEL ENDP ; REMCWD - Change remote working directory. REMCWD PROC NEAR mov remcmd,'C' mov rempac,'G' ; Packet type = generic. jmp genric REMCWD ENDP ; REMSEN - Send one line short message to remote screen. [jrd] REMSEN proc near mov remcmd,'M' mov rempac,'G' jmp genric REMSEN endp ; REMWHO - ask for list of remote logged on users [jrd] REMWHO proc near mov remcmd,'W' mov rempac,'G' jmp genric REMWHO endp ; GENRIC - Send a generic command to a remote Kermit server. GENRIC PROC NEAR call begtim ; start statistics mov bx,offset srvbuf ; Where to put the text. cmp rempac,'C' ; Remote host command? je genra ; Yes, leave as is. cmp rempac,'K' ; Remote Kermit command? je genra ; e = yes. Don't use counted string. add bx,2 ; Leave room for type and size. genra: mov ah,cmtxt ; Parse arbitrary text up to a CR. mov dx,offset genmsg ; In case they want text. call comnd jmp r mov al,ah ; Don't forget the size. mov ah,0 mov cnt,ax ; Save it here. mov flags.xflg,1 ; output coming to screen cmp rempac,'K' ; Remote Kermit command? je genra1 ; e = yes cmp rempac,'C' ; Remote host command? jne genrb ; No, skip this part. genra1: call ipack ; Remote Host or Kermit jmp genr2 mov curchk,ah ; Save desired checksum length. mov trans.chklen,1 ; Use 1 char for server functions. mov pack.numrtr,0 ; No retries yet. mov pack.numtry,0 jmp genr1 ; Send the packet. genrb: mov ax,cnt cmp ax,0 ; Any data? je genr0 ; Nope. mov ah,al ; Don't overwrite the real count value add ah,32 ; Do the char function. mov temp,bx ; Remember where we are. mov bx,offset srvbuf+1 ; Size of remote command. mov [bx],ah mov ah,0 inc al ; For the size field. cmp remcmd,'C' ; Change working directory? jne genr0 ; No, so don't ask for password. mov cnt,ax ; Save here for a bit. mov ah,prstr mov dx,offset pass ; Send along an optional password. int dos mov bx,temp ; Where to put the password. push bx ; Is safe since subroutine never fails inc bx ; Leave room for count field. call input ; Read in the password. mov temp,bx ; Remember end of data pointer. pop bx ; Where to put the size. cmp ah,0 ; No password given? jne genrc mov ax,cnt jmp genr0 ; Then that's it. genrc: mov al,ah add ah,32 ; Make it printable. mov [bx],ah ; Tell remote host the size. mov ah,0 push ax ; Remember the count. call clearl ; Clear to end-of-line. pop ax inc al ; For second count value. add ax,cnt ; Total for both fields of input. genr0: inc al ; For char representing the command. mov pack.argbk1,ax ; Set the size. mov cnt,ax ; And remember it. mov pack.argbk1,ax ; Set the size. mov cnt,ax ; And remember it. mov pack.numtry,0 ; Initialize count mov bx,offset srvbuf ; Start of data buffer. mov ah,remcmd ; Command subtype. mov [bx],ah call ipack ; Send init parameters. jmp genr2 nop ; Make it 3 bytes long. mov ah,trans.chklen mov curchk,ah ; Save desired checksum length. mov trans.chklen,1 ; Use 1 char for server functions. mov pack.numrtr,0 ; No retries yet. genr1: cmp pack.state,'A' ; Did the user type a ^C? je genr2x mov ah,pack.numtry cmp ah,maxtry ; Too many tries? jl genr3 ; Nope, keep trying. genr2: mov ah,prstr mov dx,offset erms21 ; Print error msg and fail. int dos genr2x: call serrst ; Reset the port. mov ah,curchk mov trans.chklen,ah ; Restore. mov flags.xflg,0 ; reset screen output flag before leaving xor ax,ax ; tell statistics this was a read or errlev,4 ; DOS error level, failure of REMote cmd call endtim jmp rskp genr3: mov ah,prstr mov dx,offset crlf ; First go to a new line. int dos push es ; Prepare to put string into packet. push ds pop es mov si,offset srvbuf ; Move from here mov di,offset data ; to here. mov cx,cnt ; Move this many characters. cld rep movsb ; Perform the string move. pop es mov ax,cnt mov pack.argbk1,ax ; How much data to send. mov cx,ax ; Size of data. call doenc ; Encode it. inc pack.numtry ; Increment number of trials. mov trans.chklen,1 ; use block check 1 to server mov pack.argblk,0 ; Packet number 0. mov ah,rempac ; Packet type. call pktsize ; report packet size call spack ; Send the packet. jmp genr2 ; Tell user we can't do it. nop call rpack ; Get ACK (w/o screen stuff) jmp genr3a ; Got a NAK - try again. nop jmp genr3b ; Ok. genr3a: push ax mov ah,curchk mov trans.chklen,ah ; Restore after reception. pop ax jmp genr1 ; NAK, try again genr3b: push ax ; Ok. mov ah,curchk mov trans.chklen,ah ; Restore after reception. pop ax cmp ah,'Y' ; Is all OK? jne genr4 cmp pack.argbk1,0 ; Any data in the ACK? je genr31 ; Nope - just return. call dodec ; Decode data. mov di,offset data ; Where the reply is. mov cx,pack.argbk1 ; How much data we have. call prtscr ; Print it on the screen. mov flags.xflg,0 ; reset screen output flag before leaving genr31: xor ax,ax ; tell statistics this was a read call endtim ; tell statistics jmp rskp ; And we're done. genr4: cmp ah,'X' ; Text packet? je genr5 cmp ah,'S' ; Handling this like a file? jne genr6 mov pack.state,'R' ; Set the state. mov bx,offset rin21 ; Where to go to. jmp genr51 ; Continue. genr5: mov pack.state,'F' call dodec ; Decode data. mov bx,offset rfile3 ; Jump to here. genr51: mov flags.xflg,1 ; Remember we saw an "X" packet. mov pack.numtry,0 mov pack.numrtr,0 mov pack.numpkt,0 mov pack.pktnum,0 call bx ; Handle it almost like filename. call read2 ; Receive the rest. jmp r ; Oops, we failed. nop xor ax,ax ; tell statistics this was a read call endtim jmp rskp ; Done OK. genr6: cmp ah,'E' ; Error packet? je genr6x ; e = yes jmp genr1 ; Try again. genr6x: call dodec ; Decode data. call error1 ; Print the error messge. call serrst xor ax,ax ; tell statistics this was a read call endtim mov flags.xflg,0 ; reset screen output flag before leaving jmp rskp ; And return. GENRIC ENDP ; Send "I" packet with transmission parameters IPACK PROC NEAR call serini ; Initialize port call ihosts ; initialize the host mov pack.pktnum,0 ; Use packet number 0. mov pack.numtry,0 ; Number of retries. mov pack.numrtr,-1 ; no retries (incremented below) ipk0: call updrtr cmp pack.state,'A' ; Did user type a ^C? je ipk0x ; e = yes push dx mov dl,imxtry cmp pack.numtry,dl ; Reached our limit? pop dx jl ipk1 ; l = no ipk0x: ret ; Yes, so we fail. ipk1: inc pack.numtry ; Save the updated number of tries. mov bx,portval mov trans.ebquot,dqbin ; default 8 bit quote, needed with parity cmp [bx].parflg,parnon ; using parity = none locally? jne ipk1a ; ne = using local parity, need 8 bit quoting mov trans.ebquot,'Y' ; say can do 8 bit quoting, if they insist ipk1a: mov bx,offset data ; Get a pointer to our data block call rpar ; Set up the parameter information. xchg ah,al mov ah,0 mov pack.argbk1,ax ; Save the number of arguments. mov pack.argblk,0 ; Use packet number 0. mov ah,dtrans.seol ; restore default end-of-line char mov trans.seol,ah mov ah,trans.chklen mov curchk,ah ; Save real value. mov trans.chklen,1 ; One char for server function. call pktsize ; report packet size mov ah,'I' ; "I" packet. call spack ; Send the packet. jmp ipk4 nop call rpack ; Get a packet. jmp ipk4 ; Try again. nop push ax mov ah,curchk mov trans.chklen,ah ; Reset. pop ax cmp ah,'Y' ; ACK? jne ipk3 ; If not try next. mov ax,pack.pktnum ; Get the packet number. cmp ax,pack.argblk ; Is it the right packet number? je ipk2 jmp ipk0 ; If not try again. ipk2: mov ax,pack.argbk1 ; Get the number of pieces of data. mov bx,offset data ; Pointer to the data. ipk2a: call spar ; Read in the data. mov ah,trans.chklen mov curchk,ah ; This is what we decided on. call packlen ; Get max send packet size. mov pack.numtry,0 ; Reset the number of tries. jmp rskp ipk3: cmp ah,'N' ; NAK? jne ipk3y ; Yes, try again. jmp ipk0 ipk3y: cmp ah,'E' ; Is it an error packet. je ipk3x jmp ipk0 ; Trashed data. ipk3x: mov ax,0 ; Other side doesn't know about "I" packet. ; force defaults (zero length response) jmp ipk2a ; to use lowest common denominator ipk4: mov ah,curchk mov trans.chklen,ah ; Reset. cmp flags.cxzflg,0 ; did user say quit? jne ipk5 ; ne = yes, quit jmp ipk0 ; Keep trying. ipk5: ret IPACK ENDP ; Returns in AH the count of characters read in. ; in BX the updated pointer to the input buffer. INPUT PROC NEAR mov cl,0 ; Keep a count. mov inpbuf,bx ; Where to put data. mov comand.cmquiet,1 ; turn on quiet mode input0: call cmgetc ; get a character nicely cmp al,CR ; Done with input? jne input1 push cx ; save count mov ah,prstr mov dx,offset crlf int dos ; echo a carriage return pop cx mov ah,cl ; Return count in AH. mov comand.cmquiet,0 ; turn off quiet mode jmp r input1: cmp al,BS ; Backspace? je inpt11 cmp al,DEL ; Or delete? jne input3 inpt11: dec cl ; Don't include in char count. cmp cl,0 ; Backspaced too much? jns input2 ; No, is OK. mov ah,conout mov dl,bell int dos mov cl,0 jmp input0 input2: dec bx ; 'Remove' from buffer. jmp input0 ; Go get more. input3: cmp al,'U'-64 ; Control-U? jne input4 mov cl,0 ; Reset count to zero. mov bx,inpbuf ; Start at head of buffer. jmp input0 input4: mov [bx],al ; Add char to buffer. inc cl ; Include in count. inc bx jmp input0 INPUT ENDP ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. RSKP PROC NEAR pop bp add bp,3 push bp ret RSKP ENDP ; Jumping here is the same as a ret. R PROC NEAR ret R ENDP code ends end ; Jumping here is the same as a ret. R PROC NEAR ret R ENDP code ends end