send: add sendto_one_multiline_* API
Allows simplifying multiline wrapping for multiple usages, like CAP LS/LIST, NAMES, and WHOIS channel listing
This commit is contained in:
parent
f0356d2a6f
commit
8efff56fdf
2 changed files with 180 additions and 0 deletions
|
@ -93,6 +93,18 @@ extern void kill_client(struct Client *client_p, struct Client *diedie,
|
||||||
extern void kill_client_serv_butone(struct Client *one, struct Client *source_p,
|
extern void kill_client_serv_butone(struct Client *one, struct Client *source_p,
|
||||||
const char *pattern, ...) AFP(3, 4);
|
const char *pattern, ...) AFP(3, 4);
|
||||||
|
|
||||||
|
enum multiline_item_result {
|
||||||
|
MULTILINE_FAILURE,
|
||||||
|
MULTILINE_SUCCESS,
|
||||||
|
MULTILINE_WRAPPED,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern bool send_multiline_init(struct Client *target_p, const char *separator, const char *format, ...) AFP(3, 4);
|
||||||
|
extern bool send_multiline_remote_pad(struct Client *target_p, struct Client *client_p);
|
||||||
|
extern enum multiline_item_result send_multiline_item(struct Client *target_p, const char *format, ...) AFP(2, 3);
|
||||||
|
extern bool send_multiline_fini(struct Client *target_p, const char *format, ...) AFP(2, 3);
|
||||||
|
extern void send_multiline_reset(void);
|
||||||
|
|
||||||
#define L_ALL 0
|
#define L_ALL 0
|
||||||
#define L_OPER 1
|
#define L_OPER 1
|
||||||
#define L_ADMIN 2
|
#define L_ADMIN 2
|
||||||
|
|
168
ircd/send.c
168
ircd/send.c
|
@ -1503,3 +1503,171 @@ kill_client_serv_butone(struct Client *one, struct Client *target_p, const char
|
||||||
|
|
||||||
rb_linebuf_donebuf(&rb_linebuf_id);
|
rb_linebuf_donebuf(&rb_linebuf_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct Client *multiline_stashed_target_p;
|
||||||
|
static char multiline_prefix[DATALEN+1]; /* allow for null termination */
|
||||||
|
static int multiline_prefix_len;
|
||||||
|
static char multiline_separator[2];
|
||||||
|
static int multiline_separator_len;
|
||||||
|
static char *multiline_item_start;
|
||||||
|
static char *multiline_cur;
|
||||||
|
static int multiline_cur_len;
|
||||||
|
static int multiline_remote_pad;
|
||||||
|
|
||||||
|
bool
|
||||||
|
send_multiline_init(struct Client *target_p, const char *separator, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
s_assert(multiline_stashed_target_p == NULL && "Multiline: didn't cleanup after last usage!");
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
multiline_prefix_len = vsnprintf(multiline_prefix, sizeof multiline_prefix, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (multiline_prefix_len <= 0 || multiline_prefix_len >= DATALEN)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: failure preparing prefix!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiline_separator_len = rb_strlcpy(multiline_separator, separator, sizeof multiline_separator);
|
||||||
|
if (multiline_separator_len >= sizeof multiline_separator)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: separator too long");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiline_stashed_target_p = target_p;
|
||||||
|
multiline_item_start = multiline_prefix + multiline_prefix_len;
|
||||||
|
multiline_cur = multiline_item_start;
|
||||||
|
multiline_cur_len = multiline_prefix_len;
|
||||||
|
multiline_remote_pad = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
send_multiline_remote_pad(struct Client *target_p, struct Client *client_p)
|
||||||
|
{
|
||||||
|
ssize_t remote_pad;
|
||||||
|
|
||||||
|
if (target_p != multiline_stashed_target_p)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: missed init call!");
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MyConnect(target_p))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
remote_pad = strlen(client_p->name) - strlen(client_p->id);
|
||||||
|
|
||||||
|
if (remote_pad > 0)
|
||||||
|
{
|
||||||
|
multiline_remote_pad += remote_pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum multiline_item_result
|
||||||
|
send_multiline_item(struct Client *target_p, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char item[DATALEN];
|
||||||
|
int item_len, res;
|
||||||
|
enum multiline_item_result ret = MULTILINE_SUCCESS;
|
||||||
|
|
||||||
|
if (target_p != multiline_stashed_target_p)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: missed init call!");
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return MULTILINE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
item_len = vsnprintf(item, sizeof item, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (item_len < 0 || multiline_prefix_len + multiline_remote_pad + item_len > DATALEN)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: failure preparing item!");
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return MULTILINE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiline_cur_len + ((*multiline_item_start != '\0') ? multiline_separator_len : 0) + item_len > DATALEN - multiline_remote_pad)
|
||||||
|
{
|
||||||
|
sendto_one(target_p, "%s", multiline_prefix);
|
||||||
|
*multiline_item_start = '\0';
|
||||||
|
multiline_cur_len = multiline_prefix_len;
|
||||||
|
multiline_cur = multiline_item_start;
|
||||||
|
ret = MULTILINE_WRAPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = snprintf(multiline_cur, sizeof multiline_prefix - multiline_cur_len, "%s%s",
|
||||||
|
(*multiline_item_start != '\0') ? multiline_separator : "",
|
||||||
|
item);
|
||||||
|
|
||||||
|
if (res < 0)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: failure appending item!");
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return MULTILINE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiline_cur_len += res;
|
||||||
|
multiline_cur += res;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
send_multiline_fini(struct Client *target_p, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char final[DATALEN];
|
||||||
|
int final_len;
|
||||||
|
|
||||||
|
if (target_p != multiline_stashed_target_p)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: missed init call!");
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiline_cur_len == multiline_prefix_len)
|
||||||
|
{
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format)
|
||||||
|
{
|
||||||
|
va_start(args, format);
|
||||||
|
final_len = vsnprintf(final, sizeof final, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (final_len <= 0 || final_len > multiline_prefix_len)
|
||||||
|
{
|
||||||
|
s_assert(false && "Multiline: failure preparing final prefix!");
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rb_strlcpy(final, multiline_prefix, multiline_prefix_len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendto_one(target_p, "%s%s", final, multiline_item_start);
|
||||||
|
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
send_multiline_reset(void)
|
||||||
|
{
|
||||||
|
multiline_stashed_target_p = NULL;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue