Dev:Hook API

From UnrealIRCd documentation wiki
Jump to: navigation, search

Contents

What are hooks?

When you write an UnrealIRCd module you usually want your code to be called after a specific event has been triggered, such as a new user connecting, a user joining a channel, etc. The Hook API allows a module to "hook" into UnrealIRCd's core and modules. It basically informs UnrealIRCd that your function wants be called when XYZ happens.

UnrealIRCd has more than 80 of these hooks, so chances are high that we have one you are looking for!

How hooks are called

Here's some little explanation of how hooks are called "by us" from the core and our own modules. It may not interest you if you just want to "hook in" (for that, skip this and see next section):

When we want to run a hook we have a few functions available. The most basic ones are RunHook/RunHookX:

RunHook(HOOKTYPE_XYZ);
RunHook1(HOOKTYPE_XYZ, arg1);
RunHook2(HOOKTYPE_XYZ, arg1, arg2);
RunHook3(HOOKTYPE_XYZ, arg1, arg2, arg3);
etc..

Sometimes modules want to have the option to 'stop processing', for this we have:

RunHookReturnInt(hooktype,x,retchk);
etc...

(^^ improve)

How to have your module "hook in"

If you found the hook you are looking for (see next section) then you should use our HookAddXXX functions to make it so your function will be called by the hook system. Your HookAddXXX function goes in MOD_INIT, with the exception of two or three hooks which go in MOD_TEST.

We have different HookAddXX functions, the ones you need depend on the return type of the hook.

For hooks returning integers (the majority):

HookAdd(module, hooktype, priority, func)

For hooks returning nothing (void):

HookAddVoid(module, hooktype, priority, func)

For hooks returning a string (char *):

HookAddPChar(module, hooktype, priority, func)

Example usage:

int MOD_INIT(mymod)(ModuleInfo *modinfo)
{
    HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, mymod_connect);
    HookAddPChar(modinfo->handle, HOOKTYPE_PRE_USERMSG, 0, mymod_usermsg);

A note on priority

You may have noticed the priority argument, which we set to 0 in the above example. You can use 0 if it doesn't matter to you if your hook is called before or after hooks from other modules. Use a negative value such as -100 to be called BEFORE the rest, or a positive value such as 100 to be at the end of the hook callback list.

What is NOT safe to do in a hook

It is not safe to kill the user in a hook. That is, if your hook is called for 'sptr' then do not use exit_client(sptr....). Instead you should use dead_link(sptr, "reason here").

The reason for this is that the caller of the hook does not expect the user object to disappear.

The only exception to this rule is the PRE_LOCAL_CONNECT hook. You can safely return exit_client() there.

Available hook types

HOOKTYPE_CONFIGTEST

This hook gets called when the configuration file 'test' runs. If you add your own configuration block or variable then you need this.

See Dev:Configuration API for the full configuration API, and Testing configuration there specifically.

HOOKTYPE_CONFIGPOSTTEST

This hook is called AFTER all HOOKTYPE_CONFIGTEST hooks have been called. If you require a specific configuration block or variable then this allows you (with the help of HOOKTYPE_CONFIGTEST earlier) to see if some option was never specified.

See Dev:Configuration API for the full configuration API, and Checking for missing configuration items there specifically.

HOOKTYPE_CONFIGRUN

Once the configuration file has passed testing (see previous two hooks) UnrealIRCd will "run" the configuration file. At this point you can no longer "cancel" processing of the configuration file so any options specified are assumed to be valid at this point and you must deal with it.

See Dev:Configuration API for the full configuration API, and Running the configuration there specifically.

HOOKTYPE_LOCAL_CONNECT

Called when a user connects to OUR server. When this hook is called the user is fully "registered" in IRC terms, that means "USER" and "NICK" have been received and the user is now "online".

Note that if you want to take some sort of reject/kill action on the user (eg: for access control) then you must use HOOKTYPE_PRE_LOCAL_CONNECT instead.

