Author:  Daniel.Stenberg <Daniel.Stenberg@sth.frontec.se>
Date:    1997-11-04
Version: 1.1

                        #############################
                        -=*( Using FPL in Dancer )*=-
                        #############################

    Introduction
    Setup
    Hooks
    FPL Programs
    Adding New Commands
    Adding New User Info
    Timed Events
    Built-in Function

                                 Introduction
                                 ============

 FPL is a full language interpreter. C syntax, C keywords and C expressions.
Only minor incompatibilities.

 It offers a complete setup of basic functions like strcmp(), atoi(),
sprintf(), sscanf() and more.

 For detailed language documentation, read http://www.fts.frontec.se/~dast/fpl

 This document is only targeted to Dancer specific information. All general
FPL information is left out and should be looked for elsewhere.

                                    Setup
                                    =====

File Name
---------
 The name of the file that should contain all FPL setup items, is defined by
the 'initfpl' field of the dancer.config file. The default name of the file is
'dancer.fplconf'.

File Format
------------
 The FPL setup file is contructed by lines using the following format (lines
starting with the letter '#' are treated as comments):

[+]<hook>: "<regex>" <FPL>

 Where the different data fields mean:

[+]     - Optional starting '+' letter, that if present, makes this into a
          "post hook". See the chapter about "Hooks" for details.
<hook>  - The name of the hook this concerns.
<regex> - A full blown extended regular expression. If this is left empty (""),
          it will match everything.
<FPL>   - A correct FPL program using appropriate syntax. Certain %-codes are
          supported and will be expanded before this program is run.
                 %-codes available include:
                 i - content sensitive input string (see the hook list for info)
                 n - nick name of the bot
                 u - nick name of the "current user"
                 c - name of the channel
                 t - time(NULL) integer
                 (suggestions welcome of more codes to add)

 Let's have a look at an example, where we make the bot speak to anyone that
joins the channel. It includes the channel name as one of the %-codes:

join: "" Say("Welcome to channel %c!");


The same hook name may appear any number of times in the same file to add
several different invoke-condiditions.



                                    Hooks
                                    =====

 One way to make Dancer behave differently on different events, is to find
which hook is generated at the specific event and then make your prefered fpl
function run at that time.

 There are a large amount of hooks, hopefully at least one for every
imaginable situation where you would wanna run your own functions.

 There are two kinds of hooks, pre and post. Pre hooks are the normal ones and
are performed _before_ the internal actions are done and post hooks are
surprisingly enough, run _after_ the internal actions. You specify post hooks
by prefixing the hook name with a '+' character in the setup file.

 You can add several functions to a single hook, and each funtion added to a
hook has a regex pattern that has to match the input data in order for the
function to get run.

 The 'input' to the hook is the one compared with the regex, and also the data
that the %i is expanded to.

 Although you can add any number of functions to the same hook, you can make
one function disable all the rest of the functions from being run by calling
the Cancel() function. Some if the internal functions will also be possible to
cancel in a pre-hook by the use of the Cancel() function. See the list of
built-in functions for more details about Cancel().


Table of Available Hooks (P means that this function's internal actions is
prevented from taking place if the pre-hook calls Cancel().)

Name      Input         P Description
----      -----         - -----------
init      -             - Performed when the bot is started
public    public msg    - A non-command public msg was received
action    action msg    * A /me was read in the channel
ctcppub   ctcp msg      * Public CTCP was received
ctcppriv  ctcp msg      * Private CTCP was received
topic     topic line    * Topic changed
kick      kick line     - A user was kicked off by another user
join      nick          - A user joined
signoff   nick          - A user signed off
leave     nick          - A user left
nick      nick          - A user changes nick (pre hook gets old nick, post hook
                          gets new nick)
invite    channel       * We received an invite request
numeric   number        * Numeric message was received from the server
connect   server name   * When the bot connects to a server:
disconnect disconenctmsg * When the bot disconnects from a server:
error     error msg     * Server error
alert     nick          * Alert for nick shown
offmsg    line          * Off-channel message
kickbot   nick!user     * The bot got kicked

--- Some hooks that might or might not get added in the future: ---

input     - easy-to-use (done on action, public, msg and dcc)
msg       - A non-command msg was received
dcc       - A non-command dcc line was received
note      - We received an irc NOTE
notice    - We received a NOTICE
wall      - This is activated whenever you receive a WALL

mode      - Mode change was done in channel
            user modes are ignored
            mixed modes are grouped and hook is called for each group
            banlist etc. must be updated
            reactions to bans etc. can be overruled
