Designing Perlbot Plugins
=========================

Table of Contents
-----------------

1) So you want to write a plugin
2) A very simple example plugin
3) Plugin requirements
  3.1) init
  3.2) behaviors
  3.3) hooks
    3.3.1) hook
    3.3.2) hook_commandprefix
    3.3.3) hook_addressed_command
    3.3.4) hook_regular_expression
    3.3.5) hook_addressed
    3.3.6) hook_advanced
    3.3.7) hook_admin
    3.3.8) hook_event
    3.3.9) hook_web
4) Config files
5) Cleanup
6) The plugin help facility
7) The plugin info facility

1) So you want to write a plugin
--------------------------------

This document is meant for people who want to design their own perlbot
plugin, or anyone who's just interested in how the plugin system works.

Here are the things you'll need:

- You obviously need to know perl.  In particular, you'll need a clear
  understanding of perl references and classes/objects.  The "perlref" and
  "perltoot" man pages have all you need to know.  You won't need to
  design any classes, but you'll need to deal with some objects.

2) A very simple example plugin
-------------------------------

package Perlbot::Plugin::Example;

use Perlbot::Plugin;
@ISA = qw(Perlbot::Plugin);

our $VERSION = '1.0.0';

sub init {
  my $self = shift;

  $self->hook('example', \&example);
}

sub example {
  my $self = shift;
  my $user = shift;
  my $text = shift;

  $self->reply('I saw the command "example"!');
}

3) Plugin requirements
----------------------

  3.1) init
  ---------

All plugins should define an subroutine 'init' which is called when the
plugin is loaded.  Here you initialize your plugin, set up your behaviors
and hook appropriate events.

Example:

sub init {
  my $self = shift;

  $self->want_fork(0);

  $self->hook('hi', \&hi);
}

  3.2) behaviors
  --------------

You can define different behaviors for your plugin:

  $self->want_public(0|[1]);        # wants public text
  $self->want_msg(0|[1]);           # wants messages
  $self->want_action([0]|1);        # wants ctcp actions
  $self->want_chat([0]|1);          # wants dcc chat

  $self->want_fork(0|[1]);          # wants to be forked
  $self->want_reply_via_msg([0]|1); # wants to only reply via msg

Each of these wants either a 0 or a 1 as an argument.  The default values
are in brackets above.  If you don't want behavior different than the
default, you don't need to call these functions.

Example:

sub init {
  my $self = shift;

  $self->want_fork(0); # don't want to be forked
  $self->want_msg(0);  # don't want to get messages

  $self->hook('thing', \&someroutine);
}

  3.3) hooks
  ----------

Your plugin needs to hook diffent events to be of much use, so you'll
most likely need to use at least one of the following ways of hooking:

  $self->hook('command', \&callback);
  $self->hook_regular_expression('regular expression', \&callback);
  $self->hook_addressed(\&callback);
  $self->hook_advanced('command', \&callback);
  $self->hook_admin('command', \&callback);
  $self->hook_event('eventtype', \&callback);

    3.3.1) hook
    -----------

The hook method is an alias for calling both hook_commandprefix
and hook_addressed command as defined below.  This is the most
common type of hook.  If, for instance, your commandprefix was '!'
and you added the following hook for a math function:

  $self->hook('math', \&math);

Your irc session would look like:

<ender> perlbot, math 2+2
<perlbot> 4
<ender> !math 2+2
<perlbot> 4

As you can see, either a prepended commandprefix or a prepended
address to the bot will call your hook.

In addition, if the first parameter (the command) is empty or undef,
or you omit it entirely, every line will trigger your plugin.  You can
think of this as hooking on an "empty" command.  So you would hook
like this to make your "hello world" plugin trigger on every line:

  $self->hook(\&hello);

Then you would see:

<plastik> I am saying something
<perlbot> hello world
<plastik> Now I'll say another thing
<perlbot> hello world

    3.3.2) hook_commandprefix
    -------------------------

