kike: finish implementation of NAMES

This commit is contained in:
Přemysl Eric Janouch 2015-06-13 13:31:59 +02:00
parent dd91b521df
commit 17be991dce
1 changed files with 58 additions and 18 deletions

76
kike.c
View File

@ -2093,8 +2093,26 @@ irc_append_prefixes (struct client *c, struct channel_user *user,
str_free (&prefixes);
}
static char *
irc_make_rpl_namreply_item
(struct client *c, struct client *target, struct channel_user *user)
{
struct str result;
str_init (&result);
if (user)
irc_append_prefixes (c, user, &result);
str_append (&result, target->nickname);
if (c->caps_enabled & IRC_CAP_USERHOST_IN_NAMES)
str_append_printf (&result,
"!%s@%s", target->username, target->hostname);
return str_steal (&result);
}
static void
irc_send_rpl_namreply (struct client *c, const struct channel *chan)
irc_send_rpl_namreply (struct client *c, const struct channel *chan,
struct str_map *used_nicks)
{
struct str_vector nicks;
str_vector_init (&nicks);
@ -2110,15 +2128,10 @@ irc_send_rpl_namreply (struct client *c, const struct channel *chan)
{
if (!on_channel && (iter->c->mode & IRC_USER_MODE_INVISIBLE))
continue;
struct str result;
str_init (&result);
irc_append_prefixes (c, iter, &result);
str_append (&result, iter->c->nickname);
if (c->caps_enabled & IRC_CAP_USERHOST_IN_NAMES)
str_append_printf (&result,
"!%s@%s", iter->c->username, iter->c->hostname);
str_vector_add_owned (&nicks, str_steal (&result));
if (used_nicks)
str_map_set (used_nicks, iter->c->nickname, (void *) 1);
str_vector_add_owned (&nicks,
irc_make_rpl_namreply_item (c, iter->c, iter));
}
irc_send_reply_vector (c, IRC_RPL_NAMREPLY,
@ -2126,6 +2139,30 @@ irc_send_rpl_namreply (struct client *c, const struct channel *chan)
str_vector_free (&nicks);
}
static void
irc_send_disassociated_names (struct client *c, struct str_map *used)
{
struct str_vector nicks;
str_vector_init (&nicks);
struct str_map_iter iter;
str_map_iter_init (&iter, &c->ctx->users);
struct client *target;
while ((target = str_map_iter_next (&iter)))
{
if ((target->mode & IRC_USER_MODE_INVISIBLE)
|| str_map_find (used, target->nickname))
continue;
str_vector_add_owned (&nicks,
irc_make_rpl_namreply_item (c, target, NULL));
}
if (nicks.len)
irc_send_reply_vector (c, IRC_RPL_NAMREPLY,
nicks.vector, '*', "*", "");
str_vector_free (&nicks);
}
static void
irc_handle_names (const struct irc_message *msg, struct client *c)
{
@ -2135,18 +2172,21 @@ irc_handle_names (const struct irc_message *msg, struct client *c)
struct channel *chan;
if (msg->params.len == 0)
{
struct str_map used;
str_map_init (&used);
used.key_xfrm = irc_strxfrm;
struct str_map_iter iter;
str_map_iter_init (&iter, &c->ctx->channels);
while ((chan = str_map_iter_next (&iter)))
if (!(chan->modes & (IRC_CHAN_MODE_PRIVATE | IRC_CHAN_MODE_SECRET))
|| channel_get_user (chan, c))
irc_send_rpl_namreply (c, chan);
irc_send_rpl_namreply (c, chan, &used);
// Also send all visible users we haven't listed yet
irc_send_disassociated_names (c, &used);
str_map_free (&used);
// TODO
// If no <channel> parameter is given, a list of all channels and their
// occupants is returned. At the end of this list, a list of users who
// are visible but either not on any channel or not on a visible channel
// are listed as being on `channel' "*".
irc_send_reply (c, IRC_RPL_ENDOFNAMES, "*");
}
else
@ -2159,7 +2199,7 @@ irc_handle_names (const struct irc_message *msg, struct client *c)
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|| channel_get_user (chan, c)))
{
irc_send_rpl_namreply (c, chan);
irc_send_rpl_namreply (c, chan, NULL);
irc_send_reply (c, IRC_RPL_ENDOFNAMES, channels.vector[i]);
}
str_vector_free (&channels);
@ -2606,7 +2646,7 @@ irc_try_join (struct client *c, const char *channel_name, const char *key)
free (message);
irc_send_rpl_topic (c, chan);
irc_send_rpl_namreply (c, chan);
irc_send_rpl_namreply (c, chan, NULL);
irc_send_reply (c, IRC_RPL_ENDOFNAMES, chan->name);
}