Add the hook from MOD_INIT:

HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, mymod_connect);

Function syntax and example:

int mymod_connect(aClient *sptr)
{
    sendnotice(sptr, "Hi %s, welcome on-board!!", sptr->name);
    return 0;
}

HOOKTYPE_PRE_LOCAL_CONNECT

Called after "USER" and "NICK" but before the user is fully registered / online. In contrast to HOOKTYPE_LOCAL_CONNECT this function allows you to reject/kill the user.

This function is normally only used if your module provides some sort of access control functionality. If you just want to take some sort of other action, like send a message or log something, then use HOOKTYPE_LOCAL_CONNECT instead.

Add the hook from MOD_INIT:

HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, mymod_preconnect);

Function syntax and example:

int mymod_preconnect(aClient *sptr)
{
    if (!strcmp(sptr->name, "lazyuser"))
        return exit_client(sptr, sptr, sptr, "We do not allow lazy people on this server, sorry");

    return 0;
}

HOOKTYPE_REMOTE_CONNECT

Called when a user connects to a remote server.

HOOKTYPE_LOCAL_QUIT

Called when a user gets disconnected, either via /QUIT or any other reason including but not limited to: ping timeout, being killed, network errors, etc.

If your module manages it's own per-user struct then this function allows you to free it from here (you may also be interested in HOOKTYPE_UNKUSER_QUIT then). Naturally it can also be used for logging or any other action you think is useful on user disconnection.

Hook from MOD_INIT:

HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, mymod_quit);

Function syntax & example:

int mymod_quit(aClient *sptr, char *comment)
{
    SomeDynamicInfo *e = find_some_dynamic_info(sptr);
    if (e)
        free_some_dynamic_info_and_remove_from_list(e);

    return 0;
}

HOOKTYPE_PRE_LOCAL_QUIT

Similar to HOOKTYPE_LOCAL_QUIT but this one is called a little earlier and is only meant when you want to change the quit reason. An example use case would be a censorship module.

Hook from MOD_INIT:

HookAddPChar(modinfo->handle, HOOKTYPE_PRE_LOCAL_QUIT, 0, mymod_prequit);

Function syntax & example:

char *mymod_prequit(aClient *acptr, char *comment)
{
    if (strstr(comment, "shit"))
        return NULL; // we could return a string here (which will then be used), or we can return NULL which means: no quit reason

    return comment;
}

HOOKTYPE_UNKUSER_QUIT

Called when an "unknown" user disconnects. Unknown here means: any client who is not online yet. This hook is for example triggered if you connect to the IRC port and then disconnect without sending any USER or NICK. It could be used for logging or to deallocate any custom made structures if necessary (not too common and HOOKTYPE_FREE_CLIENT is arguably more suitable for that).

The syntax and usage is exactly the same as HOOKTYPE_LOCAL_QUIT. Note, though, that sptr->name may or may not be filled in (as NICK may or may not have been received). Additionally, even if sptr->name contains a nickname it has not yet been fully "approved" and since it's not really online the other servers know nothing about this user.

HOOKTYPE_REMOTE_QUIT

Called when a user disconnects or gets killed on a remote server.

HOOKTYPE_LOCAL_NICKCHANGE

int hooktype_local_nickchange(aClient *sptr, char *newnick);

HOOKTYPE_REMOTE_NICKCHANGE

int hooktype_remote_nickchange(aClient *cptr, aClient *sptr, char *newnick);

HOOKTYPE_REHASHFLAG

int hooktype_rehashflag(aClient *cptr, aClient *sptr, char *str);

HOOKTYPE_PRE_LOCAL_PART

char *hooktype_pre_local_part(aClient *sptr, aChannel *chptr, char *comment);

HOOKTYPE_REHASH

int hooktype_rehash(void);

HOOKTYPE_SERVER_CONNECT

int hooktype_server_connect(aClient *sptr);

