The main source of XChat is in the /src directory. In it are all the .c and .h files that make up XChat. If you are looking round the code here's a little map:
Most of the other files are easy to guess.
Dagmar d'Surreal has written the documentation for writing scripts, in xchatdox2.html
There should be a sample module under the sample directory, this gives a general overview of writing a module.
Firstly you must #define USE_PLUGIN before any #includes. You must also include xchat.h and plugin.h from the xchat main directory. Every module must export a function called module_init, it is passed the version number (an int), a pointer to the module struct for your module and a pointer to the current session. It returns an int
The name and desc parts of the module structure must be filled out with strings.
You must check the version number is what you think it is (currently 2) before referencing anything else, the current version number is defined in plugin.h as MODULE_IFACE_VER.
The basic hook onto XChat, by a plugin, is a signal. At certain places in the code a signal is emitted. A chain of handlers (if any) are then called, each calling the next. If the first handler (and thus the handler that returns to the emitting function) returns TRUE then the emitting function doesn't carry out the default action. In this way a signal handler can over-right XChat's default actions with its own. Any module can hook a signal, using hook_signal and passing a pointer to an xp_signal struct, filling in the "signal", "callback", "naddr" and "mod" parts. They should be filled in like thus:
At the end of the callback you use XP_CALLNEXT(naddrfunction, a, b, c, d, e, f) to call the next callback, a to f being the arguments you were passed. The plugin code in XChat updates the function pointed to by the "naddr" field to point to the next handler, or NULL if you are the last handler. You don't have to worry about that. If you don't want the default action to take place then use XP_CALLNEXT_ANDSET() not XP_CALLNEXT. Only 1 handler in a chain needs to use XP_CALLNEXT_ANDSET to abort the default action. Be aware that XP_CALLNEXT[_ANDSET] expand to include a return, so these must be at the end of the execution paths of your handler.
The signal handlers are passed 5 void *'s and a char (just seemed about enough), by convention the first void * is a pointer to the session or server struct. To cast as a signal callback