Category : BBS Programs+Doors
Archive   : FILEDR31.ZIP
Filename : SLSTUFF.INC

Output of file : SLSTUFF.INC contained in archive : FILEDR31.ZIP
{------------------------------ FILEDEF.LIB: -------------------------------}

{ File Definitions for Searchlight BBS, ver 1.28 }
{ (C) Copyright 1987,88 by Frank LaRosa. ALL RIGHTS RESERVED. }
{ This file contains type declarations for the files created by Searchlight
BBS. We are releasing this information to the public in order to foster
the development of third party DOORware and utility software.

IF YOU USE THIS INFORMATION: Please follow the guidelines carefully.
Searchlight Software cannot be held responsible for failure of third party
software. We reserve the right to change anything in these file definitions
although we will try to keep things as consistent as possible.

All source code is Turbo Pascal 3.0. If you are programming in another
language, note that STRING data types- string[n]- consist of a one-byte
string length followed by an array of n characters. Thus, sizeof(string[n])
equals n+1. Also note that the first record of a file is record 0, while
the first element in an array is (usually) 1. For ordinal types, the
ordinal value of the first element is always 0. }

{ The following files make up the core of the BBS. They will reside in the
current directory when the BBS is run. }

const configspec = 'CONFIG.BBS'; { Configuration & Current Info }
userspec = 'USER.BBS'; { User File }
indexspec = 'INDEX.BBS'; { Sub-Board Index }
textspec = 'MESSAGE.BBS'; { Message Texts File }

logspec = 'LOG.BBS'; { Caller Log }
quotespec = 'QUOTES.BBS'; { Logoff Quotes }
dirspec = 'FILEDIR.DEF'; { UL/DL Directory Definitions }
doorspec = 'DOORS.DEF'; { External Program Definitions }

const maxsub = 24; { max number of sub boards }
maxmsg = 290; { max number of messages per sub }
blocksize = 90; { block size of message texts }
logsize = 75; { size of last caller log }
maxdir = 35; { max number of file directories }

Type { Preliminary Type Definitions }

timetype = record { time }
hour: byte;
minute: byte;

datetype = record { date }
year: byte;
month: byte;
day: byte;

pwtype = array[1..3] of byte; { 3-byte password }

int3 = record { long 3-byte integer }
low: integer;
hi: byte;

RSbaud = (B110,B150,B300,B600,B1200,B2400,B4800,B9600,B19200);
{ rs232 baud rates }

colortype = (NULLCOLOR, { no color set }
NORMAL, { normal screen color for most i/o }
INVERSE, { inverse for input highlighting }
COMCOLOR, { color for command highlight }
SUBCOLOR, { subboard information }
HEADCOLOR, { color for headings }
CHATCOLOR, { chat mode color }
SPECIAL, { special prompts and messages }
ERRCOLOR, { error and warning messages }
ALTCOLOR, { alt. special color }
PROMPTCOLOR ); { colour for prompts }

Type { File Type Definitions }

Configtype = record { format of CONFIG file }

sysname: string[30]; { the name of the BBS }
syscalls: int3; { total calls to system }
comport: byte; { comm port to use, 1-4 }
bsupport: byte; { baud rates supported }
newusers: boolean; { new user registration }
bulletins: integer; { pointer to bulletins }
progpath: string[40]; { path for program files }
textpath: string[40]; { path for text files }

