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,
|
||||
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_OPER 1
|
||||
#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);
|
||||
}
|
||||
|
||||
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