summaryrefslogtreecommitdiff
path: root/kike.c
diff options
context:
space:
mode:
Diffstat (limited to 'kike.c')
-rw-r--r--kike.c76
1 files changed, 58 insertions, 18 deletions
diff --git a/kike.c b/kike.c
index 783c6e2..d13def9 100644
--- a/kike.c
+++ b/kike.c
@@ -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,
@@ -2127,6 +2140,30 @@ irc_send_rpl_namreply (struct client *c, const struct channel *chan)
}
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)
{
if (msg->params.len > 1 && !irc_is_this_me (c->ctx, msg->params.vector[1]))
@@ -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);
}