$INCLUDE(msdefs.h86) NAME RMXKERM QUIT EQU DOS+1 true equ 1 stack segment stack 'stack' dw 600 dup(?) stk equ this word stack ends datas segment public 'datas' public citok, cotok, mbox, tmbox, sigpair, sematok extrn flags:byte,pack:byte,prttab:word,port1:byte,source:word extrn sintok:word,machnam:byte,dstmbx:word,srcptr:word extrn portval:word,savsi:word,xofsnt:byte,soutok:word,portatt:word extrn bddat:word,inbaud:word,dstflg:word env db 'COMSPEC=',0ffh,'/',0 ; "environment" must be db 'PATH=',0feh,'/',0,0 ; on PARA boundary ci db 4,':CI:' co db 4,':CO:' term db 6,':TERM:' lp db 4,':LP:' com1 db 6,':COM1:' t1 db 4,':T1:' dolsgn db 1,'$' rqglob db 8,'RQGLOBAL' dotini db 12,'MSKERMIT.INI' ; dotini is RMX string, db 0 ; dotini+1 is ASCIIZ string sigpair dw 0 db 3 ; control C setosc db ESC,']C:T=3,E=1,O=1,C=2',ESC,'\' tabosc db ESC,']T:E13=192',ESC,'\' tabesc db ESC,'[1;5H', ESC,'[2W',ESC,'[1;13H', ESC,'[2W' db ESC,'[1;21H', ESC,'[2W',ESC,'[1;29H', ESC,'[2W' db ESC,'[1;37H', ESC,'[2W',ESC,'[1;45H', ESC,'[2W' db ESC,'[1;53H', ESC,'[2W',ESC,'[1;61H', ESC,'[2W' db ESC,'[1;69H', ESC,'[2W',ESC,'[1;77H', ESC,'[2W' db ESC,'[1;85H', ESC,'[2W',ESC,'[1;93H', ESC,'[2W' db ESC,'[1;101H',ESC,'[2W',ESC,'[1;109H',ESC,'[2W' db ESC,'[1;117H',ESC,'[2W',ESC,'[1;125H',ESC,'[2W',ESC,'[2J' ltabesc equ $-tabesc printer db 0,'PRN ' chkdsk db 'chkdsk.com' dirfree db 'dir $ free' pushmsg db cr,lf,'PUSH not implemented, use RUN whatever$' wrn1prt db cr,lf,'Warning: Neither :COM1: nor :T1: were found' db cr,lf,':TERM: will be used as COM1',cr,lf,'$' wldcdms db cr,lf,'Wild cards aren''t supported at this end$' syserr db cr,lf,'Your version of MSKERMIT used an unsupported DOS ' db 'function call',cr,lf,'$' crlf db cr,lf,'$' even citok dw ? cotok dw ? sematok dw ? lptok dw ? initok dw 0 globtok dw ? mbox dw ? tmbox dw ? kbuf dw ? cmdtok dw ? status dw ? ccstat dw ? siostat dw ? savspec dw 12,12,12 dup (0) ignore dw ? xcepinf dw 3 dup (0) temp dw 110 dup(?) org offset temp db 'Copyright 1985, John Bryans. Permission is granted to copy' db ' and give away, but not to sell any form of this program. ' db 'California State University, Long Beach and Columbia University' db ' are granted all rights.' org offset temp+size temp savint dd 2 dup(?),dosint,quitint lpbuf db dmasiz dup (?) PURGE conin,conout,lstout,dconio,prstr,seldsk,openf,closf,sfirst,snext PURGE delf,readf,writef,makef,gcurdsk,setdma,prsfcb,dosver PURGE open2,close2,readf2,lseek dosf dw notimp ; DOS function call jump table dw conin dw conout dw 2 dup(notimp) dw lstout dw dconio dw dconin dw rkbd dw prstr dw 4 dup(notimp) dw seldsk dw openf dw closf dw sfirst dw snext dw delf dw readf dw writef dw makef dw 2 dup(notimp) dw gcurdsk dw setdma dw 10 dup(notimp) dw setintv dw 3 dup(notimp) dw prsfcb dw 2 dup(notimp) dw gettim dw 3 dup(notimp) dw dosver dw 4 dup(notimp) dw getintv dw 7 dup(notimp) dw open2 dw close2 dw readf2 dw 2 dup(notimp) dw lseek dw chmod dw 6 dup(notimp) dw setblk dw exec chartab db 9 dup(82h),81h,22 dup(82h) db 81h,'!',82h,'#$%&''()*',81h,81h,'-',80h,82h,'0123456789' db 81h,81h,82h,81h,82h,'?' db '@ABCDEFGHIJKLMNOPQRSTUVWXYZ',3 dup(82h),'^_' db '`1`ABCDEFGHIJKLMNOPQRSTUVWXYZ{',82h,'}~',82h datas ends code segment public 'code' assume cs:cgroup,ds:datas,ss:stack public crfile, opfile, special, reader, writer, delcon, prstr_ public aopen, aread, awrite, aspcl, waitio, sendms extrn start:near,rdbaud:near,serrst:near,outchr:near extrn dqexit:near,dqdecodetime:near,dqgetsystemid:near extrn rqcgetchar:near,rqcgetcommandname:near extrn rqccreatecommandconnection:near,rqcsendcommand:near extrn rqsopen:near,rqsdeleteconnection:near,rqsattachfile:near extrn rqsreadmove:near,rqsseek:near,rqsgetconnectionstatus:near extrn rqscreatefile:near,rqswritemove:near,rqsspecial:near extrn rqsgetfilestatus:near,rqsdeletefile:near,rqsclose:near extrn rqstruncatefile:near,rqslookupconnection:near extrn rqaopen:near,rqaread:near,rqawrite:near,rqaspecial:near extrn rqwaitio:near extrn rqsetexceptionhandler:near,rqsetpriority:near,rqcreatetask:near extrn rqcreatesemaphore:near,rqreceiveunits:near,rqgetpoolattrib:near extrn rqcreatemailbox:near,rqreceivemessage:near,rqsendmessage:near extrn rqlookupobject:near,rqdeletesegment:near,rqsetdefaultprefix:near psp: int quit ; "program segment prefix" siz dw 0 db 0 db 9ah,0f0h,0ffh,0dh,0f0h ; beats the hell out of me dd quitint ; termination address dd cctask ; control-break address dd quitint ; critical error address db (psp+2ch)-$ dup(?) dw seg env ; segment address of environment db (psp+50h)-$ dup(?) fake proc far int DOS ; DOS function dispatcher entry ret fake endp db (psp+80h)-$ dup(?) cline db 82 dup(0) begin proc far mov ax,datas ; save & set interrupt vectors mov es,ax mov di,offset savint sub bx,bx mov ds,bx mov si,4*DOS mov cx,4 cld rep movsw mov ds,ax mov si,di mov di,4*DOS mov es,bx mov cx,4 cli rep movsw sti call setexcp push ds ; call rqgetpoolattrib(@temp,@status) mov ax,offset temp push ax push ds mov ax,offset status push ax call rqgetpoolattrib mov ax,temp ; set size in program segment prefix mov siz,ax ; to poolmax mov ax,cs ; move command line to cline mov es,ax mov di,offset cline sub al,al L1: inc byte ptr cline stosb ; clears count 1st time thru push es ; save es & di push di push ds ; al=call rqcgetchar(@status) mov ax,offset status push ax call rqcgetchar pop di ; restore es & di pop es test al,al ; end of string? jnz L1 ; no mov di,offset ci ; citok=rqscreatefile(@(4,':CI:'),@status) call crfile mov citok,ax mov bx,3 ; call rqsopen(citok,3,2,@status) mov cx,2 call opfile mov di,offset co ; cotok=rqscreatefile(@(4,':CO:'),@status) call crfile mov cotok,ax mov bx,2 ; call rqsopen(cotok,2,2,@status) mov cx,bx call opfile mov ax,cotok ; call rqsspecial(cotok,4,@savspec,0,@status) mov bx,offset savspec mov cx,4 call special test savspec+18,8000h js L2 mov word ptr savspec+2,7 L2: mov ax,citok ; set OSCs for :CI: mov bx,offset setosc mov cx,length setosc call writer mov ax,cotok ; set OSCs for :CO: mov bx,offset setosc mov cx,length setosc call writer mov ax,citok ; rumor has it write before read mov bx,offset crlf ; is s'posed to convince Terminal Support Code mov cx,2 ; we're serious about wanting transparent input call writer mov di,offset dotini ;is MSKERMIT.INI in default directory? call atfile jcxz L5 ; yes push ds ; no, get pathname that called us mov ax,offset temp ; call rqgetcommandname(@temp,size temp,@status) push ax mov ax,size temp push ax push ds mov ax,offset status push ax call rqcgetcommandname mov ax,ds ; back scan to last path separator mov es,ax mov bl,byte ptr temp sub bh,bh lea si,temp[bx] std L3: lodsb dec bx cmp al,':' je L4 cmp al,'/' je L4 cmp al,'^' jne L3 L4: cld mov di,si add di,2 mov si,offset dotini+1 ; catenate 'MSKERMIT.INI' to path mov cx,length dotini add bl,cl mov byte ptr temp,bl rep movsb mov di,offset temp call atfile ; is MSKERMIT.INI in same directory we are? jcxz L5 ; yes jmp short L7 ; no L5: mov initok,ax ; save for open2 mov bx,1 mov cx,bx call opfile ; open for reading mov ax,initok mov bx,offset temp mov cx,size temp call reader ; read enuf into temp to get line 1 cmp byte ptr temp,';' ; is it commented out? jne L6 ; no, bypass configuration mov ax,ds mov es,ax mov di,offset temp+1 mov cx,0ffffh mov al,cr repne scasb ; find length of line 1 neg cx add cx,0fffeh mov bx,offset temp+1 mov ax,cotok call writer ; write it out mov ax,cotok mov bx,offset tabosc mov cx,length tabosc call writer ; write OSC to simulate clear tab mov ax,cotok mov bx,offset tabesc mov cx,ltabesc call writer ; clear enuf tabs so they're 8 apart L6: mov ax,initok push ax push dx mov ax,offset status push ax ; close MSKERMIT.INI, call rqsclose ; but leave attached for open2 L7: sub ax,ax ; sematok=rqcreatesemaphore(0,1,0,@status) push ax inc ax push ax dec ax push ax push ds mov ax,offset status push ax call rqcreatesemaphore mov sematok,ax mov sigpair,ax ; for ^C trapping call crmbx ; mbox=rqcreatemailbox(0,@status) mov mbox,ax call crmbx ; tmbox=rqcreatemailbox(0,@status) mov tmbox,ax call crmbx ; dstmbx=rqcreatemailbox(0,@status) mov dstmbx,ax call crmbx ; dstmbx+2=rqcreatemailbox(0,@status) mov dstmbx+2,ax mov bx,offset cctask ; call rqcreatetask call crtsk ; (0,@cctask,datas,0,300,0,@status) mov bx,offset siotsk ; call rqcreatetask call crtsk ; (0,@siotask,datas,0,300,0,@status) mov ax,citok ; establish ^C & sematok as signal pair mov cx,6 mov bx,offset sigpair call special mov di,offset com1 ; is there a :COM1:? call crfile jcxz L8 ; yes mov di,offset t1 ; is there a :T1:? call crfile jcxz L8 ; yes mov di,offset term ; neither, use :TERM: call crfile mov dx,offset wrn1prt ; warn user push ax push di call prstr pop di pop ax L8: mov sintok,ax ; save token mov prttab+2,di ; fill in MSXRMX's port table mov bx,1 call aopen ; open for reading assume cs:code call rdbaud ; get its baud rate mov port1.baud,cx call serrst ; reset the port assume cs:cgroup mov ax,citok ; call rqccreatecommandconnection(citok, push ax ; cotok,0,@status) mov ax,cotok push ax sub ax,ax push ax push ds mov ax,offset status push ax call rqccreatecommandconnection ; can you believe this shit! mov cmdtok,ax mov di,offset lp ; lptok=rqscreatefile(@(4,':LP:'),@status) call crfile mov lptok,ax mov bx,2 ; call rqopen(lptok,2,2,@status) mov cx,bx call opfile push ds ; call dqgetsystemid(@temp,@status) mov ax,offset temp push ax push ds mov ax,offset status push ax call dqgetsystemid mov ax,ds ; use system id for machine name mov es,ax mov si,offset temp+1 mov di,offset machnam mov cl,byte ptr temp sub ch,ch rep movsb mov al,'$' ; it's a $ terminated string stosb sub bx,bx ; globtok= rqlookupobject(0,@rqglob,0,@status) push bx push ds mov ax,offset rqglob push ax push bx push ds mov ax,offset status push ax call rqlookupobject mov globtok,ax sub ax,ax ; call rqsetpriority(0,254,@status) push ax mov ax,254 push ax push ds mov ax,offset status push ax call rqsetpriority mov ax,cs mov ds,ax ; point ds & es to psp mov es,ax assume cs:code ; keep LINK86 happy jmp start assume cs:cgroup ; ditto begin endp dosint proc far ; DOS function call table look up cmp ah,4bh ja notimp push bx push ds mov bx,datas mov ds,bx sub bh,bh mov bl,ah rol bx,1 call dosf[bx] pop ds pop bx iret dosint endp notimp proc ; not implemented DOS function error routine sti mov dx,offset syserr call prstr jmp stop notimp endp quitint proc far stop: sti mov dx,offset crlf call prstr ; mov ax,cotok ; give Terminal Support Code an ESC c ; mov bx,offset ESC_c ; to restore terminal to initial state ; mov cx,length ESC_c ; remove ;s if TSC ever gets fixed ; call writer ; don't hold your breath mov ax,cotok ; restore terminal attributes mov bx,offset savspec mov cx,5 call special sub ax,ax ; restore interrupt vectors & return to system mov es,ax mov di,4*DOS mov si,offset savint mov cx,4 cli rep movsw sti push ax ; call dqexit(0) call dqexit quitint endp cctask proc far ; ^C task mov ax,1 mov bx,sematok push bx push ax mov ax,0ffffh push ax push ds mov ax,offset ccstat push ax call rqreceiveunits cmp flags.debug,1 ; slightly adapted (mostly stolen) from je stop ; MSKERM's intbrk mov flags.cxzflg,'C' mov pack.state,'A' jmp cctask cctask endp siotsk proc far ; serial input task call setexcp ; never call exception handler SIO1: mov ax,mbox ; wait forever @ mbox for something to do push ax mov ax,0ffffh push ax push ds mov ax,offset ignore push ax push ds mov ax,offset siostat push ax call rqreceivemessage cmp ax,mbox ; if it's the token for mbox, je SIO3 ; it's SERINI asking us to crank up input push ax ; otherwise it's an IORS push ds mov ax,offset siostat push ax call rqdeletesegment ; so delete it cmp sintok,0 ; if the port has been reset, je SIO1 ; let the interrupts expire unanswered SIO2: call sread ; clear next buffer quadrant & start aread mov ax,savsi sub ax,srcptr ; if there's at least 1 quadrant between next js SIO1 ; quadrant & current pointer, cmp ax,bufsiz/4 jge SIO1 ; we don't need to XOF, so wait for interrupt mov bx,portval cmp [bx].floflg,0 ; is flow control enabled? je SIO1 ; no mov ax,[bx].flowc ; ouput whatever we're using for XOF mov ah,al assume cs:code call outchr assume cs:cgroup nop nop nop mov xofsnt,true jmp SIO1 SIO3: mov bl,flags.comflg ; get port number sub bh,bh shl bx,1 ; convert to word index mov di,prttab[bx] call crfile ; create file mov sintok,ax ; save serial input token mov bx,1 call aopen ; open for reading mov bx,portval mov bx,[bx].baud ; get port's baud index shl bx,1 ; convert to word index mov ax,bddat[bx] ; look up baud rate mov inbaud,ax ; put it in port attributes mov ax,sintok ; for aspecial to set it mov bx,offset portatt or word ptr[bx+4],3 ; change to flushing mode mov cx,5 ; while we're at it call aspcl SIO4: mov bx,offset source ; initialize mov savsi,bx ; current byte ptr mov srcptr,bx ; & next quadrant ptr mov cx,bufsiz ; in case the ports on a buffered board mov dx,tmbox ; flush it's buffer call aread mov ax,sintok mov bx,tmbox call waitio cmp ax,bufsiz je SIO4 ; no matter how big the damn thing is mov ax,sintok mov bx,offset portatt and word ptr[bx+4],0fffdh ; change back to transparent mode mov cx,5 call aspcl sub ax,ax mov dstflg,ax ; clear flags for MSXRMX's outpkt mov dstflg+2,ax call sread ; clear 1st quadrant & start 1st read jmp SIO2 ; go do 2nd read sread proc mov ax,ds mov es,ax mov bx,srcptr ; next quadrant ptr, bx for reading mov di,bx ; di for clearing sub ax,ax mov cx,bufsiz/8 cld rep stosw ; clear quadrant cmp di,bufsiz+offset source ; was it last quadrant jl SRD1 ; no mov di,offset source ; yes, point to 1st SRD1: mov srcptr,di ; set next quadrant ptr mov cx,bufsiz/4 mov dx,mbox call aread ; read current quadrant ret sread endp siotsk endp conin proc call rkbd ; read 1 from :CI: to al push dx mov dl,al ; conout writes out dl call conout ; echo it to :CO: pop dx ret conin endp conout proc call save mov ax,cotok ; write dl to :CO: CO1: sti mov cx,1 mov temp,dx mov bx,offset temp call writer call rstr ret conout endp lstout proc call save mov ax,lptok ; write dl to :LP: jmp CO1 lstout endp dconio proc cmp dl,0ffh ; if dl ain't ff, jne conout ; it's same as conout call save sub cx,cx cmp cl,flags.remflg ; bypass if REMOTE ON jne DCIO1 call rdci ; read 1 from :CI: to temp, on return DCIO1: mov si,sp ; cx=1 if read, 0 if not or ss:word ptr[si+22],40h ; set zero flag jcxz DCIO2 ; jump if not read and ss:[si+22],0ffbfh ; clear zero flag DCIO2: call rstr mov al,byte ptr temp ; return byte read ret dconio endp dconin proc call save DC1: call rdci ; read 1 from :CI: to temp jcxz DC1 ; 'til we get 1 call rstr mov al,byte ptr temp ; return byte read ret dconin endp rkbd proc call save sti RDK1: mov ax,citok ; read 1 form :CI: to al mov bx,offset temp mov cx,1 call reader test ax,ax jz RDK1 ; 'til we get 1 call rstr mov al,byte ptr temp ret rkbd endp rdci proc ; reads 1 from :CI: to temp, doesn't wait, doesn't check ^C sti ; retuns cx=1 if read, 0 if not sub ax,ax mov temp,ax mov sigpair,ax ; turn off ^C trap mov ax,citok mov bx,offset sigpair mov cx,6 call special mov ax,citok ; read 1 from :CI: to temp mov bx,offset temp mov cx,1 call reader push ax ; save num read mov ax,sematok ; restore ^C trap mov sigpair,ax mov ax,citok mov bx,offset sigpair mov cx,6 call special pop cx ; return num read ret rdci endp prstr proc prstr_ equ prstr call save ; call rqswritemove(cotok,ds:dx,#char,@status) sti mov ax,ds mov es,ax mov di,dx mov cx,0ffffh mov al,'$' repne scasb neg cx add cx,0fffeh ; cx=#characters mov ax,cotok mov bx,dx call writer call rstr ret prstr endp seldsk proc mov al,1 ; what the hell, say there's 1 ret seldsk endp openf proc call save sti call fcb2fn ; convert fcb to RMX file name jc OPF2 ; jump if NG push di ; save file name ptr push dx ; save fcb ptr call atfile ; attach file OPF1: pop bx ; fcb ptr push bx ; save again mov [bx+24],ax ; stash file token in fcb mov bx,3 mov cx,2 call opfile ; open for reading & writing w/2 buffers pop bx ; fcb ptr pop di ; file name ptr jcxz OPF3 ; jump if attach & open were OK OPF2: call rstr mov al,0ffh ; return NG ret OPF3: push bx ; save fcb ptr call gfilest ; get file status; uses di as file name ptr pop bx ; fcb ptr jcxz OPF4 ; jump if OK, jmp OPF2 ; else return NG OPF4: cmp byte ptr temp+9,0 ; gfilest put file info in temp je OPF2 ; if not a named file, return NG mov ax,temp+54 mov [bx+16],ax ; file size low part to fcb mov ax,temp+56 mov [bx+18],ax ; file size high part to fcb OPF5: mov [bx+12],cx ; clear fcb's current block ptr mov [bx+26],cx ; clear file written flag in fcb mov word ptr[bx+14],dmasiz ; set fcb's record size call rstr sub al,al ; return OK ret openf endp closf proc call save sti mov si,dx ; fcb ptr mov bx,[si+24] ; file token cmp word ptr[si+26],0 ; has file been written? je CF2 ; no cmp bx,lptok ; to printer? jne CF1 ; no mov ax,bx ; yes mov bx,kbuf mov cx,[si+16] ; compute bytes in last buffer sub cx,[si+28] add cx,dmasiz call writer ; and write it out jmp CF3 ; c'est tout CF1: push bx ; save push bx ; for truncate push bx ; for seek mov ax,2 ; call rqsseek(filtok,2,filength,@status) push ax mov ax,[si+18] push ax mov ax,[si+16] push ax push ds mov ax,offset status push ax call rqsseek push ds ; call rqstruncatefile(filtok,@status) mov ax,offset status push ax call rqstruncatefile pop bx CF2: call delcon ; delete the file connection CF3: call rstr CF4: mov bl,0ffh CF5: sub al,al cmp status,0 ; if staus=0 je CF6 ; return OK mov al,bl ; else return NG CF6: ret closf endp sfirst proc call save sti mov ax,ds mov es,ax mov di,dx mov al,'?' mov cx,12 repne scasb ; any wildcards? jne SF2 ; nope SF1: mov dx,offset wldcdms ; yup call prstr ; gripe call rstr mov al,0ffh ; & return NG ret SF2: call fcb2fn ; convert fcb to RMX file name call gfilest ; get file status jcxz SF3 ; OK call rstr mov al,0ffh ; NG ret SF3: call rstr sub al,al ret sfirst endp snext proc call save ; if it ever gets to here jmp SF1 ; whine snext endp delf proc call save sti call fcb2fn ; convert fcb to RMX file name push ds push di push ds mov ax,offset status push ax call rqsdeletefile ; delete it call rstr jmp CF4 delf endp readf proc call save sti mov bx,dx ; fcb ptr mov ax,[bx+24] ; file token mov cx,[bx+14] ; DOS record size mov temp,cx ; save it mov bx,kbuf ; buffer address call reader jcxz RF2 ; jump if OK mov bx,1 cmp cx,65h ; if EOF, use return code 1 je RF1 inc bx ; else 2 RF1: mov temp,bx ; save return code call rstr mov bx,temp ; restore return code jmp CF5 RF2: mov cx,temp ; DOS record size cmp ax,cx ; = num read? jne RF3 ; no sub bx,bx ; yes, use 0 return code jmp RF1 RF3: mov di,kbuf ; fill out partial record w/0's add di,ax sub cx,ax mov ax,ds mov es,ax sub al,al rep stosb mov bx,3 ; & use return code 3 jmp RF1 readf endp writef proc call save sti mov bx,dx ; fcb ptr mov cx,[bx+14] ; DOS record size mov dx,[bx+16] ; add it to file size in fcb mov ax,[bx+18] add dx,cx adc ax,0 mov [bx+16],dx mov [bx+18],ax mov ax,[bx+24] ; file token cmp ax,lptok je WR2 ; handle :LP: differnt mov bx,kbuf call writer ; write it out WR1: call rstr mov bx,dx mov [bx+26],bx ; set file written flag in fcb mov bl,1 ; use return code 1, when status<>0 jmp CF5 WR2: mov [bx+28],dx ; save least sig size for closef cmp word ptr[bx+26],0 ; 1st buffer je WR3 ; yes mov bx,offset lpbuf ; write previous buffer push cx call writer pop cx WR3: shr cx,1 ; save current buffer for next time mov ax,ds mov es,ax mov si,kbuf mov di,offset lpbuf rep movsw jmp WR1 writef endp makef proc call save sti mov ax,ds mov es,ax mov si,offset printer ; is it PRN:? mov di,dx mov cx,11 ; compensating bug; KERMIT only sets 11 repe cmpsb je MF2 ; yes, use :LP: call fcb2fn ; no, convert fcb to RMX file name jnc MF1 ; OK call rstr ; NG mov al,0ffh ret MF1: push di push dx call crfile ; create file jmp OPF1 ; to finsh up MF2: mov ax,lptok mov bx,dx ; fcb ptr mov [bx+24],ax ; lptok to file token in fcb sub cx,cx mov [bx+16],cx ; clear file size in fcb mov [bx+18],cx jmp OPF5 ; to finish up makef endp gcurdsk proc sub al,al ; always A: -- meaningless anyway ret gcurdsk endp setdma proc mov kbuf,dx ; save disk buffer address ret setdma endp setintv proc ret ; if KERMIT ever does more than setintv endp ; setup int 23h, we're in trouble prsfcb proc call save sti mov bx,offset chartab mov dx,di ; fcb ptr sub al,al mov byte ptr temp,al ; clear al return flag stosb ; 0 drive in fcb mov al,' ' ; blank file name in fcb mov cx,11 rep stosb mov di,dx ; fcb ptr PRS1: call gch ; get character jns PRS2 ; jump if valid cmp al,81h ; is it a separator jbe PRS1 ; yes, scan off jmp short PRS6 ; no, it's a terminator; return failure PRS2: cmp byte ptr[si],':' ; is 2nd char a drive separator je PRS5 ; yes inc di ; step past fcb drive byte dec si ; backup to 1st char PRS3: mov cx,8 ; get up to 8 filename chars call prscan ; if no terminator or separator, jns PRS6 ; return failure cmp al,80h ; code for '.' jne PRS4 ; if it ain't '.' we're done mov di,dx ; point to fcb extension field add di,9 mov cx,3 ; get up to 3 extension chars call prscan ; if not separated or terminated, jns PRS6 ; return failure PRS4: mov bx,sp mov [bx+8],si ; update saved si to current parse ptr call rstr mov al,byte ptr temp ; return code ret PRS5: inc si ; point past : mov byte ptr temp+2,al ; stash drive letter sub al,'@' ; drive letter OK? jle PRS6 ; no, Z stosb ; yes, put drive number in fcb mov byte ptr temp+1,1 ; temp+1 & 2 are RMX string push es push di push si push dx push bx push ds ; call rqslookupconnection(@temp+1,@status) mov ax,offset temp+1 push ax push ds mov ax,offset status push ax call rqslookupconnection pop bx pop dx pop si pop di pop es jcxz PRS3 ; jump if drive letter corresponds to valid prefix PRS6: sub cx,cx ; otherwise call prscan ; scan to terminator or separator mov byte ptr temp,0ffh ; and return failure jmp PRS4 prscan proc call gch ; get char js PSC4 ; jump if terinator or separator cmp al,'*' ; if '*' jne PSC1 mov byte ptr temp,1 ; set wildcard return code mov al,'?' ; & fill field w/'?'s rep stosb jmp short PSC3 PSC1: stosb cmp al,'?' ; if '?' jne PSC2 mov byte ptr temp,1 ; set wildcard return code PSC2: loop prscan ; cook 'til done PSC3: call gch ; get next char PSC4: ret prscan endp gch proc ; get character & translate it lodsb and al,7fh xlatb test al,al ret gch endp prsfcb endp gettim proc call save sti sub ax,ax ; let dword @temp be system time mov temp,ax ; set to 0, so decodetime returns current time mov temp+2,ax push ds ; call dqdecodetime(@temp,@status) mov ax,offset temp push ax push ds mov ax,offset status push ax call dqdecodetime call rstr push ax mov dx,temp+12 call asc2bin mov ch,dl ; ch=hours mov dx,temp+15 call asc2bin mov cl,dl ; cl=minutes mov dx,temp+18 call asc2bin mov dh,dl ; dh=seconds sub dl,dl ; dl=0 hundredths pop ax ret asc2bin proc sub dx,'00' shl dl,1 mov al,dl shl dl,1 shl dl,1 add dl,al add dl,dh ret asc2bin endp gettim endp dosver proc mov al,2 ; we're simulating DOS 2.x ret dosver endp getintv proc ret ; if KERMIT ever does more than getintv endp ; setup int 23h, we're in trouble open2 proc call save sti sub ah,ah ; convert DOS mode to RMX inc ax mov temp,ax ; save mode mov ax,ds mov es,ax mov si,dx mov di,offset dotini+1 ; is it MSKERMIT.INI mov cx,length dotini repe cmpsb jne OP1 ; no mov ax,initok ; yes, initok's already attached jmp short OP3 OP1: mov si,dx ; ASCIIZ string @ds:dx to RMX string @temp+2 mov di,offset temp+2 mov al,0ffh OP2: stosb ; clears count 1st time thru lodsb inc byte ptr temp+2 test al,al jnz OP2 mov di,offset temp+2 ; token=rqsattachfile(@temp+2,@status) call atfile OP3: mov bx,temp ; get mode mov temp,ax ; save token mov cx,2 ; call rqsopen(token,mode,2,@status) call opfile call rstr mov ax,temp ; return token to caller in ax mov bx,2 cryflg: push bp mov bp,sp and [bp+12],0fffeh ; clear carry cmp status,0 ; OK? je CFLG1 ; yes or word ptr[bp+12],1 ; no, set carry mov ax,bx ; & return error code CFLG1: pop bp ret open2 endp close2 proc call save sti mov bx,sp ; bx from stack has file token mov bx,word ptr ss:[bx+16] call delcon ; delete connection call rstr mov bx,6 ; error flag, if necessary jmp cryflg close2 endp readf2 proc call save sti mov bx,sp ; bx from stack has file token mov ax,word ptr ss:[bx+16] mov bx,dx ; nbyt=rqsreadmove(token,@buf,cnt,@status) call reader mov temp,ax ; save # bytes read call rstr mov ax,temp ; return to caller in ax mov bx,6 ; error flag, if necessary jmp cryflg readf2 endp lseek proc call save sti mov bx,sp ; bx from stack has file token mov bx,word ptr ss:[bx+16] push bx ; save for get con. status push bx ; call rqsseek(token,mode,count,@status) sub ah,ah ; convert DOS mode to RMX add al,2 push ax push cx push dx push ds mov ax,offset status push ax call rqsseek push ds ; call rqsgetconnectionstatus(token, mov ax,offset temp ; @temp,@status) push ax push ds mov ax,offset status push ax call rqsgetconnectionstatus call rstr mov ax,temp+4 ; dx:ax are file pointer mov dx,temp+6 mov bx,6 ; error flag, if necessary jmp cryflg lseek endp chmod proc ; 'tisn't chmod at all. differentiates PUSH, DIR, & SPACE call save ; for exec. MSKERMIT calls it twice. mov si,sp or ss:word ptr[si+22],1 ; set carry mov di,dx cmp byte ptr[di],0ffh jne CH1 ; it ain't PUSH or DIR mov word ptr[di],00fdh ; set up so exec can decide 'tween PUSH jmp short CH4 ; & DIR CH1: cmp byte ptr[di],0feh ; is it 1st pass? je CH5 ; yes mov si,offset chkdsk ; ='chkdsk.com' mov cx,length chkdsk rep cmpsb mov di,dx jne CH2 mov word ptr[di],00fch ; it's SPACE, flag for exec jmp short CH4 CH2: cmp byte ptr[di],0 ; change \ path separators to ^ je CH4 cmp byte ptr[di],'\' jne CH3 mov byte ptr[di],'^' CH3: inc di jmp CH2 CH4: mov si,sp and ss:[si+22],0fffeh ; clear carry CH5: call rstr ret chmod endp setblk proc ret setblk endp exec proc call save sti mov bx,sp mov bx,ss:[bx+16] ; saved bx mov bx,[bx+2] ; command tail pointer mov si,dx cmp byte ptr[si],0fdh ; is it PUSH or DIR? jne EX1 ; no cmp byte ptr[bx],0 ; is it PUSH? jne EX0 ; no, it's DIR mov dx,offset pushmsg ; it's PUSH, issue message call prstr ; call rqswritemove(cotok,@pushmsg, call rstr ; count,@temp) ret EX0: mov ch,0 ; it's DIR, scan off DOS garbage mov cl,[bx] lea di,[bx+1] mov al,'d' repne scasb inc cl mov byte ptr temp+4,cl ; balance of command tail is now a lea si,[di-1] ; respectable DIR command mov di,offset temp+5 ; set up to move it to string @temp+4 jmp short EX4 EX1: sub ax,ax ; initialize string @temp+4 mov di,offset temp+4 stosb cmp byte ptr[si],0fch ; is it SPACE? jne EX2 ; no mov si,offset dirfree ; yes, use 'dir $ free' as command mov cx,length dirfree mov byte ptr temp+4,cl jmp short EX4 EX2: lodsb ; move command to string @temp+4 inc byte ptr temp+4 test al,al jz EX3 stosb jmp EX2 EX3: mov al,' ' ; ensure a space 'tween command & tail stosb mov si,bx ; points to command tail lodsb ; add command tail to string add byte ptr temp+4,al mov cx,ax jcxz EX6 EX4: lodsb cmp al,'\' ; convert \ to ^ path separator jne EX5 mov al,'^' EX5: stosb loop EX4 EX6: mov dx,offset crlf call prstr mov ax,cmdtok ; call rqcsendcommand(cmdtok,@temp+4, push ax ; @temp+2,@status) push ds mov ax,offset temp+4 push ax push ds dec ax dec ax push ax push ds mov ax,offset status push ax call rqcsendcommand cmp cx,83h ; is it E$CONTINUED je EX8 ; yes, clear status & return mov ax,globtok ; lookup rqglobal push ax push ds mov ax,offset dolsgn push ax sub ax,ax push ax push ds mov ax,offset temp push ax call rqlookupobject sub bx,bx ; & set default prefix push bx ; in case user used RUN ATTACHFILE push ax push ds mov ax,offset temp push ax call rqsetdefaultprefix EX7: call rstr mov bx,2 ; error code, if necessary jmp cryflg EX8: mov status,0 jmp EX7 exec endp save proc ; save regs pop bx push es push si push di push dx push cx push ax jmp bx save endp rstr proc ; restore regs pop bx pop ax pop cx pop dx pop di pop si pop es jmp bx rstr endp setexcp proc push ds ; call rqsetexceptionhandler(@xcepinf,@status) mov ax,offset xcepinf push ax push ds mov ax,offset status push ax call rqsetexceptionhandler ret setexcp endp crtsk proc ; ax=rqcreatetask(0,cs:bx,ds,0,300h,0,@status) sub ax,ax ; bx is start address push ax push cs push bx push ds push ax push ax mov bx,300h push bx push ax push ds mov ax,offset status push ax call rqcreatetask ret crtsk endp crmbx proc ; ax=rqcreatemailbox(0,@status) sub ax,ax push ax push ds mov ax,offset status push ax call rqcreatemailbox ret crmbx endp atfile proc ; ax=rqsattachfile(ds:di,@status) push ds ; ds:di is path ptr push di push ds mov ax,offset status push ax call rqsattachfile ret atfile endp crfile proc ; ax=rqscreatefile(ds:di,@status) push di ; ds:di is path ptr. save di push ds push di push ds mov ax,offset status push ax call rqscreatefile pop di ; restore di ret crfile endp opfile proc ; call rqsopen(ax,bx,cx,@status) push ax ; token push bx ; mode push cx ; number of buffers push ds mov ax,offset status push ax call rqsopen ret opfile endp delcon proc ; call rqsdeleteconnection(bx,@status) push bx ; token push ds mov ax,offset status push ax call rqsdeleteconnection ret delcon endp special proc ; call rqsspecial(ax,cx,ds:bx,0,@status) push ax ; token push cx ; function push ds push bx ; data ptr sub ax,ax push ax push ax push ds mov ax,offset status push ax call rqsspecial ret special endp reader proc ; ax=rqsreadmove(ax,ds:bx,cx,@status) push ax ; token push ds push bx ; buffer ptr push cx ; number of bytes push ds mov ax,offset status push ax call rqsreadmove ret reader endp writer proc ; ax=rqswritemove(ax,ds:bx,cx,@status) push ax ; token push ds push bx ; buffer ptr push cx ; number of bytes push ds mov ax,offset status push ax call rqswritemove ret writer endp aopen proc ; call rqaopen(ax,bx,3,0,@status) push ax ; token push bx ; mode mov bx,3 push bx sub ax,ax push ax push ds mov ax,offset status push ax call rqaopen ret aopen endp aread proc ; call rqaread(sintok,ds:bx,cx,dx,@siostat) mov ax,sintok push ax push ds push bx ; buffer ptr push cx ; count push dx ; response mailbox push ds mov ax,offset siostat push ax call rqaread ret aread endp awrite proc ; call rqawrite(soutok,ds:bx,cx,dx,@siostat) mov ax,soutok push ax push ds push bx ; buffer ptr push cx ; count push dx ; response mailbox push ds mov ax,offset siostat push ax call rqawrite ret awrite endp aspcl proc ; call rqaspecial(ax,cx,ds:bx,tmbox,@siostat) push ax ; token push cx ; function push ds push bx ; ioparm ptr mov ax,tmbox push ax push ds mov ax,offset siostat push ax call rqaspecial mov ax,tmbox ; ax=rqreceivemessage(tmbox,0ffffh,@ignore,@siostat) push ax mov ax,0ffffh push ax push ds mov ax,offset ignore push ax push ds mov ax,offset siostat push ax call rqreceivemessage push ax ; call rqdeletesegment(ax,@siostat) push ds mov ax,offset siostat push ax call rqdeletesegment ret aspcl endp waitio proc ; ax=rqwaitio(ax,bx,0ffffh,@status) push ax ; token push bx ; response mailbox mov ax,0ffffh push ax push ds mov ax,offset status push ax call rqwaitio ret waitio endp sendms proc ; call rqsendmessage(ax,bx,0,@status) push ax ; mailbox token push bx ; object to send sub ax,ax push ax push ds mov ax,offset status push ax call rqsendmessage cld ret sendms endp fcb2fn proc ; converts DOS fcb to RMX file name mov bx,dx ; fcb ptr cmp byte ptr[bx],0ffh ; is it an extended fcb jne FCB0 ; no INT 3 ; really tacky FCB0: mov si,offset temp+131 ; point to end of RMX file name lea di,[bx+11] ; point to end of fcb mov cx,3 ; extension max chars sub bx,bx ; cumulative RMX string count mov al,' ' std repe scasb ; scan off trailing blanks je FCB1 ; jump if no extension inc di ; point to last non-blank in fcb inc cx ; adjust ext count add bx,cx ; add to string count xchg si,di rep movsb ; move ext to string mov byte ptr[di],'.' ; add ext separator dec di ; point in front of it xchg si,di inc bx ; add 1 to string count FCB1: mov cx,8 ; filename max chars repe scasb ; scan off trailing blanks inc di ; point to last non-blank in filename inc cx ; adjust filename count add bx,cx ; add to string count xchg si,di rep movsb ; move filename to string lodsb ; get drive number from fcb test al,al ; is it default? jz FCB3 ; yes cmp al,26 ; is it <=Z jle FCB2 ; yes stc ; no, return error ret FCB2: add al,'@' ; put corresponding RMX prefix in string mov ah,':' ; i.e. DOS Z: is RMX :Z: dec di stosw mov al,ah inc di stosb add bx,3 ; add 3 to string count for prefix FCB3: mov [di],bl ; stash string count in front ret fcb2fn endp gfilest proc ; call rqsgetfilestatus(ds:di,@temp,@status) push ds push di ; path ptr push ds mov ax,offset temp push ax push ds mov ax,offset status push ax call rqsgetfilestatus ret gfilest endp code ends end begin, ds:datas, ss:stack:stk