Tip of the day: Channel mode +P makes a channel permanent. The topic and modes are preserved,even if all users leave the channel, and even if the server is restarted thanks to channeldb. |
Dev:User Mode API
The User Mode API allows you to add new user modes to UnrealIRCd.
In addition to the tutorial below, you may also want to look at examples in UnrealIRCd itself (learn by copying). The built-in user mode modules are in src/modules/usermodes/.
Creating a user mode
Register your user mode by calling UmodeAdd() from MOD_INIT:
long UMODE_EXAMPLE = 0L;
#define IsExample(client) (client->umodes & UMODE_EXAMPLE)
MOD_INIT()
{
UmodeAdd(modinfo->handle, 'X', UMODE_GLOBAL, 0, umode_allow_all, &UMODE_EXAMPLE);
return MOD_SUCCESS;
}
UmodeAdd parameters
Umode *UmodeAdd(Module *module, char ch, int global, int unset_on_deoper, int (*allowed)(Client *client, int what), long *mode);
| Parameter | Type | Description |
|---|---|---|
| module | Module * | The module registering this mode (use modinfo->handle)
|
| ch | char | The mode character, e.g. 'X'
|
| global | int | UMODE_GLOBAL (1) to sync the mode to other servers, or UMODE_LOCAL (0) for a local-only mode. Most modes use UMODE_GLOBAL.
|
| unset_on_deoper | int | Set to 1 if the mode should be automatically removed when a user loses IRC Operator status. Set to 0 otherwise. |
| allowed | function pointer | A function that checks whether the user is allowed to set/unset the mode. See Permission functions below. Can be NULL if everyone is allowed. |
| mode | long * | Pointer to a long variable where UmodeAdd will store the mode bitmask. You will use this variable to check if a user has the mode set.
|
Returns: A pointer to the Umode struct on success, or NULL on failure.
Permission functions
The allowed parameter is a function pointer with the following signature:
int allowed(Client *client, int what);
The what parameter is either MODE_ADD or MODE_DEL. Return 1 to allow the mode change, or 0 to deny it.
UnrealIRCd provides several built-in permission functions you can use:
| Function | Description |
|---|---|
umode_allow_all
|
Anyone can set and unset the mode |
umode_allow_opers
|
Only IRC Operators can set the mode (anyone can unset) |
umode_allow_unset
|
Users can only unset the mode, not set it (used for modes set by the server) |
umode_allow_none
|
No local user can set the mode (only servers can set it) |
| NULL | Same as umode_allow_all
|
You can also write your own allowed function if you need custom logic.
Checking if a user has the mode
After calling UmodeAdd, the mode variable contains the bitmask. Check it like this:
if (client->umodes & UMODE_EXAMPLE)
{
/* User has mode +X set */
}
It is common practice to define a macro for readability:
#define IsExample(client) (client->umodes & UMODE_EXAMPLE)
Making the mode do something
UmodeAdd only handles setting/unsetting the mode character. To make the mode actually do something, you typically combine it with one or more Hooks.
For example, a mode that blocks CTCPs (like user mode +T) hooks into HOOKTYPE_CAN_SEND_TO_USER:
int example_can_send_to_user(Client *client, Client *target, const char **text, const char **errmsg, SendType sendtype, ClientContext *clictx)
{
if (IsExample(target) && MyUser(client) && !IsOper(client))
{
*errmsg = "User does not accept this type of message";
return HOOK_DENY;
}
return HOOK_CONTINUE;
}
Don't forget to register the hook in MOD_INIT:
HookAdd(modinfo->handle, HOOKTYPE_CAN_SEND_TO_USER, 0, example_can_send_to_user);
Examples
Simple mode: anyone can set (like +B / bot)
UmodeAdd(modinfo->handle, 'X', UMODE_GLOBAL, 0, umode_allow_all, &UMODE_EXAMPLE);
Oper-only mode that unsets on de-oper (like +H / hide oper)
UmodeAdd(modinfo->handle, 'X', UMODE_GLOBAL, 1, umode_allow_opers, &UMODE_SHOWWHOIS);
Here unset_on_deoper is set to 1, so the mode is automatically removed if the user loses oper status. And umode_allow_opers ensures only opers can set it.
Server/services-only mode (like +r)
UmodeAdd(modinfo->handle, 'X', UMODE_GLOBAL, 0, umode_allow_none, &UMODE_DEAF);
Here umode_allow_none means local users cannot set or unset this mode — only the server can.
More information
UnrealIRCd ships with many user mode modules that you can use for examples and inspiration, they are all in src/modules/usermodes/