XChat 2.0 Plugin Interface
plugin20.html revision
0.99
Latest version of this document is available at: http://xchat.org/docs/plugin20.html
Information:
Introduction
Sample plugin
What is word and
word_eol?
Lists and fields
Plugins on Windows
(Win32)
Controlling the GUI
Functions:
xchat_hook_command
xchat_hook_fd
xchat_hook_print
xchat_hook_server
xchat_hook_timer
xchat_unhook
xchat_command
xchat_commandf
xchat_print
xchat_printf
xchat_emit_print
xchat_find_context
xchat_get_context
xchat_get_info
xchat_get_prefs
xchat_set_context
xchat_nickcmp
xchat_list_get
xchat_list_free
xchat_list_fields
(not documented yet)
xchat_list_next
xchat_list_str
xchat_list_int
xchat_list_time
xchat_plugingui_add
(not documented yet)
xchat_plugingui_remove
(not documented yet)
Plugins for XChat are written in C. The
interface aims to keep 100% binary compatability. This means that if you upgrade
XChat, you will not need to recompile your plugins, they'll continue to work.
The interface doesn't depend on any structures and offsets, so compiler versions
shouldn't have an impact either. The only real requirement of an XChat plugin,
is that it define a "xchat_plugin_init" symbol. This is your entry point
function, see the example below. You should make all your global variables and
functions static, so that a symbol is not exported. There is no harm in
exporting these symbols, but they are not necessary and only pollute the
name-space. Plugins are compiled as shared objects (.so files), for example: gcc -Wall -O1 -shared myplugin.c -o myplugin.so
See the Windows
section on how to compile a plugin using visual studio.
All strings passed to and from plugins are encoded in UTF-8, regardless of
locale.
This simple plugin autoOps anyone who
joins a channel you're in. It also adds a new command /AUTOOPTOGGLE, which can
be used to turn the feature ON or OFF. Every XChat plugin must define an
xchat_plugin_init function, this is the normal entry point. xchat_plugin_deinit
is optional.
#include "xchat-plugin.h"
static xchat_plugin *ph; /* plugin handle */
static int enable = 1;
static int join_cb(char *word[], void *userdata)
{
if (enable)
/* Op ANYONE who joins */
xchat_commandf(ph, "OP %s", word[1]);
/* word[1] is the nickname, as in the Settings->Lists->EventTexts window in xchat */
return XCHAT_EAT_NONE; /* don't eat this event, xchat needs to see it! */
}
static int autooptoggle_cb(char *word[], char *word_eol[], void *userdata)
{
if (!enable)
{
enable = 1;
xchat_print(ph, "AutoOping now enabled!\n");
} else
{
enable = 0;
xchat_print(ph, "AutoOping now disabled!\n");
}
return XCHAT_EAT_ALL; /* eat this command so xchat and other plugins can't process it */
}
int xchat_plugin_init(xchat_plugin *plugin_handle,
char **plugin_name,
char **plugin_desc,
char **plugin_version,
char *arg)
{
/* we need to save this for use with any xchat_* functions */
ph = plugin_handle;
*plugin_name = "AutoOp";
*plugin_desc = "Auto Ops anyone that joins";
*plugin_version = "0.1";
xchat_hook_command(ph, "AutoOpToggle", XCHAT_PRI_NORM, autooptoggle_cb,
"Usage: AUTOOPTOGGLE, Turns OFF/ON Auto Oping", 0);
xchat_hook_print(ph, "Join", XCHAT_PRI_NORM, join_cb, 0);
xchat_print(ph, "AutoOpPlugin loaded successfully!\n");
return 1; /* return 1 for success */
}
They are arrays of strings.
They contain the parameters the user entered for the particular command. For
example, if you executed: /command NICK hi there
word[1] is command
word[2] is NICK
word[3] is hi
word[4] is there
word_eol[1] is command NICK hi there
word_eol[2] is NICK hi there
word_eol[3] is hi there
word_eol[4] is there
These arrays are simply provided for your convenience. You are NOT allowed
to alter them. Both arrays are limited to 32 elements (index 31). word[0] and
word_eol[0] are reserved and should not be read.
Lists of information (DCCs, Channels,
Userlist etc) can be retreived with xchat_list_get. All fields are READ ONLY and
must be copied if needed for a long time after calling xchat_list_str. The types
of lists and fields available are:
"channels" - list of channels, querys and their servers.
| Name |
Description |
Type |
| channel |
Channel or query name |
string |
| context |
(xchat_context *) pointer. Can be used with xchat_set_context |
string |
| network |
Network name to which this channel belongs (Added in
version 2.0.2. Older versions will return NULL) |
string |
| server |
Server name to which this channel belongs |
string |
| type |
Type of context this is: 1-Server 2-Channel
3-Dialog (Added in version 2.0.2. Older versions will return
-1) |
int |
"dcc" - list of DCC file
transfers. Fields:
| Name |
Description |
Type |
| address32 |
Address of the remote user (ipv4 address) |
int |
| cps |
Bytes per second (speed) |
int |
| destfile |
Destination full pathname |
string |
| file |
File name |
string |
| nick |
Nickname of person who the file is from/to |
string |
| port |
TCP port number |
int |
| pos |
Bytes sent/received |
int |
| resume |
Point at which this file was resumed (or zero if it was not
resumed) |
int |
| size |
File size in bytes |
int |
| status |
DCC Status: 0-Queued 1-Active 2-Failed 3-Done 4-Connecting
5-Aborted |
int |
| type |
DCC Type: 0-Send 1-Receive 2-ChatRecv 3-ChatSend |
int |
"ignore" - current ignore list.
| Name |
Description |
Type |
| mask |
Ignore mask. .e.g: *!*@*.aol.com |
string |
| flags |
Bit field of flags. 0=Private 1=Notice 2=Channel
3=Ctcp 4=Invite 5=UnIgnore 6=NoSave 7=DCC |
int |
"notify" - list of people on
notify.
| Name |
Description |
Type |
| nick |
Nickname |
string |
| flags |
0=Is online. |
int |
| on |
Time when user came online. |
time_t |
| off |
Time when user went offline. |
time_t |
| seen |
Time when user the user was last verified still online. |
time_t |
The entire "notify" list was
added in xchat 2.0.8. Fields are only valid for the context when
xchat_list_get() was called (i.e. you get information about the user ON THAT
ONE SERVER ONLY). You may cycle through the "channels" list to find notify
information for every server.
"users" - list of users in
the current channel.
| Name |
Description |
Type |
| away |
Away status (boolean) (Added in version 2.0.6. Older
versions will return -1) |
int |
| nick |
Nick name |
string |
| host |
Host name in the form: user@host (or NULL if not known). |
string |
| prefix |
Prefix character, .e.g: @ or +. Points to a single char. |
string |
Example:
list = xchat_list_get(ph, "dcc");
if(list)
{
xchat_print(ph, "--- DCC LIST ------------------\n"
"File To/From KB/s Position\n");
while(xchat_list_next(ph, list))
{
xchat_printf(ph, "%6s %10s %.2f %d\n",
xchat_list_str(ph, list, "file"),
xchat_list_str(ph, list, "nick"),
xchat_list_int(ph, list, "cps") / 1024,
xchat_list_int(ph, list, "pos"));
}
xchat_list_free(ph, list);
}
Yes, it can be done. All
you need is either MSVC (Visual Studio) or MINGW. Simply compile your plugin as a DLL. You
should have the following files:
- xchat-plugin.h - Main
Plugin header
- plugin.c - Your plugin, you need to write this one :)
- plugin.def - A simple text file containing the following:
EXPORTS
xchat_plugin_init
xchat_plugin_deinit
Leave out xchat_plugin_deinit if you
don't intend to define that function. Then, to compile: cl -O1 -MD -G5 -DWIN32 -c plugin.c
link /DLL /out:plugin.dll /SUBSYSTEM:WINDOWS plugin.obj /def:plugin.def
For a complete example, have a look at the source code of the DNS Plugin, which also
contains a Makefile.
Caveat: Plugins compiled on
Win32 MUST have a global variable called ph, which is the plugin_handle,
much like in the sample
plugin above.
A simple way to perform basic GUI functions is to use the /GUI command. You
can execute this command through the input-box, or by calling xchat_command(ph,
"GUI .....");.
| GUI HIDE |
Hide the main xchat window completely (this is used by the Systray
plugin). |
| GUI SHOW |
Show it again. |
| GUI FOCUS |
Focus the current window or tab. |
| GUI FLASH |
Flash the taskbar button (win32 only). It will flash only if the
window isn't focused and will stop when it is focused by the user. |
| GUI COLOR n |
Change the tab color of the current context, where n is a number
from 0 to 3. |
Note, the FLASH and COLOR
args were added in xchat 2.0.8, they will not work with previous versions.
Functions
Prototype:
xchat_hook *xchat_hook_command(xchat_plugin *ph, char *name, int pri,
xchat_cmd_cb *callb, char *help_text, void *userdata);
Description: Adds a new /command. This allows your program to
handle commands entered at the input box. To capture text without a "/" at the
start (non-commands), you may hook a special name of "". i.e
xchat_hook_command(ph, "", ...);.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
name: Name of the command (without the forward slash).
pri: Priority of this command. Use XCHAT_PRI_NORM.
callb: Callback function. This will be called when the user
executes the given command name.
help_text: String of text to
display when the user executes /help for this command. May be NULL if you're
lazy.
userdata: Pointer passed to the callback
function.
Returns: Pointer to the hook. Can be passed to
xchat_unhook.
Example:
static int onotice_cb(char *word[], char *word_eol[], void *userdata)
{
if(word_eol[2][0] == 0)
{
xchat_printf(ph, "Second arg must be the message!\n");
return XCHAT_EAT_ALL;
}
xchat_commandf(ph, "NOTICE @%s :%s", xchat_get_info(ph, "channel"), word_eol[2]);
return XCHAT_EAT_ALL;
}
xchat_hook_command(ph, "ONOTICE", XCHAT_PRI_NORM, onotice_cb,
"Usage: ONOTICE <message> Sends a notice to all ops", NULL);
Prototype:
xchat_hook *xchat_hook_fd(xchat_plugin *ph, int fd, int flags, xchat_fd_cb
*callb, void *userdata);
Description: Hooks a socket or file
descriptor.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
fd: The file descriptor or socket.
flags: One or more of
XCHAT_FD_READ, XCHAT_FD_WRITE, XCHAT_FD_EXCEPTION, XCHAT_FD_NOTSOCKET. Use
bitwise OR to combine them. XCHAT_FD_NOTSOCKET tells xchat that the provided
fd is not a socket, but a file descriptor. This is only relevant on
Windows, where network sockets are distinguished from file descriptors (such
as pipes).
callb: Callback function. This will be called when the
socket is available for reading/writing or exception (depending on your chosen
flags)
userdata: Pointer passed to the callback
function.
Returns: Pointer to the hook. Can be passed to
xchat_unhook.
Prototype:
xchat_hook *xchat_hook_print(xchat_plugin *ph, char *name, int
pri, xchat_print_cb *callb, void *userdata);
Description:
Registers a function to trap any print events. The event names may be any
available in the "Edit Event Texts" window. There are also some extra "special"
events you may hook using this function. Currently they are:
"Open Context" - Called when a new xchat_context is created.
"Close Context" - Called when a xchat_context pointer is closed.
"Focus Tab" - Called when a tab is brought to front.
"Focus Window" -
Called a toplevel window is focused, or the main tab-window is focused by the
window manager.
"DCC Chat Text" - Called when some text from a DCC Chat
arrives. It provides these elements in the word[] array:
word[1] Address
word[2] Port
word[3] Nick
word[4]
The Message
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
name: Name of the print event (as in Edit Event Texts Window).
pri: Priority of this command. Use XCHAT_PRI_NORM.
callb: Callback function. This will be called when this event name
is printed.
userdata: Pointer passed to the callback
function.
Returns: Pointer to the hook. Can be passed to
xchat_unhook.
Example:
static int youpart_cb(char *word[], void *userdata)
{
xchat_printf(ph, "You have left channel %s\n", word[3]);
return XCHAT_EAT_XCHAT; /* dont let xchat do its normal printing */
}
xchat_hook_print(ph, "You Part", XCHAT_PRI_NORM, youpart_cb, NULL);
Prototype:
xchat_hook *xchat_hook_server(xchat_plugin *ph, char *name, int pri,
xchat_serv_cb *callb, void *userdata);
Description: Registers a
function to be called when a certain server event occurs. You can use this to
trap PRIVMSG, NOTICE, PART, a server numeric etc... If you want to hook every
line that comes from the IRC server, you may use the special name of "RAW LINE".
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
name: Name of the server event.
pri: Priority of this
command. Use XCHAT_PRI_NORM.
callb: Callback function. This will be
called when this event is received from the server.
userdata:
Pointer passed to the callback function.
Returns: Pointer to
the hook. Can be passed to xchat_unhook.
Example:
static int kick_cb(char *word[], char *word_eol[], void *userdata)
{
xchat_printf(ph, "%s was kicked from %s (reason=%s)\n", word[4], word[3], word_eol[5]);
return XCHAT_EAT_NONE; /* don't eat this event, let other plugins and xchat see it too */
}
xchat_hook_server(ph, "KICK", XCHAT_PRI_NORM, kick_cb, NULL);
Prototype:
xchat_hook *xchat_hook_timer(xchat_plugin *ph, int timeout, xchat_timer_cb
*callb, void *userdata);
Description: Registers a function to be
called every "timeout" milliseconds.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
timeout: Timeout in milliseconds (1000 is 1 second).
callb: Callback function. This will be called every "timeout"
milliseconds.
userdata: Pointer passed to the callback
function.
Returns: Pointer to the hook. Can be passed to
xchat_unhook.
Example:
static xchat_hook *myhook;
static int stop_cb(char *word[], char *word_eol[], void *userdata)
{
if(myhook != NULL)
{
xchat_unhook(ph, myhook);
myhook = NULL;
xchat_print(ph, "Timeout removed!\n");
}
return XCHAT_EAT_ALL;
}
static int timeout_cb(void *userdata)
{
xchat_print(ph, "Annoying message every 5 seconds! Type /STOP to stop it.\n");
return 1; /* return 1 to keep the timeout going */
}
myhook = xchat_hook_timer(ph, 5000, timeout_cb, NULL);
xchat_hook_command(ph, "STOP", XCHAT_PRI_NORM, stop_cb, NULL, NULL);
Prototype: void
*xchat_unhook(xchat_plugin *ph, xchat_hook *hook);
Description:
Unhooks any hook registered with xchat_hook_print/server/timer/command.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
hook: Pointer to the hook, as returned by xchat_hook_*.
Returns: The userdata you originally gave to
xchat_hook_*.
Prototype: void
xchat_command(xchat_plugin *ph, char *command);
Description:
Executes a command as if it were typed in xchat's input box.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
command: Command to execute, without the forward slash "/".
Prototype: void
xchat_commandf(xchat_plugin *ph, char *format, ...);
Description:
Executes a command as if it were typed in xchat's input box and provides string
formating like printf.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
format: The format string.
Prototype: void
xchat_print(xchat_plugin *ph, char *text);
Description: Prints
some text to the current tab/window.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
text: Text to print. May contain mIRC color codes.
Prototype: void
xchat_printf(xchat_plugin *ph, char *format, ...);
Description:
Prints some text to the current tab/window and provides formating like printf.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
format: The format string.
Prototype:
int xchat_emit_print(xchat_plugin *ph, char *event_name, ...);
Description: Generates a print event. This can be any event found
in the Preferences > Lists > Text Events window.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
event_name: Text event to print.
Returns:
1-Success 0-Failure.
Example: xchat_emit_print(ph, "Channel Message", "John", "Hi there", "@", NULL);
Prototype:
xchat_context *xchat_find_context(xchat_plugin *ph, char *servname, char
*channel);
Description: Finds a context based on a channel and
servername. If servname is NULL, it finds any channel (or query) by the given
name. If channel is NULL, it finds the front-most tab/window of the given
servname. If NULL is given for both arguments, the currently focused tab/window
will be returned.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
servname: Servername or NULL.
channel: Channelname or
NULL.
Returns: Context pointer (for use with
xchat_set_context) or NULL.
Prototype:
xchat_context *xchat_get_context(xchat_plugin *ph);
Description:
Returns the current context for your plugin. You can use this later with
xchat_set_context.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
Returns: Context pointer (for use with
xchat_set_context).
Prototype: const
char *xchat_get_info(xchat_plugin *ph, char *id);
Description:
Returns information based on your current context.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
id: ID of the information you want. Currently supported IDs are
(case sensitive):
| away |
away reason or NULL if you are not away. |
| channel |
current channel name. |
| host |
real hostname of the server you connected to. |
| network |
current network name or NULL. |
| nick |
your current nick name. |
| server |
current server name (what the server claims to be). NULL if you
are not connected. |
| topic |
current channel topic. |
| version |
xchat version number. |
| xchatdir |
xchat config directory, e.g.:
/home/user/.xchat. |
Returns:
A string of the requested information, or NULL. This string must not be freed
and must be copied if needed after the call to xchat_get_info.
Prototype: int
xchat_get_prefs(xchat_plugin *ph, const char *name, const char **string, int
*integer);
Description: Provides xchat's setting information
(that which is available through the /set command).
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
name: Setting name required.
string: Pointer-pointer
which to set.
integer: Pointer to an integer to set, if setting is
a Boolean or Integer type.
Returns: 0-Failed 1-Returned a
string 2-Returned an Integer 3-Returned a Boolean.
Example:
{
int i;
const char *str;
if (xchat_get_prefs (ph, "irc_nick1", &str, &i) == 1)
{
xchat_printf (ph, "Current nickname setting: %s\n", str);
}
}
Prototype:
int xchat_set_context(xchat_plugin *ph, xchat_context *ctx);
Description: Changes your current context to the one given.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
ctx: Context to change to (obtained with xchat_get_context or
xchat_find_context).
Returns: 1 for success, 0 for
failure.
Prototype: int
xchat_nickcmp(xchat_plugin *ph, char *s1, char *s2);
Description:
Performs a nick name comparision, based on the current server connection. This
might be a RFC1459 compliant string compare, or plain ascii (in the case of
DALNet). Use this to compare channels and nicknames. The function works the same
way as strcasecmp.
Arguments:
ph: Plugin handle (as given to xchat_plugin_init).
s1: String to compare.
s2: String to compare s1 to.
Quote from RFC1459:
Because of IRC's scandanavian origin, the characters {}| are
considered to be the lower case equivalents of the characters []\,
respectively. This is a critical issue when determining the equivalence of two
nicknames.
Returns: An integer less than, equal to, or
greater than zero if s1 is found, respectively, to be less than, to match, or be
greater than s2.