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:
+10
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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(¤tcmd, 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(¤tcmd, 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, ¤tcmd, 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(¤tcmd, 0, sizeof(currentcmd));
|
||||
} else {
|
||||
/* Set the current context to the provided one */
|
||||
memcpy(¤tcmd, 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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user