; TNC.MAC - 1/17/87 - Deal with the TAPR TNC. ; Written by H. N. Oredson - W0RLI ; 134 Ponderosa Drive ; Santa Cruz, CA 95060 ; Comments and suggestions appreciated. .z80 maclib TNC.LIB entry tnc,logout,memtop,$memry,seenew,exclud entry mcall,scall,ocall,rcall,mcon,scon,mtnc,stnc entry ncerrs ; Messages. entry disp,mode,short,achar,rchar,tchar,wchar entry syson,sysoff,auto,bye,bsfila,bsfilb,cnusr,dload entry untall,help,info,togmen,opfila,opfilb entry exit,talk,lterma,ltermb entry byemsg,fm2,lm1,lm2,lm4,lm5 entry rcvfil,scia,scib,scua,scub,scsa,scsb entry bbmenu,symenu,lmenul,lmenus,rmenul,rmenus entry hfcb,ifcb,mumsg,reqmsg entry utime,fwdmin,twotnc entry talkm1,talkm2,talkm3,talkm4 external gmenus,gmenul external dcmd,init,hidfil,fwd1,conusr,updusr,clsusr external usopt,usobbs,usoexp,getusr,usosys,untusr external unt,clsmsg,change,ffcb,getto,uccnt external muldec,curtime,pgst,pghd,pgck,pgdn external conmod,dis,gotreq,lnkst,discon,gotcon,gotlnk external user,cmd,cmdlen,cmdtyp,itime,mcmt,getdat,getwt external rfcb,wfcb,fcb,fcb1,fcb2,fcb3,opt1,opt2 external getcmd,pause,waitc,ername,erwhat external ertime,ercant,erfind,erdone external @outch,@openr,@opena,@openw,@openn,@closew,rcv external ckdrv,@prtx,@inch,ckname,ucase,@fill,@docmd external const,cmdtnc,wtcmd,tnca,tncb,movcal,@mcmd external @move,@wait,tobuf,fmbuf external wtmon,mon,moncon external login,log,logo,logdrn,lfcb,logtxt,llogtxt,event tncdefs asciictl timdef bdosdef dseg ds 64 ; Stack space stack equ $ $memry: ds 2 ; First avail address in pool mem memtop: ds 2 ; Last avail address in pool mem saveit: db false mode: db lmode short: db false mumsg: ds 2 rmenul: ds 2 ; Address of long menu text rmenus: ds 2 ; Address of short menu text lmenul: ds 2 ; Address of long local menu text lmenus: ds 2 ; Address of short local menu text bbmenu: ds 2 symenu: ds 2 mcon: db false ; True if master tnc connected scon: db false ; True if slave tnc connected ctnc: ds 1 ; Current TNC iobyte mtnc: ds 1 ; Master TNC iobyte stnc: ds 1 ; Slave TNC iobyte twotnc: ds 1 ; True if TNC's on both ports mcall: ds 6 ; Call of station connected to master tnc ocall: ds 6 ; Call of system owner scall: db ' '; Call of station connected to slave tnc seenew: ds 1 ; Remote may see "new" files achar: ds 1 ; Char to kick user off system rchar: ds 1 ; Char to return from talk tchar: ds 1 ; Char to interrupt user and talk wchar: ds 1 ; Char to answer talk request ; TNC state changes for MailBox state changes scia: ds 2 ; Address of cmd to send to tnc for idle state scib: ds 2 ; Same, PRINTER port scua: ds 2 ; Address of cmds to put tnc in user state scub: ds 2 ; Same for PRINTER port scsa: ds 2 ; Address of cmds to put tnc in sysop state scsb: ds 2 ; Same for PRINTER port ncerrs: ds 1 ; Count of erwhats, ercants cseg tnc: ld sp,stack call init ; Initialize everything ld a,'C' ld b,'I' call logo ; Login owner call waitc ; The main loop, get here after each command. menu: call curtime ; Get current date/time cmpm mode,lmode ; Local user? jr nz,menua ; No ; Is local user. call wrtfil ; Close any blind save file call prtmen ; Give the menu call getcmd ; Get command call dcmd ; Do the command jr menu ; Is remote user. menua: console prtx mumsg ; Put users call on console master call ckreq ; Check if there was a connect request call prtmen ; Give menu menub: call getinp ; Get input from user jr nz,menu ; Owner interrupted. Put back a menu ld a,(cmdtyp) ckcmd menub,dised,timed call gotlnk ; Did adjacent node link us? jr z,menuc ; Yes call dcmd ; Do the command ld a,(ncerrs) ; Number of command errors cp 25 ; Large number? jp nc, timed ; If so, abort this connection ld a,(cmdtyp) ckcmd menu,dised,timed jr menu ; Was '*** LINKED to ' menuc: ld b,'L' call login ; Log user in jr menu ; and give menu ; Check for connect request on either TNC dseg rcall: ds 6 reqmsg: ds 2 cseg ckreq: call prtreq cmpm twotnc,true ret nz slave call const jr z,ckreqa mvim getwt,false call getdat ckreqa: master ; Print "xxx wants to use the MailBox" message ; if there was a connect request. prtreq: ld hl,gotreq ld a,(hl) ld (hl),false cp true ; Had a connect request? ret nz ; No ld hl,(reqmsg) jp @prtx ; Print the "xxx tried to connect" ; Display the proper menu. prtmen: ld a,(short) cp true jr z,prtma ld a,(mode) ld hl,(lmenul) cp lmode jr z,prtmb ld hl,(gmenul) cp gmode jr z,prtmb ld hl,(symenu) cp smode jr z,prtmb ld hl,(rmenul) jr prtmb ; Display the short menu prtma: ld a,(mode) ld hl,(gmenus) cp gmode jr z,prtmb ld hl,(lmenus) cp lmode jr z,prtmb ld hl,(symenu) cp smode jr z,prtmb ld hl,(rmenus) ld a,(usopt) and usobbs+usoexp jr z,prtmb ld hl,(bbmenu) prtmb: jp @prtx ; X command, short / long menu. togmen: ld a,(short) cpl ld (short),a ret ; @ command, change to/from sysop mode. syson: ld a,(usopt) and usosys ; IS sysop? jp z,erwhat ; No, sorry Charlie mvim mode,smode call cmdtnc call scs call conmod ; TNC to converse mode ret sysoff: mvim mode,umode call cmdtnc call scu call conmod ; TNC to converse mode ret ; Connect to user cnusr: call conusr call nz,term ret untall: call unt jp untusr ; Get input from master tnc or console. ; Return zero cleared if the local console broke in: ; Must put menu back up for the remote user. ; Return zero set in all other cases. dseg talkm1: ds 2 cseg getinp: movw timer,itime ; Start timeout timer gtina: console call const ; Console key pressed? jr z,gtinb ; No call @inch ; Yes, get character ld a,(achar) ; Get "abort user" char cp c ; Was it? jp z,force ; Yes. Kick user off ld a,(tchar) ; Break-in char cp c ; Is it? jr nz,gtinb ; Nope master prtx talkm1 ; Yes, tell user we want to talk call term ; and go talk master retnz ; Return with zero flag cleared gtinb: master call const ; Char from tnc? jr nz,gtinc ; Yes dtz timer ; Waited long enough? jr nz,gtina ; Nope mvim cmdtyp,ctimcmd ; Yes, time it out ret ; Return with zero flag set gtinc: mvim getwt,false ; Dont wait after con req call getcmd ; Get line from tnc ckcmd gtina,gtind,gtind gtind: retz ; Return with zero flag set ; Terminal emulator allowing save to file. dseg lm1: ds 2 cseg lterma: call tnca jr term ltermb: call tncb term: console prtx lm1 terma: master call const ; Char from tnc? jr nz,termc ; Yes console call const ; Char from console? jr z,terma ; No call @inch ; Get console char ld a,(rchar) ; Get "quite talk" char cp c ; Is it? jr nz,termb ; No cmpm mcon,true ; Was the tnc connected? ret nz ; No. Done. master call cmdtnc ; TNC to command mode call lnkst ; Get link state call conmod ; TNC to converse mode call discon ; Are we now disconnected? ret nz ; No jp dised ; Yes, log it termb: ld a,(achar) ; Get "abort user" char cp c ; Was it? jp z,force ; Yes. Kick user off master call @outch ; Send char to tnc jr termd ; Check if saving to file ; Char from TNC termc: call @inch ; Get char termd: cmpm saveit,false ; Saving to file? jr z,terma ; No ld a,c ; Yes cp lf ; Is it a LF? jr z,terma ; Ignore LF cp eof ; Is it EOF? jr z,terma ; Ignore ^Z call tobuf ; Put the char in the file ld a,c cp cr ; Is it CR? jr nz,terma ; No, get next char console ld c,':' ; when file save active call @outch ld c,lf call tobuf ; LF after CR into file jp terma ; Display a file locally. disp: movb topt,opt2 ; Save option ckname fcb2 ; Legal file name? jp z,ername ; No openr fcb2 ; Open the file jp z,erfind ; File not found ld hl,0 ; No header call pgst ; Init screen paging dispfa: call fmbuf ; Get char from file jr z,dispfd ; No more chars ld a,c cp eof ; End of file? jr z,dispfd ; Yes cp lf ; Line feed? jr z,dispfb ; Yes, check end of screen call @outch ; Char to console jr dispfa dispfb: cmpm topt,'P' ; Page mode? jr z,dispfc ; Yes call pause ; No, check for xoff jr dispfa dispfc: call pgck ; Check for page pause jr nz,dispfa ; Was no pause ld a,c cp etx ; Wants to abort? jr nz,dispfa ; No ret dispfd: cmpm topt,'P' ; Page mode? jp z,pgdn ; Yes jp waitc ; Get the file spec for a command. getfil: mvim event,'F' movcmd logtxt,0,llogtxt-1 ld (hl),cr zmov fcb,fcb2,fcbsize ckname fcb ret ; Send a file to the TNC bsfila: call tnca jr bsfil bsfilb: call tncb bsfil: console call getfil jp z,ername openr fcb jp z,erfind master call dloadb console ret ; Send the info or help text. dseg hfcb: ds fcbsize ; Address of help text ifcb: ds fcbsize ; Address of info text cseg help: zmov fcb2,hfcb,fcbsize jr helinf info: zmov fcb2,ifcb,fcbsize helinf: call getfil jp z,ercant openr fcb jp z,ercant jr dloada ; Download a file. dload: call getfil jp z,ername ld a,(cmdtyp) ckcmd dload,dised,timed openr fcb jp z,erfind ld a,(rfcb+10) and 80h ; $sys attribute set? jp nz,ercant ; Yes, Sorry Charlie ld a,(rfcb+4) and 80h ; New attribute set? jr z,dloada ; No cmpm seenew,true ; Ok to see new? jp nz,ercant ; No, Sorry Charlie dloada: call log ; Log the event ; Common code for bsfil and dload. dloadb: call fmbuf ; Get char from file ret z ; No more chars ld a,c cp eof ; End of file? ret z ; Yes cp lf ; Line feed? jr z,dloadb ; Yes, don't send it call @outch ; Send the char jr dloadb ; Receive a file. dseg fm2: ds 2 topt: ds 1 cseg rcvfil: movb topt,opt2 call getfil jp z,ername ld a,(usopt) and usosys ; Is sysop? jr nz,rcvfa ; Not sysop, no delete if file exists. ld a,(cmdtyp) ckcmd rcvfil,dised,timed openwn fcb ret z jr rcvfc ; Sysop. May delete if wants to. rcvfa: cmpm topt,'A' ; Append? jr z,rcvfb ; Yes call ersfil ret nz openw fcb jr rcvfc rcvfb: opena fcb rcvfc: jp z,ercant prtx fm2 call rcv push psw call log pop psw jp z,ercant ; I/O error ld a,(usopt) and usosys ; Is sysop? ret nz ; Yes mvim opt2,'N' jp hidfil ; Mark as new ; Erase a file. ; Zero set if erased, cleared if exists and not erased. dseg lm2: ds 2 cseg ersfil: dodosa setdma,defdma dodosa search,fcb inc a ret z prtx lm2 call getcmd ld a,(opt1) cp 'Y' ret nz dodosa delete,fcb retz ; Open a blind save file. opfila: call tnca jr opfil opfilb: call tncb opfil: console call getfil jp z,ername call ersfil ret nz openw fcb mvim saveit,true jp term ; Write the blind save file. wrtfil: cmpm saveit,false ret z ld c,eof call tobuf closew mvim saveit,false ret ; Talk to the sysop. dseg talkm2: ds 2 talkm3: ds 2 talkm4: ds 2 lm4: ds 2 cseg talk: prtx talkm2 ; Tell user "paging sysop" ld e,30 ; # times to ding bell console prtx talkm4 ; Tell who wants us talka: ld c,bell call @outch ; DING wait 2 ; Wait a sec call const ; Anyone answer? jr nz,talkb ; Yes master call const ; Remote get tired waiting? jr nz,talke ; Yes console dec e ; Count dings jr nz,talka ; More dings master prtx talkm3 ; Tell em "no answer" ret talke: call getdat ; Get input from TNC jr talkf ; and quit talkb: prtx lm4 ; Tell remote we are here call term ; and talk to them master talkf: ld a,(cmdtyp) ckcmd talkx,dised,timed talkx: ret ; Set current tnc to "user" state scu: ld hl,(scua) cmpm iobyte,raiob jp z,@docmd ld hl,(scub) jp @docmd ; Set current tnc to "sysop" state scs: ld hl,(scsa) cmpm iobyte,raiob jp z,@docmd ld hl,(scsb) jp @docmd off: dw $+2 db 'conok off',cr db 'mon off',cr,0 on: dw $+2 db 'mon on',cr db 'conok on',cr,0 ; Set both tncs to "idle" state twoon: call tnca docmd on cmpm twotnc,false jr z,twoona call tncb docmd on twoona: console ret ; Set both tncs to "user" state twooff: call tnca docmd off cmpm twotnc,false jr z,twoofa call tncb docmd off twoofa: console ret ; Send the beacon text to the tncs sci: call tnca docmd scia cmpm twotnc,false jr z,scip call tncb docmd scib scip: console ret dseg byemsg: ds 2 lm5: ds 2 dofwd: db true fwdmin: ds 1 utime: ds 2 ; Seconds to wait between "user" calls cseg ; Log user out. exclud: ld b,'E' jr bye logout: ld a,(usopt) and usobbs+usoexp ; Is a bbs or expert user? jr nz,logbbs ; Yes, ZAP master prtx byemsg ; Say bye bye wait 4 logbbs: ld b,'B' jr bye force: ld b,'F' jr bye dised: ld b,'D' jr bye timed: master call ertime ; Tell timout wait 4 ld b,'T' bye: ld sp,stack ; Set stack back to init push bc master call cmdtnc ; TNC to command mode docmd off ; Turn off connect and monitor call scu ; Set tnc to user state pop bc ld hl,menu ; Return point as if from command push hl ; On stack for return ld a,'X' call logo ; Log the disconnect call dis ; Disconnect cmpm logtxt,'E' ; Excluded? call nz,moncon ; No, add call to "J" list jr autoa ; Wait for next connect ; Auto answer remote operation. auto: prtx lm5 ; Say we going to auto-answer ld a,'X' ld b,'A' call logo ; Log exit by owner autoa: call updusr ; Update user record ld hl,change ld a,(hl) ld (hl),false cp true ; Any msgs sent or killed? call z,getto ; Yes, then make new beacon text ld a,false ld (gotreq),a ; No connect request seen yet ld (mcon),a ; No TNC connected yet mvim short,true ; Start with short menu call sci ; Set beacon text call twoon ; Turn on the TNC's movw timer,utime ; Initialize timer ; call scan ; Start the radios scanning ; Wait for connect. autob: console call const ; Console key? jr z,autoc ; No call @inch ; Yes, get the character ld a,(wchar) ; Get the attention character cp c ; Was it one? jr nz,autoc ; No call twooff ; Yes, turn the TNC's off zmov mcall,ocall,6 ; Owner logged in call getusr ; Make owner current user mvim mode,lmode ; Set local mode ld a,'C' ld b,'E' call logo ; Login owner call logdrn ; Make log current ret ; Go to menu autoc: call tnca call const ; Char from TNC on COMM port? jr nz,autod ; Yes cmpm twotnc,false ; We have 2 TNCs? jr z,autoe ; No call tncb ; Yes, check other one call const ; Char from TNC on PRINTER port? jr z,autoe ; No autod: mvim getwt,false ; Just in case con req call getdat ; Get line from TNC call gotcon ; Did someone connect? jr z,ans ; Yes, connected call mon ; Check for a new call seen jr autob ; and wait for something to happen ; Nothing from a TNC, check if it is time to do something. autoe: dtz timer ; Time to call the user routine? jr nz,autof ; No call user ; Yup. Call it. movw timer,utime ; Restart timer. autof: ld hl,fwdmin ; Forward at this minute ld a,(min) ; The current minute cp (hl) ; Same? jr z,autog ; Yes, forward any messages mvim dofwd,true ; No. Mark ok to forward jp autob ; and wait for something to happen ; Time to forward. autog: cmpm dofwd,false ; Did we forward already? jp z,autob ; Yes, dont try twice in same hour call twooff ; Turn TNC's off call fwd1 ; and do the forward mvim dofwd,false ; Mark that we did it ld hl,change ld a,(hl) ld (hl),false cp true ; Anything forward? jr nz,autoh ; No call getto ; Update beacon list call sci ; and beacon text autoh: call twoon ; Turn the TNC's back on ; call scan ; Restart freq scanning jp autob ; and wait for something to happen ; Someone connected. ans: mvim ncerrs,0 ; No command errors yet cmpm twotnc,true ; Two tncs? jr nz,ansa ; No slave docmd off master ansa: call cmdtnc ; Get TNC to command mode call lnkst ; Get link status ld c,28 call mcmt ; Move command tail to front call conmod ; TNC to converse mode mvim mcon,true ; Mark that master TNC is connected ld b,'A' cmpm mtnc,raiob jp z,login ld b,'B' jp login ; Log user in exit: call wtmon ; Save J lists ld a,'X' ld b,'Q' call logo ; Log exit by owner call clsmsg ; Close the mail file call clsusr ; Close user file call logdrn ; Close the log file dodosa setdma,defdma jp 0 end