home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
ccdos.tar.gz
/
ccdos.tar
/
ccssen.asm
< prev
next >
Wrap
Assembly Source File
|
1991-09-08
|
73KB
|
1,561 lines
NAME ccssen
; File CCSSEN.ASM
;CHINESE
ifdef MSDOS
include msssen.dat
else
include ccssen.dat
endif
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, prtasz:near
extrn erpos:near, rtpos:near, cxmsg:near, stpos:near, decout:near
extrn encode:near, nulref:near, decode:near, nulr:near, lnout:near
extrn errpack:near, updrtr:near, clrmod:near, prompt:near
extrn prtfn:near, strcpy:near, strlen:near, strcat: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
; Lines marked ;M energize the second CAPAS byte. Leave them as comments for
; because earlier versions of MS Kermit (and C Kermit) are confused by it
; (fail to decode bit saying second CAPAS byte follows and thus loose sync).
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,'0' ; 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,2 ; CAPAS, bit1 = can do long packets
cmp flags.attflg,0 ; allowing attributes packets?
je rpar1 ; e = no
or ah,8 ; bit #3, can do file attributes
rpar1:
;M or ah,1 ; say second CAPAS byte follows
add ah,20h ; apply tochar() to byte
mov 9[bx],ah ; add to packet
; additional CAPAS go in here
mov byte ptr 10[bx],20h+20h ; Allow M (message) pkts, (#6, bit5)
mov ah,20h ; WINDO field, null applied through tochar()
;M mov 11[bx],ah ; put into packet
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
;M mov 12[bx],al ; add to packet
mov 11[bx],al ; add to packet
add dl,20h ; apply tochar() to remainder
;M mov 13[bx],dl ; add to packet
mov 12[bx],dl ; add to packet
pop dx ; restore regs
pop ax
;M mov ah,14 ; 14 bytes of data
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
mov ah,al ; number of args is now in ah
push si
mov si,bx
cld
cmp ah,0 ; any data?
jg spara ; g = yes, want more than bare minimum
mov al,dspsiz ; nothing supplied by host use default
jmp short sparc
spara: lodsb ; get the max packet size
dec ah ; ah = bytes remaining to be examined
sub al,' ' ; subtract a space
cmp al,spmin ; below the minimum?
jge sparb ; ge = no
mov al,spmin
jmp short sparc
sparb: cmp al,spmax ; or above the maximum?
jle sparc ; le = no
mov al,spmax
sparc: mov trans.spsiz,al ; save it
mov al,dtrans.stime ; pick up default stime
cmp ah,0 ; more data?
jle spar02 ; le = no, use default
lodsb ; get the timeout value
dec ah
sub al,' ' ; subtract a space
cmp dtrans.stime,dstime ; Is current value the default?
je spar0 ; e = yes, else user value overrides
mov al,dtrans.stime ; pick up user selected stime
spar0: cmp al,0
jg spar01 ; must be non-negative
mov al,0 ; negative, so use zero
spar01: cmp al,trans.rtime ; same as other side's timeout
jne spar02 ; ne = no
add al,1 ; yes, but make it a little different
spar02: mov trans.stime,al ; save it
mov al,dtrans.spad ; get default send padding
cmp ah,0 ; more data?
jle spar11 ; le = no, use default
spar1: lodsb ; get the number of padding chars
dec ah
sub al,' '
cmp al,0
jge spar11 ; must be non-negative
mov al,0
spar11: mov trans.spad,al
mov al,dtrans.spadch ; pick up default send pad character
cmp ah,0 ; more data?
jle spar21 ; le = no, use default
spar2: lodsb ; get the padding char
dec ah
add al,40h ; remove ascii bias
and al,7FH
cmp al,del ; Delete?
je spar21 ; e = yes, then it's OK
cmp al,31 ; control char?
jle spar21 ; le = yes, then OK
mov al,0 ; no, use null
spar21: mov trans.spadch,al
mov al,dtrans.seol ; get default send eol char
cmp ah,0 ; more data?
jle spar31 ; le = no, use default
spar3: lodsb ; get the EOL char
dec ah
sub al,' '
cmp al,31 ; control char?
jle spar31 ; le = yes, then use it
mov al,cr ; else use the default
spar31: mov trans.seol,al
mov al,dtrans.squote ; send quote
cmp ah,0 ; more data?
jle spar41 ; le = no, use default
spar4: lodsb ; get the quote char
dec ah
cmp al,' ' ; less than a space?
jge spar40 ; ge = no
mov al,dsquot ; yes, use default
jmp spar41
spar40: cmp al,7eh ; must also be less than a tilde
jbe spar41 ; be = is ok
mov al,dsquot ; else use default
spar41: mov trans.squote,al
cmp ah,0 ; more data?
jg spar5 ; g = yes
mov al,dtrans.ebquot ; use default
mov trans.ebquot,al
jmp short spar51
spar5: lodsb ; get other side's 8-bit quote request
dec ah
call doquo ; and set quote char
spar51: cmp ah,0 ; more data?
jg spar6 ; g = yes
mov trans.chklen,1 ; use default
jmp short spar61
spar6: mov al,inichk
mov trans.chklen,al ;checksum length we really want to use
lodsb ; get other side's checksum length
dec ah
call dochk ; determine what size to use
spar61: cmp ah,0 ; more data?
jg spar7 ; g = yes
mov rptq,0
jmp short spar71
spar7: lodsb ; get other side's repeat count prefix
dec ah
mov ch,drpt ; default repeat count prefix
mov rptq,0 ; clear active repeat count prefix
call dorpt ; negotiate new prefix
spar71: mov al,0 ; get default operating Capabilities
cmp ah,0 ; more data?
jle spar81 ; le = no, use default
lodsb ; get capas bitmap from other side
dec ah
and al,not (1) ; remove least significant bit
sub al,20h ; apply unchar()
spar81: mov trans.capas,al ; store result in active byte
spar82: cmp ah,0 ; more data?
jle spar85 ; le = no
test byte ptr [si-1],1 ; is CAPAS byte continued to next?
jz spar85 ; z = no
lodsb ; get 2nd CAPAS bitmap from other side
dec ah
and al,not (1) ; remove least significant bit
sub al,20h ; apply unchar(). Store nothing
jmp short spar82 ; seek more CAPAS bytes
spar85: mov al,0 ; setup default window size
cmp ah,0 ; more data?
jle spar9 ; le = no, use default
lodsb ; get other side's window size
dec ah
sub al,20h ; apply unchar()
call dewind ; negotiate window size back into al
spar9: mov trans.windo,al ; 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 ah,2 ; more data (long packet needs two)?
jae spar9d ; ae = more to look at
mov ax,trans.slongp ; put above size in ax for final checks
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
lodsb ; long pkt length, high order byte
sub al,20h ; apply unchar()
xor ah,ah
mul ninefive ; times 95 to dx(hi),ax(lo)
mov trans.slongp,ax ; store that much
lodsb ; long pkt length, low order byte
sub al,20h ; apply unchar()
xor ah,ah
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: mov ax,temp4 ; recover number of pieces of data
sparx: pop si
ret
SPAR ENDP
; Set 8-bit quote character based on my capabilities and the other
; Kermit's request
DOQUO PROC NEAR
cmp dtrans.ebquot,'N' ; Can I do 8-bit quoting at all?
je dq3 ; No - so forget it
cmp dtrans.ebquot,'Y' ; Can I do it if requested?
jne dq0 ; No - it's a must that I do it
mov trans.ebquot,al ; Do whatever he wants
jmp dq1
dq0: cmp al,'Y' ; I need quoting - can he do it?
je dq1 ; Yes - then all is settled
cmp al,'N' ; No - then don't quote
je dq3
cmp al,trans.ebquot ; Both need quoting - chars must match
jne dq3
dq1: mov al,trans.ebquot
cmp al,'Y' ; If Y or N, don't validate prefix
je dq2
cmp al,'N'
je dq2
call prechk ; Is it in range 33-62, 96-126?
jnc dq4 ; nc = in range
mov al,'Y' ; don't do quoting
dq4: cmp al,trans.rquote ; Same prefix?
je dq3 ; Not allowed, so don't do quoting.
cmp al,trans.squote ; Same prefix here?
je dq3 ; This is illegal too
mov trans.ebquot,al ; Remember what we decided on
dq2: ret
dq3: mov trans.ebquot,'N' ; Quoting will not be done
ret
DOQUO ENDP
; Check if prefix in AL is in the proper range: 33-62, 96-126.
; Return carry clear if in range, else return carry set.
prechk: cmp al,33
jb prechk2 ; b = out of range
cmp al,62
jbe prechk1 ; be = in range 33-62
cmp al,96
jb prechk2 ; b = out of range
cmp al,126
ja prechk2 ; a = out of range 96-126
prechk1:clc ; carry clear for in range
ret
prechk2:stc ; carry set for out of range
ret
; Set checksum length.
dochk: cmp al,'1' ; Must be '1', '2', or '3'
jb doc1 ; b = not '1' to '3'
cmp al,'3'
jbe doc2 ; be = ok
doc1: mov al,'1' ; else use default of '1'
doc2: sub al,'0' ; remove ascii bias
mov trans.chklen,al ; other side's request is do-able here
cmp al,trans.chklen ; Do we want the same thing?
je dochk0 ; e = yes, then we're done
mov trans.chklen,1 ; No, use single character checksum
dochk0: ret
; 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?
jnc dorpt1 ; nc = in range
mov al,0 ; don't use their value
dorpt1: cmp al,trans.squote ; Same as the control quote char?
je dorpt2 ; Yes, that's illegal, no repeats
cmp al,trans.rquote ; How about this one?
je dorpt2 ; No good
cmp al,trans.ebquot ; Same as eight bit quote char?
je dorpt2 ; Yes, that's illegal too, no repeats
cmp al,ch ; Are we planning to use same char?
jne dorpt2 ; No, that's no good either
mov rptq,ch ; Use repeat quote char now
dorpt2: ret
; negotiate window size in al
dewind: xor al,al ; no windowing at our end
ret
; Send command
; MAIL filspec user@node command
SEND PROC NEAR
mov mailflg,0 ; send, not mail
mov temp,0
jmp short sendm0
MAIL: mov mailflg,1 ; set flag for mail command vs send
mov temp,1 ; temp copy of mailflag
sendm0: mov difsiz,0 ; Assume we'll use original filename
mov byte ptr sendas,0 ; clear sendas name (in case none)
mov dx,offset diskio.string ; address of filename string
; mov bx,offset filmsg ; Text of help message
mcmsgb filmsg, cfilmsg
cmp mailflg,0 ; Mail command?
je sendm1 ; e = no
mov mailflg,0 ; clear in case error exit
; mov bx,offset mailhlp ; Text of help message
mcmsgb mailhlp, cmailhlp
sendm1: mov ah,cmfile ; get an input file spec
call comnd
ret ; Give up on bad parse
nop
nop
cmp flags.cxzflg,0 ; ^X, ^Z, ^C typed?
je send0 ; e = no, continue
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
jmp rskp ; yes, quit
send0: cmp ah,0 ; any text given?
je send0d ; e = no, prompt
cmp temp,0 ; Mail command?
je send00
jmp send0c ; ne = yes, require address
send00:
mov bx,offset sendas ; See if want to send file under dif name
; mov dx,offset filhlp ; In case user needs help
mcmsg filhlp, cfilhlp
mov ah,cmtxt ; allow embedded white space
call comnd
ret
nop
nop
jmp sendm3a ; join common completion code
send0d:
; mov dx,offset lclfnm ; prompt for local filename
mcmsg lclfnm, clclfnm
call prompt
mov dx,offset diskio.string ; reload destination of user's text
; mov bx,offset filhlp ; help file
mcmsgb filhlp, cfilhlp
mov ah,cmfile ; allow paths
call comnd ; try again for a local filename
ret
nop
nop
mov temp4,ax
mov ah,cmcfm
call comnd
ret
nop
nop
mov ax,temp4
cmp flags.cxzflg,0 ; ^X, ^Z, ^C typed?
je send0a ; e = no, continue
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
mov mailflg,0
jmp rskp ; yes, quit
send0a: cmp ah,0 ; user's byte count
je send0d ; e = nothing was typed, get some
send0b:
; mov dx,offset remfnm ; ask for remote name first
mcmsg remfnm, cremfnm
cmp temp,0 ; Mail command?
je sendm2 ; e = no
; mov dx,offset mailto ; ask for name@host
mcmsg mailto, cmailto
sendm2: 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
mcmsg filhlp, cfilhlp
cmp temp,0 ; Mail command?
je sendm3 ; e = no
; mov dx,offset mailtohlp ; In case user needs help
mcmsg mailtohlp, cmailtohlp
sendm3: mov ah,cmtxt ; allow embedded white space
call comnd
ret
nop
nop
cmp ah,0 ; text entered?
je send0b ; e = no, get some
sendm3a:cmp flags.cxzflg,0 ; ^X, ^Z, ^C typed?
je send1 ; e = no, continue
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
mov mailflg,0
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 ax,temp ; get temp mailflag
mov mailflg,al ; store in secure area for later
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 short 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 kstatus,0 ; global status, success
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
mcmsgb remmsg1, cremmsg1
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'
mcmsg erms15, cerms15
int dos
or errlev,1 ; set DOS error level
or fsta.xstatus,1 ; set status
mov kstatus,1 ; global status
mov ax,1 ; tell statistics this was a send operation
call endtim ; stop statistics counter
mov mailflg,0 ; clear Mail flag
jmp rskp ; pretend successful completion
send16: call serini ; Initialize serial port
jnc send17 ; nc = success
or errlev,1 ; say send failed
or fsta.xstatus,1 ; set status
mov kstatus,1 ; global status
test flags.remflg,dquiet ; quiet display mode?
jnz send16a ; nz = yes. Don't write to screen
; mov dx,offset erms14
mcmsg erms14, cerms14
mov ah,prstr
int dos ; Print an error message
send16a:ret ; return failure
send17: 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
mcmsg infms2, cinfms2
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 send3a ; ne = no
call sfile ; Call send file
jmp send2
send3a: cmp pack.state,'a' ; are we in send attributes state?
jne send3b ; ne = no
call sattr ; call send attributes
jmp send2
send3b: cmp pack.state,'d' ; are we in initialize send data state
jne send4 ; ne = no
call sdatini ; do setup for file reading
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
;;;; call serrst ; Reset serial port
pop ax
mov mailflg,0 ; clear Mail flag
; mov dx,offset infms3 ; Completed message
mcmsg infms3, cinfms3
cmp pack.state,'C' ; Are we in the send complete state?
je send8 ; e = yes, else failure
; mov dx,offset infms4 ; Failed message
mcmsg infms4, cinfms4
or errlev,1 ; say send failed
or fsta.xstatus,1 ; set status
mov kstatus,1 ; global status
send8: cmp flags.cxzflg,0 ; completed normally?
je send8b ; e = yes, don't bother with this
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
send8b: mov ax,1 ; tell statistics this was a send operation
call endtim ; stop statistics counter
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
mcmsg infms6, cinfms6
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
mcmsg erms14, cerms14
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
mcmsgb erms20, cerms20
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
mov ah,dtrans.seol ; restore default end-of-line char
mov trans.seol,ah
mov ah,dtrans.ebquot ; our default 8-bit quoting
mov trans.ebquot,ah ; active 8-bit quoting
call rpar ; Set up the parameter information
xchg ah,al
mov ah,0
mov pack.datlen,ax ; Save the number of arguments
mov ax,pack.numpkt ; Get the packet number
mov pack.seqnum,ax
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 sndpak ; send the packet
call rpack ; Get a packet
jmp sini23 ; Trashed packet don't change state, retry
nop
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.datlen
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
cmp mailflg,0 ; non-zero to do Mail command
je sini24 ; e = send, not mail command
cmp flags.attflg,0 ; allowed to do file attributes?
je sinit6 ; e = no, so no Mail
test trans.capas,8 ; can they do file attributes?
jz sinit6 ; z = no, so cannot do Mail
sini24: 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
jmp updrtr ; Update retry counter and return
sinit4: cmp ah,'M' ; Message packet?
jne sinit4e ; ne = no
call dodec ; decode it
jmp error1 ; display it and return
sinit4e:cmp ah,'E' ; Is it an error packet
jne sinit5
call error
sinit5: jmp abort
; say Mail not supported by host
sinit6: test flags.remflg,dquiet ; quiet display mode?
jnz sinit7 ; nz = yes. Don't write to screen
call erpos
; mov dx,offset erms25
mcmsg erms25, cerms25
mov ah,prstr
int dos ; Print an error message
sinit7: mov pack.state,'B' ; go to EOT state
ret
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
mcmsg erms14, cerms14
mov ah,prstr
int dos ; Print an error message
sfile0:
; mov bx,offset erms21
mcmsgb erms21, cerms21
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.seqnum,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 sndpak ; send the packet
call rcvpak ; Get a packet
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: call fackmsg ; get/show any embedded message
mov pack.state,'a' ; set file attributes as next state
ret
sfile3: cmp ah,'M' ; Message packet?
jne sfile4 ; ne = no
call dodec ; decode it
jmp error1 ; display it and return
sfile4: cmp ah,'E' ; Is it an error packet
jne sfile4 ; ne = no
call dodec ; Do all decoding
call error
sfile5: jmp abort
SFILE ENDP
; Send file attributes. Attributes: file size in bytes and kilobytes,
; file time and date, machine identification. [jrd]
SATTR PROC NEAR
cmp flags.attflg,0 ; allowed to do file attributes?
je satt0 ; e = no
test trans.capas,8 ; can we do file attributes?
jnz satt1 ; nz = yes
satt0: mov pack.state,'d' ; set the state to initiate send-data
ret
satt1: push es ; save es around this work
push ds
pop es ; set es to datas segment for es:di
cld
mov data,'1' ; File length (Bytes) specifier
mov dx,diskio.sizehi ; high word of length
mov ax,diskio.sizelo ; low word of length
mov di,offset data+2 ; where to store data (for lnout)
call lnout ; convert file length, write to [di++]
mov cx,di ; compute field length
sub cx,offset data+2
add cl,32 ; field length to ascii
mov data+1,cl ; length. Done with File Size
; Kilobyte attribute
mov byte ptr[di],'!' ; File length (Kilobytes) specifier
inc di
mov temp4,di ; remember place for count field
inc di ; data field
mov dx,diskio.sizehi ; high word of length, from file open
mov ax,diskio.sizelo ; low word of length
add ax,1023 ; add 1023 to round up
adc dx,0
mov al,ah ; do divide by 1024 bytes
mov ah,dl
mov dl,dh ; divide by 256 part
mov dh,0
ror dl,1 ; low bit to carry flag
rcr ax,1 ; divide by two, with carry in
clc
ror dl,1 ; low bit to carry flag
rcr ax,1 ; divide by two, with carry in
and dl,3fh ; keep low six bits
call lnout ; convert file length
mov cx,di ; compute field length
sub cx,temp4 ; count field location
add cl,32-1 ; field length to ascii
push di
mov di,temp4 ; point at count field
mov byte ptr[di],cl ; store field length
pop di ; Done with Kilobyte attribute
; File date and time:
mov al,'#' ; creation date/time specifier
stosb ; and point at field length
mov al,17+32 ; length of date/time field, to ascii
stosb
mov ah,0
mov al,diskio.dta+25 ; yyyyyyym from DOS via file open
shr al,1 ; get year
add ax,1980 ; add bias
mov dx,0
call lnout ; put year (1988) in buffer
mov ax,word ptr diskio.dta+24 ; yyyyyyyym mmmddddd year+month+day
shr ax,1 ; month to al
mov ah,0
mov cl,4
shr al,cl ; month to low nibble
mov byte ptr[di],'0' ; leading digit
inc di
cmp al,9 ; more than one digit?
jbe satt2 ; be = no
mov byte ptr[di-1],'1' ; new leading digit
sub al,10 ; get remainder
satt2: add al,'0' ; to ascii
stosb ; end of month
mov al,diskio.dta+24 ; get day of month
and al,1fh ; select day bits
mov ah,0
mov cl,10
div cl ; quot = al, rem = ah
add ax,'00' ; add ascii bias
stosw ; leading digit and end of date
mov al,' ' ; space separator
stosb
mov al,diskio.dta+23 ; hours hhhhhmmm
mov cl,3
shr al,cl ; move to low nibble
mov ah,0
mov cl,10
div cl ; quot = al, rem = ah
add ax,'00' ; add ascii bias
stosw ; store hours
mov al,':' ; separator
stosb
mov ax,word ptr diskio.dta+22 ; get minutes: hhhhhmmm mmmsssss
mov cl,5
shr ax,cl ; minutes to low byte
and al,3fh ; six bits for minutes
mov ah,0
mov cl,10
div cl
add ax,'00' ; add ascii bias
stosw
mov al,':' ; separator
stosb
mov al,byte ptr diskio.dta+22 ; get seconds (double secs really)
and al,1fh
shl al,1 ; DOS counts by two sec increments
mov ah,0
mov cl,10
div cl
add ax,'00' ; add ascii bias
stosw
mov ax,'".' ; machine indicator(.), 2 data bytes
stosw
mov ax,'8U' ; U8 = Portable O/S, MSDOS
stosw
pop es ; recover es register
cmp mailflg,0 ; Mailing?
je satt3 ; e = no
mov byte ptr [di],'+' ; Mail specification
inc di
mov si,offset sendas ; user@host field
mov dx,si
call strlen ; get length into cl
push cx ; save address length
inc cl ; include M for disposition = mail
add cl,' ' ; add ascii bias
mov [di],cl ; store in length field
inc di
mov byte ptr [di],'M' ; mail the file
inc di
pop cx ; recover address length
jcxz satt3 ; z = empty field
push es
push ds
pop es ; use es:di pointing to datas segment
cld
rep movsb ; append address text to field
pop es
satt3: sub di,offset data ; get length of data
mov pack.datlen,di ; data length for packet
call pktsize ; report packet size
mov ax,pack.pktnum ; get the packet number
mov pack.seqnum,ax
mov ah,'A' ; Attributes packet
call sndpak ; send the packet
call rcvpak ; get response
call acknak ; see what they had to say
cmp al,0 ; ack'd ok?
je satt5 ; e = yes, on to next state
cmp al,1 ; maybe a nak?
jne satt6 ; ne = no, check for error
ret ; if nak, just return and try again
satt5: cmp pack.datlen,0 ; any data in the ACK?
je satt5d ; e = no
cmp data,'N' ; are they refusing this file?
jne satt5d ; ne = no
test flags.remflg,dquiet ; quiet display mode?
jnz satt5a ; nz = yes. Don't write to screen
call erpos ; Position the cursor
mov ah,prstr
; mov dx,offset erms26 ; say host rejected the file
mcmsg erms26, cerms26
int dos
satt5a: mov pack.state,'Z' ; send EOF with Discard
mov flags.cxzflg,'X' ; simulate Control-X to discard
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
ret
satt5d: mov pack.state,'d' ; next state is initiate send-data
ret
satt6: cmp ah,'E' ; Is it an error packet
jne satt7 ; ne = no
call dodec ; Do all decoding
call error
satt7: jmp abort
SATTR ENDP
; Send data
;
; set up initial data buffer from file, 'd' state
sdatini proc near
mov flags.filflg,0FFH ; Indicate file buffer is empty
mov pack.state,'D'
jmp sdat23 ; read first buffer from file
sdatini endp
; Send main body of file, 'D' state
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
mcmsg erms14, cerms14
mov ah,prstr
int dos ; Print an error message
sdat2a:
; mov bx,offset erms22
mcmsgb erms22, cerms22
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 pack.datlen,cx ; length of data in packet
call movpak ; from filbuf to buffer data
mov ax,pack.pktnum ; Get the packet number
mov pack.seqnum,ax ; store in packet
call pktsize ; report packet size
mov ah,'D' ; Data packet
call sndpak ; send the packet
call rcvpak ; Get a packet
call acknak ; see if ack or nak, check packet number
cmp al,0 ; 0 => ack ok, go on
je sdat11 ; ack, check for data in response
cmp al,1 ; 1 => nak, retry count incremented, try again
jne sdat15 ; else look for other packet types
ret ; else return
sdat11: cmp pack.datlen,0 ; any data in ACK response?
je sdat23 ; e = no
call dackmsg ; get/show any embedded message
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 ; fill buffer from file
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 ; e = yes
jmp abort ; If not give up
sdat13: mov pack.state,'Z' ; Set the state to EOF
ret
sdat15: cmp ah,'M' ; Message packet?
jne sdat16 ; ne = no
call dodec ; decode it
jmp error1 ; display it and return
sdat16: cmp ah,'E' ; Is it an error packet
jne sdat17
call dodec ; Do all decoding
call error ; display and change state to Abort
sdat17: jmp abort
SDATA 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
mcmsg erms14, cerms14
mov ah,prstr
int dos ; Print an error message
seof0:
; mov bx,offset erms23
mcmsgb erms23, cerms23
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.seqnum,ax
mov pack.datlen,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.datlen,1 ; Set data size to 1
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
seof11: mov cx,pack.datlen ; Put size in CX
call doenc ; Encode the packet
call pktsize ; report packet size
mov ah,'Z' ; EOF packet
call sndpak ; send the packet
call rcvpak ; Get a packet
call acknak ; see what they had to say
cmp al,0 ; ack?
je seof12 ; e = 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: call dackmsg ; get/show any embedded message
mov ah,close2 ; DOS 2.0 close file
push bx
mov bx,diskio.handle ; file handle
int dos
pop bx
call GTNFIL ; Get the next file
jmp seof13 ; No more
nop ; make three bytes
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
or errlev,1 ; say send failed
or fsta.xstatus,1+80h ; set status, failed + intervention
mov kstatus,1+80h ; global status
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 dodec ; Decode packet
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
mcmsg erms14, cerms14
mov ah,prstr
int dos ; Print an error message
seot0:
; mov bx,offset erms24
mcmsgb erms24, cerms24
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.seqnum,ax
mov pack.datlen,0 ; No data
call pktsize ; report packet size
mov ah,'B' ; End of Session packet
call sndpak ; send the packet
call rcvpak ; Get a packet
call acknak ; see if good ack or nak
cmp al,0 ; ack'd ok?
je seot12 ; e = yes, done with this
cmp al,1 ; maybe a nak?
jne seot3 ; ne = no, check for error
ret ; else just return
seot12: call fackmsg ; get/show any embedded message
mov pack.state,'C' ; Set state to file completed
ret
seot3: cmp ah,'E' ; Is it an error packet
jne seot4
call dodec ; Do all decoding
call error
seot4: jmp abort
SEOT ENDP
sndpak proc near ; send packet with retries
call spack
jmp updrtr
nop
ret
sndpak endp
rcvpak proc near ; receive packet with retries
call rpack ; Get a packet
jmp updrtr ; Trashed packet, retry
nop
ret
rcvpak 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.
; A Timeout packet (type 'T') simply invokes a retry and a returned 1.
; Finally, 2 is returned if anything else is seen
;
ACKNAK PROC NEAR
cmp ah,'Y' ; ack packet?
jne ackna1 ; ne = no, keep going
mov bx,pack.pktnum
cmp bx,pack.seqnum ; 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
cmp ah,'T' ; Timeout?
je ackna3 ; e = yes, not a NAK but do a retry
mov al,2
ret ; unknown packet type
ackna5: mov bx,pack.pktnum
inc bx
and bx,3fh
inc fsta.nakrcnt ; count received NAK for statistics
cmp bx,pack.seqnum ; maybe a nak for pktnum+1?
je ackna0 ; yes, treat as ack
jne ackna3
; nak or bad ack, update retry stuff
ackna2: inc fsta.nakrcnt ; count received NAK for statistics
ackna3: push ax
call rtpos ; Position cursor
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries
pop ax
mov al,1 ; nak code
ret ; and return
ACKNAK ENDP
; Display message in ACK's to D packets. Requires a leading protocol char
; and expects message to be encoded.
dackmsg proc near
cmp pack.datlen,1 ; any embedded message?
jbe dackmsgx ; be = no (skip single char msgs)
test flags.remflg,dquiet ; quiet display mode?
jnz dackmsgx ; nz = yes, don't write to screen
push ax
push dx
call cxmsg ; clear message space in warning area
call dodec ; decode message, including X/Z/other
mov dx,offset data+1 ; point to asciiz message
call prtasz ; display it
pop dx
pop ax
dackmsgx:ret
dackmsg endp
; Display messages in ACKs to F packets. Expects message to be not encoded.
fackmsg proc near ; look for in ack
cmp pack.datlen,0 ; any embedded message?
je fackmsgx ; e = no
test flags.remflg,dquiet ; quiet display mode?
jnz fackmsgx ; nz = yes, don't write to screen
push ax
push dx
call cxmsg ; clear message space in warning area
call dodec;;;decode
mov dx,offset data ; point to asciiz message
call prtasz ; display it
pop dx
pop ax
fackmsgx:ret
fackmsg endp
; newfn -- move replacement name from buffer sendas to buffer data
; update cx to new filename length
newfn: cmp difsiz,0 ; Sending file under different name?
je newf4 ; e = no, so don't give new name
mov si,offset sendas ; source field
mov di,offset fsta.xname ; statistics name area
call strcpy
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 '
mcmsg asmsg, casmsg
cmp mailflg,0 ; mail?
je newfn1 ; e = no
mov dx,offset mailto ; display ' To: '
newfn1: int dos
mov ah,conout ; use printable output
cmp mailflg,0 ; mail?
je newfa ; e = no
mov dx,offset sendas ; get name
call prtasz ; print asciiz string
jmp newf4 ; don't replace filename
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
mov dx,offset crlf ; start with cr/lf for serial display
mov ah,prstr
int dos
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.datlen,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
shr cx,1 ; divide by two (words), set carry
jnc movpak1 ; nc = even number of bytes
movsb ; do the single move for odd count
movpak1:cmp cx,0
jle movpak2
rep movsw
movpak2:pop es
ret
; Dodecoding
dodec:
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
mov cx,pack.datlen ; Size of data
jcxz dodc0 ; z = nothing to transfer
call decode
nop
nop
nop
dodc0: call decmov ; Move decoded data back to "data" buffer
pop ax
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.datlen,cx ; Remember size of real data
mov si,offset decbuf ; Data is here
mov di,offset data ; Move to here
shr cx,1 ; divide by two (words), set carry
jnc decmov1 ; nc = even number of bytes
movsb ; do single move
decmov1:cmp cx,0
jle decmov2 ; le = none to do
rep movsw ; Copy the data
decmov2: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
mov mailflg,0 ; clear Mail flag
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
or fsta.xstatus,1 ; set status
mov kstatus,1 ; global status
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: mov dx,offset data ; error message string
push bx
mov bx,pack.datlen ; Get the length of the data
add bx,dx ; Get to the end of the string
mov byte ptr [bx],0 ; terminate string
pop bx
call prtasz ; print asciiz string
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
code ends
end