Roberts Labs BBS

Products: TINYBOARD
Developer(s): Kenneth Roberts
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: BBS

Roberts Labs BBS is a bulletin board system program that enables remote callers to connect via modem, read and leave messages, enter chat mode with the sysop, and access daily specials and system data. The system stores up to 40 messages (CODE “(“) of 564 characters each in a two-dimensional string array, with message counts and indices persisted to tape as separate DATA files. Three machine code routines are POKEd into RAM at addresses 65000–65212: a modem status checker, a receive (input) routine, and a transmit (output) routine, all communicating through I/O port 119 (hex 77). Line numbers are stored as variables using VAL “number” throughout, and GO TO/GO SUB targets are resolved through these named variables (e.g., read, quit, menu), making the flow table-driven and easily reconfigurable. The sysop menu allows reading, deleting, and entering messages locally, toggling chat availability and password protection, saving the message base to tape, and editing the logon bulletin and daily special.


Program Analysis

Program Structure

The program is organized into distinct functional blocks identified by line-number ranges, with all major entry points stored as numeric variables initialized in the setup block around lines 9009–9011. This means GO TO read, GO TO quit, GO TO menu, etc., are not labels but variable references resolved at runtime, allowing the entire routing table to be changed in one place.

Line RangeFunction
1000–1020Auto-answer / idle loop (awaiting call)
2001–2070Logon sequence and main menu dispatcher
3000–3060Read messages
4010–4070Leave a message
4500–4620Message log viewer
5000–5130Quit / disconnect sequence
6000–6040Logon bulletin display (subroutine)
6500–6630New logon bulletin / daily special input
7000–7162Chat mode with sysop
7500–7570Numeric input subroutine (innum)
7600–7650Access code verification (incode)
8001–8020Name/string input subroutine (inname)
8100–8175Send string / CR subroutines
8200–8210Password management
8500–8599Sysop (local) menu
8600–8810View/edit logon text and systems data
9004–9100Initialization and variable setup
9510–9540Machine code loader
9992–9993Timer subroutine
9995–9999Save routines and stop

Machine Code Routines

Three Z80 machine code routines are loaded via READ/POKE loops in the subroutine starting at line 9510. All three communicate with the modem through I/O port 119 (0x77).

AddressSize (bytes)PurposeVariable
650009Modem status check — returns 0 (tx ready), 1 (rx ready), or 2 (both)statchk
6510033Blocking receive: waits for rx-ready, reads a byte from port 115input
6520013Transmit-ready check (used as boolean via USR output)output

The status routine at 65000 decodes the low two bits of port 119: bit 0 = TX ready, bit 1 = RX ready, returning a composite value. The receive routine at 65100 polls until RX ready, then reads from port 115 (CODE "s"). The transmit check at 65200 is used inline throughout as a boolean guard: IF USR output THEN : OUT CODE "s",....

The data bytes for the routines (lines 9515, 9525, 9535) decode as follows for the status checker: XOR A / IN A,(119) / AND 3 / LD C,A / LD B,0 / RET — returning the two status bits as a small integer to BASIC via the BC register pair.

Variable-as-Line-Number Idiom

All subroutine and branch targets are stored in numeric variables at initialization time (lines 9009–9011). For example, LET quit=VAL "5000", LET menu=VAL "2006", LET read=VAL "3000". Every subsequent GO TO quit or GO SUB cr resolves through the variable rather than a literal line number. This is an intentional design choice that centralizes routing and reduces the cost of reorganizing the program, as only the initialization block need be updated.

Message Storage

Messages are stored in the two-dimensional string array m$(), dimensioned as DIM m$(CODE "(", VAL "564") — that is, 40 messages (CODE "(" = 40) of 564 characters each. Each message uses a fixed internal layout:

  • Characters 1–4: “TO: ” header
  • Characters 5–32 (approx): addressee name
  • Characters 33 (CODE "!") to 38 (CODE "&"): “FROM: ” header
  • Characters 39 (CODE "'") to 64 (CODE "@"): sender’s username (u$)
  • Characters 65 (CODE "A") onward: message body, terminated by CHR$ PI (null/zero)

The message counter y1 wraps at 40, implementing a circular buffer. The counter and the array are saved to tape separately: SAVE "mbase" DATA m$() and SAVE "msctr" DATA y(), where y() is a 1×1 numeric array used purely to persist y1.

ON ERR Usage

ON ERR GO TO quit and ON ERR GO TO inputcom appear at several points (lines 2037, 4020, 7515, 7610). These act as timeout or disconnect handlers — if the remote end drops carrier mid-input, the USR call or I/O operation will error and the program jumps cleanly to the quit or menu routine rather than halting.

Timer Implementation

The timer subroutine (lines 9992–9993) reads the system frame counter from addresses 23672–23674 (the three-byte ticker), divides by CODE "<" = 60 to convert to seconds, then extracts hours and minutes. It formats the result into the 5-character string x$ by printing to line 21 and reading back with SCREEN$. Line 2036 checks whether the elapsed time exceeds 30 minutes (VAL x$(4 TO SQR EXP PI) > VAL "30"), enforcing a session time limit.

Chat Mode

Chat mode (lines 7000–7162) first pages the sysop with beeps and a dash-progress indicator. If the sysop does not respond within 128 iterations, a “not available” message is sent and the caller returns to the menu. Once the sysop responds, a full-duplex polling loop runs: the status routine at 65000 is called each iteration; if RX ready, a byte is received and displayed with the receive routine; if TX ready and a local key is pressed, the key is transmitted via OUT CODE "s". The sysop exits chat by pressing the key whose code matches CODE "NOT " (Sinclair NOT token, entered via Symbol Shift+S).

Sysop Local Menu

The sysop menu (lines 8500–8599) is accessible from the idle screen via the NOT keypress and provides local-only functions unavailable to callers:

  • Read any message by number with full field display
  • Delete a message (replaces content with “NO MESSAGE FOUND…………”)
  • Leave a message locally via direct keyboard entry
  • Toggle password protection (o flag) and chat availability (b flag)
  • Save the message base to tape
  • Edit the logon bulletin (t$) and daily special (h$)
  • Enter systems data string (z$)
  • View current logon and daily special text

Notable Techniques and Idioms

  • SGN PI is used throughout as a constant 1 (since PI > 0), and NOT PI as 0 (since PI is nonzero, NOT returns 0). INT PI = 3, SQR EXP PI = 5, PI*PI = ~9 are used similarly as compact numeric literals.
  • CODE "w", CODE "s", etc., provide port numbers as character codes (119, 115), avoiding magic numbers in the source while remaining readable.
  • POKE VAL "23692", CODE " COPY " appears before each character output to reset the FRAMES counter used for the BREAK key mechanism, effectively suppressing BREAK during modem I/O.
  • The DIM l$(VAL "564") blank template at line 4011 is reused to clear message slots: LET m$(x) = l$ efficiently fills an entire row with spaces.
  • Line 8530’s sysop message-read function prints three slices of m$(x) using slice notation to display the TO, FROM, and body fields separately on screen.

Anomalies and Points of Interest

  • Line 8011: IF CODE v$ = VAL "13" THEN GO TO menu inside the inname subroutine — pressing Enter during name input silently jumps to the menu rather than returning to the caller, which could cause unexpected flow if inname is called from contexts other than logon.
  • Line 9009 sets LET z$="\''"` — but z$ is also used as the “systems data” string (set by line 8800 INPUT ... LINE z$). The initialization value appears to be a placeholder block graphic character.
  • Line 2004: IF o = SGN PI skips code verification when o = 1, but o is initialized to NOT PI = 0 and incremented in line 8200 — the password toggle logic uses o as both a flag and a counter, which could cause the bypass condition to be reached after two password changes.
  • Line 7006 has a structural ambiguity: the NEXT x appears on the same line as two IF tests and a BEEP, meaning NEXT x only executes when INKEY$ = "", effectively terminating the loop early if any key is pressed — this is the intended paging mechanism.
  • Line 9100 unconditionally does GO TO quit immediately after initialization completes, so the very first action after setup is always to execute the disconnect/reset sequence, which then jumps to autoans (line 1000) to begin waiting for calls.

Content

Appears On

Related Products

Bulletin board software, written by Randy and Lucy Gordon. The original Tinyboard BBS software program provided the ability of an...

Related Articles

Related Content

Image Gallery

Source Code

    3 REM SYMBL SHIFT S "NOT"         ENDS CHAT MODE FOR SYSOP.
    5 REM SYMBL SHIFT 2 "@"           SAVES MESSAGE FOR SYSOP.
   10 GO TO VAL "9000"
 1000 PRINT "AWAITING A CALL"
 1001 OUT VAL "119",VAL "34"
 1002 OUT VAL "119",NOT PI
 1010 PRINT AT VAL "4",NOT PI;"CHAT IS        ";b$
 1011 PRINT AT VAL "10",NOT PI;"CODE ENTRY IS  ";s$
 1012 PRINT AT PI+PI,NOT PI;"CALLS RECEIVED  ";s
 1014 PRINT AT VAL "8",NOT PI;"MESSAGES        ";w
 1015 LET a=IN CODE "w"
 1016 IF CODE INKEY$=CODE "NOT " THEN GO TO edit
 1020 IF a=VAL "5" THEN GO TO ansloop
 1070 OUT CODE "w",VAL "2"
 1080 OUT CODE "w",VAL "34"
 1090 PAUSE VAL "300"
 2001 OUT CODE "w",CODE "@": OUT CODE "w",CODE "{": OUT CODE "w",CODE "7": POKE VAL "23674",NOT PI: POKE VAL "23673",NOT PI: POKE VAL "23672",NOT PI
 2003 PAUSE CODE "x": CLS : GO SUB logonbull: LET x=IN CODE "s": LET p$="Full NAME: ": GO SUB send: GO SUB inname: LET u$=y$:: LPRINT u$
 2004 IF o=SGN PI THEN GO TO VAL "2006"
 2005 LET f=NOT PI: LET f1=f: LET p$="Code Input: ": GO SUB send: GO SUB incode
 2006 LET y=f: RESTORE VAL "2007"
 2007 DATA "--------------------------------","  *>*> EXECUTIVE MAIN MENU <*<*","<R>ead Messages  <L>eave Message","<C>hat Mode      <T>ime On","<D>aily Special  <S>ystems Data","<M>essage Log    <G>oodbye","--------------------------------","Choice?: "
 2008 GO SUB cr:: IF USR output THEN : OUT CODE "s",CODE " ": PRINT 
 2020 FOR p=SGN PI TO VAL "8": PRINT : IF USR output THEN : OUT CODE "s",VAL "13" AND p<VAL "8": READ p$: GO SUB send
 2034 NEXT p
 2036 GO SUB timer: IF VAL x$(VAL "4" TO SQR EXP PI)>VAL "30" THEN LET f1=SGN PI: GO TO quit
 2037 ON ERR GO TO quit: LET c$=CHR$ USR input: PRINT c$: PRINT 
 2038 IF c$="d" OR c$="D" THEN LET p$=h$: OUT CODE "s",VAL "13": GO SUB send: PAUSE CODE "x": GO TO inputcom
 2039 IF c$="s" OR c$="S" THEN LET p$=z$: OUT CODE "s",VAL "13": GO SUB send: PAUSE CODE "x": GO TO inputcom
 2040 IF c$="r" OR c$="R" THEN FOR x=SGN PI TO SQR PI: GO SUB cr:: NEXT x: GO TO read
 2041 IF c$="t" OR c$="T" THEN GO SUB timer: LET p$="Connect Time ": LET p$=p$+x$: GO SUB scr::: GO TO menu
 2043 IF c$="M" OR c$="m" THEN GO TO VAL "4500"
 2045 IF c$="c" OR c$="C" THEN GO TO chat
 2047 IF c$="g" OR c$="G" THEN PAUSE VAL "30": GO TO quit
 2050 IF c$="l" OR c$="L" THEN GO TO leave
 2070 GO TO inputcom
 3000 LET p$="Message Number? ": GO SUB send: GO SUB innum
 3015 LET y=numin
 3018 IF m$(y,SGN PI)=" " THEN LET p$(SGN PI TO VAL "28")="No message Found............": LET p$=p$(SGN PI TO VAL "28")+CHR$ PI: GO SUB scr::: GO TO inputcom
 3019 PRINT AT VAL "21",NOT PI;"                                ": PRINT AT VAL "21",NOT PI;y: LET c$=SCREEN$ (VAL "21",NOT PI): LET c$=c$+SCREEN$ (VAL "21",SGN PI): LET p$="MESSAGE NUMBER: "+c$: GO SUB cr: GO SUB scr
 3024 FOR v=SGN PI TO VAL "563": POKE VAL "23692",CODE " COPY "
 3025 IF CODE m$(y,v)=INT PI THEN LET v=VAL "564": NEXT v: PAUSE CODE "<": GO TO VAL "3036"
 3030 PRINT m$(y,v);: IF USR output THEN : OUT CODE "s",CODE m$(y,v)
 3031 IF v>CODE "@" THEN NEXT v
 3032 IF (v>CODE " " AND CODE m$(y,v)=VAL "13") THEN LET v=CODE "@": GO SUB cr:
 3033 IF (v<CODE " " AND CODE m$(y,v)=VAL "13") THEN LET v=CODE " "
 3035 NEXT v: GO SUB cr: GO SUB sendv
 3040 LET p$="Read Another? (Y/N) ": GO SUB scr:::
 3042 LET v$=CHR$ USR input: PRINT v$
 3045 IF v$="y" OR v$="Y" THEN GO TO read
 3060 GO TO inputcom
 4010 LET y1=y1+SGN PI: IF y1>CODE "(" THEN LET y1=SGN PI
 4011 DIM l$(VAL "564"): LET m$(y1)=l$
 4012 GO SUB cr: LET p$="To Whom? : ": GO SUB send: ON ERR GO TO inputcom: LET m$(y1,SGN PI TO VAL "4")="TO: ": FOR x=SQR EXP PI TO CODE " ": LET m$(y1,x)=CHR$ USR input: PRINT m$(y1,x);
 4013 IF CODE m$(y1,x)=VAL "13" THEN LET x=CODE " "
 4014 NEXT x
 4015 LET m$(y1,CODE "!" TO CODE "&")="FROM: ": LET m$(y1,CODE "'" TO CODE "@")=u$
 4018 GO SUB cr: LET p$="Input Message (500 chars Max)..Type<CONTROL C> To Save...": GO SUB scr:
 4019: FOR x=SGN PI TO SQR PI: GO SUB cr: NEXT x
 4020 ON ERR GO TO quit: FOR v=CODE "A" TO VAL "563": POKE VAL "23692",CODE " COPY ": LET m1=USR input
 4050 LET m$(y1,v)=CHR$ m1: PRINT m$(y1,v);: IF m1=INT PI THEN LET v=VAL "564": NEXT v: LET w=w+SGN PI: LET p$="SAVED...": GO SUB cr: GO SUB scr: PAUSE VAL "30": GO TO inputcom
 4053 IF CODE m$(y1,v)<VAL "8" OR CODE m$(y1,v)>CODE "z" THEN LET m$(y1,v)=CHR$ PI: LET v=VAL "564": NEXT v: GO TO inputcom
 4054 IF CODE m$(y1,v)>=VAL "24" AND CODE m$(y1,v)<=VAL "31" THEN LET m$(y1,v)=CHR$ PI: LET v=VAL "564": NEXT v: GO TO inputcom
 4055 NEXT v
 4070 GO TO inputcom
 4500 FOR q=SGN PI TO CODE "("
 4510 IF m$(q,1)="T" THEN GO SUB VAL "4600"
 4520 NEXT q
 4530 LET p$="END OF MESSAGE LOG -"
 4535 GO SUB scr: GO TO inputcom
 4600 PRINT AT VAL "21",NOT PI;"                                ": PRINT AT VAL "21",NOT PI;q: LET c$=SCREEN$ (VAL "21",NOT PI): LET c$=c$+SCREEN$ (VAL "21",SGN PI): LET p$="MESSAGE NUMBER: "+c$: GO SUB cr: GO SUB scr
 4610 LET p$=m$(q,SGN PI TO VAL "28")
 4620 GO SUB send: GO SUB cr: RETURN 
 5000 LET n$="\d\i\s\c\oN\n\e\c\t": BORDER NOT PI: CLS 
 5001 ON ERR RESET 
 5105 CLS : PAUSE PI*PI
 5110 LET p$="*****Thank You For Calling!*****"+q$+"    >>ROBERTS LABS. B.B.S.<<    "+q$+"      Goodbye - "
 5112 IF f=SGN PI THEN LET p$(SGN PI TO VAL "28")="YOU ENTERED AN IMPROPER CODE"
 5113 IF f1=SGN PI THEN LET p$(SGN PI TO VAL "28")="SORRY - YOUR TIME IS UP....."
 5115 PAUSE VAL "30": CLS : IF USR output THEN : OUT CODE "s",VAL "28": IF USR output THEN : OUT CODE "s",VAL "31"
 5120 GO SUB send
 5121 PAUSE CODE "x"
 5125 OUT CODE "w",CODE "@": OUT CODE "w",NOT PI: OUT CODE "w",NOT PI
 5130 PAUSE CODE "x": CLS : GO TO autoans
 6000 LET s=s+SGN PI
 6001 PAUSE CODE "<": FOR x=SGN PI TO VAL "30": IF USR output THEN : OUT CODE "s",NOT PI: NEXT x
 6002 IF IN CODE "w"<CODE "\  " THEN GO TO quit
 6005 IF USR output THEN : OUT CODE "s",VAL "28": IF USR output THEN : OUT CODE "s",VAL "31"
 6008 IF USR output THEN : OUT CODE "s",VAL "28"
 6010 FOR x=SGN PI TO VAL "10": GO SUB cr: NEXT x
 6020 FOR x=SGN PI TO LEN t$: POKE VAL "23692",CODE " COPY ": PRINT t$(x);: IF USR output THEN : OUT CODE "s",CODE t$(x): NEXT x
 6025 FOR x=SGN PI TO LEN j$: POKE VAL "23692",CODE " COPY ": PRINT FLASH SGN PI;j$(x);: IF USR output THEN : OUT CODE "s",CODE j$(x): NEXT x
 6030 FOR x=SGN PI TO SQR EXP PI: GO SUB cr: NEXT x
 6040 RETURN 
 6500 CLS : LET t$=""
 6510 INPUT AT VAL "22",NOT PI;AT NOT PI,NOT PI; LINE t$
 6530 CLS : GO TO VAL "8500"
 6600 CLS : LET h$=""
 6610 INPUT AT VAL "22",NOT PI;AT NOT PI,NOT PI; LINE h$
 6630 CLS : GO TO VAL "8500"
 7000 IF b=SGN PI THEN GO TO VAL "7007"
 7001 REM ON ERR GO TO inputcom
 7003 RANDOMIZE USR 65200
 7004 PRINT : GO SUB cr: LET p$="PAGING SYSOP........": GO SUB send: FOR x=SGN PI TO PI*PI: BEEP VAL ".1",SGN PI: NEXT x: GO SUB cr:
 7005 FOR x=SGN PI TO VAL "128": IF INKEY$<>"" THEN GO TO VAL "7008"
 7006 IF INKEY$="" THEN PRINT "-";: IF USR output THEN : OUT CODE "s",CODE ".": BEEP VAL ".1",PI*PI: NEXT x
 7007 LET p$="The SYSOP is NOT AVAILABLE.....": GO SUB send: FOR x=SGN PI TO PI*PI: BEEP VAL ".1",SGN PI: NEXT x: GO SUB cr: GO TO menu
 7008 GO SUB cr: LET p$="YOU ARE NOW IN CHAT MODE:": GO SUB send: FOR X=SGN PI TO PI*PI: BEEP VAL ".1",SGN PI: NEXT X: GO SUB cr
 7009 CLS : PRINT "You are in chat with            ";u$: PRINT : PRINT "SYMBL SHIFT/NOT TO ESCAPE..."
 7010 IF CODE INKEY$=CODE "NOT " THEN GO TO inputcom
 7011 POKE VAL "23692",CODE " COPY "
 7020 LET rxrdy=NOT PI: LET txrdy=NOT PI
 7100 LET a=USR VAL "65000": LET txrdy=SGN PI AND (a=SGN PI OR a=INT PI): LET rxrdy=SGN PI AND (a=VAL "2" OR a=INT PI)
 7130 IF rxrdy THEN LET k=USR VAL "65100": PRINT CHR$ k;: IF k=VAL "13" THEN PRINT ">";
 7140 IF txrdy AND INKEY$<>"" THEN GO SUB VAL "7160"
 7150 GO TO VAL "7010"
 7160 IF txrdy THEN LET i$=INKEY$: PRINT i$;: OUT CODE "s",CODE i$: FOR x=SGN PI TO SQR EXP PI: NEXT x: IF CODE i$=VAL "13" THEN PRINT ">";
 7161 IF INKEY$<>"" THEN GO TO VAL "7161"
 7162 RETURN 
 7500 DIM g$(2): LET u=SGN PI: GO SUB sendv
 7515 ON ERR GO TO inputcom
 7520 LET v$=CHR$ USR input: IF CODE v$>CODE "/" AND CODE v$<CODE ":" THEN PRINT v$;
 7521 IF CODE v$=VAL "13" THEN GO TO VAL "7530"
 7522 IF CODE v$<CODE STR$ TAN PI OR CODE v$>CODE "9" THEN GO TO VAL "7500"
 7525 LET g$(u)=v$: IF u<INT PI THEN LET u=u+SGN PI
 7530 IF CODE v$=VAL "13" OR u>VAL "2" THEN GO TO VAL "7550"
 7540 GO TO VAL "7520"
 7550 LET numin=VAL g$
 7560 IF numin<SGN PI OR numin>CODE "(" THEN LET numin=SGN PI
 7570 RETURN 
 7600 LET f=NOT PI
 7610 ON ERR GO TO quit
 7630 GO SUB sendv: GO SUB inname: LET x$=y$: PRINT x$
 7640 IF x$=o$ THEN RETURN 
 7650 LET f=SGN PI: GO TO quit
 8001 DIM y$(CODE " "): LET u=SGN PI: GO SUB sendv
 8005 ON ERR GO TO quit: LET v$=CHR$ USR input: PRINT v$;
 8010 LET y$(u)=v$ AND u<CODE " ": LET u=u+SGN PI
 8011 IF CODE v$=VAL "13" THEN GO TO menu
 8020 GO TO VAL "8005"
 8100 FOR x=SGN PI TO LEN p$: POKE VAL "23692",CODE " COPY ": IF USR output THEN : OUT CODE "s",CODE p$(x): PRINT p$(x);: NEXT x: IF c$="c" OR c$="C" THEN RETURN 
 8105 FOR q=SGN PI TO LEN n$: POKE VAL "23692",CODE " COPY ": IF USR output THEN : OUT CODE "s",CODE n$(q): PRINT ; FLASH SGN PI;n$(q);: NEXT q
 8106 RETURN 
 8150 PRINT : IF USR output THEN : OUT CODE "s",VAL "13": RETURN 
 8175 IF USR output THEN : OUT CODE "s",SQR EXP PI: RETURN 
 8200 CLS : PRINT " The CODE is";AT SQR PI,NOT PI;o$;AT VAL "4",NOT PI;" Is this OK? Y/N": INPUT a$: LET o=o+SGN PI
 8210 IF a$="n" THEN PRINT '" INPUT CODE UP TO 32 CHARACTERS";: INPUT k$: IF a$="n" THEN LET o$=k$
 8500 BORDER PI: CLS 
 8501 IF o=SGN PI THEN LET s$="OFF": GO TO VAL "8510"
 8502 LET o=NOT PI: LET s$="ON "
 8505 IF b=SGN PI THEN LET b$="OFF": GO TO VAL "8510"
 8508 LET b$="ON  ": LET b=NOT PI
 8510: PRINT AT NOT PI,VAL "12";"SYSOP MENU";AT SQR PI,NOT PI;"<R>EAD MESSAGES"," <P>ASSWORD ";s$;AT VAL "4",NOT PI;"<D>ELETE MESSAGES";AT VAL "6",NOT PI;"<L>EAVE MESSAGES";AT VAL "8",NOT PI;"<Q>UIT MENU","  <C>HAT IS ";b$;AT VAL "10",NOT PI;"<S>AVE MESSAGE BASE";AT VAL "12",NOT PI;"<N>EW LOGON BULLETIN";AT VAL "14",NOT PI;"<I>NPUT DAILY SPECIAL";AT VAL "16",NOT PI;"<E>NTER SYSTEMS DATA";AT VAL "18",NOT PI;"<V>IEW LOGON & SPECIAL"
 8520 LET i$=INKEY$
 8521 IF I$="n" THEN GO TO VAL "6500"
 8522 IF i$="q" THEN GO TO quit
 8523 IF i$="i" THEN GO TO VAL "6600"
 8524 IF i$="v" THEN GO TO VAL "8600"
 8525 IF i$="" THEN GO TO VAL "8520"
 8526 IF i$="s" THEN GO TO VAL "9999"
 8527 IF i$="e" THEN GO TO VAL "8800"
 8528 IF i$="p" THEN GO TO VAL "8200"
 8529 IF i$="c" THEN LET b=b+SGN PI: GO TO VAL "8505"
 8530 IF i$="r" THEN INPUT ;"MESSAGE #?: ";x: CLS : PRINT "MESSAGE # ";x: PRINT m$(x)(SGN PI TO CODE " ")'m$(x)(CODE "!" TO CODE "@")'m$(x)(CODE "A" TO ): PRINT "PRESS ENTER TO CONTINUE": PAUSE NOT PI: GO TO edit
 8540 IF i$="d" THEN INPUT "message #?: ";x: PRINT "message # ";x;" deleted.": LET m$(x)=l$: LET m$(x,SGN PI TO VAL "28")="NO MESSAGE FOUND............": PAUSE NOT PI: GO TO edit
 8550 IF i$="l" THEN LET y1=y1+SGN PI: CLS : PRINT "message # ";y1: PRINT : GO SUB VAL "8700": FOR x=SGN PI TO VAL "564": LET m$(y1,x)=w$(x): PRINT m$(y1,x);
 8551 IF m$(y1,x)="@" THEN LET m$(y1,x)=CHR$ PI: LET x=VAL "600": PRINT "SAVED...": PAUSE CODE "<": GO TO VAL "8500"
 8554 IF i$="l" THEN IF CODE INKEY$=CODE "NOT " THEN LET m$(y1,x)=CHR$ PI: GO TO edit
 8560 IF i$="l" THEN NEXT x: PAUSE NOT PI: GO TO edit
 8599 CLS : GO TO edit
 8600 CLS : PRINT "LOGON"'t$: PAUSE NOT PI
 8610 CLS : PRINT "DAILY"'h$: PAUSE NOT PI
 8620 GO TO VAL "8500"
 8700 INPUT AT VAL "22",NOT PI;AT SQR PI,NOT PI; LINE w$
 8710 RETURN 
 8800 INPUT AT VAL "22",NOT PI;AT NOT PI,NOT PI; LINE z$
 8810 GO TO VAL "8500"
 9004 PAPER NOT PI: BORDER NOT PI: INK VAL "7": CLS 
 9005 CLEAR VAL "64999": GO SUB VAL "9500"
 9006 LET c$="": LET u$="": LET z$="": LET f1=NOT PI: DIM y(SGN PI,SGN PI): LET y1=NOT PI: DIM l$(VAL "564"): DIM m$(CODE "(",VAL "564"): FOR x=SGN PI TO CODE "(": LET m$(x)="NO MESSAGES FOUND..."+CHR$ PI: NEXT x: FOR x=SGN PI TO PI: BEEP VAL ".1",EXP PI: NEXT x: PRINT '"Do you wish to LOAD a message   base?": INPUT x$: IF x$="y" OR x$="Y" THEN PRINT '"Start MESSAGE BASE tape...       (2 part LOAD...)": LOAD "" DATA m$(): LOAD "" DATA y(): LET y1=y(SGN PI,SGN PI)
 9007 LET q$="                                ": LET t$="      ROBERTS LABS. B.B.S.      "+q$+q$: LET j$="   For PROFESSIONAL use only.   ": FOR x=SGN PI TO PI: BEEP VAL ".1",EXP PI: NEXT x: PRINT '"Do You wish to load a logon     bulletin?": INPUT x$: IF x$="y" THEN PRINT '"Start bulletin Tape...": LOAD "" DATA t$()
 9008 PRINT '"<NOT> from most modes will exit to SYSOP mode.": PAUSE CODE "TAN "
 9009 LET f=NOT PI: LET y=NOT PI: LET edit=VAL "8500": LET timer=VAL "9990": LET innum=VAL "7500": LET z$="\''"
 9010 LET sendv=VAL "8175": LET scr=VAL "4620": LET cr=VAL "8150": LET chat=VAL "7000": LET menu=VAL "2006": LET warmstart=VAL "2000": LET logonbull=VAL "6000": LET statchk=VAL "65000": LET input=VAL "65100": LET output=VAL "65200": LET ansloop=VAL "1010": LET inputcom=VAL "2006": LET autoans=VAL "1000": LET read=VAL "3000": LET leave=VAL "4000": LET quit=VAL "5000"
 9011 LET send=VAL "8100": LET inname=VAL "8000": LET incode=VAL "7600": LET h$="No new daily message": LET b$="ON ": LET w=NOT PI: LET s=w: LET b=w: LET o$=".": LET s$="ON": LET o=w
 9012 PRINT '''"  "; FLASH SGN PI;"Now going to autoans mode": PAUSE CODE "TAN ": CLS 
 9100 GO TO quit
 9510 RESTORE VAL "9515": FOR x=VAL "65000" TO VAL "65008": READ x1: POKE x,x1: NEXT x
 9515 DATA 175,219,119,230,3,79,6,0,201
 9520 RESTORE VAL "9525": FOR x=VAL "65100" TO VAL "65132": READ x1: POKE x,x1: NEXT x
 9525 DATA 219,119,230,128,200,175,219,119,230,2,40,244,219,115,6,0,79,219,119,230,128,200,175,219,119,230,1,40,244,121,211,115,201
 9530 RESTORE VAL "9535": FOR x=VAL "65200" TO VAL "65212": READ x1: POKE x,x1: NEXT x
 9535 DATA 219,119,230,128,200,175,219,119,230,1,40,244,201
 9540 RETURN 
 9992 DIM x$(SQR EXP PI): LET time=INT ((PEEK VAL "23672"+VAL "256"*PEEK VAL "23673"+VAL "256"*VAL "256"*PEEK VAL "23674")/CODE "<"): LET hr=INT (time/CODE "<"/CODE "<"): LET min=INT ((time-(hr*CODE "<"*CODE "<"))/CODE "<"): PRINT AT VAL "21",EXP INT PI;"0" AND hr<VAL "10";hr;":";"0" AND min<VAL "10";min: FOR x=SGN PI TO SQR EXP PI: LET x$(x)=SCREEN$ (VAL "21",x+VAL "19"): NEXT x
 9993 RETURN 
 9995 BORDER NOT PI: PAPER NOT PI: INK VAL "7": CLS 
 9996 GO TO PI*PI
 9997 SAVE "rbbs" LINE VAL "9995"
 9998 STOP 
 9999 SAVE "mbase" DATA m$(): LET y(SGN PI,SGN PI)=y1: SAVE "msctr" DATA y(): GO TO edit

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top