; HBBS.Z80 v1 17 Apr 88 ; ; This is the signon/message part of the HBBS (RCPM) program. ; ; By Irv Hoff, based on Russ Pencin's PBBS, based on Simon Ewin's EMX. ; ;----------------------------------------------------------------------- ; ASEG ; Needed by M80 - else ignore any error .Z80 ORG 0100H ; JP START ; VER: DEFB 1 ; Version ; INCLUDE HBBSHDR.INC ; Options and header file INCLUDE HBBSUBS.INC ; Subroutine file INCLUDE HDOSHDR.INC ; Clock read routine ; VMSG: DEFB CR,LF,'HBBS v',0 ; ;----------------------------------------------------------------------- ; Start of program ;----------------------------------------------------------------------- ; START: LD HL,0 ; Set up local stack ADD HL,SP LD (CCPSTK),HL ; Saving old one LD SP,STACK ; LD DE,241 LD C,SETUSR CALL SPBDOS AND A CP 77 JR Z,CONTINUE CALL PRINT DEFB 'BYE5 NOT PRESENT...PLEASE USE THE "E" ' DEFB 'OPTION TO TEST HBBS.',CR,LF,0 LD HL,(CCPSTK) LD SP,HL RET ;.... ; CONTINUE: LD A,0CDH LD (0),A ; Disable ^C for BYE5 ; ; Call to GETTIM does nothing at this time... it is here so that the user ; may use GETTIM to perform custom routines and any patching that is re- ; quired by his specific system ; CALL GETTIM ; Run of subroutine to get logon time CALL ENDBBS ; Returns hl-> last byte of file LD A,0FFH ; Flag byte for message routines LD (HL),A INC HL ; This is start of the message storage buffer LD (MSG),HL ; The next defines the message space for use ; When entering a message LD DE,MSGBUF+128 ; Messages must be multiples of 64 then... ADD HL,DE ; This become the start of general buffer XOR A LD (HL),A INC HL LD (MSGARR),HL ; LD A,SYSDRV ; Log into where the system files are LD E,A LD C,SELDSK CALL SPBDOS LD A,SYSUSR LD E,A LD C,SETUSR CALL SPBDOS ; ; Get index info from disk and store it im memory for later ; CALLER: CALL IOPEN CALL GET ; Get record CALL CLOSE ; Close file LD HL,IDATEF ; Move from buffer LD DE,IDATE ; To storage LD BC,NDXLEN ; This many bytes LDIR ; Move record ; ; Clear some flags to insure proper state. ; XOR A LD (NUSR),A ; Clear new user flag LD A,TRIES ; Set number of tries for getnme INC A LD (TRIED),A ; To maximum allowed ; ; Check if we are to get caller's info or go to the mail section. Mail ; is entered by simply loading signon and checking the REENTR byte, ; therefore BYE must reset REENTR to 0 when the caller leaves. (Or a ; 'shadow' file called BYE that updates and then runs the real BYE.) ; LD A,(REENTR) ; See if signed on already OR A ; 1=yes, 0=no (0 set by exit prog at reentr:) JR Z,SETSTATE ; Nope, so set the state of the prog. for logon LD A,1 ; Set ALTERNATE file flag LD (NOFILE),A ; Now run mail JP HBBS ;..... ; ; Clear some flags to insure proper state. ; SETSTATE: XOR A LD (UPLOADS),A ; Clear uploads LD (DNLOADS),A ; Downloads LD (WHEEL),A ; Sysop byte ; IF TCAP AND Z3SET PUSH HL LD HL,(ZWHL) LD (HL),A POP HL ENDIF ; TCAP AND Z3SET ; LD (TWIT),A ; Used in phone # check LD (MORFLG),A ; 0 = [more] pause okay LD A,'2' LD (ASCACC),A ; Set ASCII access to level 2 ; ; Check for whether hard-copy wanted (function handled by bye) ; LD A,(HRDLOG) ; See if hard-copy wanted (in index file) LD E,A LD C,RMHDR ; BYE5 hard copy call CALL SPBDOS ; 1=yes, 0=no (store in bye) ; ; Get today's date and place it in INDEX area (used next time to show ; last time the user checked in). ; CALL GETTIM ; Get date and time from BYE LD HL,TIME LD DE,LOGSTR LD BC,8 LDIR LD IY,BDATE ; Get clock date LD IX,IDATE ; Get last known date CALL DATDIF ; Check for clock accuracy LD A,H ; H has the flags OR A JP NC,MVDATE ; All's well.. LD A,1 LD (BADCLK),A ; Bad news.. the clock's screwy JR WELC ; Keep the old date in index ;..... ; MVDATE: LD IX,BDATE ; Point to binary date LD IY,IDATE ; And date storage area LD A,(IX) ; Get month LD (IY),A ; Store it LD A,(IX+1) ; Get day LD (IY+1),A ; Store it LD A,(IX+2) ; Get year LD (IY+2),A ; Store it ; ; Welcome wanted (and present) so type it. This type routine does not ; use the random file buffer(s),. rather it has its own sequential read ; routine and uses the default TBUFF at 80h. ; WELC EQU $ ; IF WELON LD A,23 ; Set to full screen temporarily LD (TYPELN),A LD HL,WELCOM CALL OPEN CP 0FFH JR Z,WELC1 ; No such file, exit CALL TYPE0 ; Display the text file ; WELC1: LD A,20 ; Back to normal LD (TYPELN),A ENDIF ; WELON ; ; Get caller's name. Name must be in form: first last. Initials are ; not permitted. There is a check done for extra spaces or any other ; nonsense that makes it more difficult to deal with later. ; GETNME: CALL PCRLF ; Turn up a line LD A,(TRIED) ; Get attempts DEC A ; Less one JP Z,PASOUT ; Too many attempts LD (TRIED),A ; Still some left so store new value LD B,NAMLEN-1 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'Your first and last name',CR,0 LD B,NAMLEN-1 ; Input length (insure 1 null) LD C,20H ; Force caps (C=0 for no caps) XOR A ; Echo on LD (COUNT+1),A ; Clear MSB of character count LD D,A ; No word-wrap ; GETNME1:CALL INPUT OR A JR Z,GETNME1 CP 3 JR C,GETNME1 LD (COUNT),A ; ; The following section allows the Sysop to sign on as "Sysop". It then ; goes to the HBBSHDR.Z80 file and finds his name under the SYSOP label ; and uses that name as though he had typed it in the first place. It ; still requires his normal password. If however you feel this weakens ; the security, go back to HBBSHDR.Z80 and select SYSOK to NO. ; IF SYSOK PUSH HL ; See if it's the Sysop LD B,5 LD DE,SYSSTR CALL MATCH OR A JR NZ,ZSYS3 ; No, continue LD B,0 ; Setup character counter LD DE,SYSOP ; Point at Sysop's name ; ZSYS1: LD A,(DE) OR A JR Z,ZSYS2 ; Until first null INC B INC DE JR ZSYS1 ; Keep counting characters in name ; ZSYS2: LD A,B LD (COUNT),A ; Save character count POP DE ; Get buffer address in DE PUSH DE LD HL,SYSOP ; And Sysop's name address LD BC,NAMLEN LDIR ; And move it ; ZSYS3: POP HL ; Restore buffer pointer ENDIF ; SYSOK ; LD C,0 ; Assume one character ; LOOP: LD A,(HL) ; Get character OR A JP Z,NMERR CP ' ' JR Z,GOTSEP CP '.' JR Z,LOOP1 ; Allow a period in first name only CP 027H ; It's a "'" for O'BRIAN JR Z,LOOP1 ; Let it by CP '-' ; For Mary JONES-SMITH JR Z,LOOP1 ; It's her fault she's a feminist... CP 'A' JP C,NMERR ; Must be between A & Z CP 'Z'+1 JP NC,NMERR INC C ; Bump character count ; LOOP1: INC HL JR LOOP ;..... ; GOTSEP: LD A,C ; A=count CP 2 ; Ensure at least two char before delimiter JP C,NMERR LD A,',' LD (HL),A ; Make seperater a comma LD (SPACE),HL ; Save address for later INC HL ; Reset pointer to character after delimiter ; FNDREC: LD A,(HL) ; Get first character of last name CP 'A' ; The first character of last name must JR C,NMERR ; be an alpha character CP 'Z'+1 JR NC,NMERR PUSH HL CALL HASH ; Calc starting position in USERS.BBS LD (HSHREC),HL ; Set the hashed record number POP HL LD C,0 ; Set counter ; LOOP2: LD A,(HL) ; Loop again for second name OR A JR Z,GOTEND CP '.' ; For St. Amant JR Z,LOOP3 CP 027H ; It's a "'" for O'Brian JR Z,LOOP3 ; Let it by CP '-' ; For Mary Jones-Smith JR Z,LOOP3 ; It's her fault she's a feminist... CP 'A' ; Otherwise it better be a alpha character JR C,NMERR CP 'Z'+1 JR NC,NMERR INC C ; Bump count ; LOOP3: INC HL JR LOOP2 ; GOTEND: LD A,C ; Get delimiter position CP 2 ; Last name needs more than 1 character JR C,NMERR ; Name entered incorrectly ; ; Got a valid name (first and last) so store it with a ',' instead of ; the space in the LASTCALR file buffer. ; LD C,RMLCBF CALL SPBDOS ; Get BYE's last caller buffer pointer EX DE,HL ; Make it the destination LD BC,(COUNT) LD HL,INBUF LDIR ; Move name to last caller buffer LD A,CR LD (DE),A INC DE LD A,LF LD (DE),A ; CRLF at end of user's name INC DE XOR A ; Null for BYE print message LD (DE),A INC DE LD A,1AH ; End-of-file marker LD (DE),A LD HL,(SPACE) ; Get delimiter position in buffer LD A,' ' LD (HL),A ; Make it a space LD HL,INBUF LD DE,UNAME LD BC,NAMLEN ; Move name to storage LDIR JR SEEK ; Now we see if we can find caller in file ;..... ; ; If neither space nor ; found then probably didn't enter two names ; or entered initial, period or non-ASCII (A-Z) character ; NMERR: CALL PRINT DEFB CR,LF,CR,LF,'First and last names required.',CR,LF DEFB 'No numbers, initials or middle name.',CR,LF,0 JP GETNME ;..... ; ; Open USERS file for search, initialize arguments ; SEEK: LD HL,-1 LD (TMPREC),HL ; Flag the possible deleted entry LD HL,WAITMSG CALL PRINTM CALL UOPEN ; Open USERS file LD HL,(HSHREC) ; Start with hashed record ; ; Loop to read users file and attempt match ; RDUSRS: CALL GET LD B,NAMLEN LD HL,UNAMEF ; Compare the user name to file record LD DE,INBUF CALL MATCH OR A JR Z,FNDUSR ; Match so process LD A,(AVAILF) OR A ; Free record? JP Z,NUOK ; (we've got room, so let him in) AND A ; Clear carry flag LD HL,(TMPREC) ; See if we've already found a deleted record LD DE,-1 SBC HL,DE JR NZ,NXTREC ; Yup, so just keep scanning LD HL,(RRNO) ; Nope, save this one in case we don't find him LD (TMPREC),HL ; NXTREC: XOR A ; Clear the carry flag LD HL,(RRNO) INC HL EX DE,HL LD HL,(HSHREC) SBC HL,DE JP Z,NOSPC ; So there's no match, so see if we have room LD HL,MAXU-1 XOR A SBC HL,DE EX DE,HL JR NC,RDUSRS LD HL,0 ; Load up first record in file JR RDUSRS ; No, keep going ;..... ; ; Found user so process info ; FNDUSR: LD A,(ACESSF) CP 1 ; Banned? JP Z,BAN ; (if user deleted this is caught later) LD HL,(RRNO) LD (TMPREC),HL ; Set record number JP PASS ;..... ; ; User access=1 means banned from access so dump ; BAN: LD HL,CLRWTMSG CALL PRINTM LD HL,TWITMSG CALL PRINTM LD IY,TWITIN ; Point to twit log message. JP LOGOUT ; Log him out but record his try. ;..... ; ; User entered an invalid phone number...let the system know ; TWITY: LD A,1 LD (TWIT),A RET ;..... ; ; Couldn't find name in file, and there are no free entries. Make sure ; he spelled it right, if so, then dump him. ; NOSPC: XOR A ; Clear the carry flag LD HL,(TMPREC) ; See if we had a deleted record to fill LD DE,-1 SBC HL,DE JR Z,NOSPC1 ; Nope check if new user, dump if he is. LD HL,(TMPREC) LD (RRNO),HL JP NUOK ;... ; NOSPC1: CALL CLOSE LD HL,NONME ; No, see if spelled okay CALL PRINTM ; Ask question ; TYPOW: CALL YESNO JP Z,GETNME CP 1 JR NZ,TYPOW ; ; On the first loss of carrier after midnight the users file will be ; purged, thus freeing up new user space. ; FULL: CALL PRINT DEFB CR,LF,'Sorry, Users file is FULL. ' DEFB 'Try again tomorrow.',0 JP 0000H ; <== LET BYE HANDLE IT ;..... ; NONME: DEFB CR,' ',CR,LF DEFB 'Are you a New User? ',0 ; ; Space available, so get his information for storage. ; NUOK: LD HL,(RRNO) LD (TMPREC),HL ; Set record number, saved from scan LD HL,NONME CALL PRINTM ; TYPOW1: CALL YESNO JP Z,GETNME CP 1 JR NZ,TYPOW1 ; NERD EQU $ ; IF PRVATE LD A,PLOGUSR ; Are we allowing them to register OR A JR NZ,CS ; Yup, we'll catch 'em later ENDIF ; PRVATE ; PREXIT EQU $ ; IF PRVTXT AND PRVATE LD HL,PRVTFIL ; Get the text file explaining CALL TYPE JP 0 ; <== LET BYE HANDLE IT ENDIF ; IF (NOT PRVTXT) AND PRVATE LD DE,PRVTCM ; Load the exit file JP CPM ENDIF ; NOT PRVTXT AND PRVATE ; ; Find where caller is from (new users) ; CS: CALL PCRLF LD B,19 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'City, State (2 chars.)',CR,0 CALL EATCHR LD B,19 ; Input length (insure 1 null) LD C,20H ; Force caps (C=0 for no caps) XOR A ; Echo on LD D,A ; No word-wrap ; CS1: CALL INPUT ; Get location OR A JP Z,CS1 LD HL,INBUF LD A,(HL) ; Can't start with a space CP ' ' JP Z,CS+3 ; If a space, ask again LD DE,CITST LD BC,19 LDIR ; And save in memory ; PHN: LD A,TRIES ; Get tries allowed INC A LD (TRIED),A ; Set countdown ; PHN1: LD A,(TRIED) DEC A JP Z,PASOUT ; Too many tries LD (TRIED),A CALL PCRLF1 ; Turn up two lines ; PHN2: CALL PRINT DEFB CR,'___-___-____<< Your home voice phone ' DEFB 'number, will remain confidential',CR,0 LD B,8 ; Length LD HL,PHONE ; GET8: PUSH BC CALL GETCH ; Get input POP BC CP BS ; Reprint phone line for new entry JR NZ,GET8A JR PHN2 ;..... ; PDASH: LD (HL),'-' ; Automatically insert the dash INC HL DEC B PUSH HL PUSH BC CALL PRINT DEFB '-',0 POP BC POP HL RET ;..... ; GET8A: CALL ECHO LD (HL),A INC HL LD A,B CP 6 CALL Z,PDASH CP 2 CALL Z,PDASH ; GET8B: DJNZ GET8 LD B,4 ; GET4: PUSH BC CALL GETCH ; Get input POP BC CP BS JP Z,PHN2 CALL ECHO LD (HL),A INC HL DJNZ GET4 LD HL,PHONE LD C,1 ; Assume one character LD B,11 ; Length-1 for decrement ; LP01: LD A,(HL) ; Get character CP '-' JR Z,GOT3 CP '0' JP C,DASH ; Must be between 0 & 9 CP '9'+1 JP NC,DASH INC HL INC C ; Bump character count DJNZ LP01 JR GOTCR ;..... ; GOT3: LD A,C CP 4 JP Z,GOT3A CP 8 JP NZ,DASH ; Dash in wrong place ; GOT3A: INC HL ; Set pointer to character after delimiter INC C ; Bump count DJNZ LP01 ;..... ; CHCKCR: DEFB '000-000-0000' CHCKC1: DEFB '012-345-6789' CHCKC2: DEFB '123-456-7890' ;..... ; ; Check for all zero (000-000) entry... ; GOTCR: LD HL,PHONE LD DE,CHCKC1 LD B,12 CALL MATCH OR A CALL Z,TWITY ; Let him finish ,but set him to twit LD HL,PHONE LD DE,CHCKC2 LD B,12 CALL MATCH OR A CALL Z,TWITY LD HL,PHONE ; Input from caller LD DE,CHCKCR ; Hope it is not this LD B,12 ; Number of characters to check CALL MATCH ; Check it for zero's OR A ; If zero then CALL Z,TWITY ; Let him finish ,but set him to twit LD HL,PHONE ; Input from caller LD DE,CHCKCR ; Hope it is not this LD B,3 ; Number of characters to check CALL MATCH ; Check it for zero's OR A ; If zero then CALL Z,TWITY ; Let him finish ,but set him to twit LD HL,PHONE+4 ; Input from caller LD DE,CHCKCR ; Hope it is not this LD B,3 ; Number of characters to check CALL MATCH ; Check it for zero's OR A ; If zero then CALL Z,TWITY ; Let him finish ,but set him to twit LD DE,CHK555 ; Hope it is not this LD B,3 ; Number of characters to check CALL MATCH ; Check it for 555 OR A ; If zero then CALL Z,TWITY ; Let him finish ,but set him to twit LD HL,PHONE+4 ; Input from caller LD DE,CHK800 ; Hope it is not this LD B,3 ; Number of characters to check CALL MATCH ; Check it for 800 OR A ; If zero then CALL Z,TWITY ; Let him finish ,but set him to twit ; PHNRET: NOP ; Self-modified to return to caller CALL PRINT DEFB CR,LF,CR,LF DEFB 'Name: ',0 LD B,NAMLEN LD HL,UNAME CALL PRINTN CALL PRINT DEFB CR,LF DEFB 'From: ',0 LD B,20 LD HL,CITST CALL PRINTN CALL PRINT DEFB ' ',CR,LF DEFB 'Phn # ',0 LD HL,PHONE LD B,12 CALL PRINTL CALL PRINT DEFB CR,LF,CR,LF DEFB 'Is this correct? ',0 ; WAIT: CALL YESNO JP Z,GETNME CP 1 JP Z,NULLQ JR WAIT ;..... ; DASH: CALL PRINT DEFB CR,LF,CR,LF,'Please use numbers only',0 JP PHN1 ;..... ; PSL6: CALL PRINT DEFB CR,LF,CR,LF,'Must be at least 4 characters',0 JP PS ;..... ; NULLQ: CALL NULLQ1 JP DUSET0 ;..... ; NULLQ1: CALL PRINT DEFB CR,LF DEFB 'Delays (nulls) at start of line (0-9)? ',0 ; NULLQ2: CALL GETCH CP '0' JR C,NULLQ2 ; If less, wait for number CP '9'+1 JR NC,NULLQ2 ; If not 0-9, wait until it is CALL ECHO SUB '0' ; Change to binary LD (NNULL),A ; Store in his parameter block LD E,A LD C,RMNULL JP SPBDOS ; Enter into BYE, then return ;..... ; DUSET0: LD A,(TRIES) INC A LD (TRIED),A ; DUSET: LD A,(ACESS) ; If level 2 don't ask CP 3 JP C,DUSET4 ; If less, exit LD A,CPMDU SUB 'A' ; Convert ASCII drive to binary LD (INTAR),A ; Sets CP/M drive/user area for uploads ; IF MSDOS DUSET1: LD A,(DUSET4) OR A JR NZ,DUSET2 LD HL,CLRWTMSG CALL PRINTM CALL PCRLF1 ; DUSET2: CALL PRINT DEFB CR,'Are you primarily: 1) CP/M or 2) MS-DOS? ',0 ; DUSET3: CALL PRINT DEFB BS,' ',BS,0 ; DUSETA: CALL GETCH ; Get the answer CP CR JR Z,DUSET2 JR C,DUSETA CALL ECHO CP '1' ; ASCII '1' for CP/M? JR Z,DUSETB ; If yes, exit, already set CP '2' ; ASCII '2' for MS-DOS? JR NZ,DUSET3 ; If more, ask again LD A,IBMDRV ; Load in MS-DOS d/u (often G0:) SUB 'A' ; Convert ASCII drive to binary LD (INTAR),A ; Goes to user 0 after signing on ; DUSETB: LD HL,WAITMSG CALL PRINTM ENDIF ; MSDOS ; DUSET4: NOP ; Can be filled in with a "RETURN" ; ; Asks the user what terminal line length he prefers ; CHGLIN: LD A,(LENG) OR A JP NZ,CHGLIN5 CALL PRINT DEFB CR,LF,CR,LF DEFB 'Select preferred screen width',CR,LF DEFB '10-7' ; IF LINNOS DEFB '4' ENDIF ; LINNOS ; IF NOT LINNOS DEFB '8' ENDIF ; NOT LINNOS ; DEFB ' columns, 72 suggested',CR,LF DEFB '(May be changed later with ''S'' option)',CR,LF,CR,LF DEFB '__<<==',CR,0 ; CHGLIN1:LD B,2 XOR A LD C,A LD D,A ; CHGLIN2:CALL INPUT OR A JP Z,CHGLIN2 LD (CNVRT0+1),A ; Set number characters to convert PUSH HL POP IX ; Pointer to ix CALL CNVRT0 ; Make string binary number LD A,L ; Get the converted value CP 10 ; Insist on at least 10 JR NC,CHGLIN3 LD A,10 ; CHGLIN3 EQU $ ; IF LINNOS CP 74+1 ; See if less than maximum JR C,CHGLIN4 ; If yes, handle normally; LD A,74 ; Maximum CRT width with line numbers ENDIF ; LINNOS ; IF NOT LINNOS CP 78+1 ; See if less than maximum JR C,CHGLIN4 ; If yes, handle normally; LD A,78 ; Maximum CRT width without line numbers ENDIF ; NOT LINNOS ; CHGLIN4:LD (LENG),A LD (LENGF),A CALL SETLIN CALL PCRLF ; CHGLIN5:NOP LD A,TRIES INC A LD (TRIED),A ; ; Allow selection of password ; PS: CALL PCRLF LD A,(TRIED) DEC A LD (TRIED),A JP Z,PASOUT LD B,10 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'Select a password (4-10 chars.)',CR,0 LD B,10 ; Length LD C,20H ; Caps XOR A ; Echo on LD D,A ; No word-wrap CALL INPUT ; Get password CP 4 JP C,PSL6 ; Must be 4 characters long minimum LD B,A ; PSCHK: LD A,(HL) ; Make sure password is all alpha chars. CP '0' ; If not alpha or numeric, ask again JP C,PS ; If not alpha, ask again INC HL ; Next position DEC B ; One fewer to check JR NZ,PSCHK ; If not finished, keep checking LD HL,INBUF ; So store the password, then LD DE,PSWRD LD BC,10 LDIR CALL PRINT DEFB CR,LF,CR,LF,'Please remember it',CR,LF,0 ; ; Set values for new user into place ; LD HL,0 LD (TMSON),HL ; Set times on to 0 LD (DNLDS),HL ; Clear number downloads LD (UPLDS),HL ; Clear number uploads LD A,1 ; Gets bumped to 2 before saving LD (ACESS),A ; Set access to new user ; (access=0=deleted) ; (access=1=banned) LD (NUSR),A ; Flag new user so we bump access by 1 ; and run special new user file LD (AVAIL),A ; Show this record used LD (XPRT),A ; Flag new user so he gets menu XOR A LD (MFLAG),A ; Clear mail waiting flag LD (MFTMP),A ; Clear mail waiting counter LD (TCODE),A ; No terminal defined yet (dumb assumed) LD (TOTME),A ; Set 0 time used today so far LD HL,(IUSER) INC HL ; Since new user, bump count and... LD (IUSER),HL ; Save bumped # users CALL UOPEN ; Open users file ; IF TCAP HTCAP: CALL HTCAP1 JR HTCAP2 ; HTCAP1: CALL PRINT DEFB CR,LF DEFB 'Please select a Terminal from the following list' DEFB CR,LF,0 XOR A ; Displays and asks for a selection CALL TCSET LD (TCODE),A ; Store the terminal type LD (TRMCD),A ; And store in low memory RET ENDIF ; TCAP ;..... ; HTCAP2: LD HL,(IUSRC) ; Get start record number LD HL,WAITMSG CALL PRINTM CALL UOPEN ; Open file LD HL,(IUSRC) ; Get start record number ; ; Got free space so set this guy into old deleted user's space. ; FNDFRE: JP UPDATE ; Update index and user files ;..... ; GMORN: DEFB 'Good morning, ',0 GAFT: DEFB 'Good afternoon, ',0 GEVE: DEFB 'Good evening, ',0 ; MONTH: DEFB 'Jan' DEFB 'Feb' DEFB 'Mar' DEFB 'Apr' DEFB 'May' DEFB 'Jun' DEFB 'Jul' DEFB 'Aug' DEFB 'Sep' DEFB 'Oct' DEFB 'Nov' DEFB 'Dec' ; ; If existing user we end up here to get password (3 tries) ; PASS: LD A,(ACESSF) ; Found name but check if this OR A ; Guy has been deleted once first JP NZ,PASS1 LD A,1 ; Be nice and let him back in, gets LD (ACESSF),A ; bumped later LD (NUSR),A ; But make him a new user ; PASS1: LD A,TRIES ; Get tries allowed INC A LD (TRIED),A ; Set countdown LD HL,CLRWTMSG CALL PRINTM CALL PCRLF ; ; Now get the password ; PS1: CALL PRINT DEFB CR,' ',CR,0 LD IY,BREAKIN ; Point to the message LD A,(TRIED) DEC A JP Z,LOGOUT ; Too many tries LD (TRIED),A LD B,10 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'Password',CR,0 ; PS2: LD B,10 ; Length LD C,20H ; Caps XOR A ; Set echo off LD D,A ; No word-wrap CALL SPINP OR A JR Z,PS2 LD A,(COUNT) LD DE,PSWRDF ; Match to password on file LD B,10 CALL MATCH OR A JP NZ,PASERR CALL PRINT DEFB CR,' ' DEFB CR,'Please wait...',0 CALL UMOV ; Move user info to memory ; ; Now check for phone number in user profile and ask for number. If area ; code is 000, this will occur because of conversion from MBBS or RBBS ; where phone numbers are not used. ; LD HL,PHONE LD DE,CHCKCR LD B,3 CALL MATCH JR NZ,SETDRV LD A,0C9H ; Make PHN: a subroutine LD (PHNRET),A CALL PHN ; ; Checks to see if drive/user is default A0: if yes, puts a "RET" in ; SETDRU: routine, jumps there to set the drive/user. While there, also ; checks to see if a special area for MS-DOS, if yes, then asks for the ; user's preference and stores that in the "INTAR" location. Once this ; has been requested, doesn't need to ever ask again. ; SETDRV EQU $ ; IF MSDOS LD A,(INTAR) ; Present drive/user default A0: ? OR A JR NZ,SETLEN ; If not, already set, exit LD A,0C9H ; Make DUSET: a subroutine LD (DUSET4),A CALL DUSET ; Set requested entry drive/user area ENDIF ; MSDOS ; ; Valid user (new or existing) so update all elements of files ; SETLEN: LD A,(LENG) OR A JR NZ,UPDATE LD A,0C9H LD (CHGLIN5),A CALL CHGLIN ; UPDATE: LD A,(BADCLK) ; SEE IF WE HAVE A BAD CLOCK OR A JP NZ,NOCLK ; YUP..DON'T CHANGE USER DATE LD IX,LASTON LD IY,IDATE ; See if same day as last day on-line CALL DATDIF ; And if not then 0 out total time today LD A,H ; See if same day (0 difference) OR L JR Z,NOREST ; No time-total reset ; NOCLK: XOR A LD (TOTME),A ; Reset byte to 0 for a new day ; ; Now we have to run through code to check for auto-bump... ; ; Code to bump user access level if today is not the same as last day ; on. Bumps a 2 to the value of BUMPHI; levels above BUMPHI must be ; set by operator using maintenance routines. May not bump if NOBUMP ; flag is set. ; NOREST EQU $ ; IF DOBUMP LD A,(ACESS) CP 2 JR C,NEWU ; If access < 2 then check for new user CP BUMPHI JR NC,BMPDON ; If access > bumphi then no auto-bump ; ; Potential is here for a bump ; LD IY,IDATE ; Today's date LD IX,LASTON ; Get last date on here CALL DATDIF ; See if this is same day as last call LD A,H OR L ; 0? JR Z,BMPDON ; Same day so skip next JR BLEV ; Go bump the level ENDIF ; DOBUMP ; NEWU: LD A,(NUSR) ; If new user still bump to 2 CP 1 JR NZ,BMPDON ; TWITS stay twits (ain't it true!) ; BLEV: LD A,(ACESS) ; Get access level INC A ; Bump 2-> BUMPHI LD (ACESS),A ; Save new level CP 2 ; Level 3 now? JR NZ,MP3 ; Yes, set usr/drv maps for 3 LD DE,USMP2 ; HBBS doesn't use these, but you might LD HL,DRMP2 JR SETMAP ; MP3: LD DE,USMP3 LD HL,DRMP3 ; SETMAP: PUSH DE POP IX ; Userarea pointer in ix LD IY,USRMP LD A,(IX) LD (IY),A LD A,(IX+1) LD (IY+1),A ; Move map to user area PUSH HL POP IX ; Drive pointer to ix LD IY,DRVMP LD A,(IX) LD (IY),A LD A,(IX+1) LD (IY+1),A ; To user area ; BMPDON: LD A,1 ; Set flag, indicate signed-on LD (REENTR),A ; LD IX,USRMP ; Point to user map in user record LD IY,USRMAP ; Address in hi mem LD A,(IX) LD (IY),A LD A,(IX+1) LD (IY+1),A ; LD IX,DRVMP ; Drive map in user record LD IY,DRVMAP ; And address to store at LD A,(IX) LD (IY),A LD A,(IX+1) LD (IY+1),A ; ; Now update the rest of the info before we write the record ; LD HL,(TMSON) INC HL LD (TMSON),HL ; Bump times on LD HL,(TMPREC) ; Get user record number LD (USREC),HL ; And move it to 'permanent' storage LD A,(MSPEED) ; Read baudrate this time on and LD (BDCDE),A ; Store it in user record LD A,(NNULL) ; Read number nulls needed LD E,A LD C,RMNULL CALL SPBDOS ; Tell BYE about it ; IF TCAP LD A,(TCODE) ; Get terminal code LD (TRMCD),A ; And store in low memory ENDIF ; TCAP ; CALL USTORE ; Move into buffer LD A,(BADCLK) ; Check for incorrect clock OR A JR NZ,BCONT LD IY,IDATE LD IX,LSTONF ; Set today as last date on in the LD A,(IY) ; Buffer ONLY, since we need last laston LD (IX),A ; For stats printout that comes next... LD A,(IY+1) LD (IX+1),A LD A,(IY+2) LD (IX+2),A ; ; Now check to see if he was a twit... ; BCONT: LD A,(TWIT) ; Was set to 1 if he is... OR A JR Z,GOOD ; He's okay, on with the program LD (ACESSF),A ; Make him a TWIT befor we write the record GOOD: CALL UPUT LD A,(ACESS) ; Get access value CP 9 ; Only real Sysop not logged JR Z,GOOD1 ; If 9 don't bump calls else continue ; ; And then write the index... ; LD HL,(ICALL) INC HL ; Bump # callers LD (ICALL),HL LD HL,IDATE LD DE,RNDBUF LD BC,NDXLEN LDIR ; Move index info to buffer CALL IOPEN CALL PUT CALL CLOSE ; ; Now set time and date into LASTCALR file, write file for other programs ; to access and then we're almost done. ; GOOD1: LD C,RMLCBF CALL SPBDOS ; Get BYE's last caller buffer LD DE,RNDBUF LD BC,LSTLEN LDIR ; Move info to random buffer ; ; Change name in buffer to normal upper-lower case before placing in the ; LASTCALR buffer for use with KMD.LOG. ; LD HL,RNDBUF+1 ; Leave first character capitalized CALL GOOD2 ; Put reset of 1st name lower case INC HL ; Skip the ',' INC HL ; Skip first letter of last name CALL GOOD2 ; Put rest of last name lower case JR GOOD4 ; Finished, exit ; GOOD2: LD A,(HL) ; Get the character CP '.' ; Ignore periods in the name JR Z,GOOD3 ; Leave it alone and keep going CP 'A' ; See if finished (likely a ',' or CR) RET C ; Exit if done this part of the name OR ' ' ; Else change to lower case LD (HL),A ; Replace with lower case character INC HL ; Next character position JR GOOD2 ; Look at it ; GOOD3: INC HL ; Next position LD A,(HL) ; Get the character after the '.' CP 'A' ; See if an ASCII character RET C ; If not, done this part of the name INC HL ; Otherwise ignore and get next char. JR GOOD2 ; GOOD4: LD HL,LASTCAL CALL OPEN ; Open file LD HL,LSTLEN LD (RRSZ),HL ; Set length of record LD HL,0 CALL PUT ; Write to record 0 CALL CLOSE LD DE,0 LD C,RMWRT CALL SPBDOS ; Clear write lock LD C,RMLCBF CALL SPBDOS EX DE,HL ; Save it LD A,(MSPEED) ADD A,'0' ; Baud rate (shows 'L' if running local) LD (DE),A ; Show callers speed INC DE LD A,' ' LD (DE),A INC DE LD HL,TIME LD B,5 ; Just show HH:MM ; TIME25: LD A,(HL) LD (DE),A INC DE INC HL DJNZ TIME25 LD A,' ' LD (DE),A INC DE LD HL,UNAME LD B,NAMLEN ; NAME: LD A,(HL) OR A JR Z,DNAME LD (DE),A INC HL INC DE DJNZ NAME DNAME: LD A,' ' LD (DE),A INC DE LD HL,CITST LD B,20 ; CITY: LD A,(HL) OR A JR Z,DCITY LD (DE),A INC HL INC DE DJNZ CITY ; DCITY: LD A,' ' LD (DE),A INC DE LD HL,PHONE ; PHNE: LD BC,12 LDIR ; DPHNE: LD A,' ' LD (DE),A INC DE LD A,(LASTON) ; Show last log date as MM/DD CALL BIN2ASC ; Convert binary to ascii LD (DE),A ; MSN is in (A), LSN in (B) INC DE LD A,B LD (DE),A INC DE LD A,'/' LD (DE),A INC DE LD A,(LASTON+1) CALL BIN2ASC LD (DE),A INC DE LD A,B LD (DE),A INC DE LD A,' ' LD (DE),A INC DE LD A,(ACESS) ADD A,'0' LD (DE),A INC DE LD A,CR LD (DE),A INC DE LD A,LF LD (DE),A INC DE XOR A LD (DE),A ; ; Now set the 25th status line if SET25 is on. ; IF SET25 LD HL,IN25 CALL PRLC ; Select the 25th line mode LD C,RMLCBF CALL SPBDOS ; Get address of data from BYE (HL) CALL PRLC ; Print local console only LD HL,OUT25 CALL PRLC ; De-select 25th line mode ENDIF ; SET25 ; ; Okay, if he's a twit, get rid of him, never to return. Let him leave ; a comment the first time, good evidence for future prosecution ; NOSET: LD A,(TWIT) OR A JP NZ,BAN ; ; Okay check if we're a private system requiring registration. If so, ; jump to the exit routine, and tell him about it. ; IF PRVATE LD A,(ACESS) ; See if he's a new user CP 2 JP Z,PREXIT ; Yup, dump him... ENDIF ; PRVATE ; ;----------------------------------------------------------------------- ; ; He's all signed in now, show any bulletins and any special WELCUMx.BBS ; files for his user level. Then display the version number and author's ; credits, if selected. ; HELLO: LD C,LOGST ; BYE DISKLOG status request LD E,0FFH ; Ask for status CALL SPBDOS CP 77 ; 77 says "NO is set in BYE5" JR Z,HELLO0 ; Exit with no change to the flag OR A ; Says DISKLOG is there but turned off LD (DSKFLG),A ; Set flag whether in being used or not JR Z,HELLO0 ; If not being used, exit, else turn off LD C,LOGST ; BYE5 DISLOG status request LD E,0 ; Now turn off the DISKLOG in BYE5 CALL SPBDOS ; ; Print any bulletins and/or special messages for each individual level ; HELLO0: LD HL,CLRWTMSG CALL PRINTM LD HL,BULLETIN CALL TYPE ; IF WELCUM LD A,(ACESS) ; See if we have special Welcome files CP 8 JP NC,HELLOA ; Don't bother with Sysop or co-Sysop ADD A,'0' ; Make it ASCII LD (WELCOM+6),A ; Rename the welcome file pointer LD HL,WELCOM CALL OPEN CP 0FFH JP Z,HELLOA CALL TYPE0 ENDIF ; WELCUM ; ; Show the version number and author's credits, if selected in HBBSHDR. ; HELLOA EQU $ ; IF VERSION LD HL,VMSG ; Print version number CALL PRINTM LD A,(VER) ; Get the version number LD L,A LD H,0 CALL PB2ASC CALL PCRLF ; Turn up a line ENDIF ; VERSION ; ; Show the current day, time and current highest message number, user's ; last message number, etc. ; CALL PCRLF CALL GETTIM ; Get time and convert to binary LD A,(BTIME) CP 12 ; Is it morning? JR NC,HELLO1 LD HL,GMORN ; Yes, say good morning JR HELLO3 ; HELLO1: CP 18 JR NC,HELLO2 LD HL,GAFT ; Say good afternoon JR HELLO3 ; HELLO2: LD HL,GEVE ; Say good evening ; HELLO3: CALL PRINTM CALL PRINT DEFB 'it''s ',0 LD HL,TIME CALL PRINTM CALL PRINT DEFB ' on ',0 CALL GETTIM ; Get the time LD A,(BDATE+1) LD H,0 LD L,A CALL PB2ASC CALL PRINT DEFB ' ',0 LD A,(BDATE) ; Get the date and convert it LD DE,3 ; Length of each entry in table LD H,0 LD L,A ; HL=index CALL MLDL ; HL=offset LD DE,MONTH-3 ; Start of table less index ADD HL,DE ; HL=address for this month LD B,3 CALL PRINTL CALL PRINT DEFB ' ',0 LD A,(BDATE+2) LD H,0 LD L,A CALL PB2ASC ; CALL PRINT DEFB CR,LF,CR,LF,'Highest message.... ',0 LD HL,(IMNXT) DEC HL CALL PB2ASC CALL PRINT DEFB CR,LF,'Last message read.. ',0 LD HL,(HIMSG) CALL PB2ASC ; LD A,(NUSR) ; If new user skip next message OR A JP NZ,NSKP0 ; CALL PRINT DEFB CR,LF,'Last sign-on was... ',0 LD A,(LASTON+1) LD H,0 LD L,A CALL PB2ASC CALL PRINT DEFB ' ',0 ; LD A,(LASTON) LD DE,3 ; Length of each entry in table LD H,0 LD L,A ; HL=index CALL MLDL ; HL=offset LD DE,MONTH-3 ; Start of table less index ADD HL,DE ; HL=address for this month LD B,3 CALL PRINTL ; CALL PRINT DEFB ' ',0 LD A,(LASTON+2) LD H,0 LD L,A CALL PB2ASC ; IF TCAP LD A,(TCODE) ; Get previous selection, if any OR A JR NZ,THELLO CALL UOPEN CALL PCRLF ; Turn up an extra blank line CALL HTCAP ; Ask for terminal selection CALL PUT ; Put user parameters into USERS.BBS CALL CLOSE ; Close USERS.BBS JR NSKP0 ; Skip normal handling ; THELLO: LD A,-1 CALL TCSET ; Come back with current selection CALL PRINT DEFB CR,LF,'Current Terminal... ',0 LD HL,SYSENV+80H LD B,16 CALL PRINTL ENDIF ; TCAP ; NSKP0: LD A,(ACESS) SUB 2 ; Make base 0 (0 & 1 never get here) LD DE,ACTBLEN ; Length of each entry in table LD H,0 LD L,A ; HL=access level CALL MLDL ; HL=offset LD DE,ACC2 ; Start of table ADD HL,DE ; HL=address for this access level ; ; Set ZCPR and BYE values based on access table and user's file ; PUSH HL LD A,(HL) DEC A LD (MXDRV),A ; IF TCAP AND Z3SET LD (ZDRV),A ENDIF ; TCAP AND Z3SET ; LD E,(HL) ; Get maximum drive LD C,RMXDRV ; Let bye set it CALL SPBDOS POP HL INC HL PUSH HL LD A,(HL) INC A LD (MXUSR),A ; IF TCAP AND Z3SET DEC A LD (ZUSR),A INC A ENDIF ; TCAP AND Z3SET ; LD E,(HL) ; Get maximum user area LD C,RMXUSR CALL SPBDOS ; Let bye set it POP HL INC HL ; Point to minutes allowed on-line LD A,(HL) ; See if he's privledged OR A ; 0 is unlimited time JP Z,STOTME ; Skip time check ; ; This code checks to see if the user has any time left today. ; ; NOTE: the update of the time used so far on a day is done by HBYE.Z80. ; If you are not using BYE5 be sure to set TOT in HBBSHDR.Z80 to ; 0 to skip this code. ; IF TOT LD A,(TOTME) ; Get total time on-line today LD B,A LD A,(HL) ; Get max time allowed per day CP B ; See if total used exceeds max allowed JR Z,OVRLIM ; If equal then drop JR C,OVRLIM ; If over then drop SUB B ; Subtract total today and the ... JP STOTME ; Time allowed is difference so set it ; OVRLIM: CALL PRINT DEFB CR,LF,CR,LF DEFB 'You have exceeded the daily maximum time ' DEFB CR,LF DEFB 'allowed, please call back tommorrow.....',CR,LF,0 JP 0000H ; <== LET BYE HANDLE IT ENDIF ; TOT ;..... ; NOTOT: LD A,(HL) ; Get minutes allowed on-line ; STOTME: PUSH HL ; Save either (adjusted or not) time LD E,A ; allowed LD C,RMMXT CALL SPBDOS ; Set BYE's max time allowed POP HL INC HL ; Days to deletion INC HL ; KMRATIO for this level LD A,(HL) LD (KMRATIO),A ; ; Set sleepy caller timeout to minutes of his level, or 30 minutes for ; Sysop. ; LD A,(ACESS) ; Sleepy caller hangup=access level in CP 8 ; minutes JP C,NOTAG LD A,30 ; Give him longer time ; NOTAG: LD E,A LD C,RMTOUT CALL SPBDOS ; Set BYE's sleepy caller time out LD A,(ACESS) ; Get access byte again LD (LOCK),A ; And load in for restricted .COM files etc. ADD A,ASCII ; Add in ASCII offset (make it an acii char.) LD (ASCACC),A ; And place in ascii access location in low mem ; CALL PRINT DEFB CR,LF DEFB 'Time allowed....... ',0 LD E,255 LD C,RMMXT CALL SPBDOS ; Ask BE... OR A ; If it a 0 then unlimited time allowed JR NZ,STOT2 CALL PRINT DEFB 'unlimited',0 JR KM ; STOT2: LD L,A LD H,0 CALL PB2ASC CALL PRINT DEFB ' minutes',0 ; ; The following code is executed if KMACC is set to 1 this allows the ; Sysop to restrict the use of KMD for various levels of user. The re- ; strictions are no KMD, uploads only, downloads only or full usage. ; Set the proper values in the HBBSHDR file to use this facility. Be ; sure to set your KMD to check these values before allowing operation. ; KM EQU $ ; IF KMACC LD A,KMLVL LD B,A LD A,(ACESS) CP B JP C,KMBLK ; Block access to xmodem LD A,(KMRATIO) ; See if we're using U/D ratio OR A JP Z,KMDOK LD B,A LD DE,(UPLDS) LD L,A ; Give him one freeby LD H,0 ; KRATAD: ADD HL,DE ; Get how many d/l he's allowed DJNZ KRATAD LD DE,(DNLDS) SBC HL,DE ; (UPLOADS * RATIO) - DOWNLOADS JP NC,KMDOK ; Still good.. CALL PRINT DEFB CR,LF,CR,LF,07H DEFB 'You have exceeded the ',0 LD H,0 LD A,(KMRATIO) LD L,A CALL PB2ASC CALL PRINT DEFB ':1 Download to Upload ratio allowed.' DEFB CR,LF DEFB 'You are restricted to upload only until your ratio improves.' DEFB CR,LF,0 JR KMBLK ; Go block transfers ; KMDOK: LD A,KMOK LD (STATUS),A JR KMSET ; KMBLK: LD A,KMNO LD (STATUS),A ; KMSET: LD HL,(01H) ; Get JMP COLDBOOT DEC HL LD D,(HL) DEC HL LD E,(HL) LD HL,BYEACC ; + offset to byte ADD HL,DE ; = ACCESS byte address LD A,(STATUS) LD B,A LD A,(ACESS) CP 8 LD A,00H JR C,KMSET2 LD A,80H ; KMSET2: OR B LD (HL),A ; Set access bit ENDIF ; KMACC ; ; Check to see if any mail waiting ; CMAIL: CALL PCRLF JP HBBS ; PASERR: LD IY,BREAKIN ; Get the message pointer JP PS1 ; ; Log the incorrect login attempt ; LOGOUT: LD A,2 ; Bump # lines by one for 'from' info LD (LINES),A LD DE,1 LD C,RMWRT CALL SPBDOS LD HL,COMMENTS CALL SPOPEN ; Open file for comments LD HL,64 LD (RRSZ),HL ; Set record size LD HL,0 ; Get record number CALL GET LD HL,(RNDBUF) ; Is first 2 bytes of record 0 PUSH HL ; Save this comment's record number LD A,(LINES) LD D,0 LD E,A ADD HL,DE ; New number for next comment LD (RNDBUF),HL ; Store it LD HL,0 ; Record number CALL PUT ; And write it ; ; And finally, write each 64 byte line to sequential records showing the ; type of access ; PASWRITE: POP HL ; Get starting record number back LD (RRNO),HL LD A,(LINES) DEC A ; Less one because of 'from' line LD B,A ; Set up counter CALL WRTLP XOR A LD HL,RNDBUF LD (HL),A LD DE,RNDBUF+1 LD BC,63 LDIR ; Clear random buffer LD HL,UNAME LD BC,0 ; PASLOP: INC BC INC HL LD A,(HL) OR A JR NZ,PASLOP LD HL,UNAME LD DE,RNDBUF LDIR ; Add line with caller's name LD A,32 ; Keep SYSREAD happy LD (DE),A CALL GETTIM ; Get date and time LD HL,TIME INC DE LD BC,8 LDIR ; Move time string into place LD A,32 LD (DE),A ; Keep SYSREAD happy LD HL,DATE INC DE LD BC,8 LDIR ; And date LD A,CR LD (DE),A INC DE LD A,LF LD (DE),A LD HL,(RRNO) CALL PUT ; Write last line CALL CLOSE ; All done LD DE,0 LD C,RMWRT CALL SPBDOS ; Clear write lock ; PASOUT: CALL PRINT DEFB CR,'Too many tries...',0 JP 0000H ; <== LET BYE HANDLE IT ;..... ; BREAKIN:DEFB 'User password failure after three tries, ' DEFB 'possible break-in.',0,0,0,0 TWITIN: DEFB 'Well, this TWIT decided to try to call us' DEFB ' again, no access.',0,0,0,0 EOFMSG: DEFB CR,LF,'End of file... to exit',0 YESMSG: DEFB 'Yes',CR,LF,0 NOMSG: DEFB 'No',CR,LF,0 WAITMSG:DEFB CR,LF,'Please wait...',0 CLRWTMSG: DEFB CR,' ',CR,0 ;..... ; ;----------------------------------------------------------------------- ; main control part starts here ; ; If 'HBBS' is called from the CP/M this is the entry point. This is ; determined by reading byte labelled 'REENTR' somewhere in memory. If ; REENTR=0 then the signon routines are entered (which ask for name, ; password, etc.) If REENTR=1 then the program jumps here after setting ; the stack. ; ;----------------------------------------------------------------------- ; HBBS: LD C,LOGST ; BYE DISKLOG status request LD E,0FFH ; Ask for status CALL SPBDOS CP 77 ; 77 says "NO is set in BYE5" JR Z,HBBS1 ; Exit with no change to the flag LD A,(DSKFLG) ; See if DISKLOG is in use OR A ; Says DISKLOG is there but turned off JR Z,HBBS1 ; Exit with no change to the flag LD C,LOGST ; BYE5 DISLOG status request LD E,0 ; Now turn off the DISKLOG in BYE5 CALL SPBDOS ; HBBS1: LD HL,WAITMSG ; Wait while checking for new messages CALL PRINTM CALL UGET ; Get the user record CALL CLOSE ; Close users file CALL SETLIN LD HL,(HIMSG) ; Get highest message read LD (SAVEHI),HL ; Store it for now ; ; Set the mail area access levels ; IF NMAREAS GT 1 LD HL,ACCTBL ; Get address of access table into 'HL' XOR A ; Clear 'A' LD (HL),A ; Store in first byte of the table PUSH HL PUSH HL INC HL EX DE,HL POP HL LD BC,9 LDIR POP HL LD D,1 LD (HL),D INC HL LD (HL),D INC HL LD IX,MAXAREA LD (IX+00H),1 LD IY,MAILTBL LD A,(UFACC) LD B,A LD A,(UFACC+1) LD C,A LD A,(ACESS) LD E,A LD A,040H LD D,NMAREAS-1 ; AFTEST: PUSH AF LD (AFT1+1),A INC A LD (AFT3+1),A ADD A,080H LD (AFT2+1),A ; AFT1: BIT 0,B JR NZ,AFT4 LD A,(IY+00H) OR A ; Clear carry CP E JR Z,AFT2 JR NC,AFT3 ; AFT2 EQU $ ; SET 0,C ; AFT3 EQU $ ; BIT 0,C JR Z,AFT4 LD (HL),1 INC (IX+00H) ; AFT4: INC HL INC IY POP AF ADD A,08H PUSH AF DEC D JR Z,AFT5 JR AFTEST ; AFT5: POP AF LD A,C LD (UFACC+1),A ENDIF ; End of set mail area access ; XOR A LD (MAREA),A ; And set current area to 0 (GLOBAL) LD (UMAREA),A ; And set the user's area to 0 (GLOBAL) ; ; Check to see if any mail waiting ; XOR A ; Zero NEW message counter LD (MFLAG),A LD (MSGCNT),A ; Zero total messages to you count LD A,1 ; Set flag to check for NEW message LD (MSGFLG),A ; ; Check for new messages, but first determine there are some messages ; LD HL,(IMNXT) ; Get the next message number LD A,L DEC A OR H ; If no messages H and L are both zero JP NZ,CKMSG ; If some, check for any NEW messages ;..... ; NEWM1: LD HL,CLRWTMSG ; Can now clear the 'please wait' msg CALL PRINTM LD A,(MFLAG) ; Any messages at all for this user? OR A JR NZ,NEWM2 ; If yes, exit LD A,1 ; Do not turn up two extra lines LD (NOWTNG),A JP HMENU ; NEWM2: LD A,(NEWMSG) ; See if there were any new messages OR A JP Z,HMENU ; To normal menu ; ; Got some new messages, tell him how many and ask if he wants to read ; them now ; GMAIL: CALL EATCHR CALL GMAIL1 JP GMAIL3 ; GMAIL1: CALL PRINT DEFB CR,'You have ',0 LD HL,(NEWMSG) XOR A LD H,A LD A,L PUSH AF ; Save the count CALL PB2ASC CALL PRINT DEFB ' new message',0 POP AF SUB 1 JR Z,GMAIL2 CALL PRINT DEFB 's',0 ; GMAIL2: CALL PRINT DEFB ' waiting, read now? ',0 RET ; GMAIL3: LD C,RDCON CALL SPBDOS AND 5FH ; Change to upper-case CP 'C' ; Ignore C,J,K or N as all saying "No" JR Z,GMAIL4 CP 'J' JR Z,GMAIL4 CP 'K' JR Z,GMAIL4 CP 'N' JR NZ,GMAIL5 ; GMAIL4: CALL PRINT DEFB BS,' ',BS,'No',0 JP HMENU ; GMAIL5: CP CR JR NZ,GMAIL6 CALL GMAIL1 ; GMAIL6: CP ' ' ; Printing character? JR C,GMAIL7 ; If not, exit CALL PRINT DEFB BS,' ',BS,0 ; GMAIL7: LD HL,YESMSG CALL PRINTM ; CKMSG: LD A,1 LD (PNEW),A LD (PNEWX),A JP READM1 ;..... ; ;======================================================================= ; HMENU: LD SP,STACK ; Clear the stack CALL EATCHR ; Clear some garbage XOR A ; Clear some flags LD (ALLFLG),A ; Message sent to 'all' LD (LFLAG),A ; Left messages flag LD (MYFLG),A ; Clear "my messages" flag LD (PFLAG),A ; Public messages flag LD (PMSND),A ; Private mail send flag LD (PNEW),A ; Clear the private new flag LD (PNEWX),A ; Clear the private new flag LD (RMAREA),A ; Clear the current message area flag LD (RNEW),A ; Clear "NEW" flag LD (SYSFLG),A ; Sysop private read function LD A,(XPRT) ; area OR A JR Z,MCMD LD HL,BBSMENU ; Load up the menu file CALL TYPE ; MCMD: LD A,(NOWTNG) OR A JR Z,MCMD1 XOR A LD (NOWTNG),A JR MCMD2 ; MCMD1: CALL PCRLF1 ; Turn up two lines ; MCMD2: LD HL,UNAME ; Make him feel at home LD B,NAMLEN CALL PRINTN LD C,RMTOS ; Show time left on system CALL SPBDOS ; (for Sysop, time on system) ; IF (NMAREAS GT 1) LD A,(MAREA) ; Get the current area OR A JR Z,MENU1 ; If global, don't bother printing CALL SAREA ; Display working area number ENDIF ; (NMAREAS GT 1) ; MENU1: LD A,(CNTN) OR A CALL NZ,PCRLF CALL MENU2 JP MENU4 ; MENU2: CALL PRINT DEFB CR,'Commands: ' ; IF NMAREAS GT 1 DEFB 'A,' ENDIF ; NMAREAS GT 1 ; DEFB 'B,C,E,F,G,H,I,L,M,N,P,R,S,T,U,Y',0 ; MENU3: CALL PRINT DEFB ' or ? ',0 RET ; MENU4: CALL EATCHR LD C,RDCON CALL SPBDOS PUSH AF CP ' ' ; Printing character? JR NC,MENU5 ; If yes, exit CALL MENU2 ; Else accept as a 'read' request POP AF CP CR JP Z,PMAIL JR MENU4 ; Ask again ; MENU5: CALL PRINT DEFB BS,' ',BS,0 POP AF CP '?' JR Z,SHOWCMD CP '@' ; Does Sysop want to chat? JP Z,YAKSOP CALL CAPS CP 'A' JR C,MENU4 CP 'Z'+1 JR NC,MENU4 ; IF NMAREAS GT 1 CP 'A' JP Z,GAREA ENDIF ; Select areas if activated ; CP 'B' ; Display any bulletins JP Z,HBLTN CP 'C' ; Go to CP/M JP Z,JMPCPM CP 'E' ; Enter a message JP Z,POSTM CP 'F' ; For descriptions of new files JP Z,KFOR CP 'G' ; Goodbye, all done on the system JP Z,GBYE CP 'H' ; Header scan of messages JP Z,SCAN CP 'I' ; Show any info or news file JP Z,HINFO CP 'J' ; Jump to CP/M JP Z,JMPCPM CP 'L' ; Read msgs left by you JP Z,LREADM CP 'M' ; Read "my new mail" JP Z,READM CP 'N' ; List new files recently uploaded JP Z,KNEW CP 'P' ; List previous callers JP Z,PCLRS CP 'R' ; Read the public mail JP Z,PMAIL CP 'S' ; Statistics JP Z,STATS CP 'T' ; Toggle [more] pause JP Z,MORTOG CP 'U' ; Show the user list JP Z,HUSERS CP 'Y' ; Yak with Sysop JP Z,YAK JP MENU4 ; None of these, ask again ;..... ; ;======================================================================= ; =?= (comes here if they use '?' to request the menu of commands ; SHOWCMD:CALL PRINT DEFB '?',CR,LF,CR,LF,0 LD HL,BBSMENU ; Load up the menu file CALL TYPE JP MCMD2 ; Back to work ;..... ; ;----------------------------------------------------------------------- ; =B= ; ; Display the bulletin file for the user ; HBLTN: CALL PRINT DEFB 'Bulletins',0 CALL EATCHR LD HL,BULLETIN ; Load the bulletin file name CALL TYPE OR A JP Z,HMENU LD HL,EOFMSG CALL PRINTM JP HMENU ;..... ; ;----------------------------------------------------------------------- ; =G= ; ; Leaves the system, finished ; GBYE: CALL PRINT DEFB 'Goodbye',0 JP QUIT ;..... ; ;----------------------------------------------------------------------- ; =I= ; HINFO: CALL PRINT DEFB 'Info',CR,LF,CR,LF,0 ; HINFO1: LD HL,INFO ; INFO must contain the question line CALL TYPE ; with no 'CR' CALL PRINT DEFB ' to exit : ',0 CALL EATCHR ; HINFOASK: CALL GETCH CP CR JP Z,HEXIT CALL CAPS CP 'A' JR C,HINFOASK ; HBBS allows up to 26 news files: A-Z CP 'Z'+1 JR NC,HINFOASK CALL ECHO LD (INFOEXT),A LD HL,INFO CALL TYPE XOR A LD (INFOEXT),A LD HL,EOFMSG CALL PRINTM CALL EATCHR CALL GETCH ; Let him read it... JP HINFO1 ; HEXIT: CALL PRINT DEFB 'Exit',0 JP HMENU ;..... ; ;----------------------------------------------------------------------- ; =L= ; ; Check for messages left by this user ; LREADM: CALL PRINT DEFB 'Left by me',0 XOR A ; Clear a LD (MAREA),A ; Set to area 1 (zero) for now LD (CNTN),A ; Clear continous read flag LD (PFLAG),A ; Clear public flag LD A,1 LD (LFLAG),A ; Set left flag JP READMP ; ; Special Sysop function to read all messages in database to allow him ; to delete offensive ones. ; SYSREAD:LD A,(ACESS) ; Better be the Sysop.. ;; ;;==>> Next line determines who can read all messages as Sysop ;; CP 8 JP C,HMENU ; Send him back empty LD A,1 LD (SYSFLG),A ; Set Sysop flag JP READMP ;..... ; ;----------------------------------------------------------------------- ; =T= ; MORTOG: CALL PRINT DEFB '[more] pauses' DEFB CR,LF,CR,LF,'[more] pauses now ',0 LD A,(MORFLG) ; Check the flag OR A JR NZ,MORENB ; If disabled, restore [more] pauses LD A,1 ; Was enabled, so disable it now LD (MORFLG),A ; Set the flag CALL PRINT DEFB 'disabled',0 JP HMENU ; Pauses disabled, ready to go ; MORENB: CALL PRINT DEFB 'enabled',0 XOR A ; Reset the flag or normal pauses LD (MORFLG),A JP HMENU ; Pauses enabled normally, ready to go ;..... ; ;----------------------------------------------------------------------- ; =S= ; ; Access statistics ; STATS: CALL PRINT DEFB 'Statistics ',0 XOR A LD (TWIT),A ; Clear TWIT/PNEW flag ; CALL PRINT DEFB CR,LF,CR,LF,'User name.......... ',0 LD B,NAMLEN LD HL,UNAME CALL PRINTN ; CALL PRINT DEFB CR,LF DEFB 'You are caller..... ',0 LD HL,(ICALL) CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Your user level.... ',0 LD A,(ACESS) LD H,0 LD L,A CALL PB2ASC ; LD A,(NUSR) ; If new user skip next message OR A JP NZ,STATS1 ; CALL PRINT DEFB CR,LF DEFB 'Your sign-ons...... ',0 LD HL,(TMSON) CALL PB2ASC ; STATS1: CALL PRINT DEFB CR,LF DEFB 'System users....... ',0 LD HL,(IUSER) CALL PB2ASC ; LD HL,LOGSTR ; HL -> logon time LD DE,ONTIM ; Point to where to put it LD BC,8 ; Number of bytes LDIR ; Move them ; CALL GETTIM ; Get the current time LD HL,TIME ; Point to the time string LD DE,CURTIM ; Where to put it LD BC,8 LDIR ; Move it CALL CALCTIM ; Calculate the elapsed time ; ; Print the results ; CURDAT1:CALL PRINT DEFB CR,LF,'Current time....... ' ; CURTIM: DEFB '00:00:00',CR,LF,0 ; CURNAM: CALL PRINT DEFB 'Logged on at....... ' ; ONTIM: DEFB '00:00:00',0 CALL PRINT DEFB CR,LF,'Connect time....... ' ; ELPTIM: DEFB '00:00:00',0 CALL PRINT DEFB CR,LF,'Time left today.... ',0 LD C,RMRTC CALL SPBDOS ; Get time on LD H,0 LD L,A PUSH HL ; Save it LD E,255 LD C,RMMXT CALL SPBDOS ; Get time allowed OR A JR NZ,ONTIM1 CALL PRINT ; 0 means unlimited time allowed DEFB 'unlimited ',0 POP HL ; Clean up stack JR ONTIM2 ; ONTIM1: LD H,0 LD L,A POP DE ; Was HL... AND A ; Clear carry flag SBC HL,DE CALL PB2ASC CALL PRINT DEFB ' minutes',0 ; ONTIM2: CALL PRINT DEFB CR,LF,CR,LF,'Total uploads...... ',0 LD A,(UPLOADS) LD H,0 LD L,A LD BC,(UPLDS) ADD HL,BC CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Total downloads.... ',0 LD A,(DNLOADS) LD H,0 LD L,A LD BC,(DNLDS) ADD HL,BC CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Highest message.... ',0 LD HL,(IMNXT) DEC HL CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Last message read.. ',0 LD HL,(HIMSG) CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Messages to you.... ',0 LD HL,(MFLAG) XOR A LD H,A CALL PB2ASC ; MSTAT0: CALL PRINT DEFB CR,LF,CR,LF,'Phone number now... ',0 LD B,12 LD HL,PHONE CALL PRINTL ; CALL PRINT DEFB CR,LF,'CRT line width..... ',0 LD HL,(LENG) XOR A LD H,A CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Current nulls...... ',0 LD E,255 LD C,RMNULL CALL SPBDOS LD H,0 LD L,A CALL PB2ASC ; CALL PRINT DEFB CR,LF,'Password now....... ',0 LD HL,PSWRD LD B,10 CALL PRINTL ; IF TCAP LD A,-1 CALL TCSET CALL PRINT DEFB CR,LF,'Current terminal... ',0 LD HL,SYSENV+80H LD B,16 CALL PRINTL ENDIF ; TCAP ; MSTAT: CALL PRINT DEFB CR,LF,CR,LF DEFB 'Change: Fone #, Nulls, Password',0 ; IF TCAP CALL PRINT DEFB ', Terminal',0 ENDIF ; TCAP ; CALL PRINT DEFB ', Line width or : ',0 CALL EATCHR ; Clear garbage ; MSTAT1: CALL GETCH JR Z,MSTAT1 CP CR JP Z,HMENU ; Exit back to main menu CALL CAPS CP 'F' JP Z,PHNCHG CP 'L' JP Z,LINCHG CP 'N' JP Z,NULCHG CP 'P' JP Z,PASCHG ; IF TCAP CP 'T' JP Z,TRMCHG ENDIF ; TCAP ; JR MSTAT1 ; None of these, wait for one of them ; LINCHG: CALL PRINT DEFB 'Length',CR,LF,CR,LF DEFB 'New line length (10-7' ; IF LINNOS DEFB '4' ENDIF ; LINNOS ; IF NOT LINNOS DEFB '8' ENDIF ; NOT LINNOS ; DEFB ') or to exit: ',0 LD A,0C9H ; "RET" instruction LD (CHGLIN5),A CALL CHGLIN1 JP MSTAT0 ; PASCHG: CALL PRINT DEFB 'Password',CR,LF,CR,LF,0 ; PASCHG1:LD B,10 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'New password (4-10 chars.) or to exit',CR,0 LD B,10 ; Length LD C,20H ; Caps XOR A ; Echo on LD D,A ; No word-wrap CALL INPUT ; Get password OR A JP Z,MSTAT0 ; No change requested CP 4 JP C,PASCHG1 ; Must be 4 characters long minimum LD B,A ; PASCHK: LD A,(HL) ; Make sure password is all alpha chars. CP '0' ; If not alpha or numeric, ask again JP C,PASCHG1 ; If not alpha, ask again INC HL ; Next position DEC B ; One fewer to check JR NZ,PASCHK ; If not finished, keep checking LD HL,INBUF LD DE,PSWRD LD BC,10 LDIR CALL USTORE ; Move info buffer CALL UPUT ; Save the new info JP MSTAT0 ;..... ; ERR: CALL PRINT DEFB CR,LF DEFB 'Must be at least 4 characters...',0 JP PASS ;..... ; NULCHG: CALL PRINT DEFB 'nulls',CR,LF,0 CALL NULLQ1 JP MSTAT0 ;..... ; PHNCHG: CALL PRINT DEFB 'Phone number' DEFB CR,LF,CR,LF,0 LD HL,PHONE LD BC,12 LD DE,PHONEF LDIR ; Save the old one LD HL,PHONE LD B,12 LD A,0C9H LD (PHNRET),A LD (TRIED),A CALL PHN2 ; Try forever to get one LD A,(TWIT) OR A ; See if he faked it JP Z,MSTAT0 LD HL,PHONEF LD BC,12 LD DE,PHONE LDIR ; Faked it, so restore old one JP MSTAT0 ;..... ; TRMCHG EQU $ ; IF TCAP CALL PRINT DEFB 'Terminal',CR,LF,0 LD A,1 CALL TCSET OR A JP Z,MSTAT LD (TCODE),A LD (TRMCD),A CALL USTORE ; Move info into buffer CALL UPUT JP MSTAT0 ENDIF ; TCAP ;..... ; ;----------------------------------------------------------------------- ; =M= ; ; Read mail addressed to user ; READM: CALL PRINT DEFB 'Read my mail',0 ; READM1: XOR A ; Clear a LD (MAREA),A ; Set to area 1 (zero) for now LD (RNEW),A LD (CNTN),A LD (LFLAG),A ; Clear left flag LD (PFLAG),A ; Clear public flag LD (MFTMP),A ; Clear temp mail count LD A,1 LD (MYFLG),A ; Read "my messages" (old and/or new) JP READMP ;..... ; ; Set the continuous read function with an '*' ; SETCON: LD A,(CNVRT0+1) ; Eliminate the * DEC A LD (CNVRT0+1),A ; Save the result LD A,1 LD (CNTN),A ; Set the flag XOR A LD (RNEW),A ; Clear new flag RET ;..... ; ;----------------------------------------------------------------------- ; =R= ; ; Reading all public mail so set flag to public ; PMAIL: CALL PRINT DEFB 'Read the mail',CR,LF,CR,LF,0 XOR A LD (CNTN),A ; Clear continous read flag LD (PNEW),A ; Reset the flag in case it is still set LD (PNEWX),A LD A,(ACESS) ; This the Sysop or co-Sysop? ;; ;;==>> Determines level for reading all messages: public, private, deleted ;; CP 8 JP NC,SYSREAD ; If yes, exit LD A,1 LD (PFLAG),A ; Set public flag ; ; Common entry point for all reads... public or private or left by user ; READMP: LD HL,R1 LD DE,SMSG LD BC,7 LDIR LD DE,(MSGARR) ; Point to messages table PUSH DE CALL MOPEN ; Open MSGINDEX LD HL,0 ; Start with first message if private LD (RRNO),HL ; ; Read message index loop and make decisions about whether to display ; based on user's name and current function (public, private) ; MRASK: LD A,(SYSFLG) ; See if Sysop is reading all OR A JR NZ,SYSASK ; YUP...ask him where to start.. LD A,(PNEW) ; Checking for new private mail? OR A JR Z,MRASK1 ; No, go check normally LD HL,1 ; Start the check at message 1 JR MDFND ; (lets Sysop answer messages later) ; MRASK1: LD A,(PFLAG) ; Is the "read public stuff" flag set? OR A JP Z,MRDLP ; If not, reading private so exit ; SYSASK: CALL PRINT DEFB 'For continuous read use * for new or after msg #',0 CALL GETNUM ; MDFND: CALL GETRC ; Go find actual record ; MRDLP: LD HL,(RRNO) CALL GET LD A,(LFLAG) ; Just reading "messges left"? OR A JP NZ,MRDLP2 ; If yes, was not from him, get next ; ; Check for messages to this user ; LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR Z,MRP ; If to this user, exit LD A,(ACESS) ;; ;;==>> Next line determines who is notified of messages to Sysop ;; CP 9 ; Just Sysop is notified of his mail JR C,MRDLP1 ; If not, exit LD HL,MTOF LD DE,SYSOP ; Compare to real Sysop name CALL MATCH OR A JP Z,MRP ; If to Sysop, exit ; ; Check for messages from this user ; MRDLP1: LD A,(MYFLG) ; Reading only messages "to me"? OR A JP NZ,MBUMP ; If yes, ignore any "from" msgs. LD A,(SYSFLG) ; Does Sysop want to read all msgs? OR A JP NZ,MRDLPC ; Go read all, including deleted ; MRDLP2: LD HL,MFROMF ; See if from this user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JP Z,MRDLPB ; Yes, exit and add it to the list LD A,(ACESS) ; See if it's the Sysop ;; ;;==>> Determines who can read "from" messages if from Sysop (co-Sysop ;; can still read them as SYSFLG has already jumped to MRDLPC area.) ;; CP 9 JR C,MRDLPA LD HL,MFROMF LD DE,SYSSTR ; Check "SYSOP" name LD B,6 ; One extra for '0' terminator CALL MATCH OR A JP Z,MRDLPB ; Was a match, exit ; MRDLPA: LD A,(LFLAG) ; Just reading "messges left"? OR A JP NZ,MBUMP ; If yes, was not from him, get next JP MRP4 ;.... ; MRP: LD A,(SYSFLG) ; Does he want all of them? OR A JR NZ,MRP1 LD A,(MREAD) ; Get status flag CP -1 ; Is it deleted JP Z,MBUMP ; Yes, get the next one ; ; This is the area that increments the NEW message count, if to this ; user. ; MRP1: LD A,(MSGFLG) ; Checking for NEW message count? OR A JR Z,MRP2 ; If not, exit LD A,(MFLAG) INC A LD (MFLAG),A LD A,(MREAD) ; See if already read OR A JP NZ,MBUMP ; If yes, skip this one LD A,(NEWMSG) ; Get NEW message count INC A ; Add this one LD (NEWMSG),A ; Count this as a NEW message to read ; ; This is the end of the check for NEW, unread messages since last high ; messge check. Exit and look for next one to check ; JP MBUMP ; Done checking for this msg, get next ;..... ; ; MRP2: LD A,(PNEWX) ; If reading NEW, skip if already read OR A JR Z,MRP3 ; If not, continue LD A,(MREAD) OR A JP NZ,MBUMP ; Ignore if already read ; MRP3: LD A,(MAREA) ; In the global area while reading msgs? OR A JR Z,MRDLP3 ; Skip area match, it's To: this user JR MRDLPB ; Otherwise, check area match ;.... ; MRP4: LD A,(PFLAG) ; Looking at public messages also? OR A JP Z,MBUMP ; No, get next one LD A,(MPUBF) ; Check to see if this is a private msg OR A JP NZ,MBUMP ; Yes, don't show it to this user ; MRDLPB: LD A,(PNEW) ; Reading NEW only? OR A JP NZ,MBUMP LD A,(MREAD) ; Get status flag CP -1 ; Is it deleted JP Z,MBUMP ; Yes go back for more LD A,(MSGFLG) ; Checking for NEW message count? OR A JP NZ,MBUMP ; MRDLPC EQU $ ; IF NMAREAS GT 1 LD A,(MAREA) ; See if we are in the 'GLOBAL' mode OR A JR Z,MRDLPD ; If yes, no need to check further, exit LD HL,MANUMF ; Load HL with message's area number adr ; ; If here, we aren't reading area 0 (GLOBAL) read, so check to see if ; active area value matches this message's area number. If it does, ; continue, else go back for more. ; LD A,(MAREA) ; Get the area we are reading into 'A' CP (HL) ; Compare to this message's area number JR NZ,MBUMP ; If not equal go back for more JR MRDLP3 ;..... ; ; If here we are doing a GLOBAL read (all areas), but we still need to ; to check if the user has access to this area. NOTE: This is not ; required for a read of a specific area, for if the user doesn't have ; access to a area he would not be able to select the area in the ; first place. ; MRDLPD: LD A,(MANUMF) ; Area number of this message LD C,A ; Place into 'C' LD B,0 ; Clear 'B' so BC has offset into table LD HL,ACCTBL ; Get address of table into 'HL' ADD HL,BC ; Add bias LD A,(HL) ; Table value into 'A' OR A ; Set the flags CP 1 ; Is it 1 (user has access)? JR NZ,MBUMP ; If not go back for more ENDIF ; NMAREAS GT 1 ; MRDLP3: LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR NZ,MRDLP4 LD A,(MFTMP) ; Get temporary count INC A LD (MFTMP),A ; MRDLP4: LD HL,MRECF ; No POP DE ; Get current pointer LD BC,2 LDIR ; Save message info PUSH DE ; New pointer LD C,D LD A,(007H) ; Get top of TPA DEC A ; Give us some head room SUB C JR NZ,MBUMP ; We still have room CALL PRINT DEFB 'Unable to display all messages',07H,CR,LF,0 JR TPAEND ; Bail out ;..... ; MBUMP: LD DE,(RRNO) ; Get record INC DE ; And up it by one LD (RRNO),DE LD HL,(IMNDX) ; See if any more XOR A ; Clear carry flag SBC HL,DE ; Yes JP NC,MRDLP ; TPAEND: CALL CLOSE LD A,(SYSFLG) OR A JR NZ,MBUMP1 ; Sysop reading all..skip update LD A,(LFLAG) ; Reading left msgs? OR A JR NZ,MBUMP1 ; Yes...skip MFLAG update LD A,(PFLAG) ; Reading public messages OR A JR NZ,MBUMP1 ; Yes...skip MFLAG update LD A,(PNEW) ; Don't update count on New priv. read OR A JR NZ,MBUMP1 LD A,(MFTMP) ; Get temporary count LD (MFLAG),A ; This keeps the mail count accurate ; MBUMP1: POP IY ; Get pointer to end of array (was DE) LD A,-1 LD (IY),A LD (IY+1),A ; PMSGS: LD IY,(MSGARR) ; Point to table ; PMLOP1: LD A,(IY) ; See if at end of array CP -1 JR NZ,PM01 LD A,(IY+1) CP -1 JP Z,NOMOR ; At end so quit ; ; Display subject of message about to be displayed ; PM01: CALL MOPEN ; Reopen MSGINDEX LD A,0C9H ; Opcode for return. LD (SCNM3C),A ; Make it a sub-routine LD L,(IY) ; Set MSGINDEX record LD H,(IY+1) LD (RRNO),HL ; Prepare to display CALL DISPH ; Do it. XOR A LD (SCNM3C),A ; Restore routine LD A,(MSGFLG) ; Checking for NEW message count? OR A JP NZ,HDR6 ; If yes, skip all the header stuff ; ; = 1 = ; CALL PRINT DEFB ' ',0 LD IX,MDATF CALL PDATE CALL PRINT DEFB ' ',0 LD HL,MTIMF ; Address the temporary buffer LD B,5 ; Print the date and time CALL PRINTL CALL PRINT DEFB ' ',0 LD HL,TIMZON ; Print the time designator ("PST") etc. LD B,3 CALL PRINTL ; ; = 2 = ; HDR1: LD HL,(MNUMF) LD (LASTMSG),HL ; Store this msg# for HIMSG: update CALL PRINT DEFB CR,LF,'Subj: ',0 LD HL,MSUBF LD B,26 CALL PRINTL ; ; = 3 = ; CALL PRINT DEFB CR,LF,'From: ',0 LD HL,MFROMF LD B,NAMLEN CALL PRINTN ; ; = 4 = ; CALL PRINT DEFB CR,LF,'To: ',0 LD HL,MTOF LD B,NAMLEN CALL PRINTN LD A,(MREAD) ; See if message has been read yet OR A ; 0 = not deleted, not read yet JR NZ,HDR2 ; Not read, check if deleted LD A,(MPUBF) ; See if it was private OR A ; Message Private JR Z,HDR6 ; If not, skip the spaces CALL PRINT DEFB ' ',0 JR HDR5 ; HDR2: CP -1 JR Z,HDR3 ; Deleted CALL PRINT DEFB ' (R)',0 ; Read JR HDR4 ; HDR3: CALL PRINT DEFB ' =D=',0 ; HDR4: LD A,(MPUBF) OR A ; Message Private JR Z,HDR6 ; HDR5: CALL PRINT DEFB '

',0 ; HDR6: LD HL,(MNUMF) LD (LASTMSG),HL LD A,(MBLKF) LD B,A PUSH BC LD HL,(MSTRF) LD (MSGREC),HL ; Set the message start record LD HL,(MRECF) ; Get this index record LD (CURREC),HL ; Save it LD HL,MFROMF ; Save name for answer LD DE,MTOTMP LD BC,NAMLEN LDIR ; IF NOT HDRSTP JP PMGO ; Exit if not stopping after each header ENDIF ; NOT HDRSTP ; LD A,(CNTN) OR A JP NZ,PMGO ; We're runnuing continous, display CALL NULIN CALL NULIN CALL PRINT DEFB ' Again, Exit, Previous, Read, Skip',0 CALL EATCHR LD A,(ACESS) ;; ;;==>> Next line determines who can see "Delete" line ;; CP 8 JR NC,PM02 ; Sysop can delete any message LD HL,MFROMF ; See if from user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR NZ,PSKP ; Nope, don't tell him about delete ; IF NOT ERASE JR PSKP ; Skip the delete if eraing not allowed ENDIF ; NOT ERASE ; PM02: CALL PRINT DEFB ', Delete',0 ; PSKP: CALL PRINT DEFB ': ',0 ; PMWT: CALL GETCH CP CR JR Z,PMWT1 CP ' ' JR C,PMWT JR Z,PMWT1 CALL CAPS CALL ECHO CP 'A' JP Z,PMAGN1 CP 'E' JP Z,PMQT1 CP 'P' JP Z,PMBCK1 CP 'R' JR Z,PMWT2 CP 'S' JP Z,PMSKP1 CP 'D' JR NZ,PMWT0 LD A,(ACESS) ; Else let the Sysop delete ;; ;;==>> Next line determines who can use the 'D' delete if restricted ;; CP 8 JP NC,MKILL ; IF ERASE JP MKILL ; Exit if anybody can erase ENDIF ; ERASE ; PMWT0: CALL PRINT DEFB BS,' ',BS,0 JR PMWT ;..... ; PMWT1: CALL PRINT DEFB 'R',0 ; PMWT2: CALL PRINT DEFB 'ead',0 ;..... ; ; Display message ; PMGO: LD HL,MTOF LD DE,UNAME LD B,NAMLEN CALL MATCH OR A LD (TOFLAG),A JR NZ,PMGO1 LD A,(MREAD) OR A JR NZ,PMGO1 LD A,1 LD (MREAD),A ; Mark it read... LD HL,(RRNO) CALL PUT ; PMGO1: CALL CLOSE ; Close MSGINDEX CALL MSGOPEN LD HL,(MSGREC) ; Get message record back LD (RRNO),HL POP BC ; Recover line count LD DE,(MSG) ; Point to start of buffer ; PMLOP2: PUSH BC ; Save counter LD HL,(RRNO) PUSH DE ; Save buffer address CALL GET POP DE ; Get buffer address LD HL,RNDBUF LD BC,64 ; Move to message buffer LDIR ; De=next buffer address LD HL,(RRNO) INC HL ; Next line (record) LD (RRNO),HL POP BC ; Get counter DJNZ PMLOP2 ; Done? CALL CLOSE ; Close the message file CALL LIST ; List the message to screen JR Z,CL2 ; Did he try to abort? LD A,(CNTN) ; Yup, are we in continous read? OR A JP NZ,HMENU ; YUP, abort listing... ; CL2 EQU $ ; IF NMAREAS GT 1 LD A,(MAREA) ; Only update HIMSG from global area OR A JR NZ,PKILLB ENDIF ; NMAREAS GT 1 ; LD HL,(HIMSG) LD DE,(LASTMSG) AND A ; Clear carry flag SBC HL,DE JR NC,PKILLB LD A,(SYSFLG) ; Do not update msg count if SYSFLG set OR A JR NZ,PKILLA LD A,(PFLAG) ; Only update during public read OR A JR Z,PKILLB ; PKILLA: LD (HIMSG),DE ; PKILLB: CALL ABORT ; Check for abort JR Z,PKILLC ; 'Z' continues, 'NZ' aborts CALL PCRLF JP HMENU ; PKILLC: LD A,(CNTN) ; Are we in continuous (+) mode ? OR A JP NZ,PMSKP+3 ; Yup, let's get another msg QUICK XOR A LD (LFLAG),A ; Clear the flag before asking LD HL,MTOTMP ; See if from this user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR NZ,PKILLD LD A,1 LD (LFLAG),A ; PKILLD: CALL EATCHR CALL PRINT DEFB CR,LF,'Again, Exit, Next, Previous',0 LD B,ALLLV ; Can user leave messages? LD A,(ACESS) ; Get his access level CP B JP C,PKILLI ; If not, exit LD HL,MFROMF ; See if from user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR Z,PKILLF ; Can't answer his own messages LD A,(ACESS) ; See if it's the Sysop CP 9 JP C,PKILLE ; Not Sysop so can reply LD HL,MFROMF LD DE,SYSSTR ; Check "SYSOP" name LD B,6 CALL MATCH ; If yes, shouldn't answer own mail JP Z,PKILLF ; PKILLE: CALL PRINT DEFB ', Reply',0 ; PKILLF: LD A,(ACESS) ; See if Sysop ;; ;;==>> Next line determines what level sees the 'Delete' command ;; CP 8 JR NC,PKILLG ; If yes, let him erase anything ; IF NOT ERASE JP PKILLH ENDIF ; NOT ERASE ; LD A,(LFLAG) ; Message left by this user? OR A JR NZ,PKILLG ; He can delete it, then LD A,(PFLAG) ; Public message ? OR A JR NZ,PKILLI ; If yes, not to him, don't allow delete ; PKILLG: CALL PRINT DEFB ', Delete',0 LD A,(ACESS) ;; ;;==>> Next line determines what level can modify message headers ;; CP 8 JR C,PKILLI CALL PRINT DEFB ', Modify',0 ; PKILLH: LD A,(ACESS) ;; ;;==>> Next line determines what level can Tag messages to answer later ;; CP 8 JR C,PKILLI ; If less, cannot tag, exit LD A,(TOFLAG) ; This message to this user? OR A JR NZ,PKILLI ; If not, do not show the option CALL PRINT DEFB ', Tag',0 ; PKILLI: CALL PRINT DEFB ': ',0 ; ; Get the answer ; PMGT: CALL GETCH ; Get the answer CP CR ; CR ? JP Z,PMSKP0 ; Skip to next CP 'K'-40H ; CTL-K to abort? JR Z,PMGT ; If yes, ignore CALL CAPS CP 'A' ; Want to see the message again? JP Z,PMAGN CP 'E' ; Want to quit/abort? JP Z,PMQT ; If yes, go quit CP 'K' ; Want to abort? JR Z,PMGT ; If yes, ignore, message is finished CP 'M' ; Requesting to modify? JP Z,HMOD ; If yes, exit CP 'N' ; Next message? JP Z,PMSKP0 CP 'P' ; For previous message JP Z,PMBCK CP 'R' ; Reply to this message? JR NZ,PMGT1 LD B,ALLLV ; Can user leave messages? LD A,(ACESS) ; Get his access level CP B JP NC,PMREP ; If yes, let him reply JP PMSKP0 ; If not, go to next message ;..... ; PMGT1: LD B,A ; Store for now LD A,(ACESS) ;; ;;==>> Next line determines what level can Tag messages to answer later ;; CP 8 LD A,B ; Get the character back JR C,PMGT2 ; If less, cannot tag, exit CP 'T' ; Tag for later read/reply JP Z,TAG ; PMGT2: CP 'D' JP NZ,PMSKP0 ; None of these, continue LD A,(ACESS) ;; ;;==>> Next line sets level at which 'D' for delete can be used ;; CP 8 ; If it's the Sysop JP NC,PKIL1 ; Ask for kill ; IF NOT ERASE JP PMSKP0 ENDIF ; NOT ERASE ; LD A,(LFLAG) ; Message left by this user? OR A JR NZ,PKIL1 ; He can delete it, then LD A,(PFLAG) ; Public flag set? OR A ; Only kill for messages to user JP NZ,PMSKP0 ; PKIL1: CALL PRINT DEFB 'Delete',0 JP MKILL ; TAG: LD A,(TOFLAG) ; This message to this user? OR A JP NZ,PMGT ; If not, ignore and ask again CALL PRINT DEFB 'Tag for later',0 CALL MOPEN ; Open or reopen MSGINDEX LD L,(IY) ; Set MSGINDEX record LD H,(IY+1) LD (RRNO),HL ; Prepare to display CALL GET ; Get the message information now XOR A LD (MREAD),A LD HL,(RRNO) ; Get the current record CALL PUT ; Put into MSGINDEX.BBS CALL CLOSE ; Close the file, all done JP PMSKP ; Go on to the next message ;..... ; HMOD: LD A,(ACESS) ; See if Sysop CP 8 JP C,PMSKP0 ; If not 'Next' ; CALL PRINT DEFB 'Modify',CR,LF,CR,LF DEFB ' 0) no change, get Next msg',CR,LF DEFB ' 1) change to Private',CR,LF DEFB ' 2) change to Public',CR,LF DEFB ' 3) undelete to ''not read'' ',CR,LF DEFB ' 4) undelete to ''was read'' ',CR,LF DEFB ' 5) change "To: " name',CR,LF ; IF NMAREAS GT 1 DEFB ' 6) change area name',CR,LF ENDIF ; NMAREAS GT 1 ; DEFB CR,LF,0 CALL MOPEN ; Open or reopen MSGINDEX LD L,(IY) ; Set MSGINDEX record LD H,(IY+1) LD (RRNO),HL ; Prepare to display CALL GET ; Get the message information now ; HMOD1: CALL PRINT DEFB CR,'select: ',BS,BS,' ',0 CALL GETCH CP '0' JP Z,PMQT2 CALL ECHO CP '6' JP Z,HMOD8 CP '5' JP Z,HMOD7 CP '4' JR Z,HMOD5 CP '3' JR Z,HMOD4 CP '2' JR Z,HMOD2 CP '1' JR NZ,HMOD1 ; None of these, ask again LD A,1 ; Set to private JR HMOD3 ; HMOD2: XOR A ; Make it public ; HMOD3: LD (MPUBF),A ; Private/public flag JR HMOD9 ; Exit and store in MSGINDEX.BBS ; HMOD4: XOR A ; Say it was not read JR HMOD6 ; HMOD5: LD A,1 ; Say it has been read ; HMOD6: LD (MREAD),A ; 0=not read, 1=read, -1=deleted JP HMOD9 ; HMOD7: LD B,NAMLEN-1 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'new name or All',CR,0 LD B,NAMLEN-1 ; Input length (insure 1 null) LD C,20H ; Force caps (C=0 for no caps) XOR A LD D,A ; No word-wrap CALL INPUT ; Character count returned in 'A' LD HL,INBUF LD DE,MTOF LD BC,NAMLEN LDIR JP HMOD9 ; HMOD8 EQU $ ; IF NMAREAS EQ 1 JP HMOD1 ; If not using areas, ignore request ENDIF ; NMAREAS EQ 1 ; IF NMAREAS GT 1 CALL PCRLF ; Turn up one blank line first CALL ISYS1 ; Ask for area number ENDIF ; NMAREAS GT 1 ; HMOD9: LD HL,(RRNO) ; Get the current record CALL PUT ; Put into MSGINDEX.BBS CALL CLOSE ; Close the file, all done JP PMLOP1 ; Display the message again ;..... ; ;----------------------------------------------------------------------- ; PMQT: CALL PRINT ; This code here for relative jumps DEFB 'Exit',0 ; PMQT1: CALL PCRLF JP HMENU ;..... ; PMQT2: CALL CLOSE ; PMSKP0: CALL PRINT DEFB 'Next',0 JP PMSKP ;..... ; ; Reply to message ; PMREP: LD HL,MFROMF ; See if from user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JP Z,PMSKP0 ; If yes, can't answer own mail ; LD A,(ACESS) ; See if it's the Sysop CP 9 JR C,PMREP1 ; Not Sysop so can reply ; LD HL,MFROMF LD DE,SYSSTR ; Check "SYSOP" name LD B,6 CALL MATCH ; If yes, shouldn't answer own mail JP Z,PMSKP0 ; PMREP1: LD A,(LFLAG) ; Message left by this user? OR A JP NZ,PMSKP0 ; If yes, exit, can't answer own mail ; CALL PRINT DEFB 'Reply',0 PUSH IY ; Save the message array pointer LD A,0C9H LD (EXITM5),A ; Make ENTER: a subroutine LD (GETTO),A ; Make TO: lookup a subroutine CALL PMWAIT ; Check for Sysop name for From: XOR A LD (GETTO),A LD HL,MTOTMP ; CALL AUTOREP ; XOR A LD (EXITM5),A POP IY CALL MSGOPEN ; Done reply, now open messages file JP PMSKP ; Get next message, if any ;..... ; ; No more mail so quit ; NOMOR: CALL CLOSE LD A,(MSGFLG) OR A JR Z,NOMOR2 LD A,(NEWMSG) OR A JR NZ,(NOMOR1) LD A,(MFLAG) ; Any messages (even if old) for him? OR A JR Z,NOMOR1 ; If not, just show the menu CALL PRINT DEFB CR,'No new messages for you',0 JR PNOMOR1 ; Say no new messages to read ; NOMOR1: XOR A ; Null the flag, go tell no messages LD (MSGFLG),A JP NEWM1 ; NOMOR2: LD A,(PNEW) ; See if it's new private read OR A JR Z,NOMOR3 ; Nope, say no more XOR A LD (PNEW),A ; Clear NEW private flag LD HL,NEWMOR ; Tell him there are others JR PNOMOR ; NOMOR3: LD HL,(IMNXT) DEC HL LD (HIMSG),HL LD HL,NOMORE ; Now show no more messages can be read ; PNOMOR: CALL PRINTM ; PNOMOR1:XOR A LD (CNTN),A LD (RNEW),A LD (PNEW),A LD (PNEWX),A LD (MSGFLG),A JP HMENU ;..... ; NEWMOR: DEFB CR,LF,'No more new messages',0 NOMORE: DEFB CR,LF,'No more messages',0 ;..... ; ; Kill routine ; MKILL: CALL CLOSE ; Close MESSAGES.BBS file while we kill CALL MOPEN ; Open the MSGINDEX.BBS file LD HL,(CURREC) ; Restore this msg #'s record CALL GET ; Read it LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JP Z,MKILL1 ; If yes, can delete the msg LD HL,MFROMF ; See if from user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JP Z,MKILL1 ; If yes, can delete the msg LD A,(ACESS) ;; ;;==>> Determines who can delete messges that have been replied to ;; CP 8 ; Is this the Sysop or co-Sysop? JP NC,MKILL1 ; If yes, can delete the msg ; NOKILL: CALL PRINT DEFB CR,LF,CR,LF DEFB 'Message not killed...invalid user ID...' DEFB CR,LF,0 CALL CLOSE ; Close MSGINDEX.BBS file JP PMSKP ; Get next message ;..... ; MKILL1: LD DE,1 ; Set BYE's WRTLOC flag LD C,RMWRT CALL SPBDOS LD A,-1 ; Clearing record number LD (MREAD),A LD HL,(RRNO) ; Restore record number CALL PUT ; And write record back CALL CLOSE ; Close MSGINDEX.PSB file LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR NZ,MF1 ; No, go update receiver's mail flag LD A,(MFLAG) ; If to receiver, decrement mail flag OR A JR Z,MF3 ; Insure we don't get below zero DEC A ; One less message LD (MFLAG),A ; Store messages read flag JR MF3 ;..... ; ; Go update receiver's mail flag ; MF1: LD HL,MTOF ; Save the receiver's name away LD DE,MTOTMP LD BC,NAMLEN LDIR CALL USRGET JP NZ,MF3 LD (RRNO),HL ; Save the record CALL UOPEN ; Open USERS.BBS file LD A,(MAILF) ; Get number of messages OR A JR Z,MF2 ; If already zero, do not decrement DEC A ; Else decrement LD (MAILF),A LD HL,(RRNO) ; Get record number ; MF2: CALL PUT CALL CLOSE ; Close USERS.BBS file ; MF3: CALL PCRLF LD DE,0 LD C,RMWRT CALL SPBDOS ; Clear WRTLOC flag JP PMLOP1 ; Repeat message, showing now deleted ;..... ; ; Play current message again ; PMAGN: CALL PRINT DEFB 'A',0 ; PMAGN1: CALL PRINT DEFB 'gain',CR,LF,0 JP PMLOP1 ; Repeat same message ;..... ; ; Skip to next message ; PMSKP1: CALL PRINT DEFB 'kip',0 POP BC ; Clear the stack ; PMSKP: CALL PCRLF LD DE,2 ADD IY,DE JP PMLOP1 ; Go back for more ;..... ; PMBCK: CALL PRINT DEFB 'P',0 ; PMBCK1: CALL PRINT DEFB 'revious',CR,LF,0 POP BC ; Clear the stack PUSH IY POP HL ; Get current index LD DE,(MSGARR) ; Get start of index XOR A ; Clear carry SBC HL,DE ; Find out where we are JP Z,PMLOP1 ; We're at the start DEC IY ; Back up one-half DEC IY ; Back up the other half JP PMLOP1 ; Go show it. ;..... ; ;----------------------------------------------------------------------- ; =H= ; ;SCAN subroutine to disply message headers ; SCAN: CALL PRINT DEFB 'Header scan ',0 LD HL,S1 LD DE,SMSG LD BC,7 LDIR LD A,24 LD (TLINES),A CALL PCRLF CALL GETNUM ; SCNFND: CALL GETRC ; SCNDLP: CALL ABORT ; Let him out of scan or pause JP NZ,SCNEND ; DISPH: LD HL,(RRNO) ; Entry point for message read header CALL GET LD A,(ACESS) ; See if this is the Sysop ;; ;;==>> Determines who can read deleted messages ;; CP 8 ; Check and see if Sysop JP NC,SCNPVT ; Sysop, show all of them LD A,(MREAD) ; See if this one has been deleted CP -1 ; (Sysop has already skipped to SCNPVT) JR NZ,SCNPVT ; No JP SBUMP ; Yes ;..... ; SCNPVT: LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JP Z,SCNMSG ; Yes... LD HL,MFROMF ; See if from user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JP Z,SCNMSG ; Yes... LD A,(MPUBF) OR A ; Message Private? (1 = private) JP Z,SCNMSG ; Public = 0, deleted = -1 LD A,(ACESS) ; See if this is the Sysop ;; ;;==>> Following line sets level which can read all private and deleted ;; CP 8 ; Check and see if Sysop JP C,SBUMP ; No not Sysop, must be regular user ; SCNMSG EQU $ ; IF NMAREAS GT 1 LD A,(MAREA) ; Area number we are working with OR A ; Is it zero JR Z,SCNMS2 ; Yes no need to check further ; ; If here, we aren't scanning area 0 (GLOBAL), so check to see if ac- ; tive area value matches this message's area number. If it does, ; continue, else go back for more. ; LD HL,MANUMF ; Put message's area # address in 'HL' LD A,(MAREA) ; Get the area we want into 'A' CP (HL) ; Comp to this message's area number JP NZ,SBUMP ; If not equal go back for more JR SCNMS3 ;..... ; ; If here we are doing a GLOBAL scan (all areas), but we still need to ; check if the user has access to this area. Note: This is not re- ; quired for a scan of a specific area, for if the user doesn't have ; access to a area he would not be able to select the area in the ; first place. ; SCNMS2: LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR Z,SCNMS3 ; Yes...show no matter which area LD A,(MANUMF) ; Put this message's area # in 'A' LD C,A ; Place into 'C' LD B,0 ; Clear 'B' so BC has offset into table LD HL,ACCTBL ; Get address of table into 'HL' ADD HL,BC ; Add bias LD A,(HL) ; Table value into 'A' OR A ; Set the flags CP 1 ; Is it 1 (user has access)? JP NZ,SBUMP ; If not go back for more ; SCNMS3: CALL PRINT DEFB CR,LF,CR,LF,'Area: ',0 ENDIF ; NMAREAS GT 1 ; LD A,(MANUMF) LD (RMAREA),A ; Save for auto reply ; IF NMAREAS GT 1 CALL SAREA2 ENDIF ; NMAREAS GT 1 ; CALL PRINT ; IF NMAREAS EQ 1 DEFB CR,LF,CR,LF ENDIF ; NMAREAS EQ 1 ; DEFB 'Msg # ',0 LD HL,(MNUMF) CALL PB2ASC ; SCNM3C: DEFB 0 ; Makes a subroutine from DISPH to here LD B,A LD A,6 SUB B LD B,A LD HL,PADSTR CALL PRINTL LD IX,MDATF CALL PDATE LD B,A LD A,9 SUB B LD B,A LD HL,PADSTR CALL PRINTL LD HL,MTIMF ; Address the temporary buffer LD B,5 ; Print the date and time CALL PRINTL CALL PRINT DEFB ' ',0 LD HL,TIMZON ; Show area designaton such as "PST" LD B,3 CALL PRINTL LD B,53 LD A,(LENG) SUB B JP NC,A0 CALL PCRLF ; A0: CALL PRINT DEFB ' ',0 LD A,(MREAD) OR A ; 0 = not deleted, not read yet JR Z,A2 JP M,A1 CALL PRINT DEFB '(R)',0 JR A3 ; A1: CALL PRINT DEFB '=D=',0 JR A3 ; A2: CALL PRINT DEFB ' ',0 ; A3: CALL PRINT DEFB ' Subj: ',0 LD HL,MSUBF LD B,26 CALL PRINTL ; NSCNMSG:CALL PRINT DEFB CR,LF,'From: ',0 LD HL,MFROMF LD B,31 CALL PRINTN LD HL,PADSTR CALL PRINTL LD A,53 LD B,A LD A,(LENG) SUB B JP NC,B0 CALL PCRLF ; B0: CALL PRINT DEFB 'To: ',0 LD HL,MTOF LD B,NAMLEN CALL PRINTN LD A,(MPUBF) OR A ; Message Private JR Z,B1 CALL PRINT DEFB '

