aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--degesch.c67
2 files changed, 46 insertions, 23 deletions
diff --git a/NEWS b/NEWS
index 4b79444..5ccd44c 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@
* degesch: added a /squery command for IRCnet
+ * degesch: now supporting IRCv3.2 capability negotiation
+
1.1.0 (2020-10-31) "What Do You Mean By 'This Isn't Germany'?"
diff --git a/degesch.c b/degesch.c
index cbc13da..8b0269b 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1718,6 +1718,7 @@ struct server
char *irc_user_host; ///< Our current user@host
bool autoaway_active; ///< Autoaway is currently active
+ struct strv cap_ls_buf; ///< Buffer for IRCv3.2 CAP LS
bool cap_echo_message; ///< Whether the server echoes messages
bool cap_away_notify; ///< Whether we get AWAY notifications
@@ -1841,6 +1842,7 @@ server_new (struct poller *poller)
self->irc_user_mode = str_make ();
+ self->cap_ls_buf = strv_make ();
server_init_specifics (self);
return self;
}
@@ -1887,6 +1889,7 @@ server_destroy (struct server *self)
str_free (&self->irc_user_mode);
free (self->irc_user_host);
+ strv_free (&self->cap_ls_buf);
server_free_specifics (self);
free (self);
}
@@ -4956,6 +4959,7 @@ irc_destroy_state (struct server *s)
str_reset (&s->irc_user_mode);
cstr_set (&s->irc_user_host, NULL);
+ strv_reset (&s->cap_ls_buf);
s->cap_away_notify = false;
s->cap_echo_message = false;
@@ -5692,9 +5696,9 @@ irc_register (struct server *s)
const char *realname = get_config_string (s->config, "realname");
hard_assert (username && realname);
- // Start IRCv3.1 capability negotiation;
+ // Start IRCv3 capability negotiation, with up to 3.2 features;
// at worst the server will ignore this or send a harmless error message
- irc_send (s, "CAP LS");
+ irc_send (s, "CAP LS 302");
const char *password = get_config_string (s->config, "password");
if (password)
@@ -6538,6 +6542,39 @@ irc_handle_away (struct server *s, const struct irc_message *msg)
}
static void
+irc_process_cap_ls (struct server *s)
+{
+ log_server_status (s, s->buffer,
+ "#s: #&S", "Capabilities supported", strv_join (&s->cap_ls_buf, " "));
+
+ struct strv chosen = strv_make ();
+ struct strv use = strv_make ();
+
+ cstr_split (get_config_string (s->config, "capabilities"), ",", true, &use);
+
+ // Filter server capabilities for ones we can make use of
+ for (size_t i = 0; i < s->cap_ls_buf.len; i++)
+ {
+ const char *cap = s->cap_ls_buf.vector[i];
+ size_t cap_name_len = strcspn (cap, "=");
+ for (size_t k = 0; k < use.len; k++)
+ if (!strncasecmp_ascii (use.vector[k], cap, cap_name_len))
+ strv_append_owned (&chosen, xstrndup (cap, cap_name_len));
+ }
+ strv_reset (&s->cap_ls_buf);
+
+ char *chosen_str = strv_join (&chosen, " ");
+ strv_free (&chosen);
+ strv_free (&use);
+
+ // XXX: with IRCv3.2, this may end up being too long for one message,
+ // and we need to be careful with CAP END. One probably has to count
+ // the number of sent CAP REQ vs the number of received CAP ACK/NAK.
+ irc_send (s, "CAP REQ :%s", chosen_str);
+ free (chosen_str);
+}
+
+static void
irc_handle_cap (struct server *s, const struct irc_message *msg)
{
if (msg->params.len < 2)
@@ -6577,30 +6614,14 @@ irc_handle_cap (struct server *s, const struct irc_message *msg)
}
else if (!strcasecmp_ascii (subcommand, "LS"))
{
- log_server_status (s, s->buffer,
- "#s: #S", "Capabilities supported", args);
-
- struct strv chosen = strv_make ();
- struct strv use = strv_make ();
-
- cstr_split (get_config_string (s->config, "capabilities"),
- ",", true, &use);
- // Filter server capabilities for ones we can make use of
- for (size_t i = 0; i < v.len; i++)
+ if (msg->params.len > 3 && !strcmp (args, "*"))
+ cstr_split (msg->params.vector[3], " ", true, &s->cap_ls_buf);
+ else
{
- const char *cap = v.vector[i];
- for (size_t k = 0; k < use.len; k++)
- if (!strcasecmp_ascii (use.vector[k], cap))
- strv_append (&chosen, cap);
+ strv_append_vector (&s->cap_ls_buf, v.vector);
+ irc_process_cap_ls (s);
}
-
- char *chosen_str = strv_join (&chosen, " ");
- strv_free (&chosen);
- strv_free (&use);
-
- irc_send (s, "CAP REQ :%s", chosen_str);
- free (chosen_str);
}
strv_free (&v);