mibcip HOWTO

Helmut Grohne

This article describes how to set up and use the IRC bot mibcip.


Table of Contents
1. What is mibcip?
2. Getting mibcip
3. Before starting
4. Starting
5. Writing plugins
6. Using plugins

1. What is mibcip?

Mibcip is a modular IRC bot core in Python. It is designed to be extensible and therefore based on a plugin system. The core is only a small Python script which knows how to handle plugins. The rest of the bot is written within plugins. Nearly the whole bot is therefore reloadable during runtime.


2. Getting mibcip

The general source for mibcip is my personal darcs repository. Darcs can be found at http://www.darcs.net/. Use the following command to create your working copy.


$ darcs get http://subdivi.de/~helmut/darcs/mibcip/
			
In order to work with the latest version just frequently update the source using the following command from within the source directory created by the previous command.

$ darcs pull
			
If you do not want to use darcs, you might be able to use a tarball at http://subdivi.de/~helmut/mibcip/mibcip.tar.gz if it exists, but it will probably be outdated. You may bug me to upload a new version via mail or irc.


3. Before starting

Assuming you have at least Python 2.3 or newer installed you basically have all necessary software. Although Twisted is not a dependency it is most advisable to install it. Mibcip will try to load twisted on startup and use a fallback library which is not tested very well. It is known to fail on Win32 and Mac OS X, but if you want you can help me debugging it on the platforms mentioned above.

Now two files are necessary. You should first create a file called mibcip.conf in the source directory. This file has the syntax defined by Python's ConfigParser module. It is divided in sections. Most sections correspond to a specific plugin within mibcip. Some plugins need configuration entires, others not. The small example below just shows this. It first defines a section for the plugin test.ctcp. Within that section a string is assigned to the variable version. You can assign other values to variables of the same name for different plugins.


[test.ctcp]
version = mibcip:devel:Debian GNU/Linux on i386
			
There is a special section called core. Within this section very basic variables are set. Two variables server and port control which server to connect to. The port is usually set to 6667. To connect to the Freenode network use irc.freenode.net as server. Another section core.startup controls the basic connection setup. The variables nick, user, hostname, servername and realname are used when sending the initial IRC USER and NICK commands. Within the section core.servcapab the variable config tells the bot which features the IRC server has. Predefined capabilities are basic, freenode, euirc and quakenet. If this options is omitted the limited basic capability set is used. As a last important option the option ircpasswd within the section core.auth has to be set to a filename containing the ircpasswd which will be the second file. This file should generally exist and can be empty when first starting the bot.


4. Starting

Now as you have gone through all the steps above you should be able to simply execute the file mibcip.py from the source directory in order to start the bot. Be sure that the working directory is the source directory. This is needed for loading any plugin at the moment. When started the bot should print a lot of debug lines and stay connected for a while. If this is not the case, you probably found a bug and should tell me about this. To terminate the bot just hit Ctrl-C if you are working on a Unix or find another way to terminate the script.


5. Writing plugins

In order to write a plugin create a Python file within the plugins or plugins/test directory. Your plugin must define a list of lists of strings called depends. The strings are names of plugins. From each list at least one plugin must be loaded for this plugin to be used. If you want to depend on a specific plugin just use its name and make a list of a single element, the name. Many plugins depend on the plugin core.config. The following code snippet achieves this.


depends = [ [ "core.config" ] ]
			
Additionally a list of strings must be stored in a variable called conflicts. This plugin will not be loaded if any of the plugins named in this list is loaded. In most cases it is save to leave this list empty.

The last and most important thing of your plugin will be a class called plugin. This means that there will be a lot of classes called plugin, but it's the way mibcip is written. The constructor (__init__) must accept exactly one argument. It will be given a reference to the base class instance which will be explained later. Plugins may also define methods called __getstate__ and __setstate__. If both are defined a plugin is considered reloadable. That means the plugin can be exchanged without unloading all plugins that depend on it first. The __getstate__ method must take no arguments and return an object. This object is then passed to __setstate__ for the newly created instance after reloading.

The base class defines some important attributes and methods. You can load plugins by calling the insmod method with the plugin name on a base class instance. A plugin can be unloaded by calling the rmmod method with the corresponding name as argument. Reloading is done the same way using the reload method. Additionally an attributed called p is provided. This is something like a plugin folder. A plugin contained in the file plugins/test/spam.py will have the name test.spam and will be accessible through base.p.test.spam. This way plugins can exchange data. The plugin test.spam could access a variable from the config for example assuming that the base class instance is stored in the variable base:


base.p.core.config.get("test.spam", "some_variable")
			


6. Using plugins

For now this task is a bit ugly, but the behaviour will somewhen change. The initial setup is done in the plugin core.startup which is located in plugins/core/startup.py. In order to load your own plugins you have to modify this file. Just append the corresponding insmod statements at the end of the __init__ method. You can join a different channel by modifying the on_connected defined within the __init__.