send_action   - We sent <stuff> (strongly ircII inspired)
send_dcc_chat
send_msg
send_notice
send_public
warning   - User warning (on join)
flood     - User flooding (type is given)
nethack   - Server modechanges
netsplit - Detection of netsplit
nethead  - Detection of netjoin (or timeout)
netleave - User left in netsplit
netjoin  - User joined in netjoin


                                 FPL Programs
                                 ============

 To add functions to Dancer, you must write the functions using the FPL syntax
in a file that is run from another FPL file before the function is called (to
run an FPL program from within a function, use Runfile()). If you write a
function in one source file and intends to call the function from another, you
must make the function "exported" which you do with the keyword 'export' in
front of the function name.

 All errors that the FPL interpreter discovers in your FPL programs, are logged
in the dancer logfile using the DEBUG flag. If you have that disabled from the
log, you won't see any FPL error messages and therefor get a very hard time
debugging your mistakes...

                             Adding New Commands
                             ===================

 Add a new command to your bot by running a FPL program that uses the CmdAdd()
function.

 int CmdAdd(string name,   /* name of new command, preferable specified in
                               uppercase like the rest of the commands
                               NO, you can't add aliases to this one. */
            int level,     /* level required for use */
            string syntax, /* syntax string */
            string help,   /* help string */
            string flags,  /* flags as below */
            string fpl)    /* complete FPL program to run at invoke in full
                              fpl-invoke style with %-support */

 the flags are strings separated with a '|' letter. Available flags are:
   showable  - Output can be redirected to another person
   passwd    - Password protected
   needcomma - Comma is part of argument, not argument seperator
   public    - Command can be used in public

 Example:

  CmdAdd("TEST",
         10,
         "[nick]",
         "tests <nick>",
         "passwd|public", /* publicly available and require password */
         "mytestfpl(%i);")); /* this function must be exported prior to the
                              invoke */

                             Adding New User Info
                             ====================

 Adding new user info, soft userdata, is userdata not controlled, used or set
by internal functions of Dancer. This kind of data is all controlled by
FPL. The data is connected to one user.

 The FPL program can define a symbol/label and then read/write any number or
string to it. That value/string can then be saved attached to a user.  It is
global and once defined the label and be read/written to/on any user.

 Non user-connected labels can be made, read and written with the same
function setup, just note the flag to LabelDefine().


