PAGE 59, 132 TITLE MSSERV -- Module to handle all Server functions ; Update 20 Jan 86 IF1 %OUT >> Starting pass 1 ELSE %OUT >> Starting pass 2 ENDIF PUBLIC Logout, Bye, Finish, Remote, Get, Server, Enter_Server INCLUDE MsDefs.H DataS SEGMENT PUBLIC 'DataS' EXTRN data:byte, flags:byte, trans:byte, pack:byte, curchk:byte EXTRN fcb:byte, Data_2:BYTE, CurDsk:BYTE remcmd DB 0 ; Remote command to be executed. [21c] rempac DB 0 ; Packet type: C (host) or G (generic). [21c] ermes7 DB 'Unable to Receive Initiate$' erms18 DB '? Unable to tell host that session is finished',cr,lf,'$' erms19 DB '? Unable to tell host to logout',cr,lf,'$' erms21 DB '? Unable to tell host to execute command',cr,lf,'$' ; [21c] erms70 DB '? Unable to send INIT (I) packet',cr,lf,'$' infms1 DB cr,' Server: Waiting for request$' infms2 DB cr,' Getting: Waiting for file$' infms3 DB cr,' Getting: Sending request to remote server$' remms1 DB 'Remote ' Program_name db ': Unknown server command$' remms2 DB 'Remote ' Program_name db ': Illegal file name$' remms3 DB 'Remote ' Program_name db ': Unknown generic server command$' remms4 DB 'Remote ' Program_name db ': Unable to change directories$'; [jrd] pass DB 'Password: $' ; When changing remote directories crlf DB cr,lf,'$' tmp DB ?,'$' temp DW 0 oloc DW 0 ; Original buffer location. [21c] osiz DW 0 ; Original buffer size. [21c] inpbuf DW 0 ; Pointer to input buffer. [21c] cnt DW 0 delinp DB BS,BS,BS,' ',BS,BS,BS,'$' ; When DEL key is used. [21d] clrspc DB ' ', Bs, '$' ; Clear space srvchr DB 'SRGIE' ; server cmd characters srvfln EQU $-srvchr ; length of tbl srvfun DW srvsnd,srvrcv,srvgen,srvini,RSkp remhlp DB cr,lf,' CWD connect to a directory' ; [21c start] DB cr,lf,' DELETE a file' DB cr,lf,' DIRECTORY listing' DB cr,lf,' HELP' DB cr,lf,' HOST command' DB cr,lf,' SPACE in a directory' DB cr,lf,' TYPE a file$' ; [21c end] remtab DB 7 mkeyw 'CWD',remcwd mkeyw 'DELETE',remdel mkeyw 'DIRECTORY',remdir mkeyw 'HELP',remhel mkeyw 'HOST',remhos mkeyw 'SPACE',remdis mkeyw 'TYPE',remtyp remfnm DB ' Remote Source File: $' lclfnm DB ' Local Destination File: $' filhlp DB ' File name to receive as$' filmsg DB ' Remote file specification 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(?) DataS ENDS Code SEGMENT PUBLIC EXTRN comnd:near, spack:near, RPack:near, init:near EXTRN 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, PrtScr:NEAR EXTRN packlen:near, send11:near, errpack:near, init1:near EXTRN NAK:NEAR, rrinit:near, Error:near, Prompt:NEAR, Read1:NEAR EXTRN Close_transfer_screen:NEAR, Show_retries:NEAR EXTRN Do_CXZ_mode_line:NEAR, Show_error:NEAR, Show_status:NEAR ASSUME cs:Code, ds:DataS ; LOGOUT - tell remote KERSRV to logout LOGOUT PROC mov ah,cmcfm call comnd ; Get a confirm jmp r mov al, flags.remflg ; Pick up current value of remote flag push ax ; Save it mov flags.remflg, 1 ; Force us into remote mode for LOGOUT command call logo nop nop nop pop ax mov flags.remflg, al ; Restore original value jmp rskp LOGOUT ENDP LOGO PROC mov pack.numtry,0 ; Initialize count mov pack.numrtr,0 ; No retries yet call serini ; Initialize port. [14] mov ah,trans.chklen ; Don't forget the checksum length mov curchk,ah mov trans.chklen,1 ; Use one char for server functions logo1: cmp pack.state,'A' ; Did user type a ^C? je logo2x ; Yes just leave mov ah,pack.numtry cmp ah,maxtry ; Too many times? js logo3 ; No, try it logo2: mov ah,prstr mov dx,offset erms19 int dos logo2x: mov ah,curchk mov trans.chklen,ah ; Restore value ret logo3: inc pack.numtry ; Increment number of tries mov pack.argblk,0 ; Packet number zero mov pack.argbk1,1 ; One piece of data mov bx,offset data mov ah,'L' mov [bx],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 SHORT logo2 ; Tell user and die nop call RPack ; Get ACK (w/o screen msgs.) jmp SHORT logo1 ; Go try again nop push ax call dodec ; Decode packet mov ah,curchk mov trans.chklen,ah ; Restore value pop ax cmp ah,'Y' ; ACK? jne logo4 jmp rskp logo4: cmp ah,'E' ; Error packet? jnz logo1 ; Try sending the packet again jmp error1 LOGO ENDP ; FINISH - tell remote KERSRV to exit FINISH PROC mov ah,cmcfm ; Parse a confirm call comnd jmp r mov al, flags.remflg ; Pick up current value of remote flag push ax ; Save it mov flags.remflg, 1 ; Force us into remote mode for LOGOUT command mov pack.numtry,0 ; Initialize count mov pack.numrtr,0 ; No retries yet call serini ; Initialize port. [14] mov ah,trans.chklen ; Don't forget the checksum length mov curchk,ah mov trans.chklen,1 ; Use one char for server functions fin1: cmp pack.state,'A' ; ^C typed? je fin2x mov ah,pack.numtry cmp ah,maxtry ; Too many times? js fin3 ; Nope, try it fin2: mov ah,prstr mov dx,offset erms18 int Dos fin2x: mov ah,curchk mov trans.chklen,ah ; Restore value jmp SHORT fin5 ; Go home fin3: inc pack.numtry ; Increment number of tries mov pack.argblk,0 ; Packet number zero mov pack.argbk1,1 ; One piece of data mov bx,offset data mov ah,'F' mov [bx],ah ; Finish running Kermit mov cx,1 ; One piece of data call doenc ; Do encoding mov ah,'G' ; Generic command packet call spack jmp SHORT fin2 ; Tell user and die nop call RPack ; Get ACK (w/o screen stuff) jmp SHORT fin1 ; Go try again nop push ax call dodec ; Decode data mov ah,curchk mov trans.chklen,ah ; Restore value pop ax cmp ah,'Y' ; Got an ACK? jnz fin4 jmp SHORT fin5 ; Yes, then we're done fin4: cmp ah,'E' ; Error packet? jnz fin1 ; Try sending it again call error1 fin5: pop ax mov flags.remflg, al ; Restore original value jmp rskp FINISH ENDP ; BYE command - tell remote KERSRV to logout & exits to DOS BYE PROC mov ah,cmcfm ; Parse a confirm call comnd jmp r mov al, flags.remflg ; Pick up current value of remote flag push ax ; Save it mov flags.remflg, 1 ; Force us into remote mode for LOGOUT command call logo ; Tell the mainframe to logout jmp SHORT Bye_1 ; Don't exit yet nop ; 3 bytes mov flags.extflg,1 ; Set exit flag Bye_1: pop ax mov flags.remflg, al ; Restore original value jmp rskp BYE ENDP ; Tell remote server to send the specified file(s) Get PROC mov flags.droflg,0 ; Reset flags from fn parsing mov flags.nmoflg,0 ; Reset flags from fn parsing mov flags.cxzflg,0 ; no ctl-c typed yet.. mov bx,offset data ; Where to put text. [8 start] mov dx,offset filmsg ; In case user needs help mov ah,cmtxt call comnd ; Get text or confirm jmp RSkp ; Failed cmp ah,0 ; Read in any chars? jne get4 ; Yes, then OK ; Empty line, ask for file names Get1: mov dx,offset remfnm ; ask for remote first call prompt mov bx,offset data mov dx,offset frem mov ah,cmtxt call comnd ; get a line of text jmp RSkp cmp flags.cxzflg,'C' ; ctl-C typed? jne get2 ; no, continue jmp rskp get2: cmp ah,0 je get1 ; Ignore empty lines mov bl,ah mov bh,0 mov byte ptr data[bx],'$' ; terminate name for printing mov pack.argbk1,bx ; remember length here mov dx,offset lclfnm call prompt mov ah,cmifi mov bx,offset filhlp mov dx,offset fcb call comnd jmp RSkp mov ah,cmcfm call comnd jmp r cmp flags.cxzflg,'C' ; control-C typed? jne get3 ; no, keep going jmp rskp get3: mov flags.nmoflg,1 ; remember changed name jmp short get5 get4: mov al,ah mov ah,0 mov pack.argbk1,ax ; Remember number of chars we read mov byte ptr [bx],'$' ; use for printing get5: push cx ; Save regs push si push di mov cx, 5Ah ; Size of the Data and Data_2 buffers mov si, OFFSET Data ; Copy from ... mov di, OFFSET Data_2 ; Copy to ... rep movsb ; Copy from Data to Data_2 mov cx, Pack.ArgBk1 ; Pick up size of data packet mov Temp, cx ; Save it for a minute pop di ; Restore regs pop si pop cx call Init ; Clear line and initialize buffers mov dx, OFFSET InfMs3 ; Say we are sending a request for the file call Show_status ; Display the message call IPack ; Send our INITIATE params to the server jmp Get_error ; Couldn't do it push cx ; Save regs push si push di mov cx, Temp ; Get back size of data packet mov Pack.ArgBk1, cx ; Restore it mov cx, 5Ah ; Size of the Data and Data_2 buffers mov si, OFFSET Data_2 ; Copy from ... mov di, OFFSET Data ; Copy to ... rep movsb ; Copy from Data_2 back to Data area pop di ; Restore regs pop si pop cx call serini ; Initialize port mov pack.pktnum,0 ; Set packet number to zero mov pack.numtry,0 ; Initialize count mov pack.numpkt,0 ; Set the number of packets to zero mov pack.numrtr,0 ; No retries yet mov pack.state,'R' ; this is what state will soon be.. cmp flags.remflg,0 ; remote mode? jne get6 ; yes, don't print anything mov dx, OFFSET InfMs2 ; Say we are waiting for the file call Show_status ; Display the message call clrfln ; Prepare to print filename mov ah,prstr mov dx,offset data ; Print file name int dos get6: call init1 ; init buffers mov cx,pack.argbk1 ; Data size call doenc ; Encode data mov ah,trans.chklen ; Don't forget the checksum length mov curchk,ah mov trans.chklen,1 ; Use one char for server functions get7: cmp pack.state,'A' ; Did user type a ^C? je get9 ; Yes - just return to main loop call Show_retries ; Give a progress report cmp pack.numtry, imxtry ; Too many times? jb get10 ; Nope, try it Get8: mov dx, OFFSET ErMes7 ; Unable to Receive Initiate jmp SHORT Get8a ; Joint common code Get_error: mov dx, OFFSET erms70 ; Message to say we couldn't send INIT packet Get8a: call Show_error Get9: call Close_transfer_screen ; Erase mode line, go to lower left mov ah,curchk mov trans.chklen,ah ; Restore value jmp rskp ; Go home get10: inc pack.numtry ; Increment number of tries mov pack.argblk,0 ; Start at packet zero mov ah,'R' ; Receive init packet call spack ; Send the packet jmp SHORT get8 ; Tell user we can't do it nop call RPack ; Get ACK (w/o screen stuff) jmp SHORT Get11 ; Got a NAK - try again nop push ax mov ah,curchk mov trans.chklen,ah ; Restore value pop ax mov pack.argbk2,ax ; this is where rinit wants pkt type if getting mov flags.getflg,1 ; "Get" as vs "Receive" jmp Read1 ; go join read code Get11: inc Pack.NumRtr ; Bump number of retries jmp Get7 ; Go try again GET ENDP ; Server command Server PROC mov ah,cmcfm call comnd jmp r ; Pre-confirmed entry to Server Mode, enter from Terminal Emulation Mode Enter_Server: push es mov ax,ds mov es,ax ; address data segment mov al,flags.remflg ; get remote flag push ax ; preserve for later ; mov flags.remflg,1 ; set remote if server (Turn on server screen) mov Flags.NmOFlg, 0 ; Clear the name override flag ; (CMIFI leaves it set) mov Flags.DrOFlg, 0 ; Likewise for drive override call Init ; Clear screen, display template & mode line call serini ; Init serial port ; should reset to default parms here.. ; should increase timeout interval Serv1: mov trans.chklen,1 ; checksum len = 1 mov pack.pktnum,0 ; pack number resets to 0 mov pack.numtry,0 ; no retries yet mov dx, OFFSET infms1 ; Message is "Server: Waiting for request" call Show_status ; Display status call rpack ; Get a packet jmp SHORT Serv2 ; No good, NAK and continue nop jmp SHORT Serv3 ; Try to figure this out PUBLIC Serv2, Serv3 serv2: cmp Flags.CxzFlg, 'C' ; Control-C? je Serv5 ; Yes call nak ; nak the packet jmp serv1 ; and keep reading packets serv3: mov di,offset srvchr ; server characters mov cx,srvfln ; length of string mov al,ah ; packet type repne scasb ; hunt for it je serv4 ; we know this one, go handle it mov bx,offset remms1 ; else give a message call errpack ; back to local kermit jmp serv1 ; and keep looking 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.. call Do_CXZ_mode_line ; Called rtn trashed the mode line jmp serv1 ; Keep going for more cmds %OUT >> About half way through source file Serv5: call Close_transfer_screen ; Close out the file transfer screen pop ax ; get this off stack mov flags.remflg,al ; restore old flag pop es ; restore register jmp rskp ; and return Server ENDP ; *** Server Commands *** ; srvsnd - receives a file that the local kermit is sending srvsnd PROC mov bx,offset data call spar ; parse the send-init packet 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 ah,'Y' ; ack call spack ; answer them jmp rskp ; can't answer, forget this call rrinit ; init variables for init inc pack.pktnum ; count the send-init packet mov pack.state,'F' ; expecting file name about now call Read1 ; and join read code nop nop nop ; ignore errors jmp rskp ; and return for more SrvSnd endp ; srvrcv - send a file that they're receiving srvrcv PROC call DoDec ; Fix up the encoded filename mov si,offset data ; this should be it after decoding mov di,offset fcb ; this is where filename goes mov al,1 ; skip leading separators mov ah,prsfcb ; parse an fcb int dos ; let dos do the work cmp al,0ffh ; invalid? jne srvrc1 ; no, keep going mov bx,offset remms2 ; complain call errpack ; that we can't find it jmp rskp ; and return SrvRc1: cmp al, 1 ; Wildcards used? jne SrvRc2 ; No mov Flags.WldFlg, 0FFh ; Flag the wildcard SrvRc2: mov pack.state,'R' ; remember state call send11 ; this should send it nop nop nop jmp rskp ; return in any case SrvRcv ENDP PUBLIC SrvGen ; srvgen - generic server commands ; We only support Logout and Finish right now srvgen PROC call DoDec ; Decode the data packet mov al,data ; get 1st packet char cmp al, 'C' ; Remote CWD (Change Working Directory)? jne srvge0 ; No call Remote_CWD ; Use other routine to do the CWD jmp RSkp ; Return normally srvge0: cmp al,'F' ; maybe finish? je srvge1 ; yup, handle cmp al,'L' ; logout? jne srvge2 ; no srvge1: mov pack.argbk1,0 ; 0-length data mov ah,'Y' call spack ; ack it nop nop nop ; *** ignore error? ret ; and return to signal exit srvge2: mov bx,offset remms3 call errpack jmp rskp srvgen endp PUBLIC Remote_CWD ; Do a REMOTE CWD for the other Kermit Remote_CWD PROC mov cl, data+1 ; get the filename byte count sub cl, ' ' ; ascii to numeric cmp cl, 0 ; anything there? jle srcwd3 ; le = no, an error sub ch, ch ; set up counter mov si, OFFSET data+2 ; received dir spec, from rpack mov di, OFFSET srvbuf ; destination rep movsb ; copy data to srvbuf, cx chars worth 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. jmp errpack ; send the bad news, ret from there 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 call spack ; Send the packet nop nop nop ret ; Done here Remote_CWD ENDP ; srvini - init parms based on init packet srvini PROC mov bx,offset data call spar ; parse info call packlen ; this should really be part of spar, but.. mov bx,offset data call rpar ; get receive info mov al,ah mov ah,0 mov pack.argbk1,ax ; set size of return info mov ah,'Y' call spack ; send the packet off jmp rskp jmp rskp ; and go succeed srvini endp ; This is the REMOTE command. [21c] REMOTE PROC mov dx,offset remtab ; Parse a keyword from the REMOTE table mov bx,offset remhlp mov ah,cmkey call comnd jmp r mov al, flags.remflg ; Pick up current value of remote flag push ax ; Save it mov flags.remflg, 1 ; Force us into remote mode for LOGOUT command call bx ; Call the appropriate routine nop ; Tolerate skip and non-skip returns nop nop pop ax mov flags.remflg, al ; Restore original value jmp rskp REMOTE ENDP ; REMDIS - Get disk usage on remote system. [21c] REMDIS PROC 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. [21c] REMHEL PROC mov remcmd,'H' ; Help..... mov rempac,'G' ; Packet type = generic jmp genric ; Execute generic Kermit command REMHEL ENDP ; REMTYP - Print a remote file. [21c] REMTYP PROC mov remcmd,'T' ; Type the file mov rempac,'G' ; Packet type = generic jmp genric REMTYP ENDP ; REMHOS - Execute a remote host command. [21c] REMHOS PROC mov remcmd,' ' ; Don't need one mov rempac,'C' ; Packet type = remote command jmp genric REMHOS ENDP ; REMDIR - Do a directory. [21c] REMDIR PROC mov remcmd,'D' mov rempac,'G' ; Packet type = generic jmp genric REMDIR ENDP ; REMDEL - Delete a remote file. [21c] REMDEL PROC mov remcmd,'E' mov rempac,'G' ; Packet type = generic jmp genric REMDEL ENDP ; REMCWD - Change remote working directory. [21c] REMCWD PROC mov remcmd,'C' mov rempac,'G' ; Packet type = generic ; jmp genric REMCWD ENDP ; GENRIC - Send a generic command to a remote Kermit server. [21c] GENRIC PROC mov bx,offset SrvBuf ; Where to put the text cmp rempac,'C' ; Remote host command? je genra ; Yes, leave as is 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 cmp rempac,'C' ; Remote host command? jne genrb ; No, skip this part call ipack jmp genr2 mov pack.numtry,0 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 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 genr0a ; 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 genr0a: push ax ; Save ax mov ah, PrStr ; Code to type a string mov dx, OFFSET CrLf ; A CrLf int Dos ; Type it pop ax ; Get back ax genr0: inc al ; For the char representing the command 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 SHORT 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? js genr3 ; Nope, keep trying genr2: mov ah,prstr mov dx,offset erms21 ; Print error msg and fail int dos genr2x: mov ah,curchk mov trans.chklen,ah ; Restore jmp rskp genr3: push es ; Prepare to put string into packet mov ax,ds mov es,ax mov si,offset SrvBuf ; Move from here mov di,offset data ; to here mov cx,cnt ; Move this many characters 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 pack.argblk,0 ; Packet number 0 mov ah,rempac ; Packet type call spack ; Send the packet jmp genr2 ; Tell user we can't do it nop call RPack ; Get ACK (w/o screen stuff) jmp genr1 ; Got a NAK - try again nop push ax mov ah,curchk mov trans.chklen,ah ; Restore 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 ah,prstr mov dx,offset crlf ; First go to a new line 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 mov ah,prstr mov dx,offset crlf ; Go to a new line int dos mov ah,prstr mov dx,offset crlf ; Go to a new line int dos genr31: 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 PUBLIC genr4,genr5,genr51,genr6 genr51: mov tmp,ah ; Save packet type 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 mov flags.cxzflg,0 mov ah,tmp ; Packet type call bx ; Handle it almost like filename call read2 ; Receive the rest jmp r ; Oops, we failed jmp rskp ; Done OK genr6: cmp ah,'E' ; Error packet? je genr6x jmp genr1 ; Try again genr6x: call dodec ; Decode data call error1 ; Print the error messge jmp rskp ; And return GENRIC ENDP ; Send "I" packet with transmission parameters. [21c] IPACK PROC NEAR mov ah,trans.chklen mov curchk,ah ; Initialize call serini mov pack.pktnum,0 ; Use packet number 0 mov pack.numtry,0 ; Number of retries ipk0: cmp pack.state,'A' ; Did user type a ^C? je ipk0x cmp pack.numtry,imxtry ; Reached our limit? jl ipk1 ipk0x: ret ; Yes, so we fail ipk1: inc pack.numtry ; Save the updated number of tries 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,trans.chklen mov curchk,ah ; Save real value mov trans.chklen,1 ; One char for server function 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 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. [21b] mov pack.numtry,0 ; Reset the number of tries jmp rskp ipk3: cmp ah,'N' ; NAK? je ipk0 ; Yes, try again cmp ah,'E' ; Is it an error packet je ipk3x jmp ipk0 ; Trashed data ipk3x: jmp rskp ; Other side doesn't know about "I" packet ipk4: mov ah,curchk mov trans.chklen,ah ; Reset jmp ipk0 ; Keep trying IPACK ENDP ; Returns in AH the count of characters read in ; in BX the updated pointer to the input buffer INPUT PROC mov cl,0 ; Keep a count mov inpbuf,bx ; Where to put data input0: mov ah,conin ; Read in a char int dos cmp al,CR ; Done with input? jne input1 mov ah,cl ; Return count in AH jmp r input1: cmp al,BS ; Backspace? je inpt11 ; cmp al,DEL ; Or delete? jne input3 call dodel ; Erase weird character inpt11: dec cl ; Don't include in char count cmp cl,0 ; Backspaced too much? jns input2 ; No, is OK push bx call clearl pop bx mov ah,conout mov dl,bell int dos mov cl,0 jmp input0 input2: dec bx ; 'Remove' from buffer mov ah,prstr mov dx,offset clrspc int dos jmp input0 ; Go get more input3: cmp al,'U'-64 ; Control-U? jne input4 mov ah,prstr mov dx,offset pass+1 int dos push bx push cx call clearl ; Blank out the line pop cx pop bx mov cl,0 ; Reset count to zero mov bx,inpbuf ; Start at head of buffer jmp input0 input4: cmp al,0 ; Two character sequence? jne input5 mov ah,conin int dos ; Get second char cmp al,83 ; Delete key? je inpt40 ; Yup cmp al,75 ; Backarrow key? je inpt40 call dodel ; Erase weird character jmp input0 ; And go on computing inpt40: mov ah,prstr mov dx,offset delinp ; Erase weird character int dos jmp inpt11 ; Remove the offending char input5: 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