; need to do: ; get KB early (before we try to assign) ; change refs to KBUNT to point to KB, set high byte (flag) ; fix HANGUP and the exit point to reattach to the terminal ; Real Soon Now. ; 2/9/88 JMBW .enabl lc .title answer the phone, my son ;++ ; ; Program to handle dial-up logins. ; ; Gives them the BBS stuff, and lets them fall through ; to LOGIN if they use the username 'DIGBY'. ; ; Must be assembled with PREFIX.MAC, which contains the ; definitions of BBSDEV, BBSUNT, and BBSPPN. ; ;-- firqb= 402 ;file request queue block xrb= 442 ;transfer request block calfip= emt ;call file processor opnfq= 2 ;CALFIP subfunc to open a file crefq= 4 ;subfunc to create and open a file errfq= 16 ;subfunc to return error message .read= emt+2 ;read a record .write= emt+4 ;write a record .sleep= emt+10 ;timed wait .peek= emt+12 ;peek monitor core .spec= emt+14 ;special device-dependent function .ttech= emt+20 ;enable echo .ttnch= emt+22 ;disable echo .postn= emt+32 ;get carriage column .date= emt+34 ;get system date/time .run= emt+42 ;chain to another program .exit= emt+46 ;exit to system default RTS (BASIC) .rts= emt+50 ;switch to new KBM .uuo= emt+66 ;FIP calls (unimplemented user operation) uu.hng= -9. ;.UUO subfunc to hang up a dataset uu.lin= 4 ;subfunc to log in uu.att= 6 ;subfunc to attach to terminal uu.det= 7 ;subfunc to detach from terminal uu.chu= 8. ;subfunc to kill a job uu.ass= 10. ;subfunc to assign device uu.trm= 16. ;subfunc to set term characteristics uu.cnv= 20. ;subfunc to convert date and time to ASCII uu.sys= 26. ;subfunc to get job status info ; cr= 15 ;carriage return lf= 12 ;line feed ; answer: ; see if we are on a dialup line mov #1010,xrb ;#JOBDA (addr of our JDB) .peek ;get it .peek ;get our KB's DDB (PEEK(PEEK(520%))) mov xrb,r0 ;save it add #36,xrb ;index into DDB .peek ;get TTINTF (interface flags) mov xrb,ttintf ;save bit #40000,xrb ;bit 14 set? beq 35$ ;no, it's not a dialup ; dialup, detach from terminal and open it in binary mode ; movb #uu.det,firqb+3 ;func=detach from terminal ; movb #200,firqb+4 ;our job, close chan #0 ; .uuo ;do it ; call clrfrq ;clear FIRQB ; movb #uu.ass,firqb+3 ;func=assign terminal ; mov #"KB,firqb+30 ;device=KBu: ; mov kbunt,firqb+32 ; .uuo ;assign it call clrfrq ;clear FIRQB movb #opnfq,firqb+3 ;OPEN mov #"KB,firqb+30 ;'KBu:' ; mov kbunt,firqb+32 movb #2,firqb+4 ;AS FILE 1%, mov #100021,firqb+22 ;MODE 17% calfip ;do it 10$: ; get a CR and set baud rate jsr pc,typahd ;clear input buffer mov #xrb,r0 ;pt at xrb mov #1,(r0)+ ;read one byte clr (r0)+ ;none read yet mov #kbbuf,(r0)+ ;point at buffer mov #2,(r0)+ ;channel 1 clr (r0)+ ;next block mov #30.,(r0)+ ;give them 30 secs clr (r0) ;RECORD 0% .read ;should read CR if baud rate is correct tstb firqb ;any errors? beq 20$ ;no, skip jmp hangup ;yes, hang up 20$: cmpb #cr,kbbuf ;did we get a CR? beq 30$ ;yes, good cmpb #cr!200,kbbuf ;how about a CR with the high bit set? beq 30$ ;yep, ok (old term with parity off or even par) cmpb #376,kbbuf ;begn of 300 baud CR? bne 10$ ;no, try again jsr pc,clrfrq ;clear out firqb movb #uu.trm,firqb+3 ;func=set term characteristics movb #377,firqb+5 ;on current term movb #7,firqb+17 ;set baud rate to 300 (on DZ11's only) .uuo ;do it 30$: clrb firqb+3 ;func=close file movb #2,firqb+4 ;channel 1 calfip ;do it 35$: ; log them in jsr pc,clrfrq ;clear FIRQB movb #opnfq,firqb+3 ;OPEN mov #"KB,firqb+30 ;'KB:' movb #2,firqb+4 ;AS FILE 1%, mov #100020,firqb+22 ;MODE 16% calfip ;do it jsr pc,typahd ;clear input ring movb #errfq,firqb+3 ;func=return error message clrb firqb+4 ;error 0 calfip ;get error message movb firqb+3,kb ;save KB # movb firqb+2,r1 ;and job # (*2) asr r1 ;/2=job movb r1,job ;save clr r0 ;sxt div #10.,r0 ;separate digits of job # mov r0,r3 ;copy high digit mul #50,r3 ;shift left (rad50) add r3,r1 ;add together add #^R 00,r1 ;convert to rad50 mov r1,jobr50 ;save mov #firqb+40,r0 ;point at end of message 40$: tstb -(r0) ;strip off trailing nulls beq 40$ ;whee! sub #firqb+2,r0 ;correct, and convert to length (allow for cr) mov r0,50$ ;poke movb #cr,firqb+3 ;put cr at begn (cover trash from baud change) jsr r5,type ;print system ID .word firqb+3 ;addr of error message 50$: .word ;length goes here .date ;get date, time mov xrb,curdat ;save date and time mov xrb+2,curtim movb #uu.cnv,firqb+3 ;func=convert date/time mov xrb,firqb+4 ;copy date clr firqb+6 ;use system default format mov xrb+2,firqb+22 ;copy time clr firqb+24 ;use default .uuo ;convert date/time to ASCII mov #timbuf,r0 ;point at buffer mov #firqb+26,r1 ;point at time 60$: movb (r1)+,(r0)+ ;copy a byte bne 60$ ;loop dec r0 ;back up movb #' ,(r0)+ ;add 2 spaces movb #' ,(r0)+ mov #firqb+10,r1 ;point at date 70$: movb (r1)+,(r0)+ ;copy bne 70$ ;loop sub #time+1,r0 ;correct for nul & find length mov r0,80$ ;poke it jsr r5,type ;print time, date .word time 80$: .word jsr r5,type ;print message .word mess,l.mess user: jsr r5,type ;prompt for username .word prompt,12 jsr pc,getlin ;read a line jsr pc,beglin ;crlf if nessa tst r1 ;empty line? bne 10$ ;no, skip jmp newacc ;yes, log in with no name 10$: ; process username mov r0,r2 ;copy ptr mov r1,r3 ;and length mov #name,r4 ;point at buffer 20$: movb (r2)+,(r4)+ ;copy a byte sob r3,20$ ;loop mov #12.,r3 ;length of field sub r1,r3 ;find amount left blos 40$ ;name fills entire field 30$: movb #' ,(r4)+ ;pad with blanks sob r3,30$ ;loop 40$: mov #usrnam,r5 ;point at buffer mov #4,r4 ;4 words (12 chars) jsr pc,rad50 ;convert to radix-50 bcs 60$ ;error, gack and try again cmp #^RDIG,usrnam ;see if username='DIGBY' bne 50$ ;nope cmp #^RBY ,usrnam+2 ;could be... bne 50$ ;nope ; chain back to LOGIN... mov #firqb+6,r0 ;point at filename mov #402,(r0)+ ;ppn=[1,2] mov #^RLOG,(r0)+ ;'LOGIN .BAC' mov #^RIN ,(r0)+ mov #^RBAC,(r0)+ mov #firqb+30,r0 ;point at device clr (r0)+ ;SY: clr (r0)+ ;no unit # tst (r0)+ ;(unused) mov #31500.,(r0) ;LINE 31500% (this is important!) .run ;go to it 50$: jsr r5,type ;prompt for password .word psword,12 .ttnch ;turn off echo for password jsr pc,getlin ;read a line .ttech ;echo back on jsr pc,beglin ;crlf if nessa mov #paswrd,r5 ;point at buffer mov #2,r4 ;2 words (6 chars) jsr pc,rad50 ;convert to radix-50 bcc 80$ ;no prob 60$: decb try ;give up? beq 70$ ;yes, tell them so jsr r5,type ;gack .word inval,l.inva br user ;try again 70$: jsr r5,type ;access denied .word noacc,l.noac jmp dscnct ;hang up on them 80$: jsr pc,clrfrq ;clear the firqb movb #opnfq,firqb+3 ;func=open file for input movb #4,firqb+4 ;on channel 2 mov #firqb+6,r0 ;point at filename mov #bbsppn,(r0)+ ;filename='devn:[p,pn]BBUSER.DAT' mov #^RBBU,(r0)+ mov #^RSER,(r0)+ mov #^RDAT,(r0) .iif ne , mov #bbsdev,firqb+30 .iif ne , mov #bbsunt,firqb+32 calfip ;open the file tstb firqb ;error? beq 90$ ;no jsr r5,type ;print message .word cntopn,l.cnto jmp dscnct ;die 90$: mov firqb+16,r5 ;get file size 100$: mov #8.,r4 ;# of records per block mov #buf,r3 ;point at buffer mov #xrb,r0 ;point at xrb mov #512.,(r0)+ ;read one block clr (r0)+ ;nothing read yet mov r3,(r0)+ ;into @#buf mov #4,(r0)+ ;channel 2 clr (r0)+ ;next block clr (r0)+ ;(KB wait time) clr (r0) ;(modifier bits) .read ;read the block 110$: mov #4,r2 ;name is 4 words long mov r3,r1 ;copy ptr mov #usrnam,r0 ;point at name 120$: cmp (r0)+,(r1)+ ;do they match? bne 140$ ;no, skip sob r2,120$ ;loop mov #2,r2 ;compare passwords 130$: cmp (r0)+,(r1)+ ;match? bne 150$ ;no, invalid entry sob r2,130$ ;loop br 160$ ;go log in 140$: add #100,r3 ;point at next entry in block sob r4,110$ ;check the whole block sob r5,100$ ;for all blocks 150$: ; bad password or username not found clrb firqb+3 ;(=CLSFQ) func=close file movb #4,firqb+4 ;channel 2 calfip ;do it br 60$ ;print message 160$: mov (r1)+,lsttim ;copy time and date of last login mov (r1),lstdat mov curdat,(r1) ;replace with current time and date mov curtim,-(r1) mov #xrb,r0 ;point at xrb mov #512.,(r0)+ ;write 1 block mov #512.,(r0)+ ;... mov #buf,(r0)+ ;from @#buf mov #4,(r0)+ ;to channel 2 tst (r0)+ ;(still there from .READ) clr (r0)+ ;(not applicable) clr (r0) ;no modifiers .write ;update time of last login clrb firqb+3 ;(=CLSFQ) func=close file movb #4,firqb+4 ;channel 2 calfip ;do it movb #uu.cnv,firqb+3 ;func=convert date/time mov lstdat,firqb+4 ;copy date clr firqb+6 ;use system default format mov lsttim,firqb+22 ;copy time clr firqb+24 ;use default .uuo ;convert date/time to ASCII mov #lst1,r0 ;point at buffer mov #firqb+26,r2 ;point at time 170$: movb (r2)+,(r0)+ ;copy bne 170$ ;loop dec r0 ;back up movb #' ,(r0)+ ;add ' on ' movb #'o,(r0)+ movb #'n,(r0)+ movb #' ,(r0)+ mov #firqb+10,r2 ;point at date 180$: movb (r2)+,(r0)+ ;copy bne 180$ ;loop sub #lstlog+1,r0 ;find length mov r0,190$ ;save jsr r5,type ;print message .word lstlog 190$: .word ;length jsr r5,type ;crlf .word crlf,2 tst 4(r1) ;any mail? beq 200$ ;no, skip jsr r5,type ;yes, tell them so .word newmai,l.newm 200$: clrb anon ;this is not an anonymous login br login ;go log in ; newacc: ; let them log in with no username jsr r5,type ;tell them how to get a username .word nouser,l.nous movb #377,anon ;anonymous login ; login: ; log them in, user name in USRNAM movb #uu.sys,firqb+3 ;func=get status clr firqb+4 ;current job .uuo ;get status tst firqb+26 ;are we already logged in? bne 25$ ;nope, don't start killing random jobs! movb #uu.lin,firqb+3 ;func=login mov #100.*400+100.,firqb+6 ;to [100,100] mov #^RDEM,firqb+10 ;password is always the same ('DEMO') mov #^RO ,firqb+12 .uuo ;do it mov #firqb+6,r3 ;point at list of detached jobs mov #buf,r4 ;point at buffer mov r4,r5 ;copy 10$: movb (r3)+,(r4)+ ;copy list of detached jobs bne 10$ ;loop ; now shoot them down, one by one ; (they are most likely jobs that were ; hung up on; this means it is not safe ; to use [100,100] detached, but there ; is no reason to do this anyway). 20$: movb (r5)+,firqb+4 ;get next job to zap beq 30$ ;no more jobs, never mind movb #uu.chu,firqb+3 ;func=kill job mov #177400,firqb+34 ;distinguish from other uu.chu funcs .uuo ;zap it br 20$ ;loop 25$: jsr r5,type ;tell them they were already logged in .word logged,l.logg 30$: tstb anon ;anonymous login? bne 40$ ;yes, skip ; write username and time of last login to NAMEjj.TMP jsr pc,clrfrq ;clear the firqb movb #crefq,firqb+3 ;func=open file for input movb #4,firqb+4 ;on channel 2 mov jobr50,r0 ;get job # add #^RE ,r0 ;name='NAMEjj.TMP' mov #firqb+10,r5 ;point at filename mov #^RNAM,(r5)+ mov r0,(r5)+ mov #^RTMP,(r5)+ movb #1,(r5) ;file size=1 block calfip ;create the file mov #xrb,r0 ;point at xrb mov #512.,(r0)+ ;write 1 block mov #512.,(r0)+ ;... mov #name,(r0)+ ;from NAME mov #4,(r0)+ ;to channel 2 clr (r0)+ ;next (first) block clr (r0)+ ;(not applicable) clr (r0) ;no modifiers .write ;do it clrb firqb+3 ;(=CLSFQ) func=close file movb #4,firqb+4 ;channel 2 calfip ;do it 40$: ; type NOTICE.TXT, exit to KBM jsr pc,clrfrq ;clear the firqb movb #opnfq,firqb+3 ;open the file movb #4,firqb+4 ;channel 2 mov #firqb+6,r0 ;point at filespec mov #bbsppn,(r0)+ ;filename='devu:[p,pn]NOTICE.TXT' mov #^RNOT,(r0)+ mov #^RICE,(r0)+ mov #^RTXT,(r0)+ mov #120000,firqb+22 ;/RONLY .iif ne , mov #bbsdev,firqb+30 .iif ne , mov #bbsunt,firqb+32 calfip ;do it mov firqb+16,r5 ;get file size 50$: mov #xrb,r0 ;point at xrb mov #1000,(r0)+ ;read one block clr (r0)+ ;nothing read yet mov #buf,(r0)+ ;read into buf mov #4,(r0)+ ;channel 2 clr (r0)+ ;next block clr (r0)+ ;n. a. clr (r0) ;no modifiers .read ;read a block mov #buf+1000,r0 ;pt at end of buffer 60$: tstb -(r0) ;trim trailing nuls beq 60$ inc r0 ;found non-nul char sub #buf,r0 ;find length mov r0,70$ ;poke jsr r5,type ;type it out .word buf 70$: .word ;length sob r5,50$ ;for all blocks clrb firqb+3 ;(=CLSFQ) func=close movb #4,firqb+4 ;channel 2 calfip mov #firqb+10,r0 ;point into firqb mov #^RBBS,(r0)+ ;KBM name='BBS' clr (r0)+ mov #-1,(r0) ;SWITCH BBS .rts ;die jsr r5,type ;it didn't work! .word nokbm,l.nokb ;print message br dscnct ;buy it ;+ ; ; RAD50 ; ; Convert a string to radix-50. ; On entry, r0 points to a string, r1 contains the length, ; r5 points to the area in which to store the result, ; and r4 contains the length (words) of the area. ; ; On return, everything is peachy unless C=1, ; in which case the string contained one or more ; non-radix-50 characters. ; ;- rad50: clr r3 ;init jsr pc,20$ ;do 3 chars jsr pc,10$ jsr pc,10$ mov r3,(r5)+ ;save sob r4,rad50 ;loop ; 10$: ;do a single char mul #50,r3 ;make space for the char 20$: tst r1 ;anything left? beq 80$ ;no, return dec r1 ;yes, dec count movb (r0)+,r2 ;and get the char cmp #'$,r2 ;dollar sign? bne 30$ ;no add #33,r3 ;yes rts pc 30$: cmp #'_,r2 ;underline? bne 40$ ;no add #35,r3 ;yes, use undefined code rts pc 40$: cmp #'.,r2 ;decimal point? beq 50$ ;yes cmp r2,#'0 ;digit? blo 60$ ;no cmp r2,#'9 ;hm? bhi 60$ ;no 50$: add #36-'0,r2 ;yes, convert to rad50 br 70$ ;skip 60$: sub #'A,r2 ;letter? blo 90$ ;no cmp r2,#25. ;hm? bhi 90$ ;no inc r2 ;yes, convert to rad50 70$: add r2,r3 ;add in 80$: rts pc 90$: tst (sp)+ ;purge stack sec ;error rts pc ;fall through to original caller ;+ ; ; GETLIN ; ; Read a line from the KB (channel 1); ; hang up and kill job on ^C or HB. ; Return ptr to line in r0, length in r1, ; Z=1 if length is zero. ; ;- getlin: mov #xrb,r1 ;point at xrb mov #82.,(r1)+ ;length of buffer clr (r1)+ ;nothing in it yet mov #kbbuf,r0 ;point at buffer mov r0,(r1)+ ;save mov #2,(r1)+ ;channel 1 clr (r1)+ ;read next block mov #10.,(r1)+ ;wait 10. seconds clr (r1) ;no modifiers .read ;read a line movb firqb,r5 ;any errors? bne 40$ ;yes, hang up mov r0,r1 ;no, copy ptr mov xrb+2,r3 ;get length of line read 10$: movb (r0)+,r5 ;get a char cmp r5,#3 ;^C? beq 40$ ;yes, hang up cmp r5,#40 ;space or ctrl char? blos 30$ ;yes, ignore cmp r5,#'A+40 ;lower case? blo 20$ ;no cmp r5,#'Z+40 ;eh? bhi 20$ ;no sub #40,r5 ;yes, convert 20$: movb r5,(r1)+ ;no, copy 30$: sob r3,10$ ;loop mov #kbbuf,r0 ;point at string sub r0,r1 ;find length rts pc 40$: ; read error, or user typed ^C cmp r5,#27. ;'?I/O to detached keyboard'? beq hangup ;yes, just hang up dscnct: jsr pc,beglin ;no, crlf, if nessa jsr r5,type ;print message .word discon,l.disc ;br hangup ;hang up ;+ ; ; Hang up the dataset and die. ; ;- hangup: .ttech ;reenable echo if stopped clrb firqb+3 ;(=CLSFQ) func=close file movb #2,firqb+4 ;channel 1 calfip ;close the terminal movb #uu.hng,firqb+3 ;func=hang up dataset mov kb,firqb+4 ;get KB #, hang up in 2 secs asr firqb+4 ;cvt to .UUO format .uuo ;do it ; wait for modem to hang up before axing ourself ; otherwise the Vadic modem makes Digby think it's ringing mov #10.,xrb ;wait 10. seconds .sleep ;for modem to hang up movb #uu.chu,firqb+3 ;func=kill job movb job,firqb+4 ;our job mov #177400,firqb+34 ;distinguish from other uu.chu funcs .uuo ;do it .exit ;exit if kill failed (should never happen) ;+ ; ; TYPE ; ; Print string with inline addr and length. ; Call: jsr r5,type ; addr ; length ; ... return ; ;- type: mov (r5)+,xrb+4 ;get ptr mov (r5),xrb ;get length mov (r5)+,xrb+2 ;twice mov #2,xrb+6 ;channel 1 clr xrb+10 ;next block clr xrb+14 ;RECORD 0% .write ;write tstb firqb ;error? bne hangup ;yes, die rts r5 ;no, return ;+ ; ; Print a crlf if not at left margin. ; ;- beglin: movb #2,xrb+6 ;no, see if at begn of line .postn ;return column tstb xrb+2 ;at begn of line? beq 10$ ;yes jsr r5,type ;print crlf .word crlf,2 10$: rts pc ;+ ; ; Clear out the FIRQB. ; ;- clrfrq: mov #firqb,r0 ;point at firqb mov #20,r1 ;length=20 words 10$: clr (r0)+ ;clear out the firqb sob r1,10$ ;loop rts pc ;+ ; ; Clear typeahead buffer for channel 1. ; ;- typahd: mov #xrb,r0 ;pt at xrb mov #7,(r0)+ ;func=cancel typeahead clr (r0)+ ;keyboard is open clr (r0)+ ;(not used) mov #1002,(r0)+ ;TTYHND, channel 1 clr (r0) ;not SEND or FORCE .spec ;do it rts pc ; kb: .word 0 ;our KB number in low byte job: .byte ;our job number try: .byte 5 ;retry count for password anon: .byte ;if non-zero, user has no name ; time: .ascii ' ' ;2 blanks timbuf: .blkb 20. ;allow 20. bytes for date and time ; mess: .ascii 'If you have no username, press RETURN.' .ascii 'Type DIGBY to log into a RSTS account.' l.mess= .-mess ; prompt: .ascii 'Username: ' ; psword: .ascii 'Password: ' ; nouser: .ascii /If you want a username, type 'USERNAME'/ .ascii /in response to the '@' prompt. You will/ .ascii /need a username only to post messages and/ .ascii /receive mail./ crlf: .byte cr,lf l.nous= .-nouser ; logged: .ascii /[already logged in]/ l.logg= .-logged ; discon: .ascii /?Disconnecting/ l.disc= .-discon ; inval: .ascii /?Invalid entry - try again/ l.inva= .-inval ; noacc: .ascii /?Access denied/ l.noac= .-noacc ; lstlog: .ascii /Last login was at / lst1: .blkb 26 ;buffer for time, date ; newmai: .ascii /You have mail. Type 'READ' to read it./ l.newm= .-newmai ; cntopn: .ascii /?FATAL ERROR - can't open BBUSER.DAT/ l.cnto= .-cntopn ; nokbm: .ascii /?FATAL ERROR - can't declare default KBM/ l.nokb= .-nokbm ; .even ttintf: .blkw ;TTINTF word from KB DDB curtim: .blkw ;current time curdat: .blkw ;current date jobr50: .blkw ;job #, 2-digit rad50 name: .blkb 12. ;username, ascii, for NAMEjj.TMP lsttim: .blkw ;time of last login lstdat: .blkw ;date of last login usrnam: .blkw 4 ;username, rad50 paswrd: .blkw 2 ;password, rad50 ; PASWRD must immediately follow USRNAM! kbbuf: ;keyboard buffer, buf: .blkb 512. ;and block buffer for BBUSER.DAT ; ; .end answer