aboutsummaryrefslogtreecommitdiff
path: root/kike.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2015-06-13 18:37:07 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2015-06-13 18:47:25 +0200
commitba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c (patch)
treeca0d944cb40d5cb4038ac64054ac5d78982d385c /kike.c
parent17be991dcec61fd8ef172c43d265ffbcb1a2b67e (diff)
downloadxK-ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c.tar.gz
xK-ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c.tar.xz
xK-ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c.zip
kike: implement WHOWAS
Diffstat (limited to 'kike.c')
-rw-r--r--kike.c89
1 files changed, 87 insertions, 2 deletions
diff --git a/kike.c b/kike.c
index d13def9..1e3fb9b 100644
--- a/kike.c
+++ b/kike.c
@@ -535,6 +535,37 @@ channel_user_count (const struct channel *chan)
// --- IRC server context ------------------------------------------------------
+struct whowas_info
+{
+ char *nickname; ///< IRC nickname
+ char *username; ///< IRC username
+ char *realname; ///< IRC realname
+ char *hostname; ///< Hostname shown to the network
+};
+
+struct whowas_info *
+whowas_info_new (struct client *c)
+{
+ struct whowas_info *self = xmalloc (sizeof *self);
+ self->nickname = xstrdup (c->nickname);
+ self->username = xstrdup (c->username);
+ self->realname = xstrdup (c->realname);
+ self->hostname = xstrdup (c->hostname);
+ return self;
+}
+
+static void
+whowas_info_destroy (struct whowas_info *self)
+{
+ free (self->nickname);
+ free (self->username);
+ free (self->realname);
+ free (self->hostname);
+ free (self);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
struct server_context
{
int *listen_fds; ///< Listening socket FD's
@@ -550,6 +581,8 @@ struct server_context
struct str_map handlers; ///< Message handlers
struct str_map cap_handlers; ///< CAP message handlers
+ struct str_map whowas; ///< WHOWAS registry
+
struct poller poller; ///< Manages polled description
struct poller_timer quit_timer; ///< Quit timeout timer
bool quitting; ///< User requested quitting
@@ -589,6 +622,10 @@ server_context_init (struct server_context *self)
str_map_init (&self->cap_handlers);
self->cap_handlers.key_xfrm = irc_strxfrm;
+ str_map_init (&self->whowas);
+ self->whowas.key_xfrm = irc_strxfrm;
+ self->whowas.free = (void (*) (void *)) whowas_info_destroy;
+
poller_init (&self->poller);
poller_timer_init (&self->quit_timer, &self->poller);
self->quit_timer.dispatcher = on_irc_quit_timeout;
@@ -638,6 +675,7 @@ server_context_free (struct server_context *self)
str_map_free (&self->channels);
str_map_free (&self->handlers);
str_map_free (&self->cap_handlers);
+ str_map_free (&self->whowas);
poller_free (&self->poller);
str_vector_free (&self->motd);
@@ -785,6 +823,15 @@ client_send (struct client *c, const char *format, ...)
}
static void
+client_add_to_whowas (struct client *c)
+{
+ // Only keeping one entry for each nickname
+ // TODO: make sure this list doesn't get too long, for example by
+ // putting them in a linked list ordered by time
+ str_map_set (&c->ctx->whowas, c->nickname, whowas_info_new (c));
+}
+
+static void
client_unregister (struct client *c, const char *reason)
{
if (!c->registered)
@@ -808,6 +855,8 @@ client_unregister (struct client *c, const char *reason)
irc_channel_destroy_if_empty (c->ctx, chan);
}
+ client_add_to_whowas (c);
+
str_map_set (&c->ctx->users, c->nickname, NULL);
free (c->nickname);
c->nickname = NULL;
@@ -1126,6 +1175,8 @@ irc_try_finish_registration (struct client *c)
client_send (c, ":%s NOTICE %s :"
"Your SSL client certificate fingerprint is %s",
ctx->server_name, c->nickname, c->ssl_cert_fingerprint);
+
+ str_map_set (&ctx->whowas, c->nickname, NULL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1328,6 +1379,8 @@ irc_handle_nick (const struct irc_message *msg, struct client *c)
if (c->registered)
{
+ client_add_to_whowas (c);
+
char *message = xstrdup_printf (":%s!%s@%s NICK :%s",
c->nickname, c->username, c->hostname, nickname);
irc_send_to_roommates (c, message);
@@ -2306,8 +2359,8 @@ static void
irc_send_whois_reply (struct client *c, const struct client *target)
{
const char *nick = target->nickname;
- irc_send_reply (c, IRC_RPL_WHOISUSER, nick, target->username,
- target->hostname, target->realname);
+ irc_send_reply (c, IRC_RPL_WHOISUSER, nick,
+ target->username, target->hostname, target->realname);
irc_send_reply (c, IRC_RPL_WHOISSERVER, nick, target->ctx->server_name,
str_map_find (&c->ctx->config, "server_info"));
if (target->mode & IRC_USER_MODE_OPERATOR)
@@ -2387,6 +2440,37 @@ irc_handle_whois (const struct irc_message *msg, struct client *c)
}
static void
+irc_handle_whowas (const struct irc_message *msg, struct client *c)
+{
+ if (msg->params.len < 1)
+ RETURN_WITH_REPLY (c, IRC_ERR_NEEDMOREPARAMS, msg->command);
+ if (msg->params.len > 2 && !irc_is_this_me (c->ctx, msg->params.vector[2]))
+ RETURN_WITH_REPLY (c, IRC_ERR_NOSUCHSERVER, msg->params.vector[2]);
+ // The "count" parameter is ignored, we only store one entry for a nick
+
+ struct str_vector nicks;
+ str_vector_init (&nicks);
+ split_str_ignore_empty (msg->params.vector[0], ',', &nicks);
+
+ for (size_t i = 0; i < nicks.len; i++)
+ {
+ const char *nick = nicks.vector[i];
+ struct whowas_info *info = str_map_find (&c->ctx->whowas, nick);
+ if (!info)
+ irc_send_reply (c, IRC_ERR_WASNOSUCHNICK, nick);
+ else
+ {
+ irc_send_reply (c, IRC_RPL_WHOWASUSER, nick,
+ info->username, info->hostname, info->realname);
+ irc_send_reply (c, IRC_RPL_WHOISSERVER, nick, c->ctx->server_name,
+ str_map_find (&c->ctx->config, "server_info"));
+ }
+ irc_send_reply (c, IRC_RPL_ENDOFWHOWAS, nick);
+ }
+ str_vector_free (&nicks);
+}
+
+static void
irc_send_rpl_topic (struct client *c, struct channel *chan)
{
if (!*chan->topic)
@@ -2812,6 +2896,7 @@ irc_register_handlers (struct server_context *ctx)
{ "NAMES", true, irc_handle_names },
{ "WHO", true, irc_handle_who },
{ "WHOIS", true, irc_handle_whois },
+ { "WHOWAS", true, irc_handle_whowas },
{ "ISON", true, irc_handle_ison },
{ "KILL", true, irc_handle_kill },