home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 31
/
CDASC_31_1996_juillet_aout.iso
/
vrac
/
lsdoor09.zip
/
LSDOOR.DOC
< prev
next >
Wrap
Text File
|
1996-06-03
|
64KB
|
1,251 lines
LsDoor Software Development Kit
Version 0.9 Wide Beta
June 1996
Thank you for trying out the LsDoor Software Development Kit. We hope you
find it to be as useful and as powerful as we have.
This is the first public release of the LightSpeed SDK. We will work to
provide rapid improvements as soon as they are needed. In the next few
versions, we plan some slightly improved documentation, speed improvements,
bug-fixes as they become necessary, as well as anything else which you
request.
A note about our technical support: We will try to provide help for
anyone who uses this product, be it a registered user or not. Unfortunetely,
we have limited resources for technical support. See the end of this
document for details.
About registeration: See the enclosed file REGISTER.FRM for this
information, and for details about the shareware vs registered LsDoor SDK.
LEGAL NOTE:
By using or attempting to use this product in any way, you signify your
acceptance and clear understanding of all terms and conditions stated in
LICENSE.DOC. If LICENSE.DOC is missing from this document, then your copy
of this product is illegal and should be destroyed.
WIDE BETA NOTICE:
This is a wide beta version of the LsDoor SDK. This means that it is an
early version and may have bugs. Because it is a WIDE beta, it is open to
the general public. Anyone who uses this does so at their own risk. Please
report any bugs to us in a thorough and complete manor, and we will fix
them promptly. Also see LICENSE.DOC.
Introduction....
The LsDoor SDK is a toolkit which programmers can use to create
their own door programs. The idea of the kit is to allow door programmers
to write programs which will support all BBS Software at once. It will
also allow programmers to use the native computer language of "C" and "C++"
without the need to learn a completely new properiety language. Many
properiety languages created for BBS Programmers give the programmer no
real advantange over a more standard language.
The C/C++ language is the most common computer language in use today. It
has been for many years. We would like to offer Pascal support (the second
most popular language) however we have no programmers experienced in
Pascal to port our source code over.
The LsDoor SDK is a library (.Lib file) which links with your own source
code to allow you to create virtually any on-line gaming experience you
can dream up. The kit is very simple to use, and yet extremely powerful.
The reason for this is two-fold: First, we took the LsDoor SDK directly
from our BBS Software's source code. When we created the BBS Software
(titled LightSpeed), we planned the LsDoor SDK right from the start. We
used a simple mechanism to tag what code would be included and what
wouldn't. The second reason is that we have, to-date, created 6 doors with
the kit. These doors were then included with the registered LightSpeed
free of charge, giving LightSpeed more out-of-the-box features than any
other BBS Software.
The result is the most powerful library available for door programming.
It is capable of almost everything your doors will need. We've even set
it up so that registered LightSpeed sysops can use the SDK free of charge
with their LightSpeed BBS Software, another out-of-the-box feature
allowing any sysop who also knows C/C++ programming to do some serious
customization on their BBS, or just create the wackiest door anyone has
ever seen.
Please note that we also refer to the LsDoor Software-Development-Kit
as the "SDK", the "door kit", and just the "kit" throughout this document.
Platforms:
* Any LightSpeed BBS (InfoLink.Dat drop-file) is supported in the
shareware SDK.
* Any standard BBS (Door.Sys drop-file) is supported in the registered
SDK.
* Legend Of the Red Dragon (LORD) IGM support is provided, however you
may not sell your IGM programs without registering.
* Runs on any 80386+ processor, includes support for DesqView,
DesqView/X, Windows 3.1+, Windows 95, TopView, and a number of other
operating systems.
* Will support the upcoming LTerm standard (we will offer an upgrade to
the SDK for this support.)
Features:
* Easy to program, and very powerful! Your door can be started with as
little as 3 lines of code! That doesn't comprimise its power though,
because there are hundreds of functions available for everything you
need! You can worry about your door instead of why the modem keeps
hanging up.
* Built-in B-Tree Indexing module, and complete database system! Setup
a complete player database for your RPG Game without ever openning a
file, and yet have data access at frightning speeds! Just ponder the
problem of a user first connecting to a BBS. If a BBS has thousands of
members, how long will it can take a while to find one person's account
(which tends to be around 300 bytes) out of all those thousands? With
the LsDoor SDK, not even a second in most cases. It even has a cache!
* Built-in messaging system. Includes an easy to use full-screen message
editor (with ANSI) or an alternate line-editor for non-color (Ascii)
users. Supports up to 150 lines with lots of function keys. You can
use the message buffer however you like (for example, the lsFaq
companion to LightSpeed uses the message editor with a maximum
of 15 lines, but instead of "sending" the message to another user, it
writes the message to a text file.)
* With help from the LsText companion to LightSpeed, you can setup
customizable text for your door. This way sysops can change the
strings however they like (you can select which strings can be
modified.) This can be a little cryptic to use as yet because the
strings are referenced by integers. But to the sysop it works great.
You'll have two files, a .BIN and .DAT. The .BIN will always include
your original text and can't be changed. The .DAT can be modified by
the sysop. As the sysop is using the LsText editor, each prompt
is displayed in the .BIN and .DAT form simultaniously. This saves
memory, but costs some speed and disk space. This is, of course,
optional.
* Time management, user credits, inactivity detect, InfoLink.Dat,
Door.Sys (+See below), and carrier detect work flawlessly. When a
door is running from a LightSpeed BBS, it barely seems to be a door at
all.
* A complete status line is available. The F1 and F2 keys function
identical to LightSpeed, that is, they shrink or enlardge the status
line.
* Sysop chat is nothing less than superb. For ansi+ users, a very nice
split screen chat system. For ascii users, a simpler free-type mode is
provided (you can't do a whole lot with Ascii.) Activated by F10.
Except in some Door.Sys apps, a user's time doesn't change during a
sysop chat (they won't loose time because the sysop interrupted them.)
* Time adjustment features (Note that these may not always work with
Door.Sys) built in to the F7 and F8 keys. Press them for +/- 5
minutes, hold down Ctrl or Alt for +/- 15 and +/- 1 minute adjustments.
Hey, we're thorough about it!
* Security is always on guard. The user's 'doorlevel' setting is always
available, unfortunetely it's just a number that the sysop can assign
each security class. When running under LightSpeed, access to all
security class information is provided.
* Integrated! When operating with a LightSpeed Host, your door can
access much of the same data LightSpeed uses. Mail, user accounts,
and even the BBS configuration are available and can be modified. This
is the outer limits of customization features. Note that it IS possible
to detect and adapt to LightSpeed Host, meaning that you can make use
of the extra LightSpeed-only features when the sysop is using
LightSpeed, or switch to Door.Sys-only features when the sysop is using
another BBS Software.
* Reliable. While the problem doesn't apply to the LsDoor SDK, the only
part of LightSpeed we're at all disappointed in is the message system.
But, that's good reason to fix it, and we intend to do so in the
following months. Messages should work fine within your door, as
long as the quantity doesn't get to be as enormous as a main BBS message
base is faced with (i.e. thousands of messages going around at one
time.)
* Automatically detects and supports DesqView, DesqView/X, Windows 3.x,
Windows 95, and any other multi-tasking software which offers the
time-release interrupts. For speed and flexibility, upon detecting
DesqView support, the kit will find the DesqView screen buffer instead
of writting directly to the video display. This enables very fast
operation under DesqView without sacrificing any performance. Note
that no support for local graphics is provided, however you could
write some. See next item.
* Supports Ascii (Non-Color), Ansi (Text Color Standard), and remote RIP
operation. RIP codes will show up as garbage on the local display,
however it should show up just fine to the user. You can adjust your
door's behavior based on the terminal type.
* Built-in ANSI Display handler. We also offer a function almost
identical to the standard printf() function with additional support for
color changes on the fly.
* Support for internal Z-Modem uploads and downloads. EASY to use. Get
a transfer going in 5 lines of code. Also extendable, add support for
external protocols, or add more internal protocols. Z-Modem transfers
continue to monitor user time, credits, etc. (Except inactivity)
** Z-Modem support requires the complete, registered MCOMM Library
See License.Doc for information.
* Includes and supports a subset of the MCOMM Serial Library for
modem/serial communications. The DoorKit takes care of all modem
communications for you (and also allows you limited access to the modem
for yourself.)
Limitations:
- [Would like to improve this] Supports only Borland C/C++ Compiler
version 3.1 and above. The door kit is compiled for 386+ Systems,
but this can be changed on request. The provided libraries will all
fail if RUN on anything less than a 386.
- No fossil support. This was removed in favor of internal Z-Modem.
If we get some requests we can put this back in just a few minutes,
however there is no way to support Z-Modem through the fossil and
the MCOMM Serial Library does an excellent job in place of a fossil (See
License.Doc.)
- See REGISTER.FRM for information about the minor limitations of the
shareware version.
Getting Started...
To setup the LsDoor SDK, just run SETUP.EXE and select your compiler.
You may need to modify the example project directory settings for your
particular computer.
Tools:
We've tried to include everything you'll need to develop doors right
away with the LsDoor SDK. Everything has been included, except for a
place to test your product (You CAN just run it in "local" mode.)
There are a few programs included in the shareware and registered LsDoor
SDK to make things simpler. The first is S_IN.EXE. This is a simple
program which gives you the return codes for the s_in() function. See
the s_in() function below for details. The next is LSTEXT.EXE, a program
which is also included in all copies (including shareware) of LightSpeed
BBS Software, and also may be redistributed with any programs you create
using the REGISTERED LsDoor SDK. See Register.Frm for details.
For a place to test your door, we recommend the LightSpeed BBS Software
because of its excellent door support. LightSpeed was carefully designed
to make door setup and operation a snap. You are welcome to use any BBS
Software you choose (if you have the registered LsDoor SDK) or you can do
without any BBS Software at all, but that isn't advised. LightSpeed is
currently available for as low as $ 30. The shareware edition of
LightSpeed (and most BBS Software) lacks any door support.
If you choose to use LightSpeed, you will have an easier time setting up
and operating door programs. An example of a typical door's batch file
for LightSpeed:
C:
Cd\Doors\MyDoor
MyDoor.Exe I%InfoLink%
Exit
Programming the LsDoor SDK:
First let us introduce our style of programming. We have provided a
header file called LsDoor.H, which in turn includes all of the other
header files required to use the SDK. All the header files except for
LsDoor.H itself will be hard to read and should generally be avoided (they
are continually in use by two seperate products, LightSpeed BBS, and the
LsDoor SDK, and as such, are somewhat messy.
Note that we use 'uchar' to mean 'unsigned char', 'ushort' to mean
'unsigned short', 'ulong' for 'unsigned long' etc. We have macros for
true and false (all lowercase). We avoid the Booleon type. We use a
'test' type which is an 'unsigned char' meant to only be true/false.
These types are all typedef'd and declared in the LsDoor.h file (or to be
exact, in Wiley.h.)
We recommend that programmers start using short and ushort in place of
int and uint. The reason for this is because more and more "32-bit" is
becoming the standard, and in 32-bit programming integers are just that,
32-bit (the same as long's). Short's remain unchanged. So if what you
really want is a 16-bit variable, use shorts when possible, when you want
a 32-bit variable, use long's so that your code will still work in the
old fashioned 16-bit environments.
Note that the lsDoor SDK uses almost entirely int's. It will be a major
task porting it into a protected-mode or 32-bit platform.
Hello World:
The tradition has always been to present a new programming style with a
"Hello World" program. Well, let's get traditional:
#define MainModule
#include "LsDoor.H"
char *errorModule( void ){ return "HelloW"; } // Show our ID...
void main( void )
{
if( !DoorInit( doorsysDISABLE ) ) exit(1); // Get things rolling.
display( "\nHello @GGreen world!" ); // Hello Green world!
display( "\nThe @RRug @BIs @GGreen!" ); // The Rug Is Green!
exit(0); // Always use exit()
}
Rule #1:
All LsDoor programs must provide the function errorModule().
errorModule() just returns a pointer to the identification of your program.
If your program experiences any errors, they are always logged A) To the
user's screen, B) To the local screen, and C) To the Error.Log file.
The Error.Log file can end up cluttered, as more than one program might
use it. By having a short, unique ID included in the Error.Log file, the
sysop can quickly trace the program that caused the error.
Rule #2:
One and only one of your program's modules must have the "MainModule"
macro declared before LsDoor.H is included. This allows for only one set
of header files. When "MainModule" is declared, another #define statement
inside of LsDoor.h defines the keyword 'global' as nothing. When
"MainModule" is not declared, 'global' becomes 'extern'. You may
#undef 'global' and/or 'MainModule' after you include the LsDoor.h and
(optional) Lord.h header.
Rule #3:
Generally the first thing you want to do is call the DoorInit() function.
This function gets everything rolling, it reads the dropfiles, it starts
the clock counting, and it sets up the carrier check. Put this first
unless absolutely necessary in your door. You should always use the if()
statement shown above (just like that) for calling DoorInit(). DoorInit()
generally only fails when it has problems with the drop files (i.e. can't
find them, file error, etc.) DoorInit() takes one parameter which flags
whether to allow the Door.sys file or not. DoorInit() always looks for an
InfoLink.Dat dropfile first, and if it can't find it, it makes due with a
Door.Sys drop file, assuming Door.Sys is supported. The two options for
the DoorInit() paramater are 'doorsysENABLE' and 'doorsysDISABLE'.
Rule #4:
Always exit your program using the exit() function. Otherwise many
clean-up chores such as closing the serial port (and de-allocating 1K to 4K
of memory) get left un-done.
The display() routine:
The display() routine is probably the most frequently used function in
the kit. It operates a lot like printf() with some provisions:
%s, %u, %i, etc all work fine.
Long and Unsigned long integers can't be used. Use out_long(long/ulong).
Floating point may or may not work. Test it before comitting.
Width and length specifiers (%2.4u) work normally. Also %*.*u works.
Display also adds the following features (Display finds its meaning
in life here):
Note that a string which you include via %s can also use all color codes
and special controls.
Color codes are @X, @x, and @{X} where X is the first letter of a color's
name. For example, @G changes the color to bright green. @B to bright
blue. Use uppercase for bright colors and lowercase for dark colors. The
@{X} codes use the same letters but ignore case and change the background
color.
@B ..Bright Blue @b ..Dark Blue
@G ..Bright Green @g ..Dark Green
@R ..Bright Red @r ..Dark Red
@Y ..Bright Yellow @y ..Dark Yellow (Brown)
@W ..Bright White @w ..Dark White
@M ..Bright Magenta (Purple) @m ..Dark Magenta (Purple)
@C ..Bright Cyan @c ..Dark Cyan
@1 ..Grey @0 ..Black
@{0} ..Black Background @{1} ..Grey background
@{B} ..Blue Background @{R} ..Red Background
@{G} ..Green Background @{C} ..Cyan Background
@{Y} ..Yellow (Brown) Background @{M} ..Magenta (Purple) Background
* Background colors are not case sensative. Flash is not supported.
* You might want to set your coloring as you first enter the door. If
you don't, you are left at the mercy of the BBS's color scheme.
Ex 1) display( "@rDark @RBright @{R} All Red" );
Ex 2) display( "@bBlue @Rs@Wo@Cr@Gt@Ma @0invisible!" );
There are also 2 common ways to re-locate the cursor. Both methods have
the same effect, and both will operate on both the local and remote screens
(you can control this, but that's a later topic.) Both methods assume the
upperleftmost coordinate on your screen is 1,1. Both methods may not
locate the cursor quite right on the LOCAL screen if a status line is
blocking the coordinate. More on that later. X is always the horizontal
(across) position and Y is always the vertical (up and down) position.
The first technique is using display() again. For the display()
function, use @[XxY] where capital X is the x coordinate and the Y is the
y coordinate to relocate your cursor to. The x in the middle is required
between the two coordinates (it can be either case.)
Just like color codes, you may use display()'s relocate codes anywhere in
the string, and any number of them. The disadvantages of the display()
technique are the loss of readability, as well as speed loss. Also, the
alternative will support a screen of 256x256 whereas display() is limited
to 99x99. Normal user screens are 80x25, so that isn't a big problem.
The s_locate(uchar x, uchar y) function simply takes the new position to
jump to. It supports up to 256x256 screens. It is also quite a bit
faster than display(), and often simpler.
We will cover more of the output functions later, now moving on to input.
Avoiding the crash:
Before you can actually get the input, you have to be aware of the
dangers of door programming which generally can't be thwarted. Some
examples of these are the carrier detect. Without a carrier detect, a
user can hang up, and if the BBS happens to be waiting for a response, it
will wait forever! One thing that will help this is the inactivity timer,
which also serves to kindly log users off if they leave their computer
un-attended (it provides a 1-minute warning, and an explanation of the
reason for being disconnected. Under door.sys the inactivity defaults to 5
minutes. Under infolink, the inactivity matches the BBS's configuration.)
Then of course there's the user's time limit, credits, etc. It's all
taken care of. You will have to make one provision in any "loop" you
have which has any chance of getting stuck waiting for input. This
provision is checking a variable named 'online'. This variable is true
as long as the user is connected, and is supposed to remain connected.
This variable will flip to false as soon as the user disconnects, or the
user is logged off for any reason.
The 'online' flag is managed by a smart little function which is the
center of it all: update(). You generally don't need to worry about this
function, however make sure it is being called in loops which care about
the online flag. If you are using the s_in() function (described in a
moment) this is automatic.
Normally when calling update(), update() will simply return most of the
time, and then perform its work only once every 4 to 20 seconds. Another
function is very rarely needed called forced_update() which forces the
call immidiately. Overuse of forced_update() will slow things down a
little bit.
We want your input:
Input is generally a single character. LightSpeed provides a very useful
input routine called s_in() which will fetch you one character. This
function does it all:
Calls update() automatically.
Sometimes releases time-slices under multi-taskers (more on that later)
Formats the character into something useful.
To you, s_in() works a lot like getch(). If the character is a regular
kind of thing (the letter A or Y for example) then s_in() just returns
that character. When the character is an extended code (be it remote or
local) s_in() returns 0, but unlike getch(), it does not need to be called
again. Rather, it puts the second byte (the extended code) into a global
variable named 'extended'. This makes things possible such as remote
users using arrow keys (Caution, if you include support for arrow keys it
is highly recommend you provide some way for the user to select an
alternative way of input, we suggest letting them choose between arrow
keys, the keypad, and some regular keys arranged like the arrow keys.)
The s_in() function will also translate some special arrow key sequences
into the normal 0/extended form.
Clever s_in() also processes what it sees and checks for any special keys
such as F10 (Sysop Chat) or F1, etc.
To find out what a s_in() code is, use the included program S_IN.EXE.
S_in() does not echo the keystroke.
Now with that in mind, let's look at a simple question. The most common,
the old Yes or No.
// Example2.Cpp - Asking a question
#define MainModule
#include "LsDoor.H"
char *errorModule( void ){ return "Example II"; } // Identify ourself...
char c;
void main( void )
{
if( !DoorInit( doorsysDISABLE ) ) exit(1); // Get things started...
display("\n@WS@wtar @WW@wings @WG@wame" );
while( online )
{
display("\nDo you wish to play? (Y/N) ");
c = toupper( s_in() ); // Toupper is a useful C function
// that converts a 'char' to uppercase.
if( c == 'Y' )
{
display("\nGame over."); exit(0);
}
if( c == 'N' )
{
display("\nReturning to the 20th century."); break;
}
}
exit(0); // Always use exit()
}
// End of Example2.Cpp
The above is a complete program and will run fine. But, it could use
some enhancements. Use the function echo_yn() as a quick way to echo
a colored YES or NO. echo_yn() takes a single character, which is either
'Y', or 'N' (defaults to No). Then, there's a lot you can do with the
question "Do you wish to play?". If you run Example2, the phrase
Star Wings Game shows up nicely colored. This is not a requirement, but
you might want to color your question just a little. Perhaps figure out
and make a note of how you want ALL your Y/N's to look. Seems trivial?
Might be. Your program will certainly look more professional if your
color scheme follows a pattern. Here's a revision of Example2:
// Examp2B.Cpp - Touched up Example2.Cpp. Much prettier.
...
while( online )
{
display("\n@CD@co you wish to play? (@GY@w/@gN@c) ");
c = toupper( s_in() ); // Convert s_in() to uppercase..
if( c == 'Y' || c == '\r' ) // Use '\r' for the return key..
{
echo_yn('Y'); display("\nGame over."); exit(0);
}
if( c == 'N' )
{
echo_yn('N'); display("\nReturning to the 20th century."); break;
...
// End of Examp2B.Cpp
Notice that we made the Y in the (Y/N) display bright green, and the
N dark green? That seems to work for letting users now that "Y is the
default. Just hit enter."
Local/Remote/Both:
You have seen the s_locate() and s_in() functions. The display()
function also follows the s_ function conventions. There are quite a
few s_ functions available to you. All functions preceded by the s_ follow
some common guidelines:
Automatically take care of calling update()
React to 'online' flag
Operate based on the 'redirect' flag
Some other commonly used s_ functions are s_ready(), s_out(), s_gets()
s_cls(), and s_color(). s_ready() returns true when input is waiting.
When you call s_in(), your function doesn't return until a key is pressed.
You can first call s_ready() to find out if it's necessary to call s_in().
s_cls() simply clears both the remote and local screen. For Ascii users,
it just scrolls down 5 lines. s_out() takes one unsigned char and outputs
it.
The s_color() function provides a fast means of changing the color on
both the local & remote sides (as per the 'redirect' flag.) The s_color()
function only changes the color when needed, thus avoiding any unnecissary
modem clutter. The s_color() also supports blinking colors unlike the
display() function. See also the color table below.
The s_gets() function is very useful, it gets a character string from the
user. s_gets() takes 3 paramaters: Unsigned char *buffer, int maxlen,
and char *filter (which defaults to 0.) 'filter' is rarely used. Buffer
is a character buffer of at least 'maxlen' bytes which will store the
input. Maxlen is the maximum number of bytes that may be input. For
example:
char mystring[15];
s_gets( mystring, 15 );
All s_ functions respect the 'redirect' flag. The redirect flag will
be set to one of these macros: RE_LOCAL, RE_ECHO, and RE_SERIAL.
RE_SERIAL disables the local screen, and begins output (or input) from the
remote user only. RE_LOCAL disables the remote user and takes input or
output from the local console only. RE_ECHO accepts input and
output from both sources. You can change the 'redirect' flag as needed,
but DON'T change the 'drop.redirect' flag. The 'drop.redirect' flag
let's you know how you are trully connected. It uses the same macros
as redirect. If you change 'redirect', set it equal to 'drop.redirect'
when you're done.
The s_ functions will all operate based on the 'redirect' flag, they
only pay attention to the 'drop.redirect' flag to avoid writing to a
modem when in local operations.
Getting the Terminal Settings:
Checking the current user's terminal setting is very easy. Just check
the global flag 'terminal'. The value of 'terminal' should not be
changed, or if it is it should be restored afterwords. 'terminal' will
be set to one of these values:
TERM_ASCII 0
TERM_ANSI 1
TERM_RIP 2
Don't check if a terminal == TERM_ANSI. When checking for
Ansi, and only ansi, always use: if( terminal >= TERM_ANSI )
The display() routine automatically adjusts to terminal settings. @X
codes are ignored for Non-Color Ascii users.
The built-in pager:
The pager is a nice way for users to communicate when teleconference is
not available. The pager is built-in to the lsDoor kit, and requires no
modifications for common support. You can also extend the pager as a way
of communication between different nodes (expect from 1-6 seconds for it
to arrive unless you pad in some forced_update() calls.) To extend the
pager in a professional program, you will need your own unique ID number,
for which you can contact us and receive free of charge.
If you need to disable the pager, set the global flag 'read_commlinks'
to false, and true again to bring it back. To clear all waiting pages,
set the global flag 'dump_commlinks' to true. This will automatically
be reset to false as soon as update() completes the purge.
Additional routines:
At this point the basics are fairly well covered. Now we'll hurry things
up, because we still have a lot to cover.
Display routines:
void display( char *format, ... ); // See above...
int s_in(); // See above...
short s_out( uchar outch ); // Outputs outch to 'redirect'
int s_ready( char giveup=true );
s_ready() will return true only when input is waiting to be
processed. If giveup is false, time slices will not be given to any
detected multi-taskers. Time-slices are never given if input is ready.
void s_cls(); // Clears 'redirect' screen(s)
void s_locate( uchar x, uchar y );
s_locate(x,y) relocates the cursor for 'redirect' screen(s).
Coordinates 1,1 are the upperleftmost corner of the screen. Use up to
256x256. This function is faster than display() for relocation.
* Do NOT call s_locate() unless terminal >= TERM_ANSI
void s_color( ushort color );
s_color(color) changes the current display color for 'redirect'
screen(s) if necissary. This function is faster than display(),
and supports blinking colors. The numbering system for s_color() is
based on hex. The upper nibble provides the background color and
the lower provides the foreground color. Hex 1 is blue, hex F is
bright white, so 0x1F is bright white on a blue background. The
colors are listed in the following table. To use blinking, add 0x80.
To use bright foreground colors instead of dark, add 0x8.
* Do NOT call s_color() unless terminal >= TERM_ANSI
Color Table for s_color() function: (Numbers are in hex)
0.. Black 4.. Red
1.. Blue 5.. Magenta
2.. Green 6.. Yellow/Brown
3.. Cyan 7.. White
To use blinking, add 0x80 to your background color.
To use bright colors, add 0x8 to your foreground color.
Examples: 0x1F is bright white on blue.
0x9F is bright, blinking white on blue
void s_eraseline( void ); // Erases current display line
This function works fine with all terminals. Ansi+ is faster.
void s_backspace( void ); // Outputs a backspace code
Always use this function (or send "\b \b") for backspaces.
void echo_yn( char ); // Outputs 'Yes' or 'No' (Y or N)
void scanner( void );
void clear_scanner( void );
Use scanner() during lengthy operations to show a small rotating
symbol. For best visual results, call scanner() about every 5
seconds. When the operation is done, call clear_scanner() before any
other output is done.
General Door Routines:
Also see the miscellanious data section below.
global unsigned long node.ID.num;
This variable will give the current node number, except the first
node is always number 0.
int DoorInit( int allowdoorsys=doorsysENABLE );
This function initializes your door program. It will return false in
the event of an error in which case you should call exit() immidiately.
After calling this function, you must use the exit() function to exit
your program in all cases. Do not use any 'return' statements in your
main() function. The paramater 'allowdoorsys' can be either
doorsysENABLE or doorsysDISABLE. The shareware LsDoor SDK will always
use doorsysDISABLE regardless of what value you pass. DoorInit()
will always look for a InfoLink.Dat file first and use that if
possible.
void clear_pause( void );
int pause( int allowstop=true );
Pause gives the user a -=Pause=- prompt with options to Continue,
Stop, or go into Nonstop mode. This function returns true when the
user selects Continue or Nonstop and false when the user selects Stop.
If a user selects Nonstop, pause() will have no effect until you call
clear_pause().
void activity( void ); // Restarts the inactivity timer
void forced_update( void );
void update( void );
Update should be called in all parts of your program, either by you
or by the LsDoor functions. Update() does housekeeping chores such as
updating timers and inactivity, as well as checking the carrier and
operating the 'online' flag. Update() will return without doing
anything until 4 to 20 seconds (depending on the situation) have passed
without doing the update. Forced_update() overrides this 4 to 20
second limit and calls update() immidiately.
void status_line( void ); // Re-displays and updates the status line
void sysop_chat( void ); // Invokes a sysop chat
uint best_userserch( uchar *find ); // LightSpeed BBS Only
This function searches through the user database for the handle
'find'. It returns true if anything was found and loads the user's
account into 'userserch'. Source code for this function can be found
in Example4.Cpp.
uint best_username( uchar *find ); // LightSpeed BBS Only
This function searches through the user database and provides the
best match for the name 'find'. If a decent match was found, it
returns true and loads 'userserch' with the person's account.
void hang_up( void ); // Use this to hang up the caller
char *ask_format( const char *text, const char *format, char *s,
int newline=false, char required=true );
This function first displays 'text' and then, following the ## and **
pattern set by 'format', it retrieves an input string from the user and
stores it in 's'. It also returns 's'. The format can include any
characters, however only ## and ** give input. For example, if the
format is "##/##/##" then the user would have to enter 2 digits, then
a / would appear, the user enters another 2 digits, another / appears,
so-on. The 's' string might be filled with "12/23/85". A * allows for
any single character to be input, a # requires a digit only. The
'newline' paramater determines if the prompt is displayed on the next
line or current line. The 'required' paramater determines if the user
may press ENTER before completing the input.
Direct Modem Access:
These functions do NO carrier checking, no time checking, and do not
call update() automatically. Use them with caution. Do not use them
when in local operation. Some of these functions are macros.
void direct_out( uchar ); // Outputs a character, no processing
void direct_string( char * ); // Outputs the string w/50ms between chars
short direct_ready( void ); // Returns true when modem input is waiting
short direct_in( void );
This function does not check for keystrokes such as the F-Keys. If
you call this function when no input is available, your program could
crash. Check if direct_ready() is true before calling.
char carrier( void ); // Returns true when a carrier is present
void set_dtr( int dtr ); // Sets the modem DTR
void set_baud( ulong newbaud ); // Sets the modem baud rate
void disable_port( void );
void enable_port( void );
These functions temporarily disable and re-enable a port. If you
will be spawning another program, use these to halt the serial port
while the new program is running.
Pager Routines:
global int read_commlinks, dump_commlinks;
Set read_commlinks to false to temporarily disable the pager. Set
dump_commlinks to true to erase all pending pages (Update() will set it
back to false when done.)
void save_commlink( int );
Writes the commlink to disk. Takes the node number as a paramater,
using start-at-0 node numbers. See Example3.Cpp for a demonstration.
uint matches( char *a, char *b ); // Returns # of char's matching..
int FindExactUserOnline( uchar *lookfor ); // Returns node # or -1
int FindUserOnline( uchar *lookfor );
This function will find the best match for 'lookfor', and also
assumes that the 'lookfor' string contains additional text after the
user's handle. If a user named "King Burgundy" is online, and
you pass this the string "King Burg Hello" it will return his node
# and modify the string to show: "Hello".
void PageUser( void );
This function is a very quick way to implement paging support. Just
call this function when the user presses the "page" key, whatever that
may be. It will prompt the user for their page and send it off.
Multi-tasker and system clock:
A common fault of many programs is the use of BIOS Interrupt 1Ah,
function 0x00 to retrieve the system's tick count. This interrupt was
apparantely intended only for operating system use. If this interrupt
is called after midnight but before the operating system calls the
interrupt, the system's date can miss a day on some computers.
unsigned long tick_count( void );
This is a safe way of retrieving the current system tick count. One
'tick' occurs 18.2 per second. The tick count is reset to 0 after
midnight.
void tick_delay( ulong ticks ); // Delays for 'ticks' giving time slices
int dv_active( void ); // Returns true if desqview is present detected.
void dv_pause( void ); // Gives up time slice to DV, DV/X, Win3.1, Win95
File Transfer:
Use of the LsDoor SDK Z-Modem code requires the fully registered version
of the MCOMM Library from Mike Dumdei. See License.Doc for details. The
Z-Modem code is useless unless you have the ZMLIB_H.LIB file included in
your project. Here's an example of how to build the ZMLIB_H.LIB file to
work with the LsDoor SDK:
tasm /DTURBOHUGE /Mx /t /w2 desqv;
tasm /DTURBOHUGE /Mx /t /w2 unixdos;
tasm /DTURBOHUGE /Mx /t /w2 zfunc;
bcc -c -X -mh -DNO_ASM batch.c zmdos.c xyzgen.c zcmplr.c
if exist zmlib_h.lib del zmlib_h.lib
tlib /C /0 zmlib_h +batch +zmdos +unixdos +desqv +zcmplr +xyzgen
-- The following only applies with the Z-Modem extension (ZMLIB_H.LIB)...
You must also include ZModem.Cpp from the registered LsDoor SDK in your
project...
Using File Transfers such as Z-Modem requires a little deviation from
the usual path. To use Z-Modem file transfers, you must add a little bit
of extra code. While we suggest sticking to Z-Modem, if you are a C++
Programmer and want to add additional protocals, look over FileXFer.H
and ZModem.H for more information. The extra code for Z-Modem will look
like this:
*** Include this code segment to enable Z-Modem File Transfers...
#include "FileXFer.H"
#include "ZModem.H"
extern ASYNC Com;
class DoorZModem : public ZModem {
public:
test ResumeTransfer( char *filename ){ return true; } // * See Below
DoorZModem( void ) : ZModem( &Com, false )
} zmodem;
void FileTransferIdle( void ){ resetDoor = 1; update(); dv_pause(); }
void SentGood( char far *filename ); // + See Below
***
* Note that the above function 'ResumeTransfer()' can return either
true or false at your descresion. It will control whether an upload of
'filename' can be resumed. For example with a BBS this only returns
true when the file in question was uploaded by the same person who is
trying to upload it again.
+ Note that you must provide your own 'SentGood()' function which will
be called AFTER every successful DOWNLOAD. For example, LightSpeed's
SentGood() function charges the user for the download if there are any
special charges, ratios, etc, associated with that file.
test DisconnectAfterTransfer( void ); // Asks Y/N, returns true or false
void zmodem.Setup( ulong Baud, char *path=0 );
Call this function before a file transfer. If you are downloading,
send only the baud rate the user is connected at (this is for display.)
If you will be uploading, send the baud rate followed by the directory
in which to place the file, for example: "C:\Receive"
void zmodem.Send( char *filename ); // Sends a single file, 'filename'
void zmodem.Add( char *filename ); // Adds 'filename' to the list
void zmodem.Send( void ); // Sends all files in the list
void zmodem.Rcv( void ); // Receives files from the user
char *zmodem.GetFileName( void );
After calling Rcv(), use this function to find out what files
were received successfully. GetFileName() will return filenames for
each of the files received, and then return NULL when there are no
more files.
Messages:
int maileditor( int lines, char abort, char clearbuf=1 );
This function edits a message but does not save it to disk. 'lines'
is the maximum length of the message. 'abort' can be true or false,
allowing the user to abort the message or forcing them to send it.
'clearbuf' is normally true, unless you are replying to another
message. This function returns true if the user selects to send the
message, or false if the user chooses to abort.
int show_message( int allowprevious=0 );
This function displays the message currently loaded in 'buffer' to
the user. It can return false when the user selects 'exit', or 1
when the user selects 'continue', and -1 when the user selects
'previous' (when enabled.)
LightSpeed Standard Client/Server Communications
Revision 1.0
The Client/Server Communications are a set of functions, tools which you
can use to build just that, client/server applications. A client/server
application is one where a host program works together with a client
program for a specific purpose. In this case, the host and client are
linked via modem, and must be written specifically for each other.
The Client/Server model is used by LightSpeed to allow for a BBS to BBS
communication. Any LightSpeed BBS can communicate effectively with another
BBS using this model. The Client/Server model is only a small set of
functions designed to provide the base of a more complex communication
system. Unlike the rest of the LightSpeed code, the complete source code
to the Client/Server standard is provided in the registered LsDoor SDK.
The LsDoor SDK itself makes no use of the Client/Server model. The
Clien/Server model is included with the shareware SDK. The source code
is also provided in Serial.Cpp for examination only. All of the
Client/Server functions use Direct Modem Access, but they provide timeouts
to prevent crashes.
#define lsTimeout 5 // Value in seconds.
truth timed_in( uchar c ); // Looks for 'c' within 'lsTimeout' seconds
int timed_get( void ); // Waits for input within timeout (Timeout = -1)
truth confirm_in( uchar c );
int confirm_get( void );
truth confirm_out( uchar c );
The confirm_ functions will verify the character, ensuring that the
character received was the exact character sent and vise-versa. If
the receiver will be using confirm_get() or confirm_in() for a
particular byte, the sender must use confirm_out(). The confirm_in()
and confirm_out() functions both return true on success and false on
failure. The confirm_get() function returns -1 on failure or the
character received.
void direct_write( void *dat, uint len ); // Sends raw data
int direct_read( void *dat, unt len );
The direct_read() function receives raw data, but only waits for
'lsTimeout' seconds. It returns the number of bytes received
successfully.
int confirm_write( void *dat, uchar len );
int confirm_read( void *dat, uchar len );
These two functions work like their direct_ counterparts, except
with some error-correction techniques. The confirm_write() function
sends the length of the string (len) out, then the actual string,
and then a 32-bit (ulong) checksum. The confirm_read() function will
compare the received checksum with its own checksum and send back the
result (the data was sent ok, or the data is invalid.) These functions
will make the attempt 10 times before giving up (except in the case
of a timeout which will cause them to give up immidiately.) The
confirm_write() function waits until the receiver has confirmed the
reception. Overall these two functions are extremely slow compared
to the direct_ functions because they send around 10 extra bytes
of data and also wait for each other to respond, but that's the cost
paid for the rather strong insurance that the data is accurate.
LightSpeed TextSystem:
The TextSystem allows you to create 2 data files to include with your
door program. You can choose a name for these files, such as MyDoor.*.
The first file would be MyDoor.Bin, and the second MyDoor.Dat. These 2
files hold text strings which your door program can use however it wants.
Usually, this is used to let the sysop customize the door to say exactly
what the sysop wants, instead of being forced to use the default prompts.
These two files are modified using LSTEXT.EXE, a program which you may
re-distribute with your door if you are using the registered LsDoor SDK
only. This program can also be found with any copy of LightSpeed BBS
Software, included the shareware versions.
The first file, the .Bin file, holds your default values and cannot be
changed by the sysop. The second file, the .Dat file, holds the values
the sysop wants to use. For a better idea, go into the LSTEXT Program.
You can type 'LsText.Exe lsDoorInit' (not case sensative) to create your
own new data files. You (or anyone with LSTEXT) can use the "External
Door" option to modify your data files, which are named BABYTEXT.DAT and
BABYTEXT.BIN when they are first created (you can rename them.) To modify
the .BIN file, you need only temporarily rename it to a .DAT file (and
vice-versa.) Your users will only need to modify the .DAT file.
To setup your door for use with the TextSystem, you need to change a
global variable AFTER you call DoorInit() but BEFORE you make any use of
the TextSystem. The global variable 'LSTextFile' should be changed to
hold the path and filename of your .DAT file. It defaults to LSText.Dat
(which won't work because it is the LightSpeed data file.) After you have
changed this variable, you can use the TextSystem function getText(). Note
that all strings are 256 bytes.
unsigned char *getText( unsigned int promptNum );
After you've set the global string 'LSTextFile', this function will
return string #'promptNum' out of your .DAT file.
Error Handling:
global char errbuf[ 80 ];
This is a workspace provided for YOU only. This can be used by
sprintf() before making a call to error().
void error( char *err ); // Logs 'err' to disk and displays. Does not
// abort the program, but does delay 2 secnds.
Log File:
global char LSLogFile[ 80 ];
Before logging anything (but AFTER calling DoorInit()), set this
global string to the filename for your log file. For example,
strcpy( LSLogFile, "MyDoor.Log" );
void add_log( char * )
After setting 'LSLogFile' call this function to add a new line to
the logs. Inside of the string can be some codes: @USER@ is replaced
by the user's handle. @SEC@ is replaced by the user's security class
(use @SEC@ only with LightSpeed BBS Systems.) @TIME@ is replaced by
the current time of day. @DATE@ is replaced by the current date.
Comma-String Functions:
Many places in LightSpeed use a special "comma-based" string. This
string can have multiple items seperated by commas. Spaces surrounding
the commas are truncated. Any character in the string preceded by a \
mark will be accepted as one character (including commas.) Double slashes
become single slashes.
char *get_substring( char *string, int sub, int maxlen=80 );
This function will return a pointer to the substring within the
main string. The maximum value for maxlen is 120. This function will
return NULL if there is no sub #'sub'. The first sub # is 0, the
second is 1, so-on.
uchar is_substring( char *string, char *find, int maxlen=80 );
This function will return true if 'find' is any of the substrings
within 'string'. This function is not case sensative.
General String Functions:
void filter( char *string, int maxlen, int style );
If 'style' is 0, this removes any characters < 32 (Space) from 'string'.
If 'style' is 1, anything other than A-Z, a-z, and space are removed.
int wildmatch( char *, char * ); // A strcmpi() with * and ? wildcards.
char *get_size( ulong filesize, char *string );
Returns a nicely formatted byte display of 'filesize' in 'string'.
char *strins( char *string, int at, char whattoinsert=' ' );
This function inserts 'whattoinsert' into the string 'string' at
'at' spaces from the left. This will shift everything already present
after 'at' to the right.
char *strdel( char *string, int at );
This function removes the character from the string at position 'at'.
char *strstri( char *string, char *find );
This function finds 'find' within 'string' in a case INsensative
search. It returns the pointer to where 'find' begins inside of
'string' (it points to somewhere in 'string') or NULL if there is no
matches found.
char *strfind( char *string, char *find );
This works just like strstri(), except it also does NOT search inside
of quotation (") marks. It does not treat quotation marks as
quotation marks if they are preceded by a \ mark. Note that a
quotation mark cannot be included in 'find'.
char *strnfind( char *string, char *find, int maxlen );
This works exactly like strnfind(), but only for 'maxlen' characters.
Date and Time Functions:
int years_since( struct date * ); // Returns years since given date
ulong date2int( struct date * ); // Returns days since 1/1/1990
void int2date( struct date *, ulong ); // Fills date (from 0/0/0000)
void smooth_date( struct date * );
This function converts dates with days such as >30 or >31 to a new
month, and converts month>12 into new years. Respects leap-years.
void smooth_time( struct time * ); // Makes a valid time
char *format_time( struct time *, char *string ); // Fills 'string'
void string2date( char *, struct date * ); // Fills date from string
uint twodigit( int ); // Returns 19xx as xx (1984 returns 84)
uint fourdigit( int, int thisyear );
Returns xx or xxxx as xxxx always using 'thisyear'.
Miscellanious Data:
As soon as DoorInit() is completely, a large number of data items are
filled in for you to use as needed. When operating with a door.sys or in
Local mode, only certain data items will be filled. When operating with
InfoLink.Dat files, the entire 'user', 'security', 'node', 'config', and
'master' structures are completely filled with the same settings used by
the BBS Software. We won't provide specifics on all the data members, as
there are far too many, but you can look at LITE.H for information when
using InfoLink.Dat files. Here are some of the data items of importance:
* Most values presented here are given a default value when in local
mode. This default value generally is that of a sysop-user, such as a
time limit of 999 minutes.
master structure
char sysop[20]; // BBS Sysop
char ramdrive; // RamDrive letter (with InfoLink) or HD Letter
node structure
ID structure
unsigned long num; // Current node number, first node is 0.
// Defaults to 0 for local mode.
user structure
ulong num; // User number: Valid with dropfiles
unsigned char handle[20]; // User's handle: Always valid
unsigned char real[20]; // User's real name: Valid with dropfiles
unsigned char citystate[20]; // User's 'from': Valid with dropfiles
unsigned char vphone[20]; // Voice phone number: Valid with dropfiles
unsigned char dphone[20]; // Data phone number: Valid with dropfiles
unsigned char password[10];// User's password: Valid with dropfiles
struct date expire; // Security class expires on: Valid w/drop
struct date bday; // User's birthdate: Valid with dropfiles
struct date newfiles; // Last newfile scan: Valid with dropfiles
struct date dateon; // User's last call: Valid with dropfiles
struct time timeon; // Time of last call: Valid with dropfiles
int timelimit; // Time limit: Always valid
char proto; // File transfer protocal: }
long s_uploads; // Total number of uploads } Valid with
long s_downloads; // Total number of downloads } dropfiles
long s_upk; // Total KB uploaded }
long s_downk; // Total KB downloaded }
long kratio; // Total KB downloaded (vs uploaded) }
long dlratio; // Total files downloaded (vs uploaded) }
char comment[8][40]; // First comment ([0]) is valid }
long s_written; // Total messages written } Valid w/drop
security structure
int doorlevel; // Security level #: Valid with dropfiles (999 local)
long klimit; // Maximum KB allowed for download in a day: Dropfile
long dllimit; // Maximum # of files allowed for d/l a day: Dropfile
drop structure
int lines; // Lines per page: Always valid
int terminal; // Terminal mode: Always valid
int redirect; // RE_LOCAL or RE_ECHO
Legend Of the Red Dragon (LORD IGM) support:
The shareware LsDoor SDK provides support for creating your own LORD
IGMs. While you may create IGMs with the shareware LsDoor SDK, you may
NOT SELL the IGMs until you register. The registered LsDoor SDK goes a
step further and includes the source code for working with LORD in
LORD.CPP. Before registering, LORD.CPP is included in LSDOOR1.LIB and
will display a message notifying the user that it uses the shareware
LsDoor SDK. After registering, this message is removed, and instead of
being included in the .LIB file, LORD.CPP is provided for you to modify
as you wish (You may NOT distribute modifications to the LsDoor SDK in
their source code form.) In the registered LsDoor SDK, make sure to
include LORD.CPP in your project.
We will not cover all of the LORD support here. Instead, you can find
2 sources for learning to use the LORD kit. First is a demo IGM called
LORDDEMO.CPP (.PRJ, .IDE, etc are included too.) It demonstrates how to
get your IGM installed into LORD, how to uninstall it, how to send mail
with LORD, how to check for bad words using LORD's BADWORDS.DAT file, and
how to make your IGM run with LORD in the first place.
The second source is LORD.H, the header file for the LORD Kit. This
header file is not included in LsDoor.h. LORD.H is well documented and
provides your reference to the LORD Kit.
LightSpeed BBS Specific:
These functions only work with LightSpeed BBS systems. You may need to
be familiar with LightSpeed's operation before working with these. It is
not necessary to use these functions at all, but they may be useful if you
are programming specifically for LightSpeed. You can also check the
global flag 'LSPresent', which will be true when LightSpeed is in use
and false for any other BBS Software.
Note that whenever LightSpeed is in use, the structures 'user',
'config', 'node', and 'security' are automatically filled by DoorInit().
See the Lite.h header file for the format of these structures.
int get_flags( int flagnum );
Under LightSpeed, all user accounts have 10 integer flags which be
set to OFF, X-Days, or ON. X-Days sets the flag to expire after so
many days have passed. This function returns true if the flag is ON
or has not yet expired, or returns false if OFF or after expiration.
int get_submenu( int subnum ); // Is submenu #subnum active (true/false)
Under LightSpeed, all security classes have 10 "submenu levels"
These submenus specify a time in minutes. After the user has been
online for longer than this time period, the submenu is "off" for that
day.
int user_security( void ); // Loads 'security' for current user
int userserch_security( void ); // Loads 'security' for current userserch
The userserch structure is of 'user' type, see Lite.h
int access_mailarea( void ); // Checks if the current security class
int access_ularea( void ); // permits access to the current mailarea
int access_dlarea( void ); // or filearea.
int in_set( uchar *setlist, uint setnum );
File and Mail areas in LightSpeed may be divided into sets. Setlist
will point to an array of 5 unsigned characters, if any of the 5
uchar's match setnum, this function returns true.
void sysop_userDB( int start ); // Opens sysop database on user #'start'
void sysop_fileDB( int newuploads );
This function opens the file database. If newuploads is set to 1,
only files marked as 'new uploads' will be displayed. Otherwise,
all files will be shown.
Advanced Programmer's Tricks:
You might have the occasion to turn off the cursor. Normally that isn't
too hard, but if you want to do it and have it work in DesqView, Windows
95, and DOS all at once it takes a little more. Note that there is no
technique to turn off a remote user's cursor using ANSI, so this only
affects the sysop's perspective.
Set AH = 0x0F, generate interrupt 0x10. This gives you the current
video mode in AL. Now, set AH = 0x01, CX = 0x2002, and generate
interrupt 0x10. This procedure covers some bugs in AMI 386 BIOS and AST
Premier 386 BIOS which require the current video mode in AL or a system
crash results. This procedure may not work properly on EGA systems.
Technical Support:
We will attempt to offer technical support to everyone, even those who
haven't registered the program. However we have very limited resources for
technical support, so everyone can expect to have a little work getting a
hold of us.
All the company's technical support is handled by myself, Wiley Black.
I am the lead programmer on the LightSpeed team, and the author of most of
this document. My name is pronounced "Why-Lee" just like in "Wile E.
Coyote".
I can be reached by modem on the Terror's Zone BBS at (505) 865-0116 or
(505) 865-7789 anytime. Login using the account "Guest" and the password
"LS" for quickest access to our BBS. I am the system operator, "Terror".
Terror's Zone BBS runs using LightSpeed as well as a number of LsDoor
programs.
I can also be reached by voice at (505) 866-5193. This is my home phone
number, and if you want voice support, you can expect me to be out a lot.
PLEASE don't call this number except between these hours:
Between June and August: * All times are Mountain Standard (MST) *
From noon to 8 PM
The rest of the year:
Weekdays from 4 PM to 8 PM
Saturday and Sunday from noon to 8 PM
These numbers may not be valid after January of 1997. You should acquire
a more recent copy of the LsDoor SDK before calling.
*REGISTERED USERS TECHNICAL SUPPORT*
If you are a registered user, the easiest way to get voice support is to
leave me a message with your name, phone number, and the times (MST) for me
to call. You can leave a message on Terror's Zone BBS, or on my answering
machine. I'm sorry but I can't afford to pay long-distance charges for
anyone who hasn't registered.