Frequently Asked Questions

IRCServices.de

 Home

 IRC-WebChat

 IRC-Board

Informationen

 IRCServices

 Module

 ModulProgrammierung

KurzInfos-Funktionen

 Überblick aller  Funktionen

 NickServ

 ChanServ

 MemoServ

 OperServ

 StatServ

 HTTP-Server

 

 

 

 

 

 

 

 

Modul-Programmierung - (Scripting)


In diesem Bereich findet ihr einige Hilfen und Tutorials, um Euren eigenen IRCServices - Module schreiben zu koennen. Wer zuvor schon C oder eine ähnliche Sprache wie Java oder gar perl gelernt hat, wird mit diesen Hilfen sicher zurecht kommen.
Andere die ernsthaft Module Schreiben moechten, sollten sich mit einigen C-Büchern beschäftigen.
Denn die hiergegebenen Hilfen Zeigen nur eine CallBack-Verfahren, damit die Services miteinander Kommunizieren koennen. Die GrundLagen sind vorerst nicht zu finden.
Demnächst werden noch eine WorkShops folgen. Aber das dauert nocht.

****
Dieser Bereich ist momentan noch in englischer Sprache.
Der unten aufgeführte Scripting text wurde der IRCSERVICES-FAQ von IRCServices.za.net entnommen.
Autor : Andrew Church

Bei der Übersetzung steht der Bereich "Überblick aller Services Funktionen" im vordergrund, ich bitte dies zu verstehen ;).
***

6. Adding to and modifying Services

6-1. Writing modules
    6-1-1. Overview
    6-1-2. Module loading and unloading
    6-1-3. Inter-module dependencies
    6-1-4. Callbacks
    6-1-5. Using external functions and variables
    6-1-6. Special types of modules
6-2. Callbacks provided by Services and standard modules
    6-2-1. Services core callbacks
    6-2-2. OperServ callbacks
    6-2-3. NickServ callbacks
    6-2-4. ChanServ callbacks
    6-2-5. MemoServ callbacks
    6-2-6. StatServ callbacks
    6-2-7. HTTP server callbacks
6-3. Submitting additions or changes to Services
6-4. Coding guidelines for Services

Table of Contents


6-1. Writing modules

IRC Services 5.0 introduces a new "module" system allowing features to be added to and removed from Services at will with no changes to the core Services code.

6-1-1. Overview

Services modules are based on, and in fact use the same system as, standard dynamic-link libraries. Upon startup , Services will load a given module into memory and execute its initialization function. This function should set up any data structures necessary and register all callback functions needed (see below). At shutdown , its cleanup function will be called, which should free all resources in use and perform other necessary cleanup functions, or return an error if the module cannot unload itself for some reason.

Module interaction with Services takes place primarily through the use of callbacks. These are functions which the module registers with Services to be called when a particular event occurs, such as a message arriving from the remote server or a certain amount of time passing. Typically, a module will register callbacks for events it is interested in in its initialization routine, and remove them when the module is unloaded.

Modules are manipulated using the functions provided by modules.c in the Services core. They are as followed:

Module *load_module(const char *modulename)

Loads the given module and returns a pointer to a data structure (Module *) for the module. The contents of this data structure are private, and the pointer should only be considered as a "handle" that indicates a particular module. If the module could not be loaded, returns NULL. See section 6-1-2 below for details on the module loading process.

int unload_module(Module *module)

Unloads the given module. Returns nonzero if the module was successfully unloaded, zero if not. See section 6-1-2 below for details on the module unloading process.

Module *find_module(const char *modulename)

Returns a handle for the module whose name is given by "modulename". If no such module has been loaded, returns NULL.

void use_module(Module *module)

Increments the "use count" for the given module. A module whose use count is nonzero is not permitted to be unloaded. This function is typically called by modules which depend on other modules to function properly; see section 6-1-3 for details on inter-module dependencies.

void unuse_module(Module *module)

The opposite of use_module(): decrements the "use count" for the given module.

void *get_module_symbol(Module *module, const char *symname)

Looks up the value of the symbol "symname" in the given module, and returns its value; if the symbol cannot be found, returns NULL. If the symbol is not defined in the given module but is defined by another module, the return value of this function is undefined. Note that the "value" of a variable as returned by this function is the address of the variable, not the value it actually contains; thus, if a module declares

int intvar;

then code similar to the following should be used to access it:

int *p_intvar = get_module_symbol(mod, "intvar");
if (p_intvar)
    printf("Value of `intvar' is %d\n", *p_intvar);
else
    printf("Unable to resolve symbol `intvar'\n");

const char *get_module_name(Module *module)

Returns the name of the given module. This is usully the path used to load the module (passed to load_module()), but may be different if the module defines a module_name symbol. If NULL is passed for the "module" parameter, returns the string "core".

MODULE_NAME

