kike: stubplement CAP

This commit is contained in:
Přemysl Eric Janouch 2015-06-11 22:41:01 +02:00
parent 55fde4803c
commit 20fc6c17d1
2 changed files with 68 additions and 0 deletions

View File

@ -48,6 +48,7 @@
403 IRC_ERR_NOSUCHCHANNEL "%s :No such channel"
404 IRC_ERR_CANNOTSENDTOCHAN "%s :Cannot send to channel"
409 IRC_ERR_NOORIGIN ":No origin specified"
410 IRC_ERR_INVALIDCAPCMD "%s :%s"
411 IRC_ERR_NORECIPIENT ":No recipient given (%s)"
412 IRC_ERR_NOTEXTTOSEND ":No text to send"
421 IRC_ERR_UNKNOWNCOMMAND "%s: Unknown command"

67
kike.c
View File

@ -308,10 +308,13 @@ struct client
struct poller_timer kill_timer; ///< Hard kill timeout
bool initialized; ///< Has any data been received yet?
bool cap_negotiating; ///< Negotiating capabilities
bool registered; ///< The user has registered
bool closing_link; ///< Closing link
bool half_closed; ///< Closing link: conn. is half-closed
unsigned long cap_version; ///< CAP protocol version
bool ssl_rx_want_tx; ///< SSL_read() wants to write
bool ssl_tx_want_rx; ///< SSL_write() wants to read
SSL *ssl; ///< SSL connection
@ -339,6 +342,7 @@ client_init (struct client *self)
self->socket_fd = -1;
str_init (&self->read_buffer);
str_init (&self->write_buffer);
self->cap_version = 301;
// TODO: make this configurable and more fine-grained
flood_detector_init (&self->antiflood, 10, 20);
str_map_init (&self->invites);
@ -1078,6 +1082,8 @@ irc_try_finish_registration (struct client *c)
struct server_context *ctx = c->ctx;
if (!c->nickname || !c->username || !c->realname)
return;
if (c->registered || c->cap_negotiating)
return;
c->registered = true;
irc_send_reply (c, IRC_RPL_WELCOME, c->nickname, c->username, c->hostname);
@ -1109,6 +1115,66 @@ irc_try_finish_registration (struct client *c)
ctx->server_name, c->nickname, c->ssl_cert_fingerprint);
}
static void
irc_handle_cap (const struct irc_message *msg, struct client *c)
{
if (msg->params.len < 1)
RETURN_WITH_REPLY (c, IRC_ERR_NEEDMOREPARAMS, msg->command);
struct str_vector v;
str_vector_init (&v);
const char *subcommand = msg->params.vector[0];
const char *params = "";
if (msg->params.len > 1)
{
params = msg->params.vector[1];
split_str_ignore_empty (params, ' ', &v);
}
const char *target = c->nickname ? c->nickname : "*";
if (!irc_strcmp (subcommand, "LS"))
{
if (v.len == 1 && !xstrtoul (&c->cap_version, v.vector[0], 10))
irc_send_reply (c, IRC_ERR_INVALIDCAPCMD,
subcommand, "Ignoring invalid protocol version number");
c->cap_negotiating = true;
// TODO: actually implement a few capabilities
client_send (c, "CAP %s LS :", target);
}
else if (!irc_strcmp (subcommand, "LIST"))
{
// TODO: list currently enabled capabilities
client_send (c, "CAP %s LIST :", target);
}
else if (!irc_strcmp (subcommand, "REQ"))
{
c->cap_negotiating = true;
// TODO: process the capability change request, "-" disables
if (v.len)
client_send (c, "CAP %s NAK :%s", target, params);
else
client_send (c, "CAP %s ACK :%s", target, params);
}
else if (!irc_strcmp (subcommand, "ACK"))
{
if (v.len)
irc_send_reply (c, IRC_ERR_INVALIDCAPCMD,
subcommand, "No acknowledgable capabilities supported");
}
else if (!irc_strcmp (subcommand, "END"))
{
c->cap_negotiating = false;
irc_try_finish_registration (c);
}
else
irc_send_reply (c, IRC_ERR_INVALIDCAPCMD,
subcommand, "Invalid CAP subcommand");
str_vector_free (&v);
}
static void
irc_handle_pass (const struct irc_message *msg, struct client *c)
{
@ -2516,6 +2582,7 @@ irc_register_handlers (struct server_context *ctx)
// TODO: add a field for oper-only commands?
static const struct irc_command message_handlers[] =
{
{ "CAP", false, irc_handle_cap },
{ "PASS", false, irc_handle_pass },
{ "NICK", false, irc_handle_nick },
{ "USER", false, irc_handle_user },