home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / U3250.ZIP / U3.DOC < prev    next >
Encoding:
Text File  |  1996-05-28  |  52.8 KB  |  1,195 lines

  1.  
  2.  
  3.  
  4.                              User Updater--Universal
  5.                                   Version 2.50
  6.  
  7.                           Copyright 1996 by Thomas Almy
  8.  
  9.                                 TABLE OF CONTENTS
  10.  
  11.  
  12.                INTRODUCTION  . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           2
  13.                          WARRANTEE  . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           2
  14.                          DISTRIBUTION . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           3
  15.                          USER UPDATER -- UNIVERSAL IS SHAREWARE . . . . . . . . . . . .                                                                           3
  16.                          TRADEMARKS . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           3
  17.  
  18.                RUNNING USER UPDATER -- UNIVERSAL . . . . . . . . . . . . . . . . .                                                                           4
  19.                          USERBASE MODE  . . . . . . . . . . . . . . . . . . . . . . . .                                                                           4
  20.                          DOOR MODE  . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           5
  21.  
  22.                USER UPDATER COMMAND FILE . . . . . . . . . . . . . . . . . . . . .                                                                           6
  23.                          OPPERANDS: FIELDS AND NUMBERS  . . . . . . . . . . . . . . . .                                                                           7
  24.                          EXPRESSIONS  . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           9
  25.                          LET STATEMENT  . . . . . . . . . . . . . . . . . . . . . . . .                                                                          10
  26.                          PRINT STATEMENT  . . . . . . . . . . . . . . . . . . . . . . .                                                                          10
  27.                          SET STATEMENT  . . . . . . . . . . . . . . . . . . . . . . . .                                                                          11
  28.                          RUN STATEMENT  . . . . . . . . . . . . . . . . . . . . . . . .                                                                          12
  29.                          RETURN STATEMENT . . . . . . . . . . . . . . . . . . . . . . .                                                                          13
  30.                          THE OPTIONAL "FINALLY" COMMAND . . . . . . . . . . . . . . . .                                                                          13
  31.  
  32.                ERROR MESSAGES  . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                          14
  33.  
  34.                EXAMPLES OF USE . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                          16
  35.                          RESET A FLAG . . . . . . . . . . . . . . . . . . . . . . . . .                                                                          16
  36.                          DELETING NON-VERIFIED CALLERS  . . . . . . . . . . . . . . . .                                                                          16
  37.                          RAISING LEVELS AND POSTING MESSAGES  . . . . . . . . . . . . .                                                                          17
  38.                          LOW CREDITS WARNING  . . . . . . . . . . . . . . . . . . . . .                                                                          17
  39.                          LIST AND TALLY TERMINAL EMULATIONS . . . . . . . . . . . . . .                                                                          17
  40.                          NOTIFY XMODEM USERS  . . . . . . . . . . . . . . . . . . . . .                                                                          18
  41.                          POSTS PER MONTH RATIO LIST . . . . . . . . . . . . . . . . . .                                                                          18
  42.                          POST PER DOWNLOAD RATIO DOOR . . . . . . . . . . . . . . . . .                                                                          18
  43.                          TIME PURCHASE DOOR . . . . . . . . . . . . . . . . . . . . . .                                                                          19
  44.                          GENDER BASED DOOR  . . . . . . . . . . . . . . . . . . . . . .                                                                          19
  45.                          NIGHTLY MAINTENANCE AT BITTER BUTTER BETTER BBS  . . . . . . .                                                                          20
  46.  
  47.                TECHNICAL NOTES . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                          21
  48.  
  49.                OTHER UTILITIES BY THE AUTHOR OF U3 . . . . . . . . . . . . . . . .                                                                          22
  50.  
  51.  
  52.      User Updater -- Universal                                                          2
  53.  
  54.  
  55.  
  56.                                    INTRODUCTION
  57.  
  58.      The User Updater--Universal (or U3) program performs userbase
  59.      maintenance in RemoteAccess 2.5x or 2.0x BBSes.  Unlike other userbase
  60.      maintenance programs, U3 provides virtually unlimited test conditions
  61.      and actions.  Conditions can be based on any combinations of date,
  62.      flag, and numeric field values.  When the condition is true, any
  63.      number of fields can be modified, information can be printed, and/or
  64.      external programs (such as robotic mailers) can be executed, and U3's
  65.      own return error level code can be set.  Almost every field in the
  66.      userbase can be examined.
  67.  
  68.      Ten "global fields" can be used to store values, allowing the program
  69.      to do such things as count the number of callers meeting a specific
  70.      criteria or to calculate the average caller age.
  71.  
  72.      In addition, U3 can be used in a type 7 or 15 menu item (door) to
  73.      perform the same set of operations on the current logged in user. This
  74.      is called "door mode."
  75.  
  76.      U3 can be readily combined with other programs in batch files. The use
  77.      of U3 is virtually limited only by your imagination!
  78.  
  79.      Sysops who have had some programming experience in a language like
  80.      BASIC or Pascal will find U3 easy to use. Those without experience
  81.      should study closely the examples at the end of the instructions.
  82.  
  83.      I wrote U3 because I found myself using several custom programs to do
  84.      userbase maintenance, and it made sense to me to have a program which
  85.      could do all modifications.  I hope you ll find it as useful as I have
  86.      and will register!
  87.  
  88.      **** WARRANTEE
  89.  
  90.      User Updater Universal (U3) is provided "AS IS" with no warranties or
  91.      guarantees of any kind.  Since U3 is distributed as fully functional
  92.      shareware, it is the responsibility of the potential purchaser to
  93.      determine that U3 is suitable for use before purchasing.  The author
  94.      does not make any claims, promises, or guarantees as to the usability
  95.      of U3 for any particular purpose and cannot and does not accept any
  96.      responsibility for system damage, loss of profit, or any other
  97.      special, incidental or consequential damages resulting from this
  98.      product.
  99.  
  100.      The author has taken care in writing this program, however U3 by its
  101.      very nature is capable of destroying or modifying data.  The user
  102.      should always back up the BBS userbase files prior to testing U3 or
  103.      modifying any U3 command files.
  104.  
  105.  
  106.      User Updater -- Universal                                                          3
  107.  
  108.  
  109.  
  110.       **** DISTRIBUTION
  111.  
  112.      U3 may be distributed by anyone as long as the files in the original
  113.      archive are intact. U3 may not be distributed as part of a commercial
  114.      product or by any means that implies that it is a registered (paid
  115.      for) copy without permission of the author.
  116.  
  117.      **** USER UPDATER -- UNIVERSAL IS SHAREWARE
  118.  
  119.      You may use User Updater to evaluate it for your needs. If you decide
  120.      it is useful to you, then you must register, otherwise you must
  121.      discontinue its use. Registration is an easily affordable $10. See the
  122.      file REGISTER.DOC for instructions.
  123.  
  124.      Registrations may not be transferred. They are are specific to a
  125.      single BBS name.
  126.  
  127.      Once registered the modest nag screen, beeps and delays will vanish.
  128.      However the unregistered program is fully functional.
  129.  
  130.      **** TRADEMARKS
  131.  
  132.      All product names mentioned in this document are trademarks of their
  133.      respective manufacturers.
  134.  
  135.  
  136.      User Updater -- Universal                                                          4
  137.  
  138.  
  139.  
  140.                          RUNNING USER UPDATER -- UNIVERSAL
  141.  
  142.      **** USERBASE MODE
  143.      To run U3 you need to create a command file telling U3 what it needs
  144.      to do.  The syntax for this file is described in the next section. 
  145.      For accessing the user base, you must have the environment variable RA
  146.      set to the directory containing the CONFIG.RA file, or else you must
  147.      run U3 from the directory containing CONFIG.RA.  Then run U3 from the
  148.      command line:
  149.  
  150.          u3 -d -f -s commandFile RegistrationNumber
  151.  
  152.      where:
  153.  
  154.      -d -f and -s are optional command switches.
  155.  
  156.                commandFile is the name (and path if not in the current directory) of
  157.           the U3 command file.
  158.  
  159.                RegistrationNumber is optional and is the number provided when you
  160.           register U3.  Until registered, U3 has an annoying delay which
  161.           can be bypassed only by hitting a key.  This allows U3 to be
  162.           fully tested but not be easily used in an automated environment.
  163.  
  164.      The registration number can also be placed as the single line in a
  165.      text file called U3.KEY, and placed in the current directory. This
  166.      eliminates the need to place the registration number on the command
  167.      line.
  168.  
  169.      The "-s" option causes U3 to skip all records for which the Deleted
  170.      flag is set. Otherwise deleted records are processed.
  171.  
  172.      If "-d" is used as the first argument, U3 runs in debug mode and will
  173.      not modify the userbase or run external programs.  Instead it displays
  174.      what it would have done if the -d option was not given.  If "-f" is
  175.      used, the userbase will not be modified, but all other actions occur.
  176.  
  177.      If no command line switches are used, U3 will not run if a copy of
  178.      RemoteAccess is running.  It is important that U3 only be used when
  179.      RemoteAccess is not running, such as during night-time maintenance. If
  180.      you are not interested in modifying the userbase, U3 can be run when
  181.      RemoteAccess is running by using the -f option.  When debug mode (the
  182.      -d option) is used, U3 will always run so that command files can be
  183.      tested without stopping RemoteAccess.
  184.  
  185.      You should always test U3 command files by using debug mode. Be
  186.      certain that U3 will do exactly what you want before removing the -d
  187.      option. You should also save a copy of USERS.BBS before testing U3. U3
  188.      is a very powerful program, and is very capable of totally mangling
  189.      your user base given the wrong commands!
  190.  
  191.      The first thing U3 will do is open the CONFIG.RA and USERS.BBS files. 
  192.      It will give an error message and quit if it cannot find either of
  193.  
  194.  
  195.      User Updater -- Universal                                                          5
  196.  
  197.  
  198.  
  199.       these files.  Then U3 will open and parse the command file.  If any
  200.      error is encountered, a message will be printed and execution will
  201.      stop. Only one error will be reported in any run. Errors during
  202.      parsing describe the error and the location in the command file where
  203.      the error was discovered.
  204.  
  205.      U3's print statements write to the display.  The output can be
  206.      directed to a file using DOS s output redirection.  For example:
  207.  
  208.          u3 u3cmd.txt c:\ra 12345 >u3out.txt
  209.  
  210.      will write the output to U3OUT.TXT.  You can then use a robotic mailer
  211.      to send the output to you as mail, or can use the output file in an
  212.      online bulletin.
  213.  
  214.      U3 can be invoked as many times as is desired, using different command
  215.      files each time.  This gives maximum flexibility.
  216.  
  217.      **** DOOR MODE
  218.  
  219.      U3 can also be used in Door Mode. In this case it is either invoked
  220.      from a type 7 menu item, or from a batch file run from a type 7 or 15
  221.      menu item.  To run U3 in Door Mode, and access the record of the
  222.      current user online, invoke U3:
  223.  
  224.          u3 -u -d -f commandFile
  225.  
  226.      The -d and -f are optional command flags, as described previously.
  227.  
  228.      U3 must be run in the directory containing the EXITINFO.BBS file. The
  229.      registration number is not necessary. There is no annoying nag screens
  230.      in Door Mode when not registered.  The user database is not touched,
  231.      so other lines of RemoteAccess can be running.  Changes made to the
  232.      exitinfo record are incorporated into the user record when
  233.      RemoteAccess is re-entered.  The EXITINFO.BBS file has more
  234.      information than the userbase record.  These additional fields can be
  235.      accessed and, with care, altered.  Operation in Door Mode is otherwise
  236.      identical with Userbase mode.
  237.  
  238.      See the end of this document for complete usage examples.
  239.  
  240.  
  241.      User Updater -- Universal                                                          6
  242.  
  243.  
  244.  
  245.                              USER UPDATER COMMAND FILE
  246.  
  247.      The command file is the heart of U3.  In it you describe the actions
  248.      you want U3 to perform.  The file is a standard ASCII text file you
  249.      can create with DOS s EDIT or EDLIN programs or any other editor which
  250.      will create text files (TED, QEDIT, Brief, Epsilon...).
  251.  
  252.      To make things easier, U3 ignores line breaks, has no limits on line
  253.      sizes, and ignores case.  You can put comments in the command file:
  254.      put a \ character in a line and everything to the right until the end
  255.      of the line will be ignored.
  256.  
  257.      The command file consists of one or more IF THEN commands, with the
  258.      format:
  259.  
  260.          IF expression THEN statements
  261.  
  262.      where
  263.  
  264.      expression is a logical expression (described later)
  265.  
  266.      and
  267.  
  268.                statements are one or more statements which are to be executed if the
  269.           expression has a non-zero ("true") value.
  270.  
  271.      There are five types of statements.  LET statements alter numeric and
  272.      date fields in the record, SET statements alter text fields in the
  273.      record, PRINT statements print data to the display or file, RUN
  274.      statements execute external programs, and RETURN statements set U3's
  275.      return code.
  276.  
  277.      Each user record is examined in turn, for each IF expression that is
  278.      true, the THEN statements are executed for that user record. Each IF
  279.      THEN command is independent -- whether or not an IF expression is
  280.      true, the following IF THEN command is executed. Commands and the
  281.      statements within are all executed sequentially. If a field is set by
  282.      a LET statement, the new field value will be used if later referenced
  283.      in the command file. Consider the following command file:
  284.  
  285.          IF level=10        \ A new caller
  286.          THEN
  287.             LET level = 20
  288.             LET D1 = 1
  289.             PRINT "New user ", name
  290.             RETURN 20
  291.          IF level=20 & today-lastdate > 30 & !nokill
  292.          THEN \ delete this caller
  293.             LET deleted = 1
  294.             PRINT "User ", name, " deleted"
  295.  
  296.      Each user record will be examined.  If the user security level is 10,
  297.      then the level will be changed to 20, the D1 flag set, and a
  298.  
  299.  
  300.      User Updater -- Universal                                                          7
  301.  
  302.  
  303.  
  304.       notification printed.  The return code will be 20 if there are any new
  305.      callers.  If the security level is 20 and the user hasn't called
  306.      within the past 30 days (difference between the today's date and the
  307.      last call date greater than 30), and the nokill flag is not set then
  308.      mark the user as deleted and print the message.
  309.  
  310.      Since the commands are executed sequentially, any user with security
  311.      level of 10 who hasn t called in thirty days will end up being
  312.      deleted.  Why? Because their level is raised to 20 by the first IF
  313.      THEN command, so the level is 20 in the IF expression of the second IF
  314.      THEN command. If this were a problem, the order of the two IF THEN
  315.      commands could be reversed. However in this particular example it is
  316.      unlikely that a new user would not have called in the last thirty
  317.      days.
  318.  
  319.      This example was formatted and capitalized to aid in reading, however
  320.      remember that the U3 program ignores line breaks and capitalization.
  321.  
  322.      **** OPPERANDS: FIELDS AND NUMBERS
  323.  
  324.      Numeric expressions consists of operators (such as add and subtract)
  325.      and opperands.  Opperands can either be the names of fields in the
  326.      userbase (or EXITINFO.BBS in Door mode), or numbers.
  327.  
  328.      A number is either an integer (examples: 0 123 6120) or a floating
  329.      point number (examples: 1.3  2.4 222.111). In addition, the name
  330.      "true" can be used in place of the value 1, and the name "false" can
  331.      be used in place of the value 0. These are particularly convenient
  332.      when dealing with flags.
  333.  
  334.      When a numeric field name is used in an expression, the value
  335.      contained in the user record being examined is used in the calculation
  336.      at that spot.  Numeric fields are of different sizes and types,
  337.      however all field contents are converted to floating point numbers for
  338.      calculations.
  339.  
  340.      Some fields are described as "calculated value." These are not real
  341.      fields in the record, but are values calculated from fields or outside
  342.      information (such as today s date).
  343.  
  344.      Valid numeric fields are (those marked with "+" are for Door Mode
  345.      only):
  346.  
  347.      ** dates:
  348.      birthdate -- date of birth
  349.      firstdate -- date of first call
  350.      lastdate -- date of last call
  351.      subdate -- subscription date
  352.      today -- today s date (calculated value, not in userbase!)
  353.  
  354.      ** flags: value 1 if true, 0 if false
  355.      hasalias -- alias and name fields are the same (calculated value)
  356.      deleted -- deleted flag
  357.  
  358.  
  359.      User Updater -- Universal                                                          8
  360.  
  361.  
  362.  
  363.       cls -- clear screen flag
  364.      more -- more prompt flag
  365.      ansi -- ANSI mode flag
  366.      nokill -- no-kill flag
  367.      xfer -- xfer priority flag
  368.      fsedit -- full screen editor flag
  369.      quiet -- quiet mode flag
  370.      hotkeys -- hotkeys flag
  371.      avt0 -- avt/0 emulation flag
  372.      fsmsg -- full screen message viewer flag
  373.      hidden -- hidden from userlist flag
  374.      page -- page priority flag
  375.      noecho -- no echomail in mailbox scan flag
  376.      mbcheck -- selected areas mail check flag (RA 2.5x only) 
  377.      guest -- guest account flag
  378.      postbill -- post bill enabled flag
  379.      a1, a2, a3, a4, a5, a6, a7, a8,
  380.      b1, b2, b3, b4, b5, b6, b7, b8,
  381.      c1, c2, c3, c4, c5, c6, c7, c8,
  382.      d1, d2, d3, d4, d5, d6, d7, d8 -- user flags
  383.  
  384.                ** Integers (these have values in range roughly +/- 2,000,000,000)
  385.      credit -- credits
  386.      pending -- pending charges
  387.      numcalls -- number of calls
  388.      uploads -- number of uploads
  389.      downloads -- number of downloads
  390.      uploadk -- kilobytes of uploads
  391.      downloadk -- kilobytes of downloads
  392.      todayk -- kilobytes of downloads today
  393.  
  394.      ** Integers (these have signed values -32768 to 32767)
  395.                elapsed -- elapsed time today (negative times are possible when time
  396.           banks are used)
  397.      + deductedtime -- (don't know what this field does)
  398.  
  399.      ** Integers (these have non-negative values 0 to 65535)
  400.                age -- caller's age (calculated value, if birthdate field is empty,
  401.           the age is returned as 0)
  402.      record -- record number (calculated value)
  403.      msgpost -- number of messages posted
  404.      level -- security level
  405.      length -- screen length
  406.      group -- group member (0 if not used)
  407.      + baud -- login speed, 0 for local
  408.                + timelimit -- number of remaining minutes for this call
  409.      + pages -- number of paging attempts for this call
  410.      + dlimit -- download limit for this call
  411.  
  412.      ** Integers (these have non-negative values 0 to 255)
  413.                pwdchange -- calls since last password change.  This value rolls over
  414.           from 255 to 0 so is not accurate unless password changing is
  415.           enforced.
  416.  
  417.  
  418.      User Updater -- Universal                                                          9
  419.  
  420.  
  421.  
  422.                 dobcheck -- calls since last date of birth check.  This value rolls
  423.           over from 255 to 0 so is not accurate unless checking is
  424.           enforced.
  425.      language -- language number selected (0 if not used)
  426.                dateformat -- selected date format: 1- DD-MM-YY, 2- MM-DD-YY, 3- YY-
  427.           MM-DD, 4- DD-Mmm-YY.
  428.      sex -- sex: 0-unknown, 1-male, 2-female
  429.                protocol -- default download protocol (ASCII character value, 0 means
  430.           not specified)
  431.                + netmail -- 0-no outgoing netmail, 1-outgoing netmail
  432.                + echomail -- 0-no outgoing echomail, 1-outgoing echomail
  433.      + wantchat -- 0-doesn't want to chat, 1-wants to chat
  434.      + errorfree -- 0-no REQ or ARQ, 1- error correcting connect
  435.      + sysopnext -- 0-not set, 1-sysop on next (ALT-N from console)
  436.      + emsi -- 0-normal session, 1-IEMSI session
  437.      + doesavt -- 0-doesn't do AVATAR, 1-does AVATAR
  438.      + ripmode -- 0-doesn't do RIP, 1-does RIP
  439.      + ripversion -- RIP Version (RA 2.5x only)
  440.  
  441.      Note that all dates are treated as integer values and are the number
  442.      of days since February 28, 1900.  Dates of January and February 1900
  443.      are not allowed and are treated as March 1, 1900.  If a date field is
  444.      blank, the value 0 is supplied. RemoteAccess 2.x has a date handling
  445.      problem in that it encodes the year as the final two digits. To handle
  446.      dates after December 31, 1999, after that date U3 will assume that
  447.      years greater than the current year are 19xx while other years are in
  448.      the current century (20xx). Since no dates after the current date are
  449.      valid, this technique should keep U3 (and maybe RemoteAccess as well)
  450.      functioning far into the future.
  451.  
  452.      In addition there are 10 global integer fields, which can hold values
  453.      in range +/- 2,000,000,000 named u1, u2, ..., u10.  These fields are
  454.      not associated with a particular user record, and can be used to
  455.      accumulate totals, count users, or as general temporary storage
  456.      locations.  The global fields initially have the value 0.
  457.  
  458.      **** EXPRESSIONS
  459.  
  460.      Expressions are traditional mathematical expressions.  Standard order
  461.      of precedence rules are followed.  I.E. multiplication is performed
  462.      before addition in the expression 2+3*5.  Otherwise execution proceeds
  463.      from left to right.  Operators in decreasing precedence order are:
  464.  
  465.      -    Unary minus (negate)
  466.      + -  Addition and Subtraction
  467.      * /  Multiplication, division
  468.                = != < <= > >= Equal, not equal, less, less or equal, greater, greater
  469.           or equal. Return a "true" value one or "false" value zero.
  470.                !    Not (logical complement-- nonzero or true values become zero or
  471.           false, and visa versa)
  472.      &    And (value true if both arguments true or non-zero)
  473.      |    Or (value true if either argument true or non-zero)
  474.  
  475.  
  476.      User Updater -- Universal                                                         10
  477.  
  478.  
  479.  
  480.       In the expression 2+3*5, the multiplication is done before the
  481.      addition because multiplication has higher precedence.  Parentheses
  482.      can be used to change the order of evaluation.  For instance (2+3)*5
  483.      will do the addition first.  All calculations are done in floating
  484.      point with 15 digits precision.
  485.  
  486.      Note that the expression age>=18 will be true if the age of the caller
  487.      is greater than or equal to 18. However 30>=age>=18 will not return
  488.      true for ages between 18 and 30. This must be done with two
  489.      comparisons and the "and" operator: 30>=age&age>=18. The order of
  490.      precedence has the comparisons done before the and operator, so no
  491.      parenthesis are necessary.
  492.  
  493.      Most expressions will be simple comparisons, or multiple comparisons
  494.      connected with the and operator. In this case, all the comparisons
  495.      must be true for the expression to be true. For example the expression
  496.      age>16 & !nokill & level=30  will be true only if all of the following
  497.      are true: age greater than 16, nokill flag *not* true, and security
  498.      level equal to 30.
  499.  
  500.  
  501.      **** LET STATEMENT
  502.  
  503.      The LET statement is used to assign new values to most numeric and
  504.      date fields.  The syntax is:
  505.  
  506.          LET field = expression
  507.  
  508.      where field is a valid assignment field and expression is any valid
  509.      expression.  If the field is a flag, then any nonzero expression value
  510.      is considered to be TRUE, while a zero value is considered to be
  511.      FALSE. For integer fields, the expression value, calculated in
  512.      floating point, is converted to the next lower integer value. For
  513.      instance, 5/2 would be stored as 2.
  514.  
  515.      All fields listed above, except for "record", "today", "hasalias", and
  516.      "age" are valid for assignments, however most of them probably should
  517.      not be used for assignments.  Use this statement with caution! When
  518.      assigning to date fields, the value assigned should be a date (e.g.
  519.      "LET subdate=today") and never a date in the future (because of the
  520.      centure checking).  Be careful not to assign invalid values as no
  521.      checking is performed. This includes storing a negative value in a
  522.      field which only holds non-negative values.
  523.  
  524.      **** PRINT STATEMENT
  525.  
  526.      The print statement prints to the display or to a file if output is
  527.      redirected, as described earlier.  The syntax is:
  528.  
  529.           PRINT printExpressions
  530.  
  531.      where printExpressions are expressions, quoted text, or text field
  532.      names. All printExpressions must be separated by commas.
  533.  
  534.  
  535.      User Updater -- Universal                                                         11
  536.  
  537.  
  538.  
  539.       Each print statement prints a single line of data.  Numeric
  540.      expressions print as integers.  Literal text can be printed by
  541.      enclosing it in quotes (e.g. "a string").  To print a quote character,
  542.      use two adjacent quote characters (e.g. " "" " will print as a space-
  543.      quote-space sequence). Tabs and control characters are valid in
  544.      literal text, making it possible to include ANSI color control
  545.      sequences for fancy reports. To allow the use of editors which don't
  546.      allow inserting control codes, they can be represented by the tilde
  547.      "~" character followed by @, A through Z, [, \, ], ^, or _, to
  548.      generate the appropriate character. For this reason, the tilde
  549.      character itself must be represented by two adjacent tilde characters
  550.      "~~".
  551.  
  552.      Text fields in the userbase can be printed as follows (those marked
  553.      with "+" are available in Door Mode only):
  554.  
  555.      name -- user name
  556.      location -- location
  557.      organization -- organization (field not used in RemoteAccess)
  558.      address1 -- address1
  559.      address2 -- address2
  560.      address3 -- address3
  561.      handle -- handle
  562.      comment -- comment
  563.      dataphone -- data phone
  564.      voicephone -- voice phone
  565.      forwardto -- name to forward mail to
  566.      + emsicrt -- IEMSI CRT field
  567.      + emsiproto -- IEMSI PROTOCOL field
  568.      + emsiable -- IEMSI CAPABILITIES field
  569.      + emsireq -- IEMSI REQUEST field
  570.      + emsisoft -- IEMSI SOFTWARE field
  571.      + pagereason -- paging reason
  572.  
  573.      There is some control possible over formatting.  To print a numeric
  574.      value as a date, follow the expression with ":d".  If the date value
  575.      is 0 (meaning "not set"), the date printed will be "  -  -  ".  
  576.  
  577.      To specify a fixed number of columns for a field, follow the
  578.      expression with ":n" where n is an integer specifying the number of
  579.      columns. Text fields will be left justified and truncated if
  580.      necessary, while numeric fields will be right justified and are never
  581.      truncated if the specified field length is too short.
  582.  
  583.      For instance:
  584.  
  585.       PRINT "Name birthdate, and age:",name:20,"  ",birthdate:d, age:3
  586.  
  587.      Will print the text "Name and age:" (without the quotes), the first 20
  588.      characters in the name, padded if necessary on the right with spaces,
  589.      two spaces, the birthdate of the caller, and the age in years of the
  590.      caller right justified in a 3 column field.
  591.  
  592.  
  593.      User Updater -- Universal                                                         12
  594.  
  595.  
  596.  
  597.       The length of the line printed is limited to about 250 characters,
  598.      including any embedded control characters.
  599.  
  600.      You can print a blank line with the statement:
  601.  
  602.          PRINT ""
  603.  
  604.  
  605.      **** SET STATEMENT
  606.  
  607.      The SET statement is used to assign values to text fields.
  608.  
  609.      The syntax of the set statement is:
  610.  
  611.          SET textField = printExpressions
  612.  
  613.      where textField is a text field name listed under the PRINT statement,
  614.      and printExpressions are expressions, quoted text, and text field
  615.      names separated by commas, as described under the PRINT statement.
  616.  
  617.      For example, the handle can be set to the callers real name with the
  618.      statement:
  619.  
  620.          SET handle = name
  621.  
  622.      If the printExpressions would create text which would not fit in the
  623.      field, the text is truncated (from the right) to fit.
  624.  
  625.      **** RUN STATEMENT
  626.  
  627.      The RUN statement works just like the print statement, except the
  628.      generated line of text is used as a command line.  The line to be
  629.      executed may not be more than 124 characters long.  For instance, a
  630.      message can be sent to the user using mbutil (part of GEcho mail
  631.      tosser) with:
  632.  
  633.       RUN "mbutil msg.txt #1 -To """, name, """ -Subject Welcome -Pvt"
  634.  
  635.      For the user Joe Blow, this would run the command:
  636.  
  637.          mbutil msg.txt #1 -To "Joe Blow" -Subject Welcome -Pvt
  638.  
  639.      The RUN command uses Ralf Brown's SPAWNO library so that U3 is swapped
  640.      out of low memory to run the program.  U3 will swap out to XMS if
  641.      available, else EMS.  If neither is available, U3 will swap to disk.  
  642.  
  643.      U3 uses the command interpreter (usually COMMAND.COM) in the RUN
  644.      command, so the user path is searched and batch programs (BAT
  645.      extensions) are allowed.  Users of JP Software's 4DOS can run BTM
  646.      files and aliases as well.  However if the program to run is an EXE or
  647.      COM file, and the full path and filename is specified, then the
  648.      program will be run directly without starting a command interpreter. 
  649.      This is faster, and conserves memory.  For instance:
  650.  
  651.  
  652.      User Updater -- Universal                                                         13
  653.  
  654.  
  655.  
  656.           RUN "foo bar"
  657.  
  658.      will run program foo, which can be an EXE, COM, or BAT file located
  659.      anywhere in the search path.  A copy of the command interpreter will
  660.      be started to run the program.  The statement:
  661.  
  662.          RUN "\xyz\foo bar"
  663.  
  664.      will run program foo, which can be an EXE, COM or BAT file, but must
  665.      be in directory \xyz\.  A copy of the command interpreter will be
  666.      started to run the program.  On the other hand:
  667.  
  668.          RUN "\xyz\foo.exe bar"
  669.  
  670.      will run program foo.exe in directory \xyz\ without starting a command
  671.      interpreter.
  672.  
  673.      **** RETURN STATEMENT
  674.  
  675.      The syntax of the RETURN statement is:
  676.  
  677.          RETURN expression
  678.  
  679.      where expression is any valid expression.
  680.  
  681.      The return statement sets the return error level of U3 to the value of
  682.      thee expression. The last RETURN statement executed determines the
  683.      value used. The return level cannot be less than 0 or greater than
  684.      255. If no RETURN statement is executed, then the level 0 is returned.
  685.      If an error occurs while running U3, the level 1 is returned. The
  686.      error level can be examined in a DOS batch file by using the IF
  687.      ERRORLEVEL statements. If you use 4DOS, you can examine, print, or
  688.      even evaluate expressions based on the level.
  689.  
  690.      **** THE OPTIONAL "FINALLY" COMMAND
  691.  
  692.      At the end of the IF THEN commands which are executed for every user
  693.      record there can be a single FINALLY followed by more IF commands. 
  694.      These final IF THEN commands are executed after all user records are
  695.      processed.  No record fields can be accessed, only the global fields
  696.      U1 through U10.  This feature is typically used to print accumulated
  697.      results.  Consider this command file that calculates the average age
  698.      of callers in security level 20:
  699.  
  700.        IF AGE > 0 & LEVEL = 20 \ if age is zero, birthdate is unknown!
  701.        THEN
  702.          LET U1 = U1 + AGE     \ sum of ages in U1
  703.          LET U2 = U2 + 1       \ number of users in U2
  704.        FINALLY \ calculate this at the end
  705.        IF U2 > 0               \ must be at least one to average
  706.        THEN
  707.          PRINT "Average age is ", U1/U2
  708.  
  709.  
  710.      User Updater -- Universal                                                         14
  711.  
  712.  
  713.  
  714.       The sum of the ages is stored in global field U1 and the number of
  715.      users in global field U2.  After all records are examined, the average
  716.      age, U1/U2, is printed.
  717.  
  718.      An enhanced version of this command file which generates a ANSI color
  719.      bulletin is shown later in the EXAMPLES OF USE section.
  720.  
  721.  
  722.      User Updater -- Universal                                                         15
  723.  
  724.  
  725.  
  726.                                   ERROR MESSAGES
  727.  
  728.      U3 can generate the following error messages. The first error will
  729.      cause the program to terminate, returning an error level 1.
  730.  
  731.      "could not access EXITINFO.BBS" -- In Door Mode, the EXITINFO.BBS file
  732.      must be in the current directory.
  733.  
  734.      "could not access CONFIG.RA" -- The RA environment variable must be
  735.      set to the directory containing CONFIG.RA, or CONFIG.RA must be in the
  736.      current directory.
  737.  
  738.      "could not read CONFIG.RA" -- This error can occur if another program
  739.      is accessing the configuration file and has it locked.
  740.  
  741.      "could not access USERS.BBS" -- This error can occur if another
  742.      program is accessing the userbase, such as a running copy of
  743.      RemoteAccess. You might want to try the -f command option.
  744.  
  745.      "could not open command file" -- The command file could not be found.
  746.  
  747.      "insufficient memory for code array" -- Not enough memory to run U3.
  748.      U3 needs about 150k bytes to run.
  749.  
  750.      "defective EXITINFO.BBS" -- in Door Mode, there was something funny
  751.      about the EXITINFO.BBS file.
  752.  
  753.      "strange symbol reference" -- program bug, please send command file to
  754.      U3 author!
  755.  
  756.      "WARNING: Attempted record write denied" -- when using the -f command
  757.      option, a LET or SET statement was encountered that attempted to
  758.      modify the record. This warning message does not abort execution, but
  759.      simply leaves the record unaltered.
  760.  
  761.      The following are FATAL COMPILATION ERRORS. These are generated
  762.      because of errors in the command file. The error message will indicate
  763.      the line number and column where the error was discovered.
  764.  
  765.      "text string not terminated before end of line" -- text strings cannot
  766.      wrap around line boundaries. The command file is probably missing a
  767.      closing quote.
  768.  
  769.      "unrecognized control character" -- only carriage return, line feed,
  770.      and tab control (non printing) characters are allowed in commands.
  771.  
  772.      "text string too long" -- text strings cannot be longer than 127
  773.      characters.
  774.  
  775.      "invalid number format" -- numbers must only consist of digits 0
  776.      through 9, and an optional single decimal point.
  777.  
  778.  
  779.      User Updater -- Universal                                                         16
  780.  
  781.  
  782.  
  783.       "unidentified symbol name" -- the indicated keyword or field name is
  784.      either mis-spelled or not allowed (non-global field names after the
  785.      FINALLY keyword, or Door Mode fields when not in Door Mode).
  786.  
  787.      "U3 command file too big" -- the command file, when encoded, must be
  788.      less than 10,000 bytes. This command file is too big. More likely than
  789.      not the problem is too much text. If this is a problem, notify the
  790.      author, who can increase this size in future versions.
  791.  
  792.      "right parenthesis expected" -- an expression is missing a closing
  793.      right parenthesis.
  794.  
  795.      "expression cannot involve text field" -- only numeric values can be
  796.      used in expressions.
  797.  
  798.      "field name expected" -- something other than a valid field name was
  799.      found where a field name was expected.
  800.  
  801.      "expression too complex" -- you need to simplify this expression.
  802.      Expressions can only have 31 simultaneous subexpression results during
  803.      a calculation. This is actually a very large number. Try rearranging
  804.      the expression so execution can proceed left to right.
  805.  
  806.      "text field name required" -- in SET statement. You probably want the
  807.      LET statement.
  808.  
  809.      ""=" expected" -- in SET or LET statement, you need an "=".
  810.  
  811.      "integer constant expected" -- field sizes must be integer constants.
  812.  
  813.      "constant too large" -- field sizes must not be bigger than 254.
  814.  
  815.      "assignable field name required" -- in LET statement, field name give
  816.      was not assignable (such as "age" or a text field).
  817.  
  818.      "THEN expected" -- the keyword THEN must be used after the IF
  819.      expression but before the LET, SET, RUN, PRINT, or RETURN statements.
  820.  
  821.      "unexpected token" -- catch-all error. U3 expected a possible end of
  822.      command file, but there was more in the file. Common causes are a
  823.      missing commas or keywords (LET, SET, RUN, PRINT, RETURN).
  824.  
  825.  
  826.      User Updater -- Universal                                                         17
  827.  
  828.  
  829.  
  830.                                   EXAMPLES OF USE
  831.  
  832.      This section describes a number of U3 command files, showing a variety
  833.      of functions that can be performed.
  834.  
  835.  
  836.      **** RESET A FLAG
  837.  
  838.      The first example uses U3 to reset a flag. It represents a "quicky"
  839.      command file that might be written and used once to handle a one-time
  840.      maintenance task:
  841.  
  842.        if true then let a1=false
  843.  
  844.      That's it. Since "true" is always true, flag a1 gets reset for all
  845.      users. If you want to know which users you have reset the flags for,
  846.      you can use a slightly longer "quicky" command file:
  847.  
  848.        if a1 then 
  849.          let a1 = false
  850.          print Name
  851.  
  852.      This will reset the flag for any user whose flag is set, and will
  853.      print out their names.
  854.  
  855.      **** DELETING NON-VERIFIED CALLERS
  856.  
  857.      This second example could be used for nightly maintenance:
  858.  
  859.        \ Delete non-verified callers who haven't called in 5 days
  860.        if level = 10 & today-lastdate > 5 
  861.        then
  862.          let deleted = true
  863.          print name, "is deleted, not verified"
  864.  
  865.      It will delete any user with security level 10 who hasn't called in 5
  866.      days. You will need to use the RAUSER program to actually purge the
  867.      "deleted" user record. Of course, RAUSER will delete users based on
  868.      number of days since last call, but it won't do it for specific
  869.      security levels (just those less than a specified value). Also, this
  870.      example will delete users who have the NOKILL flag set!
  871.  
  872.      If you didn't want to delete users who have NOKILL set, and also
  873.      didn't want to delete already deleted users, the first line could be
  874.      changed to:
  875.  
  876.          if !deleted & !nokill & level = 10 &  today - lastdate > 5
  877.  
  878.      Of course, you can also use the -s command line flag to eliminate the
  879.      need to explicitly check that the record has not been deleted.
  880.  
  881.  
  882.      User Updater -- Universal                                                         18
  883.  
  884.  
  885.  
  886.       **** UNDELETING USERS
  887.  
  888.      Ops! Deleted a bunch of users by accident? This short command file
  889.      will undelete any deleted records, and tell you to whom they belong.
  890.      Don t use the -s command line flag with this -- it won t work!
  891.  
  892.          if deleted 
  893.          then 
  894.              let deleted = false
  895.              print name, " restored!"
  896.  
  897.      **** RAISING LEVELS AND POSTING MESSAGES
  898.  
  899.      This third example raises a user's level and sends a message if a flag
  900.      has been set.  This example and further examples assume the use of
  901.      MBUTIL as the robotic mailer.  MBUTIL is part of the GEcho mail tosser
  902.      program.  However robotic mailers could be used.
  903.  
  904.  
  905.          \ raise level from 20 to 21 if c8 flag set, and send message       
  906.          \ to user about the change
  907.          if level=20 & c8
  908.          then 
  909.            let level=21
  910.            print name, "has been verified"
  911.            run "mbutil Post verified.txt #1 -To """, name, 
  912.                """ -subject Welcome -pvt"
  913.  
  914.      **** LOW CREDITS WARNING
  915.  
  916.      This fourth example sends a warning message when credits drop below a
  917.      certain amount (100 in this case). A flag is used to determine if the
  918.      message has been sent. The flag is reset when credits are restored.
  919.  
  920.          \ For registered users (level 30), send a message if 
  921.          \ credits have dropped below 100
  922.          if level = 30 & !c1 & credit - pending < 100
  923.          then
  924.            let c1 = true
  925.            run "mbutil Post locredit.txt #1 -To """, name, 
  926.                """ -subject Notification -pvt"
  927.          \ Reset flag c1 when credits are again above 100
  928.          if level = 30 & c1 & credit-pending > 100
  929.          then 
  930.            let c1 = false
  931.  
  932.  
  933.      User Updater -- Universal                                                         19
  934.  
  935.  
  936.  
  937.       **** LIST AND TALLY TERMINAL EMULATIONS
  938.  
  939.      This command file will list which terminal emulation a caller uses. 
  940.      The choices are AVATAR, ANSI, or ASCII. The user database is not
  941.      modified.  It will print the total number of users with each setting.
  942.  
  943.          if avt0 \ avatar flag set
  944.          then 
  945.            print name, " uses AVATAR"
  946.            let u1 = u1 + 1    \ count AVATAR users
  947.          if ansi & !avt0 \ ansi flag set, but avatar not set
  948.          then 
  949.            print name, " uses ANSI"
  950.            let u2 = u2 + 1    \ count ANSI users
  951.          if !(ansi | avt0) \ neither ansi or avatar flag set
  952.          then 
  953.            print name, " uses ASCII"
  954.            let u3 = u3 + 1    \ count ASCII users
  955.          finally \ print totals at end
  956.          if u1 > 0 then print u1, " AVATAR users"
  957.          if u2 > 0 then print u2, " ANSI users"
  958.          if u3 > 0 then print u3, " ASCII users"
  959.  
  960.      **** NOTIFY XMODEM USERS
  961.  
  962.      Would you rather see your callers using ZMODEM protocol rather than
  963.      XMODEM protocol?  This command file will send messages to users who
  964.      use XMODEM!
  965.  
  966.          \ Send a message to all people using Xmodem protocol
  967.          if protocol = 88 then 
  968.            run "mbutil Post xmodem.txt #1 -To """, name, 
  969.            """ -subject ""XMODEM Usage"" -pvt"
  970.  
  971.      The value 88 is the character "X", so when the default (last used)
  972.      protocol was XMODEM, the robot mailer is called to send a friendly
  973.      suggestion.
  974.  
  975.      **** POSTS PER MONTH RATIO LIST
  976.  
  977.      Lots of programs will show you the posts per call ratio. Would you
  978.      rather know the posts per month ratio?  This command file will do it,
  979.      and won't list callers who have posted fewer than five messages (a
  980.      single post of a first time caller is 30 posts per month!)
  981.  
  982.          if msgpost > 5 then
  983.            print name:20 , msgpost/((today-firstdate)/30) : 5
  984.  
  985.      Do you want to see the list sorted? That's easy! Use the sort
  986.      program that comes with DOS:
  987.  
  988.          u3 postmnth.dat | sort /+21 /r
  989.  
  990.  
  991.      User Updater -- Universal                                                         20
  992.  
  993.  
  994.  
  995.       If you have a DOS version of the Unix (TM Bell Labs) program "tail"
  996.      you can extract the top N callers, and make a custom Top N Caller
  997.      list.
  998.  
  999.      **** POST PER DOWNLOAD RATIO DOOR
  1000.  
  1001.      This command file is intended for use in Door Mode, to be executed
  1002.      automatically at the start of a BBS call. It checks the messages
  1003.      posted vs number of files downloaded and set flag A4 if there are more
  1004.      messages posted than files downloaded. This flag can then be used to
  1005.      control access to file areas. U3 can be run as a type 7 menu item.
  1006.  
  1007.          if msgpost >= downloads \ set flag if good user
  1008.          then
  1009.            let a4 = true
  1010.          if msgpost < downloads  \ reset flag if bad user
  1011.          then
  1012.            let a4 = false
  1013.  
  1014.      the same two commands could be made part of a nightly maintenance run
  1015.      of U3 if it was desirable to alter the flag once per day rather than
  1016.      on each call.
  1017.  
  1018.  
  1019.      **** TIME PURCHASE DOOR
  1020.  
  1021.      This command file is for use in Door Mode, only. It will charge the
  1022.      caller 10 credits and in return add 10 minutes of access time during
  1023.      the current day.
  1024.  
  1025.          if credit >= 10 \ must be some credits to spend
  1026.          then
  1027.            let credit = credit - 10
  1028.            let timelimit = timelimit + 10
  1029.            let elapsed = elapsed - 10
  1030.  
  1031.      If some people are allowed credit balances (postbill flag set), then
  1032.      this command file should be modified to allow those people to borrow:
  1033.  
  1034.          if credit >= 10 | postbill 
  1035.          then
  1036.            let credit = credit - 10
  1037.            let timelimit = timelimit + 10
  1038.            let elapsed = elapsed - 10
  1039.  
  1040.  
  1041.      **** GENDER BASED DOOR
  1042.                 
  1043.      Assume a game that has both male and female modes of operation.
  1044.      RemoteAccess  provides no way of running alternate programs depending
  1045.      on gender. The problem is solved with this command file:
  1046.  
  1047.          if sex = 2 then return 2 \ caller is female
  1048.  
  1049.  
  1050.      User Updater -- Universal                                                         21
  1051.  
  1052.  
  1053.  
  1054.       The game is run from this type 7 menu item batch file:
  1055.  
  1056.          u3 -u gender.dat
  1057.          if errorlevel 2 goto female
  1058.          game  -Male
  1059.          goto end
  1060.          :female
  1061.          game  -Female
  1062.          :end
  1063.  
  1064.  
  1065.      **** A SIMPLE BULLETIN
  1066.  
  1067.      This command file will generate a simple ANSI bulletin showing all
  1068.      callers and their ages. It illustrates how to embed ANSI control codes
  1069.      and how to make a bulletin head and tail (within U3). 
  1070.  
  1071.          if u1 = 0 \ Initially u1 is 0, so we will print the head
  1072.          then
  1073.            print "   ~[[1mCALLERS AND THEIR AGES~[[0m"
  1074.            print "Name                    Age"
  1075.          if !deleted \ Only consider non-deleted records
  1076.          then        \ (we can also use -s on the command line)
  1077.            let u1 = u1 + 1
  1078.            let u2 = u2 + age
  1079.            print "~[[32;1m", name:25, "~[[33m", age, "~[[0m"
  1080.          finally     \ when finished, print average age
  1081.          if u1 > 0 then
  1082.            print ""  \ empty string prints blank line
  1083.            print ""
  1084.            print "The average age is ~[[1m", u2/u1, "~[[0m"
  1085.  
  1086.  
  1087.      **** NIGHTLY MAINTENANCE AT BITTER BUTTER BETTER BBS
  1088.  
  1089.      Finally, here is the command file I use for nightly maintenance:
  1090.  
  1091.          if !nokill & ((level < 20 & today-lastdate > 3) |
  1092.            (level < 30 & today-lastdate > 90) |
  1093.            (level < 35 & today-lastdate > 120))
  1094.          then 
  1095.            let deleted = true
  1096.            print "User ", name, ", level ", level, 
  1097.                  ", deleted -- no usage"
  1098.          if !deleted & !nokill & today-lastdate > 30 & 
  1099.             numcalls = 1 & downloads = 0 & msgpost = 0
  1100.          then 
  1101.            let deleted = true
  1102.            print "User ", name, 
  1103.                  " no posts/secondcall/downloads in 30 days"
  1104.          if !deleted & level > 10 & b1=false 
  1105.          then
  1106.            let b1 = true
  1107.  
  1108.  
  1109.      User Updater -- Universal                                                         22
  1110.  
  1111.  
  1112.  
  1113.             print "User ", name, " Scrabble upgraded"
  1114.  
  1115.  
  1116.      User Updater -- Universal                                                         23
  1117.  
  1118.  
  1119.  
  1120.                                   TECHNICAL NOTES
  1121.  
  1122.      I'm always curious about such things, so I'm providing a short
  1123.      technical description of the insides of U3.  U3 is written in C, and
  1124.      compiled with the Borland C++ V4.02 compiler.  The executable program
  1125.      was compacted using Fabrice Bellard's LZEXE.  As mentioned before, U3
  1126.      uses the Ralf Brown's SPAWNO package to swap out of memory in the RUN
  1127.      command.
  1128.  
  1129.      For several years I have done userbase management with C programs that
  1130.      read the userbase, modify the fields as needed, and then write out the
  1131.      changes.  I've also written several programs to obtain statistics of
  1132.      users.  All of these programs are identical in structure.  Of course,
  1133.      each time I wanted to make a change, I had to modify the source and
  1134.      recompile.  I thought, "what if the portion of these programs that
  1135.      differed were separated out and interpreted?  Then the programs would
  1136.      be simpler and easier to maintain." So I proceeded to write U3.
  1137.  
  1138.      If U3 interpreted the command file with each record, performance would
  1139.      be hurt for large user bases.  Indeed, I wanted U3 to run quickly!  So
  1140.      I decided to compile the command file into a "byte code" program that
  1141.      would executed by a runtime byte code interpreter.  This had the added
  1142.      advantage that all syntax errors would be discovered before processing
  1143.      any of the records, rather than taking the risk that an error would
  1144.      not be discovered until the faulty statement was executed.
  1145.  
  1146.      U3 first opens all the files to make certain they are available. Then
  1147.      it compiles the command file.  The compiler is a traditional
  1148.      "recursive descent" design, which is more compact and easier to debug
  1149.      than the more recent table driven techniques.  The compiler was
  1150.      designed to be robust, and to abort on the first error.  While
  1151.      programmers generally prefer to see all error messages at once, most
  1152.      compilers will generate many error message for a single problem,
  1153.      making debugging difficult and discouraging for novices.
  1154.  
  1155.      If the command file compiles without error, records are read one at a
  1156.      time, the interpreter is run to process the record, and, if the record
  1157.      was changed (LET or SET statement executed), the record is written
  1158.      back to the file.  The interpreter implements a "virtual stack
  1159.      machine" which executes 29 different instructions. No attempt was made
  1160.      to make it general; the instruction set was tailored to the
  1161.      application.  Actual referencing of the userbase record is done via
  1162.      table lookup, which will make U3 easy to modify for future version of
  1163.      RemoteAccess.
  1164.  
  1165.  
  1166.      User Updater -- Universal                                                         24
  1167.  
  1168.  
  1169.  
  1170.                         OTHER UTILITIES BY THE AUTHOR OF U3
  1171.  
  1172.                ECHOREPT -- GEcho report generator (freeware, with sources)
  1173.                PROCESSI -- Updates download counts in RA 2.0x from
  1174.           FrontDoor/InterMail FREQs (freeware with source)
  1175.      PPNL10 -- Pretty Print Fidonet nodelists (freeware with source)                                                                   
  1176.                NNANS593 -- NNANSI ANSI.SYS fast/powerful replacement (shareware with
  1177.           source, free non-commercial use)
  1178.      KBDR.COM -- Makes caps lock key a control key (freeware)
  1179.      RESTART -- system configuration manager (freeware with source)
  1180.                RUNIT10 -- Program to spawn DOS VDM's from other DOS VDM's (for OS/2
  1181.           2.0 or later) (Freeware)
  1182.                ALMYUTIL -- text utilities to add/remove tabs and leading spaces from
  1183.           text files.  Also splits large files into smaller files. 
  1184.           (freeware)
  1185.      JUSTFY14 -- reformats text files (freeware with source)
  1186.                REANSI13 -- convert among ANSI/Graphic, Avatar0+, RemoteAccess,
  1187.           Renegade, Wildcat codes, and plain ASCII. Superset uf UNANSI
  1188.           (freeware with source)
  1189.      UNANSI12 -- convert ANSI to vanilla ASCII (freeware with source)
  1190.                UNHTML10 -- removes HTML or CGML markup from text files (freeware with
  1191.           source)
  1192.  
  1193.      Programs are available from my Internet Web site,
  1194.      http://www.teleport.com/~almy, or via FTP at
  1195.      ftp.teleport.com/vendors/almy.