Define a label
--------------
LabelDefine(string name,  /* name of the label, any sequence of non-whitespace
                             letters are accepted */
            string flags, /* flags as below */
            int/string default) /* default value/string */

 This function defines a label. Only defined labels (that differs from the
default value) are stored/existing. Available flags are:
  save - save the data per-user (otherwise the data will simply be forgotten
         when the user leaves the channel and set to default for all users
         that join the channel)
  solo - this label is plain alone and is *not* connected to any user, but
         simply a single global label. (Specifying a userid when reading or
         writing one of these kind of labels won't affect anything!)

 The reason for only saving defined ones is that otherwise there wouldn't be
any way to remove old, left-over, obsolete or test symbols.

Read a label
------------

LabelRead(string name, int userid)

 Returns the value of the label of the current user or if the userid
parameter is specified, of the specified user. Userid is returned from the
the function GetUser(). (I've decided to make this a separate call and use
the id approach to easier separate and enable FPL programs to separate
joined users from regged users and DCC-only users. A mere nick name is not
always enough.)

Set a label
-----------
LabelSet(string name, int/string value, int userid)

 Sets the label to the specified value. If the userid is specified, that
user's label is affected rather than the "current" user.

                                 Timed Events
                                 ============

 TimerAdd(time, action);

 time         - number of seconds until the action is performed
 action       - fpl program to run when the timer goes off

EXAMPLE

 TimerAnnounce.FPL lets the bot call out the time once per hour:

 void export TellTime()
 {
   Say("The time is now %s", GetCurrentTimeString());
   TimerAdd(3600, "TellTime();");
 }
 TellTime();

##############################################################################

                              Built-in Functions
                              ==================

 This is the complete list of functions Dancer provides to the FPL program
environment (as addition to the already present internal functions you can
read about in the FPL language documentation).

 Parameters written with UPPER CASE are optional and will be replaced with
default values if not specified. If non-optional parameters are left out, the
FPL interpreter will draw your attention to that position by failing hard and
report an error!

                                    -----
NAME
  Action - performs a CTCP ACTION, i.e a /me command.

SYNOPSIS
  Action ( string line );

DESCRIPTION
  Action() outputs the specified line, just as if someone had used the 'SAY'
  command to the bot. 'SET SAY OFF' does not prevent this from working.

RETURN VALUES
  No return code.
                                    -----
NAME
  BotInfo - returns info about the bot itself

SYNOPSIS
  BotInfo ( string subject );

DESCRIPTION
  Returns info about the bot.

  If 'subject' equals "chanop", returns whether the bot is channel operator.

  If 'subject' equals "nick", returns the current nick name of the bot.

RETURN VALUES
  Depends on the specified 'subject'.
                                    -----
NAME
  Cancel - prevent further execution of more hooks, and possibly the internal
           functionality too.
SYNOPSIS
  Cancel ( INT STATE );

DESCRIPTION
  If STATE is undefined or non-zero, this will prevent following hooks to get
  executed. Some pre-hooks have the capability of disabling the built-in
  actions by using this function. See the Hooks chapter for more details on
  that. Cancel() may be called any number of times with different values, it
  is the state of the last Cancel() that has precedence.

  Calling this from a non-hook function won't have any effect.

RETURN VALUES
  The state of the cancel before this function was called.
                                    -----
NAME
  ChanInfo - returns information about the channel.

SYNOPSIS
  ChanInfo ( string subject );

DESCRIPTION
  ChanInfo() returns information about the subject entered as parameter.

  If subject equals "guests", the function will return the number of guests
  currently joined.

RETURN VALUES
  Depends on the input parameter.
                                    -----
NAME
  CmdAdd - adds a new command.

SYNOPSIS
  CmdAdd ( string name,
           int level,
           string syntax,
           string help,
           string flags,
           string fpl );

DESCRIPTION
  This command creates a new command named 'name', which becomes available for
  users with at least 'level'. Whenever this new command name is entered by a
  valid user, the 'fpl' parameter is run.

  'flags' are specified by separating keywords with the '|' character and the
  flags available at this point are:

     showable  - Output can be redirected to another person
     passwd    - Password protected
     needcomma - Comma is part of argument, not argument seperator
     public    - Command can be used in public

  NOTE: there is no check at all at add-time that the fpl program added as the
  last parameter really is a valid FPL program.

RETURN VALUES
  No return code.
                                    -----
NAME
  GetUser - returns a unique identifier of the specified user.

SYNOPSIS
  GetUser ( string nick, STRING FLAGS );

DESCRIPTION
  This function returns a number which can be used to identify the specified
  user in later calls to other functions which use the user id.

  'FLAGS' are specified by separating keywords with the '|' character and the
  flags available at this point are:

        join    - return id of a joined user
        reg     - return id of a regged user

  If no flags are specified, this function scans for the nick in the following
  order:
        1. joined guests
        2. split guests
        3. registered users with that nick
        4. users connected with dcc only

RETURN VALUES
  The numerical user id.
                                    -----
NAME
  Hook - adds a hook as if it was found in the .fplconf file.

SYNOPSIS
  Hook ( string name,
         string regex,
         string fpl,
         STRING TYPE );

DESCRIPTION
  Hook lets a program add a hook, just as if it was written in the .fplconf.
  (See the Hooks section for details.)

  The 'TYPE' parameter is default considered to be "pre", but if set to "post"
  the hook will be made a post hook.

RETURN VALUES
  Returns non-zero if it failed.
                                    -----
NAME
  Join - joins a channel.

SYNOPSIS
  Join ( STRING CHANNEL, STRING KEY );

DESCRIPTION
  Makes the bot join the default or specified channel using the default or
  specified key.

RETURN VALUES
  No return code.
                                    -----
NAME
  Kick - kick a user off the channel

SYNOPSIS
  Kick ( string nick, string message );

DESCRIPTION
  Performs a regular kick. If the bot isn't channel operator or in case it has
  already been kicking a lot, the kick might be queued up to prevent the bot
  from flooding itself off the channel. Read more about that in a flood
  description somewhere else.

RETURN VALUES
  No return code.
                                    -----
NAME
  LabelDefine - define a label.

SYNOPSIS
  LabelDefine ( string name,
                STRING FLAGS,
                STRING/INT DEFAULT );

DESCRIPTION
  As described in the Adding New User Info chapter, this function adds a new
  label connected to the user data structs.

  'FLAGS' are keywords separated with the '|' characters. Available flags are:

        save -  Makes the info get saved in the user file
        solo -  This info is not user-connected, but only one instance of this
                label exists.
        string - This label contains string data, as opposed to integer data
                which a label holds by default.

  The 'DEFAULY' parameter sets the default value of the label if nothing else
  has been set.

RETURN VALUES
  No return code.
                                    -----

NAME
  LabelRead - reads the value off a label.

SYNOPSIS
  LabelRead ( string label, INT USERID );

DESCRIPTION
  LabelRead returns the value of the label of the current user or if the
  userid parameter is specified, of the specified user. USERID is the return
  code of the function GetUser().

  NOTE: I decided to make this (GetUser()) a separate call and use the id
  approach to easier separate and enable FPL programs to separate joined users
  from regged users and DCC-only users. A mere nick name is not always enough.

RETURN VALUES
  The contents of the label.
                                    -----
NAME
  LabelSet - sets a label's contents.

SYNOPSIS
  LabelSet ( string label,
             string/int value,
             INT USERID );

DESCRIPTION
  Sets the label to the specified value. If USERID is specified, that user's
  label is affected rather than the "current" user.

RETURN VALUES
  No return code.
                                    -----
NAME
  Leave - leaves the current channel.

SYNOPSIS
  Leave ( );

DESCRIPTION
  Makes the bot leave the channel.

RETURN VALUES
  No return code.
                                    -----
NAME
  Match - wildcard compare with string.

SYNOPSIS
  Match ( string string, string pattern );

DESCRIPTION
  Returns non-zero if the specified 'pattern' matches the specified 'string'.
  ? and * are suppored wildcard characters.

RETURN VALUES
  The result of the match.
                                    -----
NAME
  Mode - sets channel mode.

SYNOPSIS
  Mode ( string line );

DESCRIPTION
  Sets the mode of the channel. The specified 'line' must be properly formatted.

RETURN VALUES
  No return code.
                                    -----
NAME
  Output - writes to stderr.

SYNOPSIS
  Output ( string line );

DESCRIPTION
  This function is used for script debugging purposes only. It sends the 'line'
  sent as parameter to the stderr stream.

RETURN VALUES
  No return code.
                                    -----
NAME
  Rnd - returns a random number.

SYNOPSIS
  Rnd ( int roof );

DESCRIPTION
  Returns a random number that is between 0 and 'roof'-1.

RETURN VALUES
  The random number.
                                    -----
NAME
  Regex - performs a regex match.

SYNOPSIS
  Regex ( string line, string regex );

DESCRIPTION
  Returns whether the entered 'regex' expression matches the entered 'line'.

RETURN VALUES
  Non-zero if it matched, otherwise zero.
                                    -----
NAME
  Runfile - execute a file as an FPL program.

SYNOPSIS
  Runfile ( string filename );

DESCRIPTION
  Executes the specified file name as an FPL program.

RETURN VALUES
  Non-zero if the program failed in any way, otherwise zero.
                                    -----
NAME
  Say - talk.

SYNOPSIS
  Say ( string line );

DESCRIPTION
  Send the given line to the channel.

RETURN VALUES
  No return code.
                                    -----
NAME
  Send - send a line of text to a user

SYNOPSIS
  Send ( string nick, string line );

DESCRIPTION
  Sends the given line to the user. This will use the DCC chat if such a one is
  available and in use, otherwise a /msg will be used.

RETURN VALUES
  No return code.
                                    -----
NAME
  TimerAdd - adds a timer.

SYNOPSIS
  TimerAdd ( int time, string fpl );

DESCRIPTION
  Adds a timer that will run the specified fpl program when the time is up.
  'time' is specified in number of seconds, although the exactness of this timer
  will never be better than +-2 seconds.

RETURN VALUES
  Timer id
                                    -----
NAME
  TimerKill - kills a started timer.

SYNOPSIS
  TimerKill ( int timerid );

DESCRIPTION
  Kills the timer with the specified 'timerid'. The timerid is the return code
  from the TimerAdd() function.

RETURN VALUES
  Number of seconds left until the timer would have expired.
                                    -----
NAME
  Time2Secs - convert a HH:MM:SS string to seconds.

SYNOPSIS
  Time2Secs ( string time );

DESCRIPTION
  Returns the number of seconds that the specified input 'time' equals. The
  input format is <Hours>:<Minutes>:<Seconds>.

RETURN VALUES
  Number of seconds.
                                    -----
NAME
  UserInfo - returns info about a user

SYNOPSIS
  UserInfo ( string nick, string subject );

DESCRIPTION
  Returns information about 'nick' regarding 'subject'.

  If 'subject' equals "level", returns the status level of the user.

  If 'subject' equals "ircop", returns whether the user was ircop when he/she
  joined.

  If 'subject' equals "voice", returns whether the user has the +v flag set.

  If 'subject' equals "chanop", returns whether the user has the +o flag set.

RETURN VALUES
  Depends on the 'subject'. For the booleans, non-zero means true (yes), zero
  means false (no).
                                    -----

