;CBBS V3.5.0 CBBSSUB2.ASM - NON-DISK ROUTINES # 2 ;01/03/82 15:09 ; LINKS TO CBBSSUB3.ASM ; ; O O O O O O O O O ; O O O O O O O ; CBBS O O O O O O O O .ASM ; O O O O O O ; O O O O O O O O O O O ; ;MOD LOG: (THRU 3.2 WRITTEN TO "HISTORY") ; ;====> HISTORICAL COMMENTS SINCE 3.3 TO "HISTORY.033" ; ;MODS SINCE 3.5: ; 01/03/81 ;Put in label OUTTTY, to facilitate patching it ;out for the test version of cbbs; also correct ;some missing initializations in reinit routine ; ; -------- ;FOLLOWING COUNTERS TO KEEP SOMEONE FROM ;HANGING UP CBBS INDEFINITELY. EACH TIME ;KEYIN IS CALLED, A COUNT OF "DELAY1" IS ;SET IN A REGISTER. STAT IS CALLED 65536 ;TIMES THAT COUNT. WHEN THE COUNT REACHES ;DELAY2, A WARNING MESSAGE IS PRINTED. ;WHEN THE COUNT REACHES 0, THE CALL IS DUMPED. ; ; N-O-T-E: DOUBLE THESE VALUES IF ;RUNNING 4MHZ. THE ACTUAL TIMEOUT WILL DEPEND ;UPON THE INSTRUCTION PATH LENGTH THRU YOUR ;BIOS, SO EXPERIMENT WITH THESE VALUES. ; DELAY1 EQU 50 ;COUNT FOR TIMEOUT DELAY2 EQU 10 ;COUNT FOR WARNING ; ; ;-----> MOVE ROUTINE - (HL) TO (DE), LENGTH IN (B) ; MOVE MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; ;====> COMP4 COMPARE 4 BYTES ; COMP4 MVI B,4 ;FALL INTO "COMPR" ; ;-----> COMPARE ROUTINE (HL) VS (DE) LENGTH IN B ; FIELD (DE) TRANSLATED TO UPPER CASE ; COMPR LDAX D CPI 60H ;LOWER CASE? JC COMPNL ;NO CPI 7BH JNC COMPNL ANI 5FH ;MAKE UPPER CASE COMPNL CMP M RNZ INX H INX D DCR B JNZ COMPR RET ; ;-----> INLINE PRINT - TYPES MESSAGE (WHICH ENDS ; W/00H FOLLOWING 'CALL ILPRT'). ; RETURNS TO INSTR FOLLOWING 00H ; ILPRT POP H ;GET MSG ADDR CALL TYPEM0 ;TYPE THE MESSAGE PCHL ;RET FOLLOWING MESSAGE ; ;----> ILPRX IN-LINE PRINT, BUT WITH EXPERT USER ; MODE FLAG TEST (STOPS AT ":") ; ILPRX POP H CALL TYPEX PCHL ; ;-----> TYPE MESSAGE (HL=POINTER, (B) = END OF MSG) ; TYPEMCR MVI B,CR ;CR DELIMITER JMP TYPEM ; TYPEM0 MVI B,0 ;0 DELIMITER ; TYPEM MOV A,M ;GET CHR INX H CMP B ;END? RZ ;..YES CALL NDTYPE ;NO DUP CHAR TYPE LDA CTLCSW ORA A ;DISABLED? JNZ TYPEM ;..YES CALL CTLCKS ;CHECK FOR CTL-C OR S JZ TYPEMS ;GOT ^C CPI 'F'-40H ;A FLAG COMMAND? JZ TYPEFLG CPI 'M'-40H ;FLAG MISSED ONE? JNZ TYPEM TYPEFLG STA FLAGREQ ;SAVE IT FOR SUMMARY TEST JMP TYPEM ; ;CONTROL-C TYPED - SKIP REST OF MESSAGE ; TYPEMS MOV A,M INX H CMP B ;AT END? JNZ TYPEMS ;LOOP, THEN.. ;..FALL INTO CR/LF: ; ;-----> TYPE CR/LF ; CRLF MVI A,CR CALL TYPE MVI A,LF JMP TYPE ; ;-----> INITIALIZATION ROUTINE ; SETS UP VECTORS TO CBIOS FOR ; KEYBOARD STATUS TEST, AND KEYBOARD INPUT ; INIT LHLD 1 ;GET WARM BOOT ADDR LXI D,3 ;LENGTH OF EACH JMP DAD D ;TO CONSOLE STATUS 01 SHLD VCONST+1 ;MODIFY CALL INSTRUCTION DAD D ;TO KEYBOARD INPUT 01 SHLD VCONIN+1 ;MODIFY JMP INSTRUCTION DAD D ;TO CONSOLE OUT 01 SHLD VCONOUT+1 ;MODIFY CALL INSTR 04 DAD D ;TO LIST OUT ; SHLD VLIST+1 ;MODIFY. MVI A,0DH ;GET C/R STA INBUF ;CLEAR OUT INBUF OF PREV ANS STA FNAME ;SHOW NO NAME ENTERED ; IF TTY XRA A ;GET 0 (EMPTY BUF) STA LOGBUF ;EMPTY BUFFER ENDIF ; RET ; ;-----> KEYBOARD INPUT ROUTINE WITH NO WAIT. ; USED FOR CTL-C AND CTL-S CHECK. ; RETURNS 0 IF NO KEY PRESSED. ; KEYCHR CALL CONST ;GET CONSOLE STAT RZ ;NO CHR, RET W/A=0 CALL KEYIN ;GET CHR RET ;RET W/A=CHAR ; 01 ; START OF -01- MODS TO SAVE REGS KEYV PUSH B PUSH D PUSH H ; ;JMP VECTOR TO CBIOS KEYIN ; VCONIN CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B RET 01 ;END OF -01- MODS ; ;-----> KEYBOARD INPUT ROUTINE ;THIS DOES NOT DO A NORMAL BDOS CALL, AS THEN THE ;USER WOULD BE ABLE TO CONTROL-C BACK TO CP/M ;WHICH WE DON'T WANT TO HAPPEN ; KEYIN call const ;key pressed? ora a jz keyin ; ; ;;MAKE SURE NO ONE HANGS UP CBBS BY WALKING ;AWAY FROM THEIR TERMINAL. ; PUSH B KEYW0 MVI B,DELAY1 ;TIMES 65536 WAITS KEYWT CALL CONST ;KEY PRESSED? JNZ KEYP ;YES. DCX H ;(HL NOT INIT.. MOV A,H ;..NO SWEAT) ORA L ;MORE COUNT? JNZ KEYWT MOV A,B ;TIME TO WARN? CPI DELAY2 CZ TIMEWNG ;TYPE WARNI ; ; ; LDA PASSFLG ; ORA A ; JZ KEYW0 ;START OVER ; ;TIMEOUT - DUMP THE CALL ; IF CLOCK CALL PRETIME ENDIF LDA HOLDFLG ;OPERATOR HOLD? ORA A ; FROM "HOLD" JNZ KEYW0 ; COMMAND? CALL ILPRT DB 'CBBS is a single user system.',CR,LF DB 'Hope you don''t mind my making it ',CR,LF DB 'available for someone else! Bye.' DB CR,LF,0 JMP DISC ;DISCONNECT ;WARN OF TIME RUNNING OUT TIMEWNG CALL CRLF IF CLOCK CALL PRETIME ENDIF CALL ILPRT DB '..Please continue, ',0 LXI H,FNAME CALL TYPEMCR ;PRINT NAME CALL CRLF MVI B,DELAY2 RET ; ;GOT CHAR - CONTINUE ; KEYP POP B ; ;BUMP COUNT OF CHARACTERS RECEIVED. ; LXI H,NCHRE+6 CALL ADD1 ;ADD 1 IN ASCII CALL KEYV ;CALL JMP VECTOR ; ;TRANSLATE TO UPPER CASE IF REQ'D ; LXI H,CASE CPI 60H JC KINUC CPI 7BH JNC KINUC ANA M ;TRANSLATE IF NECESSARY KINUC POP H ; ;CHECK FOR DISCONNECT: CONSOLE IN RETURNS FF IF SO ; CPI 0FFH RNZ ;NO CARRIER LOSS ; ;IF FLAG SET, DON'T WAIT TO TRY AGAIN. ; LDA CARFLG ORA A JNZ CARLOST ; ;HAVE LOST CARRIER - WAIT 1 SEC, TRY AGAIN. ;TO CATCH MOMENTARY CARRIER LOSS GLITCHES ; PUSH H LXI H,0 ;ABOUT 1 SEC DELAY CARWT DCX H MOV A,H ORA A ;DECREMENTED TO 0? JNZ CARWT ;NO POP H CALL KEYV ;CHECK IT CPI 0FFH ;STILL NO CARRIER? RNZ ;CARRIER BACK - RET W/CHR STA CARFLG ;SHOW CARRIER LOST ; ;IF WE ARE IN THE MIDDLE OF A DISK UPDATE, ;IGNORE THE LOSS OF CARRIER, RETURNING JUST C/R ; CARLOST LDA DKUPSW ;GET SWITCH ORA A MVI A,0DH ;C/R RNZ ;RET IF NOT 'KILLABLE' ; ;PRINT DISCONNECT MESSAGE ;(WILL SHOW UP ON LOCAL CONSOLE) ; LXI H,DISCM PRDIS MOV A,M ORA A JZ DISC ;HANG UP CALL TYPE INX H JMP PRDIS ; ;DISCONNECT THE PHONE ; DISC: ; 01 IF FAST 01 CALL FLUSH ;FLUSH BUFFERS 01 ENDIF ;FAST ; 03 IF NOT TEST XRA A OUT CTLPORT ;TURN OFF MOTOR ; ;CALL THE HANGUP ROUTINE IN: ;CBBSPMMI, CBBSIDS, CBBSHAYS, OR CBBSMODM ; CALL HANGUP 03 ENDIF ;NOT TEST ; 03 IF TEST 03 JMP 0 ;REBOOT CP/M 03 ENDIF ;TEST ; 05 IF CBBSCHI 05 MVI A,0CH ;DRIVE D SELECT 05 OUT 0FCH ;NOW NO STEPPER SELECTED 05 ENDIF ; ; IF NOT REINIT ; /--------------------------\ ; ( NOTE FOLLOWING JMP ADDRESS ) ; \--------------------------/ ; ;IN THE ORIGINAL (CHICAGO) CBBS, HARDWARE RING ;DETECT WAS IMPLEMENTED, SO "THE PC WAS PARKED ;IN THE PROM MONITOR" UNTIL RING DETECT RESET ;THE SYSTEM ; ; JMP 0E000H ;EXIT TO PROM MONITOR ; ENDIF ;NOT REINIT ; ;----> COME TO THINK OF IT, IF YOU DO RESET ;YOUR SYSTEM ON A RING, JUST PUT IN SOMETHING LIKE: ; XXX JMP XXX ; IF REINIT ; ;REINITIALIZE VARIABLES, WAIT FOR PHONE TO RING ; XRA A ;GET 0 STA CARFLG ;CARRIER LOST FLAG STA DKUPSW ;NO DISK UPDATE STA NULLS ;# OF NULLS STA EXPERT ;NOT EXPERT USER STA NKILATT ;# OF BAD KILLS STA TWITSW ;NOT TWIT STA NONEFLG ;NOT SHORT OUTPUT STA HOLDFLG ;OPERATOR HOLD MODE ; INR A ;MAKE 1 STA ECHOFLG ;ECHO MODE STA PASSFLG ;NOT OPERATOR MODE STA BELLF ;TURN ON BELL PROMPT ; MVI A,4 ;^K GOES TO "1ST TIME" Q. STA CTLKSW ;DISABLE CTL-K ; MVI A,CCOUNT ;MAX COMMENTS/CALL STA CLEFT MVI A,ECOUNT ;MAX ENTERS/CALL STA ELEFT ; MVI A,8 ;RESET DEFAULT STA BSCHAR ; USER BACKSPACE CHAR ; MVI A,5FH ;TRANSLATE STA CASE ;..TO UPPER CASE ; MVI A,'N' ;RESET COMMENTS.. STA COMFLG ;..BUSY FLAG ;BLANK OUT # CHARS TYPED, RECEIVED LXI H,NCHRE ;# ENTERED CALL BLANK7 LXI H,NCHRT ;# TYPED CALL BLANK7 ; ;WAIT FOR PHONE TO RING ; JMP RINGWT ;IN CBBS(MODEM).ASM ; ;BLANK 7 BYTES, SUCH AS # CHARS IN AND OUT ; BLANK7 MVI B,7 MVI A,' ' BL7 MOV M,A INX H DCR B JNZ BL7 RET ENDIF ;REINIT ; DISCM DB 0DH,0AH DB '++Carrier lost, disconnect++' DB 0DH,0AH,0 ; ;-----> KEYBOARD CONSOLE STATUS ROUTINE ;RETURNS 0FFH IF CHR READY, 0 IF NOT ; 01 ;START OF 01 MODS - TO SAVE REGS CONST PUSH B PUSH D PUSH H VCONST CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B 01 ;END OF 01 MODS ORA A ;SET CONDITION RET ; ;====> NDTYPE TYPES, BUT NOT DUPLICATE CHARS ; NDTYPE PUSH B MOV C,A ;SAVE CHAR LDA NONEFLG ;GET FLAG ORI 80H ;SHOW SUPPRESSING JMP TYPE2 ; ;SPACE: TYPES A SINGLE SPACE ; SPACE MVI A,' ' ; ;-----> CHRACTER OUTPUT ROUTINE ; TO LOCAL DEVICE AND VIA MODIFIED CBIOS, ; TO PHONE LINE ; TYPE PUSH B MOV C,A ;SAVE CHAR LDA NONEFLG ANI 1 TYPE2 STA NONEFLG MOV A,C ;RESTORE CHAR PUSH D PUSH H CPI 60H ;LOWER CASE CHR? JC TYPEC ;NOT LOWER 01 PUSH H LXI H,CASE ;GET MASK ANA M ;MAKE UPPER CASE IF MASK=5FH 01 POP H ; (LEAVES AS IS IF MASK=0FFH) TYPEC MOV C,A ;FOR OUTPUT ROUTINE CPI TAB JNZ TYPEV TYPETAB MVI A,' ' CALL NDTYPE ;DON'T DOUBLE SPACE IF SUPPRESSED LDA TABCOL ANI 7 JNZ TYPETAB JMP TYPERET ; 01;START OF MODS: SAVE REGS ON CALL TO BIOS TYPEV PUSH B PUSH D PUSH H 03;MODS: TO SUPPRESS REDUNDANT SPACES AND ; OTHER GRAPHIC CHARS < '0' LXI H,PREVCHR CMP M ;=PREV CHAR? MOV M,A ;SAVE FOR NEXT TEST JNZ VCONOUT CPI '0' ;CANDIDATE FOR SKIPPING? JNC VCONOUT CPI ' ' JC VCONOUT ;DON'T KILL 2 BACKSPACES ;TEST IF SUPPRESSING REDUNDANT CHARS LDA NONEFLG CPI 81H ;80 = OK TO SKIP, 1 = REQUESTED JZ VCONTP ; YA, SKIP DUP CHAR VCONOUT CALL $-$ ;ADDR FILLED IN BY 'INIT' 04;MODS: VCONTP LDA NONEFLG ANI 1 ;TURN OFF PERMISSION STA NONEFLG ; LDA PRINTSW ;PRINT COMMAND EXECUTED? ; ORA A ;VLIST CNZ $-$ ;CALL BIOS LIST IF SO 04;END ; 03;END 04;MODS: TO SLOW DOWN TYPING DURING TESTING ; OPERATOR "SLOW" COMMAND SLOWS THINGS DOWN TYPDLY LXI H,1 ;THIS VALUE MODIFIED BY "SLOW" COMMAND TYPDLP DCX H MOV A,H ORA L JNZ TYPDLP 04;END POP H POP D POP B 01;END OF MODS ; ;UPDATE COLUMN USED IN TAB EXPANSION ; MOV A,C CPI CR JNZ TYPENCR MVI A,0 STA TABCOL JMP TYPEBC ; TYPENCR CPI 8 ;VIDEO BACKSPACE? JNZ TYPENBS LDA TABCOL DCR A STA TABCOL JMP TYPEBC ; TYPENBS CPI ' ' ;CTL CHAR? JC TYPEBC ;..NO CHANGE IN COL LDA TABCOL INR A STA TABCOL ; ;BUMP COUNT OF CHRACTERS TYPED ; TYPEBC LXI H,NCHRT+6 CALL ADD1 ; IF TTY ;HAVE LOG TTY? CALL CKTTY ;SEE IF ANY CHRS TO GO ENDIF ; ;CHECK IF LINEFEED, AND IF SO, SEND NULLS ;IF REQUESTED ; MOV A,C ;GET CHR CPI 0AH CZ DONUL ;DO NULLS TYPERET POP H POP D POP B RET ; ;ROUTINE TO SEND OUT NULLS FOLLOWING CR/LF ; DONUL LDA NULLS ;GET COUNT INR A ;MAKE 0 INTO 1 MOV B,A ; ;MAY ENTER HERE W/NULL COUNT + 1 IN B ; NULLP DCR B ;END OF NULLS? RZ ;..YES XRA A ;GET NULL CALL TYPE ;TYPE IT JMP NULLP ; IF TTY ; ;ROUTINE TO ASYNCHRONOUSLY LOG DATA TO A TTY. ;ONLY DATA KEYED IN IS LOGGED. ; ;THIS ROUTINE IS ASYNCHRONOUS TO ALLOW A ;110 BAUD TTY TO LOG EVEN THO SOMEONE MIGHT ;BE KEYING IN FASTER, EITHER MANUALLY, OR ;FROM A PROGRAM. IF THE LOGGING TTY GETS ;256 CHARS BEHIND, THEN IT JUST THROWS 256 ;CHARS AWAY AND CONTINUES. L/F AUTOMATICALLY ;SENT AFTER C/R ; LOG PUSH H ;SAVE HL LHLD TTYSTP ;GET BUFFER POINTER CPI CR JNZ CKSTOR ;NOT C/R, STORE ;IF COLUMN > 60 THEN STORE C/R, OTHERWISE '/' LDA COL CPI 60 MVI A,CR JNC CKSTOR ;COL < 60, STORE '/' INSTEAD MVI A,'/' CKSTOR MOV M,A ;STORE CHR INR L ;BUMP, STAY W/IN 256 BYTES MVI M,0 ;END OF BUFFER POINTER SHLD TTYSTP PUSH PSW ;SAVE CHR CALL CKTTY ;TYPE BUFFERED CHARS POP PSW ;GET CHAR FOR CR TEST ;BUMP COL, OR SET =0 IF C/R LXI H,COL INR M CPI CR JNZ CKCOL MVI M,0 ;RESET ;CHECK IF COL>70, C/R IF SO CKCOL MOV A,M ;GET COL CPI 70 POP H RC ;RET IF < 70 MVI A,CR JMP LOG ;STORE C/R THIS TIME ; ;CHECK IF TTY READY FOR OUTPUT. NO REGS SAVED ; CKTTY LHLD TTYLDP ;GET LOAD POINTER MOV A,M ;GET CHR ORA A ;END OF BUFF? RZ ;YES, RET ;SEE IF TTY READY IN TTYSP ANI TTYST ; ;-----> NOTE YOU MIGHT HAVE TO CHANGE FOLLOWING TO RNZ ; RZ ;TTY NOT READY MOV A,M ;GET CHR OUTTTY OUT TTYDP ;OUTPUT IT ADDED LABEL 1/3/82 CPI CR ;C/R? JNZ TTYNCR ;NO. ;GOT C/R - STORE LINE FEED FOR NEXT TIME MVI M,LF ; PMMI ; OR CBBSMODM SERIAL ; ; O O O O O O O O O ; O O O O O O O ; CBBS O O O O O O O O .ASM ; O 6 L/F'S ;NEXT 15 LINES ADDED, TO PAGE EJECT PRINTER CPI LF JNZ TTYNLF LDA TTYLCT ;GET LINE COUNT INR A STA TTYLCT CPI 60 JNZ TTYNLF ;NOT AT 60 ;LINE COUNT IS AT 60, STORE 6 LF'S MVI A,256-6 ;TRICK SO ASM WON'T GLITCH STA TTYLCT ;SET LINE COUNT = -6 TTYSLF DCR L ;BACK UP 1 MVI M,LF ;STORE LF INR A JNZ TTYSLF ENDIF ;EJECT AND TTY ; IF TTY TTYNLF SHLD TTYLDP ;SAVE LOAD POINTER RET ENDIF ;TTY ; ;BUMP ASCII COUNT FIELD (HL POINTS TO UNITS DIGIT) ;(SUCH AS # OF CHARS KEYED, ETC) ; ADD1 MOV A,M ;GET NUMBER (OR ' ') ORI '0' ;TURN ' ' INTO '0' INR A ;ADD 1 MOV M,A CPI '9'+1 RC ;RETURN IF 0-9 MVI M,'0' ;CARRY DCX H ;NEXT HIGHER DIGIT JMP ADD1 ; ;DECR ASCII COUNT FIELD (HL POINTS TO UNITS DIGIT) ;(USED FOR # OF ACTIVE MESSAGES UPON KILL) ; SUB1 MOV A,M ;GET NUMBER (OR ' ') ORI '0' ;TURN ' ' INTO '0' DCR A ;SUB 1 MOV M,A CPI '0'-1 ;TIME TO BORROW? RNZ ;RETURN IF 0-9 MVI M,'9' ;BORROW DCX H ;NEXT HIGHER DIGIT JMP SUB1 ; ;COUNT CHRACTERS IN FIELD ;(USED TO SEE THAT 1STNAME+LASTNAME < 21 CHRS ; COUNTC0 MVI B,0 ;INIT COUNT COUNTC MOV A,M CPI CR ;END? MOV A,B ;GET COUNT RZ INR B ;INCR COUNT INX H JMP COUNTC ; ;IDS AND PMMI CAN TAKE VARIABLE BAUD RATE, ;SO 'A' (ALTER BAUD RATE) IS USED TO SELECT ;IT AS DESIRED. INPUT IS A DECIMAL RATE. ; IF IDS OR PMMI ; ;A: ALTER BAUD RATE COMMAND ; ALTBAUD CALL GETVAR DB 'Baud rate: (65-600) ' DB '(C/R to leave as is)',0 DW ANSWER 02 DW 00 ;HELP MSG # DB 3 LDA ANSWER CPI CR JZ FUNCT ;NO ANSWER CALL GETNUM ;VALIDATE, CONV BINARY JC ALTBAUD ;INVALID, RE-ASK ; ;CALCULATE THE VALUE TO OUTPUT: ; ; RATE = 250000/16/BAUD RATE ; ; DIVIDE BY REPETITIVE SUBTRACTION ; ------ ;COMPLEMENT THE BAUD RATE ; MOV A,H ;GET HI CMA ;COMPLEMENT MOV D,A ;SAVE MOV A,L ;GET LO CMA ;COMPLEMENT MOV E,A ;SAVE INX D ;DE=2'S COMPLEMENT ;DIVIDE LXI H,15625 ;=250000/16 LXI B,-1 ;INIT QUOTIENT ; DIVLP INX B ;BUMP QUOTIENT DAD D ;'SUBTRACT' JC DIVLP ;LOOP 'TILL DONE ; ;VALIDATE THE RESULT ; MOV A,B ;CAN'T HAVE >255 ORA A JNZ BADRATE MOV A,C ;BAD IF >700 CPI 22 ;22 IS 700 BAUD JC BADRATE PUSH B ;SAVE VALUE (IN C) CALL ILPRT DB 'OK. Press any key ' DB 'to continue at that speed.' DB CR,LF,0 POP B ; ;JMP TO PMMI OR IDS ROUTINE TO SET RATE. ;BINARY VALUE TO OUTPUT IS IN C. ; JMP SETBAUD ; ;INVALID BAUD RATE ; BADRATE CALL ILPRT DB '++Invalid baud rate++',CR,LF,0 JMP FUNCT ENDIF ;PMMI OR IDS ; LINK CBBSSUB3 ;TO NEXT .ASM FILE