From d15c82346ee3d4f260afbce943602a80e0db64e0 Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Fri, 21 Mar 2025 15:35:21 +0100 Subject: [PATCH] Pass ClientContext in CMD_FUNC() and friends. So extra arg. Breaking change. It now passes 'clictx' which at the moment only has clictx->cmd which points to the command handler. So only useful in very few cases where you have like a generic command handler and thus have no idea for which command you are being called. In the future, with this new ClientContext struct, we can simply add new fields to the struct without breaking things in the core and in (third party) modules. If you use the magic functions in your modules CMD_FUNC(cmd_mycmd), OVERRIDE_FUNC(myoverride), CALL_NEXT_COMMAND_OVERRIDE() and such then you shouldn't have any compile errors as these will use the correct prototypes and variable names automatically. In a few cases you can't use these, in which case you will need to update your modules. --- doc/RELEASE-NOTES.md | 8 +++++++- include/h.h | 6 +++--- include/modules.h | 4 ++-- include/struct.h | 22 ++++++++++++++-------- src/aliases.c | 2 +- src/api-command.c | 5 ++++- src/api-efunctions.c | 4 ++-- src/modules.c | 6 +++--- src/modules/rpc/name_ban.c | 2 +- src/modules/rpc/server_ban.c | 2 +- src/modules/rpc/server_ban_exception.c | 2 +- src/modules/rpc/spamfilter.c | 2 +- src/modules/sqline.c | 2 +- src/modules/tkl.c | 14 +++++++------- src/modules/umode2.c | 3 ++- src/modules/unsqline.c | 2 +- src/parse.c | 17 +++++++++++------ 17 files changed, 62 insertions(+), 41 deletions(-) diff --git a/doc/RELEASE-NOTES.md b/doc/RELEASE-NOTES.md index a00c28500..a6aacd7f7 100644 --- a/doc/RELEASE-NOTES.md +++ b/doc/RELEASE-NOTES.md @@ -14,7 +14,13 @@ This is work in progress and may not always be a stable version. * TODO ### Developers and protocol: -* TODO +* Command handlers (and overrides) now have an extra argument + `ClientContext *clictx`. Right now it only has `clictx->cmd` + which points to the command handler, but in the future more + fields can easily be added to this struct. In your modules + you should normally use `CMD_FUNC(cmd_mycmd)` and + `CMD_OVERRIDE_FUNC(myoverridefunc)` and `CALL_NEXT_COMMAND_OVERRIDE()` + and then your module does not updating between 6.1.x and 6.2.x. UnrealIRCd 6.1.10 ================== diff --git a/include/h.h b/include/h.h index 8e73a7af5..1fb4bccc5 100644 --- a/include/h.h +++ b/include/h.h @@ -795,7 +795,7 @@ extern MODVAR MultiLineMode *(*set_mode)(Channel *channel, Client *cptr, int par char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); extern MODVAR void (*set_channel_mode)(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters); extern MODVAR void (*set_channel_topic)(Client *client, Channel *channel, MessageTag *recv_mtags, const char *topic, const char *set_by, time_t set_at); -extern MODVAR void (*cmd_umode)(Client *, MessageTag *, int, const char **); +extern MODVAR void (*cmd_umode)(ClientContext *, Client *, MessageTag *, int, const char **); extern MODVAR int (*register_user)(Client *client); extern MODVAR int (*tkl_hash)(unsigned int c); extern MODVAR char (*tkl_typetochar)(int type); @@ -835,7 +835,7 @@ extern MODVAR TKL *(*find_qline)(Client *cptr, const char *nick, int *ishold); extern MODVAR TKL *(*find_tkline_match_zap)(Client *cptr); extern MODVAR void (*tkl_stats)(Client *cptr, int type, const char *para, int *cnt); extern MODVAR void (*tkl_sync)(Client *client); -extern MODVAR void (*cmd_tkl)(Client *client, MessageTag *recv_mtags, int parc, const char *parv[]); +extern MODVAR void (*cmd_tkl)(ClientContext *clictx, Client *client, MessageTag *recv_mtags, int parc, const char *parv[]); extern MODVAR int (*take_action)(Client *client, BanAction *actions, const char *reason, long duration, int take_action_flags, int *stopped); extern MODVAR int (*match_spamfilter)(Client *client, const char *str_in, int type, const char *cmd, const char *target, int flags, TKL **rettk); extern MODVAR int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, const char *cmd); @@ -1108,7 +1108,7 @@ extern CMD_FUNC(cmd_module); extern CMD_FUNC(cmd_rehash); extern CMD_FUNC(cmd_die); extern CMD_FUNC(cmd_restart); -extern void cmd_alias(Client *client, MessageTag *recv_mtags, int parc, const char *parv[], const char *cmd); /* special! */ +extern void cmd_alias(ClientContext *clictx, Client *client, MessageTag *recv_mtags, int parc, const char *parv[], const char *cmd); /* special! */ extern const char *pcre2_version(void); extern int get_terminal_width(void); extern int has_common_channels(Client *c1, Client *c2); diff --git a/include/modules.h b/include/modules.h index 969d84228..92a26afff 100644 --- a/include/modules.h +++ b/include/modules.h @@ -998,12 +998,12 @@ extern void CommandDelX(Command *command, RealCommand *cmd); extern int CommandExists(const char *name); extern CommandOverride *CommandOverrideAdd(Module *module, const char *name, int priority, OverrideCmdFunc func); extern void CommandOverrideDel(CommandOverride *ovr); -extern void CallCommandOverride(CommandOverride *ovr, Client *client, MessageTag *mtags, int parc, const char *parv[]); +extern void CallCommandOverride(CommandOverride *ovr, ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[]); /** Call next command override function - easy way to do it. * This way you don't have to call CallCommandOverride() with the right arguments. * Which is nice because command (override) arguments may change in future UnrealIRCd versions. */ -#define CALL_NEXT_COMMAND_OVERRIDE() CallCommandOverride(ovr, client, recv_mtags, parc, parv) +#define CALL_NEXT_COMMAND_OVERRIDE() CallCommandOverride(ovr, clictx, client, recv_mtags, parc, parv) extern void moddata_free_client(Client *acptr); extern void moddata_free_local_client(Client *acptr); diff --git a/include/struct.h b/include/struct.h index e105de4d3..55878ba63 100644 --- a/include/struct.h +++ b/include/struct.h @@ -913,6 +913,11 @@ struct SWhois { char *setby; }; +/** Client context (passed in commands) */ +typedef struct ClientContext { + RealCommand *cmd; /**< Command handler (eg. cmd->command is the command name) */ +} ClientContext; + /** The command API - used by modules and the core to add commands, overrides, etc. * See also https://www.unrealircd.org/docs/Dev:Command_API for a higher level overview and example. * @defgroup CommandAPI Command API @@ -945,7 +950,8 @@ struct SWhois { * This is used in the code like
CMD_FUNC(cmd_yourcmd)
as a function definition. * It allows UnrealIRCd devs to change the parameters in the function without * (necessarily) breaking your code. - * @param client The client + * @param clictx The client context. + * @param client The client. * @param recv_mtags Received message tags for this command. * @param parc Parameter count *plus* 1. * @param parv Parameter values. @@ -955,7 +961,7 @@ struct SWhois { * Note that reading parv[parc] and beyond is OUT OF BOUNDS and will cause a crash. * E.g. parv[3] in the above example is out of bounds. */ -#define CMD_FUNC(x) void (x) (Client *client, MessageTag *recv_mtags, int parc, const char *parv[]) +#define CMD_FUNC(x) void (x) (ClientContext *clictx, Client *client, MessageTag *recv_mtags, int parc, const char *parv[]) /** Call a command function - can be useful if you are calling another command function in your own module. * For example in cmd_nick() we call cmd_nick_local() for local functions, @@ -963,14 +969,14 @@ struct SWhois { * to bother with passing the right command arguments. Which is nice because * command arguments may change in future UnrealIRCd versions. */ -#define CALL_CMD_FUNC(x) (x)(client, recv_mtags, parc, parv) +#define CALL_CMD_FUNC(x) (x)(clictx, client, recv_mtags, parc, parv) /** @} */ /** Command override function - used by all command override handlers. * This is used in the code like
CMD_OVERRIDE_FUNC(ovr_somecmd)
as a function definition. * @param ovr The command override structure. - * @param cptr The client direction pointer. + * @param clictx The client context. * @param client The source client pointer (you usually need this one). * @param recv_mtags Received message tags for this command. * @param parc Parameter count *plus* 1. @@ -981,13 +987,13 @@ struct SWhois { * Note that reading parv[parc] and beyond is OUT OF BOUNDS and will cause a crash. * E.g. parv[3] in the above example. */ -#define CMD_OVERRIDE_FUNC(x) void (x)(CommandOverride *ovr, Client *client, MessageTag *recv_mtags, int parc, const char *parv[]) +#define CMD_OVERRIDE_FUNC(x) void (x)(CommandOverride *ovr, ClientContext *clictx, Client *client, MessageTag *recv_mtags, int parc, const char *parv[]) -typedef void (*CmdFunc)(Client *client, MessageTag *mtags, int parc, const char *parv[]); -typedef void (*AliasCmdFunc)(Client *client, MessageTag *mtags, int parc, const char *parv[], const char *cmd); -typedef void (*OverrideCmdFunc)(CommandOverride *ovr, Client *client, MessageTag *mtags, int parc, const char *parv[]); +typedef void (*CmdFunc)(ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[]); +typedef void (*AliasCmdFunc)(ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[], const char *cmd); +typedef void (*OverrideCmdFunc)(CommandOverride *ovr, ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[]); #include diff --git a/src/aliases.c b/src/aliases.c index 7ec46f3e1..6f2c39a49 100644 --- a/src/aliases.c +++ b/src/aliases.c @@ -42,7 +42,7 @@ void strrangetok(char *in, char *out, char tok, short first, short last) { /* cmd_alias is a special type of command, it has an extra argument 'cmd'. */ static int recursive_alias = 0; -void cmd_alias(Client *client, MessageTag *mtags, int parc, const char *parv[], const char *cmd) +void cmd_alias(ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[], const char *cmd) { ConfigItem_alias *alias; Client *acptr; diff --git a/src/api-command.c b/src/api-command.c index 065a4eb16..cd90aff94 100644 --- a/src/api-command.c +++ b/src/api-command.c @@ -194,6 +194,7 @@ void CommandDel(Command *command) void do_cmd(Client *client, MessageTag *mtags, const char *cmd, int parc, const char *parv[]) { RealCommand *cmptr; + ClientContext clictx; cmptr = find_command_simple(cmd); if (cmptr) @@ -201,7 +202,9 @@ void do_cmd(Client *client, MessageTag *mtags, const char *cmd, int parc, const int gen_mtags = (mtags == NULL) ? 1 : 0; if (gen_mtags) new_message(client, NULL, &mtags); - (*cmptr->func) (client, mtags, parc, parv); + memset(&clictx, 0, sizeof(clictx)); + clictx.cmd = cmptr; + (*cmptr->func) (&clictx, client, mtags, parc, parv); if (gen_mtags) free_message_tags(mtags); } diff --git a/src/api-efunctions.c b/src/api-efunctions.c index 24649053d..875ac7ece 100644 --- a/src/api-efunctions.c +++ b/src/api-efunctions.c @@ -45,7 +45,7 @@ MultiLineMode *(*set_mode)(Channel *channel, Client *client, int parc, const cha char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); void (*set_channel_mode)(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters); void (*set_channel_topic)(Client *client, Channel *channel, MessageTag *recv_mtags, const char *topic, const char *set_by, time_t set_at); -void (*cmd_umode)(Client *client, MessageTag *mtags, int parc, const char *parv[]); +void (*cmd_umode)(ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[]); int (*register_user)(Client *client); int (*tkl_hash)(unsigned int c); char (*tkl_typetochar)(int type); @@ -79,7 +79,7 @@ TKL *(*find_qline)(Client *client, const char *nick, int *ishold); TKL *(*find_tkline_match_zap)(Client *client); void (*tkl_stats)(Client *client, int type, const char *para, int *cnt); void (*tkl_sync)(Client *client); -void (*cmd_tkl)(Client *client, MessageTag *mtags, int parc, const char *parv[]); +void (*cmd_tkl)(ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[]); int (*take_action)(Client *client, BanAction *action, const char *reason, long duration, int take_action_flags, int *stopped); int (*match_spamfilter)(Client *client, const char *str_in, int type, const char *cmd, const char *target, int flags, TKL **rettk); int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, const char *cmd); diff --git a/src/modules.c b/src/modules.c index fb8c1a495..7e36bd7c7 100644 --- a/src/modules.c +++ b/src/modules.c @@ -1186,12 +1186,12 @@ void CommandOverrideDel(CommandOverride *cmd) safe_free(cmd); } -void CallCommandOverride(CommandOverride *ovr, Client *client, MessageTag *mtags, int parc, const char *parv[]) +void CallCommandOverride(CommandOverride *ovr, ClientContext *clictx, Client *client, MessageTag *mtags, int parc, const char *parv[]) { if (ovr->next) - ovr->next->func(ovr->next, client, mtags, parc, parv); + ovr->next->func(ovr->next, clictx, client, mtags, parc, parv); else - ovr->command->func(client, mtags, parc, parv); + ovr->command->func(clictx, client, mtags, parc, parv); } EVENT(e_unload_module_delayed) diff --git a/src/modules/rpc/name_ban.c b/src/modules/rpc/name_ban.c index 75526c80c..c9feed22d 100644 --- a/src/modules/rpc/name_ban.c +++ b/src/modules/rpc/name_ban.c @@ -162,7 +162,7 @@ RPC_CALL_FUNC(rpc_name_ban_del) tkllayer[4] = name; tkllayer[5] = set_by; tkllayer[6] = NULL; - cmd_tkl(&me, NULL, 6, tkllayer); + cmd_tkl(NULL, &me, NULL, 6, tkllayer); if (!my_find_tkl_nameban(name)) { diff --git a/src/modules/rpc/server_ban.c b/src/modules/rpc/server_ban.c index f9dc7a72e..aa97cc4a7 100644 --- a/src/modules/rpc/server_ban.c +++ b/src/modules/rpc/server_ban.c @@ -248,7 +248,7 @@ RPC_CALL_FUNC(rpc_server_ban_del) tkllayer[4] = hostmask; tkllayer[5] = set_by; tkllayer[6] = NULL; - cmd_tkl(&me, NULL, 6, tkllayer); + cmd_tkl(NULL, &me, NULL, 6, tkllayer); if (!find_tkl_serverban(tkl_type_int, usermask, hostmask, soft)) { diff --git a/src/modules/rpc/server_ban_exception.c b/src/modules/rpc/server_ban_exception.c index 4ccc12e17..08d7814a5 100644 --- a/src/modules/rpc/server_ban_exception.c +++ b/src/modules/rpc/server_ban_exception.c @@ -221,7 +221,7 @@ RPC_CALL_FUNC(rpc_server_ban_exception_del) tkllayer[8] = "-"; tkllayer[9] = "-"; tkllayer[10] = NULL; - cmd_tkl(&me, NULL, 6, tkllayer); + cmd_tkl(NULL, &me, NULL, 6, tkllayer); if (!find_tkl_banexception(TKL_EXCEPTION|TKL_GLOBAL, usermask, hostmask, soft) && !find_tkl_banexception(TKL_EXCEPTION, usermask, hostmask, soft)) diff --git a/src/modules/rpc/spamfilter.c b/src/modules/rpc/spamfilter.c index 1ef29e7c4..90e8c0b38 100644 --- a/src/modules/rpc/spamfilter.c +++ b/src/modules/rpc/spamfilter.c @@ -319,7 +319,7 @@ RPC_CALL_FUNC(rpc_spamfilter_del) tkllayer[11] = name; tkllayer[12] = NULL; - cmd_tkl(&me, NULL, 12, tkllayer); + cmd_tkl(NULL, &me, NULL, 12, tkllayer); tkl = find_tkl_spamfilter(type, name, action, targets); if (!tkl) diff --git a/src/modules/sqline.c b/src/modules/sqline.c index a3a0bd9a4..70e0380af 100644 --- a/src/modules/sqline.c +++ b/src/modules/sqline.c @@ -83,5 +83,5 @@ CMD_FUNC(cmd_sqline) ircsnprintf(mo, sizeof(mo), "%lld", (long long)TStime()); tkllayer[7] = mo; tkllayer[8] = comment ? comment : "no reason"; - cmd_tkl(&me, NULL, 9, tkllayer); + cmd_tkl(NULL, &me, NULL, 9, tkllayer); } diff --git a/src/modules/tkl.c b/src/modules/tkl.c index 86d78e8b4..ca786c068 100644 --- a/src/modules/tkl.c +++ b/src/modules/tkl.c @@ -1997,12 +1997,12 @@ void cmd_tkl_line(Client *client, int parc, const char *parv[], char *type) } /* call the tkl layer .. */ - cmd_tkl(&me, NULL, 9, tkllayer); + cmd_tkl(NULL, &me, NULL, 9, tkllayer); } else { /* call the tkl layer .. */ - cmd_tkl(&me, NULL, 6, tkllayer); + cmd_tkl(NULL, &me, NULL, 6, tkllayer); } } @@ -2349,13 +2349,13 @@ CMD_FUNC(cmd_eline) } tkllayer[9] = reason; /* call the tkl layer .. */ - cmd_tkl(&me, NULL, 10, tkllayer); + cmd_tkl(NULL, &me, NULL, 10, tkllayer); } else { /* Remove ELINE */ /* call the tkl layer .. */ - cmd_tkl(&me, NULL, 10, tkllayer); + cmd_tkl(NULL, &me, NULL, 10, tkllayer); } } @@ -2439,7 +2439,7 @@ void spamfilter_del_by_id(Client *client, const char *id) ircsnprintf(mo2, sizeof(mo2), "%lld", (long long)TStime()); tkllayer[7] = mo2; /* deletion time */ - cmd_tkl(&me, NULL, 12, tkllayer); + cmd_tkl(NULL, &me, NULL, 12, tkllayer); } /** Spamfilter to fight spam, advertising, worms and other bad things on IRC. @@ -2632,7 +2632,7 @@ CMD_FUNC(cmd_spamfilter) tkllayer[7] = mo2; } - cmd_tkl(&me, NULL, 12, tkllayer); + cmd_tkl(NULL, &me, NULL, 12, tkllayer); } /** tkl hash method. @@ -5190,7 +5190,7 @@ int _take_action(Client *client, BanAction *actions, char *reason, long duration tkllayer[6] = mo; tkllayer[7] = mo2; tkllayer[8] = reason; - cmd_tkl(&me, NULL, 9, tkllayer); + cmd_tkl(NULL, &me, NULL, 9, tkllayer); RunHookReturnInt(HOOKTYPE_TAKE_ACTION, !=99, client, action->action, reason, duration); if ((action->action == BAN_ACT_SHUN) || (action->action == BAN_ACT_SOFT_SHUN)) { diff --git a/src/modules/umode2.c b/src/modules/umode2.c index ce38b3458..6d13e6667 100644 --- a/src/modules/umode2.c +++ b/src/modules/umode2.c @@ -70,5 +70,6 @@ CMD_FUNC(cmd_umode2) if (!parv[1]) return; - cmd_umode(client, recv_mtags, (parc > 3) ? 4 : 3, xparv); + /* (passing clictx here is kinda wrong, but why is this not a do_cmd anyway?) */ + cmd_umode(clictx, client, recv_mtags, (parc > 3) ? 4 : 3, xparv); } diff --git a/src/modules/unsqline.c b/src/modules/unsqline.c index e1fc6149b..040a92597 100644 --- a/src/modules/unsqline.c +++ b/src/modules/unsqline.c @@ -70,5 +70,5 @@ CMD_FUNC(cmd_unsqline) if (parc < 2) return; - cmd_tkl(&me, NULL, 6, tkllayer); + cmd_tkl(NULL, &me, NULL, 6, tkllayer); } diff --git a/src/parse.c b/src/parse.c index 8b67fb3f7..0688f5022 100644 --- a/src/parse.c +++ b/src/parse.c @@ -264,6 +264,7 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_ int retval; #endif RealCommand *cmptr = NULL; + ClientContext clictx; int bytes; *fromptr = cptr; /* The default, unless a source is specified (and permitted) */ @@ -552,27 +553,31 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_ if (IsUser(cptr) && (cmptr->flags & CMD_RESETIDLE)) cptr->local->idle_since = TStime(); + /* Client context. Right now not so useful, but can be extended later: */ + memset(&clictx, 0, sizeof(clictx)); + clictx.cmd = cmptr; + /* Now ready to execute the command */ #ifndef DEBUGMODE if (cmptr->flags & CMD_ALIAS) { - (*cmptr->aliasfunc) (from, mtags, i, (const char **)para, cmptr->cmd); + (*cmptr->aliasfunc) (&clictx, from, mtags, i, (const char **)para, cmptr->cmd); } else { if (!cmptr->overriders) - (*cmptr->func) (from, mtags, i, (const char **)para); + (*cmptr->func) (&clictx, from, mtags, i, (const char **)para); else - (*cmptr->overriders->func) (cmptr->overriders, from, mtags, i, (const char **)para); + (*cmptr->overriders->func) (cmptr->overriders, &clictx, from, mtags, i, (const char **)para); } #else then = clock(); if (cmptr->flags & CMD_ALIAS) { - (*cmptr->aliasfunc) (from, mtags, i, (const char **)para, cmptr->cmd); + (*cmptr->aliasfunc) (&clictx, from, mtags, i, (const char **)para, cmptr->cmd); } else { if (!cmptr->overriders) - (*cmptr->func) (from, mtags, i, (const char **)para); + (*cmptr->func) (&clictx, from, mtags, i, (const char **)para); else - (*cmptr->overriders->func) (cmptr->overriders, from, mtags, i, (const char **)para); + (*cmptr->overriders->func) (cmptr->overriders, &clictx, from, mtags, i, (const char **)para); } if (!IsDead(cptr)) {