271 lines
11 KiB
Text
271 lines
11 KiB
Text
How to Write a NeoStats Module, and not stuff it all up! Version 2.5
|
|
------------------------------------------------------------------------------
|
|
This document attempts to explain how to write Modules for NeoStats
|
|
(Versions greater than 2.5, older versions had a different API specification)
|
|
|
|
Modules are not simple :) I really suggest you use the source or
|
|
some other modules as examples as well as this document.
|
|
|
|
We have added in 2.5 a new 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 a 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 NeoStats
|
|
will still crash. If I can find a solution to this problem (without coping
|
|
the entire Neostats memory before each call) then I'll implement it.
|
|
|
|
|
|
So, your feeling very very lucky, and want to write your own wiz bang
|
|
Services? Ok... Get out the asprin, cause this is gonna be fun....
|
|
|
|
______________________________________________________________________________
|
|
|
|
Anything that the Server recieves from users, or other servers can be
|
|
intercepted by a Module... This basically means you can do what ever you
|
|
want in Modules.
|
|
|
|
Lets use example.c as example here... I'll detail each part of it....
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "dl.h"
|
|
#include "stats.h"
|
|
|
|
ok, Firstly, you have to include a few files.
|
|
"dl.h" is mandatory, needed for the Module API...
|
|
"stats.h" is also a pretty good idea, if you want to use some of the
|
|
Internal Functions of NeoStats. If your Module is going to have a Bot in it,
|
|
then its Mandatory as well...
|
|
|
|
|
|
Module_Info my_info[] = { {
|
|
"example",
|
|
"example Module Description",
|
|
"version 1.0"
|
|
} };
|
|
|
|
Module_Info *__module_get_info() {
|
|
return my_info;
|
|
};
|
|
|
|
ok, a pretty lame coding style, but hey, it works, so who cares at the
|
|
moment.
|
|
Every Module must be able to return a array describing the Module Name, a
|
|
Short Description and a *Text* based version number.
|
|
The First field is used when refercing modules (eg, unloading a Module) the
|
|
second field is the description... the third field is a Version number...
|
|
Like I said, its text based, but could be just numbers for all you care.. it
|
|
can be used by other modules that might rely on it to make sure if version
|
|
compatible...
|
|
|
|
Functions my_fn_list[] = {
|
|
{ "VERSION", new_m_version, 1 }
|
|
{ NULL, NULL, 0 }
|
|
};
|
|
|
|
|
|
Functions *__module_get_functions() {
|
|
return my_fn_list;
|
|
};
|
|
|
|
ok, here is where we define what commands we want to be routed to this
|
|
Module. In this case, if a user typed /version <NeoStats Server name> then
|
|
this Module would intercept it... (note that with most commands, the Base
|
|
NeoStats also would intercept it) so in this case, both the NeoStats and
|
|
Module would return information. again. my_fn_list[] is a array. the first
|
|
field is what command you want to intercept it Could be "NICK" or
|
|
whatever... the Second field is the name of the function in the module that
|
|
will get this command... and finally the third field helps identify if you
|
|
want to see commands that come from the locally connected servers (eg, if it
|
|
squits NeoStats) or if you want to see commands that come form the network
|
|
in General. In this case, 1 means that we want Network Commands...
|
|
Remember, NeoStats, and many IRCD's use tokens now, so VERSION might not
|
|
always work. You should also try "+" as thats the token for version. For
|
|
easy CrossIRCD
|
|
support, I suggest you use the MSG_VERSION and TOK_VERSION defines
|
|
(for example in Unreal.h) as they will be implemented in all CrossIRCD
|
|
version, and make your module more portable if you wish to release it.
|
|
|
|
the function new_m_version is passed 2 variables: char **av and int ac.
|
|
av is a array containing the parsed command, ac contains the number of
|
|
elements.
|
|
|
|
the end of the array must be NULL terminated, meaning that the TEXT fields
|
|
must be null, and the numeric fields must be 0.
|
|
|
|
|
|
EventFnList my_event_list[] = {
|
|
{ "ONLINE", Online},
|
|
{ NULL, NULL}
|
|
};
|
|
|
|
|
|
EventFnList *__module_get_events() {
|
|
return my_event_list;
|
|
};
|
|
|
|
|
|
Ok, this is Internal Functions Lists that you want to trigger on. Examples
|
|
of them are ONLINE, trigged when NeoStats is Connected to the IRC network,
|
|
or SIGNON when a new user signs on... This list is pretty small at the
|
|
moment, but will grow as we add more features. Again, the
|
|
first field is the event you want to monitor, second is the function to
|
|
trigger when this event is activated. Again, NULL terminate the array.
|
|
|
|
The Events that are in the current version (2.5Alpha4.7) are:
|
|
ONLINE
|
|
This event is called when NeoStats connects to the Network. Can be used to
|
|
init bots, and so on.
|
|
SIGNON
|
|
Called when a new user signs onto the network. the User Structure User is
|
|
passed as a param, so you can see who it was that signed on.
|
|
SIGNOFF
|
|
Called when a user quits the network. The User structure User
|
|
is passed as a param, so you can see who it was that signed off.
|
|
KILL
|
|
Called when a user is killed on the network. the user structure User
|
|
is passed as a param, so you can see who was killed (You would have to use
|
|
the recbuf global variable to see who killed them though)
|
|
BOTKILL
|
|
Called if one of the NeoStats bots gets killed. You would use it
|
|
to Re-Initilize the Bot.
|
|
NEWSERVER
|
|
Called when a server connects to the network. the server structure Server
|
|
is passed as a param so you can see details about the new server
|
|
DELSERVER
|
|
Called when a server leaves the network.
|
|
SQUIT
|
|
Called when a server squits the network (ED: whats the diff with above?)
|
|
NETINFO
|
|
Called when the connection to the network is synced.
|
|
UMODE
|
|
Called when a user changes Umodes. (eg, /mode +o fish) the
|
|
User Structure User is passed as a param.
|
|
|
|
Thats it for events right at the moment. As we have just added Channel
|
|
support though, I suspect many more events are about to be
|
|
added. For a complete and uptodate list of Events, I suggest "grep
|
|
Event_Module *" in the source directory, to find out what Events are now
|
|
available.
|
|
|
|
|
|
void _fini() {
|
|
log("unloading Spam");
|
|
};
|
|
|
|
void _init() {
|
|
log("Loaded Module");
|
|
}
|
|
|
|
Two Special Functions that can be helpfull if you have to initilize
|
|
databases or close them down (or whatever else you might need to do)
|
|
NOTE: DO NOT USE _init to start up bots or whatever. NeoStats might not even
|
|
be connected to a IRC network when _init is fired. Basically, Don't use init
|
|
to start anything that is going to try to send commands to the IRC network.
|
|
use it to Initilize a database, or read in a config file... _init is called
|
|
even before the module is fully loaded....
|
|
_fini is called when the module is unloaded, probably the very last thing
|
|
that happens, so if you need to close log files, or flush out a database
|
|
cache then here is the place to do it...
|
|
|
|
now, some special functions to use as well, like init and fini:
|
|
|
|
|
|
init_bot(nick, ident, hostname, realname, modes, my_info[0].module_name);
|
|
|
|
init_bot is a function in the Main program that Registers a Bot on the
|
|
network for you. DON'T just think that you can send a "NICK mybot" out to
|
|
the network cause it won't work. PRIVMSG's and NOTICES are handled in a
|
|
special way, and each module has to register its bots via this interface.
|
|
|
|
init bot will return 1 on success, or if there is a failure of somereason,
|
|
then it will return -1. A failure might be that the nickname already exists
|
|
on the network, in which case, you would have to try a new Nick.
|
|
|
|
bot_nick_change(currentnick, newnick)
|
|
|
|
Bot_nick is used to change the Nickname of a bot. Because the Bot Nicknames
|
|
are registered internally in NeoStats, you must call this function to change
|
|
the nickname... again, will return 1 on success, or -1 if the nickname is
|
|
already registered on the network.
|
|
|
|
del_bot(nick, reason)
|
|
This functions makes your Bot Quit from the Network, and unregisters the
|
|
name with NeoStats.. if you try to LOG off a nickname that isn't registered,
|
|
then it will return -1 otherwise on success, it returns 1
|
|
|
|
|
|
int __Bot_Message(char *origin, char **av, int ac)
|
|
|
|
This function in your Module is called whenever a bot that has been
|
|
registered like above recieves a message from the Network. If you are
|
|
programing a Bot, this this is the Interface for all PRIVMSG's and NOTICE's
|
|
the Variables passed to it are as follows:
|
|
|
|
origin -> who sent the Message to you.. It could be a Nick 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. (eg, the above would be 2)
|
|
|
|
add_mod_timer(function name, timername, my_info[0].module_name, interval);
|
|
|
|
Ahh, have a need for Timers in your Module.. Well here is how you do them...
|
|
again, you have to register your function with NeoStats, just like you would
|
|
with a Bot.
|
|
|
|
the variables are:
|
|
Function name -> the Name of the function you want to trigger when this
|
|
timer is triggered
|
|
|
|
timername -> a descriptive name of the Timer...
|
|
|
|
my_info[0].module_name -> must be the same as what you passed to NeoStats
|
|
for the module name... to stop muckups, I use the actual Variable I passed.
|
|
|
|
interval -> The Interval in Seconds that this Function can be run...
|
|
|
|
A word of Warning about timers.. These are not precision timers. when I say
|
|
Interval, all it does is say, "has this many seconds passed since I last ran
|
|
this function. If you specified 60 seconds for the Function, it might not
|
|
get run till 66 seconds. Because NeoStats is Single Threaded, it runs in a
|
|
continues loop, meaning that if NeoStats itself, or another Module held up
|
|
that loop, then the timers are not going to run untill that peice of code
|
|
gives up...
|
|
|
|
int del_mod_timer(char *timername)
|
|
|
|
ahhh, finished running your timers, and want to delete them, then just call
|
|
this function with the timername u used above, and volia, the timer will be
|
|
deleted.
|
|
|
|
|
|
This is the Main API for Modules in a Nutshell.. I really suggest you read
|
|
the source to get a good understanding of the modules, or email me
|
|
if you have questions. Modules are pretty flexable and
|
|
powerfull, but can also be the source of a lot of problems.
|
|
|
|
Other things that modules can do:
|
|
Sockets. They can make outgoing tcp connections to other servers (ie, web,
|
|
email, etc)
|
|
Call other functions in other modules.
|
|
|
|
|
|
at the moment, I know of the issue of not every platform supporting Dynamic
|
|
Libaries... So I'm going to work on linking in static libaries... but that
|
|
could take me a while... so if your host doesn't have Dynamic Libary suport,
|
|
then find one that does if you really want to run NeoStats... Don't bug me
|
|
about it...
|
|
|
|
|
|
Thats about it...
|
|
Comments and suggestions are welcome at: fish@dynam.ac
|
|
or you can find me on one of these networks occasionally:
|
|
|