I Built Slack in 1996
I was 27, working on a school network, and annoyed. So I wrote a real-time group chat app in QBasic. I just found the source code.
I Built Slack in 1996. I Just Found the Source Code.
In May of 1996, I was 27 years old and working on a Novell NetWare LAN. I was annoyed that people couldn’t easily talk to each other across the network in real time. So I built something.
I called it TALK. I wrote it in QBasic. I compiled it, copyrighted it, and apparently forgot about it for thirty years.
I found the source code recently and ran it through an AI analysis. What came back stopped me cold.
TALK was a fully functional, real-time, multi-user group chat application. Up to 16 people could join a shared chat room simultaneously. It had pulldown menus. It had mouse support -- real mouse support, talking directly to the BIOS at interrupt level. It had private messaging, a session log, a password-protected screen lock, and an auto-correct system that silently fixed common typos as you typed.
It also had an auto-upgrade mechanism that could silently push a new version of itself to every connected client. In 1996.
The architecture was surprisingly sound. User presence was tracked by dropping a small file into a shared network directory -- you existed if your file existed, and you were gone when it was deleted. Messages were passed through a shared utility and polled on a loop. No database. No server process. The filesystem was the protocol.
Slack launched in 2013. IRC existed in 1996, but required setup and infrastructure far beyond most office users. I built something in between: dead simple to run, genuinely real-time, and it worked on hardware most people were using to run WordPerfect.
Is it perfect code? No. Passwords were plaintext. Global variables were everywhere. Every external operation forked a shell process and read results from a temp file on C:. The error handler had a branch that just... retried forever on unknown errors.
But it worked. People used it. And buried in the auto-correct table, I had quietly remapped certain profanities to mixed-case versions of themselves -- apparently my way of keeping things civil on a shared network without actually blocking anything. Thirty years later, I find that funnier than I probably should.
I was 27. I had no CS degree. I was writing interrupt-level code in a language most people used to make guessing games, and I shipped a working distributed messaging app.
I’m 57 now. The code still reads clearly. I’m not sure what that says about me, but I think it says something good.
(CODE)
‘ THIS PROGRAM IS THE SOLE PROPERTY OF THOMAS WELLBORN III
‘ DO NOT DISTRIBUTE THE PROGRAM OR THE SOURCE WITHOUT FULL
‘ CONSENT OF SAID OWNER.
‘ WRITTEN AND COMPILED IN MAY OF 1996 BY THOMAS WELLBORN III
DEFINT A-Z
DECLARE SUB qbmouse (a%, b%, c%, d%)
DECLARE SUB cursor ()
REM $DYNAMIC
REM $INCLUDE: ‘qb.bi’
DIM HiPos1(10), HiPos2(10, 20), MaxSize(10), MaxItems(10), item$(10, 15), valid(10, 15), toggle(10, 15)
DIM reg AS regtype
ON ERROR GOTO oops
CLS
version$ = “3.22”
DIM bright(20)
DATA 2,3,5,7,10,11,13,14,15
DATA 2,3,5,7,10,11,13,14,15
FOR x = 1 TO 18
READ bright(x)
NEXT x
SHELL “dir c:\/b > c:\temp.dat”
OPEN “c:\temp.dat” FOR INPUT AS #2
DO UNTIL EOF(2)
INPUT #2, ask$
IF UCASE$(ask$) = “TALKY.DAT” THEN
tag = 1
END IF
LOOP
CLOSE #2
IF tag = 0 THEN
PRINT “Initializing for first time use...please wait a minute or two...”
SHELL “cd > c:\temp.dat”
OPEN “c:\temp.dat” FOR INPUT AS #2
INPUT #2, J$
CLOSE #2
J$ = LEFT$(J$, 1)
SHELL “dir “ + J$ + “:\talk.exe /b/s/w/p/a > c:\temp.dat”
OPEN “c:\temp.dat” FOR INPUT AS #2
DO UNTIL EOF(2)
INPUT #2, check$
IF UCASE$(RIGHT$(check$, 8)) = “TALK.EXE” THEN
path$ = LEFT$(check$, LEN(check$) - 8)
dupes = dupes + 1
END IF
LOOP
CLOSE #2
IF dupes > 1 THEN
PRINT “You have another program called TALK.EXE on your drive.”
PRINT “Please erase, rename, murder, etc... one of the dupes.”
KILL “c:\temp.dat”
END
END IF
OPEN “c:\talky.dat” FOR OUTPUT AS #2
PRINT #2, path$
CLOSE #2
ELSE
OPEN “c:\talky.dat” FOR INPUT AS #2
INPUT #2, path$
CLOSE #2
END IF
PRINT “Checking version...”
OPEN “f:\users\tom\talk.ver” FOR INPUT AS #2
INPUT #2, ver$
CLOSE #2
GOSUB check.version
PRINT “Setting Parameters....”
DIM chatters$(50)
DIM nick$(50)
DIM correct$(40)
DIM wrong$(40)
LENGTH = 1
csr = 1
col = 1
funky2 = 1
cha$ = “cha”
checktimes = 23
DATA “TEH”,”I “,”ADN”,”DON;T”,”OCCURENCE”,”RECIEVE”,”SEPERATE”,”SHIT”
DATA “FUCK”,”TOM”,”TV”,”DJDK”,”I’M”,”I’LL”,”MONDAY”,”TUESDAY”,”WEDNESDAY”
DATA “THURSDAY”,”FRIDAY”,”SATURDAY”,”SUNDAY”,”EWE”,”,”
DATA “the”,”I”,”and”,”don’t”,”occurance”,”receive”,”separate”,”sHiT”
DATA “FuCk”, “Tom”,”TV”,”hole”,”I’m”,”I’ll”,”Monday”,”Tuesday”,”Wednesday”
DATA “Thursday”,”Friday”,”Saturday”,”Sunday”,”you”,”-”
DATA “/yell”,”/yawn”,”/hilo”,”/hehe”,”/wait”,”/quit”
FOR x = 1 TO checktimes
READ wrong$(x)
NEXT
FOR x = 1 TO checktimes
READ correct$(x)
NEXT x
FOR x = 1 TO 6
READ macros$(x)
NEXT x
‘----------------------------------------------------------------------------
begin:
IF COMMAND$ = “/?” OR LEFT$(COMMAND$, 2) = “/H” THEN
PRINT “No help available yet!”
END
END IF
SHELL “z:\public\send /a=p > c:\temp.dat”
GOSUB your.name
IF LEN(yourname$) > 8 THEN
PRINT “Sorry. This program only supports names with eight characters or less.”
END
END IF
OPEN “f:\users\tom\temp\” + yourname$ + “.” + cha$ FOR OUTPUT AS #2
PRINT #2, “cha”
CLOSE #2
PRINT “Checking for users online.”
PRINT “Initializing Talk files.”
GOSUB welcome.screen
GOSUB check.chatters
IF chatters > 15 THEN
CLS
WIDTH 80, 25
PRINT “Sorry “; yourname$; “. The Room is full. Try again later..”
PRINT “Currently in chat: “
FOR x = 1 TO chatters
PRINT chatters$(x),
NEXT x
KILL “f:\users\tom\temp\” + yourname$ + “.” + cha$
END
END IF
IF sendit$ <> “” THEN
SHELL “z:\public\send “ + CHR$(34) + “xoxoxo” + CHR$(34) + “ to “ + sendit$ + “ > c:\temp.dat”
END IF
IF COMMAND$ <> “” THEN
SHELL “z:\public\send “ + CHR$(34) + yourname$ + “ is requesting a TALK session” + CHR$(34) + “ to “ + COMMAND$ + “ > c:\temp.dat”
END IF
OPEN “c:\talk.dat” FOR OUTPUT AS #2
PRINT #2, “ “
CLOSE #2
IF sendit$ <> “” THEN
b$ = yourname$ + “ HAS JUST ENTERED TALK “
GOSUB send.it
END IF
‘----------------------------------------------------------------------------
bread:
cursor
GOSUB factory
GOSUB menu.bottom
co1 = 2
DO
IF funny = 78 THEN funny = 0
IF VAL(RIGHT$(TIME$, 2)) <> oldtime THEN
COLOR co1, 0
funny = funny + 1
LOCATE 7, funny
PRINT “ “; CHR$(1); “ “
LOCATE 7, 79
PRINT “ “
oldtime = VAL(RIGHT$(TIME$, 2))
co1 = 2
END IF
COLOR 7, 0
LOCATE 42, 1
PRINT “ TALK...Version “; version$;
IF ver$ <> version$ THEN
COLOR 15, 0
PRINT “ (Outdated!)”;
COLOR 7, 0
END IF
PRINT “ Compiled by Tom in May of 1996.”;
LOCATE 4, 2: PRINT TIME$
LOCATE 4, 70: PRINT DATE$
look = look + 1
checkver = checkver + 1
IF checkver = 20000 THEN
checkver = 0
GOSUB check.version
GOSUB menu.bottom
END IF
host = 0
IF look = 1100 THEN
look = 0
SHELL “z:\public\send /p >> c:\talk.dat”
OPEN “c:\talk.dat” FOR INPUT AS #2
LOCATE 9, 3
DO UNTIL EOF(2)
INPUT #2, host$
IF UCASE$(RIGHT$(host$, 8)) = “TALLDONE” THEN
IF UCASE$(yourname$) <> “TOM” THEN
CLOSE #2
CLS
PRINT yourname$; “ has ended chat....”
PRINT “All users are exiting...”
SLEEP 2
GOTO alldone
END IF
END IF
IF UCASE$(RIGHT$(host$, 5)) = “TUPIT” THEN
IF UCASE$(yourname$) <> “TOM” THEN
CLS
PRINT “Hold on.....upgrading to new version”
SLEEP 2
SHELL “copy f:\users\tom\talk.exe “ + path$ + “talk.exe/y > c:\temp.dat”
CHAIN path$ + “talk.exe”
END IF
END IF
IF RIGHT$(host$, 6) = “xoxoxo” THEN
SOUND 3000, 3
CLOSE #2
GOSUB check.chatters
GOSUB menu.bottom
KILL “c:\talk.dat”
REM EXIT DO
ELSEIF host$ <> “” THEN
IF LEFT$(host$, 7) <> “No stor” THEN
COLOR 7, 0
FOR x = 1 TO LEN(host$)
IF MID$(host$, x, 1) = “:” THEN
person$ = LEFT$(host$, x - 1)
x = LEN(host$)
END IF
NEXT x
COLOR 3, 12
FOR x = 1 TO chatters
IF UCASE$(chatters$(x)) = UCASE$(person$) THEN
COLOR bright(x), 0
END IF
NEXT x
LOCATE , 3
IF LEFT$(host$, 3) = “YOU” THEN
COLOR 15, 0
END IF
co1 = 4
PRINT host$
host = host + 1
COLOR 7, 0
END IF
END IF
IF host > 29 THEN
host = 0
LOCATE 9, 3
FOR x = 9 TO 38
LOCATE x, 2
PRINT STRING$(58, “ “);
NEXT x
LOCATE 37, 3
PRINT host$
CLOSE #2
OPEN “c:\talk.dat” FOR INPUT AS #2
OPEN “c:\talk.cha” FOR APPEND AS #3
DO UNTIL EOF(2)
INPUT #2, r$
IF LEFT$(r$, 7) <> “No stor” THEN
PRINT #3, r$
END IF
LOOP
CLOSE #2
CLOSE #3
OPEN “c:\talk.dat” FOR OUTPUT AS #2
PRINT #2, “”
CLOSE #2
OPEN “c:\talk.dat” FOR INPUT AS #2
END IF
LOOP
CLOSE #2
END IF
a$ = INKEY$
IF a$ = CHR$(27) THEN
a$ = “”
GOTO alldone
END IF
IF a$ = CHR$(34) THEN a$ = “’”
IF a$ = “,” THEN a$ = “-”
IF a$ = CHR$(3) THEN
CLS
END IF
IF a$ = CHR$(8) THEN
IF LEN(b$) > 0 THEN
b$ = LEFT$(b$, LEN(b$) - 1)
END IF
ELSEIF a$ <> CHR$(27) THEN
b$ = b$ + a$
END IF
IF a$ <> “” THEN
GOSUB syntax
IF LEN(b$) > 50 THEN
SOUND 3000, 1
b$ = LEFT$(b$, LEN(b$) - 1)
END IF
IF a$ = CHR$(13) THEN
FOR x = 1 TO LEN(b$)
IF MID$(b$, x, 1) = CHR$(13) THEN
MID$(b$, x, 1) = “ “
x = LEN(b$)
END IF
NEXT x
IF LEFT$(b$, 1) = “/” THEN GOSUB special
GOSUB send.it
END IF
IF funky = 1 THEN
FOR x = 1 TO LEN(b$) STEP 2
MID$(b$, x, 1) = UCASE$(MID$(b$, x, 1))
NEXT x
END IF
LOCATE csr, col
COLOR 4, 3
PRINT “ “;
LOCATE 4, 15
COLOR 1, 0
GOSUB syntax
COLOR 4, 3
PRINT b$;
word1$ = b$
word$ = b$ ‘THIS IS IMPORTANT!
COLOR 22, 3
col = POS(0)
csr = CSRLIN
PRINT “_”;
COLOR 4, 3
PRINT “ “;
IF POS(0) > 2 THEN
LOCATE CSRLIN, POS(0) - 2
END IF
END IF
IF LEFT$(a$, 7) = “Bye....” THEN EXIT DO
itemslct = -1
DEF SEG = &H40 ‘Check if ALT key is being pressed
x = PEEK(&H17) ‘Bit 3 will be high if so
DEF SEG ‘2^3 = 8
qbmouse 3, b, mx, my ‘get mouse info
mx = mx / 8 + 1: my = my / 8 + 1 ‘convert to text coordinates
‘If ALT key is pressed, or mouse button pushed while cursor
‘positioned on menu bar, then enter the pulldown routine
IF (x AND 8) OR (b = 1 AND my = 1) THEN
DEF SEG = 0
POKE (1050), PEEK(1052) ‘empty keyboard buffer
DEF SEG
CALL PULLDOWN(menuline$, menurow, menucol, menuattr, hotattr, hiattr, NVattr, HiPos1(), HiPos2(), MaxSize(), MaxItems(), item$(), valid(), toggle(), ms, clearafter, menuslct, shadow, snd, menuslct, itemslct)
‘User input from menu selection:
FOR x = 1 TO chatters
IF item$(menuslct, itemslct) = chatters$(x) THEN
chat$ = chatters$(x)
matchit = 1
PRIV = 1
GOSUB menu.send
END IF
NEXT x
IF item$(menuslct, itemslct) = “About...” THEN
GOSUB about
END IF
FOR x = 1 TO 6
IF item$(menuslct, itemslct) = macros$(x) THEN
b$ = macros$(x)
GOSUB special
GOSUB send.it
END IF
NEXT x
IF item$(menuslct, itemslct) = “View Session” THEN
GOSUB review
END IF
IF item$(menuslct, itemslct) = “Lock...” THEN
a$ = “”
GOSUB lockit
END IF
IF LEFT$(item$(menuslct, itemslct), 4) = “Exit” THEN
a$ = “Bye....I’m leaving Chat!”
GOSUB send.it
GOTO alldone
END IF
IF LEFT$(item$(menuslct, itemslct), 4) = “Send” THEN
a$ = “”
GOSUB send.msg
GOSUB menu.bottom
END IF
IF LEFT$(item$(menuslct, itemslct), 7) = “Refresh” THEN
GOSUB refresh
END IF
IF item$(menuslct, itemslct) = “Upgrade” THEN
SHELL “copy f:\users\tom\talk.exe “ + path$ + “talk.exe/y > temp.dat”
CHAIN path$ + “talk.exe”
END IF
IF item$(menuslct, itemslct) = “DOS Shell” THEN
GOSUB dosshell
END IF
IF item$(menuslct, itemslct) = “Info...” THEN
GOSUB info
a$ = “”
END IF
IF LEFT$(item$(menuslct, itemslct), 4) = “Page” THEN
a$ = “”
page = 1
GOSUB send.msg
GOSUB menu.bottom
END IF
IF LEFT$(item$(menuslct, itemslct), 5) = “Funky” THEN
SOUND 4000, .5
SWAP funky, funky2
GOSUB menu.bottom
a$ = “”
END IF
seed = menuslct
IF seed = 0 THEN seed = 1
qbmouse 2, b, c, d
COLOR 0, 7
LOCATE 1, 1
PRINT menuline$;
qbmouse 1, b, c, d
END IF
LOOP
alldone:
IF sendit$ <> “” THEN
b$ = yourname$ + “ HAS JUST LEFT TALK “
GOSUB send.it
END IF
COLOR 7, 0
CLS
WIDTH 80, 25
PRINT “Removing “; yourname$; “ from talk.”
KILL “f:\users\tom\temp\” + yourname$ + “.” + cha$
PRINT “Setting SEND.exe to receive all messages.”
SHELL “z:\public\send /a > c:\temp.dat”
PRINT “Sending EXIT for user “; yourname$
IF sendit$ <> “” THEN
SHELL “z:\public\send “ + CHR$(34) + “xoxoxo” + CHR$(34) + “ to “ + sendit$ + “ > c:\temp.dat”
END IF
PRINT “Purging old files from temporary directory.”
SHELL “z:\public\purge f:\users\tom\temp”
PRINT “Closing down all i/o streams normally.”
PRINT “Talk is eXiting nicely and cleanly for “; yourname$; “.”
KILL “C:\temp.dat”
KILL “c:\talk.dat”
OPEN “c:\talk.cha” FOR OUTPUT AS #2
PRINT #2, “”
CLOSE #2
KILL “c:\talk.cha”
KILL “c:\fi.lst”
PRINT “Goodbye “; yourname$; “.”
REDIM HiPos1(0), HiPos2(0, 0), MaxSize(0), MaxItems(0), item$(0, 0), valid(0, 0), toggle(0, 0)
qbmouse 2, 0, 0, 0 ‘turn off mouse cursor
END
menu.bottom:
COLOR 7, 0
LOCATE 1, 1
COLOR 0, 7
PRINT menuline$;
COLOR 7, 0
COLOR 9, 0
LOCATE 8, 1
PRINT CHR$(218);
PRINT CHR$(196);
COLOR 9, 0
FOR x = POS(0) TO 79
PRINT CHR$(196);
NEXT x
PRINT CHR$(191);
FOR x = 9 TO 34
LOCATE x, 63
PRINT “ “
NEXT x
COLOR 11, 0
LOCATE 10, 64
PRINT “Current Talkers”
COLOR 12, 0
LOCATE 13, 65
IF LEN(sendit$) < 3 THEN
PRINT “You are alone”
ELSE
PRINT “ You “
END IF
FOR x = 1 TO chatters
IF chatters$(x) <> “” THEN
r = r + 2
LOCATE 13 + r, 66
PRINT nick$(x)
END IF
NEXT x
r = 0
COLOR 4, 3
LOCATE 4, 15
PRINT STRING$(53, “ “);
LOCATE 3, 13
PRINT CHR$(218)
LOCATE 4, 13
PRINT CHR$(179); “>”
LOCATE 5, 13
PRINT CHR$(192)
LOCATE 3, 14
PRINT STRING$(20, CHR$(196)); “ “;
COLOR 12, 3
PRINT yourname$; “ “;
COLOR 4, 3
FOR x = POS(0) TO 67
PRINT CHR$(196);
NEXT x
PRINT CHR$(191)
FOR x = 4 TO 5
LOCATE x, 68
PRINT CHR$(179);
NEXT x
LOCATE 5, 68
PRINT CHR$(217)
LOCATE 5, 14
FOR x = 1 TO 54
PRINT CHR$(196);
NEXT x
COLOR 9, 0
LOCATE 39, 1
PRINT CHR$(192);
PRINT STRING$(78, CHR$(196));
PRINT CHR$(217)
LOCATE 8, 62
PRINT CHR$(194)
FOR x = 9 TO 38
LOCATE x, 62
PRINT CHR$(179)
NEXT x
LOCATE 39, 62
PRINT CHR$(193)
IF message$ <> “” THEN
LOCATE 40, 1
PRINT STRING$(79, “ “);
LOCATE 40, 40 - (LEN(message$) / 2)
COLOR 2, 12
PRINT message$;
END IF
zap = zap + 1
IF zap = 13000 THEN
LOCATE 24, 1
COLOR 7, 0
PRINT STRING$(80, “ “);
zap = 0
message$ = “”
END IF
COLOR 8, 0
LOCATE 40, 1
IF funky = 1 THEN
funky$ = “ Funky=ON “
ELSE
funky$ = “ Funky=Off “
END IF
PRINT funky$;
COLOR 9, 0
FOR x = 9 TO 38
LOCATE x, 1
PRINT CHR$(179)
LOCATE x, 80
PRINT CHR$(179);
NEXT x
COLOR 7, 0
RETURN
syntax:
IF b$ <> “” THEN
J = 1
FOR stretch = LENGTH TO LEN(b$)
char$ = MID$(b$, stretch, 1)
IF char$ = “ “ THEN
FOR y = stretch + 1 TO LEN(b$)
IF MID$(b$, y, 1) <> “ “ THEN
FOR z = 1 TO LEN(b$)
IF MID$(b$, z, 1) = “ “ THEN
checkword$ = MID$(b$, y, z)
FOR check = 1 TO checktimes
IF UCASE$(checkword$) = wrong$(check) THEN
MID$(b$, y, z) = correct$(check)
check = checktimes
END IF
NEXT check
REM z = LEN(b$)
END IF
NEXT z
y = LEN(b$)
END IF
NEXT y
END IF
IF char$ = “.” OR char$ = “?” OR char$ = “!” THEN
FOR y = stretch + 1 TO LEN(b$)
IF MID$(b$, y, 1) <> “ “ AND MID$(b$, y, 1) <> CHR$(13) THEN
MID$(b$, y, 1) = UCASE$(MID$(b$, y, 1))
y = LEN(b$)
END IF
NEXT y
END IF
NEXT stretch
IF LEN(b$) > 15 THEN
LENGTH = LEN(b$) - 14
stretch = 0
END IF
END IF
RETURN
dosshell:
COLOR 7, 0
WIDTH 80, 25
CLS
LOCATE 5
PRINT “Type EXIT to return to talk...”
b$ = “I’m Exiting to DOS Shell...”
GOSUB send.it
SHELL “send/a > c:\temp.dat”
SHELL
SHELL “send/a=p > c:\temp.dat”
WIDTH 80, 43
b$ = “ “ + yourname$ + “ is Back from DosLand.”
GOSUB send.it
a$ = “”
CLS
COLOR 7, 0
CLS
GOSUB check.chatters
GOSUB menu.bottom
COLOR 7, 0
cursor
RETURN
your.name:
SHELL “z:\public\whoami>c:\name.dat”
OPEN “c:\name.dat” FOR INPUT AS #2
FOR x = 1 TO 4
INPUT #2, yourname$
NEXT x
CLOSE #2
KILL “c:\name.dat”
yourname$ = RIGHT$(yourname$, LEN(yourname$) - 12)
FOR x = 1 TO LEN(yourname$)
IF MID$(yourname$, x, 1) = “.” THEN
yourname$ = LEFT$(yourname$, x - 1)
x = LEN(yourname$)
END IF
NEXT x
yourname$ = UCASE$(LEFT$(yourname$, 1)) + LCASE$(RIGHT$(yourname$, LEN(yourname$) - 1))
RETURN
oops:
SELECT CASE ERR
CASE 5
GOTO begin:
CASE 76
PRINT “Either you are NOT connected to the Network OR”
PRINT “your drive mappings are different from the other”
PRINT “users on the network.”
PRINT
PRINT “ Z: should be mapped to nw4/sys:public”
PRINT “ F: should be mapped to nw4/work:users”
PRINT
PRINT “If you are logged to a server other than NW4, this”
PRINT “program will not currently function.”
END
CASE 75
PRINT “I could not write to or access a file that was necessary to run myself.”
PRINT “Operation aborted.”
END
CASE 53
PRINT “File not found. There is a file missing somewhere on the server.”
PRINT “Tell ToM about this.”
END
CASE ELSE
GOTO bread:
END SELECT
RESUME
check.chatters:
sendit$ = “”
FOR x = 1 TO chatters:
chatters$(x) = “”
NEXT x
chatters = 0
SHELL “dir f:\users\tom\temp\*.” + cha$ + “ /b > c:\fi.lst”
OPEN “c:\fi.lst” FOR INPUT AS #2
DO UNTIL EOF(2)
INPUT #2, ca$
chatters = chatters + 1
FOR y = 1 TO LEN(ca$)
IF MID$(ca$, y, 1) = “.” THEN
ca$ = UCASE$(LEFT$(ca$, y - 1))
END IF
NEXT y
chatters$(chatters) = LEFT$(ca$, 1) + LCASE$(RIGHT$(ca$, LEN(ca$) - 1))
nick$(chatters) = LEFT$(ca$, 1) + LCASE$(RIGHT$(ca$, LEN(ca$) - 1))
IF UCASE$(ca$) = UCASE$(yourname$) THEN
chatters = chatters - 1
END IF
LOOP
CLOSE #2
FOR b = 1 TO chatters
sendit$ = sendit$ + chatters$(b) + “ “
NEXT b
GOSUB set.params
GOSUB menu.bottom
RETURN
send.it:
OPEN “c:\talk.dat” FOR APPEND AS #2
PRINT #2, “YOU-> “; b$
CLOSE #2
IF LEN(b$) > 30 THEN
FOR x = 24 TO LEN(b$)
IF MID$(b$, x, 1) = “ “ THEN
b2$ = MID$(b$, x + 1, LEN(b$))
b1$ = LEFT$(b$, x - 1)
x = LEN(b$)
END IF
NEXT x
IF b2$ = “” THEN
b2$ = MID$(b$, 31, LEN(b$))
b1$ = LEFT$(b$, 30)
END IF
b$ = b1$
END IF
LOCATE 4, 15
COLOR 4, 3
PRINT STRING$(51, “ “);
COLOR 7, 0
cursor
IF sendit$ <> “” THEN
SHELL “z:\public\send “ + CHR$(34) + b$ + CHR$(34) + “ to “ + sendit$ + “> c:\temp.dat”
END IF
IF sendit$ <> “” THEN
IF b2$ <> “” THEN
SHELL “z:\public\send “ + CHR$(34) + b2$ + CHR$(34) + “ to “ + sendit$ + “> c:\temp.dat”
END IF
END IF
b$ = “”
b2$ = “”
RETURN
send.msg:
GOSUB header.send
IF page = 1 THEN
LINE INPUT “Page: “; chat$
ELSE
LINE INPUT “Send to: “; chat$
END IF
msg = 1
chat$ = UCASE$(chat$)
IF chat$ = “” THEN
IF page = 1 THEN
page = 0
message$ = “ Page Aborted. “
ELSE
message$ = “ Send Aborted. “
END IF
GOSUB swipe.send
msg$ = “”
RETURN
END IF
GOSUB check.again
IF page = 1 THEN
page = 0
IF matchit = 1 THEN
matchit = 0
SHELL “z:\public\send “ + CHR$(34) + yourname$ + “ is Requesting a TaLk session.” + CHR$(34) + “ to “ + chat$ + “ >c:\temp.dat”
GOSUB swipe.send
message$ = “ “ + chat$ + “ was paged to TaLk. “
ELSE
message$ = “ This user does not exist. “
GOSUB swipe.send
END IF
RETURN
END IF
menu.send:
GOSUB header.send
msg = 1
IF matchit = 1 THEN
matchit = 0
LOCATE 11, 10
PRINT STRING$(58, “ “)
LOCATE 11, 11
PRINT “Message: “;
LOCATE 11, 20
COLOR 16, 2
PRINT “_”;
COLOR 14, 2
DO
ask$ = INPUT$(1)
IF ask$ = CHR$(27) THEN
message$ = “ Message Aborted. “
GOSUB swipe.send
msg$ = “”
RETURN
END IF
IF ask$ = CHR$(13) THEN EXIT DO
IF ask$ = CHR$(8) THEN
IF LEN(msg$) > 0 THEN
ask$ = “”
msg$ = LEFT$(msg$, LEN(msg$) - 1)
ELSE
ask$ = “”
END IF
END IF
IF LEN(msg$) > 40 THEN
SOUND 3000, 2
ask$ = “”
REM msg$ = LEFT$(msg$, LEN(msg$) - 1)
END IF
LOCATE 11, 20
PRINT STRING$(48, “ “)
LOCATE 11, 20
msg$ = msg$ + ask$
PRINT msg$;
COLOR 16, 2
PRINT “_”;
COLOR 14, 2
PRINT “ “;
LOOP
IF msg$ = “” THEN
message$ = “ Message Aborted. “
GOSUB swipe.send
RETURN
END IF
GOSUB swipe.send
IF PRIV = 1 THEN
msg$ = “P:” + msg$
END IF
SHELL “z:\public\send “ + CHR$(34) + msg$ + CHR$(34) + “ to “ + chat$ + “>c:\temp.dat”
IF PRIV = 1 THEN
PRIV = 0
message$ = “ Private msg sent to “ + chat$ + “ “
GOSUB menu.bottom
ELSE
message$ = “ Message sent to “ + chat$ + “ “
END IF
msg$ = “”
ELSE
message$ = “ This user does not exist. “
END IF
RETURN
header.send:
COLOR 14, 2
LOCATE 10, 9
PRINT CHR$(218);
PRINT STRING$(58, CHR$(196));
PRINT CHR$(191)
LOCATE 11, 9
PRINT CHR$(179);
PRINT STRING$(58, “ “);
PRINT CHR$(179)
LOCATE 12, 9
PRINT CHR$(192);
PRINT STRING$(58, CHR$(196));
PRINT CHR$(217)
LOCATE 11, 23
RETURN
swipe.send:
COLOR 7, 0
LOCATE 10
FOR x = 1 TO 3
LOCATE , 9
PRINT STRING$(60, “ “)
NEXT x
GOSUB check.chatters
GOSUB menu.bottom
RETURN
check.again:
OPEN “f:\users\tom\temp\userlist.txt” FOR INPUT AS #4
DO UNTIL EOF(4)
INPUT #4, user1$
IF user1$ <> “” THEN
IF UCASE$(LEFT$(user1$, LEN(chat$))) = UCASE$(chat$) THEN
matchit = 1
END IF
END IF
LOOP
CLOSE #4
RETURN
info:
COLOR 2, 9
LOCATE 8
FOR x = 1 TO 12
LOCATE , 21
PRINT STRING$(40, “ “)
NEXT x
LOCATE 8, 22
PRINT “There is a limit of 16 users who can”
LOCATE , 22
PRINT “chat at one time. I’ve added a few”
LOCATE , 22
PRINT “shortcuts that should speed things up.”
LOCATE , 22
PRINT “We are using the send command which”
LOCATE , 22
PRINT “may cause slowdown if many people are”
LOCATE , 22
PRINT “using it at the same time. Tell me if”
LOCATE , 22
PRINT “you have any problems. The MOUSE and “
LOCATE , 22
PRINT “pulldown menus are now active.”
LOCATE CSRLIN + 2, 22
PRINT “ Compiled 5/30/1996”
LOCATE , 22
PRINT “ Hit any key”
ask$ = INPUT$(1)
COLOR 7, 0
LOCATE 8
FOR x = 1 TO 12
LOCATE , 21
PRINT STRING$(40, “ “)
NEXT x
GOSUB menu.bottom
RETURN
welcome.screen:
PRINT “All paths appear normal. All streams functioning.”
PRINT yourname$; “ is attached to TaLk..”
LOCATE 12, 29
COLOR 8, 2
PRINT “ Hi “; yourname$; “. Welcome to talk.”
SLEEP 2
COLOR 7, 0
LOCATE 12, 29
PRINT “ “
LOCATE 11, 17
COLOR 4, 0
PRINT “Do NOT run this program from a Windows environment.”
LOCATE 12, 18
COLOR 7, 0
PRINT “Do you wish to Page someone to enter Talk? [Y/N]”
LOCATE 14, 18
PRINT “ Hit <space> to enter Talk “;
x = 0
ask$ = INPUT$(1)
LOCATE 12, 20
PRINT “ “
LOCATE 11, 16
PRINT “ “
IF UCASE$(ask$) = “Y” THEN
CLS
LOCATE 12, 20
LINE INPUT “Enter the users name: “; name$
LOCATE 12, 20
PRINT “ “
IF name$ <> “” THEN
SHELL “z:\public\send “ + CHR$(34) + yourname$ + “ is requesting a TALK session” + CHR$(34) + “ to “ + name$ + “ > c:\temp.dat”
message$ = “ “ + name$ + “ paged. “
END IF
END IF
WIDTH 80, 43
RETURN
refresh:
COLOR 7, 0
host = 0
LOCATE 9, 3
FOR x = 9 TO 38
LOCATE x, 2
PRINT STRING$(58, “ “);
NEXT x
OPEN “c:\talk.dat” FOR OUTPUT AS #2
PRINT #2, “”
CLOSE #2
RETURN
review:
OPEN “c:\talk.dat” FOR INPUT AS #2
OPEN “c:\talk.cha” FOR APPEND AS #3
DO UNTIL EOF(2)
INPUT #2, r$
IF LEFT$(r$, 7) <> “No stor” THEN
PRINT #3, r$
END IF
LOOP
CLOSE #2
CLOSE #3
KILL “c:\talk.dat”
SHELL “z:\public\send/a > c:\temp.dat”
SHELL “f:\users\tom\r c:\talk.cha”
SHELL “z:\public\send/a=p > c:\temp.dat”
WIDTH 80, 43
a$ = “”
CLS
COLOR 7, 0
CLS
GOSUB check.chatters
GOSUB menu.bottom
COLOR 7, 0
cursor
RETURN
check.version:
IF ver$ <> version$ THEN
CLS
LOCATE 12, 25
PRINT “ This version is outdated. “
LOCATE , 25
PRINT “Do you wish to upgrade now? [Y/N]”
ask$ = INPUT$(1)
IF UCASE$(ask$) = “Y” THEN
SHELL “copy f:\users\tom\talk.exe “ + path$ + “talk.exe/y > temp.dat”
CHAIN path$ + “talk.exe”
ELSE
CLS
END IF
END IF
RETURN
lockit:
final$ = “”
FIRST$ = “”
second$ = “”
ask$ = “”
ask2$ = “”
CLS
GOSUB menu.bottom
LOCATE 20, 5
PRINT “Enter a password-> “;
DO UNTIL ask$ = CHR$(13)
ask$ = INKEY$
IF ask$ <> CHR$(13) THEN
IF ask$ <> “” THEN
FIRST$ = FIRST$ + ask$
PRINT “*”;
END IF
END IF
IF ask$ = CHR$(27) THEN
CLS
GOSUB menu.bottom
RETURN
END IF
LOOP
LOCATE 20, 5
PRINT “ “
LOCATE 20, 5
PRINT “Enter again to reaffirm-> “;
DO UNTIL ask2$ = CHR$(13)
ask2$ = INKEY$
IF ask2$ <> CHR$(13) THEN
IF ask2$ <> “” THEN
second$ = second$ + ask2$
PRINT “*”;
END IF
END IF
IF ask2$ = CHR$(27) THEN
CLS
GOSUB menu.bottom
RETURN
END IF
LOOP
LOCATE 20, 5
PRINT “ “
IF FIRST$ <> second$ THEN
message$ = “ Passwords do NOT match. “
COLOR 7, 0
CLS
GOSUB menu.bottom
cursor
RETURN
END IF
CLS
GOSUB menu.bottom
qbmouse 2, 0, 0, 0 ‘turn off mouse cursor
DO
LOCATE 12, 20
PRINT “Locked. Password?->”;
DO UNTIL ask2$ = CHR$(13)
ask2$ = INKEY$
IF ask2$ <> CHR$(13) THEN
IF ask2$ <> “” THEN
final$ = final$ + ask2$
PRINT “*”;
END IF
END IF
LOOP
IF FIRST$ = final$ THEN EXIT DO
LOCATE 12, 20
PRINT “ “
ask2$ = “”
final$ = “”
LOOP
LOCATE 12, 20
PRINT “ “
message$ = “ Unlocked “
CALL qbmouse(0, 0, 0, 0) ‘initialize mouse
CALL qbmouse(1, 0, 0, 0) ‘show mouse cursor
CALL qbmouse(10, 0, &H7000, 3844) ‘set mouse cursor
CLS
GOSUB check.chatters
GOSUB menu.bottom
RETURN
special:
IF LEFT$(b$, 5) = “/yell” THEN b$ = “AAAAAAUAUUGUGGHGHGHGHHHH!”
IF LEFT$(b$, 5) = “/yawn” THEN b$ = yourname$ + “ yawns...”
IF LEFT$(b$, 5) = “/hehe” THEN b$ = “HEAHaehhaHEHahehheeae!”
IF LEFT$(b$, 5) = “/quit” THEN GOTO alldone
IF LEFT$(b$, 5) = “/wait” THEN
b$ = “where are you?”: GOSUB send.it
b$ = “are you here?”: GOSUB send.it
b$ = “I’m all alone here.”: GOSUB send.it
b$ = “I’m talking to myself.”: GOSUB send.it
b$ = “I’m dying of lonliness and boredom.”
END IF
IF LEFT$(b$, 5) = “/hilo” THEN
IF word1$ = “” THEN word1$ = “No Text Entered “
FOR x = 1 TO LEN(word1$)
IF MID$(word1$, x, 1) = “ “ THEN
word$ = MID$(word1$, x + 1, LEN(b$) - x)
x = LEN(word1$)
END IF
NEXT x
g$ = word1$
FOR x = 1 TO LEN(g$) - 1
b$ = MID$(g$, x, 1)
GOSUB send.it
NEXT x
word1$ = “”
END IF
RETURN
about:
COLOR 2, 9
LOCATE 8
FOR x = 1 TO 12
LOCATE , 21
PRINT STRING$(40, “ “)
NEXT x
LOCATE 8, 22
PRINT “ “
LOCATE , 22
PRINT “ Welcome to TALK in da classroom “
LOCATE , 22
PRINT “ “
LOCATE , 22
PRINT “Good luck running this on your OWN net.”
LOCATE , 22
PRINT “ “
LOCATE , 22
PRINT “ Version: “; version$
LOCATE , 22
PRINT “ “
LOCATE CSRLIN + 2, 22
PRINT “Compiled 5/30/1996”
LOCATE CSRLIN + 1, 22
PRINT “ Hit any key”
ask$ = INPUT$(1)
COLOR 7, 0
LOCATE 8
FOR x = 1 TO 12
LOCATE , 21
PRINT STRING$(40, “ “)
NEXT x
GOSUB menu.bottom
RETURN
factory:
col = 1 ‘assume color monitor
IF INSTR(COMMAND$, “BW”) THEN col = 0 ‘user wants black/white
ms = 1 ‘assume mouse
IF INSTR(COMMAND$, “IM”) THEN ms = 0 ‘user doesn’t want mouse
COLOR 7, col * 5
bl = 25
FOR i = 1 TO 10 ‘HiPos1() holds the location in each menu
HiPos1(i) = 1 ‘name for the ‘hot’ key - in this case it
NEXT i ‘is the first letter in each name.
‘Load in menu data from data statements at the end of this program
GOSUB set.params
menuline$ = “ File Macros User PrivateMsg About “
menurow = 1 ‘Screen row of menu line
menucol = 1 ‘Beginning column position
menuattr = 7 * 16 + 5 ‘Menu color
hotattr = 7 * 16 + 15 ‘Hot key hilite color
hiattr = 0 * 16 + 2 ‘Hilite bar color
NVattr = 7 * 16 + 8 ‘color for grayed-out
‘selections
clearafter = 1 ‘erase menu after selection
menuslct = 1 ‘menu to start with
snd = 0 ‘turn sound on
shadow = 4
COLOR 0, 7
LOCATE 1, 1
PRINT menuline$;
RETURN
COLOR 7, 0
CLS
END
set.params:
qbmouse 2, 0, 0, 0 ‘turn off mouse cursor
RESTORE pulldownmenudata
FOR menu = 1 TO 5
IF menu = 4 THEN
MaxItems(menu) = chatters
MaxSize(menu) = 10
FOR slct = 1 TO chatters
item$(menu, slct) = chatters$(slct)
HiPos2(menu, slct) = 1
valid(menu, slct) = 1
toggle(menu, slct) = 0
NEXT slct
menu = 5
END IF
READ MaxItems(menu) ‘Number of selections in each menu
READ MaxSize(menu) ‘Max length of items in each menu
FOR slct = 1 TO MaxItems(menu)
READ item$(menu, slct) ‘Text displayed for selection
READ HiPos2(menu, slct) ‘Hot key for each selection in menu
READ valid(menu, slct) ‘Determines if grayed out or not
READ toggle(menu, slct) ‘Determines if selection can be
NEXT slct
NEXT menu
CALL qbmouse(0, 0, 0, 0) ‘initialize mouse
CALL qbmouse(1, 0, 0, 0) ‘show mouse cursor
CALL qbmouse(10, 0, &H7000, 3844) ‘set mouse cursor
RETURN
pulldownmenudata:
‘File menu
DATA 4,13
DATA “Upgrade”,1,1,0
DATA “~”,0,0,0
DATA “DOS Shell”,1,1,0
DATA “Exit (ESC)”,2,1,0
‘Macros menu
DATA 6,10
DATA “/yell “,2,1,0
DATA “/yawn”,3,1,0
DATA “/hilo”,2,1,0
DATA “/hehe”,3,1,0
DATA “/wait”,2,1,0
DATA “/quit”,2,1,0
‘User menu
DATA 9,20
DATA “Send a Message”,1,1,0
DATA “Page User to Talk”,1,1,0
DATA “~”,0,0,0
DATA “Funky Characters”,1,1,0
DATA “~”,0,0,0
DATA “Refresh Screen”,1,1,0
DATA “View Session”,1,1,0
DATA “~”,0,0,0
DATA “Lock...”,1,1,0
‘About menu
DATA 2,10
DATA “Info...”,1,1,0
DATA “About...”,1,1,0
‘Chatters menu
DATA 0,0
‘Debug menu
DATA 0,0
‘Calls menu
DATA 0,0
‘Options menu
DATA 0,0
REM $STATIC
DEFSNG A-Z
SUB cursor
LOCATE 4, 15
COLOR 22, 3
PRINT “_”;
END SUB
DEFINT A-Z
SUB qbmouse (a, b, c, d)
SHARED reg AS regtype
reg.ax = a
reg.bx = b
reg.cx = c
reg.dx = d
CALL interrupt(&H33, reg, reg)
a = reg.ax
b = reg.bx
c = reg.cx
d = reg.dx
END SUB




You should release it on GitHub as OpenSource.😉