HOOKTYPE_SERVER_QUIT

int hooktype_server_quit(aClient *sptr);

HOOKTYPE_STATS

int hooktype_stats(aClient *sptr, char *str);

HOOKTYPE_LOCAL_JOIN

int hooktype_local_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[]);

HOOKTYPE_USERMSG

int hooktype_usermsg(aClient *sptr, aClient *to, char *text, int notice);

HOOKTYPE_CHANMSG

int hooktype_chanmsg(aClient *sptr, aChannel *chptr, char *text, int notice);

HOOKTYPE_LOCAL_PART

int hooktype_local_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *comment);

HOOKTYPE_LOCAL_KICK

int hooktype_local_kick(aClient *cptr, aClient *sptr, aClient *victim, aChannel *chptr, char *comment);

HOOKTYPE_LOCAL_CHANMODE

int hooktype_local_chanmode(aClient *cptr, aClient *sptr, aChannel *chptr, char *modebuf, char *parabuf, time_t sendts, int samode);

HOOKTYPE_LOCAL_TOPIC

int hooktype_local_topic(aClient *cptr, aClient *sptr, aChannel *chptr, char *topic);

HOOKTYPE_LOCAL_OPER

int hooktype_local_oper(aClient *sptr, int add);

HOOKTYPE_LOCAL_PASS

int hooktype_local_pass(aClient *sptr, char *password);

HOOKTYPE_PRE_LOCAL_JOIN

This function allows you, unlike HOOKTYPE_LOCAL_JOIN, to "reject" a local join. Useful if your module provides some sort of channel access restriction.

int hooktype_pre_local_join(aClient *sptr, aChannel *chptr, char *parv[]);

HOOKTYPE_PRE_LOCAL_KICK

This function allows you, unlike HOOKTYPE_LOCAL_KICK, to "reject" a KICK request from a local client. For example if your module creates some special class of users that may not be kicked.

char *hooktype_pre_local_kick(aClient *sptr, aClient *victim, aChannel *chptr, char *comment);

Note: see also HOOKTYPE_CAN_KICK

HOOKTYPE_PRE_LOCAL_TOPIC

This function allows you, unlike HOOKTYPE_LOCAL_TOPIC, to "reject" a topic change request from a local user.

char *hooktype_pre_local_topic(aClient *cptr, aClient *sptr, aChannel *chptr, char *topic);

HOOKTYPE_CHANNEL_CREATE

int hooktype_channel_create(aClient *sptr, aChannel *chptr);

HOOKTYPE_CHANNEL_DESTROY

int hooktype_channel_destroy(aChannel *chptr, int *should_destroy);

HOOKTYPE_REMOTE_CHANMODE

int hooktype_remote_chanmode(aClient *cptr, aClient *sptr, aChannel *chptr, char *modebuf, char *parabuf, time_t sendts, int samode);

HOOKTYPE_TKL_EXCEPT

int hooktype_tkl_except(aClient *cptr, aTKline *tkl);

HOOKTYPE_UMODE_CHANGE

int hooktype_umode_change(aClient *sptr, long setflags, long newflags);

HOOKTYPE_TOPIC

int hooktype_topic(aClient *cptr, aClient *sptr, aChannel *chptr, char *topic);

HOOKTYPE_REHASH_COMPLETE

int hooktype_rehash_complete(void);

HOOKTYPE_TKL_ADD

int hooktype_tkl_add(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[]);

HOOKTYPE_TKL_DEL

int hooktype_tkl_del(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[]);

HOOKTYPE_LOCAL_KILL

int hooktype_local_kill(aClient *sptr, aClient *victim, char *comment);

HOOKTYPE_LOG

int hooktype_log(int flags, char *timebuf, char *buf);

HOOKTYPE_REMOTE_JOIN

int hooktype_remote_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[]);

HOOKTYPE_REMOTE_PART

int hooktype_remote_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *comment);

HOOKTYPE_REMOTE_KICK