This preprocessor macro is a shortcut for get_module_name(module) (where `module' is a variable pointing to the current module's handle). It can be used just like any other string constant or macro, except that it cannot be inserted into literal string constants; in other words, "Module name: " MODULE_NAME will not compile.

int register_callback(Module *module, const char *name)

Registers a new callback list. The calling module should pass its own module information structure (as passed to init_module() or obtained from find_module()). Returns an ID value, which is a non-negative integer.

int call_callback(Module *module, int id)
int call_callback_1(Module *module, int id, void *arg1)
int call_callback_2(Module *module, int id, void *arg1, void *arg2)
int call_callback_3(Module *module, int id, void *arg1, void *arg2, void *arg3)
int call_callback_4(Module *module, int id, void *arg1, void *arg2, void *arg3, void *arg4)
int call_callback_5(Module *module, int id, void *arg1, void *arg2, void *arg3, void *arg4, void *arg5)

Calls each function in the given callback list, optionally passing additional arguments to the callback function. If a function in the list returns a nonzero value, that value is returned immediately to the caller without calling any additional callback functions. If all callback functions return zero (or there are no functions to call), returns 0; returns -1 on error (the given callback ID does not exist for the given module).

int unregister_callback(Module *module, int id)

Deletes a callback list. Returns nonzero on success, zero on failure (given callback does not exist).

int add_callback_pri(Module *module, const char *name, callback_t callback, int priority)

Adds the given callback function to the given list with the given priority (a higher priority value means the function is called sooner). The priority must be between CBPRI_MIN and CBPRI_MAX inclusive. Returns nonzero on success, zero on failure (given callback does not exist or priority out of range). An error will not be returned if the same function is registered more than once, but this behavior is not supported and may change in the future.

int add_callback(Module *module, const char *name, callback_t callback)

Adds the given callback function to the given list with priority zero. This is a shortcut for add_callback_pri(module,name,callback,0), and the two forms are exactly equivalent.

int remove_callback(Module *module, const char *name, callback_t callback)

Removes the given callback function from the given list. Returns nonzero on success, zero on failure (given callback does not exist, given function is not on callback list).

6-1-2. Module loading and unloading

Modules are loaded through the load_module() function in modules.c. load_module() takes one parameter, the name of the module to load, and performs the following steps (assuming dynamically-compiled modules on a system with the dlXXX() family of functions):

  • Calls dlopen() for the module (the filename is the module name passed to load_module() with ".so" appended). If dlopen() fails, load_module() returns NULL.

  • Creates a module information structure (Module *) for the module and initializes it.

  • Checks the module's version code against the version code of the Services core; if the two do not match or a version number is not present in the module, load_module() frees the module information structure, calls dlclose() on the module and returns NULL. The version code is declared as
        int32 module_version = MODULE_VERSION_CODE;
    and must be exported by every module.

  • Parses the section of the modules.conf file for the module (if any), using the configuration directives in module_config[]. module_config[] must be defined as an array of ConfigDirective elements, terminated by an element with name == NULL. If any errors occur during parsing, load_module() frees the module information structure, calls dlclose() on the module and returns NULL.

  • Calls the module's init_module() function, passing the allocated module information structure. This function should return nonzero on success and zero on failure. If the function returns failure, load_module() frees the module information structure, calls dlclose() on the module and returns NULL.

  • Calls the load module callback, passing the module pointer to each function in the callback list.

  • Links the module information structure into the global module list and returns it.

The unload_module() function takes a pointer to the module structure (handle) for the module to unload, and performs the following steps:

  • Calls the module's exit_module() function. This function takes a single parameter, `int shutdown', which is 0 for a regular module unload and 1 if the program is shutting down. The function should return nonzero on success and zero on failure; if it returns failure, unload_module() returns zero (failure).

  • Calls the unload module callback, passing the module pointer to each function in the callback list.

  • Calls dlclose() for the module.

  • Unlinks the module information structure from the global list and returns nonzero (success).

6-1-3. Inter-module dependencies

Some modules may require functions from other modules to work correctly; for example, a module adding a new command to NickServ would obviously require NickServ itself to be loaded first. Such modules can use the find_module() function from modules.c to check whether the module has been loaded. An example might look like this:


int init_module(Module *me)
{
if (!find_module("nickserv/main"))
return 0;
...
return 1;
}

Modules should not attempt to load other modules themselves, as the administrator may have deliberately chosen not to include such modules. Instead, the module should fail to load, optionally writing a log message explaining the problem.

6-1-4. Callbacks

modules.c provides an interface for registering and calling callback functions. Callbacks are referred to by a combination of module and callback name or ID (callbacks in the Services core use a module pointer of NULL).

The type of a callback function is defined by callback_t: int (*)(...). The parameters passed to the function depend on the particular callback. If a callback function desires to terminate processing of the callback list, it should return a nonzero value; returning zero will allow the next function in the list to be called. Any pointer parameters should be considered "const" (unmodifiable) unless the function processes the event and returns nonzero.

To add a callback function to a callback list registered by another module (or a callback list defined by the Services core), use the add_callback() function (or add_callback_pri() if you want to use a priority other than zero; priorities are used to determine the order in which the functions are called, as described below). To remove a function previously added to a callback list, use the remove_callback() function. It is legal to attempt to remove a callback function which was not added in the first place; remove_callback() will return failure in this case.

To create your own callback list, use the register_callback() function; to delete it, call the unregister_callback() function, passing in the callback ID returned from register_callback(). To call a list of callback functions, use the call_callback_X() set of functions, where X is the number of parameters passed to each callback function (the _X is omitted if no parameters are passed). This syntax is used to help module creators double-check that the right number of parameters are being passed to callback functions, since such functions cannot be checked against prototypes.

Callback functions are called in descending order of priority (so, for example, a priority-1 function is called before a priority-0 one); functions with the same priority are called in the same order they were added to the callback list.

See section 6-2 below for a list of available callbacks.

6-1-5. Using external functions and variables

Modules can access functions and variables defined in the Services core or other modules just as in a normal program, by #include'ing the appropriate header file (or explicitly declaring the symbols "extern", though using a header file is preferable because it ensures the symbols are declared the same way in all source files). The symbol references will be resolved to addresses when the program is loaded.

However, since an undefined symbol will cause the module to f