Answer IRCv3 CAP commands to fix client connect hang in the proxy module

irssi connecting to an irssi+proxy hangs indefinitely waiting for a
CAP LS response. This change fixes this by answering to CAP LS with an
empty list and NAK REQs so capability negotiation can finish cleanly.
This commit is contained in:
Haw Loeung 2026-08-24 08:17:51 +10:00
commit 7ffce705d0
No known key found for this signature in database
GPG key ID: F44EEA5398FF1996

View file

@ -164,6 +164,44 @@ static void grab_who(CLIENT_REC *client, const char *channel)
g_string_free(arg, TRUE); g_string_free(arg, TRUE);
} }
static void handle_client_cap(CLIENT_REC *client, const char *args)
{
char *subcmd, *cap_args;
const char *target_nick;
subcmd = g_strdup(args);
cap_args = strchr(subcmd, ' ');
if (cap_args != NULL) {
*cap_args++ = '\0';
while (*cap_args == ' ')
cap_args++;
} else {
cap_args = "";
}
target_nick = client->nick != NULL ? client->nick : "*";
if (g_ascii_strcasecmp(subcmd, "LS") == 0) {
proxy_outdata(client, ":%s CAP %s LS :\r\n", client->proxy_address, target_nick);
} else if (g_ascii_strcasecmp(subcmd, "REQ") == 0) {
const char *req = cap_args;
while (*req == ' ' || *req == ':')
req++;
if (*req != '\0') {
proxy_outdata(client, ":%s CAP %s NAK :%s\r\n", client->proxy_address,
target_nick, req);
}
} else if (g_ascii_strcasecmp(subcmd, "LIST") == 0) {
proxy_outdata(client, ":%s CAP %s LIST :\r\n", client->proxy_address, target_nick);
} else if (g_ascii_strcasecmp(subcmd, "END") == 0) {
/* CAP negotiation complete */
}
g_free(subcmd);
}
static void handle_client_connect_cmd(CLIENT_REC *client, static void handle_client_connect_cmd(CLIENT_REC *client,
const char *cmd, const char *args) const char *cmd, const char *args)
{ {
@ -215,6 +253,8 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
client->nick = g_strdup(args); client->nick = g_strdup(args);
} else if (g_strcmp0(cmd, "USER") == 0) { } else if (g_strcmp0(cmd, "USER") == 0) {
client->user_sent = TRUE; client->user_sent = TRUE;
} else if (g_strcmp0(cmd, "CAP") == 0) {
handle_client_cap(client, args);
} }
if (client->nick != NULL && client->user_sent) { if (client->nick != NULL && client->user_sent) {
@ -241,6 +281,11 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
return; return;
} }
if (g_strcmp0(cmd, "CAP") == 0) {
handle_client_cap(client, args);
return;
}
if (g_strcmp0(cmd, "QUIT") == 0) { if (g_strcmp0(cmd, "QUIT") == 0) {
remove_client(client); remove_client(client);
return; return;