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)) {