home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
01e
/
msk230s1.zip
/
MSSSEN.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-12
|
59KB
|
1,235 lines
NAME msssen
; File MSSSEN.ASM
; Edit history:
; Last edit: 1 Jan 1988
; 1 Jan 1988 version 2.30
; 26 Dec 1987 clean ups [jrd]
; 8 Oct 1987 Ensure error pkts use 1 byte chksum at init stage. [jrd]
; 21 Sept 1987 Add error return to doenc for filenames too long for pkt. [jrd]
; 6 July 1987 Fix bug of 9 Dec below for case of short S/I packets. [jrd]
; 27 June 1987 Correct statistics gathering for last file. [jrd]
; 7 June 1987 Return DOS errlev of 1 if sending fails. [jrd]
; 24 May 1987 Add Delay seconds before starting local Send file. [jrd]
; 7 May 1987 Add statistics gathering functions. [jrd]
; 9 Dec 1986 Version 2.29a
; 9 Dec 1986 Add final check on packet length in Spar to avoid sending
; packets longer than the local user wishes. [jrd]
; 5 Sept 1986 minor cleanup in spar regular pkt size calculation. [jrd]
; 14 August 1986 Fix Send/Receive EOL, padding, pad-char [rjd]
; 3 August 86 modify for long packets, fix 8 bit quoting negotiations. [jrd]
; 26 May 1986 Revise code to permit serial display. [jrd]
; Also, remove case conversion of "as" filename being sent. [rjd]
; [2.29] code frozen on 6 May 1986 [jrd]
public spar, rpar, error, error1, nout, send, flags, trans, pack
public dodec, doenc, curchk, inichk, packlen, send11, dtrans
include mssdef.h
spmin equ 20 ; Minimum packet size.
spmax equ 94 ; Maximum packet size.
datas segment public 'datas'
extrn buff:byte, data:byte, filbuf:byte, fsta:word
extrn decbuf:byte, chrcnt:word, bufpnt:word, errlev:byte
extrn rptq:byte, origr:byte, rptct:byte, rptval:byte
extrn diskio:byte, maxtry:byte, imxtry:byte, portval:word
flags flginfo <>
trans trinfo <>
dtrans trinfo <> ; default trans info
pack pktinfo <>
crlf db cr,lf,'$'
ender db bell,bell,'$'
erms14 db '?Unable to receive an acknowledgment from the host$'
erms15 db '?Unable to find file$'
erms20 db 'Unable to send init packet$'
erms21 db 'Unable to send file header$'
erms22 db 'Unable to send data$'
erms23 db 'Unable to send end-of-file packet$'
erms24 db 'Unable to send break packet$'
infms2 db cr,' Sending: In progress',cr,lf,'$'
infms3 db 'Completed',cr,lf,'$'
infms4 db 'Failed',cr,lf,'$'
infms6 db 'Interrupted$'
remmsg1 db 'Kermit-MS: File not found$'
filhlp db ' A filename (possibly wild) $'
filmsg db ' Local Source File or a carriage return $'
remfnm db ' Remote Destination File: $'
lclfnm db ' Local Source File: $'
curchk db 0 ; Use to store checksum length.
inichk db 1 ; Original or set checksum length.
siz dw ? ; Size of data from gtchr.
difsiz dw 0 ; Size of new exported file name.
sendas dw 50 dup(0) ; Buffer for file name.
temp dw 0
temp4 dw 0
asmsg db ' as $'
filopn db 0 ; Says if disk file is open.
ninefive dw 95 ; constant word for long packets
datas ends
code segment public 'code'
extrn serini:near, serrst:near, comnd:near, init:near
extrn spack:near, rpack:near, gtnfil:near, gtchr:near
extrn getfil:near, clrfln:near, nppos:near, rprpos:near
extrn erpos:near, rtpos:near, cxmsg:near, stpos:near, decout:near
extrn encode:near, nulref:near, decode:near, nulr:near
extrn errpack:near, updrtr:near, clrmod:near, prompt:near
extrn prtfn:near, strcpy:near, strlen:near, pktsize:near
extrn pcwait:near, ihosts:near, begtim:near, endtim:near
assume cs:code, ds:datas
; This routine sets up the data for init packet (either the
; Send_init or ACK packet).
; trans.rxxx are items we are prepared to receive
RPAR PROC NEAR
mov ah,trans.rpsiz ; Get the receive packet size.
add ah,' ' ; Add a space to make it printable.
mov [bx],ah ; Put it in the packet.
mov ah,trans.rtime ; Get the receive packet time out.
add ah,' ' ; Add a space.
mov 1[bx],ah ; Put it in the packet.
mov ah,trans.rpad ; Get the number of padding chars.
add ah,' '
mov 2[bx],ah ; Put it in the packet.
mov ah,trans.rpadch ; Get the padding char.
add ah,40h ; Uncontrol it.
and ah,7FH
mov 3[bx],ah ; Put it in the packet.
mov ah,trans.reol ; Get the EOL char.
add ah,' '
mov 4[bx],ah ; Put it in the packet.
mov ah,trans.rquote ; Get the quote char.
mov 5[bx],ah ; Put it in the packet.
mov ah,trans.ebquot ; Get 8-bit quote char.
mov 6[bx],ah ; Add it to the packet.
mov ah,trans.chklen ; Length of checksum.
add ah,48 ; Make into a real digit.
mov 7[bx],ah
mov ah,rptq ; Repeat quote char.
cmp ah,0 ; Null means no.
jne rpar0
mov ah,' ' ; Send a blank instead.
rpar0: mov 8[bx],ah
; begin long packet changes
mov ah,02h ; CAPAS, bit1 = can do long packets
add ah,20h ; apply tochar() to byte
mov 9[bx],ah ; add to packet
; additional CAPAS go in here
mov ah,20h ; WINDO field, null applied through tochar()
mov 10[bx],ah ; put into packet
push ax ; save some regs
push dx
mov ax,trans.rlongp ; long packet length which we can receive
xor dx,dx ; clear extended part for division
div ninefive ; divide by 95. quo = ax, rem = dx
add al,20h ; apply tochar() to quotient
mov 11[bx],al ; add to packet
add dl,20h ; apply tochar() to remainder
mov 12[bx],dl ; add to packet
pop dx ; restore regs
pop ax
mov ah,13 ; 13 bytes of data
ret
RPAR ENDP
; This routine reads in all the send init packet information.
; Enter with BX/ packet address, AX/ packet length
; This could probably be done much more legibly if it were table
; driven, but I'm afraid to touch it...
;
; dtrans.xxx are the default parameters if the other side says nothing.
; trans.sxxx are the active negotiated parameters we will use for sending.
SPAR PROC NEAR
mov temp4,ax ; Save the number of arguments
cmp ax,1
jge spara ; ge = want more than bare minimum
mov ah,dspsiz ; Data not supplied by host, use default
jmp short sparc
spara: mov ah,[bx] ; Get the max packet size.
sub ah,' ' ; Subtract a space.
cmp ah,spmin ; Can't be below the minimum.
jge sparb
mov ah,spmin
jmp short sparc
sparb: cmp ah,spmax ; Or above the maximum.
jle sparc
mov ah,spmax
sparc: mov trans.spsiz,ah ; Save it.
mov ax,temp4
mov ah,dtrans.stime ; pick up default stime
cmp al,2 ; Fewer than two pieces?
jl spar02 ; yes, use default
spar0: cmp ah,dstime ; Is current value the default?
jne spar02 ; No, assume changed by user.
mov ah,1[bx] ; Get the timeout value.
sub ah,' ' ; Subtract a space.
cmp ah,0
ja spar01 ; Must be non-negative.
mov ah,0
spar01: cmp ah,trans.rtime ; Same as other side's timeout.
jne spar02
add ah,5 ; If so, make it a little different.
spar02: mov trans.stime,ah ; Save it.
mov ax,temp4
mov ah,dtrans.spad ; get default send padding
cmp al,3 ; Fewer than three pieces?
jl spar11 ; yes, use default
spar1: mov ah,2[bx] ; Get the number of padding chars.
sub ah,' '
cmp ah,0
jge spar11 ; Must be non-negative.
mov ah,0
spar11: mov trans.spad,ah
mov ax,temp4
mov ah,dtrans.spadch ; pick up default send pad character
cmp al,4 ; Fewer than four pieces?
jl spar21
spar2: mov ah,3[bx] ; Get the padding char.
add ah,40h ; Re-controlify it.
and ah,7FH
cmp ah,del ; Delete?
je spar21 ; Yes, then it's OK.
cmp ah,0
jge spar20
mov ah,0 ; Below zero is no good.
jmp spar21 ; Use zero (null).
spar20: cmp ah,31 ; Is it a control char?
jle spar21 ; Yes, then OK.
mov ah,0 ; No, use null.
spar21: mov trans.spadch,ah
mov ax,temp4
mov ah,dtrans.seol ; get default send eol char
cmp al,5 ; Fewer than five pieces?
jl spar31 ; yes, use default
spar3: mov ah,4[bx] ; Get the EOL char.
sub ah,' '
cmp ah,0
jge spar30 ; Cannot be negative.
mov ah,cr ; If so, use default of carriage return
jmp spar31
spar30: cmp ah,31 ; Is it a control char?
jle spar31 ; Yes, then use it.
mov ah,cr ; Else, use the default.
spar31: mov trans.seol,ah
mov ax,temp4
mov ah,dtrans.squote ; send quote
cmp al,6 ; Fewer than six pieces?
jl spar41
spar4: mov ah,5[bx] ; Get the quote char.
cmp ah,' ' ; Less than a space?
jge spar40
mov ah,dsquot ; Yes, use default.
jmp spar41
spar40: cmp ah,7eh ; Must also be less than a tilde.
jle spar41
mov ah,dsquot ; Else, use default.
spar41: mov trans.squote,ah
cmp al,7 ; Fewer than seven pieces?
jge spar5
mov trans.ebquot,'Y' ; Data not supplied by host, use default
jmp short spar51
spar5: mov ah,6[bx] ; Get other sides 8-bit quote request
call doquo ; And set quote char.
spar51: cmp al,8 ; Fewer than eight pieces?
jge spar6
mov trans.chklen,1
jmp short spar61
spar6: mov ah,inichk
mov trans.chklen,ah ;Checksum length we really want to use
mov ah,7[bx] ; Get other sides checksum length.
call dochk ; Determine what size to use.
spar61: cmp al,9 ; Fewer than nine pieces?
jge spar7
mov rptq,0
jmp short spar71
spar7: mov ah,8[bx] ; Get other sides repeat count prefix.
mov ch,drpt
mov rptq,0
call dorpt
;;; begin long packet changes - update this for strict ELP protocol
spar71: mov ah,0 ; get default operating capabilities
cmp al,10 ; 10 or more pieces?
jl spar81 ; l = no
mov ah,9[bx] ; get capas bitmap from other side
sub ah,20h ; apply unchar()
call decapa ; negotiate them back into ah
spar81: mov trans.capas,ah ; store result in active byte
mov ah,0 ; setup default window size
cmp al,11 ; 11 or more pieces?
jl spar9 ; l = no, use default
mov ah,10[bx] ; get other side's window size
sub ah,20h ; apply unchar()
call dewind ; negotiate window size back into ah
spar9: mov trans.windo,ah ; store it
; decode window info
push cx ; save a reg
xor ch,ch
mov cl,trans.spsiz ; normal packet size
mov trans.slongp,cx ; assume not using long packets
pop cx ; restore reg
cmp al,13 ; 13 or more pieces (long packet needs two)?
jae spar9d ; ae = more to look at
mov ax,trans.slongp ; put above size in ax for final checks
push ax
jmp spar9a ; do final checks (they want longer than us)
spar9d: test trans.capas,2 ; do they have long packet capability?
jz sparx ; z = no, skip following lp length fields.
push ax ; save al
xor ah,ah
mov al,11[bx] ; long packet length, high order byte
sub al,20h ; apply unchar()
mul ninefive ; times 95 to dx(hi),ax(lo)
mov trans.slongp,ax ; store that much
xor ah,ah
mov al,12[bx] ; long packet length, low order byte
sub al,20h ; apply unchar()
add ax,trans.slongp ; plus high order part
mov trans.slongp,ax ; store it
or ax,ax ; if result is zero then use regular packets
jnz spar9a ; non-zero, use what they want
mov ah,0
mov al,trans.spsiz ; default to regular packet size
mov trans.slongp,ax ; and ignore the CAPAS bit (no def 500 bytes)
spar9a: cmp ax,trans.slong ; longer than we want to do?
jbe spar9b ; be = no
mov ax,trans.slong ; limit to our longest sending size
mov trans.slongp,ax ; and use it
spar9b: cmp ax,94 ; shorter than normal packet too?
ja spar9c ; a = no
mov trans.spsiz,al ; update normal packet size, again.
spar9c: pop ax ; recover al
sparx: ret
SPAR ENDP
; Set 8-bit quote character based on my capabilities and the other
; Kermit's request.
DOQUO PROC NEAR
cmp trans.ebquot,'N' ; Can I do 8-bit quoting at all?
je dq3 ; No - so forget it.
cmp trans.ebquot,'Y' ; Can I do it if requested?
jne dq0 ; No - it's a must that I do it.
mov trans.ebquot,ah ; Do whatever he wants.
jmp dq1
dq0: cmp ah,'Y' ; I need quoting - can he do it?
je dq1 ; Yes - then all is settled.
cmp ah,'N' ; No - then don't quote.
je dq3
cmp ah,trans.ebquot ; Both need quoting - chars must match
jne dq3
dq1: mov ah,trans.ebquot
cmp ah,'Y' ; If Y or N, don't validate prefix.
je dq2
cmp ah,'N'
je dq2
call prechk ; Is it in range 33-62, 96-126?
mov ah,'Y' ; Failed, don't do quoting.
nop
cmp ah,trans.rquote ; Same prefix?
je dq3 ; Not allowed, so don't do quoting.
cmp ah,trans.squote ; Same prefix here?
je dq3 ; This is illegal too.
mov trans.ebquot,ah ; Remember what we decided on.
dq2: ret
dq3: mov trans.ebquot,'N' ; Quoting will not be done.
ret
DOQUO ENDP
; Check if prefix in AH is in the proper range: 33-62, 96-126.
; RSKP if so else RETURN.
prechk: cmp ah,33
jge prec0 ; It's above 33.
ret
prec0: cmp ah,62
jg prec1
jmp rskp ; And below 62. OK.
prec1: cmp ah,96
jge prec2 ; It's above 96.
ret
prec2: cmp ah,126
jg prec3
jmp rskp ; And below 126. OK.
prec3: ret
; Set checksum length.
dochk: cmp ah,'1' ; Must be 1, 2, or 3.
jl doc1
cmp ah,'3'
jle doc2
doc1: mov ah,'1'
doc2: sub ah,48 ; Don't want it printable.
mov trans.chklen,ah ; other side's request is do-able here
cmp ah,trans.chklen ; Do we want the same thing?
je dochk0 ; Yes, then we're done.
mov trans.chklen,1 ; No, use single character checksum.
dochk0: ret ; Just return for now.
; Set repeat count quote character. The one used must be different than
; the control and eight-bit quote characters. Also, both sides must
; use the same character.
dorpt: call prechk ; Is it in the valid range?
mov ah,0 ; No, don't use their value.
nop
cmp ah,trans.squote ; Same as the control quote char?
je dorpt0 ; Yes, that's illegal, no repeats.
cmp ah,trans.rquote ; How about this one?
je dorpt0 ; No good.
cmp ah,trans.ebquot ; Same as eight bit quote char?
je dorpt0 ; Yes, that's illegal too, no repeats.
cmp ah,ch ; Are we planning to use same char?
jne dorpt0 ; No, that's no good either.
mov rptq,ch ; Use repeat quote char now.
dorpt0: ret
; negotiate capas byte in ah
decapa: ret ; nothing for now
; negotiate window size in ah
dewind: xor ah,ah ; no windowing at our end
ret
; Send command
SEND PROC NEAR
mov difsiz,0 ; Assume we'll use original filename.
mov byte ptr sendas,0 ; clear sendas name (in case none)
mov ah,cmfile ; get an input file spec
mov dx,offset diskio.string ; address of filename string
mov bx,offset filmsg ; Text of help message.
call comnd
jmp r ; Give up on bad parse.
cmp flags.cxzflg,0 ; ^X, ^Z, ^C typed?
je send0 ; e = no, continue
or errlev,1 ; say send failed
jmp rskp ; yes, quit
send0: cmp ah,0 ; any text given?
ja send0c ; a = yes
mov dx,offset lclfnm ; prompt for local filename
call prompt
mov dx,offset diskio.string ; reload destination of user's text
mov bx,offset filhlp ; help file
mov ah,cmfile ; allow paths
call comnd ; try again for a local filename
jmp r
cmp flags.cxzflg,0 ; ^X, ^Z, ^C typed?
je send0a ; e = no, continue
or errlev,1 ; say send failed
jmp rskp ; yes, quit
send0a: cmp ah,0 ; user's byte count
jne send0b ; something was typed
jmp r ; else return (gives "not confirmed" msg)
send0b: mov dx,offset remfnm ; ask for remote name first
call prompt
send0c: mov bx,offset sendas ; See if want to send file under dif name
mov dx,offset filhlp ; In case user needs help.
mov ah,cmtxt ; allow embedded white space
call comnd
jmp r
cmp flags.cxzflg,0 ; ^X, ^Z, ^C typed?
je send1 ; e = no, continue
or errlev,1 ; say send failed
jmp rskp ; yes, quit
send1: mov al,ah ; store count of user's chars.
mov ah,0
mov difsiz,ax ; Remember length of new name.
mov bx,offset sendas ; 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
send1c: cmp byte ptr [si],0 ; at terminator?
je send1d ; e = yes
cmp byte ptr [si],' ' ; text (greater than space)?
ja send1d ; a = yes.
inc si ; look at next char
jmp send1c ; look some more
send1d: cmp bx,si ; did we find leading whitespace?
je send1e ; e = no
mov di,bx ; place to copy chars
call strcpy ; from ds:si to ds:di
send1e: mov dx,bx ; address of string
call strlen ; get its new length (returned in cx)
mov difsiz,cx ; store it
pop si
pop di
pop es
mov ah,trans.sdelay ; seconds to delay before sending
shl ah,1 ; times 4*256 to get millisec
shl ah,1 ; for pcwait
mov al,1 ; set low byte to 1 for no delay case
call pcwait ; wait number of millisec in ax
mov flags.xflg,0 ; Reset flag for normal file send[mtd]
mov flags.cxzflg,0 ; clear interrupt flag too.
mov bx,offset diskio.string
cmp byte ptr [bx],'#' ; Is first char a replacement for '?'?
jne send1f ; ne = no
mov byte ptr [bx],'?' ; yes. Change '#' for '?'
send1f: mov bx,offset sendas
cmp byte ptr [bx],'#' ; Is first char a replacement for '?'?
jne snd11a
mov byte ptr [bx],'?' ; yes. Change '#' for '?'
jmp snd11a
; SEND11 is an entry point for REMote cmds.
SEND11: mov flags.nmoflg,0 ; Reset flags from fn parsing.
mov difsiz,0 ; clear any old 'sendas' filespec
snd11a: mov ah,setdma ; set dta address
mov dx,offset diskio.dta
int dos
mov ah,first2 ; search for first
mov cx,0 ; consider only regular files
mov dx,offset diskio.string ; full filename, inc paths
int dos
pushf ; save flags
push dx
mov ah,setdma ; restore dta to offset buff
mov dx,offset buff
int dos
pop dx
popf ; restore flags
jnc send16 ; carry reset = file found
cmp pack.state,'R' ; was this from a remote GET?
jne sen11a ; no, print error and continue
mov bx,offset remmsg1 ; else get error message
mov ah,trans.chklen
mov curchk,ah ; Store checksum length we want to use
mov trans.chklen,1 ; Send init checksum is always 1 char.
call errpack ; go complain
mov ah,curchk
mov trans.chklen,ah ; Checksum length we want to use.
jmp abort ; and abort this
sen11a: mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr
mov dx,offset erms15 ; '?Unable to find file'
int dos
or errlev,1 ; set DOS error level
mov ax,1 ; tell statistics this was a send operation
call endtim ; stop statistics counter
jmp rskp ; pretend successful completion
send16: call serini ; Initialize serial port
mov ax,1 ; say this is a send operation
call endtim ; get tod for end of transfer
call begtim ; get tod for start of transfer
mov pack.pktnum,0 ; Set the packet number to zero.
mov pack.numtry,0 ; Set the number of tries to zero.
mov pack.numpkt,0 ; Set the number of packets to zero.
mov pack.numrtr,0 ; Set the number of retries to zero.
mov pack.state,'S' ; Set the state to receive initiate.
call ihosts ; initialize the host (clear NAKs)
call init ; Clear the line and initialize the buffers.
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jnz send2 ; nz = yes, suppress 0 retry msg
call stpos ; Print status of file transfer.
mov ah,prstr ; Be informative.
mov dx,offset infms2
int dos
send18: test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jnz send2 ; nz = yes, suppress 0 retry msg
call rtpos ; Position cursor.
mov ax,0 ; set retry counts to zero
call nout ; Write the number of retries.
send2: call nppos ; Number of packets sent.
mov ax,pack.numpkt
call nout ; Write the packet number.
cmp pack.state,'D' ; Are we in the data send state?
jne send3 ; ne = no
call sdata ; send data
jmp send2
send3: cmp pack.state,'F' ; Are we in the file send state?
jne send4
call sfile ; Call send file.
jmp send2
send4: cmp pack.state,'Z' ; Are we in the EOF state?
jne send5
call seof
jmp send2
send5: cmp pack.state,'S' ; Are we in the send initiate state?
jne send6
call sinit
jmp send2
send6: cmp pack.state,'B' ; Are we in the eot state?
jne send7
call seot
jmp send2
; Completion processor section
send7: push ax
mov ax,1 ; tell statistics this was a send operation
call endtim ; stop statistics counter
call serrst ; Reset serial port.
pop ax
mov dx,offset infms3 ; Completed message
cmp pack.state,'C' ; Are we in the send complete state?
je send8 ; e = yes, else failure
mov dx,offset infms4 ; Failed message
or errlev,1 ; say send failed
send8: cmp flags.cxzflg,0 ; completed normally?
jne send8b ; ne = no, don't bother with this
or errlev,1 ; say send failed
send8b: test flags.remflg,dquiet ; quiet display mode?
jnz send8f ; nz = yes, no printing.
test flags.remflg,dserial ; serial display mode?
jnz send8c ; nz = yes, skip positioning
push dx
call stpos
pop dx
send8c: mov ah,prstr
cmp flags.cxzflg,0 ; Completed or interrupted?
je send8d ; e = no interruption
mov dx,offset infms6 ; Say transfer was interrupted.
send8d: int dos
cmp flags.belflg,0 ; Bell desired?
je send8e ; e = no
mov dx,offset ender ; Ring them bells.
int dos
send8e: test flags.remflg,dserial ; serial display mode?
jnz send8f ; nz = yes, no cursor positioning
call clrmod
call rprpos
send8f: jmp rskp
SEND ENDP
; Send routines
; Send initiate
SINIT PROC NEAR
mov dl,imxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl sinit2 ; l = no
test flags.remflg,dquiet ; quiet display mode?
jnz sinit1 ; nz = yes. Don't write to screen.
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
sinit1: mov ah,trans.chklen
mov curchk,ah ; Store checksum length we want to use
mov trans.chklen,1 ; Send init checksum is always 1 char.
mov bx,offset erms20
call errpack ; Send error packet just in case.
mov ah,curchk
mov trans.chklen,ah ; Checksum length we want to use.
jmp abort ; Change the state to abort.
sinit2: 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,dtrans.seol ; restore default end-of-line char
mov trans.seol,ah
mov ah,0
mov pack.argbk1,ax ; Save the number of arguments.
mov ax,pack.numpkt ; Get the packet number.
mov pack.argblk,ax
mov trans.ebquot,'Y' ; say we can do 8 bit quoting
push bx
mov bx,portval
cmp [bx].parflg,parnon ; using parity=none locally?
pop bx
je sinit2a ; e = no parity
mov trans.ebquot,dqbin ; def 8 bit quot, needed with parity
sinit2a:mov ah,trans.chklen
mov curchk,ah ; Store checksum length we want to use
mov trans.chklen,1 ; Send init checksum is always 1 char.
call pktsize ; report packet size
mov ah,'S' ; Send initiate packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp sini23 ; Trashed packet don't change state, retry.
push ax
mov ah,curchk
mov trans.chklen,ah ; Checksum length we want to use.
pop ax
call acknak ; was it ok?
cmp al,0 ; maybe an ack?
je sini22 ; yes, go handle it
cmp al,1 ; maybe a nak?
jne sinit4 ; no, check for error or something
ret ; else just return and try again
sini22: mov ax,pack.argbk1
mov bx,offset data ; point to data for spar
call spar ; Read in the data.
call packlen ; Get max send packet size.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.state,'F' ; Set the state to file send.
call getfil ; Open the file.
jmp abort ; Something is wrong, die.
mov filopn,1 ; Disk file is open.
ret
sini23: mov ah,curchk ; Restore desired checksum length.
mov trans.chklen,ah
call updrtr ; Update retry counter.
ret ; And retry.
sinit4: cmp ah,'E' ; Is it an error packet.
jne sinit5
call error
sinit5: jmp abort
SINIT ENDP
; Send file header
SFILE PROC NEAR
mov dl,maxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl sfile1 ; l = no
test flags.remflg,dquiet ; quiet display mode?
jnz sfile0 ; nz = yes. Don't write to screen
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
sfile0: mov bx,offset erms21
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
sfile1: inc pack.numtry ; Increment it.
mov flags.cxzflg,0 ; Clear ^X,^Z flag.
mov si,offset diskio.fname ;addr of asciiz filename without paths
mov di,offset data ; destination
call strcpy ; copy filename there
push dx
mov dx,offset data
call strlen ; get length (w/o terminator) into cx
pop dx
mov ch,0
test flags.remflg,dquiet ; quiet display mode?
jnz sfil13 ; nz = yes, no printing.
call prtfn ; print filename in data
sfil13: call newfn ; show possible new filename, put length in cx
call doenc ; Do encoding; length is in cx.
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov ah,'F' ; File header packet.
cmp flags.xflg,0 ; remote display requested?
je sfl13y ; e = no
mov ah,'X' ; use X rather than F packet for remote
sfl13y: call pktsize ; report packet size
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Do all decoding.
call acknak ; see what they had to say
cmp al,0 ; ack'd ok?
je sfil14 ; yes, on to next state
cmp al,1 ; maybe a nak?
jne sfile3 ; no, check for error
ret ; if nak, just return and try again
sfil14: mov flags.filflg,0FFH ; Indicate file buffer empty.
call gtchr
jmp sfil16 ; Error go see if its EOF.
nop
jmp sfil17 ; Got the chars, proceed.
sfil16: cmp ah,0FFH ; Is it EOF?
je sfl161
jmp abort ; If not give up.
sfl161: mov ah,'Z' ; Set the state to EOF.
mov pack.state,ah
ret
sfil17: mov siz,ax
mov pack.state,'D' ; Set the state to data send.
ret
sfile3: cmp ah,'E' ; Is it an error packet.
jne sfile4
call error
sfile4: jmp abort
SFILE ENDP
; Send data
SDATA PROC NEAR
cmp flags.cxzflg,0 ; Have we seen ^X or ^Z?
je sdata2 ; Nope, just continue.
cmp flags.cxzflg,'C' ; Stop it all?
jne sdata1 ; It was a ^X or ^Z.
mov pack.state,'A' ; It was a ^C -- abort
ret
sdata1: mov pack.state,'Z' ; Else, abort sending the file.
ret
sdata2: mov dl,maxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl sdata3 ; l = no
test flags.remflg,dquiet ; quiet display mode?
jnz sdat2a ; nz = yes. Don't write to screen
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
sdat2a: mov bx,offset erms22
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
sdata3: inc pack.numtry ; Increment it.
mov cx,siz ; number to transfer
mov si,offset filbuf ; source of characters
mov di,offset data ; destination
push es ; save es
push ds
pop es ; make es:di point to datas segment
cld
rep movsb ; just copy data
pop es ; restore reg
mov ax,siz ; this is how many were moved
sdata7: mov pack.argbk1,ax
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
call pktsize ; report packet size
mov ah,'D' ; Data packet.
call spack ; Send the packet.
jmp tryagn ; if can't send it, retry before giving up
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Do all decoding.
call acknak ; see if ack or nak, check packet number
cmp al,0 ; 0 => ack ok, go on
je sdat11
cmp al,1 ; 1 => nak, retry count incremented, try again
jne sdat15 ; else look for other packet types...
ret ; else return
sdat11: cmp pack.argbk1,1 ; any data?
jne sdat23
mov bl,data ; get 1st byte
cmp bl,'X' ; someone typed control X?
je sdat24 ; e = yes.
cmp bl,'Z' ; Control Z? Corrects earlier proto error
jne sdat23 ; not X or Z, just keep going
sdat24: mov flags.cxzflg,bl ; set flag appropriately
mov pack.state,'Z' ; simulate eof
ret ; and return
sdat23: call gtchr
jmp sdat12 ; Error go see if its EOF.
nop ; make three bytes
mov siz,ax ; Save the size of the data gotten.
ret
sdat12: cmp ah,0FFH ; Is it EOF?
je sdat13
jmp abort ; If not give up.
sdat13: mov pack.state,'Z' ; Set the state to EOF.
ret
sdat15: cmp ah,'E' ; Is it an error packet.
jne sdat16
call error
sdat16: jmp abort
SDATA ENDP
; check the current packet for an ack or nak and handle it from any of
; the send states. Returns: 0 if an ack received with the correct expected
; packet number, or if a nak received with the NEXT packet number (the
; packet number is incremented, retry count reset); 1 if a nak or ack
; with a bad packet number is received, retry count is updated and displayed.
; Finally, 2 is returned if anything else is seen.
;
ACKNAK PROC NEAR
cmp ah,'Y' ; ack packet?
jne ackna1 ; no, keep going
mov bx,pack.pktnum
cmp bx,pack.argblk ; is it what we were expecting?
jne ackna2 ; no, update retries and punt
; packet ok, increment packet number
ackna0: mov bx,pack.pktnum ; reload packet number (!!!)
inc bx
and bx,03fh ; increment packet number
mov pack.pktnum,bx ; store back
inc pack.numpkt ; increment # of packets
mov pack.numtry,0
mov al,0 ; ack'd ok
ret
; not a 'Y'...
ackna1: cmp ah,'N' ; a nak?
je ackna5 ; yes, go on
mov al,2
ret ; unknown packet type
ackna5: mov bx,pack.pktnum
inc bx
and bx,3fh
cmp bx,pack.argblk ; maybe a nak for pktnum+1?
je ackna0 ; yes, treat as ack
; nak or bad ack, update retry stuff
ackna2: call rtpos ; Position cursor.
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries.
mov al,1 ; nak code
inc fsta.nakrcnt ; count received NAK for statistics
ret ; and return
ACKNAK ENDP
; Send EOF
SEOF PROC NEAR
mov dl,maxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl seof1 ; l = no
test flags.remflg,dquiet; quiet display mode?
jnz seof0 ; nz = yes. Don't write to screen
call erpos ; Position cursor.
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
seof0: mov bx,offset erms23
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
seof1: inc pack.numtry ; Increment it.
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov pack.argbk1,0 ; No data.
cmp flags.cxzflg,0 ; Seen a ^X or ^Z?
je seof11 ; Nope, send normal EOF packet.
mov data,'D' ; Use "D" for discard.
mov pack.argbk1,1 ; Set data size to 1.
seof11: mov cx,pack.argbk1 ; Put size in CX.
call doenc ; Encode the packet.
call pktsize ; report packet size
mov ah,'Z' ; EOF packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Do decoding.
call acknak ; see what they had to say
cmp al,0 ; ack?
je seof12 ; yes, go close file and proceed
cmp al,1 ; maybe a nak?
jne seof3 ; no, check for error packet
ret ; if nak, just return...
seof12: mov ah,close2 ; DOS 2.0 close file
push bx
mov bx,diskio.handle ; file handle
int dos
pop bx
mov ax,1 ; tell statistics this was a send operation
call endtim ; get tod of end of file transfer
call GTNFIL ; Get the next file.
jmp seof13 ; No more.
nop ; make three bytes
call begtim ; start statistics counter
mov pack.state,'F' ; Set the state to file send.
cmp flags.cxzflg,'X' ; Control-X seen?
jne seof14
call cxmsg ; Clear out the interrupt msg.
seof14: mov flags.cxzflg,0 ; Reset the flag.
ret
seof13: mov pack.state,'B' ; Set the state to EOT.
mov filopn,0 ; No files open.
mov difsiz,0 ; clear original filename
mov byte ptr sendas,0 ; clear sendas name
ret
seof3: cmp ah,'E' ; Is it an error packet?
jne seof4
call error
seof4: jmp abort
SEOF ENDP
; Send EOT
SEOT PROC NEAR
mov dl,maxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl seot1 ; l = no
test flags.remflg,dquiet ; quiet display mode?
jnz seot0 ; nz = yes. Don't write to screen
call erpos ; Position cursor.
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
seot0: mov bx,offset erms24
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
seot1: inc pack.numtry ; Increment it.
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov pack.argbk1,0 ; No data.
call pktsize ; report packet size
mov ah,'B' ; EOF packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Decode packet.
call acknak ; see if good ack or nak
cmp al,0 ; ack'd ok?
je seot12 ; yes, done with this
cmp al,1 ; maybe a nak?
jne seot3 ; no, check for error
ret ; else just return
seot12: mov pack.state,'C' ; Set the state to file send.
ret
seot3: cmp ah,'E' ; Is it an error packet.
jne seot4
call error
seot4: jmp abort
SEOT ENDP
tryagn: call updrtr
ret
; newfn -- move replacement name from buffer sendas to buffer data
newfn: cmp difsiz,0 ; Sending file under different name?
je newf4 ; e = no, so don't give new name
test flags.remflg,dquiet ; quiet display mode?
jnz newfa ; nz = yes. Don't write to screen
mov ah,prstr
mov dx,offset asmsg ; display ' as '
int dos
mov ah,conout ; use printable output
newfa: mov si,offset sendas ; Buffer where the name is
mov di,offset data
mov cx,difsiz ; Length of name.
inc cx ; plus null terminator
newf0: lodsb ; Get a character into al.
stosb
test flags.remflg,dquiet ; quiet display mode (should we print)?
jnz newf2 ; nz = yes
mov dl,al ; set into dl for display
int dos ; Print them.
newf2: loop newf0
mov cx,difsiz ; Reset the length field.
newf4: test flags.remflg,dserial ; serial display mode?
jz newf5 ; z = no
push ax
push dx
mov dx,offset crlf ; start with cr/lf for serial display
mov ah,prstr
int dos
pop dx
pop ax
newf5: ret
; Do encoding. Expect CX to be the data size.
doenc: jcxz doen0
mov chrcnt,cx ; Number of bytes of source data
mov bufpnt,offset data ; Source of data.
mov bx,offset nulref ; Null routine for refilling buffer.
mov ah,rptq
mov origr,ah ; Save repeat prefix here.
mov rptct,1 ; Number of times char is repeated.
mov rptval,0 ; Value of repeated char.
call encode ; Make a packet with size in AX.
nop
nop
nop
mov pack.argbk1,ax ; Store length of data field
mov cx,ax
call movpak ; Move to data part of packet.
cmp chrcnt,0 ; Did all chars fit into the buffer?
jne doen1 ; ne = no, we have an error condition
clc ; clear c bit for success
doen0: ret
doen1: stc ; set c bit for did not fit condition
ret
; CX is set before this is called.
movpak: push es
mov ax,ds
mov es,ax
cld
mov si,offset filbuf ; Move from here
mov di,offset data ; to here
cmp cx,0
jle movpak1
repne movsb
movpak1:pop es
ret
; Dodecoding.
dodec:
mov cx,pack.argbk1 ; Size of data.
jcxz dodc0 ; z = nothing to transfer
push ax ; Save packet size.
mov bx,offset data ; Address of data.
mov ax,offset nulr ; Routine to dump buffer (null)
mov bufpnt,offset decbuf ; Where to put output.
mov chrcnt,maxpack ; Buffer size
call decode
nop
nop
nop
call decmov ; Move decoded data back to "data" buffer.
pop ax
dodc0: ret
; Move decoded data from decode buffer back to "data".
decmov: push si
push di
push es
mov ax,ds
mov es,ax
cld
mov cx,bufpnt ; Last char we added.
sub cx,offset decbuf ; Get actual number of characters.
mov pack.argbk1,cx ; Remember size of real data.
mov si,offset decbuf ; Data is here
mov di,offset data ; Move to here
cmp cx,0
jle decmov1 ; le = none to do
repne movsb ; Copy the data.
decmov1:mov al,0 ; Null to end the string.
stosb
pop es
pop di
pop si
ret
; Abort
ABORT PROC NEAR
mov difsiz,0 ; clear original filename
mov byte ptr sendas,0 ; clear sendas name
cmp filopn,0 ; Any disk files open?
je abort0 ; No so don't do a close.
mov ah,close2 ; DOS 2.0 close file
push bx
mov bx,diskio.handle ; file handle
int dos
pop bx
mov filopn,0 ; say file is closed now
abort0: mov pack.state,'A' ; Otherwise abort.
or errlev,1 ; set DOS error level
ret
ABORT ENDP
; This is where we go if we get an error packet. A call to ERROR
; positions the cursor and prints the message. A call to ERROR1
; just prints a CRLF and then the message.
ERROR PROC NEAR
mov pack.state,'A' ; Set the state to abort.
test flags.remflg,dquiet ; quiet display mode?
jnz errorx ; nz = yes. Don't write to screen
call erpos ; Position the cursor.
jmp error2
ERROR1: mov ah,prstr ; entry point for Server Generic cmds.
mov dx,offset crlf
int dos
error2: push bx
mov bx,pack.argbk1 ; Get the length of the data.
add bx,offset data ; Get to the end of the string.
mov ah,'$' ; Put a dollar sign at the end.
mov [bx],ah
mov ah,prstr ; Print the error message.
mov dx,offset data
int dos
pop bx
errorx: ret
ERROR ENDP
; Set the maximum send data packet size; modified for long packets.
PACKLEN PROC NEAR
push ax
push cx
xor ah,ah
mov al,trans.spsiz ; Maximum send packet size for Regular pkts.
cmp ax,trans.slongp ; negotiated long packet max size
jae pack2 ; ae = use regular packets
mov ax,trans.slongp ; else use long kind
sub ax,3 ; minus extended count & checksum
cmp ax,(95*94-1-2) ; longer than Long?
jle pack2 ; le = no, Long will do
dec ax ; minus one more for extra long count
pack2: sub ax,2 ; minus Sequence, Type
sub al,trans.chklen ; And minus Checksum chars.
sbb ah,0 ; borrow propagate
cmp trans.ebquot,'N' ; Doing 8-bit Quoting?
je pack0 ; Nope so we've got our size.
cmp trans.ebquot,'Y'
je pack0 ; Not doing it in this case either.
dec ax ; Another 1 for 8th-bit Quoting.
pack0: cmp rptq,0 ; Doing repeat character Quoting?
je pack1 ; Nope, so that's all for now.
dec ax ; minus repeat prefix
dec ax ; and repeat count
pack1: dec ax ; for last char might being a control code
mov trans.maxdat,ax ; Save max length for data field.
pop cx
pop ax
ret
PACKLEN ENDP
; Print the number in AX on the screen in decimal rather that hex.
NOUT PROC NEAR
test flags.remflg,dserial ; serial display mode?
jnz pnout ; nz = use "dot and plus" for serial mode
test flags.remflg,dquiet ; quiet display mode?
jnz nout1 ; nz = yes. Don't write to screen
call decout ; call standard decimal output routine
nout1: ret
pnout: or ax,ax ; display packet in serial display mode
jz pnoutx ; z = nothing to display
push ax ; for serial mode display
push dx ; output .........+.........+ etc
mov temp,10
mov dx,0
div temp ; number/10. (AX=quo, DX=rem)
push ax ; save around printing
push dx ; save around initial printing
cmp dx,0 ; remainder non-zero?
jne pnout1 ; ne = yes
mov dl,'+' ; symbol plus for tens
jmp pnout2 ; display it
pnout1: mov dl,'.' ; symbol for between tens
pnout2: mov ah,conout ; output to console
int dos
pop dx ; recover remainder
pop ax ; recover quotient
or dx,dx ; check for multiples of 70, to break lines
jnz pnout3 ; nz = non-zero remainder, just exit
mov temp,7 ; divide ax by 7 (dx is zero by construction)
div temp ; ax = quotient, dx = remainder
or dx,dx ; zero remainder?
jnz pnout3 ; nz = non-zero remainder, just exit
mov ah,prstr ; output cr/lf after every 70th chars
mov dx,offset crlf
int dos
pnout3: pop dx
pop ax
pnoutx: ret
NOUT 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