NAME MSZRMX true equ 1 escbslh equ 5c1bh ; ESC \ escbrac equ 5d1bh ; ESC ] $INCLUDE(mssdef.h86) %*DEFINE(pushv(v))(%IF(%OS EQ 286)THEN(push %v)ELSE(mov ax,%v push ax)FI) datas segment public citok, cotok, mbox, tmbox, sigpair, sematok, bufill, ciptr public cifill, cibuf1, cibuf2, combx, cimbx, termatt, oneport public subpksz, trok, source, trmstr, temp, machnam extrn sintok:word, srcptr:word, takadr:word, taklev:byte, comand:byte extrn portval:word, savsi:word, xofsnt:byte, portatt:word extrn costrt:word, coptr:word, flags:byte, pack:byte, dtrtime:word extrn bdtab:byte, bddat:word env db 0,0 ; "environment" must be on PARA boundary machnam db 21 dup(' ') trmstr db 6,':TERM:' lp db 4,':LP:' bb db 4,':BB:' work db 6,':WORK:' dolsgn db 1,'$' rqglob db 8,'RQGLOBAL' dotini db 'MSKERMIT.INI',0 kermtmp db '$kermit$.tmp ',0 ; Kermit's DOS name for scratch file sigpair dw 0 db 3 ; control C kilpair dw 0 db 0 setosc db ESCAPE,']C:T=1,E=1,R=1,O=1,C=2;T:R=1',ESCAPE,'\' flush db ESCAPE,']C:T=3',ESCAPE,'\' escapec db ESCAPE,'c' printer db 'PRN',0 typecmd db 'type ' delcmd db 'del ' chkdsk db 'chkdsk.com' dirfree db 'dir $ free',cr delrmx db 'delete ' ; keep these 2 lines together deltail db 73 dup(?) wccmd db 0,'WC ' ; keep these 2 lines together wcpath db 80 dup(?) pushmsg db cr,lf,'PUSH not implemented, use RUN whatever$' syserr db cr,lf,'Your version of MSKERMIT used an unsupported DOS ' db 'function call' crlf db cr,lf,'$' cfgerr db cr,lf,'Configuration error',cr,lf,'$' killmsg db cr,lf,'Only 1st KILL accepted',cr,lf,'$' mbmsg db cr,lf,'MAX-BAUD error',cr,lf,'$' oscmsg db cr,lf,'OSC error',cr,lf,'$' prmsg db cr,lf,'Priority error',cr,lf,'$' nmsg db cr,lf,'Number > 0ffh',cr,lf,'$' dnmsg db cr,lf,'Must be decimal number',cr,lf,'$' nxtflg db 1 oneport db 0 codone db ? esc_c db 0 trok db 0 $SAVE NOGEN comtab db 13 %mkeyw (%('bufill'),fillbuf) %mkeyw (%('cifill'),fillci) %mkeyw (%('co-delay'),codel) %mkeyw (%('dtr-time'),dtr) %mkeyw (%('echo'),takset) %mkeyw (%('escc'),esccset) %mkeyw (%('kill'),kill) %mkeyw (%('max-baud'),maxbd) %mkeyw (%('no-modem'),nomdm) %mkeyw (%('osc'),osc) %mkeyw (%('priority'),prior) %mkeyw (%('sub-pack'),subpack) %mkeyw (%('translate'),trnslt) $RESTORE even citok dw ? ; DON'T reorder citok, cotok, lptok lines cotok dw 3 dup (?) lptok dw ? sematok dw ? initok dw 0 globtok dw ? doltok dw ? scfitok dw ? rcmdtok dw ? mbox dw ? tmbox dw ? cimbx dw ? combx dw ? kbuf dw ? cmdtok dw ? xitcode dw 40ffh savebx dw ? status dw ? ccstat dw ? siostat dw ? priorty dw 254 bufill dw 0ffffh cifill dw 8080h subpksz dw 60 codelay dw 6 ciptr dw offset cibuf1 cistrt dw ? inisize dw ? savspec dw 12,12,12 dup (0) termatt dw 2,2,2 dup (?) ; terminal port attributes for special ignore dw ? xcepinf dw 3 dup (0) temp dw 110 dup(?) org offset temp db 'Copyright 1988, John Bryans.' db 'Permission is granted to copy and give away,' db 'but not to sell for profit any form of this program.' db 'No Warranties Whatsoever' org offset temp+size temp cibuf1 db cibufl dup (?) cibuf2 db cibufl dup (?) cobuf1 db cobufl dup (?) cobuf2 db cobufl dup (?) source db bufsiz dup(0) ; serial input buffer PURGE conin,conout,lstout,dconio,coninq,prstr,seldsk,gcurdsk,setdma,gettim PURGE dosver,gswitch,chdir,creat2,open2,close2,readf2,write2,del2,lseek,gcd PURGE alloc,setblk,exec,first2,next2 dosf dw notimp ; DOS function call jump table dw conin dw conout dw 2 dup(notimp) dw lstout dw dconio dw coninq dw rkbd dw prstr dw 4 dup(notimp) dw seldsk dw 10 dup(notimp) dw gcurdsk dw setdma dw 10 dup(notimp) dw setintv dw 6 dup(notimp) dw gettim dw 3 dup(notimp) dw dosver dw 4 dup(notimp) dw getintv dw notimp dw gswitch dw 3 dup(notimp) dw chdir dw creat2 dw open2 dw close2 dw readf2 dw write2 dw del2 dw lseek dw 4 dup(notimp) dw gcd dw alloc dw notimp dw setblk dw exec dw exit dw notimp dw first2 dw next2 dosfl equ ($-dosf-2)/2 datas ends %IF (%OS EQ 86) THEN ( stack segment stack 'stack' dw 750 dup(?) stack ends ) ELSE ( stack stackseg 1500 )FI code segment public dosint, crfile, opfile, special, writer, delcon, prstr, dconio public aopen, aclose, awrite, aspcl, waitio, sendms, rcvmsg, delseg public gfilsta, flushci extrn start:near, outchr:near, takrd:near, prompt:near, comnd:near extrn takset:near, atoi:near, katoi:near extrn 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, rqexitiojob:near extrn rqaopen:near, rqaclose:near, rqaread:near, rqawrite:near extrn rqwaitio:near, rqaspecial:near, rqsetdefaultprefix:near extrn rqsetexceptionhandler:near, rqsetpriority:near extrn rqcreatesemaphore:near, rqreceiveunits:near, rqcreatetask:near extrn rqcreatemailbox:near, rqreceivemessage:near, rqsendmessage:near extrn rqcreatesegment:near, rqdeletesegment:near, rqlookupobject:near %IF (%OS EQ 286) THEN ( extrn rqegetaddress:near, rqecreatedescriptor:near extrn rqedeletedescriptor:near )FI psp: jmp stop ; "program segment prefix" db 10h ; combined w/previous byte makes size>65K 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 jmp dosint ; DOS function dispatcher entry fake endp db (psp+80h)-$ dup(?) cline db 82 dup(0) begin proc far call setexcp %IF (%OS EQ 286) THEN ( push cs push offset psp push ds push offset status call rqegetaddress push dx push ax push offset begin push ds push offset status call rqecreatedescriptor )ELSE( mov ax,cs )FI mov es,ax mov di,offset cline ; move command line to cline sub al,al L1: inc byte ptr es:cline stosb ; clears count 1st time thru push es ; save es & di push di push ds ; al=call rqcgetchar(@status) %pushv(offset status) call rqcgetchar pop di ; restore es & di pop es test al,al ; end of string? jnz L1 ; no mov byte ptr es:[di],cr ; stuff cr %IF (%OS EQ 286) THEN ( push es ; let's not leave this descriptor laying around push ds push offset status call rqedeletedescriptor)FI call crmbx ; mbox=rqcreatemailbox(0,@status) mov mbox,ax call crmbx ; tmbox=rqcreatemailbox(0,@status) mov tmbox,ax call crmbx ; combx=rqcreatemailbox(0,@status) mov combx,ax call crmbx ; cimbx=rqcreatemailbox(0,@status) mov cimbx,ax mov di,offset work ; scfitok=rqscreatefile(@(6,':WORK:'),@status) call crfile ; scratch file is for wild card implementation mov scfitok,ax ; (FIRST2 & NEXT2), and :CO: redirection (EXEC) mov bx,3 ; call rqsopen(scfitok,3,2,@status) mov cx,2 call opfile mov di,offset trmstr call crfile mov citok,ax ; citok=rqscreatefile(@(4,':TERM:'),@status) mov bx,3 ; call rqaopen(citok,3,3,0,@status) call aopen mov di,offset trmstr call crfile mov cotok,ax ; cotok=rqscreatefile(@(4,':TERM:'),@status) mov cotok+2,ax mov cotok+4,ax mov bx,3 ; call rqsopen(cotok,3,3,@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,size setosc sub dx,dx call awrite mov ax,cotok ; set OSCs for :CO: mov bx,offset setosc mov cx,size 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 mov dx,tmbox call awrite push ds ; get pathname that called us %pushv(offset cobuf1) ; stash @cobuf1 %pushv(size cobuf1) ; call rqgetcommandname push ds ; (@cobuf1,size cobuf1,@status) %pushv(offset status) call rqcgetcommandname mov ax,citok ; wait for TSC to settle down mov bx,tmbox ; necessary for 386's & lickety-split 286's call waitio mov ax,ds ; back scan to last path separator mov es,ax mov bl,cobuf1 sub bh,bh lea si,cobuf1[bx] call bakscan ; si=file name ptr, bx=its length, al=separator ; The full string @cobuf1 is used to look for .cfg & .ini in the dir from which ; Kermit was loaded. The mid-string, @si-1, is used to look in :$:. mov [bx+si],'c.' ; catenate '.cfg' mov [bx+si+2],'gf' dec si ; byte before file name for string count mov word ptr cobuf2,si ; save ptr add cobuf1,4 ; bump length of full string for .cfg add bl,4 ; bump length of mid-string mov [si],bl ; RMX string for lookup in :$: mov ah,bl ; ah=current byte @si, al=old char @si cmp si,offset cobuf1 ; if no path, use bl for old char jne L3 mov al,bl ; instead of the one from bakscan L3: mov word ptr cobuf2+2,ax ; save them call cfgini ; look for .cfg, open, size to dx:si jcxz L4 ; OK? jmp short L7 ; no, do .ini L4: inc taklev add takadr,size takinfo mov di,takadr mov [di].takhnd,ax ; token mov [di].taktyp,0feh ; mark as take mov [di].takcnt,si ; low size mov [di].takcnt+2,dx ; high size call takrd L5: mov ax,ds mov es,ax mov dx,offset dolsgn ; ptr for prompt call prompt cmp taklev,0 ; done? je L7 ; eq = yes mov dx,offset comtab ; command table ptr mov bx,offset dolsgn ; help ptr mov comand.cmcr,1 mov ah,cmkey call comnd jmp short L6 ; error exit nop call bx ; call cfg s/r jmp L5 ; loop L6: mov dx,offset cfgerr ; output error msg & loop call prstr jmp L5 L7: mov si,word ptr cobuf2 ; point to mid-string mov ax,word ptr cobuf2+2 ; ah=mid-string count, al=path separator mov [si],ah mov bl,ah sub bh,bh mov byte ptr[bx+si],'i' ; replace 'cfg' w/'ini' dec bx dec bx mov [bx+si],'ni' call cfgini ; look for .ini, open, size to dx:si jcxz L8 ; found jmp short L9 ; not found CFGINI proc mov di,si mov temp,si ; save string pointer call atfile ; attach from :$: jcxz CGIN1 ; z=found mov si,word ptr cobuf2 ; point to mid-string mov ax,word ptr cobuf2+2 ; al=path separator mov [si],al ; put it back mov di,offset cobuf1 ; point to full path mov temp,di ; save string pointer call atfile ; attach from full path jcxz CGIN1 ret CGIN1: mov temp+100,ax ; save token mov bx,1 mov cx,bx call opfile ; open for reading jcxz CGIN2 ret CGIN2: mov di,temp ; string pointer call gfilsta ; get file status to find size mov si,ax ; low order file size mov ax,temp+100 ; token ret CFGINI endp L8: mov inisize,si ; size of .ini mov initok,ax ; close KERMIT.INI, call clfile ; but leave attached for open2 L9: mov ax,cotok ; save configured attributes mov bx,offset termatt ; for ping-ponging mov cx,4 call special call crsema ; sematok=rqcreatesemaphore(0,1,0,@statu mov sematok,ax mov sigpair,ax ; for ^C trapping mov ax,citok ; establish ^C & sematok as signal pair mov cx,6 mov bx,offset sigpair call aspcl mov bx,offset cctask ; call rqcreatetask call crtsk ; (0,@cctask,datas,0,300,0,@status) mov bx,offset siotsk ; call rqcreatetask call crtsk ; (0,@siotsk,datas,0,300,0,@status) mov bx,offset citsk ; call rqcreatetask call crtsk ; (0,@citsk,datas,0,300,0,@status) mov bx,offset cotsk ; call rqcreatetask call crtsk ; (0,@cotsk,datas,0,300,0,@status) mov di,offset lp ; lptok=rqscreatefile(@(4,':LP:'),@status) call crfile jcxz L10 ; jump if OK mov di,offset bb ; otherwise use :BB: call crfile L10: mov lptok,ax mov bx,2 ; call rqsopen(lptok,2,2,@status) mov cx,bx call opfile mov ax,citok ; cmdtok = rqccreatecommandconnection(citok, mov bx,cotok ; cotok,0,@status) sub cx,cx call crcmdco mov cmdtok,ax mov ax,lptok ; rcmdtok = rqccreatecommandconnection(lptok, mov bx,scfitok ; scfitok,1,@status) mov cx,1 ; lptok forces error if ":CI:" gets read, call crcmdco ; scfitok is ":CO:" redirected to scratch file mov rcmdtok,ax push ds ; call dqgetsystemid(@temp,@status) %pushv(offset temp) push ds %pushv(offset status) 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 mov ax,cx mov bx,offset rqglob call lookup ; globtok=rqlookupobject(0,@rqglob,0,@status) mov globtok,ax mov bx,offset dolsgn call lookup ; doltok=rqlookupobject(globtok,@dolsgn,0,@statu mov doltok,ax push cx ; call rqsetpriority(0,priorty,@status) push priorty push ds %pushv(offset status) call rqsetpriority mov ax,cs mov ds,ax ; point ds & es to psp mov es,ax jmp start ; go to Kermit begin endp ; cfg subroutines. ; Number conversion routines getn & getdn return to caller's caller on error fillbuf proc call getn ; convert backslash number mov bufill,ax ; set serial input background fill ret fillbuf endp fillci proc call getn ; convert backslash number mov cifill,ax ; set terminal input background fill ret fillci endp codel proc call getdn ; convert decimal number mov codelay,ax ; set connect mode terminal output buffer time ret codel endp dtr proc call getdn ; convert decimal number mov dtrtime,ax ; set time to hold DTR down ret dtr endp esccset proc mov esc_c,true ; enable sending ESC c (VT100 reset) on exit ret esccset endp kill proc call getn ; convert backslash number cmp kilpair,0 ; has task already been created? jne K1 ; ne = yes mov byte ptr kilpair+2,al ; set control char to trap call crsema ; kilpair=rqcreatesemaphore(0,1,0,@status) mov kilpair,ax mov bx,offset kiltsk call crtsk ; create kill task mov ax,citok mov cx,6 mov bx,offset kilpair call aspcl ; establish trap char & kiltsk as signal pair ret K1: mov dx,offset killmsg ; don't let 'em do it twice call prstr ret kill endp maxbd proc mov dx,offset bdtab ; parse for baud rate sub bx,bx mov ah,cmkey call comnd jmp short MB1 ; NG, bitch nop mov temp,bx ; save baud ix mov ah,cmcfm ; proper parsing ettiqutte call comnd jmp short MB1 ; NG, bitch nop mov bx,temp ; baud ix inc bx ; next higher mov cx,baudsiz ; baudsiz - (1+baud ix) is # wds to clear sub cx,bx ; x2 is word ix shl bx,1 mov ax,ds mov es,ax sub ax,ax mov di,offset bddat ; point to 1st word to clear add di,bx cld rep stosw ; wipe 'em out ret MB1: mov dx,offset mbmsg call prstr ret maxbd endp nomdm proc and portatt+6,0fff7h ; turn off modem control bit ret nomdm endp osc proc mov ah,cmtxt ; parse text upto cr to temp+2 mov bx,offset temp+2 mov dx,offset dolsgn call comnd jmp short OSCERR ; NG nop mov cl,ah sub ch,ch ; cx = # bytes mov di,offset temp+2 ; point to start mov ax,ds mov es,ax mov al,' ' cld repe scasb ; discard leading blanks je OSCERR ; empty, show indignation xchg bx,di ; bx = 1st non-blank char ptr dec di ; di = last char ptr std repe scasb ; discard trailing blanks cld add cl,6 ; cx = total length of OSC inc di inc di ; point to plant trailer sub bx,3 ; point to plant lead-in mov [bx],escbrac ; insert lead-in mov [di],escbslh ; insert trailer mov ax,cotok push bx ; save ptr for ci push cx ; save count for ci call writer ; write OSC to cotok pop cx pop bx mov ax,citok ; write OSC to citok sub dx,dx call awrite ret OSCERR: mov dx,offset oscmsg call prstr ret osc endp prior proc call getn ; convert backslash number je PRERR ; getn compared to 255, reject if = mov byte ptr priorty,al ; set priority ret PRERR: mov dx,offset prmsg call prstr ret prior endp subpack proc call getdn ; convert decimal number mov subpksz,ax ; set sub-packet size (tuning param for sending) ret subpack endp trnslt proc mov trok,true ; enable translation during connect ret trnslt endp getn proc ; bags backslash #, converts it, ensures<256, returns in ah & al mov ah,cmfile ; parse upto whitespace into temp mov bx,offset dolsgn mov dx,offset temp mov byte ptr temp,0 call comnd jmp short NERR ; NG return nop mov si,offset temp ; point to it call katoi ; convert it jc NERR ; carry set = NG cmp ax,0ffh ; we want 255 max ja NERR mov ah,al ; both bytes the same for word filling ret NERR: mov dx,offset nmsg call prstr pop ax ret getn endp getdn proc ; bags decimal number, converts it, returns it in ax mov ah,cmtxt ; parse upto cr into temp mov bx,offset temp mov dx,offset dolsgn mov byte ptr[bx],0 call comnd jmp short DNERR ; NG return nop mov si,offset temp ; point to it call atoi ; convert it jmp short DNERR ; NG return nop ret ; got it, it's in ax DNERR: mov dx,offset dnmsg call prstr pop ax ret getdn endp dosint proc ; DOS function call table look up push ds push bx mov bx,datas mov ds,bx pop savebx cmp ah,dosfl ja notimp sub bh,bh mov bl,ah rol bx,1 call dosf[bx] mov bx,savebx pop ds ret dosint endp notimp: ; not implemented DOS function error routine mov dx,offset syserr call prstr quitint proc far stop: mov ax,datas mov ds,ax mov dx,offset crlf call prstr cmp esc_c,true ; is ESC c cfg'd? jne ST1 ; ne = no mov ax,cotok ; give Terminal Support Code an ESC c mov bx,offset escapec ; to restore terminal to initial state mov cx,size escapec call writer ST1: mov ax,cotok ; close to wait for output completion call clfile mov ax,citok ; restore terminal attributes mov bx,offset savspec mov cx,5 call aspcl mov cx,globtok ; restore $ directory mov ax,doltok ; call rqsetdefaultprefix(globtok,doltok,@status call sdefpfx mov cx,kilpair ; was a kill kermit ctrl char established jcxz ST2 ; z = no mov ax,citok ; yes, disestablish mov bx,offset kilpair mov word ptr[bx],0 mov cx,6 call aspcl ST2: mov ax,citok ; wait for completion before exit mov cx,tmbox call aclose mov ax,tmbox mov bx,0ffffh call rcvmsg push xitcode ; call rqexitiojob(xitcode,@0,@status) sub ax,ax push ax push ax push ds %pushv(offset status) call rqexitiojob quitint endp kiltsk proc ; kill task mov ax,kilpair ; wait for kill char to be typed call rcvun jmp STOP ; then quit kiltsk endp cctask proc far ; ^C task CCT: mov ax,sematok ; wait for ^C to be typed call rcvun mov flags.cxzflg,'C' ; slightly adapted (mostly stolen) from mov pack.state,'A' ; MSSKER's intbrk jmp CCT cctask endp siotsk proc far ; serial input task call setexcp ; never call exception handler SIO1: mov bx,0ffffh ; wait forever @ mbox for something to do SIO2: mov ax,mbox call rcvmsg cmp ax,mbox ; if it's the token for mbox, je SIO6 ; it's SERINI asking us to crank up input dec cx ; otherwise it's E$TIME or an IORS jz SIO3 ; it's E$TIME call delseg ; it's an IORS, so delete it SIO3: cmp sintok,0 ; if the port has been reset, je SIO1 ; let the interrupts expire unanswered cmp xofsnt,true jne SIO4 mov bx,50 jmp SIO2 SIO4: call sread ; start aread & fill following buffer quadrant mov ax,srcptr sub ax,savsi ; if there's at least 2 quadrants between next jns SIO5 ; quadrant & current pointer, add ax,bufsiz SIO5: cmp ax,bufsiz/2 jle 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 call outchr nop nop nop mov xofsnt,true jmp SIO1 SIO6: 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 SIO7: mov ax,sintok 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,mbox ; flush it's buffer call aread mov ax,sintok mov bx,mbox call waitio cmp ax,bufsiz je SIO7 ; 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 mov ax,ds ; fill 1st quadrant mov es,ax mov ax,bufill mov cx,bufsiz/8 mov di,offset source cld rep stosw call sread ; start 1st read & fill 2nd quadrant jmp SIO4 ; go do 2nd read sread proc mov ax,sintok mov bx,srcptr ; next quadrant ptr mov cx,bufsiz/4 mov dx,mbox call aread ; read current quadrant mov ax,ds mov es,ax mov ax,bufill mov cx,bufsiz/4 mov di,srcptr add di,cx 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 shr cx,1 cld rep stosw ; fill quadrant ret sread endp siotsk endp citsk proc far ; read terminal task call setexcp CIT1: mov bx,offset cibuf1 CIT2: mov cistrt,bx ; set buffer ptr mov ax,ds ; fill it w/cifill mov es,ax mov di,bx mov cx,(size cibuf1)/2 mov ax,cifill cld rep stosw mov ax,citok ; call rqaread mov cx,size cibuf1 ; (citok,@buffer,size(buffer),cimbx,@statu mov dx,cimbx call aread CIT3: mov ax,cimbx ; wait for completion or task restart mov bx,0ffffh call rcvmsg cmp ax,cimbx ; if it's the mail box token, it's task restart jne CIT4 ; if, not it's an IORS mov bx,offset cibuf1 mov ciptr,bx ; initialize buffer & char pointers jmp CIT2 ; & start over CIT4: mov es,ax ; check IORS for "flushing" status cmp es:word ptr 0,2ch pushf call delseg ; delete IORS popf ; "flushing" means suspend task, je CIT3 ; go wait for restart mov bx,offset cibuf2 cmp bx,cistrt ; exchange buffers je CIT1 jmp CIT2 citsk endp cotsk proc far ; write terminal task -- active in connect mode call setexcp COT1: mov ax,combx ; wait for task start or IORS mov bx,0ffffh call rcvmsg cmp ax,combx ; if it's the mail box token, it's task start je COT2 call delseg ; otherwise it's an expiring IORS, delete it jmp COT1 ; & wait for task start COT2: mov ax,cotok ; task start. close EIOS & re-open BIOS call clfile mov ax,cotok mov bx,2 mov codone,bl ; mark write complete call aopen COT3: mov ax,offset cobuf1 COT4: mov coptr,ax ; byte ptr mov costrt,ax ; buffer ptr COT5: mov ax,combx ; wait for timer, IORS, or suspend task request mov bx,codelay ; default = 60 milliseconds call rcvmsg jcxz COT6 ; 0 = IORS or suspend task cmp codone,0 ; timeout. Is write complete? jne COT7 ; ne = yes jmp COT5 ; no, wait for it COT6: cmp ax,combx ; if mail box token je COT9 ; it's suspend task request mov codone,true ; it's IORS, mark write complete call delseg ; delete IORS COT7: mov bx,costrt ; buffer ptr mov cx,coptr ; byte prt sub cx,bx ; # bytes to write jcxz COT8 ; don't write 0 mov ax,cotok ; call rqawrite mov dx,combx ; (cotok,@buffer,nbytes,combx,@status) call awrite mov codone,0 ; mark write not finished COT8: mov ax,offset cobuf2 cmp ax,costrt ; exchange buffers je COT3 jmp COT4 COT9: mov ax,cotok ; suspend task. Close BIOS, wait for task start call aclose jmp COT1 cotsk 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: 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 push si push cx call rdci ; read 1 from :CI: to temp, on return test cx,cx ; cx=1 if read, 0 if not, set zero flag if not pop cx pop si ret dconio endp coninq proc push cx DC1: call rdci ; read 1 from :CI: to temp jcxz DC1 ; 'til we get 1 pop cx ret coninq endp rkbd proc RKBD1: call pollci ; read 1 from :CI: to al je RKBD1 ; 'til we get 1 ret rkbd endp rdci proc sub cx,cx cmp flags.cxzflg,'C' ; reads 1 from :CI: to temp, doesn't jne RDC1 ; wait, doesn't check ^C mov flags.cxzflg,ch ; returns cx=1 if read, 0 if not mov al,3 jmp short RDC2 RDC1: call pollci je RDC3 RDC2: inc cx RDC3: ret rdci endp pollci proc push si cmp sintok,0 ; if serial port's active je PCI1 cmp oneport,true ; & oneport je PCI3 ; return no character PCI1: mov si,ciptr ; next byte ptr lodsb cmp al,byte ptr cifill je PCI3 ; eq = no byte cmp si,offset cibuf2 + size cibuf2 jne PCI2 mov si,offset cibuf1 test si,si ; clear equal PCI2: mov ciptr,si ; set ptr for next byte PCI3: pop si ret pollci endp prstr proc call save ; call rqswritemove(cotok,ds:dx,#char,@status) mov ax,ds mov es,ax mov di,dx mov cx,0ffffh mov al,'$' repne scasb neg cx add cx,0fffeh ; cx=#characters jcxz PRSTR1 ; why bother mov ax,cotok mov bx,dx call writer PRSTR1: call rstr ret prstr endp seldsk proc mov al,1 ; what the hell, say there's 1 ret seldsk endp gcurdsk proc sub al,al ; always A: -- meaningless anyway ret gcurdsk endp setdma proc mov kbuf,dx ; save disk transfer address, DTA ret setdma endp setintv proc ret ; if KERMIT ever does more than setintv endp ; setup int 23h, we're in trouble gettim proc call save 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) %pushv(offset temp) push ds %pushv(offset status) 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 gswitch proc mov dl,'/' ; undocumented DOS get switch character ret gswitch endp getintv proc ret ; if KERMIT ever does more than getintv endp ; setup int 23h, we're in trouble chdir proc call save mov ax,ds mov es,ax mov si,offset temp+1 call z2rmx ; copy ASCIIZ string @ds:dx to temp+1 mov byte ptr temp,al mov di,offset temp ; length to temp makes it RMX string call atfile ; attach file jcxz CHD2 ; jump if OK CHD1: call rstr mov ax,3 ; return error code w/carry set stc ret CHD2: mov cx,globtok ; call rqsetdefaultprefix(globtok,ax,@status) push ax call sdefpfx pop ax jcxz CHD3 jmp CHD1 CHD3: call sdefpfx ; call rqsetdefaultprefix(0,ax,@status) call rstr clc ret chdir endp creat2 proc call save mov ax,ds mov es,ax mov si,offset printer ; is it PRN ? mov di,dx mov cx,size printer repe cmpsb jne CRF1 ; ne=no call rstr mov ax,lptok ; yes, use :LP: clc ret CRF1: call cropsr jnc CRF2 call exfisr jmp short OP5 CRF2: call crfile ; create file mov bx,3 ; mode for OPEN & error return code mov temp+2,bx ; error return code jmp short OP4 cropsr proc mov si,dx mov di,offset kermtmp ; is it "$kermit$.tmp"? mov cx,size kermtmp repe cmpsb jne CROP1 mov bx,scfitok ; yes, use token for scratch file mov temp,bx ; save it stc ret CROP1: mov si,offset temp+3 call z2rmx ; ASCIIZ string to temp+3 mov di,offset temp+2 ; setup di mov [di],al ; length makes it RMX string at temp+2 clc ret cropsr endp creat2 endp open2 proc call save 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 ; is it MSKERMIT.INI? mov cx,size dotini repe cmpsb jne OP1 ; no mov ax,initok ; yes, initok's already attached jmp short OP3 OP1: call cropsr jnc OP2 call rewind jmp short OP5 OP2: call atfile OP3: mov temp+2,2 ; error return code mov bx,temp ; get mode OP4: mov temp,ax ; save token mov cx,2 ; call rqsopen(token,mode,2,@status) call opfile OP5: call rstr mov ax,temp ; return token to caller in ax mov bx,temp+2 ; get error return code jmp short CRYFLG open2 endp close2 proc mov bx,savebx ; savebx has file token cmp bx,scfitok ; if it's the scratch file, je CL1 ; don't you dare! cmp bx,lptok ; :LP:, neither je CL1 call save mov bx,savebx call delcon ; delete connection call rstr mov bx,6 ; error flag, if necessary jmp short CRYFLG CL1: ret close2 endp readf2 proc call save mov ax,savebx ; savebx has file token mov bx,dx ; nbyt=rqsreadmove(token,@buf,cnt,@status) call reader RF1: mov temp,ax ; save # bytes read call rstr mov ax,temp ; return to caller in ax mov bx,6 ; error flag, if necessary jmp short CRYFLG readf2 endp write2 proc call save mov bx,savebx ; savebx has file token test bx,bx ; is it magic token 0 (CI)? jz WRT1 ; yes, let fail gracefully cmp bx,4 ; other magic tokens? ja WRT1 ; no shl bx,1 ; yes, lookup real token mov bx,citok[bx] WRT1: mov ax,bx mov bx,dx ; nbyt=rqswritemove(token,@buf,cnt,@status) call writer jmp RF1 write2 endp del2 proc call save mov ax,ds mov es,ax mov si,offset temp+1 ; ASCIIZ string @ds:dx to temp+1 call z2rmx mov bx,offset temp mov byte ptr[bx],al ; length makes it RMX string at temp push ds ; call rqsdeletefile(@temp,@status) push bx push ds %pushv(offset status) call rqsdeletefile call rstr mov bx,2 ; error return code CRYFLG: clc cmp status,0 ; OK? je CFLG1 ; yes stc mov ax,bx ; & return error code CFLG1: ret del2 endp lseek proc call save mov bx,savebx ; savebx has file token push bx ; save for get con. status add al,2 ; convert DOS mode to RMX cbw call seek pop bx call gconsta ; getconnectionstatus puts file ptr call rstr ; in temp+4 & 6 mov ax,temp+4 ; dx:ax are file pointer mov dx,temp+6 mov bx,6 ; error flag, if necessary jmp CRYFLG lseek endp alloc proc call save mov ax,savebx ; savebx has # paragraphs cmp ax,1000h ; is it 65K? jl AL2 ; <65K, it's OK jne AL1 ; >65K, too much sub ax,ax ; =65K, use 0 for full segment jmp short AL2 AL1: mov status,ax ; force error jmp short AL3 AL2: mov cl,4 ; convert paragraphs to bytes shl ax,cl push ax ; seg_base=rqcreatesegment(#bytes,@status) push ds %pushv(offset status) call rqcreatesegment mov temp,ax ; save AL3: call rstr mov ax,temp ; restore seg_base return param mov bx,8 ; error return code jmp CRYFLG alloc endp gcd proc mov byte ptr[si],0 ; return null string @ds:si clc ret gcd endp setblk proc ret setblk endp PUSHCMD: ; actually, part of exec mov dx,offset pushmsg ; for now, say "no pushing" call prstr ; but here's the spot to implement later call rstr mov ax,11 stc ret exec proc call save mov bx,savebx ; saved bx mov di,es:[bx+2] ; command tail pointer to es:di mov es,es:[bx+4] sub cx,cx mov cl,es:[di] ; if command tail length is 0, it's PUSH jcxz PUSHCMD inc di mov al,' ' repne scasb ; scan past DOSisms repe scasb dec di ; 1st non-blank char of command mov bx,di mov dx,cx ; bx is ptr, dx is count mov al,'>' ; if '>' appears, Kermit's asking for repne scasb ; redirected output mov ax,cmdtok ; if not, use ordinary cmd token jne EX1 ; ne = no redirection sub dx,cx ; reduce count by chars from '>' to end dec dx push bx push dx push es call exfisr ; rewind & truncate scratch file pop es pop dx pop bx mov ax,rcmdtok ; use redirected cmd token EX1: mov temp+100,ax ; save cmd token mov si,offset typecmd ; is it 'TYPE'? mov di,bx mov cx,size typecmd repe cmpsb jne EX2 ; ne = no mov [bx],'oc' ; replace w/'COPY' mov [bx+2],'yp' jmp short EX4 EX2: mov si,offset delcmd ; is it 'DEL'? mov di,bx mov cl,size delcmd repe cmpsb jne EX3 ; ne = no sub dx,size delcmd ; construct RMX DELETE command @delrmx mov cx,dx mov al,' ' repe scasb dec di inc cx mov dx,cx add dx,size delrmx push ds push es pop ds pop es mov si,di mov di,offset deltail rep movsb mov si,offset delrmx jmp short EX5 EX3: mov si,offset chkdsk mov di,bx mov cl,size chkdsk repe cmpsb jne EX4 mov bx,offset dirfree ; yes, use 'dir $ free' as command mov dx,size dirfree mov cx,ds mov es,cx EX4: push ds ; swap ds & es push es pop ds pop es mov si,bx EX5: mov di,offset temp ; move command to temp mov ax,dx stosb mov cx,dx rep movsb push es ; restore ds pop ds mov ax,temp+100 ; command token cmp ax,rcmdtok ; if output's going to scratch file je EX6 ; bypass fussing w/:TERM: mov ax,citok ; shut down citsk call aclose mov ax,citok ; reopen mov bx,3 call aopen call flushci ; wait for output to :TERM: to finish mov bx,offset savspec ; ping back to user's connection & push word ptr[bx+2] ; terminal attributes mov word ptr[bx+2],2 mov ax,cotok mov cx,5 call special mov ax,citok mov bx,offset savspec mov cx,5 call aspcl pop savspec+2 EX6: mov ax,temp+100 ; command token push ax ; save it mov bx,offset temp ; call rqcsendcommand mov cx,offset temp+100 ; (token,@temp,@temp+100,@status) call sendcmd pop ax ; command token cmp ax,rcmdtok ; if it went to scratch file, je EX7 ; don't mess w/:TERM: push cx ; save status call flushci ; wait for completion of cmd's output mov ax,cotok ; pong attr's back to Kermit's mov bx,offset termatt mov cx,5 call special mov ax,citok mov bx,offset termatt mov cx,5 call aspcl mov ax,cimbx ; restart citsk mov bx,ax call sendms pop cx ; restore status EX7: cmp cx,83h ; is it E$CONTINUED je EX8 ; yes, return w/carry clear or cx,temp+100 ; sendcmd status OR status from command jcxz EX8 ; jump if OK call rstr mov ax,2 ; return error code w/carry set stc ret EX8: call rstr clc ret exfisr proc ; rewind & truncate scratch file mov bx,scfitok push bx ; save for truncate call rewind ; rewind scratch file push ds ; call rqstruncatefile(scfitok,@status) %pushv(offset status) call rqstruncatefile ret exfisr endp flushci proc mov ax,citok ; this is necessary to wait for completion mov bx,offset flush ; of output to :TERM: for fast systems mov cx,size flush sub dx,dx call awrite mov ax,citok mov bx,offset cobuf1 mov cx,cobufl mov dx,tmbox call aread mov ax,citok mov bx,tmbox call waitio ret flushci endp exec endp exit proc sub ah,ah ; convert DOS exit code to RMX test ax,ax jz X1 mov ah,40h ; put in user range, if non-0 X1: mov xitcode,ax jmp stop exit endp first2 proc call save mov si,dx ; ds:dx points to ASCIIZ file name mov ax,ds mov es,ax mov di,offset kermtmp ; is it "$kermit$.tmp"? mov temp+100,di mov cx,size kermtmp mov temp+102,cx repe cmpsb jne FST2 mov bx,scfitok ; yes, fill in DTA. For scratch file, call gconsta ; getconnectionstatus to temp mov ax,temp+4 ; bx:ax are file pointer, mov bx,temp+6 ; which is length of scratch file FST1: mov di,kbuf mov [di+1ah],ax ; lo file size to DTA mov [di+1ch],bx ; hi file size to DTA mov byte ptr [di+15h],0 ; clear DTA's attribute field add di,1eh ; point to DTA's file name field mov si,temp+100 mov cx,temp+102 rep movsb call rstr mov bx,2 jmp CRYFLG FST2: mov si,dx mov di,offset dotini ; is it MSKERMIT.INI? mov temp+100,di mov cx,size dotini mov temp+102,cx sub bx,bx repe cmpsb mov ax,inisize je FST1 ; yes, initok's already attached mov temp+100,2 mov si,dx cmp word ptr[si],002ch ; is it ',',0? je NXT1 ; eq = yes, treat as next push es push dx call exfisr ; rewind & truncate scratch file pop dx pop es mov si,offset wcpath ; move file-spec to wcpath, length to ax call z2rmx mov bx,ax add al,3 mov wccmd,al ; + 3 for 'wc ' makes RMX string mov si,dx ; point to file-spec mov cx,bx ; length FST3: lodsb ; scan for wc chars, if any goto FST4 cmp al,'*' je FST4 cmp al,'?' je FST4 cmp al,',' je FST4 loop FST3 mov si,dx ; no need for wc, next can handle it mov di,offset wcpath+1 ; if we move it over 1 byte mov cx,bx rep movsb jmp short NXT3 FST4: mov si,dx add si,bx ; point to end dec si ; backup over zero byte call bakscan ; find rightmost path separater cmp al,'\' ; is it \? jne FST5 call rstr ; yes, force error mov ax,2 ; it's a DOSism we can do without stc ret FST5: mov ax,rcmdtok ; call rqcsendcommand mov bx,offset wccmd ; (rcmdtok,@wccmd,@temp,@status) mov cx,offset temp call sendcmd mov bx,scfitok ; rewind scratch file call rewind mov nxtflg,0 jmp short NXT1 ; let next finish up first2 endp next2 proc call save mov temp+100,18 ; error return code cmp nxtflg,0 ; was next called before 1st, jne NXT4 ; or after no more? ne = yes NXT1: mov bx,offset wcpath ; place to stash file name string mov byte ptr[bx],0 ; empty NXT2: inc bx ; bump count push bx mov ax,scfitok ; read 1 from scratch mov cx,1 call reader test ax,ax pop bx jz NXT4 ; 0 = EOF cmp byte ptr[bx],lf jne NXT2 ; loop 'til EOL sub bx,offset wcpath+2 ; bx = length file name NXT3: mov di,offset wcpath mov [di],bl ; RMX string @di call gfilsta ; does it exist? jcxz NXT5 ; 0 = yes NXT4: mov nxtflg,1 ; mark no more next w/o 1st 1st call rstr mov ax,temp+100 ; return error code stc ret NXT5: mov di,kbuf mov [di+15h],bl ; directory attribute to DTA mov [di+1ah],ax ; low file size mov [di+1ch],dx ; high file size mov bl,byte ptr wcpath sub bh,bh ; bx = length file name stirng lea si,wcpath[bx] ; point to end call bakscan ; separate path/file name mov cx,bx ; cx = file name length add di,1eh ; DTA file name field ptr mov ax,ds ; si points to file name, move it mov es,ax rep movsb mov [di],cl ; make ASCIIZ call rstr clc ret next2 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) %pushv(offset xcepinf) push ds %pushv(offset status) call rqsetexceptionhandler ret setexcp endp crtsk proc ; ax=rqcreatetask(0,cs:bx,ds,0:0,300h,0,@status) sub cx,cx ; bx is start address push cx push cs push bx push ds push cx push cx %pushv(300h) push cx push ds %pushv(offset status) call rqcreatetask ret crtsk endp crmbx proc ; ax=rqcreatemailbox(0,@status) %pushv(0) push ds %pushv(offset status) call rqcreatemailbox ret crmbx endp crsema proc sub ax,ax ; ax=rqcreatesemaphore(0,1,0,@status) push ax inc ax push ax dec ax push ax push ds %pushv(offset status) call rqcreatesemaphore ret crsema endp atfile proc ; ax=rqsattachfile(ds:di,@status) push ds ; ds:di is path ptr push di push ds %pushv(offset status) 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 %pushv(offset status) 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 %pushv(offset status) call rqsopen ret opfile endp clfile proc ; call rqsclose(ax,@siostat) push ax ; token push ds %pushv(offset siostat) call rqsclose ret clfile endp delcon proc ; call rqsdeleteconnection(bx,@status) push bx ; token push ds %pushv(offset status) 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 %pushv(offset status) 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 %pushv(offset status) 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 %pushv(offset status) call rqswritemove ret writer endp rewind proc mov ax,2 ; setup so seek positions to BOF sub cx,cx mov dx,cx seek proc push bx ; call rqsseek(token,mode,count,@status) push ax push cx push dx push ds %pushv(offset status) call rqsseek ret seek endp rewind endp lookup proc ; ax=rqlookupobject(ax,ds:bx,0,@status) push ax ; job token push ds ; @name push bx push cx ; time limit push ds %pushv(offset status) call rqlookupobject ret lookup endp sdefpfx proc ; call rqsetdefaultprefix(cx,ax,@status) push cx ; job token push ax ; prefix token push ds %pushv(offset status) call rqsetdefaultprefix ret sdefpfx endp crcmdco proc ; ax=rqccreatecommandconnection(ax,bx,cx,@status) push ax ; input token push bx ; output token push cx ; flag push ds %pushv(offset status) call rqccreatecommandconnection ; can you believe this shit? ret crcmdco endp sendcmd proc ; call rqcsendcommand(ax,ds:bx,ds:cx,@status) push ax ; command connection token push ds push bx ; pointer to command push ds push cx ; pointer to command exception push ds %pushv(offset status) call rqcsendcommand push cx ; save status mov ax,citok mov bx,offset sigpair mov cx,6 call aspcl ; restore ^C trap pop cx ; restore status ret sendcmd endp z2rmx proc ; copies ASCIIZ @ds:dx to si, returns count in ax mov di,dx mov cx,0ffffh sub ax,ax repne scasb neg cx add cx,0fffeh mov ax,cx ; ax=cx= # of bytes mov di,si mov si,dx rep movsb ret z2rmx endp bakscan proc ; finds path part & file name part std ; bx=string size, si points to EOstring mov cx,bx BSC1: lodsb cmp al,':' je BSC2 cmp al,'/' je BSC2 cmp al,'^' je BSC2 loop BSC1 dec si BSC2: inc si inc si ; si point to file name cld sub bx,cx ; bx=size file name, cx=size path ret ; al=separator bakscan endp aopen proc ; call rqaopen(ax,bx,3,0,@status) push ax ; token push bx ; mode %pushv(3) %pushv(0) push ds %pushv(offset status) call rqaopen ret aopen endp aclose proc push ax ; call rqaclose(ax,cx,@siostat) push cx push ds %pushv(offset siostat) call rqaclose ret aclose endp aread proc ; call rqaread(ax,ds:bx,cx,dx,@siostat) push ax push ds push bx ; buffer ptr push cx ; count push dx ; response mailbox push ds %pushv(offset siostat) call rqaread ret aread endp awrite proc ; call rqawrite(ax,ds:bx,cx,dx,@siostat) push ax push ds push bx ; buffer ptr push cx ; count push dx ; response mailbox push ds %pushv(offset siostat) 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 push tmbox push ds %pushv(offset siostat) call rqaspecial mov ax,tmbox mov bx,0ffffh call rcvmsg ; ax=rqreceivemessage(tmbox,0ffffh,@ignore,@siostat) call delseg ret aspcl endp waitio proc ; ax=rqwaitio(ax,bx,0ffffh,@status) push ax ; token push bx ; response mailbox %pushv(0ffffh) push ds %pushv(offset status) call rqwaitio ret waitio endp sendms proc ; call rqsendmessage(ax,bx,0,@status) push ax ; mailbox token push bx ; object to send %pushv(0) push ds %pushv(offset status) call rqsendmessage cld ret sendms endp rcvmsg proc pop bp ; ax=rqreceivemessage(tmbox,0ffffh,@ignore,@siostat) push ax ; mail box token push bx ; time limit push ds %pushv(offset ignore) push ds %pushv(offset siostat) call rqreceivemessage jmp bp rcvmsg endp rcvun proc ; call rqreceiveunits(ax,1,0ffffh,@ccstat) pop bp push ax ; semaphore token %pushv(1) ; units %pushv(0ffffh) ; time limit push ds %pushv(offset ccstat) call rqreceiveunits jmp bp rcvun endp delseg proc ; call rqdeletesegment(ax,@status) push ax push ds %pushv(offset siostat) call rqdeletesegment ret delseg endp gconsta proc push bx ; call rqsgetconnectionstatus(token,@temp,@status) push ds %pushv(offset temp) push ds %pushv(offset status) call rqsgetconnectionstatus ret gconsta endp gfilsta proc push ds ; call rqsgetfilestatus(ds:di,@temp,@status) push di ; path ptr push ds %pushv(offset temp) push ds %pushv(offset status) call rqsgetfilestatus jcxz GFIL1 ret GFIL1: mov bx,cx cmp byte ptr temp+9,0ffh ; is it a named file? je GFIL2 mov ax,cx ; no, setup for zero length mov dx,cx ret GFIL2: cmp byte ptr temp+38,8 ; is it a directory? je GFIL3 ; eq = no mov bl,10h ; yes, get DOS directory attribute GFIL3: mov ax,temp+54 ; low file size mov dx,temp+56 ; high file size ret gfilsta endp code ends end begin, ds:datas, ss:stack