diff --git a/degesch.c b/degesch.c index 97b804e..17965ef 100644 --- a/degesch.c +++ b/degesch.c @@ -1035,11 +1035,6 @@ 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 @@ -1048,6 +1043,22 @@ struct server char *irc_user_mode; ///< Our current user mode char *irc_user_host; ///< Our current user@host + // Server-specific information (from RPL_ISUPPORT): + + // TODO: implement a generic strcmp() on top of "irc_tolower" + /// Convert an IRC identifier character to lower-case + int (*irc_tolower) (int); + + /// Key conversion function for hashmap lookups + size_t (*irc_strxfrm) (char *, const char *, size_t); + + char *irc_chantypes; ///< Channel types (name prefixes) + char *irc_idchan_prefixes; ///< Prefixes for "safe channels" + char *irc_statusmsg; ///< Prefixes for channel targets + + char *irc_chanuser_prefixes; ///< Channel user prefixes + char *irc_chanuser_modes; ///< Channel user modes + // Events: struct poller_timer ping_tmr; ///< We should send a ping @@ -1068,9 +1079,16 @@ 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"); + // Defaults as per the RPL_ISUPPORT draft + self->irc_tolower = irc_tolower; + self->irc_strxfrm = irc_strxfrm; + + self->irc_chantypes = xstrdup ("#&"); + self->irc_idchan_prefixes = xstrdup (""); + self->irc_statusmsg = xstrdup (""); + + self->irc_chanuser_prefixes = xstrdup ("@+"); + self->irc_chanuser_modes = xstrdup ("ov"); str_map_init (&self->irc_users); self->irc_users.key_xfrm = irc_strxfrm; @@ -1119,8 +1137,12 @@ 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); + free (self->irc_chantypes); + free (self->irc_idchan_prefixes); + free (self->irc_statusmsg); + + free (self->irc_chanuser_prefixes); + free (self->irc_chanuser_modes); str_map_free (&self->irc_users); str_map_free (&self->irc_channels); @@ -3731,7 +3753,6 @@ irc_is_highlight (struct server *s, const char *message) // --- Input handling ---------------------------------------------------------- // TODO: we will need a proper mode parser; to be shared with kike -// TODO: we alse definitely need to parse server capability messages static void irc_handle_join (struct server *s, const struct irc_message *msg) @@ -4430,7 +4451,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]; - const char *nick = item + strspn (item, s->irc_channel_modes); + const char *nick = item + strspn (item, s->irc_chanuser_modes); struct channel_user *channel_user = str_map_find (&map, nick); if (!channel_user) { @@ -4479,11 +4500,72 @@ irc_handle_isupport_prefix (struct server *s, char *value) if (*modes++ != '(' || !prefixes++ || strlen (value) != 2 * n_prefixes--) return; - free (s->irc_channel_modes); - free (s->irc_channel_prefixes); + free (s->irc_chanuser_modes); + free (s->irc_chanuser_prefixes); - s->irc_channel_modes = xstrndup (modes, n_prefixes); - s->irc_channel_prefixes = xstrndup (prefixes, n_prefixes); + s->irc_chanuser_modes = xstrndup (modes, n_prefixes); + s->irc_chanuser_prefixes = xstrndup (prefixes, n_prefixes); +} + +static void +irc_handle_isupport_casemapping (struct server *s, char *value) +{ + // TODO: reinitialize hashtables with the new tolower() and strxfrm(), + // note that collisions may arise on reconnecting + + if (!strcmp (value, "ascii")) + { + s->irc_tolower = tolower_ascii; + s->irc_strxfrm = tolower_ascii_strxfrm; + } + else if (!strcmp (value, "rfc1459")) + { + s->irc_tolower = irc_tolower; + s->irc_strxfrm = irc_strxfrm; + } + else if (!strcmp (value, "rfc1459-strict")) + { + // TODO: implement + s->irc_tolower = irc_tolower; + s->irc_strxfrm = irc_strxfrm; + } +} + +static void +irc_handle_isupport_chantypes (struct server *s, char *value) +{ + free (s->irc_chantypes); + s->irc_chantypes = xstrdup (value); +} + +static void +irc_handle_isupport_idchan (struct server *s, char *value) +{ + struct str prefixes; + str_init (&prefixes); + + struct str_vector v; + str_vector_init (&v); + split_str_ignore_empty (value, ',', &v); + for (size_t i = 0; i < v.len; i++) + { + // Not using or validating the numeric part + const char *pair = v.vector[i]; + const char *colon = strchr (pair, ':'); + if (colon) + str_append_data (&prefixes, pair, colon - pair); + } + str_vector_free (&v); + + free (s->irc_idchan_prefixes); + s->irc_idchan_prefixes = str_steal (&prefixes); +} + +static void +irc_handle_isupport_statusmsg (struct server *s, char *value) +{ + free (s->irc_statusmsg); + s->irc_statusmsg = xstrdup (value); } static void @@ -4522,14 +4604,22 @@ irc_handle_rpl_isupport (struct server *s, const struct irc_message *msg) str_init (&value_unescaped); unescape_isupport_value (value, &value_unescaped); - if (!strcmp (param, "PREFIX")) - irc_handle_isupport_prefix (s, value_unescaped.str); + if (!strcmp (param, "PREFIX")) + irc_handle_isupport_prefix (s, value_unescaped.str); + else if (!strcmp (param, "CASEMAPPING")) + irc_handle_isupport_casemapping (s, value_unescaped.str); + else if (!strcmp (param, "CHANTYPES")) + irc_handle_isupport_chantypes (s, value_unescaped.str); + else if (!strcmp (param, "IDCHAN")) + irc_handle_isupport_idchan (s, value_unescaped.str); + else if (!strcmp (param, "STATUSMSG")) + irc_handle_isupport_statusmsg (s, value_unescaped.str); + + // TODO: also parse MODES, TARGMAX, CHANMODES and make use of them + // to split client commands as necessary str_free (&value_unescaped); } - - // TODO: initialize key_strxfrm according to server properties; - // note that collisions may arise on reconnecting } static void