The hook_commandprefix method will hook a command issued with the
commandprefix in front of it.  If your command prefix is '!' and
you added the following hook:

  $self->commandprefix_hook('blah', \&blah);

When the bot sees '!blah some text here'.  It will call the callback
'blah' with a ref to $self, a user (if the person who said it was a
user) and the text 'some text here'. (it will strip the command)

    3.3.3) hook_addressed_command
    -----------------------------

The hook_addressed_command method will hook a command after the bot
has been addressed.  For instance:

  $self->hook_addressed_command('lala', \&lala);

Would get called back with 'so then' if a user typed into irc:

  yourbotnick, lala so then

    3.3.4) hook_regular_expression
    ------------------------------

The hook_regular_expression function will hook on a regular expression.
For instance, you could get yourself called on every line of text with
the following:

  $self->hook_regular_expression('.*', \&somesub);

You get passed the same type of stuff as the hook() call, but with
nothing stripped.

    3.3.5) hook_addressed
    ---------------------

This will hook any event in which the bot itself is address. If, for
instance, your bot was named 'samuelkins', then the following text
would trigger an event hooked in this manner:

  sameulkins, how are you?

You get called with the same arguments as hook, but with the addressed
part stripped, so you'd get 'how are you?'.

    3.3.6) hook_advanced
    --------------------

Exactly the same as hook, but you get the irc event passed as an
additional argument.

    3.3.7) hook_admin
    -----------------

The same as hook, but it will only be triggered by bot admins saying
the command.

    3.3.8) hook_admin
    -----------------

With this, you can hook any irc event you like.  To hook all messages:

  $self->hook_event('msg', \&something);

You just get passed a self ref and the event.

    3.3.9) hook_web
    ---------------

This allows plugin authors to 'hook' certain 'web events'.  It takes
as arguments: the hook, a coderef, and a description of what your
plugin is providing.  The bot will start a webserver on a
hostname/port combo specified in its config file if any plugins
request web hooks.  If you were to:

  $self->hook_web('myplugin', \&handle_web, 'My Plugin Stuff');

And a user went to the hostname:port/myplugin, your sub
'handle_web' would be called with all the path elements following
/myplugin.  So, if they entered:

  http://somehost.com:9090/mypluing/here/is/more

The sub 'handle_web' would be called with the array:

  ('here', 'is', 'more')

For good examples, see the StatsServer or LogServer plugins.


4) Config files
---------------

All plugins try to read a valid XML config file from their own directory.
An example config for a plugin is:

<config>
  <server hostname="www.someplace.com" port="9000" />
</config>

You can access elements from your config by using the Perlbot::Config
object:

  $self->config->value(server => 'hostname')

would return 'www.someplace.com'.


5) Cleanup
----------

When your plugin is shut down, Perlbot will try to call the method
'shutdown' on it.  You can define this method if you have anything you
want to clean up.


6) The plugin help facility
---------------------------

Help for plugins is defined by creating a file 'help.xml' in your plugin's
directory.  It should have the following format:

<help>
  <overview>An overview of the function of your plugin.</overview>
  <command name="something">What the command 'something' does.</command>
  <usage name="something">something [some arguments]</usage>
  <command name="someotherthing">What 'someotherthing' does.<br/>More</command>
  <usage name="someotherthing">someotherthing [some other arguments]</usage>
</help>

If you define this file, Perlbot will automatically give users acess to your
help.

<command> tags can contain <br/> tags which will be interpreted as a 'line break'
by perlbot and sent as a new line in irc.

*** <usage> tags CANNOT contain <br/> tags!  They will also have the admin's
commandprefix PREPENDED to them atomatically.  Be aware.


7) The plugin info facility
---------------------------

Info about your plugin is provided via a file 'info.xml' in your plugin's
directory:

<info>
  <author>Author's Name</author>
  <contact>author@place.com</contact>
  <url>http://web.address.com/plugin</url>
</info>

