; CHAT.ASM v3.6 ; (revised: 05/28/84) ; NO: EQU 0 YES: EQU 0FFH ; CPM22: EQU YES ;must be yes for turbodos ; statn equ 2 ; which station to notify of chat request ; ; ; Conditional assembly switches ; BELTOG: EQU NO ;yes if BYE supports console bell toggle key CLOCK: EQU 4 ;set to your CPU clock spped in MHz MEASURE:EQU NO ;yes for "measuring stick" MPMPRL: EQU NO ;yes if MP/M program relocatable format NOISY: EQU NO ;yes for multus alertus (lotsa bells) ; CBBS: EQU no ;yes if CBBS system DATA: EQU NO ;yes if DataTech system METAL: EQU NO ;yes if METAL system MBBS: EQU NO ;yes if MBBS system MINCBBS:EQU NO ;yes if MINICBBS system ORACLE: EQU NO ;yes if Oracle system OXGATE: EQU NO ;yes if OxGate system RBBS: EQU yes ;yes if RBBS system SIGNON: EQU NO ;yes if Signon CPM: EQU NO ;if none of these being used ; ; IF BELTOG KILBEL: EQU 3BH ;if BELTOG EQU YES, set to KILBEL address ENDIF ; IMSAI: EQU NO ;yes if IMSAI front panel ; IF IMSAI SENSE: EQU 0FFH ;Front panel port address. SSOPAV: EQU 010H ;Bit to check for operator available ENDIF ; ;======================================================================= ; ; Pick either one or neither of the below, NOT both... ; ASKNAM: EQU NO ;yes if ask user's name before paging... GETCALR:EQU no ;yes to enable feature to get name from LASTCALR ; ; ; Define drive and user area if GETCALR is set to YES ; IF GETCALR LASTUSR:EQU 0 ;user area of LASTCALR LASTDRV:EQU 'A' ;Drive of LASTCALR file ENDIF ; ;======================================================================= ; ; Define ASCII characters used ; ABORT: EQU 'X'-40H ;CTL-X for ring abort BAKSP: EQU 08H ;backspace BELL: EQU 07H ;bell CR: EQU 0DH ;carriage return CTLC: EQU 03H ;CTL-C, chat-mode exit character DEL: EQU 7FH ;delete ESC: EQU 1BH ;escape character LF: EQU 0AH ;line feed ; ; ; Define line length & warning location ; ELINE: EQU 79 ;end of terminal line EWARN: EQU 74 ;place to start wrap ; ; ; Define operator acknowledge code ; ACK: EQU ESC ;respond to page by hitting an escape QUICK: EQU 'C' ;starts chat [jumps to chat loop] ; ; ; Define number of alert attempts ; IF NOISY ALERT: EQU 30 ;thirty if noisy ENDIF ; IF NOT NOISY ALERT: EQU 11 ;yell 11 times ENDIF ; ; ; Define DELAY loop value (the larger the value, shorter the delay...) ; IF NOISY DELAYV: EQU 64500 ;(1 second between bells) ENDIF ; IF NOT NOISY DELAYV: EQU 60000 ;few secs between bells ENDIF ; ; ; BDOS equates ; BASE: EQU 0 ;start of CP/M memory area BDOS: EQU 5 ;BDOS call address FCB: EQU 5CH ;CCP file control block DMAADR: EQU 80H ;Default DMA buffer address ; ; ; BDOS functions ; PRINT: EQU 9 ;print string function SELDSK: EQU 14 ;select disk FOPEN: EQU 15 ;file open FREAD: EQU 20 ;file read RTNDSK: EQU 25 ;return current disk SETDMA: EQU 26 ;set dma address SETUSR: EQU 32 ;get/set user number ; IF MPMPRL ORG BASE ENDIF ; IF NOT MPMPRL ORG BASE+100H ENDIF ; ;======================================================================= ; ; Program starts here ; ;======================================================================= ; START: LXI H,0 DAD SP ;get old stack pointer SHLD STACK ;save it LXI SP,STACK ;set new stack pointer ; ; ; Initialize jumps to CBIOS for direct I/O ; LHLD BASE+1 ;get pointer to CBIOS LXI D,3 ;ready for add DAD D ;HL = constat vector SHLD CSTAT+1 ;modify jump DAD D ;HL = CONIN vector SHLD CONIN+1 ;modify jump DAD D ;HL = CONOUT vector SHLD CONOUT+1 ;modify jump ; ; ; Check command parameters for help request ; LDA FCB+1 ;look at start of command line CPI QUICK ;if quick character requested then JZ CHAT ;sign on, and then jump to loop CPI ' ' ;no argument? JZ CHAT ;if no argument, then do normal chat ; ; ; Otherwise, help the poor confused fellow... ; CALL ILPRT DB CR,LF,'CHAT v3.6 - 05/28/84',CR,LF,CR,LF DB 'This will attempt to alert the operator. If he is ' DB 'not around',CR,LF,'you will be returned to CP/M. ' DB '(Use CTL-X to abort the alert ',CR,LF,'before then.) ' DB 'If the operator is available you will enter the ',CR,LF DB 'CHAT mode and will be able to type with him.',0 JMP EXIT ; ; ; Print signon message ; CHAT: CALL ILPRT DB CR,LF,'CHAT v3.6',0 ; mvi c,41 ;tdos function return user data mvi b,0 mvi h,91h call 50h lda 80h cpi 4 jc nohere IF BELTOG ;Console Bell Toggle Key? LDA KILBEL ORA A JNZ NOHERE ;if bell's off.. not here... ENDIF ;BELTOG ; IF IMSAI IN SENSE ;Have front panel, go check the switch ANI SSOPAV JZ NOHERE ;Not set, not here. ENDIF ;IMSAI ; LDA FCB+1 ;if it was quick mode, just sign-on CPI QUICK ;and drop right to the chat loop JNZ WHO CALL ILPRT ;turn up a new line DB CR,LF,0 JMP CRLF ;now go chat ; ; ;Get caller's name from LASTCALR, user or not at all ; WHO: IF CPM22 AND GETCALR MVI E,0FFH ;get current user # MVI C,SETUSR CALL BDOS STA CURUSR ;save current user MVI E,LASTUSR MVI C,SETUSR ;set user of LASTCALR CALL BDOS ENDIF ;CPM22 AND GETCALR ; IF GETCALR MVI C,RTNDSK ;get current disk CALL BDOS STA CURDSK MVI E,LASTDRV-'A' ;set drive of LASTCALR MVI C,SELDSK CALL BDOS LXI D,LFCB ;open LASTCALR MVI C,FOPEN CALL BDOS INR A ;Check if file not found (FFh) JZ UNDO ;if not found, don't complain, Zflag set LXI D,DMAADR MVI C,SETDMA ;make sure DMA is default addr CALL BDOS LXI D,LFCB MVI C,FREAD ;fill default buffer CALL BDOS ORI 0FFH ;Make sure the Zflag is clear ENDIF ;GETCALR ; ; ; If the file open was not successful, the Zflag is set. We still need ; to return to the current disk and user ; UNDO: IF GETCALR PUSH PSW ;Save it for for later ENDIF ;GETCALR ; IF CPM22 AND GETCALR LDA CURUSR ;restore current user MOV E,A MVI C,SETUSR CALL BDOS ENDIF ;CPM22 AND GETCALR ; IF GETCALR LDA CURDSK ;restore current disk MOV E,A MVI C,SELDSK CALL BDOS POP PSW ;Was the file open successful?... JZ CHAT1 ;..No, so skip the rest of this stuff ENDIF ;GETCALR ; IF GETCALR AND (NOT MBBS) LXI H,DMAADR ENDIF ;GETCALR AND (NOT MBBS) ; IF GETCALR AND MBBS LXI H,DMAADR+11 ENDIF ;GETCALR AND MBBS ; ; ; CLOOP is a bit more complex because of SIGNON*. The SIGNON* system ; places additional information into LASTCALR, which need not be ; presented to the caller. (* OxGate, too) ; IF GETCALR CALL ILPRT DB CR,LF,'Hold on, ',0 ; CLOOP: MOV A,M CPI CR JZ CLOOPE ;found end of file CPI ',' JNZ NOCO ; IF SIGNON OR OXGATE OR MBBS OR RBBS LDA SECND ORA A JNZ CLOOPE ;MBBS & OxGate need to stop at the 2nd ',' MVI A,1 STA SECND ENDIF ;MBBS OR OXGATE OR SIGNON ENDIF ;GETCALR ; IF GETCALR MVI A,' ' NOCO: PUSH H MOV C,A CALL CONOUT POP H INX H JMP CLOOP ; CLOOPE: CALL ILPRT DB '...',0 JMP CHAT1 ;done ; LFCB: DB 0 ENDIF ;GETCALR ; IF GETCALR AND (NOT MBBS) DB 'LASTCALR ' ;file containing name of last caller ENDIF ;GETCALR AND (NOT MBBS) ; IF GETCALR AND MBBS DB 'LASTCALRBBS' ENDIF ;GETCALR AND MBBS ; IF GETCALR DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 SECND: DB 0 CURDSK: DB 0 ENDIF ;GETCALR ; IF CPM22 AND GETCALR CURUSR: DB 0 ENDIF ;CPM22 AND GETCALR ; IF ASKNAM CALL ILPRT DB CR,LF,'Your name, please? (optional): ',0 ; GLOOP: CALL CONIN CPI CR JZ CHAT1 ;CR, end of name CPI BAKSP JZ BACK0 ;BS, erase previous char. CPI DEL JZ BACK0 ;DEL, erase previous char also.. CPI CTLC JZ EXIT ;CTL-C or CPI ABORT JZ EXIT ;CTL-X, abort CPI ' ' JC GLOOP ;CTL-character, ignore it MOV C,A CALL CONOUT ;else echo it.. LDA LCNT INR A ;increment line count (for BACK0) STA LCNT JMP GLOOP ;keep looping ; BACK0: CALL BACKIT ;do BS,SPACE,BS JMP GLOOP ENDIF ;ASKNAM ; CHAT1: lxi d,80h mvi c,26 call 5 lxi b,0fe29h lxi d,statn mvi h,91h call 50h lda 81h cpi 77h jnz NOHERE lxi d,100h-65 lxi h,chm lxi b,chm1-chm db 0edh,0b0h lxi b,0fe29h lxi d,2 mvi h,90h call 50h CALL ILPRT ;print: DB CR,LF,'Will page operator, use CTL-X to abort.' IF MEASURE DB CR,LF,'|-------------------|',CR,LF,0 CALL START1 ENDIF ;MEASURE ; DB CR,LF,'Ringing . ',0 ; ; ; Attempt to alert operator ; START1: CALL ILPRT ;print bell, period, space DB '.',0 CALL DELAY ;wait... LDA CNT ;get attempt counter DCR A ;done with alert attempts? STA CNT ;save new count JNZ START1 ;not done with attempts, do more ; ; ; Operator did not answer ; NOHERE: CALL ILPRT ;print: DB CR,LF,CR,LF,'Sorry, operator is not available - ' ; IF CPM DB 'back to CP/M...',0 ENDIF ;CPM ; IF NOT CPM DB 'please leave your message',CR,LF,'in the ' ENDIF ; IF CBBS DB 'CBBS' ENDIF ; IF DATA DB 'DataTech' ENDIF ; IF METAL DB 'METAL' ENDIF ; IF MINCBBS DB 'MINICBBS' ENDIF ; IF ORACLE DB 'Oracle' ENDIF ; IF OXGATE DB 'CBBS (R)' ENDIF ; IF RBBS DB 'RBBS' ENDIF ; IF SIGNON DB 'comments section when exiting the system...',0 ENDIF ; IF MBBS DB 'MBBS' ENDIF ; IF NOT CPM DB ' message system...' ENDIF ; db esc,'9',0 ; JMP EXIT ;exit to CP/M ; ; ;======================================================================= ; ; Routines start here ; ;======================================================================= ; ; Backspaces one column, first erasing the current character ; BACKIT: LDA LCNT ;get character count DCR A ;subtract one because of backspace RM ;dont go past zero STA LCNT ;save new count CALL ILPRT ;print DB BAKSP,' ',BAKSP,0 RET ;continue looping ;..... ; ; ; Conversation routine - uses direct CBIOS I/O to prevent control char- ; acters from being echoed. ; CONT: CALL CONIN ;get console input with no echo CPI ABORT ;CTL-X? JZ EXIT ;yes, exit to CP/M CPI CTLC ;CTL-C? JZ EXIT ;yes, exit to CP/M CPI CR ;carriage return? JZ CRLF ;yes, send CRLF CPI BAKSP ;backspace? JZ BACK1 ;yes, do backspace space backspace CPI DEL ;delete? JZ BACK1 ;yes, treat like backspace CPI ' ' ;space or above? if not, JC CONT ;it's a CTL-character, continue looping MOV C,A ;else, save char in C (also for CBIOS) LDA LCNT ;check count CPI EWARN ;near end of line limit? JC CHROK ;no, char ok... MOV A,C ;get character CPI ' ' ;space? JZ CRLF ;yes, then word wrap LDA LCNT ;no, check line count agin.. CPI ELINE ;at end of line? JNZ CHROK ;not at end of line, char ok MVI C,BELL ;else, CALL CONOUT ;ignore char, beep.. JMP CONT ;and continue ; CHROK: CALL CONOUT ;send character to console LDA LCNT ;get character count INR A ;increment counter STA LCNT ;save new count JMP CONT ;continue looping ; CRLF: CALL ILPRT ;print: DB CR,LF,0 XRA A ;zero character counter STA LCNT JMP CONT ;continue looping ; BACK1: CALL BACKIT ;BS, space, BS JMP CONT ;continue looping ;..... ; ; ; CBIOS routines for console status, get character and show character ; CSTAT: JMP $-$ ;modified at init ; CONIN: JMP $-$ ;modified at init ; CONOUT: JMP $-$ ;modified at init ; CNT: DB ALERT ;alert counter LCNT: DB 0 ;line position counter ; ; ; Delay routine to wait between beeps ; DELAY: MVI B,CLOCK ; DELAY1: LXI H,DELAYV LXI D,1 ; DELAY2: PUSH H ;save the values, consume some time PUSH D PUSH B CALL CSTAT ;get console status ORA A ;char ready? JNZ DELAY4 ;let's check it out... ; DELAY3: POP B ;restore the values POP D POP H DAD D JNC DELAY2 DCR B JNZ DELAY1 RET ;finished this time ; DELAY4: CALL CONIN ;get character CPI ABORT ;user has cold feet? JZ EXIT ;yes? then go back to CP/M CPI CTLC ;used to using CTL-C to quit? JZ EXIT ;ok, then back to CP/M CPI ACK ;was it the right answer? JNZ DELAY3 ;if not, keep timing ; ; ; Operator is present ; LXI SP,STACK ;fix stack CALL ILPRT ;print: DB CR,LF,CR,LF DB 'Operator is available, please go ahead...',CR,LF DB '(Use CTL-X to exit and return to CP/M)',CR,LF DB CR,LF,0 JMP CRLF ;now in chat mode ; EXIT: CALL ILPRT DB CR,LF,0 ; EXIT1: jmp 0 ;..... ; ; ; Inline print routine ; ILPRT: XTHL ;save HL, generate message ; ILPLP: MOV C,M ;get character PUSH H CALL CONOUT ;output it POP H INX H ;point to next character MOV A,M ;test ORA A ;...for end JNZ ILPLP XTHL ;restore HL, return address RET ;return past message string ;..... ; chm: db 0ffh,cr,lf,lf db '<<>>',cr,lf,lf,'$' chm1 equ $ ; end of routines ;======================================================================= ; DS 64 ;room for 32 level stack STACK: DS 2 ;old CP/M (or MP/M) stack saved here ; IF MPMPRL DB 0 ;force allocation of storage space ENDIF ; END START