==== CtrlProxy developer documentation ==== Written by Jelmer Vernooij, 2003 Updated October 2005 General ------- The core of ctrlproxy is in the top source directory, standard module are in mods/. Here's what the core files do: cache.c - Caches and sends cached network state info client.c - Maintains connections to clients gen_config.c - Generates configuration file from current network state hooks.c - Handles calling hooks for various things (connect/disconnect/message) isupport.c - Maintains information about capabilities of server line.c - Parse / generate IRC messages linestack.c - Store lines / network state for later retrieval log.c - Logging main.c - main() network.c - Maintains connection to network plugins.c - Handles loading/unloading of plugins posix.c - POSIX support functions redirect.c - Send message received from server to the right clients repl.c - Replication support (sends JOIN/TOPIC messages to client from server state) settings.c - Configuration state.c - Maintains network state information (what users on which channel, etc) util.c - Random utility functions Writing Modules --------------- As has been said in the introduction, ctrlproxy is easily extendible. At the time of writing, there are nine modules available. The simplest possible module would be: #include gboolean init_plugin(struct plugin *p) { /* Do something */ return TRUE; } gboolean fini_plugin(struct plugin *p) { /* Free my structures here */ return TRUE; } The init_plugin function is called when the module is loaded. In this function, you should register whatever functions the module provides, such as a 'message handler' or a linestack backend. You can use the data member of the plugin struct to store data for your plugin. This function should return a boolean: false when initialisation failed or true when it succeeded. The fini_plugin function is called before the module is unloaded. In this function, you should free the data structures your module is using and make sure there are no other pointers in ctrlproxy pointing to functions or data structures from your module. For example, unregister hooks. The fini_plugin should return a boolean as well. This value should be true if the unloading may preceed, or false if there are reasons ctrlproxy should not attempt to unload the module (such as resources that are currently in use, etc). Building and installing ----------------------- A module is in fact a shared library that's loaded at run-time, when the program is already running. The .so file can compiled with a command like: $ gcc -shared -o foo.so input1.c input2.o input3.c Message handler functions ------------------------- A message handling function is a function that is called whenever ctrlproxy receives an IRC message. The only argument this function should have would be a line struct. Flags can be set on the line (the field in the struct to use is called 'options') to influence the handling of the packet by the rest of ctrlproxy. There is one other option that can be specified, but is only useful when sending your own messages: LINE_IS_PRIVATE Do not send this line to other clients currently connected. Registering a message handler ----------------------------- All IRC lines that ctrlproxy receives and sends are passed thru so-called 'filter functions'. These functions can do things based on the contents of these lines, change the lines or stop further processing of these lines. To add a filter function, call 'add_filter'. To remove the filter function again (usually when your plugin is being unloaded) call 'del_filter'. Example: ... add_filter("my_module", my_message_handler); ... The prototype for the message handling function in the example above would look something like this: static gboolean my_message_handler(struct line *l); Your message handler should return TRUE if the rest of the filter functions should also see the message and FALSE if ctrlproxy should stop running filter functions on the given line struct. These hooks are executed before the data as returned by find_channel() and find_nick() is updated Registering a new client/server or lose client/server handler ------------------------------------------------------------- A module can also register a function that should be called when a new client connects or when a client disconnects and when the server has successfully connected to the client or when the connection to the client is broken. typedef gboolean (*new_client_hook) (struct client *); typedef void (*lose_client_hook) (struct client *); void add_new_client_hook(char *name, new_client_hook h); void del_new_client_hook(char *name); void add_lose_client_hook(char *name, lose_client_hook h); void del_lose_client_hook(char *name); typedef void (*server_connected_hook) (struct network *); typedef void (*server_disconnected_hook) (struct network *); void add_server_connected_hook(char *name, server_connected_hook); void del_server_connected_hook(char *name); void add_server_disconnected_hook(char *name, server_disconnected_hook); void del_server_disconnected_hook(char *name); The prototypes of these functions pretty much speak for themselves. If a new_client_hook function returns FALSE, the client will be denied access. Registering a initialization function ------------------------------------- The initialization hooks are called after ctrlproxy has been initialized - all plugins are loaded, all networks have been loaded. typedef void (*initialized_hook) (void); void add_initialized_hook(initialized_hook); Registering a MOTD function --------------------------- MOTD functions are functions that add one or more lines to the MOTD that is sent to a client. A module can register a MOTD function using the add_motd_hook() and del_motd_hook() functions, that work similar to the add_new_client_hook() and del_new_client_hook() functions documented above. A motd function should return a dynamically allocated array containing dynamically allocated nul-terminated strings that should be added to the MOTD. Log functionality ----------------- Ctrlproxy uses GLib's logging functions. Read the related section in the GLib documentation for details. Storing data ------------ Paths to data should be configurable, but default to the file/directory name returned by ctrlproxy_path(). The argument to this function should be the name of the subsystem. All top level directories have been created when this function returns. If NULL was returned, one or more directories could not be created. Debugging --------- Two very useful utilities are valgrind and gdb. If you're running from gdb, make sure you have set the following: handle SIGPIPE nostop handle SIGINT nostop Debug module ------------- The debug module, if compiled adds support for the following two admin commands, that might be useful when debugging: DUMPJOINEDCHANNELS Makes ctrlproxy print a list of the channels it thinks it has joined on the current network. CRASH Makes the current plugin crash. This is useful for testing the auto-unload-on-crash functionality.