426 lines
15 KiB
Text
426 lines
15 KiB
Text
************************************************************************
|
|
** NeoStats - IRC Statistical Services **
|
|
** Copyright (c) 1999-2003 NeoStats Group. All Rights Reserved. **
|
|
** This program and all associated documentation is free but **
|
|
** copyrighted software; see the file COPYING for details. **
|
|
** Homepage: http://www.neostats.net/ **
|
|
************************************************************************
|
|
|
|
How to Write a NeoStats Module, and not stuff it all up! Version 2.5.6
|
|
----------------------------------------------------------------------
|
|
|
|
This document explains how to write modules for NeoStats.
|
|
|
|
The module instructions apply to versions 2.5.6 and higher. For older
|
|
versions you must refer to the documentation which comes with that
|
|
version since older versions had a different API specification.
|
|
|
|
This document also includes a section at the end for upgrading your
|
|
modules to the improved system available in 2.5.6. The new system
|
|
is backwards compatible with the 2.5.x system but since the old
|
|
system will eventually be removed, we recommend uprading your module
|
|
as soon as possible.
|
|
|
|
Modules are not simple but we are trying to make the API as simple as
|
|
possible so that they are easy to write. We suggest you use the source
|
|
of other modules as examples as well as this document.
|
|
|
|
2.5.x includes a feature that will help you with your modules. This
|
|
feature is aimed at all the bad coders out there that write buggy code.
|
|
Basically, if your module executes an instruction that would cause a
|
|
segfault, NeoStats will unload your modules and return itself to its
|
|
state before your module was called. But, it has one drawback, it can't
|
|
handle buffer overflows and so on. It might detect a segfault in your
|
|
module, but if your module has been overflowing memory left right and
|
|
center, then chances are that NeoStats will still crash. If I can find
|
|
a solution to this problem (without copying the entire NeoStats memory
|
|
before each call) then I'll implement it.
|
|
|
|
So, you're feeling very very lucky, and want to write your own wiz bang
|
|
Services? Ok... Get out the aspirin, cause this is going to be fun....
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
|
|
Anything that the Server receives from users, or other servers can be
|
|
intercepted by a module. This basically means that you can do what ever
|
|
you want in your modules.
|
|
|
|
In order to help you learn how to make a module, we have included an
|
|
example basic module layout in template/template.c. We will use that
|
|
file in our disucssion of how to setup the module.
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
First we must include the header file which gives our code access to the
|
|
NeoStats API:
|
|
|
|
#include "neostats.h"
|
|
|
|
Next we have to export a definition which include specific information
|
|
about our module. This is required.
|
|
|
|
ModuleInfo __module_info = {
|
|
"example",
|
|
"example Module Description",
|
|
"version 1.0"
|
|
__DATE__,
|
|
__TIME__
|
|
};
|
|
|
|
This structure contains:
|
|
module_name - A string for the module name
|
|
(one word e.g. "example")
|
|
module_description - A string short description of the module
|
|
(e.g. "My example module")
|
|
module_version - A string containing a version number
|
|
(e.g. "1,0", "Version 1.0" etc)
|
|
module_build_date - The build date of the module. The macro
|
|
__DATE__ allows us to create this automatically
|
|
module_build_time - The build time of the module. The macro
|
|
__TIME__ allows us to create this automatically
|
|
|
|
This information is used to report back to users on what modules and
|
|
what versions are loaded and can be used by the core and other modules
|
|
to check that they are compatible.
|
|
|
|
We also need to export a list of any responses to IRCd commands sent by
|
|
users to our modules that we wish to support e.g. /VERSION mymodule. This
|
|
is optional.
|
|
|
|
******************************** WARNING ********************************
|
|
This table is optional but depreciated. You should respond to module
|
|
events to be portable across all ircds and only use this table as a
|
|
last resort if a module event is not available. This table will be
|
|
removed from operation in a future release. If you need to use this
|
|
table for anything, tell us so we can add an appropiate event handler.
|
|
******************************** WARNING ********************************
|
|
|
|
NeoStats, and many IRCD's use tokens now, and the strings differ between
|
|
IRCds so a hard coded string such as "VERSION" might not always work.
|
|
For easy CrossIRCD support, we provide macros for all the available
|
|
commands such as MSG_VERSION and TOK_VERSION. These will make your module
|
|
more portable if you wish to release it. e.g.
|
|
|
|
Functions __module_functions[] = {
|
|
{MSG_VERSION, new_m_version, 1} ,
|
|
#ifdef GOTTOKENSUPPORT
|
|
{TOK_VERSION, new_m_version, 1} ,
|
|
#endif
|
|
{NULL, NULL, 0}
|
|
};
|
|
|
|
The table entries are:
|
|
- the server command you want to respond to (e.g. MSG_VERSION)
|
|
- the function to call when this happens (e.g. new_m_version)
|
|
- Flag to say whether to process
|
|
only local server commands (0) or
|
|
network commands (1)
|
|
|
|
Each function in this table is passed 2 variables: char **av and int ac.
|
|
av is a array containing the parsed command, ac contains the number of
|
|
elements.
|
|
|
|
The array must be NULL terminated, so set the final command and function
|
|
fields to NULL and the flag to 0.
|
|
|
|
We can also have a table for any events on IRC that we wish to process.
|
|
This is optional.
|
|
|
|
EventFnList __module_events[] = {
|
|
{ EVENT_ONLINE, Online},
|
|
{ NULL, NULL}
|
|
};
|
|
|
|
The table contains the event we want to process (e.g. ONLINE) and the
|
|
function to call when it happens (e.g. Online). Events signify both
|
|
server actions (e.g. the ONLINE event is triggered when NeoStats
|
|
connects to the network) and user actions (e.g. SIGNON is triggered when
|
|
a user joins the network).
|
|
|
|
The array must be NULL terminated with both event string and function
|
|
fields set to NULL.
|
|
|
|
We provide macros for each event which are listed with descriptions and
|
|
available parameters in "events.h". The header file is automatically
|
|
included by "stats.h" so you do not need to worry about including it in
|
|
your module.
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
Although that is all you need for a working module, there are a number
|
|
of other functions to further extend your module's capability.
|
|
|
|
__ModInit is called when a module is first loaded so can be used to
|
|
initialise settings for your module. It must not be used to start
|
|
anything which will try to send commands to the IRC network such
|
|
as starting a bot since you may not be connected to a network when
|
|
this function is called. It is mainly useful for processing
|
|
configuration and starting databases.
|
|
|
|
int __ModInit(int modnum, int apiver)
|
|
{
|
|
if(apiver<API_VER)
|
|
return -1;
|
|
s_my_bot_name = "NeoBot";
|
|
return 1;
|
|
}
|
|
|
|
The function is passed two parameters
|
|
- the module number ...
|
|
- the api version. You should use this to check that your module is
|
|
compatible with the version of NeoStats loading your module using
|
|
the api version. The API_VER value is used to determine this.
|
|
You should return 1 for success or -1 one for failure (for example the
|
|
api version is incompatible.
|
|
|
|
__ModFini is called when a module is unloaded so is useful for saving
|
|
databases.
|
|
|
|
void __ModFini()
|
|
{
|
|
};
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
You cannot use commands like "NICK" and "PRIVMSG" and "NOTICE" are
|
|
handled through specific NeoStats calls. Following are functions that
|
|
you will use to talk to the network and register bots on it.
|
|
|
|
init_bot allows you to create and initialize a bot to introduce for your
|
|
module. This is the only way to reguster your bot on the network.
|
|
|
|
init_bot(nick, ident, hostname, realname, modes,
|
|
__module_info.module_name);
|
|
|
|
init bot will return 1 on success, or -1 if there is a failure. A
|
|
failure might be that the nickname already exists on the network,
|
|
in which case, you would have to try a different nickname.
|
|
|
|
bot_nick_change is used to change the nickname used for your bot.
|
|
|
|
bot_nick_change(currentnick, newnick);
|
|
|
|
The function will return 1 on success, or -1 if the nickname is already
|
|
registered on the network.
|
|
|
|
del_bot allows you to remove your bot from the network.
|
|
|
|
del_bot(nick, reason);
|
|
|
|
The function will returns 1 on success or -1 otherwise for example if
|
|
you try to delete a nickname that isn't registered,
|
|
|
|
__Bot_Message is called whenever a message is sent to your bot, e.g.
|
|
/msg yourbotname or /notice yourbotname.
|
|
|
|
int __Bot_Message(char *origin, char **av, int ac)
|
|
|
|
The parameters are as follows:
|
|
|
|
origin - who sent the message to you. It could be a user nickname
|
|
or could be a server message
|
|
av - an array of the message, starting with the bots name.
|
|
So the message:
|
|
/msg NeoStats Help would be:
|
|
av[0] = "NeoStats";
|
|
av[1] = "help";
|
|
ac - the number of elements in the array.
|
|
(e.g. the above would be 2)
|
|
|
|
You can process any custom commands for your bot inside this function
|
|
e.g. to process /msg yourbotname help, you would check av[1] for the
|
|
string "help" and perform whatever task you desire.
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
Timers are available to register for your module.
|
|
|
|
To add a timer:
|
|
|
|
add_mod_timer(function name, timername,
|
|
__module_info.module_name, interval);
|
|
|
|
function name - the function you want to trigger when this timer
|
|
is triggered
|
|
timername - a descriptive name of the timer
|
|
module_name - must be the same as that defined in your ModuleInfo
|
|
structure so we recommend you use
|
|
__module_info.module_name
|
|
interval - interval in seconds that this function is to be
|
|
called.
|
|
|
|
Note, this interval is not precise. NeoStats will check the timers and
|
|
if at least interval has passed, will call your routine. Since NeoStats
|
|
is single threaded, it runs in a continuous loop, meaning that if
|
|
NeoStats itself, or another module held up that loop, then the timers
|
|
are not going to run until that piece of code completes. Therefore an
|
|
interval of 60 seconds might be called after 65 seconds.
|
|
|
|
To delete a timer:
|
|
|
|
int del_mod_timer(timername)
|
|
|
|
timername - the name the timer created with in add_mod_timer
|
|
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
TODO:
|
|
int __Chan_Message(char *origin, char **argv, int argc)
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
TODO:
|
|
Sockets. They can make outgoing tcp connections to other servers (i.e.,
|
|
web, email, etc)
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
TODO:
|
|
Call other functions in other modules.
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
TODO:
|
|
Document any other APIs for modules, kptool etc.
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
Caveats:
|
|
|
|
Not every platform supporting dynamic libraries so we are working on
|
|
support for static libraries but that might take a while. For now, if
|
|
your host does not support dynamic libraries, we suggest that you try to
|
|
find one that does if you really want to run NeoStats.
|
|
|
|
Don't bug me about it...
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
Upgrading modules from 2.5.x to 2.5.6
|
|
-------------------------------------
|
|
|
|
Although we retain backwards compatibility with the original 2.5.x API,
|
|
we will eventually only support the newer API so you should upgrade
|
|
your module to use the new system. This is quite quick and easy to do.
|
|
|
|
1) Module Info:
|
|
|
|
Old System:
|
|
|
|
const char exversion_date[] = __DATE__;
|
|
const char exversion_time[] = __TIME__;
|
|
|
|
Module_Info my_info[] = { {
|
|
"example",
|
|
"example Module Description",
|
|
"version 1.0"
|
|
} };
|
|
|
|
Module_Info *__module_get_info() {
|
|
return my_info;
|
|
}
|
|
|
|
New System:
|
|
|
|
1) rename your info structure to be exactly as follows:
|
|
ModuleInfo __module_info = {
|
|
"example",
|
|
"example Module Description",
|
|
"version 1.0"
|
|
__DATE__,
|
|
__TIME__
|
|
};
|
|
2) Delete the function __module_get_info since it is not longer needed.
|
|
3) Change all occurences of exversion_date and exversion_time to
|
|
__module_info.module_build_date and __module_info.module_build_time
|
|
4) Change all references to my_info[0] to be __module_info
|
|
|
|
2) Module functions:
|
|
|
|
Old System:
|
|
|
|
Functions my_fn_list[] = {
|
|
{ "VERSION", new_m_version, 1 },
|
|
{ NULL, NULL, 0 }
|
|
};
|
|
|
|
Functions *__module_get_functions() {
|
|
return my_fn_list;
|
|
};
|
|
|
|
New System:
|
|
|
|
1) rename your Functions structure as follows:
|
|
Functions __module_functions[] = {
|
|
{ "VERSION", new_m_version, 1 },
|
|
{ NULL, NULL, 0 }
|
|
};
|
|
2) Delete the function __module_get_functions since it is not longer
|
|
needed.
|
|
|
|
3) Events:
|
|
|
|
Old System:
|
|
|
|
EventFnList my_event_list[] = {
|
|
{ NULL, NULL}
|
|
};
|
|
|
|
EventFnList *__module_get_events() {
|
|
return my_event_list;
|
|
};
|
|
|
|
New System:
|
|
|
|
1) rename your Events structure as follows:
|
|
EventFnList __module_events[] = {
|
|
{ NULL, NULL, 0 }
|
|
};
|
|
2) Delete the function __module_get_events since it is not longer
|
|
needed.
|
|
|
|
4) _init and _fini
|
|
|
|
These were optional functions in the original system so you may not have
|
|
them. If you do, please update as follows:
|
|
|
|
Old System:
|
|
|
|
void _init()
|
|
{
|
|
}
|
|
void _fini()
|
|
{
|
|
}
|
|
|
|
New System:
|
|
|
|
1) replace _init with
|
|
|
|
int __ModInit(int modnum, int apiver)
|
|
{
|
|
if(apiver<API_VER)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
You should include a check for the apiver and fail if your module was
|
|
compiled with a different version using the define as in the example.
|
|
return 1 for success or -1 one for any failure.
|
|
|
|
2) replace _fini with
|
|
|
|
void __ModFini()
|
|
{
|
|
};
|
|
|
|
That is all you need to do to update to the 2.5.6 module API.
|
|
|
|
-----------------------------------<>-----------------------------------
|
|
That's about it.
|
|
|
|
The module API is constantly reviewed and is updated and added to from
|
|
time to time. We try to maintain backwards compatibility where it is
|
|
possible for a short time after we make any major changes. Your modules
|
|
should always work with all releases of the 2.5.x series, but you may
|
|
find that in version 2.6, you have to make a few changes to support
|
|
new features and API changes.
|
|
|
|
If you have any questions, comments or suggestions about our module API
|
|
or this document, please post on our message boards at www.neostats.net.
|
|
|
|
************************************************************************
|
|
** This document was last updated on October 8th, 2003 by M and is **
|
|
** based on documents originally created by Fish. **
|
|
************************************************************************
|