home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / dr2v41b1.zip / DOORS2.DOC < prev    next >
Text File  |  1994-10-02  |  52KB  |  1,186 lines

  1.                         DOORS/2 -- Version 4.10
  2.  
  3.                         (C) 1994 Joel W. Downer
  4.  
  5.     Based on source for OpenDoors 4.10, (C) 1991 - 1993, Brian Pirie
  6.  
  7.                             WHAT IS DOORS/2?
  8.  
  9. Doors/2 is a 32-bit, multithreaded OS/2 port of Brian Pirie's OpenDoors
  10. 4.10, which is widely acknowledged as the best door library available
  11. for any language or BBS environment.  Doors/2 is a C/C++ library
  12. intended to be used with Borland C++ for OS/2.  It includes features
  13. such as:
  14.  
  15. * Fast, efficient OS/2 serial communications code -- no FOSSILs, .DLLs,
  16.   or other comm service packages required.
  17. * Support for virtually any type of serial port through the OS/2
  18.   communications driver model.
  19. * Multithreaded serial, keyboard, messaging, kernal, and video code for
  20.   top-flight performance with minimal CPU load.
  21. * Support for a wide variety of dropfiles, such as DOOR.SYS,
  22.   DORINFOx.DEF, CHAIN.TXT, and RA 2.00 EXITINFO.BBS.
  23. * The ability to run an OS/2 door from a BBS running in the OS/2 DOS box
  24.   (and they said it couldn't be done... <g>).
  25. * An ultra-fast internode messaging/chat system with throughput suitable
  26.   for real-time interactive doors.
  27. * Built-in support for blanked-screen "secure mode" *with* the ability
  28.   to save and restore the remote screen on demand.
  29. * The rich graphics, dropfile, communications, and interface features of
  30.   OpenDoors 4.10 for DOS (exceptions and exclusions noted below).
  31. * The ability to produce a *single-source* door portable to DOS and OS/2
  32.   with little more than a recompile!
  33. * Coming soon:  OpenDoors 5.00 compatibility and support for popular
  34.   non-Borland compilers!
  35.  
  36. If you're a seasoned door developer and customers have been asking for
  37. OS/2 versions of your products, Doors/2 can help you meet this goal
  38. *without* hundreds of hours porting and fussing with a new environment.
  39.  
  40. If you're a new door developer, OpenDoors for DOS and Doors/2
  41. can allow you to focus on *your application* with minimal attention to
  42. dropfiles, modems, or details of ANSI graphics.  You can create an OS/2
  43. door even if you know little about doors and OS/2!
  44.  
  45.                             SHAREWARE NOTICE
  46.  
  47. This library is distributed as copyrighted shareware.  Although you are
  48. permitted (and encouraged) to copy and distribute this library in its
  49. original, unaltered archive form (with documentation and license
  50. information), the library is *NOT* in the public domain.
  51.  
  52. You are allowed to evaluate this library for a period up to thirty days.
  53. If you wish to use this library after that initial evaluation period,
  54. *OR* if you wish to distribute a program developed with Doors/2 *at any
  55. time* (during the evaluation period or afterwards), you must register.
  56.  
  57. Please see the section on licensing/registration for information on how
  58. to register.  Registered users of Doors/2 will receive a registered copy
  59. of the library, a copy of the source code, and additional tools for OS/2
  60. and DOS door programming that aren't available in the unregistered
  61. version.
  62.  
  63. Thanks for evaluating Doors/2.  Future development and support for this
  64. product depends on you!
  65.  
  66.                                DISCLAIMER
  67.  
  68. Neither I nor any other individual or organization makes a warranty of
  69. any kind regarding the usefulness, reliability, merchantability, or
  70. fitness of this software and documentation for any purpose whatsoever.
  71. While I have tested this library thoroughly, I cannot and will not make
  72. any promises that programs developed with it will run well or safely on
  73. your hardware or with your particular software configuration.  You use
  74. it at your own risk.
  75.  
  76. Your use of Doors/2 and/or any companion material constitutes your
  77. acceptance of these terms.
  78.  
  79.                         REQUIREMENTS/LIMITATIONS
  80.  
  81. Doors/2 is a C/C++ library developed for the Borland C++ for OS/2
  82. compiler.  The version of the library (4.10 wide beta 1) does *not*
  83. currently support other OS/2 compilers, such as CSet++ or Watcom C/C++.
  84. I am feverishly working on providing support for popular OS/2 compilers
  85. for wide beta 2.
  86.  
  87. Doors/2 is intended as a companion product to OpenDoors 4.10 by Brian
  88. Pirie.  It was originally ported from the source to OpenDoors 4.10.
  89. From this point forward, this documentation will assume that you have
  90. and are generally familiar with OpenDoors 4.10:  it will focus almost
  91. exclusively on differences between the two libraries and on techniques
  92. for porting code.  For reference on functions and data members that are
  93. common to OD and Doors/2, please refer to the OpenDoors documentation.
  94. If you need a copy of OpenDoors 4.10, see the section on support, below,
  95. for information on how to obtain one.
  96.  
  97. Because the current version of Doors/2 is based on OpenDoors 4.10,
  98. Doors/2 is *not* completely compatible with OpenDoors 5.00.  Now that
  99. OpenDoors 5.00 has been publicly released, 5.00 support is one of the
  100. top two priorities (along with multicompiler support) that I'm working
  101. on for wide beta 2.  I can't make a promise about a specific release
  102. date for wide beta 2.  I *can* suggest that you not make extreme changes
  103. in your code for backwards compatibility, and that you not spend money
  104. purchasing Borland C for OS/2 (which is apparently generally inferior to
  105. CSet++ and Watcomm) if you don't already have it.
  106.  
  107. Although Doors/2 is intended as an add-on to OpenDoors and must be
  108. registered as such, complete compatibility between OD and Doors/2 is
  109. *not* guaranteed.  In particular, I make no guarantee that Doors/2 will
  110. be compatible with future versions of OpenDoors.
  111.  
  112. Brian Pirie has been very gracious to allow me to distribute this add-on
  113. to his OpenDoors library.  However, he bears *NO* responsibility for the
  114. support and maintenance of this product.  In particular, he has no
  115. obligation to make future changes to OpenDoors in ways that maintain
  116. compatibility with Doors/2.  All responsibility for supporting this
  117. library -- insofar as such responsibility exists -- belongs to Joel W.
  118. Downer.
  119.  
  120.                               QUICK START
  121.  
  122. If you already have a working door that uses OpenDoors 4.10, and you'd
  123. like to recompile it and try it out with Doors/2 and BC-OS/2, this
  124. section will give you a brief introduction to what you'll need to do.
  125.  
  126. Note:  because there are a number of "under-the-hood" differences
  127. between OD 4.10 and Doors/2, I strongly recommend that you read the next
  128. few sections on functionality differences.  If, for example, your door
  129. uses any internal information about OpenDoors, if it uses RA and AVATAR
  130. support, or if it uses control keys (several of which have been
  131. appropriated by the library for use with the messaging system), you may
  132. need to do more work than I describe in this section to get up and
  133. running under OS/2.  However, I understand the impulse to compile and
  134. try things out instead of lingering on documentation.... <g>
  135.  
  136. These instructions will refer to the EZVOTE.C sample door included with
  137. ODoors 4.10, but they should apply to a wide range of door projects.
  138.  
  139. 1. Create a directory for your Doors/2 library and header files, and
  140.    copy the files to that directory.  I'll assume from here that you're
  141.    using C:\SOURCE\DOORS2\, and that your OpenDoors library and header
  142.    files are in C:\SOURCE\ODOORS\.
  143.  
  144. 2. Seek out the line where you include the OpenDoors header file.
  145.    That line probably looks something like this:
  146.  
  147.       #include "c:\source\odoors\opendoor.h"
  148.  
  149.    Replace that line with the following lines, substituting the correct
  150.    directories on your system:
  151.  
  152.       #ifndef __OS2__
  153.       #include "c:\source\odoors\opendoor.h"
  154.       #else
  155.       #include "c:\source\doors2\opendoor.h"
  156.       #endif
  157.  
  158.    This code will tell your compiler to use the Doors/2 version of
  159.    OPENDOOR.H if and only if you're compiling under OS/2.  The __OS2__
  160.    macro is automatically defined by the BC-OS/2 compiler.  Conditional
  161.    compilation -- which tells the compile to ignore or to use certain
  162.    code based on the state of various macros -- is extremely helpful
  163.    when you're writing source code that you want to compile under two or
  164.    more platforms.
  165.  
  166. 3. If your main() function isn't already coded to receive command-line
  167.    arguments, modify it so that it will do so.  In EZVOTE.C, that will
  168.    involve changing the line:
  169.  
  170.       main()
  171.  
  172.    to look like this:
  173.  
  174.       int main(int ac, char *av[])
  175.  
  176.    (Why?  See 4., below.)
  177.  
  178. 4. If you weren't using or processing command-line arguments before, add
  179.    the following prototype to your program:
  180.  
  181.       void ProcessCmdLine(int ac, char *av[]);
  182.  
  183.    and merge the contents of the file cmdline.c into your source file.
  184.    If you're already processing command-line arguments, refer to
  185.    cmdline.c for an example of how to support timing and use_port
  186.    parameters.  Place a call to ProcessCmdLine(ac, av); near the
  187.    beginning of main (in EZVOTE, we'll do it at the very first line).
  188.    Bracket the new code with #ifdef __OS2__ ... #endif directives so
  189.    that it's "invisible" to your DOS compiler, like so:
  190.  
  191.       void main(int ac, char *av[])
  192.          {
  193.          #ifdef __OS2__
  194.          ProcessCmdLine(ac, av);
  195.          #endif
  196.  
  197.          /* And so forth.... */
  198.  
  199.    The purpose of this extra code is to allow the user to indicate
  200.    whether a port or handle will be included in the BBS dropfile (i.e.,
  201.    whether the door is running under Maximus/2 or under a DOS-style BBS)
  202.    and to control the multitasking aggressiveness of the program.
  203.  
  204.    If you prefer to use some other method (a config file, for example),
  205.    that will work just as well; the command-line method is outlined here
  206.    to provide for the quickest possible start.
  207.  
  208. 5. You're now ready to compile!  For EZVOTE.C, we can just compile from
  209.    the command line, like so:
  210.  
  211.       BCC EZVOTE.C C:\SOURCE\DOORS2\DOORS2.LIB
  212.  
  213.    If you're using a makefile, you'll need to create OS/2 versions of
  214.    each of the components.  For example, I build Iron Ox/2 with a
  215.    makefile called OS2MAKE, which (vastly simplified and with many
  216.    source files reduced) looks something like this:
  217.  
  218.       .autodepend
  219.       .path.c = C:\SOURCE\OX
  220.       .path.obj = C:\SOURCE\OS2OBJ
  221.       .path.exe = C:\SOURCE\OS2OUT
  222.  
  223.       .c.obj:
  224.        bcc -c -Vo -v- -f -d -O2 -Od -G- -N -H- -DDEBUG -nC:\SOURCE\OS2OBJ $<
  225.  
  226.       ironox.exe: ironox.obj badstuff.obj auctfunc.obj mailfunc.obj \
  227.       joingame.obj rungame.obj prospect.obj auction.obj makemap.obj \
  228.       (... and so forth ... )
  229.  
  230.        tlink @os2resp
  231.  
  232.    My linker response file, OS2RESP, looks something like this:
  233.  
  234.        -c -s -Toe d:\bcos2\lib\c02 \source\os2obj\rungame +
  235.        \source\os2obj\ironox + \source\os2obj\draw_sqr +
  236.        \source\os2obj\lockfile +
  237.        \source\os2obj\(lots of other object files <g>) +
  238.        \source\os2obj\oxware, c:\source\os2out\ironox.EXE,,
  239.        c:\source\doors2\doors2.lib +
  240.        d:\bcos2\lib\c2mt.lib d:\bcos2\lib\c2mti.lib d:\bcos2\lib\os2.lib
  241.  
  242.    In general, OS/2 text-mode makefiles are simpler than DOS makefiles
  243.    because memory models are not an issue.
  244.  
  245.    Anyway, if you're using makefiles you can compile using a command
  246.    like this:
  247.  
  248.       MAKE -fos2make
  249.  
  250. 6. If you're using non-portable code in your project like direct memory
  251.    access or interrupt calls, the compiler will probably tell you about
  252.    it in a hurry. <g>  EZVOTE.C doesn't, so it'll compile without error
  253.    on the standard warning level for BC-OS/2.  (It will generate one
  254.    warning, because <stdio.h> was not included in the original source,
  255.    but you can safely ignore this warning.)
  256.  
  257.                               THE LIBRARY
  258.  
  259. The next section outlines the functionality differences between Doors/2
  260. and OpenDoors.  The section after that provides some information about
  261. the design and internal workings of Doors/2.  Because Doors/2 was
  262. written to hide the details of OS/2 from the door developer, only the
  263. first section is necessary reading for now.  The material on design
  264. philosophy is intended to give you an idea what to expect if you
  265. purchase the source and to give you a feel for what's going on "under
  266. the hood."
  267.  
  268.         DOORS/2 VS. OPENDOORS 4.10 -- FUNCTIONALITY DIFFERENCES
  269.  
  270. The following known functionality differences exist between OD 4.10 and
  271. this version of Doors/2.  In some cases, the functionality differences
  272. are based on additions or corrections to take advantage of the new
  273. operating environment.  In others, they're based on decisions of
  274. convenience I made during the porting process (i.e., I stripped some
  275. features that did not seem vital in order to simplify the recoding).
  276.  
  277. I am happy to provide suggestions on how to add any unsupported
  278. features that exist in OD 4.10, and/or to correct discrepancies myself
  279. for future versions.
  280.  
  281. Control structure changes:
  282.  
  283.    I've added several new control members to the od_control structure to
  284.    handle specific features of the OS/2 BBS environment.  You will
  285.    probably need to support at least two of them, od_control.use_port
  286.    and od_control.od_timing, with command-line parameters or
  287.    configuration options.  For an example of command-line processing for
  288.    these options, see the cmdline.c file included in the standard
  289.    distribution package.
  290.  
  291. 1. A new od_control member, od_control.od_timing, has been added to
  292.    control the multitasking aggressiveness of the library.  Three values
  293.    are supported:  TIMING_NICE, which is suitable for systems running
  294.    only native software, TIMING_NORMAL, which is a reasonable default
  295.    for most systems, and TIMING_NASTY, which is appropriate on systems
  296.    running DOS comm apps and misbehaved software.  TIMING_NORMAL is the
  297.    default.  Adjustments to this setting should be made before calling
  298.    od_init.
  299.  
  300. 2. Another control member, od_control.use_port, controls whether the
  301.    library expects to find a comm port name or an open comm handle in
  302.    a found dropfile.  The most popular OS/2 native BBS program,
  303.    Maximus/2, places a handle in its dropfiles, not a port name, so the
  304.    library expects a comm handle by default.  Set use_port to TRUE if
  305.    you know that a valid port name will be included in the dropfile.
  306.    Adjustments to this setting should be made before calling od_init.
  307.  
  308.    Sysops will need some means to select use_port to run Doors/2 doors
  309.    with OS/2 software that writes a port name to its dropfile, like
  310.    Lora.  Using the /PORT parameter and Ray Gwinn's SIO drivers, sysops
  311.    who run *DOS BBS'es* under OS/2 can also run Doors/2 doors from the
  312.    OS/2 DOS box.  (See the documentation for Iron Ox for OS/2 for
  313.    information on how to set up an OS/2 door from the DOS box.  Sysops
  314.    will need OS2EXEC or a similar utility to accomplish this purpose.)
  315.  
  316. 3. Another control member, od_infofile[], allows preselection of
  317.    dropfile.  If you wish to allow users to specify dropfile name on the
  318.    command line, you can copy this name (8 x 3 only, not full path!) to
  319.    od_control.od_infofile.  Use of this member is completely optional.
  320.  
  321. 4. Variables for several thread ID's and semaphore handles are currently
  322.    in the od_control structure.  These variables probably do not belong
  323.    in the od_control structure, and will be removed in an upcoming
  324.    version.  In the meantime, I would strongly discourage you from using
  325.    or changing them in any way.
  326.  
  327. 5. A flag, od_control.od_no_messages, allows you to disable multinode
  328.    messaging and chat.  This flag is FALSE by default.  Adjustments to
  329.    this setting should be made before calling od_init.
  330.  
  331. 6. The variable od_control.od_max_nodes controls the highest node number
  332.    the messaging system should search for when it tries to send an
  333.    internode message.  This value is unused when od_no_messages is TRUE;
  334.    otherwise, it defaults to 10.  Adjustments to this setting should be
  335.    made before calling od_init.
  336.  
  337. 7. Seven variables (fossil, od_no_fossil, od_accept_baud,
  338.    od_fifo_disable, force_address, force_irq, and lockbps) have been
  339.    added for compatibility with changes I have made to the DOS version
  340.    of the code to add internal async.  None of these variables is used
  341.    under OS/2; you can remove them if you wish to save a few bytes. <g>
  342.  
  343. 8. Four new function hooks have been added.  All are optional:
  344.  
  345.    void          (*od_warnfunc)(char *str);
  346.  
  347.    If you wish to control the formatting of warnings about keyboard
  348.    inactivity and remaining time, you can write your own function to
  349.    display the warning string, str, to the user.  If you do not set this
  350.    parameter, the default behavior will be used.
  351.  
  352.     void              (*od_cbefore_status)(void);
  353.     void              (*od_cafter_status)(void);
  354.  
  355.    These hooks allow you to define functions that will be called
  356.    immediately before and after updating the status line.
  357.  
  358.    void          (*od_node_message)(tInternodeMsg *);
  359.  
  360.    This function pointer will allow you to define a handler for received
  361.    internode messages.  If max_nodes is greater than one and messaging
  362.    is not disabled, this pointer defaults to the od_show_message
  363.    function when not in chat and the chat_show_message function when in
  364.    chat.  Source for od_show_message (the default function used to
  365.    display messages) is included in the standard shareware package as
  366.    smessage.c.  If you wish to define a new handler for this function, I
  367.    recommend that you use this source as a model.
  368.  
  369. 9. The pointer od_pipe_name controls the name format for the named pipes
  370.    used in internode messaging.  The node number is appended to this
  371.    string to create a unique pipe name for each node.  By default, the
  372.    pipe name is "\\PIPE\\ODPIPE".
  373.  
  374.    If you wish to make internode messaging available in your door, you
  375.    should provide some means by which sysops can change this value.  For
  376.    messaging to work across a LAN, the pipe name must contain the name of
  377.    the server, thus:  "\\SERVER\\PIPE\\ODPIPE".  Also, using a unique
  378.    name for your application might be advisable in case two different
  379.    doors using this library are running simultaneously. <g>
  380.  
  381. 10. Support for the RA 2.00 EXITINFO.BBS format required that several
  382.    members of the od_control user variables be resized (e.g., strings
  383.    lengthened, unsigned ints converted to unsigned longs).  Code that
  384.    relies on the size of these members may need to be changed.
  385.  
  386. 11. The maximum string length handled safely by od_printf is now
  387.    controlled by the macro OD_MAX_STRING, defined in the source package.
  388.    Default is 1,024 bytes.
  389.  
  390. od_init function:
  391.  
  392. 1. A function called od_srand is called from od_init.  Use of od_srand
  393.    and od_random (exactly analogous to Borlands srand and random
  394.    functions) rather than the Borland equivalents is recommended.  The
  395.    Borland OS/2 random number generator is broken.
  396.  
  397. od_kernal function:
  398.  
  399. 1. Checks on carrier and time remaining have been moved to a separate
  400.    kernal thread.  If od_kernal looks a little bare, that's why. <g>
  401.  
  402. 2. The keyboard queue (input_buffer[], b_head, b_tail) is now protected
  403.    by a Mutex semaphore (a system semaphore that allows you to be sure
  404.    that another thread will not modify data you're using at the time).
  405.    Direct manipulation of the keyboard buffer or modem buffer is
  406.    *strongly* discouraged:  you're best off letting the library do the
  407.    work for you.  If you must manipulate the buffers directly, look
  408.    carefully at the way Mutex semaphores are used in the check_key
  409.    function source and do the same.
  410.  
  411. 3. Several of the status line hotkey options have been removed because
  412.    status lines other than F1 and F9 are usually annoyingly blank with
  413.    dropfiles other than EXITINFO.BBS.  If you like having the full range
  414.    of status lines, pasting in the code from the original source should
  415.    be a trivial matter.
  416.  
  417. od_exit function:
  418.  
  419. 1. DOOR.SYS is not rewritten on exit.  The DOOR.SYS standard indicates
  420.    that DOOR.SYS is not to be reread on door exit.
  421.  
  422. 2. The value of "TRUE" for the term_call parameter is unsupported.
  423.  
  424. 3. The od_control.od_noexit toggle is unsupported.  The library
  425.    currently relies on DosExit(1, errorlevel) to terminate library
  426.    threads, so terminating library operation without exiting completely
  427.    is infeasible in this version.  This will change in an upcoming
  428.    version.
  429.  
  430. od_video subsystem:
  431.  
  432. 1. All OpenDoors video functions have been modified to use a cached
  433.    video write system.  Lines 1-23 (the "client window area") are
  434.    maintained using a logical video buffer; od_printf, od_disp,
  435.    od_putch, and so forth have been modified to update this buffer
  436.    instead of addressing the screen directly.  The library uses the
  437.    Borland video routines to maintain the status bar lines.
  438.  
  439.    The most important consequence of this change is that you should use
  440.    avoid using Borland conio functions in your door code.  Use the
  441.    following corresponding functions for each video operation:
  442.  
  443.    For:                    Use:
  444.    --------------------------------------------------------
  445.    clrscr()                od_clr_scr()
  446.    gettext()               od_gettext() or od_save_screen()
  447.    puttext()               od_restore_screen()
  448.    gotoxy()                od_set_cursor()
  449.    wherex()                od_wherex()
  450.    wherey()                od_wherey()
  451.    gettextinfo()           od_get_attrib()   and others...
  452.    textattr()              od_set_attrib()
  453.  
  454. 2. You can now maintain a blank local client window (while keeping track
  455.    of the status of the remote screen) by calling od_blank_display(), and
  456.    restore the local screen with od_restore_display().  This option is
  457.    most useful for games in which the sysop may not want the unfair
  458.    advantage of watching other people play.
  459.  
  460.    od_restore_display() requires no arguments.  od_blank_display() takes
  461.    as argument a string that should be displayed on the local screen to
  462.    indicate that secure mode is on, thus:
  463.  
  464.    od_blank_display("IRON OX 2.00 -- Game in Secure Mode!");
  465.  
  466.    See "Using Secure Mode," below, for more details.
  467.  
  468. od_emu.c
  469.  
  470. 1. The od_emu function itself now writes characters to be sent to the
  471.    modem to a cache for buffering to improve the performance of
  472.    od_send_file under OS/2.
  473.  
  474.    If you call od_emu() outside of od_send_file and od_hotkey_menu, you
  475.    should call od_flush afterward to make sure the characters addressed
  476.    to the modem are sent promptly.
  477.  
  478. 2. od_send_file now returns TRUE if a file was sent successfully and
  479.    FALSE if the send failed or was aborted.  This change can be ignored,
  480.    but it was made to support code like the following:
  481.  
  482.    if (od_send_file(datapath("ALPHANOT", buf)))
  483.       pause();    // Don't pause if this file isn't found....
  484.  
  485. 3. I removed support for RA-specific control codes (which seemed of
  486.    fairly narrow interest) from the emulator to simplify the caching
  487.    code.  If you need this support, let me know and we can give it a
  488.    try....
  489.  
  490. 4. Avatar support is not currently available in the emulator.  From the
  491.    research I did while doing the original port, I found virtually no
  492.    sysop demand for Avatar support, and eliminating the complex
  493.    sequence-handling greatly simplified the conversion.  I am open to
  494.    re-adding Avatar support to an upcoming version if I find sufficient
  495.    demand.
  496.  
  497.                           DOORS/2:  THE DESIGN
  498.  
  499. I began work on Doors/2 when I decided that I wanted to create an OS/2
  500. version of my BBS game door, Iron Ox.  Having already done considerable
  501. work with the OpenDoors library source, I naturally concluded that
  502. adapting that source would be the easiest way to develop a complete door
  503. library for OS/2.
  504.  
  505. My design goal in porting OpenDoors was to try to encapsulate all
  506. operating-system specific code in the door library.  In other words,
  507. your application source code shouldn't need to know whether it's going
  508. to be linked to OpenDoors for DOS or to Doors/2.
  509.  
  510. Modifying OpenDoors so that it would compile cleanly under BC-OS/2, link
  511. with program code, and run from a Maximus/2 BBS was a relatively minor
  512. job.  There were a number of small details, like eliminating direct
  513. access to the hardware clock and adapting the dropfile code to read a
  514. comm handle instead of the name of a comm port from a dropfile, but the
  515. only serious change was isolating and modifying the communications code
  516. and changing the FOSSIL interrupts into calls to the OS/2 device driver.
  517. Easy enough.
  518.  
  519. Unfortunately, the resulting first try was a pig, and a very slow one at
  520. that. <g>  Performance was at best half what I'd learned to expect from
  521. OpenDoors 4.10, and the emulator was even worse -- emulating a large
  522. ANSI file took 4-10 times as long under this ported version as it did in
  523. the original.  CPU load was also higher than you'd get from a DOS door
  524. written with OpenDoors running in the DOS box.  This outcome wasn't a
  525. surprise -- single-character I/O and polling just don't cut it under
  526. OS/2 -- but it did indicate that the work had just begun.
  527.  
  528. So, let's make a boring story short:  Doors/2 makes heavy use of caching
  529. and multithreading to achieve performance comparable to what you can get
  530. from DOS video and communications code.  Input (through the keyboard or
  531. the modem) is read by dedicated threads that block on input (put
  532. themselves to sleep until something happens).  Output is written to
  533. memory buffers, and is flushed by low-priority output threads.  The
  534. result is door programs with excellent performance and less than 4% CPU
  535. load on most systems.
  536.  
  537. Doors/2 programs will usually have seven threads of execution (fewer if
  538. multinode messaging is disabled and/or the program is running in local
  539. mode):
  540.  
  541. 1. Main program thread:
  542.  
  543.    This thread executes the code you write.  It will call functions like
  544.    od_get_key() to get input from the keyboard and serial input threads,
  545.    and functions like od_send_file, od_printf, and od_disp to request
  546.    that data be displayed to the screen and sent out the modem.
  547.  
  548. 2. Serial input thread:
  549.  
  550.    This thread waits for characters to come in through the serial port.
  551.    When characters are received, it adds them to the input queue.  Like
  552.    most good threads, it spends most of its time sleeping.
  553.  
  554. 3. Keyboard input thread:
  555.  
  556.    This thread waits for characters to come in through the keyboard
  557.    buffer so that it can add them to the input queue.  Again, the rest
  558.    of the time, it sleeps.
  559.  
  560. 4. Message thread:
  561.  
  562.    This thread waits for messages to come in through the node's message
  563.    pipe.  When a message is received, it adds the message to a queue
  564.    that will be checked next time your program waits for keyboard input
  565.    (i.e., calls od_get_key(TRUE)).  This thread is not created if you
  566.    disabled multinode messaging.
  567.  
  568. 5. Serial output thread:
  569.  
  570.    This thread writes characters to the serial driver.  It has a lower
  571.    priority than the other program threads, which allows the program to
  572.    buffer outgoing characters and send them out in blocks when a large
  573.    volume of data is being sent.
  574.  
  575. 6. Video refresh thread:
  576.  
  577.    Updating the text-mode video screen is a relatively expensive
  578.    activity under OS/2:  the VIO16 functions are fairly slow and have
  579.    significant overhead.  Therefore, all of the Doors/2 video functions
  580.    work by updating a virtual screen -- a memory buffer belonging to the
  581.    program.  The video refresh thread uses idle time to repaint lines of
  582.    the display that have been changed.
  583.  
  584. 7. Kernal thread:
  585.  
  586.    This thread checks for timeout, user time remaining, and dropped
  587.    carrier.  It, too, is a low-priority thread, and sleeps approximately
  588.    five seconds between checks.
  589.  
  590. This design may seem fairly Byzantine if you're unaccustomed to
  591. multithreaded programming, but the underlying philosophy -- creating
  592. threads for logically discrete activities and having them go to sleep
  593. until something happens rather than having them poll -- provides
  594. excellent performance with minimal CPU load.
  595.  
  596.                               NEW FEATURES
  597.  
  598. Doors/2 contains two substantial additions to the functionality of
  599. OpenDoors 4.10:  "Secure Mode" blank screen support, and multinode
  600. messaging.  Both of these features are entirely optional.  You can avoid
  601. using secure mode simply by not calling the functions that activate it.
  602. You can disable multinode messaging by setting:
  603.  
  604.    od_control.od_no_messages = TRUE;
  605.  
  606. However, both of these features do add useful functionality to the
  607. library, so you may wish to consider using them.
  608.  
  609.                            USING SECURE MODE
  610.  
  611. When you activate secure mode, the local display is blanked except for
  612. the status bar and a line that you specify across the middle of the
  613. screen.  The screen remains blank until you explicitly unblank it or
  614. until the user exits the door.  Secure mode would most often be used to
  615. prevent an unfair sysop advantage in door games.  If you don't wish to
  616. use secure mode, you can skip over this section:  secure mode is off by
  617. default.
  618.  
  619. Blanking and unblanking the screen is very simple.  You can blank it
  620. with a call to:
  621.  
  622.    od_blank_display(pszBlankLine);
  623.  
  624. where pszBlankLine is a string you want displayed centered on the blank
  625. display (for example, "Iron Ox 2.00 -- Game in Secure Mode").  You can
  626. unblank it at any time using:
  627.  
  628.    od_restore_display();
  629.  
  630. While the screen is blanked with od_blank_display(), what *would have*
  631. been displayed on the screen is stored in a memory buffer, so that
  632. Doors/2 can keep track of the remote user's display.  If you use the
  633. function od_gettext() while the display is blanked, od_gettext will
  634. capture the contents of the memory buffer (the "virtual display") and
  635. not of the blank actual display.  Why might you want to save the
  636. contents of the "virtual display"?  The most common reason is to allow
  637. screen restore after sysop chat.  (Screen restore after multiplayer chat
  638. is handled automatically by the library assuming that enough memory is
  639. available.)
  640.  
  641. Handling sysop chat is one of the few hairy things about secure mode.
  642. Both OpenDoors and Doors/2 have the function pointers
  643. od_control.od_cbefore_chat and od_control.od_cafter_chat that allow you
  644. to run a custom function before and after sysop chat.  At very least,
  645. you need to use the od_cbefore_chat function to restore the display so
  646. that the sysop will be able to see what he/she and the remote user are
  647. typing.  You need to use the od_cafter_chat function to reblank the
  648. display if it was blanked before chat.  You also may want to insert
  649. logic to save and restore the remote screen if your application is a
  650. fixed-screen rather than scrolling-screen program.
  651.  
  652. Here are sample pre-chat and post-chat functions that do as described:
  653.  
  654.  
  655. char            pszBlankStr[] = "IRON OX -- GAME IN SECURE MODE";
  656.  
  657. static boolean  secure_mode;         // Module status variables; shared by
  658. static short    savex;               // save and restore functions.
  659. static short    savey;
  660. static char *   screenbuf;
  661.  
  662. void save_screen(void)        // Pre-chat func; saves screen & secure state
  663.    {
  664.    saveattrib = cur_attrib;
  665.    savex = od_wherex();
  666.    savey = od_wherey();
  667.     
  668.    if (screenbuf != NULL)
  669.       {
  670.       od_printf("\n\r\aCan't save screen!  Buffer is in use!");
  671.       return;
  672.       }
  673.    
  674.    if ((screenbuf = malloc(3680 * sizeof(char))) == NULL)
  675.       {
  676.       od_printf("\n\r\aInsufficient memory to save screen!");
  677.       return;
  678.       }
  679.    
  680.    od_gettext(1, 1, 80, 23, screenbuf);
  681.  
  682.    if (fScreenBlank)
  683.       {
  684.       secure_mode = TRUE;
  685.       od_restore_display();
  686.       }
  687.    else
  688.       secure_mode = FALSE;
  689.  
  690.    clr_scr();
  691.    }
  692.  
  693.  
  694. void restore_screen(void)
  695.    {
  696.    od_control.od_chat_disable = TRUE;     // Re-entrancy protection... don't
  697.    od_control.od_shell_disable = TRUE;    // want chat while redrawing!
  698.    
  699.    if (screenbuf == NULL)
  700.       {
  701.       od_printf("\n\r\aError:  unable to restore screen!");
  702.       od_control.od_chat_disable = FALSE;
  703.       od_control.od_shell_disable = FALSE;
  704.       return;
  705.       }
  706.    
  707.    if ((secure_mode == TRUE) && (od_control.baud != 0))
  708.       od_blank_display(pszBlankStr);
  709.    
  710.    od_restore_screen(screenbuf, savex, savey, 1, 1, 80, 25);
  711.     
  712.    free(screenbuf);
  713.     
  714.    screenbuf = NULL;
  715.     
  716.    od_clear_keybuffer();
  717.  
  718.    /* If sysop hits 's' during chat, will abort od_send_file.  This is
  719.       common to OD 4.10 and Doors/2. */
  720.  
  721.    _last_control_key = 0;
  722.     
  723.    od_set_attrib(saveattrib);
  724.     
  725.    od_control.od_chat_disable = FALSE;
  726.    od_control.od_shell_disable = FALSE;
  727.    }
  728.  
  729.  
  730.                      THE MULTINODE MESSAGING MODULE
  731.  
  732. Doors/2 adds three built-in multinode-aware features to the
  733. functionality of OpenDoors.  At any time your program is waiting for
  734. input, the user can request a list of other people currently in the
  735. door, can send a message to one of those people, and can enter multinode
  736. chat.  Doors/2 automatically intercepts the following key commands:
  737.  
  738.    Ctrl-O      List people on the other nodes.
  739.    Ctrl-E      Enter a message for a player on another node.
  740.    Ctrl-T      Enter multinode chat.
  741.  
  742. Doors/2 automatically saves the screen before any of these functions and
  743. restores the screen afterwards.  If you have enabled the OpenDoors log
  744. feature, Doors/2 will add a notice to the log when users activate these
  745. options.
  746.  
  747. For the most part, these functions are completely automatic and clean up
  748. after themselves.  If you wish to disable messaging, you must do so
  749. explicitly by setting od_control.od_no_messages to TRUE before calling
  750. od_init():  messaging defaults to ON.
  751.  
  752. If you do decide to leave messaging active in your application, here are
  753. some concerns you should be aware of:
  754.  
  755. 1. The value od_control.od_max_nodes contains the highest node number
  756.    Doors/2 will look for.  This value defaults to ten.  If a user
  757.    attempts to enter the door on a node number *higher* than
  758.    od_control.od_max_nodes, and multinode messaging is enabled, the door
  759.    will display an error message and exit.  Therefore, you will
  760.    definitely want to give sysops running your door some way
  761.    (command-line argument, config file option) to adjust this value.
  762.    (Sysops running fewer than ten nodes may also wish to adjust it to
  763.    improve performance.)
  764.  
  765. 2. Somewhere in your program, you will probably want to display a menu
  766.    of multinode options so that users will know how to use them.  I have
  767.    code like the following in Iron Ox/2 v. 1.12:
  768.  
  769.          #ifdef __OS2__
  770.  
  771.          if (od_control.od_max_nodes > 0)
  772.             {
  773.             clr_scr();
  774.  
  775.             od_set_cursor(1, 19);
  776.  
  777.             od_printf("`bright cyan`Iron Ox multinode messaging is "
  778.                "`bright white`ENABLED.");
  779.  
  780.             od_set_cursor(3, 31);
  781.             od_printf("Commands`bright cyan`:");
  782.             od_set_cursor(5, 13);
  783.             od_printf("Press `bright white`Ctrl-O`bright cyan`"
  784.                " to list players currently in the game.");
  785.             od_set_cursor(6, 13);
  786.             od_printf("Press `bright white`Ctrl-E`bright cyan` to enter "
  787.                "a message for another node, and");
  788.             od_set_cursor(7, 13);
  789.             od_printf("Press `bright white`Ctrl-T`bright cyan` to enter "
  790.                "group chat!\n\r");
  791.  
  792.             od_printf("`bright yellow`< Press a Key >");
  793.  
  794.             od_get_key(TRUE);
  795.             }
  796.  
  797.          #endif
  798.           
  799. 3. You may also want to have your program send messages to other nodes
  800.    about common events -- someone entering or leaving the door, someone
  801.    being immortalized for the all-time record bowling score, and so
  802.    forth.  See documentation on SendMessage(), below, for instructions
  803.    on doing this.
  804.  
  805. That's all there is to it!
  806.  
  807.                        DOORS/2 FUNCTION REFERENCE
  808.  
  809. For the most part, your Doors/2 door program will rely on the functions
  810. included in OpenDoors to do its work.  Please refer to the OpenDoors
  811. documentation for information on these functions.  This section includes
  812. details on functions unique to Doors/2.
  813.  
  814.  
  815. od_blank_display()
  816. ----------------------------------------------------------------------------
  817.  
  818. PURPOSE        Activates blanked-screen secure mode.
  819.  
  820. FORMAT         void od_blank_display(char *pszBlankStr);
  821.  
  822. DESCRIPTION    This function blanks the local display and redirects screen
  823.                writes to a virtual video buffer.  pszBlankStr is
  824.                displayed, centered, on the blank screen.  See "Using
  825.                Secure Mode," above, for more details.
  826.  
  827. SEE ALSO       od_restore_display(), od_gettext();
  828.  
  829.  
  830. od_get_attrib()
  831. ----------------------------------------------------------------------------
  832.  
  833. PURPOSE        Returns the current video attribute.
  834.  
  835. FORMAT         int od_get_attrib(void);
  836.  
  837. DESCRIPTION    Because all video attributes are virtualized, the Borland
  838.                run-time library gettextinfo call will not return correct
  839.                information about the current video attribute.  This
  840.                function will return that information.
  841.  
  842. SEE ALSO       od_gettext();
  843.  
  844.  
  845. od_gettext()
  846. ----------------------------------------------------------------------------
  847.  
  848. PURPOSE        Activates blanked-screen secure mode.
  849.  
  850. FORMAT         void od_gettext(int lcol, int lrow, int rcol, int rrow,
  851.                                void *buf);
  852.  
  853. DESCRIPTION    This function allows you to save the contents of the
  854.                *user* display (what the library has transmitted to the
  855.                remote screen) regardless of the state of secure mode.
  856.                (The Borland library function gettext() will capture the
  857.                local screen, which is fine in standard mode but is
  858.                probably not what you want when the local screen is
  859.                blanked.)
  860.  
  861. EXAMPLE        See the sample pre-chat and post-chat functions in "Using
  862.                Secure Mode" for an example of this function.
  863.  
  864. SEE ALSO       od_blank_display(), od_restore_display();
  865.  
  866.  
  867. od_random()
  868. ----------------------------------------------------------------------------
  869.  
  870. PURPOSE        Returns a random number.
  871.  
  872. FORMAT         int od_random(int max);
  873.  
  874. DESCRIPTION    This function will return a random number between 0 and
  875.                max - 1.  This function was necessary because the Borland
  876.                random number generator is broken:  the Borland code
  877.                returns a small subset of the possible range of values in
  878.                a very tight periodicity, such that programs that rely on
  879.                normal pseudorandom periods can hang.
  880.  
  881.                The library seeds the random number generator
  882.                automatically in od_init, so no preparatory work on your
  883.                part is required.
  884.  
  885.  
  886. od_restore_display()
  887. ----------------------------------------------------------------------------
  888.  
  889. PURPOSE        Deactivates blanked-screen secure mode.
  890.  
  891. FORMAT         void od_restore_display(void);
  892.  
  893. DESCRIPTION    This function unblanks a display that has been previously
  894.                blanked with od_blank_display().  See "Using Secure
  895.                Mode," above, for more details.
  896.  
  897. SEE ALSO       od_blank_display();
  898.  
  899.  
  900. od_wherex()
  901. ----------------------------------------------------------------------------
  902.  
  903. PURPOSE        Returns the current cursor x position.
  904.  
  905. FORMAT         int od_wherex(void);
  906.  
  907. DESCRIPTION    Because the video display and cursor location are
  908.                virtualized, the Borland library call wherex() will
  909.                usually *not* return the correct cursor position.
  910.                (Virtualizing the cursor position reduces the number of
  911.                performance-reducing API calls and eliminates the
  912.                "dancing cursor" when in secure mode.)  od_wherex() will
  913.                return the correct cursor location.
  914.  
  915. EXAMPLE        See the sample pre-chat and post-chat functions in "Using
  916.                Secure Mode" for an example of this function.
  917.  
  918. SEE ALSO       od_wherey();
  919.  
  920.  
  921. od_wherey()
  922. ----------------------------------------------------------------------------
  923.  
  924. PURPOSE        Returns the current cursor y position.
  925.  
  926. FORMAT         int od_wherey(void);
  927.  
  928. DESCRIPTION    Because the video display and cursor location are
  929.                virtualized, the Borland library call wherex() will
  930.                usually *not* return the correct cursor position.
  931.                od_wherey() will return the correct cursor location.
  932.  
  933. EXAMPLE        See the sample pre-chat and post-chat functions in "Using
  934.                Secure Mode" for an example of this function.
  935.  
  936. SEE ALSO       od_wherex();
  937.  
  938.  
  939. SendMessage()
  940. ----------------------------------------------------------------------------
  941.  
  942. PURPOSE        Transmits a message to some or all of the other nodes in
  943.                the door.
  944.  
  945. FORMAT         int SendMessage(short dest_node, char *player, short event,
  946.                                boolean from_player, char *format, ...);
  947.  
  948. RETURNS        OK on success, ERROR on failure (macros defined in
  949.                Doors/2 version of OPENDOOR.H).
  950.  
  951. DESCRIPTION    This function allows you to send a message and
  952.                accompanying information to other instances of the
  953.                program running on other BBS nodes.  This message may be
  954.                a text note directed to a user, or it may be
  955.                notification of an event that is not displayed to the
  956.                user.
  957.  
  958.                The parameter "dest_node" controls which nodes will
  959.                receive the message.  This parameter may be any number
  960.                between 1 and the value contained in
  961.                od_control.od_max_nodes, or DEST_ALL_NODES, which
  962.                indicates that the message should be sent to all active
  963.                nodes.
  964.  
  965.                The parameter "player" should include the name of the
  966.                person currently using the door.  Usually, you will want
  967.                to use od_control.user_name for this parameter.
  968.  
  969.                The "event" parameter is used by internal messaging
  970.                functions to transmit background information -- for
  971.                example, that a user is entering or exiting chat, or
  972.                entering or leaving the door.  You should normally set it
  973.                to zero.
  974.  
  975.                The "from_player" parameter distinguishes whether a
  976.                message was written by a player or sent by the door.
  977.                This parameter will often determine how a message is
  978.                displayed on the receiving end, thus distinguishing:
  979.  
  980.                   Received from Bob on Node 2:  Hi!
  981.  
  982.                from:
  983.  
  984.                   Bob has just died in game 6!
  985.  
  986.                Because users are already able to enter messages using
  987.                the Ctrl-E hotkey, your code will usually set this value
  988.                to FALSE.
  989.  
  990.                The remaining parameters correspond to the structure used
  991.                by printf() and od_printf().
  992.  
  993. EXAMPLE        I use the following code if a new player decides not to
  994.                join Iron Ox:
  995.  
  996.                if (ans == 'H')
  997.                   {
  998.                   od_printf("\n\r\nOh, well, if you change your mind, "
  999.                      "you know where to find the launching pad.\n\r");
  1000.                   pause();
  1001.                   SendMessage(DEST_ALL_NODES, od_control.user_name, 0, FALSE,
  1002.                      "%s decided Ox looked too tough.", od_control.user_name,
  1003.                      od_control.od_node);
  1004.                   od_exit(10, FALSE);
  1005.                   }
  1006.  
  1007.                To maintain compatibility with ODoors 4.10, you could use
  1008.                conditional compilation so that SendMessage() will only
  1009.                be called in your OS/2 version:
  1010.  
  1011.                   #ifdef __OS2__
  1012.                   SendMessage(DEST_ALL_NODES, od_control.user_name, 0, FALSE,
  1013.                      "%s decided Ox looked too tough.", od_control.user_name,
  1014.                      od_control.od_node);
  1015.                   #endif
  1016.  
  1017.  
  1018.                               REGISTRATION
  1019.  
  1020. Doors/2 is distributed as an add-on for OpenDoors.  I created Doors/2 by
  1021. adding to and modifying Brian Pirie's source to support a new
  1022. environment.
  1023.  
  1024. For this reason, registration for Doors/2 is only available to people
  1025. who have a source registration for OpenDoors.  I have included a copy of
  1026. the registration form for OpenDoors as ODSORDER.FRM.  Remember:  before
  1027. I can send you your registration for Doors/2, I am required by law to
  1028. verify that you have purchased a *full source registration* to
  1029. OpenDoors!
  1030.  
  1031. Registration for Doors/2 costs US$50.00.  Registration entitles you to
  1032. use Doors/2 in any of your programs without royalties.  You will also
  1033. receive complete source to the Doors/2 library.  You may modify and
  1034. recompile this source in any way you like.  (You may not distribute
  1035. modified versions of the library, except as part of executable door
  1036. programs, without my permission.)  When new versions of Doors/2 become
  1037. available, you will be entitled to an updated version of the source (see
  1038. below for details).
  1039.  
  1040. EARLY REGISTRATION DISCOUNT:  If you register your copy of Doors/2
  1041. before December 31, 1994, you will qualify for a discount of US$15.00
  1042. off the standard registration price of $50.00.  In other words,
  1043. registration will only cost US$35.00!
  1044.  
  1045.               PLACING YOUR ORDER AND UPDATING YOUR SOURCE
  1046.  
  1047. To order Doors/2, fill out the order form contained in REGISTER.FRM and
  1048. mail it, along with a check or money order for the correct amount, to:
  1049. Joel Downer, 4431 Parks Avenue #2, La Mesa, CA  91941-6166.
  1050.  
  1051. Please note:  I require that checks or money orders be made in United
  1052. States funds drawn on United States banks.  While I want to be as
  1053. accommodating as possible, checks that are not in U.S. funds or that are
  1054. drawn on foreign banks can cost US$10.00 or more for me to process, so I
  1055. will not accept them.
  1056.  
  1057. When I receive your registration and have verified that you are already
  1058. a registered owner of OpenDoors, I will send you a registration package
  1059. including (1) a library version of Doors/2 without the "unregistered
  1060. evaluation -- illegal to distribute" message, and (2) a complete copy of
  1061. the Doors/2 source code.  You may choose to receive your registration in
  1062. any of the following ways:
  1063.  
  1064. (1) Fidonet crashmail:  If you run a Fidonet BBS in North America, I
  1065.     can transmit your registration package to you via Fido crashmail
  1066.     file attachment.  I am willing to crashmail orders outside of North
  1067.     America, but to call outside North America I require an additional
  1068.     fee of US$15.00 to cover long-distance charges.
  1069.  
  1070. (2) Conventional mail:  If you prefer, I can transmit your registration
  1071.     package on a 3-1/2" or 5-1/4" diskette (your choice) through
  1072.     conventional mail.  Sorry, but I'm unable to offer accelerated
  1073.     shipping (next-day air, etc.) under any circumstances.
  1074.  
  1075. (3) BBS Login:  If you have no Fidonet address but are in a hurry to get
  1076.     your registration package, you can arrange to log into my BBS to
  1077.     download your registration package.  Please be sure to fill out the
  1078.     required login information on the registration form (i.e., password,
  1079.     date of birth)!  When I receive your registration, I will create an
  1080.     account for you so that you can pick up your package on one call.
  1081.  
  1082. Once you have received your registration package, you will be entitled
  1083. to receive updates to the library upon request, in any of the following
  1084. ways:
  1085.  
  1086. (1) On request, I will put the files on hold for you to pick up via a
  1087.     Fidonet poll (you must be a nodelisted sysop),
  1088.  
  1089. (2) You may mail me a self-addressed, stamped envelope and diskette, or
  1090.  
  1091. (3) You may ask me to attach the files to a personal message to you on
  1092.     my BBS (I ask that you already have an account on my BBS when you
  1093.     make this request).
  1094.  
  1095.                        ADDITIONAL LICENSE INFO
  1096.  
  1097. You are allowed (and encouraged) to distribute unmodified copies of
  1098. the shareware version of Doors/2 so long as you distribute the complete
  1099. archive with all files intact.  You may include unmodified, complete
  1100. archive versions of the shareware edition of Doors/2 in software
  1101. collections (e.g., CD-ROMs) so long as the documentation for the
  1102. collection clearly indicates that it contains shareware products and
  1103. that the purchase of the collection does not constitute a license for
  1104. the use of said products.
  1105.  
  1106. Distribution of the registered version of Doors/2 (the source to the
  1107. library and the registered version of the library) is strictly
  1108. prohibited.  Distribution of programs developed with the unregistered
  1109. version of the library is also prohibited.  Registered users may
  1110. distribute programs developed with modified versions of Doors/2, but may
  1111. *not* distribute modified versions of Doors/2 in reusable (library)
  1112. form.
  1113.  
  1114. Your registration is good for all future releases of Doors/2:  you will
  1115. be entitled to obtain a new copy of the library source by any of the
  1116. means listed above.
  1117.  
  1118. Registrations are non-transferrable without my direct permission.
  1119.  
  1120.                               SUPPORT
  1121.  
  1122. I am committed to supporting and improving this product.  Please feel
  1123. free to contact me with questions, problems, or suggestions.
  1124.  
  1125. I can be reached via the Internet as joel@dreamcty.jd.com.  For those
  1126. with Internet access, this approach may provide the fastest and most
  1127. reliable method of asking questions, reporting problems, or providing
  1128. feedback except Fidonet crashmail.
  1129.  
  1130. I can be reached via crashmail or routed netmail at Fidonet 1:202/704
  1131. and 1:202/705, and at DoorNet 75:7619/7.
  1132.  
  1133. The support BBS for Doors/2, and for all other software by Joel Downer,
  1134. is The Dreaming City.  The Dreaming City has two lines:
  1135.  
  1136. Node 1:  USR Dual HST 14.4/ v.32 9600    (619) 462-8406
  1137. Node 2:  ZyXEL 16.8 v.32bis              (619) 462-7146
  1138.  
  1139. The latest shareware version of Doors/2 will always be available for
  1140. first-call download on this system and for FREQ as DOORS2 from 1:202/704
  1141. and 1:202/705.  I will also have ODOORS41.ZIP available as long as
  1142. Doors/2 is based on it (Magic Name:  OD4), and the latest version of
  1143. OpenDoors (Magic Name:  ODOORS).
  1144.  
  1145. I monitor the Fidonet OPENDOORS echo for personal mail.  I will attempt
  1146. to reply promptly to echo messages, email and netmail messages, and
  1147. messages in the DOORS2 support conference on my BBS.
  1148.  
  1149.                               FUTURE PLANS
  1150.  
  1151. I regularly update my door development tools as I develop versions of
  1152. Iron Ox and other doors.  While I can't make guarantees about future
  1153. versions, here are some of the features I'm considering for future
  1154. versions of Doors/2:
  1155.  
  1156. * OpenDoors 5.00 compatibility
  1157.  
  1158.   As of this writing (September, 1994), OpenDoors 5.00 has just been
  1159.   publicly released.  I am already working on converting this library
  1160.   for 5.00 compatibility.
  1161.  
  1162. * Multicompiler support
  1163.  
  1164.   As an adjunct to the 5.00 port, I am also working on converting this
  1165.   library to support multiple compilers.  Both 5.00 compatibility and
  1166.   support for several popular compilers are targeted goals for wide
  1167.   beta 2.
  1168.  
  1169. * "Reverse compatibility"
  1170.  
  1171.   This version of Doors/2 includes a number of (optional) features that
  1172.   don't appear in OpenDoors (e.g., internode messaging, secure mode).  I
  1173.   already have code to duplicate these features for DOS using OpenDoors
  1174.   4.10; I am considering updating this code for OD 5.00, bundling it
  1175.   into libraries, and making them available to registered Doors/2 users.
  1176.  
  1177. * Stronger Wildcat! Support
  1178.  
  1179.   I am considering including support for the WC 3.x USERINFO.DAT file
  1180.   and the WC 4.x USERREC.BIN files in future versions.  These are the
  1181.   dropfiles read back by Wildcat, so they are required for time banks
  1182.   and other Wildcat utility doors.
  1183.  
  1184. Your feedback will help me decide which of these features (and which
  1185. features not listed here) will appear in future versions!
  1186.