',0 ; B1: LD A,(SMSG) CP 's' JR NZ,SBUMP LD A,(MORFLG) OR A JR NZ,SBUMP LD B,4 LD A,(TLINES) SUB B LD (TLINES),A JP NZ,SBUMP CALL PRINT DEFB ' [more]',0 CALL GETCH PUSH AF CALL PRINT DEFB BS,BS,BS,BS,BS,BS,' ',0 POP AF CP 'K'-40H JR Z,SCNEND CP 'X'-40H JR Z,SCNEND CALL CAPS CP 'E' JR Z,SCNEND CP 'K' JR Z,SCNEND CP 'X' JR Z,SCNEND LD A,24 LD (TLINES),A ; SBUMP: LD DE,(RRNO) ; Get record INC DE ; And add one LD (RRNO),DE LD HL,(IMNDX) ; Past the end? AND A ; Clear carry flag SBC HL,DE JP NC,SCNDLP ; Nope... ; SCNEND: CALL CLOSE JP HMENU ;..... ; end of SCAN routine ;----------------------------------------------------------------------- ; SYSSTR: DEFB 'SYSOP',0 ; Used as 'from' when name not wanted ;..... ; ;----------------------------------------------------------------------- ; =E= ; ; Post mail to another user (enter a message) ; POSTM: CALL PRINT DEFB 'Enter a message',0 ; POSTM1: LD B,ALLLV ; See if access allows public messages LD A,(ACESS) CP B JP C,CMNT ; If not, gets a private comment LD A,(ACESS) CP 9 JP C,GETTO ; PMWAIT: LD A,(ACESS) ; See if this is Sysop CP 9 JP C,GETTO ; No, so skip this bit JP GETTO ;;; CALL PRINT ;;; DEFB CR,LF,CR,LF,'Use your Name or Sysop? ',0 ; PMW0: CALL GETCH JR Z,PMW0 CALL CAPS CP 'N' JR Z,PMWDON LD A,'S' ; PMWDON: LD (SYSBYT),A ; Store answer ;;; CALL ECHO ; And show it ; GETTO: NOP ; Inline modification for return CALL PCRLF1 LD B,NAMLEN-1 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'Message to? ',0 LD B,ALLLV ; See if access allows public messages LD A,(ACESS) CP B JP C,GETTO1 ; Access too low, skip next CALL PRINT DEFB ' for ALL',0 ; GETTO1: CALL PRINT DEFB CR,0 LD B,NAMLEN-1 LD C,20H XOR A ; Echo on LD (TOSYSOP),A ; Clear Sysop flag LD D,A ; Clear wrap flag CALL INPUT OR A JP Z,PUB ; Jump to ALL area LD HL,INBUF LD DE,MTOTMP LD BC,NAMLEN LDIR ; Save message 'to' LD HL,INBUF ; Point to input LD DE,UNAME ; See if he selected his own name LD B,NAMLEN CALL MATCH OR A JR NZ,GETTO2 CALL PRINT DEFB CR,LF,'(No messages to yourself)',0 JP GETTO ; GETTO2: LD HL,INBUF ; Point to input ; ; If message was to 'SYSOP' then substitute name at label 'SYSOP' ; as message 'To' name. ; AUTOREP:LD DE,SYSSTR ; See if to 'Sysop' LD B,6 CALL MATCH OR A JP NZ,POSTM2 ; Not 'Sysop' so search for entry LD A,1 LD (TOSYSOP),A LD HL,SYSOP ; Was 'Sysop' so move name at label LD DE,MTOTMP ; 'Sysop' to MTO stuff LD BC,NAMLEN LDIR ; POSTM2: XOR A LD (PMSND),A CALL PRINT DEFB CR,LF,CR,LF DEFB 'Checking user file...',0 CALL USRGET JR Z,GOTIT CALL PRINT DEFB CR DEFB 'User not found, check your spelling',0 JP GETTO ; GOTIT: LD (MTOREC),HL ; Save record number for later CALL PRINT DEFB ' Found',CR,LF,0 LD B,ALLLV ; See if access allows public messages LD A,(ACESS) CP B JP NC,ENTER ; Access >ALLLV so skip next LD A,1 LD (PMSND),A ; Force private JP ENTER ;..... ; PUB: LD B,ALLLV ; See if access allows public messages LD A,(ACESS) CP B JP C,HMENU ; Actually he was checked out before CALL PRINT DEFB 'ALL',CR,LF,0 LD HL,MTOTMP LD BC,29 XOR A LD (HL),A LD DE,MTOTMP+1 LDIR ; Clear message 'to' field LD HL,ALLMSG LD DE,MTOTMP LD BC,10 LDIR ; Move 'ALL' to buffer LD A,1 LD (ALLFLG),A ; Set message to 'all' flag ; ENTER: CALL PCRLF LD B,26 CALL PLINE ; Type the ______<< line CALL PRINT DEFB 'Subject? to exit',CR,0 LD B,26 XOR A ; Set input flags LD D,A LD C,A CALL INPUT OR A JP Z,EXITM5 ; Exit with LD DE,MSUBTMP LD HL,INBUF LD BC,26 LDIR ; Save subject ; CMNTE: CALL PCRLF1 CALL PRINT DEFB 'You can use up to ',0 LD H,0 LD L,MSGLIN CALL PB2ASC ; Show max message length CALL PRINT DEFB ' lines for this message' DEFB CR,LF DEFB 'Use a space in 1st column to add a blank line' DEFB CR,LF DEFB 'Use 2 to exit',0 LD C,RMTOS ; Time remaining CALL SPBDOS CALL PRINT DEFB 'Enter text... ',CR,LF,CR,LF,0 XOR A LD (CRS),A ; Clear the CR's counter LD (COLUMN),A ; Current column number LD (LINCNT),A LD (LSTLN),A ; Set last line routine LD (PNTCHR),A ; Zero printing character flag LD (SPCSTR),A ; Zero the 'no space yet' flag CALL LINNUM ; Show the current line # LD HL,0 ; Ready to 0 buffers LD IX,(MSG) ; Point to start of buffer LD BC,MSGBUF ; Get length of buffer ; ; Add any special delete characters here ; DEL EQU 7FH ; 'normal' delete key DELOS EQU 1FH ; ^- on the OS-1 ; MSLOP: PUSH BC CALL GETCH POP BC AND 7FH CP BS ; Normal backspace? JP Z,BCKSPC ; If yes, exit CP DEL ; Delete key used for backspace? JP Z,BCKSPC ; If yes, exit CP DELOS ; Special backspace key of some sort? JP Z,BCKSPC ; If yes, exit CP TAB ; Tab key to jump ahead on line? JP Z,CHKTAB ; If yes, exit CP ' ' ; Space character? JP Z,CHKSPC ; If yes, exit, show we got one CP CR ; New line requested? CALL Z,CRLF ; If yes, display CR-LF both CP ' '+1 JR C,MSLOP ; Must be a printable character CP '~'+1 JR NC,MSLOP LD (PNTCHR),A ; Have a printing character this line ; MSLOP1: CALL ENTCHR JR MSLOP ;..... ; CHRCNT: DEFB 0 ; Character count for word wrap transfer LINCNT: DEFB 0 ; Line count for messages PNTCHR: DEFB 0 ; Got a printing char. for auto-wrap SPCSTR: DEFB 0 ; Flag to show a space has been received ;..... ; ; Got printable character, add to buffer, then show it. First, see if ; if any room is left in the buffer, to continue the message. ; ENTCHR: PUSH AF ; Save the character DEC BC ; Buffer has a '0' to terminate LD A,B ; Check MSP of buffer length OR A ; Less than 255 characters available? JR NZ,ENTCH0 ; Nope, continue OR C ; Check LSP of buffer length JP Z,ENDBUF ; If Buffer is empty now, exit LD A,C ; See how far under 255 chars. we are CP 150 ; Under 150 characters left to go? CALL C,LSTLN ; If yes, warn user one time only ; ; Now check to see if line length would be exceeded ; ENTCH0: LD A,(COLUMN) ; See what column we are in now ; LIN1 EQU $+1 ; CP 72 ; Check maximum line length JP C,ENTCH7 ; If less, can continue normally LD A,(SPCSTR) ; Had any space characters yet? OR A JR NZ,ENTCH1 ; If yes, exit POP AF ; Set the stack correctly JR ENTCH6 ; No space char. yet, beep and exit ; ; Line will be too long, so remove characters from buffer back to last ; printing character in previous word, store temporarily, insert CR-LF ; then place the characters on next line and continue. ; ENTCH1: XOR A ; Zero first character in temp. buffer LD HL,TBUFF LD (HL),A ; Zero 1st character in TBUFF ; ; Next store current typed character into temporary buffer, if a space ; handle as CRLF unless no printing characters are on the line yet. ; POP AF ; Get typed character back CP ' ' ; See if it was a space JR NZ,ENTCH2 ; If not, exit LD A,(PNTCHR) ; See if printing character yet OR A JP Z,ENTCH6 ; No, beep and ignore LD A,' ' ; Restore the character CALL ENTCH8 ; Enter the space into the message JP TURNUP ; Now turn up a new line ; ENTCH2: INC HL ; Next TBUFF position LD (HL),A ; Store typed character temporarily ; ; Now get into the message buffer and pick off characters back to end of ; previous word. Store into temporary buffer, quit if a space character. ; ENTCH3: INC HL ; Next TBUFF position DEC IX ; Previous message buffer address LD A,(IX) ; Get the character from message buffer CP ' ' ; See if a space character, yet JR Z,ENTCH4 ; If yes, exit CP '-' ; Accomodate hyphenated words JR Z,ENTCH4 ; Exit and turn up a new line LD (HL),A ; Store the character temporarily PUSH BC PUSH HL PUSH IX CALL PRINT DEFB BS,' ',BS,0 ; Remove it from the display POP IX POP HL POP BC JR ENTCH3 ; Keep looping until space char. found ; ; Found a space character or hyphen ; ENTCH4: INC IX ; Position to first printing character CALL TURNUP ; Display a new line on CRT ; ; Now start replacing characters from temporary buffer to next line ; ENTCH5: DEC HL ; Get previous temp. buffer position LD A,(HL) ; Get the character there OR A RET Z ; CALL ENTCH8 ; Display and enter the character JP ENTCH5 ; Continue until done ; ; Line will be too long with this character and no spaces have been sent ; yet, so can't use auto-wrap at this point. Beep and wait for a ; or backspace to some other character. ; ENTCH6: PUSH BC PUSH HL CALL PRINT ; Sound off as can't continue at present DEFB BEL,0 POP HL POP BC RET ; Return for next character ; ENTCH7: POP AF ; Get the character back ; ENTCH8: LD (IX),A ; Add to buffer CALL ECHO ; Show character INC IX ; Increment it for next character LD A,(COLUMN) ; Get current position on line INC A LD (COLUMN),A XOR A ; In meanwhile, zero it just in case LD (IX),A ; Float a 0 at end of message LD (CRS),A ; Reset the consecutive CR count RET ;..... ; BCKSPC: LD A,(COLUMN) ; Get position on the line OR A JP Z,MSLOP ; If zero, can't backspace DEC A LD (COLUMN),A ; This backspace go to left margin? JR NZ,BCKSP1 ; If not, exit LD (PNTCHR),A ; Reset flag for printing character LD (SPCSTR),A ; Reset flag for got a space character LD A,1 LD (CRS),A ; Set the consecutive CR count ; BCKSP1: DEC IX ; Move the buffer pointer back one XOR A ; Float a 0 at end of message LD (IX),A INC BC PUSH BC PUSH IX CALL PRINT DEFB BS,' ',BS,0 ; Backspace one POP IX POP BC JP MSLOP ;..... ; ; Check for a tab, expand up to 8 spaces if yes, quit prior to end of ; line. ; CHKTAB: LD A,(COLUMN) ; Get position on line ; LIN2 EQU $+1 ; CP 72 ; At end now? JP NC,MSLOP ; If yes, exit ; LIN3 EQU $+1 ; CP 72-7 ; Prevent a partial tab at end of line JR C,CHKT1 ; No close to end, handle normally AND 7 ; Stop at normal tab before line end JP Z,MSLOP ; If at tab stop, quit ; CHKT1: LD A,' ' CALL ENTCHR LD A,(COLUMN) AND 7 JR NZ,CHKTAB JP MSLOP ;..... ; CHKSPC: LD (SPCSTR),A ; Keep track of last space received JP MSLOP1 ;..... ; ; Enter and display a CR-LF ; CRLF: CALL CRCOM ; Call common section LD A,(CRS) ; Bump # cr in a row INC A ; And if over 3 then quit LD (CRS),A CP 2 JP NC,EXITCR ; Two consecutive CR, so quit LD A,CR LD (IX),A ; Store in the buffer CALL ECHO ; Show the CR on the CRT INC IX ; Increment to next position LD A,LF CALL ECHO ; Display a line feed on CRT XOR A ; Clear the A register LD (COLUMN),A ; Show in Column 0, now LD (PNTCHR),A ; Reset flag for printing character LD (SPCSTR),A ; Reset flag for got a space character LD (IX),A ; Terminate message with a 0 CALL LINNUM ; Show next line number RET ;..... ; CRCOM: DEC BC ; Add back one count for this CR LD A,B ; More that 256 characters left? OR A RET NZ ; If yes, everything is ok OR C ; See if out of space entirely JR Z,CRCOM1 ; If yes, reset stack and exit LD A,C ; See if only two lines left CP 150 ; Last 150 characters? JP C,LSTLN ; If yes, tell user only 2 lines left RET ; CRCOM1: POP HL ; Remove CALL Z,CRLF, or CALL ENTCHR POP HL ; Remove CALL CRCOM from stack ; ; Puts a line number while writing a message ; LINNUM EQU $ ; IF NOT LINNOS RET ENDIF ; NOT LINNOS ; IF LINNOS PUSH BC PUSH HL LD A,(LINCNT) INC A LD (LINCNT),A CP 10 JR NC,LINNUM1 CALL PRINT DEFB ' ',0 ; LINNUM1:LD A,(LINCNT) LD H,0 LD L,A CALL PB2ASC CALL PRINT DEFB ': ',0 POP HL POP BC RET ENDIF ; LINNOS ;..... ; ENDBUF: POP AF ; Clear stack INC BC ; Re-align counter DEC IX PUSH BC ; Save count PUSH IX ; Save position XOR A LD (IX),A ; Set end of message CALL PRINT DEFB CR,LF,CR,LF DEFB '++ Buffer Full ++',0 JP EXITM ;..... ; LSTLN: NOP ; Get's changed to a RET PUSH BC PUSH IX CALL PRINT DEFB CR,LF,'++ Only 2 lines left ++',CR,LF,0 LD A,0C9H ; Disable last line message so it can LD (LSTLN),A ; Only be shown the one time POP IX POP BC RET ;..... ; TURNUP: CALL CRCOM ; See if any room left, etc. PUSH BC PUSH HL PUSH IX CALL PCRLF POP IX POP HL POP BC LD A,1 LD (CRS),A XOR A LD (COLUMN),A LD (PNTCHR),A LD (SPCSTR),A CALL LINNUM ; Show next line number RET ;..... ; EXITCR: POP HL ; Remove 'CALL CRLF' from stack LD HL,(MSG) LD A,(HL) CP CR ; Starts with a CR JR NZ,XITCR1 ; Nope, exit normally INC HL LD A,(HL) OR A ; Insurance.. JR NZ,XITCR1 ; Nope, exit normally LD BC,MSGBUF PUSH BC ; Reset to zero PUSH HL ; Reset to zero JP ABXIT ; XITCR1: PUSH BC ; Save buffer length for later handling PUSH IX ; Save address for later handling JR EXITM1 ;..... ; ; Exit writing a message routines ; EXITM: CALL PCRLF ; EXITM1: CALL PRINT DEFB CR,' ',CR,LF DEFB 'Save, Abort, Continue, Edit, List',0 LD A,(ALLFLG) ; This message to ALL? OR A JR NZ,EXITM3 ; If yes, can't be private LD A,(ACESS) ; This message from the Sysop? ;; ;;==>> Determines who uses 'Private' option regardless of restrictions ;; CP 8 JP NC,EXITM2 ; Sysop and co-Sysop can send private LD B,ALLLV ; See if access allows public messages LD A,(ACESS) CP B JP C,EXITM3 ; Not to ALL, and private not allowed ; IF PRVSYS LD HL,MTOTMP LD DE,SYSOP ; Compare to real Sysop name LD B,NAMLEN CALL MATCH OR A JP Z,EXITM2 ; If to Sysop, exit ENDIF ; PRVSYS ; LD A,(TOSYSOP) ; This note to the Sysop? OR A ; IF PRVSYS JR NZ,EXITM2 ; Can be private ENDIF ; PRVSYS ; IF NOT PRVSYS JR NZ,EXITM3 ; Exit, not allowing private ENDIF ; NOT PRVSYS ; IF NOT PRIVATE JR EXITM3 ; If not, skip private ENDIF ; NOT PRIVATE ; EXITM2: CALL PRINT DEFB ', Private',0 ; EXITM3: CALL PRINT DEFB ': ',0 CALL EATCHR ; Kill any stray characters... ; EXITM4: CALL GETCH CP CR JP Z,CONT CALL CAPS CP 'A' JP Z,ABXIT CP 'C' JP Z,CONT CP 'E' JP Z,EDIT CP 'L' JP Z,LISTE ; Actual list is a subroutine this will call CP 'S' ; Want to store the message? JP Z,SAVE CP 'P' ; Requesting private? JR NZ,EXITM4 ; If none of these, ask again LD A,(ALLFLG) ; See if message is to ALL OR A JR NZ,EXITM4 ; If yes, can't be private, ask again LD A,(ACESS) ; See if this is Sysop or co-Sysop ;; ;;==>> Determines who can send private messages regardless of restrictions ;; CP 8 JP NC,PRVT ; If yes, they can send private ; IF PRVSYS LD HL,MTOTMP LD DE,SYSOP ; Compare to real Sysop name LD B,NAMLEN CALL MATCH OR A JP Z,PRVT ; If to Sysop, exit ENDIF ; PRVSYS ; LD A,(TOSYSOP) ; Message to Sysop? OR A ; IF PRVSYS JP NZ,PRVT ; Ok can send private to Sysop ENDIF ; PRVSYS ; IF NOT PRVSYS JP NZ,EXITM4 ; Exit if not allowing private ENDIF ; NOT PRVSYS ; IF PRIVATE ; Allowing private messages to users? JP PRVT ; If ;yes, exit, else fall through ENDIF ; PRIVATE ; JR EXITM4 ; Just in case ;..... ; ABXIT: CALL PRINT DEFB 'Abort' DEFB CR,LF,CR,LF DEFB 'Abort this message ? ',0 CALL YESNO CP 1 JR Z,ABXIT1 JP EXITM ; ABXIT1: POP IX POP BC ; EXITM5: NOP ; Inline mod to force return JP HMENU ;..... ; end of EXIT routines ;----------------------------------------------------------------------- ; edit routine EDIT: CALL PRINT DEFB 'Edit',0 XOR A ; Clear edit buffers LD HL,EBUF LD (HL),A LD DE,EBUF+1 LD BC,129 ; Including ELEN and RLEN LDIR CALL PRINT DEFB CR,LF,CR,LF DEFB 'Characters to change: ',0 LD B,64 XOR A LD C,A LD D,A CALL INPUT OR A JP Z,EXITM LD (ELEN),A ; Save length LD B,0 LD C,A LD HL,INBUF LD DE,EBUF LDIR ; Move search edit string to buffer CALL PRINT DEFB CR,LF DEFB 'Change them to these: ',0 XOR A LD B,64 LD C,A LD D,A CALL INPUT LD (RLEN),A ; Save length OR A JR Z,CHKSTR ; If no replacement then skip move LD B,0 LD C,A LD HL,INBUF LD DE,RBUF LDIR ; Move new string into place ; CHKSTR: LD HL,EBUF ; Point to search string LD DE,(MSG) ; And message start ; SELOP: LD A,(DE) CP (HL) JR Z,SELOP0 INC DE ; Next in buffer LD A,(DE) OR A ; At end? JR NZ,SELOP ; Not yet so try again JP NOSTR ; String not found ; SELOP0: PUSH DE PUSH HL ; Save current positions ; SELOP1: INC HL INC DE LD A,(HL) ; At end of edit string yet? OR A JR Z,SELOP2 ; Got a match LD A,(DE) CP (HL) JR Z,SELOP1 POP HL POP DE INC DE ; Point to next in buffer JR SELOP ; Go look some more ; SELOP2: POP HL ; Get rid of junk PUSH DE ; Save end of found string LD A,(ELEN) LD B,A LD A,(RLEN) CP B ; Compare lengths of strings JP Z,REQU JP C,RLESS ; ; ------------------------------------------------------------------ ; | While all the message routines use the stack, this section in : ; : particular is EXTREMELY stack intensive. Use a LOT of care if : ; : you change ANY of this. | ; ------------------------------------------------------------------ ; ; These routines enter with stack as:; ; top - end of found string ; next - start of found string ; next - current pos in buffer ; next - characters remaining in buffer ; RGTR: SUB B LD E,A LD D,0 ; De=diff LD (DIFF),DE ; Need later POP IY ; Get end POP BC ; Get start POP IX ; Get current POP HL ; Get chars left PUSH HL ; And restore them PUSH IX ; And current PUSH BC ; And start PUSH IY ; And end AND A ; Clear carry SBC HL,DE ; Hl must be > de JP C,LNGSTR ; Too long so abort LD (NEWFRE),HL ; Save characters free for later PUSH IX ; End of buffer POP HL ; In hl PUSH HL ADD HL,DE ; New end in hl EX DE,HL ; De=move to POP HL ; Hl=move from PUSH IY POP BC ; Bc=end of found string PUSH HL ; Save move from AND A ; Clear carry SBC HL,BC ; Hl=# characters to move INC HL ; Need one more moved PUSH HL POP BC ; Bc=count POP HL ; Hl=move from LDDR ; Move back to open space up POP HL ; Don't need end anymore POP DE ; Move to LD HL,RBUF ; From here LD A,(RLEN) LD C,A LD B,0 ; This many LDIR POP IX POP BC LD HL,(NEWFRE) PUSH HL ; Save new characters remaining PUSH IX ; And current pos in buffer POP HL ; To hl LD DE,(DIFF) ADD HL,DE PUSH HL ; Save new position on stack JP EXITM ;..... ; RLESS: LD A,(RLEN) OR A JR Z,RL0 ; If 0 then we are deleteing so skip first move LD C,A LD B,0 POP HL ; Get end of found string POP DE ; Get start of found string PUSH HL ; Need end later LD HL,RBUF LDIR ; Move new string to old position JR RL1 ; Skip next unless no replacement string ; RL0: POP HL ; End of found string POP DE PUSH HL ; For next pop ; RL1: POP HL ; Move from here (de set from ldir or rl0) POP BC ; Get current buffer position PUSH BC ; Save again PUSH DE ; Save end of old string (in buffer) PUSH HL ; Save start of string to move up (in buffer) AND A ; Clear carry PUSH HL PUSH BC ; Reverse BC and HL POP HL POP BC SBC HL,BC ; HL=characters to move less one INC HL ; Re-align PUSH HL POP BC ; Count POP HL ; From POP DE ; To LDIR ; Move rest of string up LD A,(RLEN) LD B,A LD A,(ELEN) SUB B LD E,A LD D,0 ; DE=diff POP IX POP HL ; Get characters left ADD HL,DE ; Update count PUSH HL ; Save it PUSH IX POP HL ; Get current position AND A SBC HL,DE ; Update PUSH HL JP EXITM ;..... ; REQU: LD A,(RLEN) LD C,A LD B,0 POP DE ; Don't need end of found string address POP DE ; Get start of found string LD HL,RBUF LDIR ; Move new string into buffer JP EXITM ;..... ; LNGSTR: POP HL POP HL ; Clear stack CALL PRINT DEFB CR,LF,CR,LF DEFB 'Replacement string too long.',0 JP EXITM ;..... ; NOSTR: CALL PRINT DEFB CR,LF,CR,LF DEFB 'Old string not found...',0 JP EXITM ;..... ; CONT: CALL PRINT DEFB 'Continue',CR,LF,CR,LF,0 POP IX POP BC DEC BC ; Buffer full when 1 byte left (!) LD A,B OR C ; See if at end of buffer INC BC ; Re-align counter JR Z,NOCONT ; Nope, so go PUSH BC PUSH IX CALL PRINT DEFB 'Continue entering text...' DEFB CR,LF,CR,LF,0 LD A,(LINCNT) ; Returning so show correct line count DEC A LD (LINCNT),A CALL LINNUM ; Replace the erased line number POP IX POP BC JP MSLOP ; Go for it... ;,,,,, ; NOCONT: PUSH BC PUSH IX CALL PRINT DEFB 'Can''t continue, at end of buffer.',CR,LF DEFB 'Use E)dit to delete from and change message...',0 JP EXITM ;..... ; end of EDIT routine ;----------------------------------------------------------------------- ; displays messages LISTE: CALL PRINT DEFB 'List',0 LD HL,(MSG) LD IX,(MSG) LD A,24-2 ; Number of lines available on CRT LD (TLINES),A ; If [more] is shown CALL LISTA JP EXITM1 ; LIST EQU $ ; IF NMAREAS GT 1 LD A,24-7 ; If not stopping one less needed ENDIF ; NMAREAS GT 1 ; IF NOT (NMAREAS GT 1) LD A,24-6 ; If not stopping one less needed ENDIF ; NOT (NMAREAS GT 1) ; IF HDRSTP AND (NMAREAS GT 1) LD A,24-9 ; Extra 2 lines in header if stopping ENDIF ; HDRSTP AND (NMAREAS GT1) ; IF HDRSTP AND NOT (NMAREAS GT 1) LD A,24-8 ; Extra 2 lines in header if stopping ENDIF ; HDRSTP AND NOT (NMAREAS GT 1) ; LD (TLINES),A ; If [more] is shown LD BC,128 LD HL,(MSG) ; Independent check for line length LD IX,(MSG) ; Point to buffer ADD HL,BC ADD IX,BC ; LISTA: PUSH HL CALL PCRLF1 ; Start a new line POP HL XOR A LD (COLUMN),A ; Current column number LD (PNTCHR),A ; Reset printing character flag LD (SPCSTR),A ; Flag to show a space has been received ; ; Count the text one character at a time. If too many for the desired ; maximum line length, do a word wrap on the local display. ; LSTLP: LD A,(HL) ; Get the character OR A JP Z,LSTLP1 ; End of message, exit CP CR ; End of line character? JP Z,LSTNEW ; See if CR should be retained CP ' ' ; See if 01 or other non-printing JR C,LSTLP4 ; Skip any non-printing characters ; LSTLP1: LD A,(COLUMN) ; Increment for this character INC A LD (COLUMN),A LD A,(HL) ; Get the character back again CP CR+1 ; See if a JP C,SHOLIN ; If yes, send the new line CP ' ' JR NZ,LSTLP2 LD (SPCSTR),A JR LSTLP3 ;..... ; LSTLP2: LD (PNTCHR),A ; Show a printing character on the line ; LSTLP3: LD A,(COLUMN) ; See what column we are in now ; LIN4 EQU $+1 ; CP 72 JP NC,LSTWRP ; Exit if line is now too long ; LSTLP4: INC HL JP LSTLP ; Get the next character ;... ; ; Line was too long, see why and fix the count accordingly ; LSTWRP: LD A,(HL) ; Get the character back CP ' ' ; Space at end of full line? JR NZ,LSTWR3 ; Not a space, exit PUSH HL ; Save current location CALL LSTSP1 ; Eliminate any trailing spaces POP HL ; Get the original location again PUSH HL ; Save once more ; LSTWR1: INC HL ; Increment next position in line LD A,(HL) ; Get that character CP ' ' ; Double space after a period? JR NZ,LSTWR2 ; If not exit, done LD (HL),3 ; Else eliminate the extra space JP LSTWR1 ; Check/eliminate any more spaces ;... ; LSTWR2: POP HL ; Restore the buffer location JR SHOLIN ; Go show the line ;... ; LSTWR3: DEC HL LD A,(COLUMN) DEC A LD (COLUMN),A LD A,(SPCSTR) ; Any spaces yet? OR A JR Z,SHOLIN ; If not show what we have so far LD A,(HL) CP '-' JR Z,SHOLIN CP ' ' JR NZ,LSTWR3 ; Neither of these, keep backtracking PUSH HL CALL LSTSP ; Check for any trailing spaces POP HL JR SHOLIN ; Then display the line ; LSTSP: DEC HL ; Don't check current location ; LSTSP1: LD A,(HL) ; Get the character CP ' ' ; A space character? RET NZ ; Exit if not ; LD (HL),3 ; Don't keep the space JR LSTSP ; See if any more spaces ;... ; ; Ok all finished, now, display the line ; SHOLIN: LD A,(IX) OR A ; Message all finished? RET Z ; Yes, exit CP CR JR Z,LSTCR ; Exit if at end of this line CP 3 JR NZ,SHOLN1 LD (IX),' ' ; Change the "Ignore char" back to space ; SHOLN1: CP ' ' JR C,SHOLN2 ; Ignore non-printing CALL ECHO ; Display the character SHOLN2: LD A,(COLUMN) DEC A LD (COLUMN),A JR Z,LSTCR ; If zero, no so add one ; LSTWR5: INC IX JR SHOLIN ; Do the next character ;..... ; ; Displays CR, resets the column counter, then checks to see if time for ; the [more] pause, returns with LF in 'A', not displayed yet. ; LSTCR: CALL LSTUP ; Display a CR and check for [more] OR A ; TWAIT want to abort? RET Z ; CALL ECHO ; Display the LF CALL ABORT ; Check for pause, skip or abort RET NZ ; INC HL ; Increment for this character PUSH HL ; Transfer HL address to IX POP IX JP LSTLP ; Back to work for the next line ;... ; LSTUP: XOR A LD (COLUMN),A ; Reset column counter LD (PNTCHR),A ; Reset printing character flag LD (SPCSTR),A ; Reset space character flag LD A,CR CALL ECHO LD A,(CNTN) ; In non-stop continuous mode? OR A LD A,LF RET NZ ; If yes, prohibit the [more] message JP TWAIT ; Otherwise allow the [more] message ;..... ; ; Found a CR, check following character to see if: ; ; 1) end of message - keep CR ; 2) space - keep CR, as intentional new line ; 3) printing character - means this was a short line so remove CR ; LSTNEW: INC HL ; Check next character LD A,(HL) OR A ; See if end of message JR Z,LSTN1 ; If yes, handle this CR normally CP ' ' ; Is it a space for blank line? JR Z,LSTCK ; If yes, handle normally DEC HL ; Back to normal position LD A,(PNTCHR) ; Current line have any printing chars? OR A JP Z,LSTCK1 ; If not, keep the CR and check spaces LD (HL),' ' ; Change the CR to a space character JP LSTCK1 ; Now check for any trailing spaces ;... ; LSTN1: DEC HL JP LSTLP1 ; Keep the CR, handle normally ;..... ; ; Keeping the CR, so check for any trailing spaces ; LSTCK: DEC HL ; Back to the CR location ; LSTCK1: PUSH HL ; Save this location for now LD A,(SPCSTR) ; Current line have any spaces? OR A JR Z,LSTCK3 ; If not, can't have any trailing spaces ; LSTCK2: DEC HL ; Previous location on line LD A,(HL) ; Get the previous character CP ' ' ; Was it a trailing space character? JR NZ,LSTCK3 ; If not, ext LD (HL),3 ; Eliminates the trailing space JR LSTCK2 ; Check for additional trailing spaces ; LSTCK3: POP HL ; Back to the original CR location JP LSTLP1 ; Handle normally ;..... ; end of display messages ;----------------------------------------------------------------------- ; save the message ; PRVT: CALL PRINT DEFB 'Private ',0 LD A,1 LD (PMSND),A ; Make it private JR SAVEP ; SAVE: CALL PRINT DEFB 'Save',0 ; SAVEP: POP IX POP BC ; Must clear stack first LD HL,MSGBUF ; Get maximum characters allowed AND A ; Clear carry SBC HL,BC ; HL=number of characters in message INC HL ; Plus one LD DE,64 LD C,0FFH ; Set up quotient ; DLOP: INC C AND A ; Clear carry SBC HL,DE ; Divide by 64 to get number of lines JR NC,DLOP ADD HL,DE ; Remainder back in HL LD A,C ; Get number of lines INC A ; Bump # lines by one for 'from' info INC A ; And one for 'to' and time/date LD (LINES),A LD A,H OR L ; If any remainder then need extra line JR Z,NOREM LD A,(LINES) INC A LD (LINES),A ; Save new value ; NOREM: CALL PRINT DEFB CR,LF DEFB 'Updating index, message and user files...',0 LD DE,1 LD C,RMWRT CALL SPBDOS ; SET WRITE LOCK LD A,(PMSND) ; See if this is public msg to a user OR A JR NZ,USET ; Yes so set user record LD A,(ALLFLG) ; See if this is to 'all' or a user OR A JR NZ,ALLSKP ; Yes so skip next ; ; Set flag in 'To' user's record so he's bumped to mail next signon ; USET: CALL UOPEN ; Read 'To' user into buffer LD HL,(MTOREC) ; Record # saved when we searched for 'to' user CALL GET LD A,(MAILF) ; Flag mail waiting INC A ; Show one more LD (MAILF),A ; And set it LD HL,(RRNO) ; Get record number CALL PUT ; And write record back CALL CLOSE ; ; Message is to 'ALL' so we don't have to flag a user's record. Just ; see if space is free in the message index and, if so, use it. Else ; we will extend messages file with a new record. ; ALLSKP: CALL MOPEN CALL CLRBUF ; Nice clean buffer ; ; Have to open new record for message in MSGINDEX so set up for it ; LD HL,(IMRNM) LD (MSTRF),HL ; Set message record number LD A,(LINES) LD (MBLKF),A ; & number lines (records) LD D,0 LD E,A ADD HL,DE ; Calc new record start LD (IMRNM),HL ; And store in index LD HL,(IMNDX) ; And bump number records in index INC HL LD (IMNDX),HL ; And bump number records in index LD (MRECF),HL ; Store record number in MSGINDEX LD (RRNO),HL ; Set record number in buffer ; ; Now write the MSGINDEX record # determined above ; WRITE: CALL GETTIM ; Get date/time string LD HL,(IMNXT) ; Next message number LD (MNUMF),HL ; Make it this message LD HL,MTOTMP LD DE,MTOF LD BC,NAMLEN LDIR ; Set message 'to' field LD HL,TIME ; Get the current time LD DE,MTIMF ; Put it in MSGINDEX.BBS LD BC,5 ; Just the hour and minutes is ample LDIR LD IY,IDATE LD IX,MDATF ; And date LD A,(IY) LD (IX),A LD A,(IY+1) LD (IX+1),A LD A,(IY+2) LD (IX+2),A LD IY,PMSND ; Private flag LD A,(IY) LD (MPUBF),A LD DE,MSUBF LD HL,MSUBTMP LD BC,26 LDIR ; Set subject field PUSH DE ; Save next buffer address ; ; See if this is Sysop and if he wants his name or 'SYSOP' used in the ; 'From' string ; LD A,(ACESS) ;; ;;==>> Sysop want to use From: Sysop or his normal name in msg header? ;; CP 9 JP C,NOSYS ; No, not Sysop so store user's name LD A,(SYSBYT) ; Is Sysop, does he want to use his name? CP 'N' JR NZ,NOSYS ; Wanted to use his name LD HL,SYSSTR ; Wants to store 'Sysop' as name LD BC,6 JR ISYS ; NOSYS: LD HL,UNAME ; Get user's name LD BC,NAMLEN ; ISYS: POP DE LDIR CALL ISYS1 JP ISYS3 ; ISYS1 EQU $ ; IF NMAREAS GT 1 LD A,(ACESS) ;; ;;==>> Asks Sysop, etc. for area to put message in after a reply ;; CP 8 JR NC,ISYS0 ENDIF ; NMAREAS GT 1 ; LD A,(RMAREA) ; Get current area ; IF NMAREAS GT 1 OR A JR NZ,ISYS2 ; See if it's zero (GLOBAL), if not, ok LD A,(MAXAREA) ; See if user has access to multiple areas CP 1 ; If not just stuff a 1 in MSGINDEX record JR Z,ISYS2 ; Go stuff a 1 ; ISYS0: XOR A ; Else go get the subject (area) for DEC A ; this message LD (MLSEL),A CALL PRINT DEFB CR,LF,CR,LF,'Select area for message',CR,LF,0 CALL GAREA1 ; Get the area number from the user ENDIF ; NMAREAS GT 1 ; ISYS2: LD (MANUMF),A LD HL,(RRNO) CALL PUT CALL CLOSE ; MSGINDEX closed RET ; ; Now update INDEX information ; ISYS3: LD HL,(MSTRF) ; Get record number for first line LD (STRTMP),HL ; Save it for later LD HL,(IMNXT) ; Next message number INC HL LD (IMNXT),HL ; Update next message number LD HL,IDATE ; Update index information LD DE,IDATEF LD BC,NDXLEN LDIR CALL IOPEN CALL PUT CALL CLOSE ; Index closed ; ; And finally, write each 64 byte line to sequential records ; CALL MSGOPEN LD HL,(STRTMP) ; Set record number for first line LD (RRNO),HL ; ; Now we create the first two records which are the message header with ; time/date, to/from, subject stuff ; CALL CLRBUF ; Nice clean buffer LD HL,MSG1 ; Move first of header to buffer LD DE,RNDBUF LD BC,6 LDIR LD HL,DATE ; And date string LD BC,8 LDIR LD A,' ' LD (DE),A INC DE LD HL,TIME ; And time string LD BC,8 LDIR LD A,CR LD (DE),A INC DE LD HL,MSG2 ; Next header bit LD BC,6 LDIR LD HL,MTOTMP ; Who to LD BC,NAMLEN LDIR XOR A ; Insure clean buffer LD (DE),A INC DE LD A,CR ; End of line LD (DE),A CALL STRIP ; Waste the nulls LD HL,(RRNO) ; Get record # CALL PUT ; And write it CALL CLRBUF ; Clear the buffer for next stuff ; ; Now get 'From' name and move into place ; LD HL,MSG3 LD DE,RNDBUF LD BC,6 LDIR ; Move characters before 'from' name PUSH DE ; Save next buffer address ; ; See if this is Sysop and if he wants his name or 'SYSOP' used in the ; 'From' string ; LD HL,UNAME ; Move name to random buffer LD DE,SYSOP ; Unless from name at label 'Sysop' LD B,NAMLEN CALL MATCH ; See if so... OR A JR NZ,NOTSYS ; No, not Sysop so store user's name ; SYSBYT EQU $+1 ; In-code modification ; LD A,0 ; Is Sysop, does he want to use his name? CP 'S' JR NZ,NOTSYS ; Wanted to use his name LD HL,SYSSTR ; Wants to store 'Sysop' as name LD BC,6 JR ISSYS ; NOTSYS: LD HL,UNAME ; Get user's name LD BC,NAMLEN ; ISSYS: POP DE ; Get buffer address back LDIR ; Move users name LD A,CR LD (DE),A ; Last carriage return INC DE LD (DE),A ; Twice CALL STRIP ; Get rid of nulls LD HL,(RRNO) INC HL CALL PUT ; Write second record LD HL,(RRNO) INC HL LD (RRNO),HL ; Save updated record number LD IY,(MSG) ; Point to message LD A,(LINES) DEC A ; Less 2 for time/date stuff ... DEC A ; That has already been written LD B,A ; Set up counter CALL WRTLP CALL CLOSE LD DE,0 LD C,RMWRT CALL SPBDOS ; Clear write lock JP EXITM5 ;..... ; ; Take the nulls out of the record being written to MESSAGES.BBS. This ; is only needed on the first 2 records which contain data moved from ; other areas that use nulls to pad the fields. ; STRIP: LD HL,RNDBUF ; Start of buffer LD B,MSGLEN ; Length of each message record ; STRIP0: LD A,(HL) ; Get character OR A ; Is it a null? JR NZ,STRIP1 ; Not 0 INC A ; Yes, so change 0 to 1 ; STRIP1: LD (HL),A ; Save character INC HL ; Next character DJNZ STRIP0 ; Do entire buffer RET ; Done ;..... ; ; Clear buffer for next ; CLRBUF: XOR A LD HL,RNDBUF LD (HL),A LD DE,RNDBUF+1 LD BC,SYSLEN-1 ; Longest used length LDIR RET ;..... ; ; Header data strings... ; MSG1: DEFB 'Left: ' ; 6 characters before time/date MSG2: DEFB 'To : ' ; 6 characters before who to MSG3: DEFB 'From: ' ; 6 characters before who from ;..... ; ;----------------------------------------------------------------------- ; ; Comes here when a new user tries to leave a message. Controlled by ; 'ALLLV' in the HBBSHDR options. ; CMNT: XOR A LD (ALLFLG),A LD B,ALLLV ; See if access allows public messages LD A,(ACESS) CP B JP NC,CMNTA ; Access >ALLLV so skip next LD A,1 LD (PMSND),A ; Force private JP CMNTB ; CMNTA: XOR A LD (PMSND),A ; CMNTB: LD A,'N' LD (SYSBYT),A ; Clear Sysop personal message byte LD HL,SYSOP ; To 'Sysop' so move name at label LD DE,MTOTMP ; 'Sysop' to MTO stuff LD BC,NAMLEN LDIR CALL PCRLF CALL USRGET JP Z,ENTER CALL PCRLF CALL PRINT DEFB 'SYSOP not found',0 JP HMENU ;..... ; ;----------------------------------------------------------------------- ; =P= ; ; Print the CALLERS file for an alphabetic character ; PCLRS: CALL PRINT DEFB 'Previous callers',CR,LF,CR,LF,0 LD HL,CALLRS CALL OPEN CP 0FFH ; Did it exist? JR NZ,PCLRS1 CALL PRINT DEFB CR,LF DEFB 'CALLERS file not found',CR,LF,0 JP MCMD ; PCLRS1: LD A,23-5 ; Scrolling for first page LD (TLINES),A LD HL,64 LD (RRSZ),HL ; Set record size LD HL,0 ; Get record number CALL GET LD HL,(RNDBUF) ; Is first 2 bytes of record 0 LD (RRNO),HL ; Our starting record # LD IX,LINES LD (IX),100 ; Number of previous users to look at ; PCLRS2: LD HL,(RRNO) DEC HL LD A,H OR L ; Record zero? JR Z,PCLRS3 ; Yup...get out DEC (IX) ; Decrement the count JP Z,PCLRS3 ; Looked at max number requested yet? CALL GET ; Nope... LD HL,RNDBUF CALL PRINTM ; Print it to the null CALL ABORT JP NZ,PCLRS3 CALL TWAIT ; Had a full screen yet? PUSH HL CALL PRINT DEFB CR,0 POP HL JR PCLRS2 ; PCLRS3: CALL CLOSE JP MCMD ;..... ; ;----------------------------------------------------------------------- ; =U= ; ; Alphabetic list of users, by Last initial ; HUSERS: CALL EATCHR ; Clear garbage CALL PRINT DEFB 'User''s names',CR,LF,0 ; HUSERS1:CALL PRINT DEFB CR,LF DEFB 'Enter first character of last name ' DEFB '(or user level): ',0 CALL GETCH CALL CAPS CALL ECHO CP 'A' ; Insure A-Z entry JP C,HLEVEL CP 'Z'+1 JP NC,MCMD LD (COUNT),A ; Save it away for later CALL HASH LD (HSHREC),HL LD HL,PAUSMSG CALL PRINTM LD A,23 LD (TLINES),A CALL NULIN CALL NULIN CALL UOPEN LD HL,(HSHREC) ; ; We now have the beginning hashed record for this user probe ; USLP: CALL GET LD A,(AVAILF) ; See if active OR A JR Z,USDONE ; Not an active record, so no more users LD A,(ACESSF) ; See if active 0=deleted, 1=twit, >=2 ok CP 2 JR C,USLP0 LD HL,UNAMEF ; See if it is the right character ; USNXT: LD A,(HL) ; Get a character INC HL ; Next character CP ' ' ; See if it's a space JR NZ,USNXT LD A,(HL) ; Get first character of last name LD HL,COUNT ; Get the character back CP (HL) CALL Z,GOTUS ; USLP0: CALL ABORT JR NZ,USDONE XOR A ; Clear the carry flag LD HL,(RRNO) INC HL EX DE,HL LD HL,(HSHREC) SBC HL,DE JR Z,USDONE ; So there's user here LD HL,MAXU-1 XOR A SBC HL,DE EX DE,HL JR NC,USLP LD HL,0 ; Load up first record in file JR USLP ; No, keep going ; USDONE: CALL CLOSE ; Close CALL NULIN CALL PRINT DEFB 'End of list...',0 JP MCMD ; All finished ;..... ; GOTUS: LD A,(ACESS) ; See if Sysop or co-Sysop ;; ;;==>> Following line determines user level that can see user levels ; CP 8 JP C,GOTUS0 ; If not, exit LD A,(ACESSF) ; Display user's access level ADD A,'0' LD ($+6),A CALL PRINT DEFB '1 ',0 ; GOTUS0: LD HL,UNAMEF LD B,22 ; Length of name to be displayed CALL PRINTN LD A,B OR A JR Z,GOTUS1 LD HL,PADSTR CALL PRINTL ; GOTUS1: CALL CITYS LD A,B OR A JR Z,GOTUS2 LD HL,PADSTR CALL PRINTL ; GOTUS2: LD A,(ACESS) ; See if Sysop or co-Sysop ;; ;;==>> Following line determines user level that can see phone numbers ; CP 8 JP C,GOTUS3 ; If not, exit CALL PRINT DEFB ' ',0 LD B,12 ; Eelse show the phone number also LD HL,PHONEF CALL PRINTL ; Print the phone number for the Sysop ; GOTUS3: CALL PRINT DEFB ' last: ',0 ; Space in case city/state = 20 chars. LD IX,LSTONF ; Last time on CALL PDATE ; Convert to ASCII and display CALL NULIN ; Turn up a new line RET ;..... ; HLEVEL: LD C,A ; Save the requested user level for now LD A,(ACESS) ; Get user's access level LD B,A ; Save the current user's access level ;; ;;==>> Following line determines user level that can see all user levels ;; CP 8 ; See if Sysop or Co-Sysop LD A,C ; Get the requested user level back JR C,HLEVEL1 ; If not, exit CP '0' ; Otherwise can look at '0' and twits JP C,HUSERS1 ; If less than '0', ask again JR HLEVEL2 ; HLEVEL1:CP '2' ; Normal users limited to '2' and above JP C,HSORRY ; HLEVEL2:LD A,B ADD A,'0' LD (HSORRY1),A LD A,C ; Get the requested user level back SUB '0' ; Convert to binary CP B ; Compare with current user's level JR Z,HLEVEL3 ; If the same, it's ok JP NC,HSORRY ; If higher, not allowed to see it ; HLEVEL3:LD (COUNT),A ; Save it away for later LD A,23 LD (TLINES),A CALL NULIN CALL NULIN CALL UOPEN LD HL,0 ; ; We now have the beginning hashed record for this user probe ; USLVP: CALL GET LD A,(AVAILF) ; See if active OR A JR Z,USLVP0 ; Not an active record, so next record LD A,(ACESSF) ; See if active 0=deleted, 1=twit, >=2 okay LD HL,COUNT CP (HL) CALL Z,GOTUS ; USLVP0: CALL ABORT JP NZ,USDONE XOR A ; Clear the carry flag LD HL,(RRNO) INC HL EX DE,HL LD HL,MAXU-1 XOR A SBC HL,DE EX DE,HL JR NC,USLVP JP MCMD ; No, quit ;..... ; HSORRY: CALL PCRLF1 CALL PRINT DEFB 'Only access levels from 2 through your level ' ; HSORRY1:DEFB ' allowed',CR,LF,0 JP HUSERS1 ;..... ; ; Prints the City and State ; CTYBUF: DEFS 19 SAVEST: DEFW 0 ; CITYS: LD DE,CTYBUF LD HL,CITSTF LD BC,19 ADD HL,BC LD B,20 ; ; Decrementing to last character of state ; CITY1: LD A,(HL) CP 'A' JR NC,CITY2 DEC HL DEC B JP Z,PDONE JR CITY1 ; ; Decrementing to last character ahead of state ; CITY2: LD (SAVEST),HL ; first character of state LD A,(HL) CP 'A' JR C,CITY3 DEC HL DEC B JR Z,CITY4 JR CITY2 ; ; Decrementing to last character of city ; CITY3: LD A,(HL) CP 'A' JR NC,CITY4 DEC HL DEC B JR NZ,CITY3 ; ; Now are at end of city and know how many characters that is ; CITY4: LD A,16 CP B JR NC,CITY5 LD B,A ; CITY5: LD C,B ; Save the value for now LD HL,CITST ; CITY6: LD A,(HL) AND 7FH ; Strip off any parity INC HL DJNZ CITY6 ; LD B,C ; Get the original value back INC B ; Increment for MOVNM LD HL,CITSTF CALL MOVNM LD B,1 LD A,C CP 16 JP NC,CITY7 INC C LD A,',' LD (DE),A LD A,17 SUB C LD B,A INC DE ; CITY7: LD A,' ' LD (DE),A INC DE DJNZ CITY7 ; LD HL,(SAVEST) INC HL LD A,(HL) LD (DE),A INC DE INC HL LD A,(HL) LD (DE),A INC DE ; PDONE: XOR A LD (DE),A LD HL,CTYBUF LD B,20 CALL PRINTL RET ;..... ; ;----------------------------------------------------------------------- ; =Y= ; ; Either Sysop or user wants to chat with the other... ; YAK: LD A,(ACESS) ; See if Sysop CP 9 JP Z,YAKSOP ; If yes, he can Yak regardless of hour ; IF CHTBYE LD E,255 ; See if the bell is on LD C,RMBELL CALL SPBDOS OR A JP Z,NOYAK ; Nope, sorry Charlie ENDIF ; CHTBYE ; CALL PRINT DEFB 'Yak with Sysop',CR,LF,0 CALL GETTIM ; Get time and convert to binary LD A,CHAT0 ; Available 'from' hour LD B,CHAT1 ; Available 'to' hour CP B ; See which is larger LD A,(BTIME) ; Get current time JP Z,OKYAK ; If same times, ok to yak JP C,YAK1 ; Asking for up to 11 pm or less, exit ; ; This area handles times past midnight, such as 1800 to 0100, etc. ; CP CHAT1 ; Get stopping time JR C,OKYAK ; If less, ok to ask for Sysop CP CHAT0 ; Get starting time JP NC,OKYAK ; If more. ok to ask for Sysop JP NOYAK ; Else not within his posted hours ; ; This area handles times up to 2300 (11 pm) ; YAK1: CP CHAT0 ; Get starting time JP C,NOYAK ; If less, do not ask for Sysop CP CHAT1 ; Get stopping time JP NC,NOYAK ; If more, do not ask for Sysop ; ; Ok to proceed - calculate the hash to insure proper state ; OKYAK: CALL PRINT DEFB CR,LF DEFB 'You have requested chat mode, ' DEFB 'want to page the Sysop? ',0 CALL EATCHR ; YAKASK: CALL GETCH CALL CAPS CALL ECHO CP 'Y' JP NZ,HMENU CALL PRINT DEFB CR,LF,'Hold on, ',0 LD B,NAMLEN LD HL,UNAME CALL PRINTN CALL PRINT ; Print DEFB '. You may use ^C or ^X to abort.',CR,LF,CR,LF,0 CALL PRINT DEFB ' |',0 LD A,ALERT ; Get the value LD (LINES),A LD IY,LINES ; BARS1: CALL PRINT ; Print bar and space DEFB '-',0 DEC (IY) ; Done with bars? JR NZ,BARS1 ; Not done, do it again CALL PRINT DEFB '|',CR,LF,0 LD A,ALERT ; Restore value LD (LINES),A ; Temp counter CALL PRINT DEFB 'Ringing: ',0 ; ; Attempt to alert operator ; RNGBEL: CALL DELAY ; Exit if operator answers CALL PRINT ; Print period, space DEFB BEL,'.',0 ; Ring the bell DEC (IY) ; Done with alert attempts? JR NZ,RNGBEL ; Not zero yet keep trying JP NOYAK ; Give up ;..... ; ; Delay routine to wait between beeps ; OLDSEC: DEFB 0 OLDMXT: DEFB 0 OLDTON: DEFB 0 ;..... ; DELAY: CALL GETTIM LD A,(BTIME+2) ; Get the current second LD (OLDSEC),A ; Save it PUSH HL ; Save the values, consume some time PUSH DE PUSH BC PUSH AF ; DELAY1: LD C,CONST ; Get console status CALL SPBDOS OR A ; Character ready? JR Z,DELAY2 ; Let's check it out LD C,RDCON CALL BDOS JR DELAY3 ; Go check it out ; DELAY2: CALL GETTIM ; Check new time LD A,(OLDSEC) LD HL,BTIME+2 CP (HL) JR Z,DELAY1 POP AF POP BC ; Restore the values POP DE POP HL RET ; Finished this time ; DELAY3: AND 1BH ; Convert to upper case CP 'C'-40H ; Used to using CTL-C to quit? JR Z,DELAY4 ; Ok, then back to HBBS CP 'K'-40H ; CTL-K JR Z,DELAY4 CP 'X'-040H ; User has cold feet? JR Z,DELAY4 ; Yes? then go back to HBBS CP ESC ; Was it the right answer? JR NZ,DELAY2 ; If not, keep timing JR YAKOK ; Else ok to yak ; DELAY4: LD SP,STACK ; Reset the stack JP MCMD ; Back to the menu, Sysop not available ;..... ; YAKSOP: CALL PRINT ; Sysop has typed '@' to get here DEFB 'Sysop wants to Yak',0 ; ; Operator is present ; YAKOK: LD C,LOGST ; BYE DISKLOG status request LD E,0FFH ; Ask for status CALL SPBDOS CP 77 ; 77 says "NO is set in BYE5" JR Z,YAKOK1 ; Exit with no change to the flag LD A,(DSKFLG) ; See if DISKLOG is in use OR A JR Z,YAKOK1 ; Exit if not LD C,LOGST ; Else turn it off during CHAT LD E,0 CALL SPBDOS ; YAKOK1: LD SP,STACK ; Fix stack LD C,RMRTC ; Get the current time on CALL SPBDOS LD (OLDTON),A ; Store it LD E,255 LD C,RMMXT CALL SPBDOS LD (OLDMXT),A ; Get old max time OR A JR Z,YAKOK2 ; User already has unlimited time LD E,90 ; Give him plenty of time to chat ADD A,E ; Add to old max time LD E,A LD C,RMMXT ; Reset to new max time CALL SPBDOS ; YAKOK2: CALL PRINT DEFB CR,LF,CR,LF DEFB 'Operator is available, please go ahead...',CR,LF DEFB 'Use three to exit',CR,LF,0 ; YAKOK3: LD IY,LINES LD (IY),3 ; YAKOK4: CALL PCRLF LD B,68+15 ; Input length + 15 for simple linewrap XOR A ; Allow echo LD C,A ; No caps forced LD D,1 ; Turns linewrap on CALL INPUT ; Get line OR A JR NZ,YAKOK3 DEC (IY) JR NZ,YAKOK4 LD A,(OLDMXT) OR A JP NZ,YAKOK5 LD E,A LD C,RMMXT CALL SPBDOS JP HMENU ; ; Add time to maximum time ; YAKOK5: PUSH AF LD C,RMRTC CALL SPBDOS PUSH AF LD A,(OLDTON) LD B,A POP AF SUB B LD B,A POP AF ADD A,B LD E,A LD C,RMMXT CALL SPBDOS JP HMENU ;..... ; NOYAK: LD HL,NOCHAT ; In the HBBSHDR.MAC CALL PRINTM JP MCMD ;..... ; end of YAK routine ;----------------------------------------------------------------------- ; ; Special routine to set the drive/user area for MSDOS 'FOR' and 'NEW' ; files. ; KMSDOS EQU $ ; IF MSDOS LD A,(INTAR) ; Get user's stored preference LD B,A LD A,IBMDRV ; Get the drive for IBM uploads SUB 'A' ; Change to binary CP B JR NZ,KMSD1 ; If not requesting IBM files, exit ; LD A,NIBMDR ; Get drive for IBM 'FOR and KMD.LOG' LD (KMSD1+1),A LD A,NIBMUS ; Get user aea for IBM 'FOR and KMD.LOG' LD (KMSD2+1),A ENDIF ; MSDOS ; KMSD1: LD A,NCPMDR ; CP/M drive for 'FOR and KMG.LOG' files SUB 'A' LD E,A LD C,SELDSK ; Set drive to FOR and KMD.LOG files CALL SPBDOS ; KMSD2: LD A,NCPMUS LD E,A LD C,SETUSR ; Set user area to FOR and KMG.LOG files CALL SPBDOS RET ;..... ; ;----------------------------------------------------------------------- ; ; =F= ; ; Displays the 'FOR' file describing recent uploads ; KFOR: CALL PRINT DEFB 'For',CR,LF,CR,LF DEFB 'Description of new files',CR,LF DEFB '[type S to pause, C, K or X to abort, ' DEFB '? for help]',CR,LF,CR,LF,0 CALL KMSDOS ; Set drive/user area for IBM 'FOR' file LD HL,FOR CALL TYPE JP TDONE2 ;..... ; ;----------------------------------------------------------------------- ; =N= ; ; Displays the 'NEW' file showing recent uploads ; KNEW: CALL PRINT DEFB 'New',CR,LF,0 CALL KMSDOS ; Set drive/user area for IBM 'NEW' file LD A,22 LD (TLINES),A XOR A LD B,24 ; Reset the FCB just in case LD HL,EXTENT ; KNEW1: LD (HL),A INC HL DJNZ KNEW1 LD DE,KMDLOG LD C,OPENF ; Open a file CALL SPBDOS CP 0FFH ; Did we find it? JP Z,NONE ; Nope LD DE,KMDLOG LD C,CFSIZE ; Get the size of the file CALL SPBDOS ; Which is then stored in RECORD LD DE,HBSEND+81 ; Store a CR for first line LD A,CR LD (DE),A ; Save it now CALL PRINT DEFB CR,LF,'D/U Filename Size Speed ' DEFB ' Date Time Uploaded by',0 LD DE,HBSEND+80 ; ; Read record from source file ; KNEW2: PUSH DE LD DE,-1 LD HL,(RECORD) ADD HL,DE LD A,L OR H JP Z,TDONE LD (RECORD),HL LD DE,TBUFF ; Set the buffer area for our read LD C,SETDMA ; BDOS Set File Buffer Address CALL SPBDOS LD DE,KMDLOG ; Now read the record LD C,RRDM ; Read random file CALL SPBDOS POP DE ; Restore register OR A ; Read ok? JP NZ,RDERR LD HL,TBUFF+127 ; Set up end of buffer LD B,128 ; The buffer will be filled up backwards ; KNEW3: LD A,(HL) ; Get character AND 7FH CP LF ; Check for end of line - LF is the marker JR Z,KNEW5 ; That we will use to determine each line CP 7FH ; Strip off any parity JR Z,KNEW4 CP 1AH ; Check for CTRL-Z, end-of-file marker JR Z,KNEW4 EX DE,HL LD (HL),A ; Store character in our working buffer EX DE,HL DEC E ; Decrement counters (DE=work buffer) ; KNEW4: DEC L ; (HL=TBUFF) DEC B ; (B=Counter for number of char.) JP Z,KNEW2 ; If zero, go read another record JR KNEW3 ; ; Write record to output file (with buffering) ; KNEW5: DEC B ; Decrement our counter PUSH AF ; As well as the flags DEC L ; Decrement our TBUFF buffer PUSH HL ; Save it PUSH BC ; Save counter EX DE,HL ; HL will now be our working buffer LD (HL),A ; Go save CR INC L ; If not, go see if it is a uploaded file LD A,(HL) LD B,A ; Store this away for later DEC L CP 'S' ; Was this a "Send" file? JP Z,KNEW6 ; Yes, so try next one CP 'L' ; A single file from a library? JP Z,KNEW6 ; Yes, so try next one CP 'A' ; A single file from an LBR/ARC/ARK? JP Z,KNEW6 ; Yes, so try next one LD A,(ACESS) ; See if it's the Sysop CP 8 JP P,WRDLOP ; Yep, keep pluggin LD A,B ; Nope, check if it was a Private file CP 'P' ; If it was Private and access not Sysop, JP Z,KNEW6 ; Say goodbye ; WRDLOP: LD A,(HL) ; Get byte from read buffer LD B,A ; Save the character for now CP CR JP Z,SENDLF ; Go send a CR and start all over again CP LF ; If LF, then just send it to output JP Z,SEND ; ; Will show entire XMODEM.LOG in reverse if requested. ; LD A,(COLUMN) ; See if in first column OR A JP NZ,WRDL4 ; If not, exit INC A LD (COLUMN),A ; Won't be in first column any longer ; ; ; Shows "P" entries only if wheel byte is set for SYSOP's use ; LD A,B ; Get the character back CP 'P' ; This line a private upload? JR NZ,WRDL1 ; If not, exit LD A,(ACESS) ; See if it's the Sysop CP 8 JP M,WRDL3 ; Nope, no Private files for this guy LD (PRIVT),A ; To distinguish "P" lines when shown LD (STORE),A ; Just in case it is JR WRDL5 ; WRDL1: CP 'S' JR NZ,WRDL2 XOR A LD (STORE),A LD (COLUMN),A JP KNEW6 ; WRDL2: CP 'R' ; This a "received file"? LD (STORE),A ; Set the flag just in case JR Z,WRDL5 ; If 'R', keep the flag set ; WRDL3: XOR A LD (STORE),A ; Otherwise reset flag to zero ; WRDL4: LD A,(STORE) ; Storing into memory? OR A JP Z,NEXT ; If not, exit ; WRDL5: LD A,(COLUMN) ; Increment the column counter INC A LD (COLUMN),A ; ; The following retains original format of XMODEM "R" lines ; CP 3 ; User's modem speed is in column 2 JR NZ,WR1 ; If not column 2, continue LD A,B ; Otherwise get the character LD (STORE),A ; Store it for conversion to baud rate JP NEXT ; Do not print the "MSPEED" number ;..... ; WR1: CP 11 JP C,NEXT ; Skip everything through column 9 CP 14 JP C,SEND ; Print everything through column 12 JR NZ,WR4 LD A,(PRIVT) ; Going to distinguish a "P" line? OR A JR Z,WR2 XOR A LD (PRIVT),A LD B,'*' CALL SEND1 JR WR3 ; WR2: LD B,':' ; Stick in a colon after column 12 CALL SEND1 ; WR3: LD B,' ' ; Send a space JP SEND ; WR4: CP 22 ; Print through column 20 JP C,SEND JR NZ,WR5 CALL SEND1 ; Send character in colum 21 LD B,'.' ; Add a period after the file name JR SEND ; WR5: CP 27 JR C,SEND ; Print file type and some spaces CP 39 JP C,NEXT ; Ignore the "big gap" CP 43 JR C,SEND ; Print the file size JR Z,WR6 ; ; Customizes area after the file size. ; LD A,(COLUMN) ; Get the column count back again JR WR7 ; If not column 42, continue ; WR6: CALL SEND1 ; Print first space CALL BAUD ; Print the baud rate and two spaces JP NEXT ; WR7: CP 52 JR C,SEND ; Print the date JR NZ,WR8 CALL SEND1 ; Print 2 spaces after date JR SEND ; WR8: CP 58 JR C,SEND ; Print the time program was sent JR NZ,SEND ; If not column 57, continue CALL SEND1 ; Print two spaces CALL SEND1 JR NEXT ; Continue with rest of line (name) ;..... ; SEND: LD A,B ; Get the character back CALL SHOW ; Show the character ; NEXT: INC L ; Next address JP WRDLOP ; Get another byte ;..... ; SEND1: LD A,B ; Get the character back JP SHOW ; Show the character ;..... ; SENDLF: XOR A LD (COLUMN),A ; Othewise in column 0 now CALL ABORT ; Want to quit already? JP NZ,TDONE1 ; Always close file before quitting ; SENDL1: LD A,(COUNT) INC A ; Just to get a positive value LD (COUNT),A ; Have at least one line to show CALL PRINT DEFB CR,0 ; KNEW6: XOR A ; Now restore everything so LD (COLUMN),A ; We can get on with our business LD DE,HBSEND+80 POP BC POP HL POP AF JP NZ,KNEW3 ; Read next character JP KNEW2 ; If empty, get next record ;..... ; ; Shows the received baud rate ; BAUD: PUSH HL ; Save the address LD A,(STORE) ; Get the baud rate SUB '0' LD C,A ; keep it for now LD B,' ' CP 5 ; Using under 1200 baud? CALL C,SEND1 ; If yes, send an extra space LD A,C ; Get the baud rate back, just in case CP 9 ; This entry at 19200 baud? CALL NZ,SEND1 ; If not, send a space LD HL,BDTBL ; Start of baud rate speeds LD D,0 ; Zero the 'D' register LD A,C ; Get the current baud rate back ADD A,A ; Index into the baud rate table ADD A,A LD E,A ; Now have the index factor in 'DE' ADD HL,DE ; Add to 'HL' to get proper address EX DE,HL ; Put address in 'DE' registers PUSH BC LD C,STRING ; Display the baudrate CALL SPBDOS POP BC LD A,C ; Get the baud rate back again CP 5 JP C,BAUD1 ; If less, have enough zeros already LD B,'0' CALL SEND1 ; Adds a zero for 2400, 9600, 19200 ; BAUD1: CALL PRINT DEFB ' bps ',0 POP HL ; Restore the original address RET ;..... ; BDTBL: DEFB '110$','300$','450$','600$','710$','120$','240$' DEFB '480$','960$','1920$' ;..... ; ; Display the character. If a line feed, see if time to pause, yet ; SHOW: CP LF ; Was it a line feed? JP NZ,ECHO ; If not, go display it CALL TWAIT ; Else see if time for [more] OR A ; Requesting abort? JP NZ,ECHO ; If not display the line feed POP HL ; Clean up the stack CALL PRINT DEFB CR,LF,'++ ABORTED ++',0 JP TDONE1 ; Close the file, all finished ;..... ; NONE: CALL PRINT DEFB CR,'++ NO NEW FILES ++',0 JP TDONE1 ; Close file and exit ;..... ; RDERR: CALL PRINT DEFB CR,LF,'++ SOURCE FILE READ ERROR ++' JP TDONE1 ; Close file and exit ;..... ; ; Transfer is done - close destination file ; TDONE: POP DE ; Clear the stack CALL PRINT DEFB CR,LF,CR,LF,CR,'[End of listing] ',0 CALL GETCH ; TDONE1: LD C,CLOSEF ; Close the file LD DE,KMDLOG CALL SPBDOS LD C,26 ; SETDMA - reset to TBUFF default address LD DE,TBUFF CALL SPBDOS ; ; Restore original System drive/user area and exit to main menu ; TDONE2: LD A,SYSDRV ; Log into where the system files are LD E,A LD C,SELDSK ; Restore system drive CALL SPBDOS LD A,SYSUSR LD E,A LD C,SETUSR ; Restore system user area CALL SPBDOS CALL PCRLF JP HMENU ;..... ; ; Aborts the display when requested, but only at end of line ; PAUSMSG: ;;;; DB 0 ; Quit now ;;;; DEFB CR,LF,'Type S to pause, Q to abort',CR,LF,0 ; ABORT: PUSH HL ; Save the TBUF address PUSH DE PUSH BC LD C,CONST ; Check to see if key pressed CALL SPBDOS OR A JR Z,ABORT3 ; If no key pressed, then continue LD C,RDCON ; If key pressed, then check for abort CALL SPBDOS AND 5FH ; Remove parity, insure to upper-case CP 'S'-40H ; CTL-S to pause? JR Z,ABORT0 CP 'S' ; Upper or lower 'S' to pause? JR NZ,ABORT1 ; If not, exit CALL ABORT4 ; Erase the character ; ABORT0: XOR A LD (CNTN),A ; Reset the non-stop flag, if stoppin LD C,RDCON ; Otherwise wait for another character CALL SPBDOS ; ABORT1: CP 'C'-40H ; Is it CTL-C to abort? JP Z,ABORT2 CP 'K'-40H ; Is it CRL-K to abort? JR Z,ABORT2 CP 'X'-40H ; Is it CTL-X to abort? JR Z,ABORT2 CP ' ' JR C,ABORT3 AND 5FH ; Remove parity, insure upper-case CALL ABORT4 ; Erase the character, then check it CP 'E' ; Is it 'E' to exit? JR Z,ABORT2 CP 'K' ; Is it 'K' to exit? JR Z,ABORT2 CP 'X' ; Is it 'K' to exit? JR NZ,ABORT3 ; None of these, continue normally ; ABORT2: CALL PRINT ; If yes, then print abort message DEFB CR,LF,'++ ABORTED ++',CR,LF,0 POP BC ; Reset the stack POP DE POP HL LD A,1 ; Set the Zero flag so a 'NZ' aborts OR A RET ; ABORT3: XOR A ; Clear the Zero flag so a 'Z' continues POP BC POP DE POP HL RET ; ABORT4: PUSH AF CALL PRINT DEFB BS,' ',BS,0 POP AF RET ;..... ; ; Clears any garbage characters that may have been entered ; EATCHR: LD C,CONST ; Check console status CALL SPBDOS OR A RET Z ; No characters, exit ; LD C,RDCON ; Get the character CALL SPBDOS CP ' ' ; Non-printing character? JR C,EATCH1 ; If yes, ignore and exit CALL PRINT ; Else remove from the display DEFB BS,' ',BS,0 ; EATCH1: XOR A ; Ignore this character JR EATCHR ; See if any more characters ;..... ; ; Exit mail, asking to kill all messages to current user first ; QUIT: CALL PRINT DEFB CR,LF,CR,LF DEFB 'Sign-off now? ',0 CALL EATCHR ; QUITW: CALL YESNO CP 1 JR Z,YQUIT JP HMENU ; YQUIT: LD A,1 LD (QFLAG),A JP KILLM ;..... ; ;----------------------------------------------------------------------- ; =C or J= ; JMPCPM: CALL PRINT DEFB 'CP/M',0 ; IF RSTKON AND A ; Clear carry LD B,RSTKLV ; At what level? LD A,(ACESS) CP B JP NC,KILLM ; He's okay... LD HL,RSTMSG ; He's not... CALL PRINTM JP HMENU ENDIF ; RSTKON ; KILLM: LD A,(MFLAG) ; See if mail was waiting OR A JP Z,MEXIT ; No so skip killing old msgs ; IF ERASE LD A,(ACESS) CP 8 JR C,SKILL ENDIF ; ERASE ; LD A,1 ; No delete wanted so set flag LD (SYSDEL),A ; And skip kill routine JP MEXIT ; SKILL: CALL PRINT DEFB CR,LF DEFB 'Kill the ',0 LD HL,(MFLAG) XOR A LD H,A CALL PB2ASC CALL PRINT DEFB ' message',0 LD A,(MFLAG) CP 1 JR Z,SNP CALL PRINT DEFB 's',0 ; SNP: CALL PRINT DEFB ' to you? ',0 CALL EATCHR ; SKILLW: CALL YESNO CP 1 ; '1' if Yes was typed JP Z,SKY ; SKN: LD A,1 ; No delete wanted so set flag LD (SYSDEL),A ; And skip kill routine JP MEXIT ;..... ; SKY: XOR A ; Yes, kill old messages so set flag LD (SYSDEL),A ; And kill... ; KILLM1: LD DE,1 LD C,RMWRT CALL SPBDOS ; Set write lock LD IY,MREAD ; Point to message number field CALL PRINT DEFB CR,LF DEFB 'Killing old messages...',0 CALL MOPEN LD HL,(IMNDX) ; Number of records ; KILMLP: CALL GET LD HL,MTOF ; See if to user LD DE,UNAME LD B,NAMLEN CALL MATCH OR A JR NZ,KBPREC ; No LD (IY),-1 ; Set delete flag LD HL,(RRNO) CALL PUT ; KBPREC: LD HL,(RRNO) ; Get record DEC HL ; And drop it by one LD A,H CP 0FFH ; See if any more JR NZ,KILMLP ; Yes CALL CLOSE ; ; Killing done, if required, so exit mail, rewriting index with new ; message counts etc. and clearing mail waiting flag in user's record ; MEXIT: LD DE,1 LD C,RMWRT CALL SPBDOS ; Set write lock LD HL,WAITMSG CALL PRINTM LD HL,IDATE LD DE,RNDBUF LD BC,NDXLEN ; Move index info to buffer and LDIR ; We're ready to write CALL IOPEN CALL PUT ; Write it CALL CLOSE LD A,(SYSDEL) ; Avoid reset of mail flag OR A ; See if Sysop and no msg-kill JR NZ,SDEL ; 1=no delete wanted XOR A ; Clear mail waiting flag LD (MFLAG),A ; In memory as well ; SDEL: CALL USTORE ; Move info into buffer CALL UPUT ; Write user info to disk CALL CLOSE LD DE,0 LD C,RMWRT CALL SPBDOS ; Clear write lock ; SDONE1: LD HL,CLRWTMSG CALL PRINTM CALL PCRLF LD A,(QFLAG) OR A JP NZ,0000H ; <== LET BYE5 HANDLE IT LD A,(ACESS) ; See if SYSOP CP 8 JP NC,SDONE2 ; If yes, ignore turning DISK LOG on LD C,LOGST ; BYE DISKLOG status request LD E,0FFH ; Ask for status CALL SPBDOS CP 77 ; 77 says "NO is set in BYE5" JR Z,SDONE12 ; Exit with no change to the flag LD A,(DSKFLG) ; See if DISK LOG was turned off OR A JR Z,SDONE12 ; If zero, was never in use LD C,LOGST ; BYE DISKLOG status request LD E,1 ; Turn DISK LOG back on, then CALL SPBDOS ; SDONE12:LD HL,CPMTXT ; CP/M file, if any CALL TYPE CALL PCRLF CALL EATCHR LD HL,UNAME LD B,NAMLEN CALL PRINTN ; Print the user's name CALL PRINT DEFB ' has uploaded ',0 LD HL,(UPLDS) PUSH HL CALL PB2ASC ; Display his downloads CALL PRINT DEFB ' file',0 POP HL LD A,H OR A JR NZ,SDONE13 LD A,L CP 1 JR Z,SDONE14 ; SDONE13:CALL PRINT DEFB 's',0 ; SDONE14:CALL PRINT DEFB ' and downloaded ',0 LD HL,(DNLDS) PUSH HL CALL PB2ASC ; Display his uploads CALL PRINT DEFB ' file',0 POP HL LD A,H OR A JR NZ,SDONE15 LD A,L CP 1 JR Z,SDONE16 ; SDONE15:CALL PRINT DEFB 's',0 ; SDONE16:CALL PCRLF LD A,(ACESS) SUB 2 ; Make base 0 (0 & 1 never get here) LD DE,ACTBLEN ; Length of each entry in table LD H,0 LD L,A ; HL=access level CALL MLDL ; HL=offset LD DE,ACC2 ; Start of table ADD HL,DE ; HL=address for this access level INC HL INC HL INC HL INC HL ; Get KMRATIO address LD A,(HL) LD (KMRATIO),A OR A JP Z,NORATIO LD B,A LD DE,(UPLDS) LD L,A ; Give him one freeby LD H,0 ; KRAT00: ADD HL,DE ; Get how many d/l he's allowed DJNZ KRAT00 LD DE,(DNLDS) OR A ; Reset the carry flag SBC HL,DE ; (UPLOADS * RATIO) - DOWNLOADS LD A,H ; See if togo is >255 OR A JP NZ,NORATIO ; Togo is >255 so skip LD A,(KMRATIO) RRA ; Divide ratio by 2 AND 7FH ; Get rid of any bit zero data LD B,A ; And put it in B LD A,L ; Pick up lsb of togo downloads OR A CP B ; Halfway yet? JP NC,NORATIO ; No, don't plead for uploads yet CALL PRINT DEFB CR,LF,CR,LF,'How about some upload help.....??',CR,LF,0 ; NORATIO:CALL EATCHR CALL EATCHR LD A,(NOFILE) ; Has he been here once? OR A JP NZ,JUSTJMP ; Yup, just drop to CP/M ; SDONE2: LD A,(ACESS) ;; ;;==>> Following line sets the wheel byte for level desired ;; CP 8 ; Is this the Sysop or co-Sysop? JP C,SDONE3 LD A,0FFH ; For ZCPR3 LD (WHEEL),A ; Give him privileges. ; IF TCAP AND Z3SET PUSH HL LD HL,(ZWHL) LD (HL),A POP HL ENDIF ; TCAP AND Z3SET ; IF SETPATH ; Are we setting Sysop path? LD HL,SYSPATH ; New path LD DE,PATH ; Destination LD BC,PATHLEN ; Length LDIR ; Move it.. ENDIF ; JP JMP ; Skip any entry files for Sysop ; SDONE3: LD A,(NOFILE) ; Has he been here once? OR A JP NZ,JUSTJMP ; Yup, just drop to CP/M LD A,(NUSR) ; This a new user? OR A JR Z,NOTNEW LD DE,NENTRY ; New users get file named at NENTRY JP CPM ; NOTNEW EQU $ ; IF SPON LD A,(ACESS) ; See if this user is =>7 CP 7 ; If not then = 0 JR C,NOTSP ; So not special LD DE,SPENTRY ; Get special file JP CPM ENDIF ; NOTSP: LD A,(ACESS) ; See if Sysop or co-Sysop ;; ;;==>> Following line determines user level that must see the directory ; CP 5 JR NC,JMP LD DE,ENTRY ; Gets regular entry file JP CPM ;..... ; JUSTJMP EQU $ ; IF ALTON LD DE,ALTFILE JP CPM ENDIF ; JMP: LD DE,FAKE ; He's seem the file once JP CPM ; Don't show it again. ;..... ; FAKE: DEFW 0 ; ; Now we write the user's record... ; UPUT: LD DE,1 LD C,RMWRT CALL SPBDOS ; Set write lock CALL UOPEN LD HL,(USREC) ; Get record number CALL PUT CALL CLOSE RET ;..... ; UGET: CALL UOPEN ; Get user info to memory LD HL,(USREC) ; Get this user's record number CALL GET ; Get user's info and move it to memory ;..... ; UMOV: LD HL,AVAILF LD DE,AVAIL LD BC,USRLEN LDIR RET ;..... ; UOPEN: LD HL,USERS CALL OPEN LD HL,USRLEN ; Length of record LD (RRSZ),HL RET ; Get user info to memory ;..... ; IOPEN: LD HL,INDEX ; Point to index name CALL OPEN ; Open file LD HL,NDXLEN ; Length of record LD (RRSZ),HL ; Set into buffer LD HL,0 ; Set record number RET ;..... ; MOPEN: LD HL,MSGINDEX ; Point to index name CALL OPEN ; Open file LD HL,MNDXLEN ; Length of record LD (RRSZ),HL ; Set into buffer RET ;..... ; MSGOPEN:LD HL,MESSAGES CALL OPEN ; Open messages file LD HL,MSGLEN LD (RRSZ),HL ; Set record length RET ;..... ; USTORE: LD HL,AVAIL LD DE,AVAILF LD BC,USRLEN LDIR ; Move info to buffer RET ;..... ; WRTLP: PUSH BC PUSH IY POP HL LD DE,RNDBUF LD BC,MSGLEN LDIR PUSH HL POP IY LD HL,(RRNO) CALL PUT LD HL,(RRNO) INC HL LD (RRNO),HL POP BC DJNZ WRTLP RET ;..... ; ; Get a message record number - subroutine ; GETRC: PUSH HL ; User request - popped as DE later OR A ; Clear carry LD DE,1 SBC HL,DE ; See if user requested msg #1 JP NZ,GETNXT ; Exit if not LD (RRNO),HL ; Select record 0 for 1st message JP GETDONE ; GETNXT: LD A,(MSGFLG) OR A JR NZ,GETNX1 CALL PRINT DEFB CR,LF,'Stand by...locating messages...',0 ; GETNX1: LD HL,(IMNDX) ; Number records INC HL LD (RRNO),HL ; To record # counter ; GETRC1: LD HL,(RRNO) DEC HL LD A,H CP 0FFH ; Done with records? JR Z,GETDONE ; Start with record 0 LD (RRNO),HL ; Set new record CALL GET LD A,(ACESS) ;; ;;==>> Who can see deleted messages ;; CP 8 ; Is this the Sysop JP NC,GETRC2 ; Get 'em all LD A,(MREAD) CP -1 ; Deleted ? JR Z,GETRC1 ; Yes... next please ; GETRC2: POP DE ; Restore user ask PUSH DE AND A ; Clear carry flag LD HL,(MNUMF) SBC HL,DE JR Z,GETDONE ; May need work JR C,GETRC3 JR GETRC1 ; GETRC3: LD HL,(RRNO) INC HL LD (RRNO),HL ; GETDONE:POP DE ; Clear the stack LD A,(MSGFLG) OR A RET NZ ; ; Subroutine to print a CR,LF - saves many bytes ; PCRLF: CALL PRINT DEFB CR,LF,0 RET ;,,,,, ; ; Subroutine to print CR,LF,CR,LF - saves many bytes ; PCRLF1: CALL PRINT DEFB CR,LF,CR,LF,0 RET ;,,,,, ; YESNO: CALL GETCH CALL CAPS CP 'Y' JR Z,PRYES CP 'N' JR Z,PRNO LD A,-1 ; Set minus flag OR A RET ; PRYES: LD HL,YESMSG CALL PRINTM LD A,1 ; Set plus flag OR A RET ; PRNO: LD HL,NOMSG CALL PRINTM XOR A ; Set zero flag RET ;..... ; ;*********************************************************************** ; ; SUBROUTINE: GETNUM ; PURPOSE: get user input to start scan or read start search ; INPUT: none ; OUTPUT: random record number in msgindex file to begin search ; USES: A,BC,DE,HL,IX ; ;*********************************************************************** ; R1: DEFB 'reading' S1: DEFB 'scan at' ; GETNUM: CALL MOPEN CALL PRINT DEFB CR,LF,'Start ' ; SMSG: DEFB 'scan at (',0 LD HL,0 LD (RRNO),HL CALL GET LD HL,(MNUMF) ; Get 1st message's number CALL PB2ASC ; Display it CALL PRINT DEFB '-',0 LD HL,(IMNXT) ; Next message number DEC HL CALL PB2ASC CALL PRINT DEFB ') or for new messages: ',0 LD B,5 XOR A ; Set echo LD C,A LD D,A CALL INPUT ; Returns 0 if nothing entered OR A JP Z,GN3 ; Nothing entered so quit LD (CNVRT0+1),A ; # of characters entered LD A,(HL) CP CR JR Z,GN3 CP '*' JR Z,GN2 CALL CAPS CP 'N' JR Z,GN4 CP '1' JR C,GN1 CP '9'+1 JP NC,HMENU JR GN6 ; GN1: CALL PRINT DEFB CR,LF,'Enter message number or for new' DEFB CR,LF,0 POP HL ; Fix the stack for CALL GETNUM JP HMENU ; GN2: CALL SETCON ; For NEW, continuous JR GN5 ; GN3: CALL PRINT DEFB 'N',0 ; GN4: CALL PRINT DEFB 'ew',0 ; GN5: LD HL,(SAVEHI) INC HL LD A,1 LD (RNEW),A RET ; GN6: PUSH HL ; GN7: LD A,(SMSG) CP 's' JR Z,GN8 INC HL LD A,(HL) CP '*' ; Wants continous? CALL Z,SETCON ; Set continous read OR A ; Guess not JP NZ,GN7 ; GN8: POP IX CALL CNVRT0 XOR A LD (RNEW),A ; Reset to check out of range ; GN9: PUSH HL POP DE LD HL,(IMNXT) ; Next message number DEC HL AND A ; Clear carry flag SBC HL,DE JP C,NANY ; Tell him no NEW or out of range PUSH DE POP HL ; Get user request back LD A,L OR A RET NZ LD A,H OR A RET NZ ; ENDNUM: POP HL ; Clear the stack CALL CLOSE JP HMENU ;..... ; end of GETNUM routine ;----------------------------------------------------------------------- ; NANY: POP HL ; Clear stack from CALL GETNUM LD A,(RNEW) ; Out of range "NEW" read? OR A LD HL,TOOBIG ; Tell him it's too big JP Z,PNOMOR ; Nope.. LD HL,NOTANY JP PNOMOR ;..... ; NOTANY: DEFB CR,LF,CR,LF,'No new messages',0 TOOBIG: DEFB CR,LF,CR,LF,'No message that high',0 ;..... ; ;*********************************************************************** ; ; SUBROUTINE: GETUSR ; PURPOSE: Calc pos'n in USERS.BBS to start search ; INPUT: NAME MUST BE IN MTOTMP ; OUTPUT: HL=USER RECORD NUMBER, Z FLAG SET IF MATCH, CLEAR IF NOT ; USES: A,DE,HL ; ;*********************************************************************** ; USRGET: CALL UOPEN LD HL,MTOTMP ; Get to: name ; PMHSH: LD A,(HL) ; Get a character INC HL ; Next character OR A ; See if it's a null (error) JP Z,PBNONE ; Go back and get a real name CP ' ' ; See if it's a space JP NZ,PMHSH LD A,(HL) ; Get first char of last name CP 'A' ; Check for valid char. JP C,PBNONE ; Go get a real name CP 'Z'+1 JP NC,PBNONE ; Go get A real name CALL HASH LD (HSHREC),HL LD HL,(HSHREC) ; ; We now have the beginning hashed record for this user probe ; PMLP: CALL GET LD A,(AVAILF) ; See if active OR A JR Z,PBNONE ; Not an active record, so no user LD A,(ACESSF) ; See if active 0=deleted, 1=twit, >=2 okay CP 2 JR C,PMLP0 LD HL,UNAMEF ; See if to user LD DE,MTOTMP LD B,NAMLEN CALL MATCH OR A JR Z,USRGOT ; PMLP0: XOR A ; Clear the carry flag LD HL,(RRNO) INC HL ; Next record number EX DE,HL LD HL,(HSHREC) ; Have we checked all of them SBC HL,DE JR Z,PBNONE ; So there's no user here LD HL,MAXU-1 XOR A SBC HL,DE EX DE,HL JR NC,PMLP LD HL,0 ; Load up first record in file JR PMLP ; No, keep going ; PBNONE: CALL CLOSE ; Close LD A,-1 OR A ; Set no user found flag RET ; USRGOT: CALL CLOSE LD HL,(RRNO) ; Return the record number XOR A ; Set flag RET ;..... ; ;*********************************************************************** ; ; SUBROUTINE: HASH ; PURPOSE: Calc pos'n in USERS.BBS to start search ; INPUT: A =first character of last name ; OUTPUT: HL=pos'n in USERS.BBS to begin search ; USES: A,DE,HL ; ;*********************************************************************** ; HASH: SUB 41H ; Make it 0 thru 25 ADD A,A ; Double it LD HL,HSHTBL ; Point to start of table LD E,A ; Calc pos'n in table LD D,0 ADD HL,DE LD A,(HL) ; Get starting pos'n in HL INC HL LD H,(HL) LD L,A RET ;..... ; ; Set the user's preferred terminal with for writing, reading messages ; SETLIN: LD A,(LENG) ; Get user's terminal line width LD (LIN1),A LD (LIN2),A INC A LD (LIN4),A SUB 8 LD (LIN3),A RET ;..... ; ; This is the entry point to the ZCPR3 terminal selection code. On ; entry 'A' contains a zero if this is a new user, or if the user's ; terminal code from the USERS.BBS record is zero (no terminal). On ; exit 'A' will contain the number of the selected terminal unless the ; user aborted the selection, in which case 'A' will be zero and the ; the 'Z' flag will be set. The calling program must log into the ; drive and user number that contains the Z3TCAP.TCP file before cal- ; ling TCSET and return to the original drive user number after the ; call. ; TCSET EQU $ IF TCAP PUSH AF LD A,TCPDRV LD E,A LD C,SELDSK CALL SPBDOS LD A,TCPUSR LD E,A LD C,SETUSR CALL SPBDOS POP AF CALL TC1 PUSH AF LD A,SYSDRV LD E,A LD C,SELDSK CALL SPBDOS LD A,SYSUSR LD E,A LD C,SETUSR CALL SPBDOS POP AF RET ;,,,,, ; TCMNT EQU 26 ; Number of entries per screen ; TC1: OR A LD (TCVAR1),A JR Z,TC2 LD A,(TCODE) ; TC2: LD L,A LD H,0 DEC HL LD (TCVAR2),HL LD HL,TCPNAM CALL OPEN LD HL,128 LD (RRSZ),HL CALL ENDBBS LD (TCVAR9),HL LD BC,0 LD HL,-1 PUSH HL ; ; Load Z3TCAP Index ; TC3: POP HL INC HL PUSH HL INC C PUSH BC LD (RRNO),HL CALL GET LD HL,(TCVAR9) PUSH HL LD DE,RNDBUF EX DE,HL LD BC,128 LDIR POP HL LD DE,16 LD B,8 ; ; Check for End of Index ; TC4: LD A,(HL) CP ' ' JR Z,TC5 ADD HL,DE LD (TCVAR9),HL DEC B JR NZ,TC4 POP BC JR TC3 ; ; Reached End of Index ; TC5: ADD HL,DE ; Compute address of next block after last DEC B JP NZ,TC5 POP BC ; Get record number of next block LD A,C LD (TCVAR6),A ; Save count CALL CLOSE ; Close the file POP HL LD A,(TCVAR2) INC A JP NZ,TC10 ; ; Print menu of terminals ; TC6: LD A,1 ; Set menu number LD (TCVAR7),A CALL ENDBBS ; Point to first terminal LD (TCVAR8),HL ; Save pointer ; TC7: CALL TC18 ; Print menu pointed to by HL CALL PRINT DEFB CR,LF,'Enter Selection',0 CALL TC29 ; First menu? LD HL,TCMSG2 ; Pt to last message CALL Z,PRINTM CALL TC30 ; Last menu? LD HL,TCMSG1 ; Pt to next message CALL Z,PRINTM CALL PRINT DEFB ', or ^K to Exit - ',0 ; TC8: CALL GETCH CALL CAPS PUSH AF CALL PCRLF POP AF CP CR JP Z,TC14 CP 'K'-'@' ; Abort? JP Z,TC10 CP '+' ; Next? JP Z,TC14 CP '-' ; Last? JP Z,TC16 SUB 'A' ; Convert to digit JP C,TC13 ; Print error message LD C,A ; Result in C LD A,(TCV10) ; Number of menu items DEC A CP C ; Range error? JP C,TC13 ; ; Set pointer to menu entry. On input, C = offset in 20-terminal menu ; and TCVAR7 is menu (1..) ; LD A,(TCVAR7) ; Get menu number DEC A ; Adjust to 0 offset LD D,0 ; HL = number LD E,A LD HL,0 LD B,TCMNT ; Multiply by number of entries ; TC9: ADD HL,DE DEC B ; Count down JR NZ,TC9 ; B=0 on exit ADD HL,BC ; Compute offset from record 1 for entry LD (TCVAR2),HL ; ; HL now contains terminal number (zero relative) ; TC10: LD HL,(TCVAR2) LD A,(TCVAR6) ; Get location of terminal data record 1 LD C,A LD B,0 ADD HL,BC ; HL has terminal's random record number ; ; HL now contains random record number for terminal in file (zero ; Relative). Reopen Z3TCAP.TCP ; PUSH HL LD HL,TCPNAM CALL OPEN LD HL,128 LD (RRSZ),HL POP HL ; ; Position to Correct Record and Read it in ; LD (RRNO),HL CALL GET CALL CLOSE ; ; Confirm Selection ; LD A,(TCVAR1) CP -1 JR Z,TC12 CALL PRINT DEFB CR,LF,' Selected Terminal is: ',0 LD HL,RNDBUF LD B,16 CALL PRINTL CALL PRINT DEFB ' -- Confirm (Y/N)? ',0 ; TC11: CALL GETCH CALL CAPS CALL ECHO PUSH AF CALL PCRLF POP AF CP 'Y' JR Z,TC12 ; Continue LD A,(TCVAR1) OR A JP Z,TC7 XOR A LD (TCVAR1),A LD L,A LD H,A LD (TCVAR2),HL JP TC6 ; ; Place Z3TCAP Entry into Z3 Environment Descriptor ; TC12: LD HL,SYSENV ; Point to environment descriptor LD DE,80H ; Point to TCAP entry ADD HL,DE EX DE,HL ; DE points to entry LD HL,RNDBUF ; Point to scratch area LD BC,128 ; Copy 128 bytes LDIR LD A,(ACESS) CP 2+1 JR NC,TC125 CALL PRINT DEFB CR,LF,'ZCPR3 Environment Descriptor Loaded',0 ; TC125: LD A,(TCVAR2) ; Get the selected terminal number INC A ; Increment for HBBS OR A ; Set the flags RET ;..... ; ; Invalid Selection ; TC13: CALL PRINT DEFB ' -- Error: Invalid Selection',0 JP TC7 ; ; Advance to next menu ; TC14: CALL TC30 ; At end? JR Z,TC15 CALL PRINT DEFB ' -- Error: Already at Last Menu',0 JP TC7 ; TC15: LD HL,(TCVAR8) ; Point to current table LD DE,16*TCMNT ; Advance to next ADD HL,DE LD (TCVAR8),HL LD A,(TCVAR7) ; Increment menu number INC A LD (TCVAR7),A JP TC7 ; ; Backup to last menu ; TC16: CALL TC29 ; At beginning? JP Z,TC17 CALL PRINT DEFB ' -- Error: Already at First Menu',0 JP TC7 ; TC17: LD HL,(TCVAR8) ; Pt to current table LD DE,-16*TCMNT ; Backup ADD HL,DE LD (TCVAR8),HL LD A,(TCVAR7) ; Decrement menu number DEC A LD (TCVAR7),A JP TC7 ; ; TC18 performs the following functions: ; ; 1. Sets flag if at 1st menu ; 2. Sets flag if at last menu ; 3. Prints menu in 2 columns ; TC18: XOR A LD (TCV10),A ; Save the menu items CALL PRINT DEFB CR,LF,'** Terminal Menu ' DEFB ' for Z3TCAP ' DEFB ' **',CR,LF,CR,LF,0 XOR A LD (TCVAR3),A ; Set not at 1st menu LD (TCVAR4),A ; Set not at nth menu ; ; Determine if at 1st menu ; CALL ENDBBS ; Point to terminal table in DE EX DE,HL LD HL,(TCVAR8) ; Set 1st menu flag PUSH HL XOR A SBC HL,DE POP HL JP NZ,TC19 LD A,0FFH ; Set flag LD (TCVAR3),A ; ; Determine if at nth menu ; TC19: PUSH HL ; Save pointer to current table LD DE,16 ; Size of table entry LD B,TCMNT ; ENTCNT entries per screen ; TC20: LD A,(HL) ; End? CP ' ' ; No entry? JP Z,TC21 ADD HL,DE ; Advance DEC B ; Count down JP NZ,TC20 JP TC22 ; TC21: LD A,0FFH ;at nth menu LD (TCVAR4),A ;set flag ; ; Determine menu bounds ; TC22: LD HL,0 ; Clear pointer to column 2 LD (TCVAR5),HL POP HL ; Get pointer to current table LD B,TCMNT/2 ; Try to advance entcnt/2 entries ; TC23: LD A,(HL) ; No next entry? CP ' ' JP Z,TC24 ADD HL,DE ; Advance to next DEC B ; Count down JP NZ,TC23 LD (TCVAR5),HL ; Save pointer to column 2 ; ; Print menu ; TC24: LD HL,(TCVAR5) ; Get pointer to column 2 EX DE,HL ; In DE LD HL,(TCVAR8) ; Get pointer to column 1 LD B,TCMNT/2 ; Entcnt/2 lines maximum LD C,'A' ; Current letter ; TC25: LD A,(HL) ; Get first character? CP ' ' ; Done? RET Z LD A,C ; Output letter CALL TC27 ; Print entry EX DE,HL ; HL points to column 2 LD A,H ; Done? OR L JP Z,TC26 LD A,(HL) ; Empty? CP ' ' JP Z,TC26 LD A,C ; Get character ADD A,13 ; Add offset CALL TC27 ; TC26: INC C ; Increment menu letter EX DE,HL ; Restore HL/DE PUSH HL PUSH BC PUSH DE CALL PCRLF POP DE POP BC POP HL DEC B ; Count down JP NZ,TC25 RET ;..... ; ; Print entry whose letter is in A and whose text is pointed to by HL, ; advance HL ; TC27: PUSH DE PUSH HL PUSH BC CALL ECHO ; Output character CALL PRINT DEFB '. ',0 POP BC POP HL PUSH BC ; Save registers LD B,16 ; 16 characters ; TC28: LD A,(HL) ; Get character INC HL ; Point to next CALL ECHO ; Print character DEC B JP NZ,TC28 PUSH HL CALL PRINT DEFB ' ',0 ; Separator POP HL POP BC POP DE LD A,(TCV10) INC A LD (TCV10),A RET ;..... ; ; Check to see if this is the first menu ; TC29: LD A,(TCVAR3) ; Get flag OR A RET ;..... ; ; Check to see if this is the last menu ; TC30: LD A,(TCVAR4) ; Get flag OR A RET ENDIF ; TCAP ;..... ; end of TCAP routine ;----------------------------------------------------------------------- ; =F= ; ; Print a menu of the available mail areas including area 0 (GLOBAL) ; then get and validate input. Set (UMAREA) to the input value, but set ; the contents of MAREA to the real (DECODED) area value. After the ; user's input is validated, place the value in UMAREA and jump to UAREA ; to set the acutal values, unless this routine was called called from ; the 'E'nter function. If it was don't show area 0, and just return ; the selected value in 'A'. ; GAREA EQU $ ; IF NMAREAS GT 1 XOR A LD (MLSEL),A CALL PRINT DEFB 'areas',CR,LF,CR,LF DEFB 'Select an area from the following list:' DEFB CR,LF,CR,LF,0 LD HL,ANAMES LD B,35 ; Only B reg for DJNZ length CALL PRINTL ; GAREA1: CALL GAREA3 ; Display names 1 through (MAXAREA) CALL GAREA7 ; Get and validate input PUSH AF ; Save the selected value LD A,(MLSEL) ; Get flag as to type of call OR A ; Is this select from mail enter? JR Z,GAREA2 ; If non-zero it is not, so jump POP AF ; Else restore the requested area CALL UAREA2 ; Map to the real area RET ; Return ; GAREA2: POP AF OR A ; Is it 0 (GLOBAL)? JP Z,UAREA1 ; If yes no table mapping required CALL UAREA2 ; It's not zero so go map the value JP UAREA1 ; Set the value into MAREA ;..... ; ; Print the available area names (1 thru (MAXAREA)) NOW ; GAREA3: PUSH IY LD HL,ANAME1-11 LD IY,ACCTBL ; Acccess table LD D,NMAREAS ; Loop count LD E,0 ; For display PUSH DE PUSH HL ; GAREA4: POP HL POP DE INC IY LD BC,11 ADD HL,BC LD A,(IY+00H) CP 1 JR NZ,GAREA3B PUSH DE PUSH HL CALL PCRLF POP HL POP DE INC E PUSH DE PUSH HL LD L,E LD H,0 CALL PB2ASC CALL PRINT DEFB '. ',0 POP HL PUSH HL LD BC,11 CALL PRINTL POP HL POP DE ; GAREA3B:DEC D PUSH DE PUSH HL JR Z,GAREA6 JR GAREA4 ; GAREA6: POP HL POP DE POP IY RET ;..... ; ; Get and validate the user's input here. If (MLSEL) is now zero, then ; area 0 is an invalid selection. ; GAREA7: CALL PRINT DEFB CR,LF,CR,LF,'Enter area #: ',0 ; GAREA8: CALL GETCH CALL CAPS LD C,A CP '0' JR C,GAREA8 LD A,(MAXAREA) ADD A,030H CP C JR C,GAREA8 LD A,(MLSEL) OR A JR Z,GAREA9 LD A,C CP '0' JR Z,GAREA8 ; GAREA9: LD A,C CALL ECHO SUB 30H LD (UMAREA),A RET ;..... ; ; The number of the area the user wanted is in'A' ; UAREA: OR A ; Is it 0 (GLOBAL)? JR Z,UAREA1 ; If yes no table mapping required CALL UAREA2 ; It's not zero so go map the value ; UAREA1: CALL UAREA4 ; Set the value into MAREA JP HMENU ;..... ; ; Using the value in UMAREA scan the ACCTBL for the UMAREAth area the ; user has access to, place the table position value in 'A' and then re- ; turn. The number of the area the user wanted is in'A' ; UAREA2: LD IX,ACCTBL ; Set IX to first table entry LD C,A ; Area user wanted into 'C' LD D,0 ; Clear 'D' and 'E' for counters LD E,D ; UAREA3: INC IX ; Point to next table entry INC E ; Increment table loop counter LD A,(IX+00H) ; Get access code OR A ; Is it zero JR Z,UAREA3 ; Yes, go chech next entry INC D ; No increment valid counter LD A,C ; Get desired area back CP D ; Eaual to valid counter JR NZ,UAREA3 ; No, try next entry LD A,E ; Yes, table ineex into A RET ;..... ; ; Update (MAREA) with the value in 'A' which is the decoded value for ; the user's selected area (UMAREA). ; UAREA4: LD (MAREA),A RET ;..... ; ; Display the area number and name of the currently active area, or ; area 0 if universal. ; SAREA: CALL PRINT DEFB 'Current area is: ',0 LD A,(MAREA) ; SAREA2: LD HL,ANAMES+3 ; Point to "GLOBAL" area OR A CALL NZ,CNAME ; If not zero go set 'HL' to name LD BC,25 ; Print the name (null terminated) CALL PRINTL CALL PCRLF ; Finish the line RET ;..... ; ; Get the area name of the active area and display it after the ; user's area number (may not be the actual area number) ; CNAME: LD HL,ANAME1 ; Point to area names DEC A ; Decrement for base 0 LD D,A ; Multiply by 11 ADD A,A LD C,A ADD A,A ADD A,A ADD A,C ADD A,D LD B,0 LD C,A ; 'BC' now has offset ADD HL,BC ; Add to base to form true address RET ENDIF ; NMAREAS GT 1 ;..... ; ; This routine outputs the string pointed at by HL to the local console ; only, without going out the modem. String must be terminated with a ; null (0). ; PRLC: LD A,(HL) ; Get character OR A ; Null? RET Z ; Yes, all done ; LD E,A ; Setup for BDOS LD C,RCONOT ; BYE's console only call PUSH HL CALL SPBDOS ; Send it POP HL INC HL ; Next character JR PRLC ; And loop till null found ;..... ; ; This routine will convert a binary number 0-99 in (A), to two ASCII ; digits. ASCII is returned in (A)=most sign. nibble, (B)=LSN. ; BIN2ASC:CALL BINBCD ; First convert it to packed bcd LD B,A ; Save binary AND 0FH ; Get LSB ADD A,'0' ; Make ASCII LD C,A ; Save it LD A,B ; Get binary again RRA RRA RRA RRA AND 0FH ADD A,'0' ; Make ASCII, MSN in (A) LD B,C ; LSN in (B) RET ;..... ; ; This routine will convert a binary 0-99 number to packed BCD. ; Call with (A)=binary number, exits with (A)=BCD number ; BINBCD: PUSH DE LD E,255 ; -1 ; BLP: INC E ; Increment 10's counter SUB 10 ; Sub 10 each pass JR NC,BLP ADD A,10 ; Get the number back LD D,A LD A,E RLCA RLCA RLCA RLCA ADD A,D ; Put the two together POP DE RET ;..... ; ; Turn up a new line for SCAN headers and other routines using the ; [more] line count for TWAIT, etc. ; NULIN: LD A,CR CALL ECHO LD A,LF CALL TWAIT ; See if [more] messge is needed yet OR A JP NZ,ECHO POP HL ; Reset stack CALL PRINT DEFB CR,LF,CR,LF,'++ ABORTED ++',0 JP HMENU ;..... ; ; Prints the _______<< line used in various places ; PLINE: PUSH BC ; 'PRINT' wipes out the 'B' register CALL PRINT DEFB CR,0 POP BC ; PLINE1: PUSH BC ; 'PRINT' wipes out the 'B' register CALL PRINT DEFB '_',0 POP BC DJNZ PLINE1 CALL PRINT DEFB '<< ',0 RET ;..... ; ; This type routine does not use the random file buffer(s). It has ; its own sequential read routine and uses the default TBUFF at 80h. ; Point to the file name with HL and call TYPE. File not found will ; cause a default file to be displayed, then return to the caller. ; TYPE: CALL OPEN ; Open text file CP 0FFH ; File not found? requires HBBSUBS.INS JP Z,TYPERR ; Display default file ; TYPE0: PUSH HL ; Save the argument LD HL,PAUSMSG CALL PRINTM ; TYPELN EQU $+1 ; LD A,20 ; 23 for a complete new screen turnover LD (TLINES),A POP HL ; Restore it LD DE,TBUFF ; Set buffer address LD C,SETDMA CALL SPBDOS ; Using BDOS call ; TYPE1: LD BC,80H ; Set character position ; TYPE2: LD A,C CP 80H ; End of buffer yet? JR C,TYPE3 PUSH HL PUSH BC LD DE,FCB LD C,READSEQ ; Read block CALL SPBDOS POP BC POP HL OR A JR NZ,TYPE9 LD C,0 ; Reset character count LD HL,TBUFF ; TYPE3: LD A,(HL) ; Type block AND 7FH ; Strip off any parity CP EOF JR Z,TYPE9 CP CR JR Z,TYPE5 CP LF JR Z,TYPE4 CP TAB JR Z,TYPE6 CALL TYPE8 INC B ; Increment tab JR TYPE7 ; TYPE4: CALL TWAIT OR A ; Check for abort JR NZ,TYPE5 CALL PRINT DEFB CR,LF,'++ ABORTED ++',CR,LF,0 JR TYPE9 ; TYPE5: CALL TYPE8 LD B,0 ; Reset tab JR TYPE7 ; TYPE6: LD A,' ' CALL TYPE8 ; Tab becomes spaces INC B LD A,B AND 7 JR NZ,TYPE6 ; TYPE7: INC C INC HL CALL ABORT JR NZ,TYPE9 ; Aborted JR TYPE2 ; TYPE8: PUSH HL PUSH BC CALL ECHO POP BC POP HL RET ; TYPE9: CALL CLOSE RET ; Done ;..... ; TYPERR EQU $ ; IF MSDOS LD A,SYSDRV ; Reset system drive LD E,A LD C,SELDSK CALL SPBDOS ENDIF ; LD HL,INFOERR JP TYPE ;..... ; MORE: DEFB CR,LF,'[more] ',0 MORE1: DEFB CR,' ',0 ;.... ; TWAIT: PUSH BC PUSH HL PUSH AF LD A,(TLINES) DEC A LD (TLINES),A JR NZ,TWTRTN LD A,(MORFLG) OR A ; [More] on? JR NZ,TWTRTN ; Toggled off, so return ; TWLF: LD HL,MORE CALL PRINTM ; TWAIT1: CALL GETCH CP 'K'-40H JR Z,TWABRT CP 'X'-40H JR Z,TWABRT CP ' ' ; Space bar character? JR C,TWAIT3 ; Unwanted CTL-char, exit JR NZ,TWAIT2 ; Not a space, exit ;;; ;;;;; (Remove the ;;; for line scrolling with space char after [more] ;;; ;;; LD A,1 ; Set accumulated line feeds to 1 ;;; JR TWAIT4 ; Will scroll one line with space bar ; TWAIT2: CALL CAPS CP 'K' JR Z,TWABRT CP 'E' ; 'E' to Exit JR Z,TWABRT CP 'X' JR Z,TWABRT ; TWAIT3: LD A,20 ; TWAIT4: LD (TLINES),A LD HL,MORE1 CALL PRINTM POP AF LD A,CR ; Make the caller print the CR PUSH AF JR TWTRTN ; TWABRT: LD HL,MORE1 CALL PRINTM POP AF XOR A PUSH AF ; TWTRTN: POP AF POP HL POP BC RET ;..... ; ; Calculate the elapsed time ; CALCTIM:LD HL,ONTIM+6 ; Point to start time secs CALL GETBIN ; Get binary LD D,A ; Save it LD HL,CURTIM+6 ; Stop time secs CALL GETBIN LD E,0 ; Reset the borrow flag SUB D ; Subtract JR NC,SKBS ; Skip if no borrow DEC E ; Else make e = ff ADD A,60 ; Make mod 60 ; SKBS: LD HL,ELPTIM+7 ; Point to elapsed time seconds CALL STOR LD HL,ONTIM+3 CALL GETBIN LD D,A LD HL,CURTIM+3 CALL GETBIN INC E ; If not borrow JR NZ,SKBM1 ; Then skip INC D ; Else add borrowed value ; SKBM1: LD E,0 SUB D JR NC,SKBM2 ; Skip if no borrow DEC E ADD A,60 ; Make mod 60 ; SKBM2: LD HL,ELPTIM+4 CALL STOR ; Store it LD HL,ONTIM CALL GETBIN LD D,A LD HL,CURTIM CALL GETBIN INC E JR NZ,SKBH1 INC D ; SKBH1: SUB D JR NC,SKBH2 ADD A,24 ; Add 24 hrs ; SKBH2: LD HL,ELPTIM+1 JR STOR ;..... ; GETBIN: LD A,(HL) ; Get tens AND 0FH LD B,A ; Save XOR A LD C,10 ; Set up multiplier ; MUL: ADD A,C DEC B JR NZ,MUL LD B,A ; Save tens INC HL ; Point to units LD A,(HL) AND 0FH ADD A,B ; Add tens RET ; Return value in ac ;..... ; STOR: LD B,-1 ; TLP: INC B SUB 10 JR NC,TLP ADD A,10 OR 30H LD (HL),A DEC HL LD A,30H ADD A,B LD (HL),A RET ;..... ; KMDLOG: DEFB 0 DEFB 'KMD LOG' ; EXTENT: DEFB 0,0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0 DEFB 0,0,0,0,0 ; RECORD: DEFB 0,0,0 ;..... ; ;----------------------------------------------------------------------- ; ; Data area, double labels used in different routines to avoid confusion ; ; Stack area ; DATA: DEFB 'STACKSTACKSTACKSTACKSTACKSTACKSTACKSTACKSTACKSTACKSTACK' DEFB 'STACKSTACK' STACK: DEFW 0 CCPSTK: DEFW 0 ; Stack storage SPACE: DEFW 0 ; Temporary storage SAVEHI: DEFW 0 ; Allows multiple reviews of messages not read PTR: COUNT: DEFW 0 ; Temporary storage NOFILE: DEFB 0 ; Re-entered HBBS so don't give him a file on exit NOWTNG: DEFB 0 ; No message waiting flag CNTTMP: DEFB 0 ; Temporary storage CNTN: DEFB 0 ; Continous read flag MORFLG: DEFB 0 ; [more] flag toggle MYFLG: DEFB 0 ; "Read my messages" flag PRIVT: DEFB 0 ; For showing private uploads to Sysop RNEW: DEFB 0 ; "NEW" read flag STORE: DEFB 0 ; Xmodem storage flag STATUS: DEFB 0 ; Temporary storage of user flag TMPREC: DEFW 0 ; Storage for user record number HSHREC: DEFW 0 ; Starting hash record FIRST: DEFB 0 ; Flag for first read TRIED: DEFB 0 ; Tries at password NUSR: DEFB 0 ; New user flag PNEW: TWIT: DEFB 0 ; Twit flag set in phone # routine PNEWX: DEFB 0 ; Skips messages already read in NEW routine XPRT: DEFB 0 ; Expert flag QFLAG: DEFB 0 ; Quit flag PFLAG: DEFB 0 ; Public message read flag PMSND: DEFB 0 ; Private mail flag (for send mail) LFLAG: DEFB 0 ; User left message read flag TMPFLG: DEFB 0 ; Temporary flag, clear before using MFTMP: DEFB 0 ; Temporary message waiting count ALLFLG: DEFB 0 ; Public message send flag SYSFLG: DEFB 0 ; Sysop read-all flag TOFLAG: DEFB 0 ; Message 'to this user' flag LINES: DEFB 0 ; Line count for message entry TLINES: DEFB 0 ; TWAIT lines for [more] MSGREC: DEFW 0 ; Message starting record number MTOREC: DEFW 0 ; Record # of user message is being sent to STRTMP: DEFW 0 ; Starting record number for message MTOTMP: DEFS 30 ; Name of user a message is being sent to MSUBTMP:DEFS 26 ; Subject of message being sent SYSDEL: DEFB 0 ; Flag no-kill by Sysop BADCLK: DEFB 0 ; Flag to siginal a bad clock return WHMSG: DEFW 0 ; Storage for himsg if multiple used LASTMSG: LAST: DEFW 0 ; Last message pointer CURREC: DEFW 0 ; Current msgindex record, used in kill routine ; IF TCAP TCMSG1: DEFB ', or + for Next',0 TCMSG2: DEFB ', - for Last',0 TCVAR1: DEFS 1 ; Flag for auto load if '1' no initial menu TCVAR2: DEFS 2 ; Hold area for terminal record number in Z3TCAP file TCVAR3: DEFS 1 ; 1st menu flag TCVAR4: DEFS 1 ; Nth menu flag TCVAR5: DEFS 2 ; Pointer to column 2 entries TCVAR6: DEFS 1 ; Number of 1st data record TCVAR7: DEFS 1 ; Number of current menu TCVAR8: DEFS 2 ; Current table ptr TCVAR9: DEFS 2 ; Table load pointer TCV10: DEFS 2 ; Menu max counter ENDIF ; TCAP ; MAREA: DEFS 1 ; Number of curent area being worked with RMAREA: DEFS 1 ; Auto-replay area number UMAREA: DEFS 1 ; User's selected area (external value) ; function when = to number of areas imple- ; mented function is done. ACCTBL: DEFS 10 ; Area access table, if the byte value is 0 the ; user doesn't have access to a given area ; (his system level is too low, or the Sysop ; has blocked his access via HBBSMNT. MAXAREA:DEFS 1 ; The maximum area this user has access to. ; This is an external number for the user ; interface. Thus user may have access to say ; (real) areas 1,2,3,5, and 6, but his maximum ; area would be 5 and his area numbers for se- ; lection would be 0 (GLOBAL), 1,2,3,4, and 5. ; If the user entered a 5 the value in UMAREA ; would be 5 while the value in MAREA would be ; 6 (real area). MLSEL: DEFS 1 ; Flag for the area selection routines, if value ; is zero call to routines is from the mail ; 'F', '-', or '+' option, if value is -1, ; call to routines is from the mail 'E' op- ; tion when the user is in the 'GLOBAL' mode. ; Can't enter mail into a 'GLOBAL' area, must ; select a valid area. ; EBUF: DEFS 64 ; Edit string buffer RBUF: DEFS 64 ; Replacement string buffer ELEN: DEFB 0 ; Length of old string RLEN: DEFB 0 ; Length of new string NEWFRE: DEFW 0 ; Temp storage DIFF: DEFW 0 ; Ditto COLUMN: DEFB 0 ; Current column counter CRS: DEFB 0 ; Carriage return counter MSGCNT: DEFW 0 ; Messages 'to you' count MSGFLG: DEFB 0 ; Private message check flag NEWMSG: DEFB 0 ; NEW private message count TOSYSOP:DEFB 0 ; Allows private messages to Sysop ; ADR: MSG: DEFW 0 ; Message entry storage MSGARR: DEFW 0 ; Storage for message pointers HBSEND: DEFS 0 ; END