curruser: integer; { current user ID number }
currboard: byte; { current active sub board }
logtime: timetype; { current time of logon }
remote: boolean; { remote/local logon flag }
baudrate: rsbaud; { caller's baud rate }
ansi: boolean; { ANSI graphics mode indicator }
newlogon: boolean; { set if main program not yet run }

lastuser: integer; { last user on the system }
lastquote: string[72]; { quote left by last user }
defaccess: byte; { default new user access level }
deftimelimit: byte; { default new user time limit }
rsactive: boolean; { true if rs port active }
valaccess: byte; { default validation access }
valtimelimit: byte; { default validation timelimit }
deffile: byte; { new user file access }
valfile: byte; { validated file access }

currdir: integer; { current directory }
sysavail: boolean; { sysop availability flag }
logfile: string[40]; { default log file }
paged: boolean; { set if sysop paged }
timelimit: byte; { time limit for this session }

color: boolean; { ANSI color mode indicator }
normback: byte; { textbackground for normal }
invtext: byte; { DEFUNCT }
invback: byte; { textbackground for inverse }

superuser: boolean; { superuser alt-s status }
buffactor: integer; { output buffer size }
hayes: boolean; { unused }
maxmaillen: integer; { max. lines in e-mail }
maxbulllen: integer; { max. lines in bulletins }
laston: datetype; { last logon date of current user }

command: string[80]; { command line of currently active DOOR }
commtype: byte; { command type }
commdir: string[80]; { default dir for command }
wp: boolean; { write protection flag in door }

relogtime: integer; { min. time between logins }

initstr: string[40]; { modem init string }
localstr: string[40]; { modem 'local' init string }
overpath: string[40]; { overlay path }

abort: byte; { abort type, for doors }
defaultpw: string[40]; { default password for uploads }
xratio: byte; { dl/ul ratio }
activlog: boolean; { activity logging flag }
presshard: byte;
modemmsg: boolean; { true for modem msg baud detect }

colorchart: array [NORMAL..PROMPTCOLOR]
of byte; { color definitions }

indoors: boolean; { set if doors menu active }

subtext: array[1..maxsub]
of boolean; { subboard text message flags - these flags are
reset with each call, and set when a user
enters the corresponding subboard }
dirtext: array[1..maxdir]
of boolean; { file dir text message flags }

incpath: string[40]; { path for message include files }
sysfile: string[40]; { path/filename for DOORS setup file }



The CONFIG file is a fixed length, one record file containing the above
information. Typically, a DOORware or utility program will read the config
file to pick up information about the currently active user, comm port,
etc. All items from the CONFIG.COM program are stored here.

The BULLETINS field is a two-byte pointer into the MESSAGE.BBS file,
indicating the header record of the first bulletin. The second bulletin
is chained onto the first via the "ID" field in the message header, etc.
A word of zero indicates the end of the chain.

BSUPPOSRT is a bit field. Bit 0 of this byte is set if 300 baud is
supported, bit 1 is set for 1200 baud support, etc.

ALL FIELDS ARE RESERVED. Searchlight Software reserves the right to use
all unused fields in future versions of Searchlight BBS. If you want to
save your own information, you should create your own data files indexed
on user names and/or record numbers. This goes for the rest of this file
as well. }

type Usertype = record { format of USER file }

name: string[25]; { user name }
location: string[20]; { user location }
passwd: pwtype; { password }
cksum: byte; { checksum of name }
firston: datetype; { date of first logon }
laston: datetype; { date of last logon }
calls: int3; { total number of calls }
systype: string[15]; { system type }
phoneno: string[12]; { phone number }
lasttime: timetype; { time of last logon }
xproto: byte; { default file xfer protocol }
extra: string[7]; { reserved }

access: byte; { BBS access level }
faccess: byte; { file system access level }
access2: byte; { unused }
timelimit: byte; { time limit in minutes }
uploads: integer; { Kbytes uploaded }
downloads: integer; { Kbytes downloaded }

firstmsg: integer; { pointer to first message in mailbox }
lastmsg: integer; { pointer to last message in mailbox }

lastread: array[1..maxsub]
of integer; { last message read pointers }

spare: string[7]; { reserved }

extend: integer; { reserved }
parent: integer; { pointer to parent node }
left,right: integer; { pointers to child nodes }



The USER file is structured as a binary tree. Record 1 is the root of the
tree, and will always contain the SYSOP account. To traverse the tree, use
the pointers LEFT and RIGHT. The PARENT pointer will always point to a
node's parent node. Record zero contains the pointer to the free record
chain; the pointer is stored in the PARENT field. Also in record zero,
field RIGHT contains the total number of users in the file.

A deleted user record is marked with a -1 in the LEFT field and removed
from the tree. If you process the user file sequentially instead of using
tree traversal, you must ignore deleted records.

