summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kike.c83
1 files changed, 67 insertions, 16 deletions
diff --git a/kike.c b/kike.c
index 4f9e3cd..948e635 100644
--- a/kike.c
+++ b/kike.c
@@ -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,