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