diff options
| author | Přemysl Janouch <p.janouch@gmail.com> | 2015-06-13 18:37:07 +0200 | 
|---|---|---|
| committer | Přemysl Janouch <p.janouch@gmail.com> | 2015-06-13 18:47:25 +0200 | 
| commit | ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c (patch) | |
| tree | ca0d944cb40d5cb4038ac64054ac5d78982d385c | |
| parent | 17be991dcec61fd8ef172c43d265ffbcb1a2b67e (diff) | |
| download | xK-ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c.tar.gz xK-ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c.tar.xz xK-ba14a30c0a88b0e35a99cabe73525ddfcfd6ef3c.zip | |
kike: implement WHOWAS
| -rw-r--r-- | kike-replies | 3 | ||||
| -rw-r--r-- | kike.c | 89 | 
2 files changed, 90 insertions, 2 deletions
| diff --git a/kike-replies b/kike-replies index c585740..ed26232 100644 --- a/kike-replies +++ b/kike-replies @@ -17,6 +17,7 @@  311 IRC_RPL_WHOISUSER "%s %s %s * :%s"  312 IRC_RPL_WHOISSERVER "%s %s :%s"  313 IRC_RPL_WHOISOPERATOR "%s :is an IRC operator" +314 IRC_RPL_WHOWASUSER "%s %s %s * :%s"  315 IRC_RPL_ENDOFWHO "%s :End of WHO list"  317 IRC_RPL_WHOISIDLE "%s %d :seconds idle"  318 IRC_RPL_ENDOFWHOIS "%s :End of WHOIS list" @@ -39,6 +40,7 @@  366 IRC_RPL_ENDOFNAMES "%s :End of NAMES list"  367 IRC_RPL_BANLIST "%s %s"  368 IRC_RPL_ENDOFBANLIST "%s :End of channel ban list" +369 IRC_RPL_ENDOFWHOWAS "%s :End of WHOWAS"  372 IRC_RPL_MOTD ":- %s"  375 IRC_RPL_MOTDSTART ":- %s Message of the day - "  376 IRC_RPL_ENDOFMOTD ":End of MOTD command" @@ -47,6 +49,7 @@  402 IRC_ERR_NOSUCHSERVER "%s :No such server"  403 IRC_ERR_NOSUCHCHANNEL "%s :No such channel"  404 IRC_ERR_CANNOTSENDTOCHAN "%s :Cannot send to channel" +406 IRC_ERR_WASNOSUCHNICK "%s :There was no such nickname"  409 IRC_ERR_NOORIGIN ":No origin specified"  410 IRC_ERR_INVALIDCAPCMD "%s :%s"  411 IRC_ERR_NORECIPIENT ":No recipient given (%s)" @@ -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     }, | 