int hooktype_remote_kick(aClient *cptr, aClient *sptr, aClient *victim, aChannel *chptr, char *comment);

HOOKTYPE_LOCAL_SPAMFILTER

int hooktype_local_spamfilter(aClient *acptr, char *str, char *str_in, int type, char *target, aTKline *tkl);

HOOKTYPE_SILENCED

int hooktype_silenced(aClient *cptr, aClient *sptr, aClient *to, int notice);

HOOKTYPE_POST_SERVER_CONNECT

int hooktype_post_server_connect(aClient *sptr);

HOOKTYPE_RAWPACKET_IN

int hooktype_rawpacket_in(aClient *sptr, char *readbuf, int *length);

HOOKTYPE_LOCAL_NICKPASS

int hooktype_local_nickpass(aClient *sptr, aClient *nickserv);

HOOKTYPE_PACKET

int hooktype_packet(aClient *from, aClient *to, char **msg, int length);

HOOKTYPE_HANDSHAKE

int hooktype_handshake(aClient *sptr);

HOOKTYPE_AWAY

int hooktype_away(aClient *sptr, char *reason);

HOOKTYPE_INVITE

int hooktype_invite(aClient *from, aClient *to, aChannel *chptr);

HOOKTYPE_CAN_SEND

int hooktype_can_send(aClient *sptr, aChannel *chptr, char *text, Membership *member, int notice);

HOOKTYPE_CAN_SEND_SECURE

int hooktype_can_send_secure(aClient *sptr, aChannel *chptr);

HOOKTYPE_CAN_JOIN

int hooktype_can_join(aClient *sptr, aChannel *chptr, char *key, char *parv[]);

HOOKTYPE_CAN_JOIN_LIMITEXCEEDED

int hooktype_can_join_limitexceeded(aClient *sptr, aChannel *chptr, char *key, char *parv[]);

HOOKTYPE_CAN_SAJOIN

int hooktype_can_sajoin(aClient *target, aChannel *chptr, aClient *sptr);

HOOKTYPE_CAN_KICK

int hooktype_can_kick(aClient *sptr, aClient *victim, aChannel *chptr, char *comment, long sptr_flags, long victim_flags, char **error);

HOOKTYPE_FREE_CLIENT

int hooktype_free_client(aClient *acptr);

HOOKTYPE_FREE_USER

int hooktype_free_user(anUser *user, aClient *acptr);

HOOKTYPE_PRE_CHANMSG

Similar to HOOKTYPE_CHANMSG, this one is called when a user wants to send a channel message. This hook, however, allows you to actually change the channel message (or reject/block it entirely). It used by for example censorship modules.

char *hooktype_pre_chanmsg(aClient *sptr, aChannel *chptr, char *text, int notice);

Note: see also HOOKTYPE_CAN_SEND ??

HOOKTYPE_PRE_USERMSG

Similar to HOOKTYPE_USERMSG, this one is called when a user wants to send a private message to another user. This hook, however, allows you to actually change the message (or reject/block it entirely). It used by for example censorship modules.

char *hooktype_pre_usermsg(aClient *sptr, aClient *to, char *text, int notice);

HOOKTYPE_KNOCK

int hooktype_knock(aClient *sptr, aChannel *chptr);

HOOKTYPE_MODECHAR_ADD

int hooktype_modechar_add(aChannel *chptr, int modechar);

HOOKTYPE_MODECHAR_DEL

int hooktype_modechar_del(aChannel *chptr, int modechar);

HOOKTYPE_EXIT_ONE_CLIENT

int hooktype_exit_one_client(aClient *sptr);

HOOKTYPE_VISIBLE_IN_CHANNEL

int hooktype_visible_in_channel(aClient *sptr, aChannel *chptr);

HOOKTYPE_PRE_LOCAL_CHANMODE

Is called a little earlier than HOOKTYPE_LOCAL_CHANMODE ? (does not allow rejection right?)

