1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-08 04:23:13 +02:00

Support for labeled-response in LIST (I really wanted this)

This commit is contained in:
Bram Matthys
2019-10-05 18:15:48 +02:00
parent f992a0c1c0
commit c399aab016
7 changed files with 147 additions and 32 deletions
+10
View File
@@ -673,6 +673,7 @@ extern void do_cmd(Client *client, MessageTag *mtags, char *cmd, int parc, char
extern MODVAR char *me_hash;
extern MODVAR int dontspread;
extern MODVAR int labeled_response_inhibit;
extern MODVAR int labeled_response_inhibit_end;
extern MODVAR int labeled_response_force;
/* Efuncs */
@@ -758,8 +759,17 @@ extern MODVAR int (*find_tkl_exception)(int ban_type, Client *cptr);
extern MODVAR int (*del_silence)(Client *client, const char *mask);
extern MODVAR int (*add_silence)(Client *client, const char *mask, int senderr);
extern MODVAR int (*is_silenced)(Client *client, Client *acptr);
extern MODVAR void *(*labeled_response_save_context)(void);
extern MODVAR void (*labeled_response_set_context)(void *ctx);
extern MODVAR void (*labeled_response_force_end)(void);
/* /Efuncs */
extern void parse_message_tags_default_handler(Client *client, char **str, MessageTag **mtag_list);
extern char *mtags_to_string_default_handler(MessageTag *m, Client *client);
extern void *labeled_response_save_context_default_handler(void);
extern void labeled_response_set_context_default_handler(void *ctx);
extern void labeled_response_force_end_default_handler(void);
extern MODVAR MOTDFile opermotd, svsmotd, motd, botmotd, smotd, rules;
extern MODVAR int max_connection_count;
extern int add_listmode(Ban **list, Client *cptr, Channel *channel, char *banid);
+3
View File
@@ -1297,6 +1297,9 @@ enum EfunctionType {
EFUNC_ADD_SILENCE,
EFUNC_DEL_SILENCE,
EFUNC_IS_SILENCED,
EFUNC_LABELED_RESPONSE_SAVE_CONTEXT,
EFUNC_LABELED_RESPONSE_SET_CONTEXT,
EFUNC_LABELED_RESPONSE_FORCE_END,
};
/* Module flags */
+7 -2
View File
@@ -99,9 +99,7 @@ int (*do_remote_nick_name)(char *nick);
char *(*charsys_get_current_languages)(void);
void (*broadcast_sinfo)(Client *client, Client *to, Client *except);
void (*parse_message_tags)(Client *client, char **str, MessageTag **mtag_list);
extern void parse_message_tags_default_handler(Client *client, char **str, MessageTag **mtag_list);
char *(*mtags_to_string)(MessageTag *m, Client *client);
extern char *mtags_to_string_default_handler(MessageTag *m, Client *client);
int (*can_send_to_channel)(Client *client, Channel *channel, char **msgtext, char **errmsg, int notice);
void (*broadcast_md_globalvar)(ModDataInfo *mdi, ModData *md);
void (*broadcast_md_globalvar_cmd)(Client *except, Client *sender, char *varname, char *value);
@@ -118,6 +116,9 @@ int (*find_tkl_exception)(int ban_type, Client *client);
int (*is_silenced)(Client *client, Client *acptr);
int (*del_silence)(Client *client, const char *mask);
int (*add_silence)(Client *client, const char *mask, int senderr);
void *(*labeled_response_save_context)(void);
void (*labeled_response_set_context)(void *ctx);
void (*labeled_response_force_end)(void);
Efunction *EfunctionAddMain(Module *module, EfunctionType eftype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*cfunc)())
{
@@ -357,4 +358,8 @@ void efunctions_init(void)
efunc_init_function(EFUNC_ADD_SILENCE, add_silence, NULL);
efunc_init_function(EFUNC_DEL_SILENCE, del_silence, NULL);
efunc_init_function(EFUNC_IS_SILENCED, is_silenced, NULL);
efunc_init_function(EFUNC_IS_SILENCED, is_silenced, NULL);
efunc_init_function(EFUNC_LABELED_RESPONSE_SAVE_CONTEXT, labeled_response_save_context, labeled_response_save_context_default_handler);
efunc_init_function(EFUNC_LABELED_RESPONSE_SET_CONTEXT, labeled_response_set_context, labeled_response_set_context_default_handler);
efunc_init_function(EFUNC_LABELED_RESPONSE_FORCE_END, labeled_response_force_end, labeled_response_force_end_default_handler);
}
+19
View File
@@ -1326,6 +1326,25 @@ void generate_batch_id(char *str)
gen_random_alnum(str, BATCHLEN);
}
/* A default handler if labeled-response module is not loaded.
* Normally a NOOP, but since caller will safe_free it
* later we do actually allocate something.
*/
void *labeled_response_save_context_default_handler(void)
{
return safe_alloc(8);
}
/* A default handler for if labeled-response module is not loaded */
void labeled_response_set_context_default_handler(void *ctx)
{
}
/* A default handler for if labeled-response module is not loaded */
void labeled_response_force_end_default_handler(void)
{
}
/** my_timegm: mktime()-like function which will use GMT/UTC.
* Strangely enough there is no standard function for this.
* On some *NIX OS's timegm() may be available, sometimes only
+75 -20
View File
@@ -31,16 +31,9 @@ ModuleHeader MOD_HEADER
"unrealircd-5",
};
/* Forward declarations */
int lr_pre_command(Client *from, MessageTag *mtags, char *buf);
int lr_post_command(Client *from, MessageTag *mtags, char *buf);
int lr_packet(Client *from, Client *to, Client *intended_to, char **msg, int *len);
/* Our special version of SupportBatch() assumes that remote servers always handle it */
#define SupportBatch(x) (MyConnect(x) ? HasCapability((x), "batch") : 1)
#define SupportLabel(x) (HasCapabilityFast((x), CAP_LABELED_RESPONSE))
struct {
/* Data structures */
typedef struct LabeledResponseContext LabeledResponseContext;
struct LabeledResponseContext {
Client *client; /**< The client who issued the original command with a label */
char label[256]; /**< The label attached to this command */
char batch[BATCHLEN+1]; /**< The generated batch id */
@@ -48,14 +41,38 @@ struct {
int sent_remote; /**< Command has been sent to remote server */
int version; /**< Which version? Zero for official, non-zero is draft */
char firstbuf[4096]; /**< First buffered response */
} currentcmd;
};
long CAP_LABELED_RESPONSE = 0L;
/* Forward declarations */
int lr_pre_command(Client *from, MessageTag *mtags, char *buf);
int lr_post_command(Client *from, MessageTag *mtags, char *buf);
int lr_packet(Client *from, Client *to, Client *intended_to, char **msg, int *len);
void *_labeled_response_save_context(void);
void _labeled_response_set_context(void *ctx);
void _labeled_response_force_end(void);
/* Our special version of SupportBatch() assumes that remote servers always handle it */
#define SupportBatch(x) (MyConnect(x) ? HasCapability((x), "batch") : 1)
#define SupportLabel(x) (HasCapabilityFast((x), CAP_LABELED_RESPONSE))
/* Variables */
static LabeledResponseContext currentcmd;
static long CAP_LABELED_RESPONSE = 0L;
static char packet[8192];
int labeled_response_mtag_is_ok(Client *client, char *name, char *value);
MOD_TEST()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
EfunctionAddPVoid(modinfo->handle, EFUNC_LABELED_RESPONSE_SAVE_CONTEXT, _labeled_response_save_context);
EfunctionAddVoid(modinfo->handle, EFUNC_LABELED_RESPONSE_SET_CONTEXT, _labeled_response_set_context);
EfunctionAddVoid(modinfo->handle, EFUNC_LABELED_RESPONSE_FORCE_END, _labeled_response_force_end);
return MOD_SUCCESS;
}
MOD_INIT()
{
ClientCapabilityInfo cap;
@@ -96,7 +113,7 @@ MOD_UNLOAD()
int lr_pre_command(Client *from, MessageTag *mtags, char *buf)
{
memset(&currentcmd, 0, sizeof(currentcmd));
labeled_response_inhibit = labeled_response_force = 0;
labeled_response_inhibit = labeled_response_inhibit_end = labeled_response_force = 0;
for (; mtags; mtags = mtags->next)
{
@@ -215,16 +232,19 @@ int lr_post_command(Client *from, MessageTag *mtags, char *buf)
}
/* End the batch */
savedptr = currentcmd.client;
currentcmd.client = NULL;
if (MyConnect(savedptr))
sendto_one(from, NULL, ":%s BATCH -%s", me.name, currentcmd.batch);
else
sendto_one(from, NULL, ":%s BATCH %s -%s", me.name, savedptr->name, currentcmd.batch);
if (!labeled_response_inhibit_end)
{
savedptr = currentcmd.client;
currentcmd.client = NULL;
if (MyConnect(savedptr))
sendto_one(from, NULL, ":%s BATCH -%s", me.name, currentcmd.batch);
else
sendto_one(from, NULL, ":%s BATCH %s -%s", me.name, savedptr->name, currentcmd.batch);
}
}
done:
memset(&currentcmd, 0, sizeof(currentcmd));
labeled_response_inhibit = labeled_response_force = 0;
labeled_response_inhibit = labeled_response_inhibit_end = labeled_response_force = 0;
return 0;
}
@@ -340,3 +360,38 @@ int labeled_response_mtag_is_ok(Client *client, char *name, char *value)
return 0;
}
/** Save current context for later use in labeled-response.
* Currently used in /LIST. Is not planned for other places tbh.
*/
void *_labeled_response_save_context(void)
{
LabeledResponseContext *ctx = safe_alloc(sizeof(LabeledResponseContext));
memcpy(ctx, &currentcmd, sizeof(LabeledResponseContext));
return (void *)ctx;
}
/** Set previously saved context 'ctx', or clear the context.
* @param ctx The context, or NULL to clear the context.
* @note The client from the previously saved context should be
* the same. Don't save one context when processing
* client A and then restore it when processing client B (duh).
*/
void _labeled_response_set_context(void *ctx)
{
if (ctx == NULL)
{
/* This means: clear the current context */
memset(&currentcmd, 0, sizeof(currentcmd));
} else {
/* Set the current context to the provided one */
memcpy(&currentcmd, ctx, sizeof(LabeledResponseContext));
}
}
/** Force an end of the labeled-response (only used in /LIST atm) */
void _labeled_response_force_end(void)
{
if (currentcmd.client)
lr_post_command(currentcmd.client, NULL, NULL);
}
+27 -9
View File
@@ -23,7 +23,7 @@
#include "unrealircd.h"
CMD_FUNC(cmd_list);
void send_list(Client *client);
int send_list(Client *client);
#define MSG_LIST "LIST"
@@ -49,6 +49,7 @@ struct ChannelListOptions {
time_t chantimemax;
time_t topictimemin;
time_t topictimemax;
void *lr_context;
};
/* Global variables */
@@ -161,8 +162,12 @@ CMD_FUNC(cmd_list)
ALLOCATE_CHANNELLISTOPTIONS(client);
CHANNELLISTOPTIONS(client)->showall = 1;
if (DBufLength(&client->local->sendQ) < 2048)
send_list(client);
if (send_list(client))
{
/* Save context since there is more to be sent */
CHANNELLISTOPTIONS(client)->lr_context = labeled_response_save_context();
labeled_response_inhibit_end = 1;
}
return;
}
@@ -298,8 +303,12 @@ CMD_FUNC(cmd_list)
CHANNELLISTOPTIONS(client)->nolist = nolist;
CHANNELLISTOPTIONS(client)->yeslist = yeslist;
if (DBufLength(&client->local->sendQ) < 2048)
send_list(client);
if (send_list(client))
{
/* Save context since there is more to be sent */
CHANNELLISTOPTIONS(client)->lr_context = labeled_response_save_context();
labeled_response_inhibit_end = 1;
}
return;
}
@@ -312,7 +321,7 @@ CMD_FUNC(cmd_list)
* client = Local client to send the output back to.
* Taken from bahamut, modified for Unreal by codemastr.
*/
void send_list(Client *client)
int send_list(Client *client)
{
Channel *channel;
ChannelListOptions *lopt = CHANNELLISTOPTIONS(client);
@@ -426,7 +435,7 @@ void send_list(Client *client)
{
sendnumeric(client, RPL_LISTEND);
free_list_options(client);
return;
return 0;
}
/*
@@ -434,7 +443,7 @@ void send_list(Client *client)
* at once.
*/
lopt->starthash = hashnum;
return;
return 1;
}
EVENT(send_queued_list_data)
@@ -443,7 +452,15 @@ EVENT(send_queued_list_data)
list_for_each_entry_safe(client, saved, &lclient_list, lclient_node)
{
if (DoList(client) && IsSendable(client))
send_list(client);
{
labeled_response_set_context(CHANNELLISTOPTIONS(client)->lr_context);
if (!send_list(client))
{
/* We are done! */
labeled_response_force_end();
}
labeled_response_set_context(NULL);
}
}
}
@@ -457,6 +474,7 @@ void list_md_free(ModData *md)
free_entire_name_list(lopt->yeslist);
free_entire_name_list(lopt->nolist);
safe_free(lopt->lr_context);
safe_free(md->ptr);
}
+6 -1
View File
@@ -31,9 +31,10 @@ static char buf[BUFSIZE];
/** Inhibit labeled/response reply. This means it will result in an empty ACK
* because we cannot handle the command via labeled-reponse. Rare, but
* possible in for example /TRACE which multiple servers handle and which
* has no clear end. /LIST is another common example.
* has no clear end.
*/
MODVAR int labeled_response_inhibit = 0;
/** Force a labeled/response reply (of course, only if a label is present etc.).
* This is used in case the "a remote server is handling the request" was
* incorrect and there were 0 responses. This is the case for PRIVMSG.
@@ -43,6 +44,10 @@ MODVAR int labeled_response_inhibit = 0;
*/
MODVAR int labeled_response_force = 0;
/** Inhibit labeled/response END. Only used in /LIST.
*/
MODVAR int labeled_response_inhibit_end = 0;
/** Set to 1 if an UTF8 incompatible nick character set is in use */
MODVAR int non_utf8_nick_chars_in_use = 0;