If you write programs to update this file, you must be extremely careful.
All data structures must be maintained, including the free record list,
the tree pointers, the parent node pointers, etc. Also note that it is
extremely important that data is never moved; Searchlight BBS maintains
pointers to absolute record numbers in this file, and expects that a
user's record will ALWAYS OCCUPY THE SAME PHYSICAL RECORD on the disk.
Consequently, user programs can safely store record numbers for fast access
to the user file. You must, however, ensure that the record still contains
valid information each time you access it. The fastest way to do this is
to store a checksum of the user name with the record number, comparing it
to the CKSUM field above. A checksum failure indicates the user was
deleted from the system and the record reused by another user.

Mail is stored as a pointer to the header of the first message in the
mailbox (firstmsg). Subsequent messages are linked via the ID field in
the message header, with a zero word indicating the end of the list.
The user file also maintains a pointer to the header record of the last
message in the mailbox (lastmsg); this pointer is used to quickly append
messages to the mailbox without having to process the entire linked list.

See notes below concerning passwords. }

type Indextype = record { format of INDEX file }

status: byte; { access level }
name: string[25]; { sub board name }
subsysop: integer; { ID of sub-sysop }

messages: integer; { number of messages on sub }
next: integer; { next MSG ID number }

index: array[1..maxmsg]
of integer; { pointers to messages }
{ maxmsg = 290 for version 1.28-1.29,
maxmsg = 480 for extended vesions }

maxmsglen: integer; { max. message length }
spare: array [1..18]
of byte; { reserved (29 in extended versions) }



The INDEX file is a 24-record file defining the 24 message subboards.
Each subboard contains up to messages (maxmsg=290). The messages
are stored as two-byte pointers into the MESSAGE.BBS file. The first
record of a message contains the header information, followed by a pointer
to the text.

MSG ID number is a sequential number that is incremented with each new
message posted. It is stored in the header of each message, and in the
"last message read" fields in the USER file. Since this number is always
increasing, it is used for the NEW scan to determine which messages are
new, regardless of how many deletions have taken place.

In shareware versions, the 'index' array consists of 290 two-byte
numbers, yielding a total record size of 633 bytes. In extended versions,
the index size is increased to 480 words and the reserved area to 29
bytes, giving a record size of 1024 bytes. This difference must be kept
in mind if you will be writing software designed to process files used
with either version.

It is important to note that messages do not, for all practical purposes,
have numbers. The index file is simply an array of pointers. To delete
a message, you remove the pointer from the array, and move all subsequent
pointers up by one. }

type Textype = record { format of MESSAGE file }

next: integer; { next record of message }
copies: integer; { number of active copies }

case header: boolean of

true: ( { message header }
id: integer; { message ID number (public msg)/
next message pointer (mail/bulletin) }
from: integer; { ID of sender }
cksum: byte; { sender's checksum }
time: timetype; { time recorded }
date: datetype; { date recorded }
rd: int3; { times read }
ffrom: string[25]; { forwarded-from }
subj: string[40]; { subject }
prot: boolean; { purge protection }
reply: byte; { times replied-to } );

false: ( { message text }
data: string[blocksize]; );



There are two types of records in the message file: header and text. Header
records contain time, date, subject, etc.; text records contain message
text, a block at a time. One block is a string of up to 90 characters.

Messages are pointer structures. The NEXT field points to the next block
of message text or contains zero to indicate the end of the chain. If the
message is a public message, the ID field contains the "next message ID"
number from the INDEX file. If the message is electronic mail or a
bulletin, the ID field contains a pointer to the NEXT item in the mailbox
or next bulletin. These pointers must be maintained if you add or
delete messages.

Message text is stored in the DATA string. DATA should always be of length
90 except in the last block. Individual lines are truncated with the CR
character embedded in the data string, and one line can span two or more
records. To recover the text of a message, you must de-block all lines
and then uncompress the message text. A sample routine for reading messages
is included in the file READ.LIB.

Record zero contains the pointer to the free record list (stored in the NEXT
field). To store data in the message file, pop a record off the free list
or expand the data file if no free records exist.

It is OK for more than one pointer to point to a message. When this
happens, the COPIES field of each record is incremented. When a message
is deleted, the COPIES field is decremented if it is greater than zero;
otherwise the record is cleared and added to the free space list. }