HOOKTYPE_PRE_REMOTE_CHANMODE

Is called a little earlier than HOOKTYPE_REMOTE_CHANMODE ? (does not allow rejection)

HOOKTYPE_JOIN_DATA

int hooktype_join_data(aClient *who, aChannel *chptr);

HOOKTYPE_PRE_KNOCK

Similar to HOOKTYPE_KNOCK this is called when a user issues a /KNOCK request. Unlike HOOKTYPE_KNOCK, this function actually allows you to reject/block the /KNOCK.

HOOKTYPE_PRE_INVITE

Similar to HOOKTYPE_INVITE this is called when a user issues an /INVITE request. Unlike HOOKTYPE_INVITE, this function actually allows you to reject/block the /INVITE.

HOOKTYPE_OPER_INVITE_BAN

int hooktype_oper_invite_ban(aClient *sptr, aChannel *chptr);

HOOKTYPE_VIEW_TOPIC_OUTSIDE_CHANNEL

int hooktype_view_topic_outside_channel(aClient *sptr, aChannel *chptr);

HOOKTYPE_CHAN_PERMIT_NICK_CHANGE

int hooktype_chan_permit_nick_change(aClient *sptr, aChannel *chptr);

HOOKTYPE_IS_CHANNEL_SECURE

int hooktype_is_channel_secure(aChannel *chptr);

HOOKTYPE_CHANNEL_SYNCED

void hooktype_channel_synced(aChannel *chptr, unsigned short merge, unsigned short removetheirs, unsigned short nomode);

HOOKTYPE_WHOIS

int hooktype_whois(aClient *sptr, aClient *target);

HOOKTYPE_CHECK_INIT

int hooktype_check_init(aClient *cptr, char *sockname, size_t size);

HOOKTYPE_WHO_STATUS

int hooktype_who_status(aClient *sptr, aClient *target, aChannel *chptr, Member *member, char *status, int cansee);

HOOKTYPE_MODE_DEOP

int hooktype_mode_deop(aClient *sptr, aClient *victim, aChannel *chptr, u_int what, char modechar, long my_access, char **badmode);

HOOKTYPE_PRE_KILL

int hooktype_pre_kill(aClient *sptr, aClient *victim, char *killpath);

HOOKTYPE_SEE_CHANNEL_IN_WHOIS

int hooktype_see_channel_in_whois(aClient *sptr, aClient *target, aChannel *chptr);

HOOKTYPE_DCC_DENIED

int hooktype_dcc_denied(aClient *sptr, aClient *target, char *realfile, char *displayfile, ConfigItem_deny_dcc *denydcc);

HOOKTYPE_SERVER_HANDSHAKE_OUT

int hooktype_server_handshake_out(aClient *sptr);

HOOKTYPE_SERVER_SYNCHED

Called when the server is synchronized. That is: the server has linked in and all the channel/user state synchronization and such has been done.

int hooktype_server_synched(aClient *sptr);

HOOKTYPE_SECURE_CONNECT

Called when a secure user connects. Used internally so the secure flag can be stripped. Not really meant for 3rd party modules.

int hooktype_secure_connect(aClient *sptr);

HOOKTYPE_CAN_BYPASS_CHANNEL_MESSAGE_RESTRICTION

Called to check if a user can bypass a channel message/notice restriction.

int hooktype_can_bypass_channel_message_restriction(aClient *sptr, aChannel *chptr, BypassMessageRestrictionType bypass_type);

Naturally, sptr is the client pointer and chptr the channel. The bypass_type is one of:

  • BYPASS_MSG_EXTERNAL: bypass +n
  • BYPASS_MSG_MODERATED: bypass +m
  • BYPASS_MSG_COLOR: bypass +c/+S
  • BYPASS_MSG_CENSOR: bypass +G
  • BYPASS_MSG_NOTICE: bypass +T

This hook is used by the extended ban exception +e ~m:type:mask