From 7ffce705d09d464406be1a0b824009984cae30a3 Mon Sep 17 00:00:00 2001 From: Haw Loeung Date: Mon, 24 Aug 2026 08:17:51 +1000 Subject: [PATCH] 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. --- src/irc/proxy/listen.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index 1fed639e..806cae96 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -164,6 +164,44 @@ static void grab_who(CLIENT_REC *client, const char *channel) 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, const char *cmd, const char *args) { @@ -215,6 +253,8 @@ static void handle_client_connect_cmd(CLIENT_REC *client, client->nick = g_strdup(args); } else if (g_strcmp0(cmd, "USER") == 0) { client->user_sent = TRUE; + } else if (g_strcmp0(cmd, "CAP") == 0) { + handle_client_cap(client, args); } if (client->nick != NULL && client->user_sent) { @@ -241,6 +281,11 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, return; } + if (g_strcmp0(cmd, "CAP") == 0) { + handle_client_cap(client, args); + return; + } + if (g_strcmp0(cmd, "QUIT") == 0) { remove_client(client); return;