type Logtype = record { LOG file }
head: integer;
users: array[1..logsize] of record
id: integer; { user ID # }
time: timetype; { time of login }
date: datetype; { date of login }


The caller log file is a simple circular list containing a log of the last
75 callers (LOG.BBS). HEAD points to the beginning of the list. The ID
number is a pointer to the caller's record number in the USER.BBS file. }

type Quotetype = record { QUOTES file }
name: string[25]; { their name }
quote: string[72]; { what they said }


The QUOTES.BBS file has no data structure; it is simply an array of quotes
and user names. The names are stored as text rather than pointers. This
file is updated by Searchlight BBS simply by picking a random record number
to overwrite.

This file contains 75 records initially, but you can expand it. If you
expand the file, Searchlight will use the new records automatically. }

type Dirtype = record { file directory format }

active: boolean;
case integer of

1: ( { normal data record }
name: string[12]; { filename }
descrip: string[40]; { description }
length: integer; { length in 128-char blocks }
id: integer; { ID of uploader }
date: datetype; { date uploaded }
last,next: integer; { ptrs to date sorted list }
left,right: integer; { tree pointers }
times: int3; { # of times downloaded }
passwd: pwtype; { password }
extra: string[9]; { reserved } );

2: ( { root record }
dataroot: integer; { root of tree }
dateroot: integer; { root of date chain }
freeroot: integer; { root of free space chain }
files: integer; { # of entries } );



Each file directory file contains two data structures: a binary tree keyed
on the file names, and a doubly-linked list keyed on the upload dates.
Record 0 contains the pointers to the root nodes, including the root to the
free record list. The 'active' flag is set for valid nodes, reset for
deleted data. The binary tree does not contain parent node pointers as it
does in the USER file.

To traverse the tree, start with the dataroot pointer and follow the left
and right node pointers. To follow the linked list, start with the dateroot
pointer and follow the next pointers. If you update the file, you must
maintain all pointers.

See the note below on passwords. }

{ Additional Notes }


All passwords are stored as 3-byte hash codes. Here is the procedure to use
to transform a string into a password: }

Type pwstr = string[60];

Procedure Hash (s: pwstr; var r:pwtype);
{ return modified 3-byte checksum }

var i,j: integer;

for i:=1 to 3 do
for i:=1 to length(s) do begin
if (r[j] mod 2)=0 then begin
if (j=4) then j:=1;

{ To verify a password, hash it and compare the result with the stored hash-
code of the password in question. You cannot "unhash" a stored password
in order to get the value of the password string. }

{---------------------------- END FILEDEF.LIB ------------------------------}

{---------------------------- From DOOR.PAS: -------------------------------}

type SlData = record

PROGID: string[6]; { Program ID }

carrier: boolean; { carrier check enable }
writeprotect: boolean; { disk write protection }
aborttype: byte; { 0=no abort, 1=terminate, 2=reboot }

rsactive: boolean; { set if rs232 active }
ansi: boolean; { user ANSI mode }
color: boolean; { user COLOR mode }
directvid: boolean; { system DirectVid mode }

curratt: byte; { current video attribute }
commtype: byte; { run parameter }
idletime: word; { idle limit (seconds) }

lastkey: boolean; { TRUE = last key from local kbd }

OldVector: array[$00..$FF] of pointer; { old user int vectors }


var regs: registers;
data: ^SlData;
save: pointer;

procedure SetSearchlightIO ( Assert : boolean);

MsDos(regs); { Load pointer to SLBBS data }

if data^.progid<>'SLBBS'
then writeln('Searchlight driver not loaded');

if Assert
then setintvec ($10, save)
getintvec($10,save); { read existing address }
setintvec($10,Data^.OldVector[$10]) { restore original BIOS address }

{------------------------------- END DOOR.PAS ------------------------------}

  3 Responses to “Category : BBS Programs+Doors
Archive   : FILEDR31.ZIP
Filename : SLSTUFF.INC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: