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

From UnrealIRCd documentation wiki
Jump to navigation Jump to search

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/