kike: fix RPL_WHOISCHANNELS and RPL_NAMREPLY
Now we automatically split the lists and send multiple replies, but only if it's needed.
This commit is contained in:
parent
3552b9e1fb
commit
7bcf2a066b
81
kike.c
81
kike.c
|
@ -944,23 +944,66 @@ client_set_ping_timer (struct client *c)
|
||||||
|
|
||||||
// --- IRC command handling ----------------------------------------------------
|
// --- IRC command handling ----------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_make_reply (struct client *c, int id, va_list ap, struct str *output)
|
||||||
|
{
|
||||||
|
str_append_printf (output, ":%s %03d %s ",
|
||||||
|
c->ctx->server_name, id, c->nickname ? c->nickname : "");
|
||||||
|
str_append_vprintf (output,
|
||||||
|
irc_get_text (c->ctx, id, g_default_replies[id]), ap);
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: this way we cannot typecheck the arguments, so we must be careful
|
// XXX: this way we cannot typecheck the arguments, so we must be careful
|
||||||
static void
|
static void
|
||||||
irc_send_reply (struct client *c, int id, ...)
|
irc_send_reply (struct client *c, int id, ...)
|
||||||
{
|
{
|
||||||
struct str tmp;
|
struct str reply;
|
||||||
str_init (&tmp);
|
str_init (&reply);
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start (ap, id);
|
va_start (ap, id);
|
||||||
str_append_printf (&tmp, ":%s %03d %s ",
|
irc_make_reply (c, id, ap, &reply);
|
||||||
c->ctx->server_name, id, c->nickname ? c->nickname : "");
|
|
||||||
str_append_vprintf (&tmp,
|
|
||||||
irc_get_text (c->ctx, id, g_default_replies[id]), ap);
|
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
client_send_str (c, &tmp);
|
client_send_str (c, &reply);
|
||||||
str_free (&tmp);
|
str_free (&reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a space-separated list of words across as many replies as needed
|
||||||
|
static void
|
||||||
|
irc_send_reply_vector (struct client *c, int id, char **items, ...)
|
||||||
|
{
|
||||||
|
struct str common;
|
||||||
|
str_init (&common);
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, items);
|
||||||
|
irc_make_reply (c, id, ap, &common);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
|
// We always send at least one message (there might be a client that
|
||||||
|
// expects us to send this message at least once)
|
||||||
|
do
|
||||||
|
{
|
||||||
|
struct str reply;
|
||||||
|
str_init (&reply);
|
||||||
|
str_append_str (&reply, &common);
|
||||||
|
|
||||||
|
// If not even a single item fits in the limit (which may happen,
|
||||||
|
// in theory) it just gets cropped. We could also skip it.
|
||||||
|
if (*items)
|
||||||
|
str_append (&reply, *items++);
|
||||||
|
|
||||||
|
// Append as many items as fits in a single message
|
||||||
|
while (*items
|
||||||
|
&& reply.len + 1 + strlen (*items) <= IRC_MAX_MESSAGE_LENGTH)
|
||||||
|
str_append_printf (&reply, " %s", *items++);
|
||||||
|
|
||||||
|
client_send_str (c, &reply);
|
||||||
|
str_free (&reply);
|
||||||
|
}
|
||||||
|
while (*items);
|
||||||
|
str_free (&common);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RETURN_WITH_REPLY(c, ...) \
|
#define RETURN_WITH_REPLY(c, ...) \
|
||||||
|
@ -1858,13 +1901,8 @@ irc_send_rpl_namreply (struct client *c, const struct channel *chan)
|
||||||
str_vector_add_owned (&nicks, str_steal (&result));
|
str_vector_add_owned (&nicks, str_steal (&result));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nicks.len)
|
irc_send_reply_vector (c, IRC_RPL_NAMREPLY,
|
||||||
{
|
nicks.vector, type, chan->name, "");
|
||||||
// FIXME: split it into multiple messages if it's too long
|
|
||||||
char *reply = join_str_vector (&nicks, ' ');
|
|
||||||
irc_send_reply (c, IRC_RPL_NAMREPLY, type, chan->name, reply);
|
|
||||||
free (reply);
|
|
||||||
}
|
|
||||||
str_vector_free (&nicks);
|
str_vector_free (&nicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2024,6 +2062,9 @@ irc_send_whois_reply (struct client *c, const struct client *target)
|
||||||
if (target->away_message)
|
if (target->away_message)
|
||||||
irc_send_reply (c, IRC_RPL_AWAY, nick, target->away_message);
|
irc_send_reply (c, IRC_RPL_AWAY, nick, target->away_message);
|
||||||
|
|
||||||
|
struct str_vector channels;
|
||||||
|
str_vector_init (&channels);
|
||||||
|
|
||||||
struct str_map_iter iter;
|
struct str_map_iter iter;
|
||||||
str_map_iter_init (&iter, &c->ctx->channels);
|
str_map_iter_init (&iter, &c->ctx->channels);
|
||||||
struct channel *chan;
|
struct channel *chan;
|
||||||
|
@ -2040,14 +2081,12 @@ irc_send_whois_reply (struct client *c, const struct client *target)
|
||||||
else if (channel_user->modes & IRC_CHAN_MODE_VOICE)
|
else if (channel_user->modes & IRC_CHAN_MODE_VOICE)
|
||||||
str_append_c (&item, '+');
|
str_append_c (&item, '+');
|
||||||
str_append (&item, chan->name);
|
str_append (&item, chan->name);
|
||||||
str_append_c (&item, ' ');
|
str_vector_add_owned (&channels, str_steal (&item));
|
||||||
|
|
||||||
// TODO: try to merge the results into as few messages as possible
|
|
||||||
irc_send_reply (c, IRC_RPL_WHOISCHANNELS, nick, item.str);
|
|
||||||
|
|
||||||
str_free (&item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irc_send_reply_vector (c, IRC_RPL_WHOISCHANNELS, channels.vector, nick, "");
|
||||||
|
str_vector_free (&channels);
|
||||||
|
|
||||||
irc_send_reply (c, IRC_RPL_ENDOFWHOIS, nick);
|
irc_send_reply (c, IRC_RPL_ENDOFWHOIS, nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue