Dev:Hook API

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 generally goes in MOD_INIT or MOD_LOAD, 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: DLLFUNC int MOD_INIT(mymod)(ModuleInfo *modinfo) {   HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, mymod_connect); HookAddPCharEx(modinfo->handle, HOOKTYPE_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.

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_LOAD: HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, mymod_connect);

Function syntax and example: DLLFUNC int mymod_connect(aClient *sptr) {   sendnotice(sptr, "Hi %s, welcome on-board!!", sptr->name); }

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_LOAD: HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, mymod_preconnect);

Function syntax and example: DLLFUNC 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_LOAD: HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, mymod_quit);

Function syntax & example: DLLFUNC 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_LOAD: HookAddPChar(modinfo->handle, HOOKTYPE_PRE_LOCAL_QUIT, 0, mymod_prequit);

Function syntax & example: DLLFUNC 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_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.

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.

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.

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.

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.

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_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.