Hook documentation #
Hooks allow modules to execute logic during predefined spots of other module
code or core code. Each function attached to a hook is passed a data pointer
containing contextual information to assist with any logic that function may
need to perform. For examples on how to register a hook function with a
module or define a new hook in a module, see extensions/example_module.c.
Hook list #
| Module | Hook name | Description |
|---|---|---|
| Core | after_client_exit | A user has left the server |
| Core | burst_channel | A channel was sent to a remote server during a netjoin |
| Core | burst_client | A user was sent to a remote server during a netjoin |
| Core | burst_finished | We finished bursting users/channels during a netjoin |
| Core | can_join | A local user is about to join a channel |
| Core | can_kick | A user is about to be kicked from a channel |
| Core | can_send | Called when checking if a user can talk on a channel |
| Core | cap_change | A user's client capabilities changed |
| Core | client_exit | A user is leaving the server |
| Core | conf_read_end | Called after reading conf files on start or rehash |
| Core | conf_read_start | Called before reading conf files on start or rehash |
| Core | get_channel_access | Called when checking a user's privileges on a channel |
| Core | introduce_client | A user has been introduced to the rest of the network |
| Core | message_handler | Determine the handler used to process an incoming message |
| Core | message_tag | Called for each tag on incoming messages |
| Core | new_local_user | A user connected locally, before introducing to network |
| Core | new_remote_user | A remote user was introduced, before propagating onward |
| Core | outbound_msgbuf | A message is about to be sent to one or more targets |
| Core | parse_end | We have finished processing an incoming message |
| Core | priv_change | An oper's privset changed |
| Core | privmsg_channel | A message or PART is about to be sent to a channel |
| Core | privmsg_user | A message is about to be sent to a user |
| Core | rehash | The server finished rehashing its conf files |
| Core | server_introduced | A server has been introduced to the network (pre-burst) |
| Core | server_eob | A server has finished processing a netjoin burst from us |
| Core | umode_changed | The modes for a user have changed |
| Core | user_welcome | Called during the registration burst for a new local user |
| m_info | doing_info_conf | Conf entries have been sent to an oper using INFO |
| m_invite | can_invite | A local user is about to invite another user to a channel |
| m_invite | invite | A local user is about to be invited to a channel |
| m_join | can_create_channel | A user is about to create a channel |
| m_join | channel_join | A user has finished joining a channel |
| m_join | channel_lowerts | A remote server gave us a lower TS for a channel |
| m_kill | can_kill | A local oper is about to kill a user |
| m_monitor | new_monitor | A user has added a new entry to their MONITOR list |
| m_nick | local_nick_change | A local user has changed nicknames |
| m_nick | remote_nick_change | A remote user has changed nicknames |
| m_quit | client_quit | A user has quit from the network |
| m_services | account_change | A user's services account has changed |
| m_stats | doing_stats | A user has run STATS |
| m_stats | doing_stats_show_idle | Called to determine if send/recv data is shown in STATS l |
| m_trace | doing_trace_show_idle | Called to determine if timestamp data is shown in TRACE |
| m_version | doing_version_confopts | Called before sending confopts in VERSION |
| m_who | doing_who_show_idle | Called to determine if idle time is shown in WHOX |
| m_whois | doing_whois | A local user has run WHOIS |
| m_whois | doing_whois_channel_visibility | Called to determine which channels to display in WHOIS |
| m_whois | doing_whois_global | A user has run a remote WHOIS targeting this server |
| m_whois | doing_whois_show_idle | Called to determine if idle time is shown in WHOIS |
Registering hook functions #
To register a function to be called when a hook is executed, you will need to
create an mapi_hfn_list_av1[] in your module. Each element of the array
contains the following, in order:
- The name of the hook as a string. This hook name does not need to exist at the time of registration. If the hook doesn't exist and is later defined, the hook function will still be called.
- The function to execute. The function takes a single
void *parameter and has avoidreturn value. - Optionally, a hook priority. There are six priority levels defined:
HOOK_LOWEST,HOOK_LOW,HOOK_NORMAL,HOOK_HIGH,HOOK_HIGHEST, andHOOK_MONITOR. Hooks are executed in order of lowest to highest priority withHOOK_MONITORbeing executed last. If unspecified, normal priority is used.
The final array element must contain a NULL hook name, to indicate the end
of the array. This array is then passed into the DECLARE_MODULE_AV2 macro.
Registering new hooks #
A module can state that it is registering additional hooks that it will call
internally. To do so, you will need to create an mapi_hlist_av1[] in your
module. Each element of the array contains the following, in order:
- The name of the hook as a string. It is possible to register the same hook name multiple times across different modules without error. Should this happen, all modules registering that hook will share the same registration and hook function list.
- An
int *to store the hook registration number. This pointer should be declared as astatic intat the file scope of the module.
The final array element must contain a NULL hook name, to indicate the end
of the array. This array is then passed into the DECLARE_MODULE_AV2 macro.
Calling hooks #
If a module wishes to call a hook, it uses the call_hook() function declared
in include/hook.h. It passes the integer registration number of the hook to
this function along with the data pointer to be passed to hook functions.
When calling an existing hook, check the documentation below to ensure that the data pointer you are passing is compatible with the documented usage elsewhere, to avoid crashing other modules with unexpected data.
Example:
/* File scope (DECLARE_MODULE_AV2 omitted for brevity): */
static int h_doing_whois;
mapi_hlist_av1[] my_module_hlist = {
{ "doing_whois", &h_doing_whois },
{ NULL, NULL }
};
/* Inside of some relevant function: */
hook_data_client hdata;
hdata.client = source_p;
hdata.target = target_p;
call_hook(h_doing_whois, &hdata);
Hook data structures #
Most of the time, the data pointer passed to hook functions is one of the
various structures defined in include/hook.h. This is not always the case,
so consult the documentation for the specific hook to find out what it passes
for its data pointer, how it populates its fields, and whether data can flow
back to the calling module.
When defining a new hook, pick one of the predefined structures to use for your data whenever possible. Think about the interaction model you want between hooked functions and your module, such as if you want other modules to be able to pass data back to you by modifying any of the field values.
Hook details #
account_change #
This hook is called after a user's services user (account name) has changed. The user may be either local or remote. This hook is not called when a user's services account changes during registration.
Hook data: hook_cdata *
Fields:
- client (
struct Client *): The user whose services account changed - arg1 (
const char *): The user's previous services account - arg2 (
const void *): Unused (alwaysNULL)
The user's updated account is available via client->user->suser. If the
user was previously logged out, arg1 will be an empty string. If the user
just logged out, then client->user->suser will be an empty string.
Although unlikely, it is possible for the old and updated account names to be
identical or vary only by casing; no checks are made for this before invoking
the hook. Hook functions that need to operate only if the services account
meaningfully changed should compare the two strings via irccmp().
after_client_exit #
This hook is called after any client (user or server) exits the network. All
cleanup has happened for this client already. If the client is local, it has
been placed on the dead_list. Remote clients are not added to dead_list.
Hook data: always NULL
Given the lack of hook data, if you need to perform cleanup on the specific
client that is exiting, use the client_exit hook instead. The
after_client_exit hook is suitable if you need to investigate global state
after cleanup has been performed in order to carry out some logic.
burst_client #
This hook is called once for each client we send to another server during a netjoin burst. The client has already been introduced to the remote server before the hook is called.
Hook data: hook_data_client *
Fields:
- client (
struct Client *): The server we are sending the burst to - target (
struct Client *): The client (user or server) we are bursting
burst_channel #
This hook is called once for each channel we send to another server during a netjoin burst (n.b. local-only '&' channels are not sent during bursts). The channel and its member list have already been sent to the remote server before the hook is called.
Hook data: hook_data_channel *
Fields:
- client (
struct Client *): The server we are sending the burst to - chptr (
struct Channel *): The channel we are bursting - approved (
int): Unused (always 0)
burst_finished #
This hook is called after we have finished bursting all clients and channels. We have not yet sent the end of burst marker to the remote server at the time this hook is called.
Hook data: hook_data_client *
Fields:
- client (
struct Client *): The server we have sent the burst to - target (
struct Client *): Unused (alwaysNULL)
This hook is ideal for other data that needs to be sent to a remote server during a netjoin burst, e.g. new global channel types added by modules since core code only bursts '#' channels.
can_create_channel #
This hook is called when a local user attempts to JOIN a nonexistent
channel. Hook functions can reject the channel creation attempt by modifying
the passed-in data.
Hook data: hook_data_can_create_channel *
Fields:
- client (
struct Client *): The user attempting to create the channel - name (
const char *): The channel name the user is attempting to create - approved (
int): Output field indicating whether this attempt succeeds
The hook function should modify the approved field according to whether the
channel creation attempt should succeed or the error that should be sent to
the user should it not succeed. The following values are recognized:
- 0 (default): Allow the channel creation
ERR_BADCHANNELKEY: Prevent the channel creation and send the user a message that they have an incorrect channel key (+k)ERR_BANNEDFROMCHAN: Prevent the channel creation and send the user a message that they are banned from the channel (+b)ERR_CHANNELISFULL: Prevent the channel creation and send the user a message that the channel has reached its user limit (+l)ERR_CUSTOM: Prevent the channel creation and do not send any message to the userERR_INVITEONLYCHAN: Prevent the channel creation and send the user a message that the channel is invite only (+i)ERR_NEEDREGGEDNICK: Prevent the channel creation and send the user a message that a registered nickname is required to join (+r)ERR_THROTTLE: Prevent the channel creation and send the user a message that the join throttle was exceeded and that they should try again (+j)- Any other value: Prevent the channel creation and send the user a generic message that they cannot join the channel with the specified value as the numeric sent to the client. The numeric will additionally have the channel name as a parameter.
Sending a custom numeric as the value is not recommended as there is no
control over the number of parameters sent nor the error message. Care must be
taken to ensure any numeric sent is compatible with three parameters (client,
channel, and the generic error message "Cannot join channel"). It is better to
set it to ERR_CUSTOM and send an appropriate error message to the client
from within your hook function.
can_invite #
This hook is called when a local user invites another user (whether local or remote) into a channel. It is called even when the user does not have permissions to issue invites to the channel. However, if the source user is not on the channel, the invite attempt is rejected before this hook is called. Hook functions can allow or reject the invite attempt by modifying the passed-in data.
Hook data: hook_data_channel_approval *
Fields:
- client (
struct Client *): The user sending the INVITE - chptr (
struct Channel *): The channel that client is inviting target to - msptr (
struct membership *): The client's membership on chptr - target (
struct Client *): The user being invited - approved (
int): Output field indicating whether this attempt succeeds - dir (
int): Unused (always 0) - modestr (
const char *): Unused (alwaysNULL) - error (
const char *): Output field containing an optional error message to send to the user
The default value for approved is 0 if the client is a channel operator or
if the channel has the +g (free invite) channel mode set. Otherwise, the
default value is 1.
To approve the invite attempt, approved must be set to 0. If it is set to
any other value, how the caller behaves depends on whether error is also
set. If approved is nonzero and error is NULL, the invite attempt will
be rejected and the client will be sent the numeric ERR_CHANOPPRIVSNEEDED.
If approved is nonzero and error is not NULL, the invite attempt will be
rejected and the client will be sent the approved value as a numeric with
parameters contained in the error string (the client's nick is automatically
inserted as the first parameter and should not be present in the string).
Example:
/* reject all invite attempts with a custom message */
void can_invite_example(void *data_)
{
hook_data_channel_approval *data = data_;
char error[BUFSIZE];
snprintf(error, sizeof(error), "%s %s :%s",
data->target->name,
chptr->name,
"The INVITE command is disabled");
data->approved = ERR_USERONCHANNEL;
data->error = &error;
}
can_join #
This hook is called when checking whether a local user is able to join a channel. The target channel will always exist, although it may have just been created. Newly-created channels passed to this hook will have no members. Hook functions can allow or reject the join attempt by modifying the passed-in data.
Hook data: hook_data_channel *
Fields:
- client (
struct Client *): The local user attempting to join the channel - chptr (
struct Channel *): The channel being joined - approved (
int): Output field indicating whether this attempt succeeds
The hook function should modify the approved field according to whether the
join attempt should succeed or the error that should be sent to the user
should it not succeed. The following values are recognized:
- 0: Allow the join
ERR_BADCHANNELKEY: Prevent the join and send the user a message that they have an incorrect channel key (+k)ERR_BANNEDFROMCHAN: Prevent the join and send the user a message that they are banned from the channel (+b)ERR_CHANNELISFULL: Prevent the join and send the user a message that the channel has reached its user limit (+l)ERR_CUSTOM: Prevent the join and do not send any message to the userERR_INVITEONLYCHAN: Prevent the join and send the user a message that the channel is invite only (+i)ERR_NEEDREGGEDNICK: Prevent the join and send the user a message that a registered nickname is required to join (+r)ERR_THROTTLE: Prevent the join and send the user a message that the join throttle was exceeded and that they should try again (+j)- Any other value: Prevent the join and send the user a generic message that they cannot join the channel with the specified value as the numeric sent to the client. The numeric will additionally have the channel name as a parameter.
The default value for approved will be either 0 or one of the error numerics
specified above (except ERR_CUSTOM), depending on if any of them apply based
on the default logic which runs before the hook is called.
Sending a custom numeric as the value is not recommended as there is no
control over the number of parameters sent nor the error message. Care must be
taken to ensure any numeric sent is compatible with three parameters (client,
channel, and the generic error message "Cannot join channel"). It is better to
set it to ERR_CUSTOM and send an appropriate error message to the client
from within your hook function.
can_kick #
This hook is called when checking if a local user is able to kick a user (who may be either local or remote) from a channel. It is only called if the user has channel operator access to the channel (see also the get_channel_access hook) and the target is on the channel and is not a service (umode +S). Hook functions can reject the kick attempt by modifying the passed-in data.
Hook data: hook_data_channel_approval *
Fields:
- client (
struct Client *): The local user issuing the KICK - chptr (
struct Channel *): The channel the target is being kicked from - msptr (
struct membership *): The client's membership on chptr - target (
struct Client *): The user being kicked - approved (
int): Output field indicating whether this attempt succeeds - dir (
int): Always set toMODE_ADD(1) - modestr (
const char *): Unused (alwaysNULL) - error (
const char *): Unused (alwaysNULL)
The default value of approved is 1, which indicates that the kick is
allowed. Setting approved to 0 rejects the kick attempt. No error message is
sent to the client on a rejected attempt; it is up to the hook function to
send any appropriate error message. Any nonzero value also indicates that the
kick is allowed.
can_kill #
This hook is called when a local oper issues a kill for a user, who may be either local or remote. It is only called after verifying that the oper has the oper:kill privilege. Hook functions can reject the kill attempt by modifying the passed-in data.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The oper issuing the kill - target (
struct Client *): The user being killed - approved (
int): Output field indicating whether this attempt succeeds
The default value of approved is 1, which indicates that the kill is
allowed. Setting approved to 0 rejects the kill attempt. No error message is
sent to the client on a rejected attempt; it is up to the hook function to
send any appropriate error message. Any nonzero value also indicates that the
kill is allowed.
can_send #
This hook is called whenever the server needs to check if a user can send a message to a channel, e.g. a PRIVMSG, NOTICE, TAGMSG, TOPIC change, or PART reason. This hook is only called for local users with respect to TOPIC and PART, but is called for both local and remote users for PRIVMSG, NOTICE, and TAGMSG. This hook is not called if the user is not a member of the channel, even if the channel allows external messages (-n). Hook functions can allow or reject the ability to send the message by modifying the passed-in data.
Hook data: hook_data_channel_approval *
Fields:
- client (
struct Client *): The user sending the message - chptr (
struct Channel *): The channel the message is being sent to - msptr (
struct membership *): The client's membership on chptr - target (
struct Client *): Unused (alwaysNULL) - approved (
int): Output field indicating whether this attempt succeeds - dir (
int): Set toMODE_QUERY(0) if default logic indicates the user is allowed to send to the channel andMODE_ADD(1) if default logic indicates the user cannot send to the channel - modestr (
const char *): Unused (alwaysNULL) - error (
const char *): Unused (alwaysNULL)
The hook function should modify approved to indicate whether the user is
allowed to send a message to the channel. The following values are allowed:
CAN_SEND_NO: The user is not allowed to send messages to the channel. This is the default value if the user is not opped or voiced on the channel and at least one of the following criteria is met:- The channel is moderated (+m)
- The user is banned or quieted from the channel
- The user is joined to a RESVed channel and is not an oper with the oper:general privilege and is not RESV exempt from their I-line
CAN_SEND_NONOP: The user is allowed to send messages to the channel. Flood and target change controls will apply to the message. This is the default value when none of the criteria in the other two values are met.CAN_SEND_OPV: The user is allowed to send messages to the channel. Flood and target change controls do not apply to the message. This is the default value when the user is opped or voiced on the channel.
cap_change #
This hook is called after successfully processing a CAP REQ command from a local user. The CAP ACK reply has already been sent to the user by the time this hook is called. This hook is not called if the request is unsuccessful (meaning a CAP NAK was sent to the user).
Hook data: hook_data_cap_change *
Fields:
- client (
struct Client *): The user who requested caps - oldcaps (
int): Bitfield of caps the user had before this request - add (
int): Bitfield of caps that this request added - del (
int): Bitfield of caps that this request removed
channel_join #
This hook is called after a local user joins a channel. It is not called for remote users. It is called after the TOPIC and NAMES listing have been sent to the user and the JOIN has been sent to all other members of the channel.
Hook data: hook_data_channel_activity *
Fields:
- client (
struct Client *): The local user who joined the channel - chptr (
struct Channel *): The channel being joined - key (
const char *): The key the user specified when joining the channel orNULLif the user did not specify a key
The key does not necessarily match any key specified by the +k channel mode, since the can_join hook may have permitted a join despite having an invalid or missing key. Additionally, a key may be present in the hook data even if the channel is -k.
channel_lowerts #
This hook is called after the server receives a JOIN or SJOIN message for
a remote user with a lower channel timestamp than what the server has for the
channel.
Hook data: hook_data_channel *
Fields:
client (struct Client *): For JOIN, the remote user joining the channel;
for SJOIN, the server issuing the SJOIN message
- chptr (
struct Channel *): The channel being joined - approved (
int): Unused (always 0)
At the time the hook is called, client has not yet been added to chptr as a
member (for JOIN) or the clients specified in the user list have not yet
been joined to the channel (for SJOIN), but we have cleared all modes from
the local channel.
client_exit #
This hook is called when a client is exiting, but before the client has been removed from the network. The client could be either a user or a server, and is called for both local and remote clients exiting. It is not called when a client exits due to exceeding their send queue or if the server encountered an error while writing to the socket for the client.
Hook data: hook_data_client_exit *
Fields:
- local_link (
struct Client *): The local client originating the exit orNULLif this exit was generated by the server for internal reasons - target (
struct Client *): The client that is exiting - from (
struct Client *): The client causing target to exit - comment (
const char *): Reason for the exit
Because the local_link field can be NULL and otherwise does not have
consistent semantics, if you need the local connection for the exiting client
or the source of the exit it is better to use target->from or from->from,
respectively.
The from field is usually the same as target (for cases where the client
causes itself to exit) or is &me (for cases where the server is exiting the
client). However, this is not always the case. For example, in KILL, from is
the oper issuing the KILL command.
The comment field contains the quit message that will be sent to other
clients once the exit is processed (after this hook is run). The field is not
editable or replaceable; use the client_quit hook if you need to adjust the
quit message.
client_quit #
This hook is called when a local user sends a QUIT to the server. It is called before the user is exited. Hook functions can modify the quit reason displayed to others by modifying the passed-in data.
Hook data: hook_data_client_quit *
Fields:
- client (
struct Client *): The user who is quitting - reason (
const char *): Output field containing the quit message - orig_reason (
const char *): The quit reason specified by the user, or the user's nickname if they did not specify a reason
The reason field by default is the same as orig_reason. Hook functions can
replace the field with a different pointer value to modify the quit reason. If
a hook function changes the reason, the new reason is not prepended with the
"Quit: " prefix. Hook functions can also set reason to NULL to default to
a quit reason of "Client Quit".
conf_read_end #
This hook is called after reading ircd.conf on start or during a rehash. All configuration options have been read and validated and all consequences of re-reading the configuration (such as updating connection classes) have been applied.
Hook data: always NULL
Modules which define new configuration can make use of this hook to perform their own validation routines to ensure any module-specific values are set correctly, or perform other initialization that depends on specific config values.
conf_read_start #
This hook is called after clearing out any existing configuration (e.g. deallocating string buffers) but before reading the ircd.conf file on start or dring a rehash.
Hook data: always NULL
Modules which define their own configuration can make use of this hook to
perform cleanup on their own values as needed. String values read from conf
are allocated via rb_malloc() so if a module defines new string values it
should call rb_free() on those buffers and set them to NULL here.
doing_info_conf #
This hook is called when an oper executes the INFO command. The server config has been sent to that oper, but subsequent information provided by the command has not yet been sent.
Hook data: hook_data *
Fields:
- client (
struct Client *): The oper executing INFO - arg1 (
void *): Unused (alwaysNULL) - arg2 (
void *): Unused (alwaysNULL)
Modules which define their own configuration should make use of this hook to send information about that configuration to opers executing INFO. See the example below for the format string that should be used in order to ensure all module-created options visually align with options printed by default.
Example:
/* This example assumes my_conf_option is a boolean option */
static int my_conf_option;
void send_module_conf(void *data_)
{
hook_data *data = data_;
sendto_one(data->client, ":%s %d %s :%-30s %-16s [%s]",
get_id(&me, data->client), RPL_INFO,
get_id(data->client, data->client),
"my_conf_option",
my_conf_option ? "YES" : "NO",
"Description of my_conf_option");
}
doing_stats #
This hook is called when a user executes the STATS command, before any handler for the stats letter is executed. If STATS was targeted at a remote server, the hook is only executed on the server where STATS is ultimately running. Hook functions can prevent the default handler for the stats letter from being executed by modifying the passed-in data.
Hook data: hook_data_int *
Fields:
- client (
struct Client *): The user executing STATS - arg1 (
void *): Unused (alwaysNULL) - arg2 (
int): The stat character (upcast fromchartoint) - result (
int): Output field indicating whether to execute default handler
The result field may be set to any nonzero value to stop processing and not
execute any default handlers for the given stats character. Setting result
to 0 (which is also the default value) will result in the default handler
being run (or an error given to the client if no default handler for that
character exists). Modules which add additional stats characters should
perform their logic in this hook function, including any output to the client,
and then set result to 1. Note that RPL_ENDOFSTATS is given to the client
even if default handlers do not execute, so hook functions should not emit
that numeric to the client themselves.
doing_stats_show_idle #
This hook is called when a user executes STATS l against a user. Hook
functions can prevent details that would expose that user's idle time on the
network by modifying the passed-in data.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The user executing STATS l - target (
struct Client *): The target of the stats command - approved (
int): Output field indicating whether idle information is shown
The default value of approved is WHOIS_IDLE_SHOW, which displays
information that can be used to determine the target's idle time on the
network. Hook functions can set this to WHOIS_IDLE_HIDE instead to make the
output return 0's for that data instead. Setting approved to
WHOIS_IDLE_AUSPEX or any other nonzero value behaves exactly the same as
WHOIS_IDLE_SHOW.
The information reported as 0 when approved is set to WHOIS_IDLE_HIDE is
the following:
- The number of lines in the target's send queue
- The number of protocol messages sent to the target
- The size in KiB of all data sent to the target, rounded down
- The number of protocol messages received from the target
- The size in KiB of all data received from the target, rounded down
- The number of seconds since we last received a protocol message from the target
doing_trace_show_idle #
This hook is called when a user executes TRACE against a user. Hook functions can prevent details that would expose that user's idle time on the network by modifying the passed-in data.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The user executing TRACE - target (
struct Client *): The target of the trace command - approved (
int): Output field indicating whether idle information is shown
The default value of approved is WHOIS_IDLE_SHOW, which displays
information that can be used to determine the target's idle time on the
network. Hook functions can set this to WHOIS_IDLE_HIDE instead to make the
output return 0's for that data instead. Setting approved to
WHOIS_IDLE_AUSPEX or any other nonzero value behaves exactly the same as
WHOIS_IDLE_SHOW.
The information reported as 0 when approved is set to WHOIS_IDLE_HIDE is
the following:
- The number of seconds since we last received a protocol message from the target
- The number of seconds since the target last sent a PRIVMSG or TAGMSG
doing_version_confopts #
This hook is called when a user executes VERSION. Hook functions can modify which characters are sent in the RPL_VERSION response comment that indicate ircd configuration options.
Hook data: char[256]
See doc/server-version-info.txt for more information on what each character in this response represents. The hook data is pre-filled with the default options supported by comet according to the referenced document. Modules can set members of the array to 1 (or any other nonzero value) to have the associated character show up in the VERSION response. Setting the value to 0 will cause the associated character to be omitted from the VERSION response.
Only the characters A-Z, a-z, and 0-9 will be displayed in VERSION responses; setting other characters to 1 will have no effect on the output. Characters will be output in sorted order, with letters first followed by numbers. If a letter has both uppercase and lowercase variants set, the uppercase letter will be output before the lowercase letter.
Example:
void doing_version_confopts_example(void *data)
{
char *opts = data;
/* Causes Q to additionally appear in the VERSION response */
opts['Q'] = 1;
}
doing_who_show_idle #
This hook is called when a user executes an extended WHO (WHOX) query while
specifying the l flag to retrieve idle time. Hook functions can prevent the
details that would expose a user's idle time on the network by modifying the
passed-in data. The hook is called once for each user returned by the WHO.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The user executing WHO - target (
struct Client *): The target matching the WHO query - approved (
int): Output field indicating whether idle information is shown
The default value of approved is WHOIS_IDLE_SHOW, which displays the
target's idle time in seconds if the target is a local user. If the target is
a remote user, a value of 0 will always be returned regardless of the value of
approved, but the hook functions will nonetheless be called. Hook functions
can set this to WHOIS_IDLE_HIDE instead to make the output always return 0.
Setting approved to WHOIS_IDLE_AUSPEX or any other nonzero value behaves
exactly the same as WHOIS_IDLE_SHOW.
doing_whois #
This hook is called when a local user performs a WHOIS on someone else. The
target of the WHOIS will always be a local client. The hook is called after
all regular WHOIS lines have been sent to the user, but before the
RPL_ENDOFWHOIS numeric is sent to the user.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The user executing WHOIS - target (
struct Client *): The target of the WHOIS command - approved (
int): Set to 1 if this is an operspy WHOIS, 0 otherwise
Hook functions can use this hook to send additional lines to the client as a part of the WHOIS response. The approved field is not an output field; it is an indicator as to whether or not an operspy was performed.
doing_whois_channel_visibility #
This hook is called for each channel the target of a WHOIS command belongs to. The target will always be a local client. Hook functions can prevent the channel from being displayed in the WHOIS output by modifying the passed-in data.
Hook data: hook_data_channel_visibility *
Fields:
- client (
struct Client *): The user executing WHOIS - target (
struct Client *): The target of the WHOIS command - chptr (
struct Channel *): The channel being displayed - clientms (
struct membership *): The client's membership in the channel, orNULLif they are not in the channel. - targetms (
struct membership *): The target's membership in the channel - approved (
int): Output field indicating whether the channel is shown
The default value of approved is 1 if client is a member of the channel or
if the channel is public (not channel mode +s or +p) and 0 otherwise. If
approved is set to 1, the channel will be displayed in the WHOIS output.
Otherwise, the channel is either hidden from the output for regular WHOIS or
prefixed with the ! character for operspy WHOIS.
doing_whois_global #
This hook is called when a remote user performs a WHOIS on someone else. The
target of the WHOIS in such a case will always be a local client. The hook is
called after all regular WHOIS lines have been sent to the user, but before
the RPL_ENDOFWHOIS numeric is sent to the user.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The user executing WHOIS - target (
struct Client *): The target of the WHOIS command - approved (
int): Set to 1 if this is an operspy WHOIS, 0 otherwise
Hook functions can use this hook to send additional lines to the client as a part of the WHOIS response. The approved field is not an output field; it is an indicator as to whether or not an operspy was performed.
doing_whois_show_idle #
This hook is called when a user runs WHOIS against a local target. The user may be either local or remote. Hook functions can prevent the details that would expose the target's idle time on the network by modifying the passed-in data.
Hook data: hook_data_client_approval *
Fields:
- client (
struct Client *): The user executing WHOIS - target (
struct Client *): The target of the WHOIS command - approved (
int): Output field indicating whether idle information is shown
The default value of approved is WHOIS_IDLE_SHOW. The output given to the
user varies based on the value of approved and whether the target has the
+I user mode (ostensibly from extensions/umode_hide_idle_time):
approved |
target +I |
result |
|---|---|---|
WHOIS_IDLE_SHOW |
- | idle time shown |
WHOIS_IDLE_HIDE |
yes | idle time hidden, client told the target is hiding their idle time |
WHOIS_IDLE_HIDE |
no | idle time hidden, client told the target's idle time is hidden because the client is +I |
WHOIS_IDLE_AUSPEX |
yes | idle time shown, client told the target is hiding their idle time but the client has auspex and can see it anyway |
WHOIS_IDLE_AUSPEX |
no | idle time shown, client told the target's idle time would be hidden because the client is +I but the client has auspex and can see it anyway |
Any values for approved other than the above are treated equivalently to
WHOIS_IDLE_AUSPEX. The user mode +I is checked irrespective of which
module is providing it, if any.
get_channel_access #
This hook is called whenever a client's access to a channel needs to be verified before the action is allowed to proceed. Hook functions can alter the user's ability to perform the action by modifying the passed-in data.
Hook data: hook_data_channel_approval *
Fields:
- client (
struct Client *): The client performing a channel action - chptr (
struct Channel *): The channel being checked for client's access - msptr (
struct membership *): The client's membership on chptr - approved (
int): Output field indicating client's access to the channel - dir (
int): One ofMODE_ADD,MODE_QUERY, orMODE_OP_QUERY - modestr (
const char *): The canonicalized set of channel mode changes as would be passed to a MODE command if this hook is called as a result of channel mode changes, otherwiseNULL - error (
const char *): Unused (alwaysNULL)
This hook is called under the following circumstances:
- Retrieving the values of a queryable mode for a channel
- The following modes are considered queryable:
beIfkq - The following modes are considered privileged while querying:
eI - Module-defined channel modes can be marked queryable by setting either
CHM_QUERYABLEorCHM_CAN_QUERYwhen defining the mode and privileged by settingCHM_OPS_QUERYwhen defining the mode dirwill beMODE_OP_QUERYif at least one of the queried modes inmodestris a privileged mode andMODE_QUERYotherwisemodestrwill be the canonicalized set of channel modes being queried
- The following modes are considered queryable:
- Updating (adding or removing) modes for a channel
- If the mode update is combined with a privileged mode query, e.g.
MODE #channel +m=I,dirwill beMODE_OP_QUERY; otherwise,dirwill always beMODE_ADD, regardless of whether modes are being added, removed, or both modestrwill be the canonicalized set of channel modes being updated
- If the mode update is combined with a privileged mode query, e.g.
- Forwarding (channel mode
+for ban forwards) to another channel- The hook is called for the target channel to verify the client has operator status on it and is in addition to the hook invocation for updating modes on the source channel
dirwill always beMODE_QUERYandmodestrwill always beNULL
- Setting the topic for a channel
dirwill always beMODE_ADDandmodestrwill always beNULL
- Kicking a user from a channel
dirwill always beMODE_ADDandmodestrwill always beNULL
- Removing a user from a channel (via extensions/m_remove)
dirwill always beMODE_ADDandmodestrwill always beNULL
For mode queries and updates, the direction in modestr is always explicitly
specified by prefixing with = for queries, + for additions, and - for
removals. For example, a user sending MODE #channel b to query the ban list
would cause modestr to be =b. Unrecognized or invalid mode letters are
removed from modestr, e.g. attempts to query non-queryable modes. Multiple
adjacent modes with the same direction will not duplicate the prefix. For
example, a user sending MODE #channel +m+z would cause modestr to be +mz
but a user sending MODE #channel +m-R+z would cause modestr to remain as
+m-R+z (i.e. modes are not rearranged from what the user specified).
modestr will additionally contain all relevant arguments to modes, separated
by spaces. These transformations are what the documentation above refers to
when it talks about the canonicalized set of channel modes.
The default value of approved is CHFL_CHANOP if client is a member of
the channel and has channel operator status on the channel and CHFL_PEON
otherwise. In general, for everything except querying non-privileged modes,
the action will be denied if approved is set to anything lower than
CHFL_CHANOP (e.g. CHFL_PEON or CHFL_VOICE).
introduce_client #
This hook is called whenever a client is introduced to the network. The client has already been fully registered before this hook is called, and the client may be either local or remote.
Hook data: hook_data_client *
Fields:
- client (
struct Client *): The local connection for the introduced client - target (
struct Client *): The client being introduced
For local clients, client and target will point to the same place. For remote clients, client will be the locally-connected server that is introducing the client to us.
invite #
This hook is called whenever a local user is invited to a channel, after the can_invite hook has already been executed on the sender's server. The user sending the invite may be either local or remote. Hook functions can allow or reject the invite attempt by modifying the passed-in data.
Hook data: hook_data_channel_approval *
Fields:
- client (
struct Client *): The user sending the INVITE - chptr (
struct Channel *): The channel that client is inviting target to - msptr (
struct membership *): The client's membership on chptr - target (
struct Client *): The user being invited - approved (
int): Output field indicating whether this attempt succeeds - dir (
int): Unused (always 0) - modestr (
const char *): Unused (alwaysNULL) - error (
const char *): Output field containing an optional error message to send to the user
The default value for approved is 0. To approve the invite attempt,
approved must be set to 0. If it is set to any other value, how the caller
behaves depends on whether error is also set. If approved is nonzero and
error is NULL, the invite attempt will silently fail. If approved is
nonzero and error is not NULL, the invite attempt will be rejected and the
client will be sent the approved value as a numeric with parameters
contained in the error string (the client's nick is automatically inserted
as the first parameter and should not be present in the string).
local_nick_change #
This hook is called whenever a local user changes their nickname. This hook is
only called when the nickname change would succeed, and timing-wise occurs
after RPL_MONOFFLINE is sent for the old nickname but before RPL_MONONLINE
is sent for the new nickname and before the nick change is propagated to local
users and the rest of the network.
Hook data: hook_cdata *
Fields:
- client (
struct Client *): The user whose nick is changing - arg1 (
const char *): The user's previous nickname - arg2 (
const char *): The user's new nickname
message_handler #
This hook is called for every incoming message processed by the server. Hook functions can alter the message handler ordinarily called by the ircd for the client by modifying the passed-in data.
Hook data: hook_data *
Fields:
- client (
struct Client *): The client sending the message - arg1 (
struct MsgBuf *): The message - arg2 (
struct MessageEntry *): Output field for the function used to handle the message
The default value for arg2 is the defined message handler for the command
based on the client's status (unregistered, local user, remote user, server,
encap, oper). Hook functions can replace this with a different handler by
setting arg2->handler to a different pointer. arg2->min_args may be
modified as well if the new handler supports a different minimum number of
arguments compared to the default handler.
message_tag #
This hook is called for every message tag present in an incoming message. Hook functions can reject the tag or message or update the tag by modifying the passed-in data.
Hook data: hook_data_message_tag *
Fields:
- client (
struct Client *): The local connection the message came from - source (
struct Client *): The client originating the message - key (
const char *): The name of the message tag - value (
const char *): The value of the message tag, orNULLif a value was not specified with this tag - capmask (
unsigned int): Output field indicating the client capabilities a user must possess in order to receive this tag in server-sent messages - message (
const struct MsgBuf *): The full command received, including all tags and parameters - approved (
int): Output field indicating whether this message tag should be retained before passing the message off to the appropriate handler
The default value of approved is MESSAGE_TAG_REMOVE, which causes the tag
to be stripped from the message before being passed to the handler. Hook
functions can instead set this to MESSAGE_TAG_ALLOW to include the tag in
the message or MESSAGE_TAG_DROP to prevent the entire message from being
processed. When using MESSAGE_TAG_DROP it is the hook function's
responsibility to provide any relevant error messages to the source. Using any
value outside of these will be treated equivalently to MESSAGE_TAG_REMOVE.
The default value of capmask is CLICAP_MESSAGE_TAGS. Hook functions can
modify this to be a different client capability or bitwise combination of
client capabilities. While there is no guarantee that modifying capmask
will accomplish anything, some message handlers pass some or all incoming tags
to outgoing messages, and setting this appropriately allows such tags to be
propagated appropriately.
Finally, key and value may both be set to different pointer values to
adjust the tag's key and value passed to the message handler. The pointed-to
buffers are not copied and must persist for the lifetime of the message
handler. Setting value to NULL will strip the value from the tag.
new_local_user #
This hook is called after a local user has completed connection registration, but before it is formally introduced to the server or network. This hook is only called for users; see server_introduced for the introduction of new server connections.
Hook data: struct Client *
The hook data is the user being introduced. Hook functions can safely kill this client should the connection attempt not be allowed to proceed.
new_monitor #
This hook is called after a local user has added a new nickname to their MONITOR list.
Hook data: hook_data *
Fields:
- client (
struct Client *): The client adding the monitor entry - arg1 (
struct monitor *): The monitor entry that was added - arg2 (
struct Client *): The client corresponding to the new entry, orNULLif no client matching the nickname is online
The client has already been added to the arg1->users list at the time this
hook is called. All relevant RPL_MONONLINE and RPL_MONOFFLINE messages
have already been sent to the client for the added nickname.
new_remote_user #
This hook is called after a remote user has been introduced to this server. This hook is only called for users; see server_introduced for the introduction of new server connections.
Hook data: struct Client *
The hook data is the user being introduced. Unlike new_local_user, hook functions must not attempt to disconnect clients during this hook. The user will still be introduced to downstream servers after this hook completes running and disconnection attempts will therefore introduce state desynchronization between servers. If a remote user needs to be disconnected as early as possible after having been introduced, the introduce_client hook is the best spot to do that.
outbound_msgbuf #
This hook is called when constructing a message to be sent from the server. Hook functions can manipulate the message tags that would be sent by modifying the passed-in data. This hook is only called once per outbound message, regardless of how many clients the message will be sent to.
Hook data: hook_data_outbound_msgbuf *
Fields:
- source (
struct Client *): The client sending the message - msgbuf (
struct MsgBuf *): The message buffer being sent - target (
struct Client *): The single client receiving the message orNULL - chptr (
struct Channel *): The channel receiving the message orNULL - source_sees_message (
bool): Whether the client sending the message will also receive it
Hook functions can inspect msgbuf and modify it. Any modifications such as the
addition or removal of message tags will be sent to the targets of the
message. To add message tags, call msgbuf_append_tag. To remove tags, set the
tag's capmask to 0. Changing other aspects of the MsgBuf such as the origin
or parameter array is not recommended and may not function as expected.
The target field will be non-NULL when the message is being sent to a single
client and will be NULL for messages sent to channels or that are broadcast
to potentially many clients. The chptr field will be non-NULL when the
message is being sent to a single channel and will be NULL for messages not
sent to channels or that are sent to everyone in multiple channels. Both
fields will be NULL for broadcast-type messages.
The following send functions currently do not call this hook:
- kill_client
- kill_client_serv_butone
parse_end #
This hook is called after we have processed an incoming message, including sending all relevant responses.
Hook data: always NULL
The global state variables incoming_client and incoming_message are still
defined at the time this hook is executed. If sending messages from this hook,
ensure that you choose a priority lower than HOOK_HIGHEST; any messages sent
from hook functions with HOOK_HIGHEST or HOOK_MONITOR will not have proper
context for labeled-response.
priv_change #
This hook is called whenever an oper's privilege set changes. This could be due to a user successfully becoming an oper, deopering, or an ircd rehash.
Hook data: hook_data_priv_change *
Fields:
- client (
struct Client *): The oper whose privileges have changed - old (
struct PrivilegeSet *): The oper's previous privset, orNULLif they are opering up - new (
struct PrivilegeSet *): The oper's new privset, orNULLif they have deopered - added (
const struct PrivilegeSet *): The set of privileges added - removed (
const struct PrivilegeSet *): The set of privileges removed - unchanged (
const struct PrivilegeSet *): Privileges which remained intact
When ircd.conf is rehashed, this hook will be invoked for every local oper, even if there was no change to the privileges in their privset. Additionally, this hook will not be invoked upon rehash for remote opers even if there were changes to the privileges in their privset.
privmsg_channel #
This hook is called whenever a user sends a message to a channel or is parting a channel. Hook functions can reject the message attempt or alter the message text by modifying the passed-in data. This hook is called for messages sent by both local and remote users.
Hook data: hook_data_privmsg_channel *
Fields:
- msgtype (
enum message_type): The type of message being sent - source_p (
struct Client *): The user sending the message - chptr (
struct Channel *): The channel the message is being sent to - text (
const char *): The message text - approved (
int): Output field indicating whether the message is allowed to be sent - msgbuf (
struct MsgBuf *): The full message, including tags, being sent
The default value for approved is 0, which allows the message to be sent.
Setting approved to any nonzero value silently drops the message for
MESSAGE_TYPE_PRIVMSG, MESSAGE_TYPE_NOTICE, and MESSAGE_TYPE_TAGMSG and
causes the user to part without a reason parameter for MESSAGE_TYPE_PART.
It is up to the hook function to provide any relevant error output to the user
when messages are rejected.
Hook functions may set text to a different pointer value. If this is done,
the new text will be used for message content instead of the original text.
Hook functions may additionally manipulate the tags present in msgbuf; any
modifications to tags will be reflected in the message sent to the channel but
other modifications will not be effective.
privmsg_user #
This hook is called whenever a user sends a message to a channel. Hook functions can reject the message attempt or alter the message text by modifying the passed-in data. This hook is called for messages sent by both local and remote users.
Hook data: hook_data_privmsg_user *
Fields:
- msgtype (
enum message_type): The type of message being sent - source_p (
struct Client *): The user sending the message - target_p (
struct Client *): The user the message is being sent to - text (
const char *): The message text - approved (
int): Output field indicating whether the message is allowed to be sent - msgbuf (
struct MsgBuf *): The full message, including tags, being sent
The default value for approved is 0, which allows the message to be sent.
Setting approved to any nonzero value silently drops the message. It is up
to the hook function to provide any relevant error output to the user when
messages are rejected.
Hook functions may set text to a different pointer value. If this is done,
the new text will be used for message content instead of the original text.
Hook functions may additionally manipulate the tags present in msgbuf; any
modifications to tags will be reflected in the message sent to the user but
other modifications will not be effective.
rehash #
This hook is called after an ircd.conf rehash operation has completed.
Hook data: hook_data_rehash *
Fields:
- signal (
bool): Whether the rehash was the result of a signal or an oper command
The value of signal will be true if the rehash was the result of a SIGHUP
sent to the ircd process and false if the rehash was the result of a REHASH or
MODRESTART command.
remote_nick_change #
This hook is called whenever a remote user changes their nickname. This hook
is only called when the nickname change would succeed, and timing-wise occurs
after RPL_MONOFFLINE is sent for the old nickname but before RPL_MONONLINE
is sent for the new nickname and before the nick change is propagated to local
users and the rest of the network.
Hook data: hook_cdata *
Fields:
- client (
struct Client *): The user whose nick is changing - arg1 (
const char *): The user's previous nickname - arg2 (
const char *): The user's new nickname
server_introduced #
This hook is called whenever a server is introduced to the network. The server may be directly connected or remote.
Hook data: hook_data_client *
Fields:
- client (
struct Client *): The server introducing this server - target (
struct Client *): The server being introduced
For local connections, client will be &me.
server_eob #
This hook is called after a netjoin burst has been processed by a server. The server may be either directly connected or remote.
Hook data: struct Client *
The hook data is the server that has indicated it has finished processing any netjoin burst data sent by us. The EOB flag has already been set on source_p by the time this hook is called.
umode_changed #
This hook is called after a user is introduced and after any changes to their user modes, such as by the MODE, OPER, or DEHELPER commands. Any mode changes have already been applied at the time this hook is called.
Hook data: hook_data_umode_changed *
Fields:
- client (
struct Client *): The user whose modes have changed - oldumodes (
unsigned int): The user's old user modes - oldsnomask (
unsigned int): The user's old server notice mask
Because any mode changes have already been applied, hook functions can check the current user modes or snomask for the user to determine what has changed.
user_welcome #
This hook is called while the registration burst for a new local user is being sent. It happens after sending ISUPPORT but before sending LUSERS. Some IRCv3 specifications require sending additional registration data during precisely this timing.
Hook data: struct Client *
The hook data is the client that is being introduced to the network.