degesch: IRCv3.2 capability negotiation
We can receive and display capability values now.
This commit is contained in:
parent
735096d76d
commit
17f430043a
2
NEWS
2
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'?"
|
||||
|
||||
|
67
degesch.c
67
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)
|
||||
@ -6537,6 +6541,39 @@ irc_handle_away (struct server *s, const struct irc_message *msg)
|
||||
user->away = !!msg->params.len;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user