Plugins HOW TO (last update : 2009-04-18) : =========================================== Table of content ================ => Introduction => Plugins' types => Base plugin => Inititalize plugin/function => construct / destruct => Plugin compilation => Features/functions provided by kernel => Plugins interractions => IRCProtocol usage => Plugin sample Introduction ============ trustyRC main particularity is to be fully modular. trustyRC is just a kernel that is able to load/unload plugins (and provide them ressources to work or communicate). Some plugins are provided with trustyRC sources, but you can write your own plugins. This howto aims to make you able to do it. Plugins' types ============= There are different plugins types. Here are there descriptions : IN_LOOP : function will be triggered cyclically in the main loop. It's possible to control time between executions. IN_COMMAND_HANDLER : function will be triggered when a given command is typed IN_FREE_COMMAND_HANDLER : function will be triggered when a command is typed (command prefix is free) IN_TYPE_HANDLER : function will be triggered on a specific message type IN_BEFORE_TREATMENT : function will be triggered before treatment (possibility to cancel treatment) IN_ALL_MSGS : function will be triggered on all messages IN_FIRST_WORD : function will be triggered on a specific word (first one of the message) COUNTDOWN : function will be triggered at the end of the countdown OUT_ALL_MSGS : function will be triggered on all outgoing messages Base plugin =========== A "base" plugin class exists. use it to start your first plugin. It's a kind of skeleton. You can find it in "src/plugins/base_plugin". Copy class.cpp and class.h in "src/plugins/" and rename it. Modify those files to make your own plugin. Initialize plugin/function ========================== To be loaded on the kernel, a plugin must be initialized : - to register informations (name,author,version ...) - to register its functions against the kernel - to provides its requirements (dependacy to other plugins) Theses actions must be done in the plugin's constructor. Here is the initialize template : this->author = "AUTHOR"; this->description = "DESCRIPTION"; this->version = VERSION; this->name = "NAME"; this->bindFunction(handler,function_type,callback_function,last_exectution,timeout); this->addRequirement("plugin_name"); handler : depends on plugin type. Can be the command handler, the message type handler, or the time to wait between 2 executions function_type: plugin type callback_function: name of the function called when plugin is triggered. Callback function have to be in the "external C {}" section. last_execution: timestamp used to inititalise last exectution of the function. It will be usually '0', but you can put a timestamp in the future to make that the function will not be executed at plugin load (for IN_LOOP only) timeout: maximum execution time for the function. If this time is elapsed, the execution will be cancelled by the kernel (to avoid kernel freeze, in a "infinity while" for example) Use "bindFunction" as many time as you need to register function. /!\ ATTENTION /!\ : bindFunction will have effect only if used in plugin's constructor. If used afterwards, the function will not be registred (an other solution exists to register functions during execution (see "Features/functions provides by kernel) Here is an initialization example for "admin" plugin. 4 functions are registred. The first one will be call the "reset" callback when the command reset is typed (!reset for example). Then the function clearTemporaryAdmins will be called every 35 seconds, and allowedCommandCheck will be called before each treatment. Finaly onPrivateMsg function will be called on each message : this->author = "eponyme"; this->description = "bot admin management"; this->version = VERSION; this->name = "admin"; this->bindFunction("reset",IN_COMMAND_HANDLER,"reset",0,10); this->bindFunction("35",IN_LOOP,"clearTemporaryAdmins",0,30); this->bindFunction("",IN_BEFORE_TREATMENT,"allowedCommandCheck",0,10); this->bindFunction("PRIVMSG",IN_TYPE_HANDLER,"onPrivateMsg",0,10); this->addRequirement("foo"); // So the plugin "admin" won't be loaded if "foo" is not loaded. And "foo" plugin won't be unloaded if "admin" is loaded callback function must respect this prototype : bool functionName (Message*,Plugin*,BotKernel*); construct / destruct ==================== To be implemented by the kernel, stored objects must be "constructed". Then, when the plugin is unloaded, the plugin must be destructed. So you must ahve two function for that. The first one will construct the object and return it, the second one will destruct will delete the object. Here are the prototypes : Plugin *contruct_(BotKernel*b) { return new (b); } void destroy_(Plugin*p) { delete p; } For the "antiflood" plugin, here are the two functions : Plugin *contruct_antiflood(BotKernel*b) { return new AntiFlood(b); } void destroy_antiflood(Plugin*p) { delete p; } Plugin compilation ================== To compile your plugin, you don't have anything to do. As your plugin sources are in src/plugins, it will automaticaly be compiled. If you need some special compilation flags for your plugin, insert a new line in the Makefile, in "specific rules" sections. If you want to compile *only* your plugin, just type "make plugins/my_plugin_name.so" (my_plugin_name must be the name of cpp/h files. Features/functions provided by kernel ===================================== Use doxygen code documentation to see detailed descriptions. The kernel provides several features to help your plugin to be useful. Here are all public function that can be called by a plugin (a kernel pointer is passed to the function when called) : - registerFunction - unregisterFunction - addCountDown - send - getVersion - getDescription - getAuthor - setConnected - getConnected - getSysLog - getNick - setNick - loadPlugin - unloadPlugin - getPlugin - getPluginsList - getStartTime - getStartOnline - getCountDowns - getCONFF - getDatasDir Functions provided with Message object : - getSplit - setMessage - nbParts - getPart - getSender - getNickSender - getHostSender - getIdentSender - isPrivate - isPublic - getSource - getMessage Functions provided with Plugin object : - getFunctions - getAuthor - getDescription - getVersion - getName - checkMembers - bindFunction - getHandle - setHandle - addRequirement - getRequirements - requires The kernel also provides implementations to use tinyxml librairie, and a PThread class, that provides a (simple) wrapper to pthread librairie. Plugins interractions ===================== The kernel allows a plugin to acces to an other one. To do this, from a plugin, use "getPlugin" function. A "pointer plugin (pPlugin)" on a given plugin will be returned (NULL will be returned if the plugin is not loaded). A pPlugin is a structure from witch you can retrieve different information : - name => plugin name - handle => plugin handle - object => pointer on the instanciated object embeded in the plugin. Use this to acces to plugin features - creator => object constructor - destructor => object destructor So, to acces to a plugin, get its pPlugin from the kernel, and then use its object. You will then acces to its public functions. Dont forget to add loaded plugin's cpp file to compilation. IRCProtocol usage ================= IRCProtocol is a class that provides only public static functions. Use it to pass "IRC formated strings" to BotKernel::send() function. Example, to join a channel : b->send(IRCProtocol::join("#nicechan")); See doxygen code documentation for a complete description of IRCProtocol class. Plugin sample ============= The plugin called "plugin sample" is a plugin example. Read it to see how to write your first plugin. This plugin just make the bot answer "hello" to the "hello" command. It will help you to understand basic plugins mechanism. You will find sources in src/plugins directory.