From 0b91604acd02f765cb417e42652920bc2ce9babc Mon Sep 17 00:00:00 2001
From: Přemysl Janouch <p.janouch@gmail.com>
Date: Mon, 25 May 2015 22:54:04 +0200
Subject: degesch: some basic RPL_ISUPPORT parsing

---
 degesch.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 51 insertions(+), 9 deletions(-)

diff --git a/degesch.c b/degesch.c
index dd7afaa..f92c86b 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1035,6 +1035,11 @@ struct server
 
 	// IRC:
 
+	// TODO: casemapping-specific strxfrm and/or tolower (CASEMAPPING=rfc1459)
+	// TODO: channel name prefixes (CHANTYPES=#& + IDCHAN)
+	char *irc_channel_prefixes;         ///< Channel user prefixes
+	char *irc_channel_modes;            ///< Channel user modes
+
 	struct str_map irc_users;           ///< IRC user data
 	struct str_map irc_channels;        ///< IRC channel data
 	struct str_map irc_buffer_map;      ///< Maps IRC identifiers to buffers
@@ -1063,6 +1068,10 @@ server_init (struct server *self, struct poller *poller)
 	str_init (&self->read_buffer);
 	self->state = IRC_DISCONNECTED;
 
+	// RFC 1459 as per the RPL_ISUPPORT draft
+	self->irc_channel_prefixes = xstrdup ("@+");
+	self->irc_channel_modes    = xstrdup ("ov");
+
 	str_map_init (&self->irc_users);
 	self->irc_users.key_xfrm = irc_strxfrm;
 	str_map_init (&self->irc_channels);
@@ -1110,6 +1119,9 @@ server_free (struct server *self)
 	free (self->irc_user_mode);
 	free (self->irc_user_host);
 
+	free (self->irc_channel_prefixes);
+	free (self->irc_channel_modes);
+
 	str_map_free (&self->irc_users);
 	str_map_free (&self->irc_channels);
 	str_map_free (&self->irc_buffer_map);
@@ -4418,8 +4430,7 @@ irc_process_names (struct server *s, struct channel *channel)
 	for (size_t i = 0; i < updates->len; i++)
 	{
 		const char *item = updates->vector[i];
-		// FIXME: use server-specific chanmode characters
-		const char *nick = item + strspn (item, "@+");
+		const char *nick = item + strspn (item, s->irc_channel_modes);
 		struct channel_user *channel_user = str_map_find (&map, nick);
 		if (!channel_user)
 		{
@@ -4459,6 +4470,43 @@ irc_handle_rpl_endofnames (struct server *s, const struct irc_message *msg)
 		irc_process_names (s, channel);
 }
 
+static void
+irc_handle_isupport_prefix (struct server *s, char *value)
+{
+	char *modes = value;
+	char *prefixes = strchr (value, ')');
+	size_t n_prefixes = prefixes - modes;
+	if (*modes++ != '(' || !prefixes++ || strlen (value) != 2 * n_prefixes--)
+		return;
+
+	free (s->irc_channel_modes);
+	free (s->irc_channel_prefixes);
+
+	s->irc_channel_modes    = xstrndup (modes,    n_prefixes);
+	s->irc_channel_prefixes = xstrndup (prefixes, n_prefixes);
+}
+
+static void
+irc_handle_rpl_isupport (struct server *s, const struct irc_message *msg)
+{
+	if (msg->params.len < 2)
+		return;
+
+	for (size_t i = 1; i < msg->params.len - 1; i++)
+	{
+		// TODO: if the parameter starts with "-", it resets to default
+		char *param = msg->params.vector[i];
+		char *value = param + strcspn (param, "=");
+		if (*value) *value++ = '\0';
+
+		if (!strcmp (param, "PREFIX"))
+			irc_handle_isupport_prefix (s, value);
+	}
+
+	// TODO: initialize key_strxfrm according to server properties;
+	//   note that collisions may arise on reconnecting
+}
+
 static void
 irc_process_numeric (struct server *s,
 	const struct irc_message *msg, unsigned long numeric)
@@ -4491,14 +4539,8 @@ irc_process_numeric (struct server *s,
 		if (msg->params.len == 2)
 			irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]);
 		break;
-	case IRC_RPL_ISUPPORT:
-		// TODO: parse this, mainly PREFIX; see
-		//   http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
-
-		// TODO: initialize key_strxfrm according to server properties;
-		//   note that collisions may arise on reconnecting
-		break;
 
+	case IRC_RPL_ISUPPORT:   irc_handle_rpl_isupport   (s, msg); break;
 	case IRC_RPL_USERHOST:   irc_handle_rpl_userhost   (s, msg); break;
 	case IRC_RPL_NAMREPLY:   irc_handle_rpl_namreply   (s, msg); break;
 	case IRC_RPL_ENDOFNAMES: irc_handle_rpl_endofnames (s, msg); break;
-- 
cgit v1.2.3-70-g09d2