home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
extra
/
nyenhuis3.arc
/
MSSSER.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-16
|
65KB
|
2,136 lines
NAME mssser
; File MSSSER.ASM
include mssdef.h
; Edit history:
; Last edit 16 Jan 1990
public logout, bye, finish, remote, get, server, denyflg, srvtmo
public luser, lpass
data segment public 'data'
extrn flags:byte, trans:byte, curdsk:byte, diskio:byte, auxfile:byte
extrn comand:byte, filtst:byte, maxtry:byte, dtrans:byte
extrn fmtdsp:byte, errlev:byte, fsta:word, kstatus:word
extrn rpacket:byte, encbuf:byte, decbuf:byte, sstate:byte
extrn rstate:byte, pktnum:byte, windlow:byte, takadr:word
extrn taklev:byte, prmptr:word
scrser equ 0209H ; place for server state display line
scrmsg equ 0C16H ; place for Last message
remcmd db 0 ; Remote command to be executed
rempac db 0 ; Packet type: C (host) or G (generic)
remlen db 0 ; length of following text field
ermes6 db 'Filename too long for packet',0
cemsg db 'User intervention',0
infms1 db 'Server mode: type Control-C to exit',cr,lf,'$'
infms2 db cr,lf,'?More parameters are needed$'
infms3 db 'REMOTE command reply',0 ; for transaction logging
infms4 db 'Help text',0 ; filename for REM Help reply
inthlp db cr,lf,' Time-limit to remain in Server mode, seconds or'
db ' specific hh:mm:ss (24h clock).'
db cr,lf,' SET TIMER ON to time. Return for no time limit.$'
remms1 db ' Unknown server command',0
remms2 db ' Invalid login information',0
remms3 db ' Kermit-MS Server ready',0
remms5 db ' File not found',0
remms6 db ' Command failed',0
remms7 db ' REMOTE LOGIN is required',0
remms8 db ' Command succeeded',0
remms9 db ' Command is Disabled',0
remms10 db ' Could not create work file',0
byemsg db ' Goodbye!',0
whomsg db ' Just this Server',0
spcmsg db ' bytes available on drive ' ; remote space responses
spcmsg1 db ' ',0
spcmsg2 db ' Drive '
spcmsg3 db ' : is not ready',0
user db ' Username: ',0 ; for Remote Login, asciiz
password db ' Password: ',0 ; for Remote Login and Remote CD
account db ' Account: ',0 ; for Remote Login
slogin db 0 ; non-zero if successful local login
luser db 17 dup (0) ; local Username, case insenstitive
lpass db 17 dup (0) ; local Password, case sensitive
srvtmp db ' > :$kermit$.tmp',0 ; asciiz, kermit's temp output file
delstr db 'del ',0
dirstr db 'dir ',0
crlf db cr,lf,'$'
skertmp dw 0 ; REMOTE KERMIT work word
denyflg dw 0 ; bit field of denied commands
temp dw 0
temp2 dw 0
cnt dw 0
bufptr dw 0
dsptmp db 0 ; temp to hold fmtdsp during serving
srvtmo db 0 ; idle NAK time, default is no NAKs
srvtime db 0 ; non-zero if timing Server residence
remfnm db ' Remote Source File: ',0 ; asciiz
lclfnm db ' Local Destination File: ',0 ; asciiz
filhlp db ' File name to use locally$'
filmsg db ' Remote filename, or press ENTER for prompts$'
frem db ' Name of file on remote system $'
genmsg db ' Enter text to be sent to remote server $'
numhlp db ' number$'
xfrhlp db ' character set identifier string$'
rdbuf db 20 dup (0)
srvbuf db 80 dup (0) ; place After rdbuf, for status
savflg flginfo <> ; save area for flags.*
savflgl equ $-savflg ; length
savdtr trinfo <> ; save area for dtrans.*
savdtrl equ $-savdtr ; length
savtr trinfo <> ; save area for trans.*
savmaxtry db 0 ; save area for maxtry
srvchr db 'SRGIECK' ; server cmd characters, use w/srvfun
srvfln equ $-srvchr ; length of table
srvfun dw srvsnd,srvrcv,srvgen,srvini,srverr,srvhos,srvker ; for srvchr
remhlp db cr,lf,'CD/CWD change working directory' ; Answer to
db cr,lf,'Delete a file' ; local
db cr,lf,'Directory filespec' ; REM HELP
db cr,lf,'Help'
db cr,lf,'Host command'
db cr,lf,'Kermit command'
db cr,lf,'Login name password to a Kermit server'
db cr,lf,'Message short one line message'
db cr,lf,'Set command'
db cr,lf,'Space drive/directory'
db cr,lf,'Type a file'
db cr,lf,'Who user spec$'
; Answer from Server to REMOTE HELP
hlprem db cr,lf,'Kermit-MS Server commands:',lf
db cr,lf,'GET filespec '
db 'REMOTE DIRECTORY filespec '
db 'REMOTE MESSAGE 1-line msg'
db cr,lf,'SEND filespec '
db 'REMOTE HELP this text '
db 'REMOTE SET command'
db cr,lf,'FINISH, LOGOUT, BYE '
db 'REMOTE HOST command '
db 'REMOTE SPACE drive-letter'
db cr,lf,'REMOTE CD/CWD directory '
db 'REMOTE KERMIT SET command '
db 'REMOTE TYPE filespec'
db cr,lf,'REMOTE DELETE filespec '
db 'REMOTE LOGIN name password '
db 'REMOTE WHO'
db 0
remtab db 13 ; 13 entries
mkeyw 'CD',remcwd
mkeyw 'CWD',remcwd
mkeyw 'Delete',remdel
mkeyw 'Directory',remdir
mkeyw 'Help',remhel
mkeyw 'Host',remhos
mkeyw 'Kermit',remker
mkeyw 'Login',remlogin
mkeyw 'Message',remmsg
mkeyw 'Set',remset
mkeyw 'Space',remdis
mkeyw 'Type',remtyp
mkeyw 'Who',remwho
setval dw 300,302,310 ; answer REMOTE SET workers
dw 400,401,402,403,404,405,406
setvlen equ ($-setval)/2 ; number of entries
setvec dw sftype,sfcoll,sfinc ; routines paralleling setval
dw sblkck,srpkt,srtmo,sretry,sstmo,sxfrch,swind
remstt1 db 9 ; REMOTE SET top level table
mkeyw 'Attributes',1
mkeyw 'File',2
mkeyw 'Incomplete',310
mkeyw 'Block-check',400
mkeyw 'Receive',3
mkeyw 'Retry',403
mkeyw 'Server',404
mkeyw 'Transfer',405
mkeyw 'Window-slots',406
remsat1 db 2 ; REMOTE SET ATTRIBUTES
mkeyw 'IN',0
mkeyw 'OUT',100
remsat2 db 17 ; REMOTE ATTRIBUTES {IN} item
; REM ATT {OUT} item is 100 greater
mkeyw 'All',132
mkeyw 'Length',133
mkeyw 'Type',134
mkeyw 'Date',135
mkeyw 'Creator',136
mkeyw 'Account',137
mkeyw 'Area',138
mkeyw 'Block-size',139
mkeyw 'Access',140
mkeyw 'Encoding',141
mkeyw 'Disposition',142
mkeyw 'Protection',143
mkeyw 'Gprotection',144
mkeyw 'System-ID',145
mkeyw 'Format',146
mkeyw 'Sys-Info',147
mkeyw 'Byte-count',148
remsfit db 5 ; REMOTE SET FILE
mkeyw 'Type',300
mkeyw 'Names',301
mkeyw 'Collision',302
mkeyw 'Replace',303
mkeyw 'Incomplete',310
remsfty db 2 ; REMOTE SET FILE TYPE
mkeyw 'Text',0
mkeyw 'Binary',1
remsfna db 2 ; REMOTE SET FILE NAME
mkeyw 'Converted',0
mkeyw 'Literal',1
remsfco db 6 ; REMOTE SET FILE COLLISION
mkeyw 'Rename',0
mkeyw 'Replace',1
mkeyw 'Backup',2
mkeyw 'Append',3
mkeyw 'Discard',4
mkeyw 'Ask',5
remsfre db 2 ; REMOTE SET FILE REPLACE
mkeyw 'Preserve',0
mkeyw 'Default',1
remsfin db 2 ; REMOTE SET FILE INCOMPLETE
mkeyw 'Discard',0
mkeyw 'Keep',1
remsrcv db 2 ; REMOTE SET RECEIVE
mkeyw 'Packet-length',401
mkeyw 'Timeout',402
remsxfr db 1 ; REMOTE SET TRANSFER
mkeyw 'Character-set',405
onoff db 2 ; ON, OFF table
mkeyw 'off',0
mkeyw 'on',1
data ends
code segment public 'code'
extrn comnd:near, rpack:near, init:near, serini:near, rrinit:near
extrn read2:near, rpar:near, spar:near, intmsg:near, sparmax:near
extrn serhng:near, bufclr:near, bufrel:near, clrbuf:near, clearl:near
extrn dodec: near, doenc:near, packlen:near, send10:near, errpack:near
extrn pktsize:near, poscur:near, lnout:near, clrmod:near, ermsg:near
extrn rprpos:near, crun:near, prompt:near, prtscr:near, strcat:near
extrn strlen:near, strcpy:near, fparse:near, isfile:near, ihostr:near
extrn begtim:near, inptim:near, chktmo:near, pcwait:near, makebuf:near
extrn getbuf:near, nakpak:near, sndpak:near, response:near
extrn msgmsg:near, ackpak:near, dskspace:near, cdsr:near, dec2di:near
extrn takopen:near, takclos:near, setcom:near
assume cs:code, ds:data, es:nothing
; Server command
SERVER PROC NEAR
mov ah,cmword ; get a word
mov dx,offset srvbuf ; place to put text
mov bx,offset inthlp ; help message
call comnd ; get the pattern text
jnc serv1a ; nc = success
ret ; failure
serv1a: mov ah,cmeol
call comnd
jnc serv1b ; nc = success
ret
serv1b: mov srvtime,0 ; assume not doing timed residence
mov si,offset srvbuf
cmp byte ptr [si],0 ; any time given?
je serv4 ; e = no
cmp byte ptr [si],'0' ; numeric or colon?
jb serv2 ; b = not proper time value
cmp byte ptr [si],':' ; this covers the desired range
ja serv2 ; a = no proper time value
call inptim ; convert text to timeout tod
jnc serv3 ; c = syntax errors in time
serv2: stc ; failure
ret
serv3: mov srvtime,1 ; say doing timed residence
serv4: or flags.remflg,dserver ; signify we are a server now
call clrbuf ; clear serial port buffer of junk
test denyflg,pasflg ; Login required?
jnz serv4a ; nz = no
or denyflg,pasflg ; assume no login info required
mov al,luser ; check for user/password required
or al,lpass ; if both null then no checks
jz serv4a ; z = null, no name/pass required
and denyflg,not pasflg ; say need name/password
serv4a: mov dsptmp,0 ; assume no formatted server display
mov si,offset flags ; main flags structure
mov di,offset savflg ; save area
mov cx,savflgl ; length in bytes
push es
push ds
pop es
cld
rep movsb ; save all of them
mov si,offset dtrans ; default transmission parameters
mov di,offset savdtr ; save area
mov cx,savdtrl ; length
rep movsb ; save all of them
mov si,offset trans ; active transmission paramters
mov di,offset savtr ; save area
mov cx,savdtrl ; same length
rep movsb
mov al,maxtry
mov savmaxtry,al
pop es
test flags.remflg,dquiet ; quiet display?
jnz serv9 ; nz = yes
mov ah,prstr
mov dx,offset crlf
int dos
test flags.remflg,dserial ; serial display?
jnz serv5 ; nz = yes
call init ; init formatted display
call clrmod ; but no modeline yet
mov dl,fmtdsp
mov dsptmp,dl ; remember state of fmtdsp
mov dx,scrser ; move cursor near top of screen
call poscur
serv5: mov ah,prstr
mov dx,offset infms1 ; say now in server mode
int dos
; TOP OF SERVER IDLE LOOP
serv9: test flags.remflg,dquiet+dserial ; quiet or serial display?
jnz serv10 ; nz = yes, do not change screen
mov dx,scrmsg ; move cursor to Last message area
add dx,0100H ; look at line below (DOS does CR/LF first)
call poscur
call clearl ; and clear the line
mov dl,cr ; set cursor to left margin
mov ah,conout
int dos
serv10: mov flags.cxzflg,0 ; clear ^X, ^Z, ^C seen flag
mov flags.xflg,0 ; reset X packet flag
mov auxfile,0 ; say no override filename
mov srvbuf,0 ; work buffer, clear
mov al,dsptmp ; get our fmtdsp state
mov fmtdsp,al ; and restore it
call sparmax ; set our maximum capabilities
mov trans.windo,1 ; but only 1 window slot here
call makebuf ; remake all buffers for new windowing
call packlen ; determine max packet length
mov trans.chklen,1 ; checksum len = 1
mov pktnum,0 ; pack number resets to 0
mov al,dtrans.xchset ; reset Transmission char set
mov trans.xchset,al ; to the current user default
mov al,dtrans.xtype ; ditto for File Type
mov trans.xtype,al
mov al,srvtmo ; use server mode timeout
mov trans.stime,al ; use this interval in the idle loop
call serini ; init serial line, just in case
jnc serv11 ; nc = success
jmp serv20 ; c = failure
serv11: cmp srvtime,0 ; doing timed residence?
je serv12 ; e = no
call chktmo ; check for time to exit Server mode
jnc serv12 ; nc = ok
jmp serv20 ; c = timeout, exit server mode
serv12: mov windlow,0 ; reset windowing
mov pktnum,0 ; packet number to be used
call getbuf ; get a buffer
call rpack ; receive a packet, si has buffer ptr
mov al,dtrans.stime ; get default timeout interval
mov trans.stime,al ; restore active timeout interval
jc serv13 ; c = timeout, bad pkt, intervention
mov al,[si].seqnum ; sequence number received
mov rpacket.seqnum,al ; for our reply
or al,al ; must be sequence number of zero
jnz serv13 ; nz = bad packet
mov ah,[si].pktype
cmp ah,'I' ; never "decode" S, I, and A packets
je serv17 ; e = I packet
cmp ah,'S'
je serv17
cmp ah,'A'
je serv17
call dodec ; decode packet to decbuf
call bufrel ; release the packet buffer
jmp short serv17 ; dispatch on packet type in ah
serv13: cmp flags.cxzflg,'C' ; Control-C?
jne serv14 ; ne = no
mov flags.cxzflg,0 ; clear flag for later uses
jmp short serv20 ; and exit server mode
serv14: cmp flags.cxzflg,'E' ; ^E protocol abort?
jne serv15 ; ne = no
call bufclr ; clear all buffers
mov dx,offset cemsg ; user intervention message for error packet
call ermsg
mov bx,dx
call errpack ; send error message
call intmsg ; show interrupt msg for Control-C-E
jmp serv9
serv15: cmp [si].pktype,'T' ; packet type of time-out?
jne serv16 ; ne = no
mov rpacket.seqnum,0
call nakpak ; nak the packet, uses rpacket
serv16: call bufrel ; release the buffer
jmp serv9 ; return to top of server idle loop
serv17: cmp [si].pktype,'N' ; received a Nak?
je serv18 ; e = yes, ignore it
push es
push ds
pop es ; set es to data segment
mov di,offset srvchr ; server characters
mov cx,srvfln ; length of command set
mov al,ah ; packet type
cld
repne scasb ; hunt for it
pop es
je serv19 ; e = found that kind
mov dx,offset remms1 ; say unknown server command
call ermsg
mov bx,dx
call errpack ; tell the other kermit
serv18: jmp serv9 ; get another server command
serv19: 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
jc serv20 ; c = someone wanted to exit
jmp serv9 ; get another server command
serv20: mov di,offset flags ; main flags structure
mov si,offset savflg ; save area
mov cx,savflgl ; length in bytes
push es
push ds
pop es
mov al,flags.extflg ; leave server mode and Kermit flag
cld
rep movsb ; restore all of them
mov di,offset dtrans ; default transmission parameters
mov si,offset savdtr ; save area
mov cx,savdtrl ; length
rep movsb ; restore all of them
mov di,offset trans ; active transmission paramters
mov si,offset savtr ; save area
mov cx,savdtrl ; same length
rep movsb
mov flags.extflg,al ; set flag as current
mov al,savmaxtry
mov maxtry,al
pop es
call rprpos ; put prompt here
and flags.remflg,not dserver ; say not a server anymore
mov flags.cxzflg,0
clc
ret
SERVER ENDP
; commands executable while acting as a server
; Validate LOGIN status. Return carry set if login is ok, else
; send Error Packet saying Login is required (but has not been done) and
; return carry clear. Carry bit is this way because returning to the server
; idle loop with carry set exits the server mode.
logchk proc near
test denyflg,pasflg ; login required?
jnz logchk1 ; nz = no (disabled)
cmp slogin,0 ; logged in yet?
jne logchk1 ; ne = yes
mov dx,offset remms7 ; reply REMOTE LOGIN is required
call ermsg
mov bx,dx ; errpack works from bx
mov trans.chklen,1 ; reply with 1 char checksum
call errpack
clc ; say cannot proceed with command
ret
logchk1:stc ; say can proceed with command
ret
logchk endp
; srvsnd - receives a file that a remote kermit is sending
srvsnd proc near
call logchk ; check login status
jc srvsnd1 ; c = ok
ret ; else have sent error packet
srvsnd1:call init ; setup display form
xor ax,ax
test denyflg,sndflg ; command disabled?
jz srvsnd2 ; z = no
mov al,'.' ; dot+nul forces use of current dir
srvsnd2:mov word ptr auxfile,ax ; override name
mov rstate,'R' ; receive initiate state
jmp read2 ; packet pointer is SI, still valid
srvsnd endp
; srvrcv - send a file to a distant kermit
srvrcv proc near
call logchk ; check login status
jc srrcv1 ; c = ok
ret ; else have sent error packet
srrcv1: mov si,offset decbuf ; received filename, asciiz from dodec
test denyflg,getsflg ; command enabled?
jz srrcv2 ; z = yes
mov dx,si ; source string, from other side
mov di,offset srvbuf ; local path
mov si,offset rdbuf ; local filename
call fparse ; split string
srrcv2: mov di,offset diskio.string ; destination
call strcpy ; copy filename to diskio.string
mov auxfile,0 ; no alias name
mov sstate,'S' ; set sending state
jmp send10 ; this should send it
srvrcv endp
srverr proc near ; incoming Error packet
clc ; absorb and ignore
ret
srverr endp
; srvgen - G generic server command dispatcher
;
srvgen proc near
call bufrel ; release buffer
mov al,decbuf ; get first data character from pkt
cmp al,'I' ; LOGIN?
jne srvge1 ; ne = no
jmp srvlogin ; yes
srvge1: call logchk ; check login status
jc srvge2 ; c = ok
ret ; else have sent error packet
srvge2:cmp al,'T' ; Type a file?
jne srvge3 ; ne = no
jmp srvtyp ; do the typing
srvge3: cmp al,'D' ; do a directory?
jne srvge4
jmp srvdir ; do the directory command
srvge4: cmp al,'E' ; do a file erase (delete)?
jne srvge5
jmp srvdel ; do the delete command
srvge5: cmp al,'C' ; change working dir?
jne srvge6 ; ne = no
jmp srvcwd ; do it
srvge6: cmp al,'U' ; do a space command?
jne srvge7
jmp srvspc ; do the space command
srvge7: cmp al,'F' ; FIN?
jne srvge8 ; ne = no
jmp short srvfin
srvge8: cmp al,'L' ; LOGO or BYE?
jne srvge9 ; ne = no
call srvfin
pushf ; carry set means leave Server mode
call serhng ; hangup the phone and return
popf
jnc srvge8a ; nc = stay active (command denied)
mov flags.extflg,1 ; leave server mode and Kermit
srvge8a:mov di,offset flags ; main flags structure
mov si,offset savflg ; save area
mov cx,savflgl ; length in bytes
push es
push ds
pop es
mov al,flags.extflg ; leave server mode and Kermit flag
cld
rep movsb ; restore all of them
mov di,offset dtrans ; default transmission parameters
mov si,offset savdtr ; save area
mov cx,savdtrl ; length
rep movsb ; restore all of them
mov di,offset trans ; active transmission paramters
mov si,offset savtr ; save area
mov cx,savdtrl ; same length
rep movsb
mov flags.extflg,al ; make flag current
mov al,savmaxtry
mov maxtry,al
pop es
clc
ret
srvge9: cmp al,'M' ; one line Message?
jne srvge10 ; ne = no
jmp srvmsg
srvge10:cmp al,'W' ; WHO?
jne srvge11 ; ne = no
jmp srvwho
srvge11:cmp al,'H' ; Help?
jne srvge12 ; ne = no
jmp srvhlp
srvge12:cmp al,'S' ; SET?
jne srvgex ; ne = no
jmp srvset
srvgex: mov dx,offset remms1 ; reply Unknown server command
call ermsg
mov bx,dx
mov trans.chklen,1 ; reply with 1 char checksum
call errpack
clc
ret
srvgen endp
; srvfin - respond to remote host's Fin command
srvfin proc near
mov slogin,0 ; say not logged in anymore
mov si,offset byemsg ; add brief msg of goodbye
mov di,offset encbuf ; packet's data field
call strcpy ; copy msg to pkt
mov dx,si ; strlen works on dx
call strlen
push si
mov si,offset rpacket ; get a reply buffer
call doenc ; encode the reply in encbuf
pop si
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak
mov ax,100 ; wait 0.1 sec for client to settle
call pcwait
test denyflg,finflg ; command enabled?
jz srfin2 ; z = yes
clc ; stay in server mode
ret
srfin2: stc ; stc exits server mode
ret
srvfin endp
; srvcwd - handle other side's Remote CWD dirspec
srvcwd proc near
mov trans.chklen,1 ; reply with 1 char checksum
test denyflg,cwdflg ; is command enabled?
jz srcwd1 ; z = yes
mov dx,offset remms9 ; say command is disabled
call ermsg ; to us and
mov bx,dx
call errpack ; to the other Kermit
clc
ret
srcwd1: mov si,offset decbuf+1 ; point to byte count
xor bh,bh
mov bl,[si]
sub bl,' ' ; remove ascii bias from byte count
inc si
mov word ptr[si+bx],0 ; make ASCIIZ w/one extra null
call cdsr ; CD common sub-routine
mov si,dx ; returns msg in dx
mov di,offset encbuf ; put in encode buffer
call strcpy
mov dx,di
call strlen ; get its length to cx
mov si,offset rpacket ; use this packet for the reply
call doenc ; encode reply
call ackpak ; send ACK with data
clc
ret
srvcwd endp
; srvtyp - handle other side's Remote Type filename request
; expects "data" to hold Tcfilename where c = # bytes in filename
srvtyp proc near
cmp decbuf+1,0 ; any data in packet
je srtyp2 ; e = no
mov cl,decbuf+1 ; get the filename byte count
sub cl,' ' ; ascii to numeric
xor ch,ch ; set up counter
mov si,offset decbuf+2 ; received filename, asciiz from rpack
mov di,si
add di,cx
mov byte ptr [di],0 ; make string asciiz
test denyflg,typflg ; paths permitted?
jz srtyp1 ; z = yes, else use just filename part
mov di,offset srvbuf ; local path
mov si,offset rdbuf ; local filename
mov dx,offset decbuf+2 ; local string
call fparse ; split string
srtyp1: mov di,offset diskio.string ; copy local filename to destination
mov ax,di ; pointer to filename, for isfile
call strcpy ; do the copy
call isfile ; does it exist?
jnc srtyp3 ; nc = yes
srtyp2: mov si,offset remms5 ; "File not found"
mov di,offset encbuf ; destination for message
call strcpy ; move the message
mov dx,di
call strlen ; length to cx
mov si,offset rpacket ; use this packet for reply
call doenc ; encode
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak ; send ACK with message
clc
ret
srtyp3: mov flags.xflg,1 ; say use X packet rather than F pkt
mov auxfile,0 ; no alias name
mov sstate,'S' ; remember state
jmp send10 ; this should send it
srvtyp endp
; srvdir - handle other side's Remote Dir filespec(optional) request
srvdir proc near
mov di,offset decbuf+2 ; received filespec, asciiz from rpack
xor cx,cx ; assume no data in packet
mov cl,decbuf+1 ; get the filename byte count
cmp cl,' ' ; byte count present and > 0?
jg srdir1 ; g = yes
mov word ptr [di],0 ; clear data field
jmp short srdir2 ; 0 = no info in pkt
srdir1: sub cl,' ' ; ascii to numeric
add di,cx ; step to end of filename, terminate
mov word ptr [di],0 ; ensure string is asciiz
mov di,offset srvbuf ; local path
mov si,offset rdbuf ; local filename
mov dx,offset decbuf+2 ; local string
call fparse ; split string
test denyflg,dirflg ; paths permitted?
jz srdir2 ; z = yes, else use just filename part
mov si,offset rdbuf ; copy local filename to
mov di,offset decbuf+2 ; final filename
call strcpy ; copy just filename to buffer
srdir2: mov cl,curdsk ; current drive number
add cl,'A'-1 ; to letter
cmp decbuf+3,':' ; drive specified?
jne srdir3 ; ne = no
cmp decbuf+2,0 ; drive letter specified?
je srdir3 ; e = no
mov cl,decbuf+2 ; get drive letter
and cl,5fh ; convert to upper case
srdir3: call dskspace ; check if drive ready (drive => CL)
jnc srdir5 ; nc = success (drive is ready)
mov spcmsg3,cl ; insert drive letter
mov si,offset spcmsg2 ; say drive not ready
mov di,offset encbuf ; destination for message
call strcpy ; move the message
mov dx,di
call strlen ; length to cx
mov si,offset rpacket ; use this packet for reply
call doenc ; encode
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak ; send ACK with message
clc
ret
srdir5: mov di,offset srvbuf ; work area
mov si,offset dirstr ; prepend "dir "
call strcpy
mov si,offset decbuf+2 ; directory spec, asciiz
mov di,offset srvbuf
call strcat
; srdir6 does common processing for both REM DIR & REM HOST
SRDIR6: mov si,di ; srvbuf
mov di,offset auxfile ; send-as name is command line
call strcpy
mov dl,curdsk
add dl,'A'-1 ; change to letter
mov srvtmp+2,dl ; insert current disk drive
mov si,offset srvtmp ; add redirection tag " >d:$kermit$.tmp"
mov di,offset srvbuf
call strcat
mov si,offset srvbuf ; command pointer for crun
call crun
; fall thru! jmp srvtail ; send contents of temp file
srvdir endp
; Send contents of srvtmp+2 temporary file, or error packet if it does not
; exist.
srvtail proc near
mov si,offset srvtmp+2 ; get name of temp file
mov di,offset diskio.string ; destination
call strcpy ; copy it there
mov ax,di ; filename pointer for isfile
call isfile ; did we make the temp file?
jnc srvtai1 ; nc = yes
mov dx,offset remms10 ; "Could not create work file"
mov trans.chklen,1 ; reply with 1 char checksum
call ermsg
mov bx,dx
call errpack ; send the error message
clc
ret
srvtai1:mov flags.xflg,1 ; say use X rather than F packet
mov sstate,'S' ; remember state
call send10 ; this should send it
mov flags.xflg,0 ; clear flag
mov dx,offset srvtmp+2 ; name of temp file
mov ah,del2 ; delete the file
int dos
clc
ret ; return in any case
srvtail endp
; srvdel - handle other side's request of Remote Del filespec
srvdel proc near
test denyflg,delflg ; command enabled?
jz srvdel4 ; z = yes
mov dx,offset remms9 ; else give a message
mov trans.chklen,1 ; reply with 1 char checksum
call ermsg
mov bx,dx
call errpack ; back to local kermit
clc
ret
srvdel4:cmp decbuf+1,0 ; any data?
je srdel1 ; e = no
mov bl,decbuf+1 ; get the filename byte count
sub bl,' ' ; ascii to numeric
xor bh,bh
cmp bl,0 ; anything there?
jle srdel3 ; le = no
mov decbuf [bx+2],0 ; plant terminator
mov ax,offset decbuf+2 ; point to filespec
call isfile ; is/are there any to delete?
jc srdel1 ; c = there is none
test byte ptr filtst.dta+21,1EH ; attr bits: is file protected?
jz srdel2 ; z = not protected
srdel1: mov si,offset remms5 ; "File not found"
mov di,offset encbuf ; destination for message
call strcpy ; move the message
mov dx,di
call strlen ; length to cx
mov si,offset rpacket ; use this packet for reply
call doenc ; encode
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak ; send ACK with message
clc
ret
srdel2: mov di,offset encbuf ; work area
mov si,offset delstr ; prepend "del "
call strcpy
mov si,offset decbuf+2 ; append incoming filespec
call strcat ; append to "del "
mov si,di ; set pointer for crun
call crun
srdel3: mov dx,offset encbuf ; where command lies
call strlen ; length to cx
push si
mov si,offset rpacket ; packet to use for reply
call doenc ; encode reply
pop si
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak
clc
ret
srvdel endp
; srvlogin - handle other side's request of REMOTE LOGIN, USERNAME, PASSWORD
srvlogin proc near
mov slogin,0 ; say not logged in yet
cmp luser,0 ; local username specified?
je srvlog9 ; e = no, do no checking
mov cl,decbuf+1 ; ascii byte count of username
sub cl,' ' ; to binary
cmp cl,0 ; anything there?
jle srvlog8 ; le = no
xor ch,ch
mov si,offset decbuf+2 ; source, username field
mov di,offset luser ; local username template
cld
srvlog2:lodsb ; remote char
mov ah,[di] ; local char
inc di
or ax,2020h ; lower case both
cmp ah,al ; same?
jne srvlog8 ; ne = no, fail
loop srvlog2 ; continue match
cmp lpass,0 ; local password specified?
je srclog6 ; e = no, don't check incoming p/w
mov cl,decbuf+1 ; username length
sub cl,' '
xor ch,ch ; clear high byte
mov si,offset decbuf+2 ; skip over username field
add si,cx ; password length byte
mov cl,[si] ; ascii count of password bytes
sub cl,' ' ; to binary
jc srvlog8 ; carry means no field
inc si ; start of password text
mov di,offset lpass ; local password text, case sensitive
srvlog5:lodsb ; remote char
mov ah,[di] ; local char
inc di
cmp ah,al ; same?
jne srvlog8 ; ne = no, fail
loop srvlog5 ; do all chars
srclog6:mov slogin,1 ; declare user logged-in
jmp short srvlog9 ; ACK with brief message
srvlog8:mov si,offset remms2 ; say invalid login information
jmp short srvlog10
srvlog9:mov si,offset remms3 ; welcome aboard message
mov slogin,1 ; say logged in successfully
srvlog10:mov di,offset encbuf ; copy to here
call strcpy
mov dx,di ; where command lies
call strlen ; length to cx
push si
mov si,offset rpacket ; packet to use for reply
call doenc ; encode reply
pop si
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak
clc
ret
srvlogin endp
; srvspc - handle other side's request of Remote Space
srvspc proc near
test denyflg,spcflg ; is command enabled?
jz srspc1 ; z = yes
mov dx,offset remms9 ; else give a message
mov trans.chklen,1 ; reply with 1 char checksum
call ermsg
mov bx,dx
call errpack ; back to local kermit
clc
ret
srspc1: xor cl,cl ; use current drive
cmp decbuf+1,0 ; any data?
je srspc2 ; e = no
mov cl,decbuf+2 ; get the drive letter
srspc2: call dskspace ; calculate space, get letter into CL
jnc srspc3 ; nc = success
mov spcmsg3,cl ; insert drive letter
mov di,offset encbuf ; encoder buffer
mov si,offset spcmsg2 ; give Drive not ready message
call strcpy
jmp short srspc4 ; send it
srspc3: mov spcmsg1,cl ; insert drive letter
mov di,offset encbuf ; destination
mov word ptr[di],' ' ; space space
add di,2 ; start number here
call lnout ; convert number to asciiz in [di]
mov si,offset spcmsg ; trailer of message
call strcat ; tack onto end of number part
srspc4: mov trans.chklen,1 ; reply with 1 char checksum
mov dx,offset encbuf
call strlen ; get data size into cx for doenc
mov si,offset rpacket
call doenc ; encode
call pktsize ; report packet size
call ackpak
clc
ret
srvspc endp
; srvwho - respond to remote host's WHO command.
srvwho proc near
mov si,offset whomsg ; add brief msg of just us chickens
mov di,offset encbuf ; encoder source field
call strcpy ; copy msg to pkt
mov dx,si ; strlen works on dx
call strlen
mov si,offset rpacket
call doenc ; encode reply, size is in cx
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak
clc
ret
srvwho endp
; srvmsg - respond to remote host's Message (Send) command
; show message on our screen.
srvmsg proc near
cmp decbuf,0 ; any data in the packet?
jbe srvmsg2 ; e = no, just ack the message
cmp decbuf,'M' ; Message packet?
jne srvmsg2 ; ne = no, ack and forget
test flags.remflg,dquiet+dserial ; quiet or serial display?
jnz srvmsg1 ; nz = yes
mov dx,scrmsg ; move cursor to Last message area
call poscur
call clearl ; and clear the line
srvmsg1:xor ch,ch
mov cl,decbuf+1 ; data length
sub cl,' ' ; remove ascii bias
jle srvmsg2 ; le = nothing
mov di,offset decbuf+2 ; main part of message
call prtscr ; display cx chars on the screen
srvmsg2:mov rpacket.datlen,0 ; length
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak
clc
ret
srvmsg endp
; srvhos - handle other side's request of REM Host command-line. [jrd]
; We execute the command with STDOUT redirected to $kermit$.tmp and then
; read and transmit that file to the other end. No such file results in
; returning just an error msg ACK packet
srvhos proc near
test denyflg,hostflg ; command enabled?
jz srvhos2 ; z = yes
mov trans.chklen,1 ; reply with 1 char checksum
mov dx,offset remms9 ; else give a message
call ermsg
mov bx,dx
call errpack ; back to local kermit
clc
ret
srvhos2:mov si,offset decbuf ; received filename, asciiz from dodec
mov di,offset srvbuf ; destination
call strcpy ; copy data to srvbuf
jmp SRDIR6 ; do common completion code
srvhos endp
; Respond to other side's request of Remote Help. Write & read $kermit$.tmp
srvhlp proc near
mov dl,curdsk
add dl,'A'-1 ; change to letter
mov srvtmp+2,dl ; insert current disk drive
mov dx,offset srvtmp+2 ; use filename of d:$kermit$.tmp
mov ah,creat2 ; create the file
xor cx,cx ; attributes r/w
int dos
jc srvhlp1 ; c = could not open
mov dx,offset hlprem ; data to be sent, strlen uses dx
call strlen ; put string length in cx
mov bx,ax ; handle
mov ah,write2 ; write to file
int dos ; write the info
mov ah,close2 ; close the file so we can reread it below
int dos
srvhlp1:mov si,offset infms4 ; pseudo filename
mov di,offset auxfile ; send-as name
call strcpy ; copy it there
jmp srvtail ; send temporary file to remote screen
srvhlp endp
; srvker - handle other side's request of REM Kermit command-line. [jrd]
srvker proc near
test denyflg,kerflg ; command enabled?
jz srvker1 ; z = yes
mov trans.chklen,1 ; reply with 1 char checksum
mov dx,offset remms9 ; else give a message
call ermsg
mov bx,dx
call errpack ; back to local kermit
clc
ret
srvker1:call takopen ; open a Take file
jc srvker3 ; c = failed to obtain Take space
mov dx,prmptr ; get prompt
call prompt ; prompt user, set reparse address
mov bx,takadr ; pointer to Take structure
mov skertmp,bx ; remember it here for cleanup
mov [bx].taktyp,0ffh ; mark as a macro
mov dx,offset decbuf ; received command, asciiz
call strlen ; get length into cx
mov si,dx
srvker6:cmp byte ptr [si],' ' ; strip leading white space
ja srvker7 ; a = non-white
loop srvker6 ; continue
srvker7:cmp cx,8 ; need at least 8 chars "SET xx y"
jb srvker2 ; b = too few, bad command
mov ax,[si] ; get first two characters
or ax,2020h ; lower case them
cmp ax,'es' ; start of "SET"?
jne srvker2 ; ne = no, bad command
mov ax,[si+2] ; next two
or ax,2020h
cmp ax,' t' ; rest of "SET "?
jne srvker2 ; ne = no, bad command
add si,4 ; move to end of "SET "
sub cx,4
mov [bx].takcnt,cx ; number of bytes in command
push es
mov ax,[bx].takbuf ; segment of Take buffer
mov es,ax
mov di,1 ; place here (skip buf length byte)
cld
rep movsb
pop es
call setcom
jnc srvker3 ; nc = success
srvker2:mov si,offset remms6 ; "Command failed"
jmp short srvker4
srvker3:mov si,offset remms8 ; "Command succeeded"
srvker4:mov di,offset encbuf ; destination for message
call strcpy ; move the message
mov dx,di
call strlen ; length to cx
mov si,offset rpacket ; use this packet for reply
call doenc ; encode
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak ; send ACK with message
mov ax,skertmp ; get old take address
cmp ax,takadr ; same (still in current Take)?
jne srvker5 ; ne = no
call takclos ; close the Take file
srvker5:clc
ret
srvker endp
; Command Code Values
; REMOTE SET ATTRIBUTES IN ALL 132 0 = OFF, 1 = ON
; REMOTE SET ATTRIBUTES IN LENGTH 133 0 = OFF, 1 = ON
; REMOTE SET ATTRIBUTES IN TYPE 134 0 = OFF, 1 = ON
; REMOTE SET ATTRIBUTES IN DATE 135 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN CREATOR 136 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN ACCOUNT 137 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN AREA 138 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN BLOCK-SIZE 139 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN ACCESS 140 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN ENCODING 141 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN DISPOSITION 142 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN PROTECTION 143 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN GPROTECTION 144 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN SYSTEM-ID 145 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN FORMAT 146 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN SYS-INFO 147 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES IN BYTE-COUNT 148 0 = OFF, 1 = ON
;
; REMOTE SET ATTRIBUTES OUT ALL 232 0 = OFF, 1 = ON
; REMOTE SET ATTRIBUTES OUT LENGTH 233 0 = OFF, 1 = ON
; REMOTE SET ATTRIBUTES OUT TYPE 234 0 = OFF, 1 = ON
; REMOTE SET ATTRIBUTES OUT DATE 235 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT CREATOR 236 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT ACCOUNT 237 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT AREA 238 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT BLOCK-SIZE 239 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT ACCESS 240 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT ENCODING 241 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT DISPOSITION 242 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT PROTECTION 243 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT GPROTECTION 244 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT SYSTEM-ID 245 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT FORMAT 246 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT SYS-INFO 247 0 = OFF, 1 = ON
;X REMOTE SET ATTRIBUTES OUT BYTE-COUNT 248 0 = OFF, 1 = ON
;
; REMOTE SET FILE TYPE 300 0 = TEXT, 1 = BINARY
;X REMOTE SET FILE NAMES 301 0 = CONVERTED, 1 = LITERAL
; REMOTE SET FILE COLLISION 302 0 = RENAME, 1 = REPLACE,
; X 2 = BACKUP, X 3 = APPEND,
; 4 = DISCARD, X 5 = ASK
;X REMOTE SET FILE REPLACE 303 0 = PRESERVE, 1 = DEFAULT
; REMOTE SET INCOMPLETE 310 0 = DISCARD, 1 = KEEP
;
; REMOTE SET BLOCK-CHECK 400 number (1, 2, or 3)
; REMOTE SET RECEIVE PACKET-LENGTH 401 number (10-9024)
; REMOTE SET RECEIVE TIMEOUT 402 number (any, 0 = no timeout)
; REMOTE SET RETRY 403 number (any, 0 = no limit)
; REMOTE SET SERVER TIMEOUT 404 number (any, 0 = no timeout)
; REMOTE SET TRANSFER CHARACTER-SET 405 Character Set Designator
; REMOTE SET WINDOW-SLOTS 406 number (1-31)
;
; Items marked with "X" are ignored by this server
; srvset - manage incoming REMOTE SET commands
; decode buffer looks like S<len1><value1><len2><value2>
srvset proc near
mov bufptr,offset decbuf+1 ; received command data, asciiz
call srvswk ; worker to convert first value to ax
jc srvset3 ; c = failure
mov temp,ax ; save first value here
cmp ax,132 ; before known set?
jb srvset3 ; b = yes, bad
mov di,offset sattr ; assume SET ATTRIBUTES
cmp ax,148 ; still in range?
jbe srvset2 ; be = yes
cmp ax,232 ; before next range?
jb srvset1 ; b = yes
cmp ax,248 ; still in range?
jbe srvset2 ; be = yes, get final value
srvset1:push es ; do table lookup on other values
push ds
pop es
mov di,offset setval ; look up other codes in table
mov cx,setvlen
cld
repne scasw
pop es
mov bx,offset remms1 ; "Unknown server command", if needed
jne srvset3 ; ne = no match, unknown command
sub di,offset setval+2 ; get displacement
mov di,setvec[di]
srvset2:call di ; call the action routine
mov bx,offset remms6 ; "Command failed", if needed
jc srvset3 ; c = failure
mov si,offset remms8 ; "Command succeeded"
mov di,offset encbuf ; destination for message
call strcpy ; move the message
mov dx,di
call strlen ; length to cx
mov si,offset rpacket ; use this packet for reply
call doenc ; encode
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak ; send ACK with message
clc
ret
srvset3:mov trans.chklen,1 ; reply with 1 char checksum
call errpack ; send error message in ptr bx
clc
ret
srvset endp
sattr proc near ; SET ATTRIBUTES IN/OUT ITEM ON/OFF
mov ax,temp ; get kind of attribute
cmp ax,200 ; the OUT kind?
jb sattr1 ; b = no, IN kind
sub ax,100 ; merge to same thing
sattr1: cmp ax,132 ; ALL?
jne sattr2 ; be = ok
mov bl,0ffh ; all bits
jmp short sattr6
sattr2: cmp al,133 ; Length?
jne sattr3 ; ne = no
mov bl,attlen
jmp short sattr6
sattr3: cmp al,134 ; Type
jne sattr4 ; ne = no
mov bl,atttype
jmp short sattr6
sattr4: cmp bl,135 ; Date?
jne sattr5 ; ne = no, fail
mov bl,attdate
jmp short sattr6
sattr5: stc ; fail
ret
sattr6: call srvswk ; get second value to ax, 1 = on
jc sattr5 ; c = failure
cmp ax,0 ; off?
jne sattr7 ; ne = no, on
mov al,flags.attflg ; current flags
not bl ; invert selected items
and al,bl ; turn off selected items
mov flags.attflg,al ; store the flags
clc
ret
sattr7: cmp ax,1 ; on?
jne sattr5 ; ne = no, fail
or flags.attflg,bl ; insert ON selected bits
clc
ret
sattr endp
sftype proc near ; SET FILE TYPE
call srvswk ; get second value to ax
jc sftypb ; c = failure
cmp al,1
ja sftypb ; a = bad
mov trans.xtype,al ; store transfer type
clc
ret
sftypb: stc ; bad command
ret
sftype endp
sfcoll proc near ; SET FILE COLLISION
call srvswk ; get second value to ax
jc sfcollb ; c = failure
cmp ax,4
ja sfcollb ; a = bad
cmp ax,2 ; backup?
je sfcollb ; e = yes, bad command
cmp ax,3 ; append?
je sfcollb ; e = yes, bad command
mov flags.flwflg,al ; set file collison state
clc
ret
sfcollb:stc ; bad command
ret
sfcoll endp
sfinc proc near ; SET INCOMPLETE, SET FILE INCOMPLETE
call srvswk ; get second value to ax
jc sfincb ; c = failure
cmp ax,1
ja sfincb ; a = bad
mov flags.abfflg,al ; discard incomplete files if al = 1
clc
ret
sfincb: stc ; bad command
ret
sfinc endp
srtmo proc near ; SET RECEIVE TIMEOUT
call srvswk ; get second value to ax
jnc srtmo1 ; nc = success
ret
srtmo1: cmp ax,94 ; above limit?
jbe srtmo2 ; be = no
mov al,94
srtmo2: mov trans.rtime,al
clc
ret
srtmo endp
sblkck proc near ; SET BLOCK-CHECK
call srvswk ; get second value to ax
jnc sblkck1 ; nc = success
ret ; fail
sblkck1:cmp ax,3 ; our limit
jbe sblkck2 ; be = safe
mov ax,3 ; set to max
sblkck2:or ax,ax ; too small?
jnz sblkck3 ; z = no
inc ax
sblkck3:mov dtrans.chklen,al ; use this char as initial checksum
clc
ret
sblkck endp
srpkt proc near ; SET RECEIVE PACKET-LENGTH
call srvswk ; get second value to ax
jnc srpkt1 ; nc = success
ret
srpkt1: cmp ax,maxpack ; above limit?
jbe srpkt2 ; be = no
mov ax,maxpack
srpkt2: cmp ax,20 ; too small?
jae srpkt3 ; ae = no
mov ax,20 ; set minimum
srpkt3: mov dtrans.rlong,ax ; set long packet size
mov bl,dtrans.rpsiz ; regular packet size
xor bh,bh
cmp ax,bx ; is long packet shorter
jae srpkt4 ; ae = no
mov dtrans.rpsiz,al ; set regular pkt length too
srpkt4: clc
ret
srpkt endp
sretry proc near ; REMOTE SET RETRY
call srvswk ; get second value to ax
jnc sretry1 ; nc = success
ret ; fail
sretry1:cmp ax,63 ; our limit
jbe sretry2 ; be = safe
mov ax,63 ; set to max
sretry2:mov maxtry,al ; set packet retry limit
clc
ret
sretry endp
sstmo proc near ; SET SERVER TIMEOUT
call srvswk ; get second value to ax
jnc sstmo1 ; nc = success
ret
sstmo1: cmp ax,255
jbe sstmo2 ; be = in range
mov al,255 ; limit to max
sstmo2: mov srvtmo,al ; store timeout value
clc
ret
sstmo endp
sxfrch proc near ; SET TRANSFER CHARACTER-SET string
mov bx,bufptr
xor ch,ch
mov cl,[bx] ; byte count of next field, if any
sub cl,' ' ; remove ascii bias
jnc sxfrch1 ; nc = is ok
ret
sxfrch1:inc bx ; look at character string
cmp byte ptr[bx],'A' ; A for Transparent?
jne sxfrch2
cmp cx,1 ; just that char?
jne sxfrchb ; ne = no, fail
mov trans.xchset,0 ; set transfer char set to Transparent
clc
ret
sxfrch2:cmp cx,6 ; "I2/100"?
jne sxfrchb ; ne = no, fail
cmp word ptr [bx],'2I' ; length is ok, check spelling
jne sxfrchb ; ne = failure
cmp word ptr [bx+2],'1/'
jne sxfrchb
cmp word ptr [bx+4],'00'
jne sxfrchb
mov trans.xchset,1 ; set transfer char set to Latin1
clc
ret
sxfrchb:stc ; fail
ret
sxfrch endp
swind proc near ; SET WINDOW-SLOTS
call srvswk ; get second value to ax
jnc swind1 ; nc = success
ret
swind1: cmp ax,31 ; max legal
jbe swind2 ; be = in range
mov al,31 ; limit to max
swind2: or ax,ax ; no windowing?
jnz swind3 ; nz = no, not that way
mov ax,1 ; local min size for no windowing
swind3: mov dtrans.windo,al ; store default window size
clc
ret
swind endp
; Worker for srvset. Reads buffer pointed at by bufptr looking for
; construction <length><numbers>. Returns carry clear and binary number
; in AX, else carry set and AX = -1. Bufptr is always updated.
srvswk proc near
push bx
push cx
push dx
push si
mov bx,bufptr
xor ch,ch
mov cl,[bx] ; byte count of next field, if any
sub cl,' ' ; remove ascii bias
jnc srvswk1 ; nc = is ok
mov ax,-1 ; else say value is -1
jmp short srvswkx
srvswk1:inc bx
xor si,si ; accumulated value
mov dl,10
srvswk2:mov ax,si ; accumulated value
mul dl ; times 10
mov si,ax ; store
xor ah,ah
mov al,[bx] ; get a digit
inc bx
sub al,'0' ; remove ascii bias
jnc srvswk3 ; nc = no
mov ax,-1 ; say bad value
jmp short srvswkx ; and quit
srvswk3:add si,ax ; accumulate new digit
loop srvswk2 ; do all digits
mov ax,si ; return results in ax
clc
srvswkx:mov bufptr,bx ; remember where we read from decbuf
pop si
pop dx
pop cx
pop bx
ret
srvswk endp
; srvini - init parms based on 'I' init packet
srvini proc near
call spar ; parse info
call packlen
call makebuf ; remake buffers for new windowing
push si
mov si,offset rpacket
call rpar ; setup info about our reception
pop si
mov al,trans.chklen ; checksum length negotiated
push ax ; save around reply
mov trans.chklen,1 ; reply with 1 char checksum
call ackpak
pop ax ; restore checksum length
mov trans.chklen,al
clc ; success
ret
srvini endp
; BYE command - tell remote KERSRV to logout & exit to DOS
BYE PROC NEAR
mov ah,cmeol ; get a confirm
call comnd
jnc bye1 ; nc = success
ret ; failure
bye1: mov remcmd,'L' ; Logout command letter
call logo ; tell the host Kermit to logout
jc bye2 ; c = failed, do not exit
mov flags.extflg,1 ; set this Kermit's exit flag
call serhng ; hangup the phone
bye2: clc
ret
BYE ENDP
; FINISH - tell remote KERSRV to exit
FINISH PROC NEAR
mov ah,cmeol ; get a confirm
call comnd
jnc finish1 ; nc = success
ret ; failure
finish1:mov remcmd,'F' ; Finish command letter
call logo
clc
ret
FINISH ENDP
; LOGOUT - tell remote KERSRV to logout
LOGOUT PROC NEAR
mov ah,cmeol
call comnd ; get a confirm
jnc logout1 ; nc = success
ret ; failure
logout1:mov remcmd,'L' ; Logout command letter
call logo
clc
ret
LOGOUT ENDP
; Common routine for FINISH, LOGOUT, BYE
; Return carry clear for success, else carry set
LOGO PROC NEAR
call serini ; Initialize port
jnc logo1 ; nc = success
ret ; c = failure
logo1: call clrbuf ; clear serial port buffer
call ihostr ; initialize the host
mov diskio.string,0 ; clear local filename for stats
call makebuf ; set up packet buffers
mov pktnum,0 ; packet number to be used
mov windlow,0 ; reset windowing
call packlen ; get max packet length
call getbuf ; get buffer for sending
mov trans.chklen,1 ; use one char for server functions
mov ah,remcmd ; get command letter ('L' or 'F')
mov encbuf,ah ; encode the command
mov cx,1 ; one piece of data
call doenc ; do encoding
mov [si].pktype,'G' ; Generic command packet type
mov flags.xflg,1 ; say receiving to screen
call sndpak ; to suppress # pkts msg
jc logo3 ; c = failure
mov al,[si].seqnum ; get response for this sequence num
mov ah,maxtry ; retry threshold
call response ; get response
mov si,offset rpacket ; packet to look at
call msgmsg ; show any message
logo3: mov flags.cxzflg,0 ; clear these flags
mov flags.xflg,0
ret ; exit with carry flag from response
LOGO ENDP
; GET command. Ask remote server to send the specified file(s)
; Queries for remote filename and optional local override path/filename
GET PROC NEAR
mov auxfile,0 ; clear, for safety
mov encbuf,0 ; ditto
mov flags.cxzflg,0 ; no Control-C typed yet
mov bx,offset encbuf ; where to put text
mov dx,offset filmsg ; help
mov ah,cmline ; filenames with embedded whitespace
call comnd ; get text or confirm
jnc get1 ; nc = success
ret ; failure
get1: mov al,ah
xor ah,ah
mov cnt,ax ; remember number of chars we read
or al,al ; read in any chars?
jnz get7 ; nz = yes, analyze
; if empty line, ask for file names
get2: mov dx,offset remfnm ; ask for remote name first
call prompt
mov bx,offset encbuf ; place for remote filename
mov dx,offset frem ; help message
mov ah,cmline ; use this for embedded spaces
call comnd ; get a filename
jnc get3 ; nc = success
ret ; failure
get3: mov al,ah
xor ah,ah
mov cnt,ax ; remember number of chars read
or al,al ; count of entered chars
jz get2 ; z = none, try again
mov dx,offset lclfnm ; prompt for local filename
call prompt
mov bx,offset filhlp
mov dx,offset auxfile ; complete local filename
mov auxfile,0 ; clear, for safety
mov ah,cmword ; get a word
call comnd
jnc get5 ; nc = success
ret ; failure
get5: mov ah,cmeol ; get confirmation
call comnd
jnc get6 ; nc = success
ret ; failure
get6: cmp auxfile,'#' ; is first char a replacement for '?'
jne get7 ; ne = no
mov auxfile,'?' ; replace '#' by '?'
get7: cmp encbuf,'#' ; is first char a replacement for '?' ?
jne get8 ; ne = no
mov encbuf,'?' ; replace '#' by '?'
get8: call rrinit ; clear buffers and counters
mov flags.xflg,1 ; assume writing to screen
cmp flags.destflg,2 ; receiving to screen?
je get8a ; e = yes, skip screen stuff
mov flags.xflg,0 ; not writing to screen, yet
call init ; init (formatted) screen
get8a: call begtim ; start statistics
mov kstatus,0 ; global status, success
call makebuf ; setup packet buffers
call ipack ; Send Initialize, 'I', packet
jnc get8b ; nc = success
jmp short get10 ; failure
get8b: mov si,offset encbuf ; copy from here
mov di,offset fsta.xname ; to statistics remote name field
call strcpy
mov si,offset rpacket ; packet for response
mov cx,cnt ; get back remote filename size
call doenc ; encode data already in encbuf
jnc get9 ; nc = success
mov dx,offset ermes6 ; filename is too long for pkt
call ermsg
mov bx,dx ; point to message, for errpack
call errpack ; tell the host we are quiting
jmp short get10 ; data could not all fit into packet
get9: mov trans.chklen,1 ; use one char for server functions
mov rpacket.pktype,'R' ; Receive init packet
mov si,offset rpacket
call sndpak ; send the packet, no ACK expected
jc get10 ; c = failure to send packet
mov rstate,'R' ; Set the state to receive initiate
jmp READ2 ; go join read code
get10: call bufclr ; total failures come here
call rprpos ; reset cursor for prompt
or errlev,2 ; set DOS error level to cannot rcv
or fsta.xstatus,2 ; set status
mov kstatus,2 ; global status
mov flags.cxzflg,0 ; clear flag for next command
mov auxfile,0 ; clear send-as filename buffer
mov flags.xflg,0 ; clear to-screen flag
clc
ret
GET ENDP
; This is the REMOTE command
REMOTE PROC NEAR
mov dx,offset remtab ; Parse keyword from the REMOTE table
mov bx,offset remhlp
mov ah,cmkey
call comnd
jnc remote1 ; nc = success
ret ; failure
remote1:jmp bx ; do the appropriate routine
REMOTE ENDP
; REMSET - Execute a REMOTE SET command
REMSET PROC NEAR
mov rempac,'G' ; Packet type = generic
mov encbuf,'S' ; command type = Set
mov bufptr,offset encbuf+1 ; place more pkt material here
mov ah,cmkey ; get keyword
mov dx,offset remstt1 ; table of keywords
xor bx,bx ; help
call comnd
jnc remset1 ; nc = success
ret
remset1:cmp bx,1 ; Attributes?
jne remset5 ; ne = no
mov dx,offset remsat1 ; Attributes IN, OUT table
xor bx,bx ; help
mov ah,cmkey
call comnd
jnc remset2
ret
remset2:mov temp,bx ; save in out
mov dx,offset remsat2 ; next attributes keyword table
xor bx,bx ; help
mov ah,cmkey
call comnd
jnc remset3
ret
remset3:add bx,temp ; save final value
call remwork
mov dx,offset onoff ; ON, OFF table
xor bx,bx ; help
mov ah,cmkey ; get on,off
call comnd
jnc remset4
ret
remset4:jmp remset17
remset5:cmp bx,2 ; REMOTE SET FILE?
jne remset14 ; ne = no
mov dx,offset remsfit ; REM SET FILE table
xor bx,bx ; help
mov ah,cmkey
call comnd
jnc remset6
ret
remset6:push bx
call remwork ; write kind to buffer
pop bx
cmp bx,300 ; TYPE?
jne remset8
mov dx,offset remsfty ; TYPE table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset17
ret
remset8:cmp bx,301 ; NAME?
jne remset10 ; ne = no
mov dx,offset remsfna ; NAME table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset17
ret
remset10:cmp bx,302 ; COLLISION?
jne remset12 ; ne = no
mov dx,offset remsfco ; COLLISION table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset17
ret
remset12:cmp bx,303 ; REPLACE?
jne remset13 ; ne = no
mov dx,offset remsfre ; REPLACE table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset17
ret
remset13:cmp bx,310 ; INCOMPLETE?
jne remset13a ; ne = no
mov dx,offset remsfin ; INCOMPLETE table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset17
remset13a:stc
ret
remset14:cmp bx,310 ; REMOTE SET INCOMPLETE?
jne remset15 ; ne = no
push bx
call remwork ; write main command
pop bx
jmp short remset13 ; use above to complete the command
remset15:cmp bx,3 ; REMOTE SET RECEIVE?
jne remset18 ; ne = no
mov dx,offset remsrcv ; RECEIVE table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset19 ; get value as text
remset16:stc
ret
remset17:call remwork ; write to buffer
jmp remset22
; text as last item commands
remset18:mov temp,bx
cmp bx,405 ; Transfer?
jne remset19 ; ne = no
mov dx,offset remsxfr ; TRANSFER table
xor bx,bx
mov ah,cmkey
call comnd
jnc remset19
ret
remset19:call remwork ; store command type
mov dx,bufptr ; store response as text
inc dx ; skip count byte
mov bx,offset numhlp
cmp temp,405 ; Transfer character set needs string
jne remset20 ; ne = not string
mov bx,offset xfrhlp ; use this help
remset20:mov ah,cmword
call comnd
jnc remset21
ret
remset21:mov dx,bufptr ; field pointer
inc dx ; look at text
call strlen ; length to cx
add cx,' ' ; compute byte count field
mov bx,bufptr
mov [bx],cl ; store byte count
remset22:mov ah,cmeol ; get a confirmation
call comnd
jnc remset23
ret
remset23:mov dx,offset encbuf
call strlen ; get length
mov cnt,cx ; length for generic
mov flags.xflg,1 ; response coming to screen
jmp genr9 ; do the operation
REMSET ENDP
; Remote Set worker. Enter with new numerical value in BX. Writes length
; and asciiz value to encbuf and increments buffer pointer bufptr.
remwork proc near
mov di,offset rdbuf ; temp buffer
mov byte ptr [di],0 ; clear it
mov ax,bx
call dec2di ; convert value to asciiz
mov dx,offset rdbuf ; get length to cx
call strlen
push cx ; save length
mov di,bufptr ; byte count field
add cl,' ' ; to ascii
mov [di],cl ; store count byte
inc di
pop cx
mov si,offset rdbuf ; asciiz data source
push es
push ds
pop es
cld
rep movsb ; copy asciiz data value
pop es
mov byte ptr [di],0 ; insert null terminator
mov bufptr,di
ret
remwork endp
; REMDIS - Get disk usage on remote system
REMDIS PROC NEAR
mov remcmd,'U' ; Disk usage command
mov rempac,'G' ; Packet type = generic
mov remlen,1 ; optional text permitted
jmp genric ; Execute generic Kermit command
REMDIS ENDP
; REMHEL - Get help about remote commands
REMHEL PROC NEAR
mov remcmd,'H' ; Help
mov rempac,'G' ; Packet type = generic
mov remlen,0 ; no text required
jmp genric ; Execute generic Kermit command
REMHEL ENDP
; REMTYP - Type a remote file
REMTYP PROC NEAR
mov remcmd,'T' ; Type the file
mov rempac,'G' ; Packet type = generic
mov remlen,2 ; text required
jmp genric
REMTYP ENDP
; REMHOS - Execute a remote host command
REMHOS PROC NEAR
mov remcmd,' ' ; Don't need one
mov rempac,'C' ; Packet type = remote command
mov remlen,2 ; text required
jmp genric
REMHOS ENDP
; REMKER - Execute a remote Kermit command
REMKER PROC NEAR
mov remcmd,' ' ; Don't need one
mov rempac,'K' ; Packet type = remote Kermit command
mov remlen,2 ; text required
jmp short genric
REMKER ENDP
; REMDIR - Do a directory
REMDIR PROC NEAR
mov remcmd,'D'
mov rempac,'G' ; Packet type = generic
mov remlen,0 ; no text required
jmp short genric
REMDIR ENDP
; REMDEL - Delete a remote file
REMDEL PROC NEAR
mov remcmd,'E'
mov rempac,'G' ; Packet type = generic
mov remlen,2 ; text required
jmp short genric
REMDEL ENDP
; REMCWD - Change remote working directory
REMCWD PROC NEAR
mov remcmd,'C'
mov rempac,'G' ; Packet type = generic
mov remlen,0 ; no text required
jmp short genric
REMCWD ENDP
; REMLOGIN - LOGIN [username [password [account]]]
REMLOGIN PROC NEAR
mov remcmd,'I'
mov rempac,'G' ; Packet type = generic
mov remlen,0 ; no text required
jmp short genric
REMLOGIN ENDP
; REMMSG - Send one line short message to remote screen.
REMMSG proc near
mov remcmd,'M'
mov rempac,'G'
mov remlen,2 ; text required
jmp short genric
REMMSG endp
; REMWHO - ask for list of remote logged on users
REMWHO proc near
mov remcmd,'W'
mov rempac,'G'
mov remlen,1 ; optional text permitted
jmp short genric
REMWHO endp
; GENRIC - Send a generic command to a remote Kermit server
; remlen = 0: no additional text
; remlen = 1: additional text is optional
; remlen = 2: additional text is required
GENRIC PROC NEAR
mov si,offset infms3 ; dummy filename for transaction log
mov di,offset diskio.string ; where such names go
call strcpy ; move the name
mov bx,offset encbuf ; where to put text
mov temp,bx ; where field starts
cmp rempac,'C' ; Remote Host command?
je genr2 ; e = yes, no counted string(s)
cmp rempac,'K' ; Remote Kermit command?
je genr2 ; e = yes, no counted string(s)
genr1: mov ah,remcmd ; get command letter
mov [bx],ah ; store in buffer
inc temp ; inc to data field
add bx,2 ; leave room for type and size
genr2: mov ah,cmline ; get a line text
mov dx,offset genmsg ; help message
call comnd
jnc genr3 ; nc = success
ret ; failure
genr3: mov al,ah ; size
xor ah,ah
mov cnt,ax ; save it here
call genredir ; act on any ">filespec" redirection
add temp,ax ; point to next field
cmp rempac,'C' ; Remote Host command?
je genr4 ; e = yes, no counted string(s)
cmp rempac,'K' ; Remote Kermit command?
je genr4 ; e = yes, no counted string(s)
mov encbuf+1,al ; size of first field
add encbuf+1,32 ; do tochar function
inc temp ; include count byte
genr4: cmp al,remlen ; got necessary command text?
jae genr5 ; ae = yes
cmp remlen,1 ; is text optional?
je genr5 ; e = yes, continue without it
mov dx,offset infms2 ; say need more info
mov ah,prstr
int dos
or errlev,2 ; say cannot receive
or fsta.xstatus,2 ; set status failed
mov kstatus,2 ; global status
clc
ret
genr5: mov flags.xflg,1 ; output coming to screen
cmp rempac,'K' ; Remote Kermit command?
je genr8 ; e = yes
cmp rempac,'C' ; Remote host command?
je genr8 ; e = no, skip this part
cmp remcmd,'C' ; change working directory?
je genr7a ; e = yes, get optional password
cmp remcmd,'I' ; remote login command?
je genr6 ; e = yes
jmp short genr8 ; neither so no extra prompts here
genr6: cmp cnt,0 ; have user name already?
jne genr7 ; ne = yes
mov dx,offset user ; prompt for username
call prompt
mov bx,offset encbuf+1 ; skip command letter
mov temp,bx ; start of field
call input ; read text
jc genr8 ; c = none
mov temp,bx ; point to next data field
genr7: mov dx,offset password ; get optional password
call prompt
genr7a: mov bx,temp ; where to put the password
mov comand.cmquiet,1 ; turn on quiet mode
call input ; read in the password
mov comand.cmquiet,0 ; turn off quiet mode
jc genr8 ; c = no text, do not add field
mov temp,bx ; point to next data field
;
cmp remcmd,'I' ; remote login command?
jne genr8 ; ne = no
mov dx,offset account ; get optional account ident
call prompt
mov bx,temp ; where this field starts
call input ; read text
jc genr8 ; c = no text, do not add field
mov temp,bx ; point to next data field
; all fields completed
genr8: mov ax,temp ; pointer to next field
sub ax,offset encbuf ; minus start of buffer = data length
mov cnt,ax ; remember size here
cmp flags.cxzflg,'C' ; Control-C entered?
jne genr9 ; ne = no
stc
ret ; return failure
GENR9: mov kstatus,0 ; global status
call ipack ; Send Init parameters
jc genr11 ; c = failure
mov trans.chklen,1 ; use 1 char for server functions
mov fsta.pretry,0 ; no retries yet
mov pktnum,0
cmp flags.cxzflg,'C' ; did the user type a ^C?
jne genr10 ; ne = no
stc
ret ; return in error state
genr10: push si
mov si,offset rpacket ; use this packet for reply
mov cx,cnt ; length of data
call doenc ; encode data
mov trans.chklen,1 ; use block check 1 to server
mov ah,rempac ; packet type
mov rpacket.pktype,ah
call sndpak ; send the Generic command packet
pop si
jc genr11 ; c = failure
mov rstate,'R' ; next state is Receive Initiate
jmp READ2 ; file receiver does the rest
genr11: mov flags.xflg,0 ; reset screen output flag
xor ax,ax ; tell statistics this was a read
or errlev,4 ; DOS error level, failure of REMote cmd
mov fsta.xstatus,4 ; set status
mov kstatus,4 ; global status
clc
ret
GENRIC ENDP
; Extract ">filespec" redirection at end of command line. If found put
; filespec in auxfile as new output name.
genredir proc near
mov cx,cnt ; chars on command line
mov di,offset encbuf+2 ; buffer, after prologue
add di,cx ; end of buffer + 1
dec di ; last char
push ax
mov al,'>' ; redirection symbol
push es
push ds
pop es
std ; scan backward
repne scasb ; found '>'?
cld
pop es
pop ax
jne genred3 ; ne = no
inc di ; look at '>'
mov byte ptr[di],0 ; insert terminator
mov ax,cx ; new count length
mov cnt,cx ; remember here too
genred1:inc di ; look at optional filename
or di,di ; terminator?
jz genred2 ; z = yes
cmp byte ptr [di],' ' ; remove lead-in puncutation
jbe genred1 ; be = punctuation, go until text
genred2:mov si,di
mov di,offset auxfile ; new output name goes here
call strcpy
genred3:ret
genredir endp
; Send "I" packet with transmission parameters
IPACK PROC NEAR
call serini ; initialize serial port
jnc ipack1
ret ; c = failure
ipack1: call clrbuf ; clear serial port buffer
call ihostr ; initialize the host
call sparmax ; set up our maximum capabilites
mov trans.windo,1 ; no windows yet
mov rpacket.numtry,0 ; number of receive retries
mov fsta.pretry,0 ; no retries
call makebuf ; remake buffers
mov pktnum,0 ; packet number 0
mov windlow,0 ; reset windowing
call packlen ; compute packet length
call getbuf ; get buffer for sending
call rpar ; store them in the packet
mov trans.chklen,1 ; one char for server function
mov [si].pktype,'I' ; "I" packet
call sndpak ; send the packet
jnc ipack2 ; nc = success
ret ; return failure
ipack2: mov al,[si].seqnum
mov ah,maxtry ; retry threshold
add ah,ah
add ah,maxtry ; triple the normal retries
call response ; get response
jnc ipack3 ; nc = success
call bufclr ; clear all
stc ; carry set for failure
ret ; return failure
ipack3: push si
mov si,offset rpacket ; packet address
call spar ; read in the data
pop si
call packlen ; get max send packet size
call makebuf ; remake buffers for new windowing
clc
ret ; return success
IPACK ENDP
; Returns BX the updated pointer to the input buffer
; input buffer = <ascii data length count byte>textstring
; return carry clear if have text, else carry set for none
INPUT PROC NEAR
mov temp2,bx ; where to put byte count
inc bx ; start text after count byte
xor dx,dx ; help, none
mov ah,cmline ; get text with embedded whitespace
call comnd
jnc input1 ; nc = success
mov bx,temp2 ; empty field, restore pointer
ret ; failure
input1: push bx
mov bx,temp2
add ah,' ' ; convert byte count to ascii
mov [bx],ah ; store count byte
pop bx ; return pointer to next free byte
clc ; say have bytes
ret
INPUT ENDP
code ends
end