diff options
-rw-r--r-- | kike.c | 83 |
1 files changed, 67 insertions, 16 deletions
@@ -293,6 +293,11 @@ enum IRC_USER_MODE_RX_SERVER_NOTICES = (1 << 4) }; +enum +{ + IRC_CAP_MULTI_PREFIX = (1 << 0), +}; + struct client { LIST_HEADER (struct client) @@ -314,6 +319,7 @@ struct client bool half_closed; ///< Closing link: conn. is half-closed unsigned long cap_version; ///< CAP protocol version + unsigned caps; ///< Enabled capabilities bool ssl_rx_want_tx; ///< SSL_read() wants to write bool ssl_tx_want_rx; ///< SSL_write() wants to read @@ -1140,20 +1146,53 @@ irc_handle_cap (const struct irc_message *msg, struct client *c) subcommand, "Ignoring invalid protocol version number"); c->cap_negotiating = true; - // TODO: actually implement a few capabilities - client_send (c, "CAP %s LS :", target); + client_send (c, "CAP %s LS :multi-prefix", target); } else if (!irc_strcmp (subcommand, "LIST")) { - // TODO: list currently enabled capabilities - client_send (c, "CAP %s LIST :", target); + struct str_vector caps; + str_vector_init (&caps); + + if (c->caps & IRC_CAP_MULTI_PREFIX) + str_vector_add (&caps, "multi-prefix"); + + char *caps_str = join_str_vector (&caps, ' '); + str_vector_free (&caps); + client_send (c, "CAP %s LIST :%s", target, caps_str); + free (caps_str); } else if (!irc_strcmp (subcommand, "REQ")) { c->cap_negotiating = true; - // TODO: process the capability change request, "-" disables - if (v.len) + + unsigned new_caps = c->caps; + bool success = true; + for (size_t i = 0; i < v.len; i++) + { + bool neg = false; + const char *name = v.vector[i]; + if (*name == '-') + { + neg = true; + name++; + } + unsigned cap = 0; + if (!strcmp (name, "multi-prefix")) + cap = IRC_CAP_MULTI_PREFIX; + else + success = false; + + if (neg) + new_caps &= ~cap; + else + new_caps |= cap; + } + + if (success) + { + c->caps = new_caps; client_send (c, "CAP %s NAK :%s", target, params); + } else client_send (c, "CAP %s ACK :%s", target, params); } @@ -1944,6 +1983,26 @@ irc_handle_list (const struct irc_message *msg, struct client *c) } static void +irc_append_prefixes (struct client *c, struct channel_user *user, + struct str *output) +{ + struct str prefixes; + str_init (&prefixes); + + if (user->modes & IRC_CHAN_MODE_OPERATOR) str_append_c (&prefixes, '@'); + if (user->modes & IRC_CHAN_MODE_VOICE) str_append_c (&prefixes, '+'); + + if (prefixes.len) + { + if (c->caps & IRC_CAP_MULTI_PREFIX) + str_append (output, prefixes.str); + else + str_append_c (output, prefixes.str[0]); + } + str_free (&prefixes); +} + +static void irc_send_rpl_namreply (struct client *c, const struct channel *chan) { struct str_vector nicks; @@ -1963,10 +2022,7 @@ irc_send_rpl_namreply (struct client *c, const struct channel *chan) struct str result; str_init (&result); - if (iter->modes & IRC_CHAN_MODE_OPERATOR) - str_append_c (&result, '@'); - else if (iter->modes & IRC_CHAN_MODE_VOICE) - str_append_c (&result, '+'); + irc_append_prefixes (c, iter, &result); str_append (&result, iter->c->nickname); str_vector_add_owned (&nicks, str_steal (&result)); } @@ -2029,12 +2085,7 @@ irc_send_rpl_whoreply (struct client *c, const struct channel *chan, struct channel_user *user; if (chan && (user = channel_get_user (chan, target))) - { - if (user->modes & IRC_CHAN_MODE_OPERATOR) - str_append_c (&chars, '@'); - else if (user->modes & IRC_CHAN_MODE_VOICE) - str_append_c (&chars, '+'); - } + irc_append_prefixes (c, user, &chars); irc_send_reply (c, IRC_RPL_WHOREPLY, chan ? chan->name : "*", target->username, target->hostname, target->ctx->server_name, |