From mboxrd@z Thu Jan 1 00:00:00 1970 From: git@delthas.fr To: list+catgirl@causal.agency Cc: delthas Subject: [PATCH] Send CAP END on RPL_SASLSUCCESS Date: Mon, 3 Aug 2026 12:37:19 +0200 Message-ID: <20260803103733.1201291-1-git@delthas.fr> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: delthas soju doesn't send RPL_LOGGEDIN on successful authentication, reserving it to mirror the upstream connection status[1], so waiting for it means registration never completes. RPL_SASLSUCCESS is what ends the SASL exchange; RPL_LOGGEDIN only means an account name was set, by SASL or otherwise[2], and can arrive long after registration. Only send CAP END the first time. Also treat ERR_NICKLOCKED as a SASL failure, which otherwise hangs the same way. [1]: https://github.com/ircv3/ircv3-specifications/pull/476 [2]: https://ircv3.net/specs/extensions/sasl-3.1 --- handle.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/handle.c b/handle.c index 0b01de6..fe7b462 100644 --- a/handle.c +++ b/handle.c @@ -167,6 +167,13 @@ static void handleErrorErroneousNickname(struct Message *msg) { } } +static void capEnd(void) { + static bool sent; + if (sent) return; + sent = true; + ircFormat("CAP END\r\n"); +} + static void handleCap(struct Message *msg) { require(msg, false, 3); enum Cap caps = capParse(msg->params[2]); @@ -181,7 +188,7 @@ static void handleCap(struct Message *msg) { capList(buf, sizeof(buf), caps); ircFormat("CAP REQ :%s\r\n", buf); } else { - if (!(self.caps & CapSASL)) ircFormat("CAP END\r\n"); + if (!(self.caps & CapSASL)) capEnd(); } } else if (!strcmp(msg->params[1], "ACK")) { self.caps |= caps; @@ -190,7 +197,7 @@ static void handleCap(struct Message *msg) { "AUTHENTICATE %s\r\n", (self.plainUser ? "PLAIN" : "EXTERNAL") ); } - if (!(self.caps & CapSASL)) ircFormat("CAP END\r\n"); + if (!(self.caps & CapSASL)) capEnd(); } else if (!strcmp(msg->params[1], "NAK")) { errx(1, "server does not support %s", msg->params[2]); } @@ -251,9 +258,8 @@ static void handleAuthenticate(struct Message *msg) { explicit_bzero(self.plainPass, strlen(self.plainPass)); } -static void handleReplyLoggedIn(struct Message *msg) { - (void)msg; - ircFormat("CAP END\r\n"); +static void handleReplySASLSuccess(struct Message *msg) { + capEnd(); handleReplyGeneric(msg); } @@ -1390,7 +1396,9 @@ static const struct Handler { { "704", +ReplyHelp, handleReplyHelp }, { "705", +ReplyHelp, handleReplyHelp }, { "706", -ReplyHelp, NULL }, - { "900", 0, handleReplyLoggedIn }, + { "900", 0, handleReplySASLSuccess }, + { "902", 0, handleErrorSASLFail }, + { "903", 0, handleReplySASLSuccess }, { "904", 0, handleErrorSASLFail }, { "905", 0, handleErrorSASLFail }, { "906", 0, handleErrorSASLFail }, base-commit: 38dc6a301914efd34f9a57cf75e4d0dae8a529fc -- 2.55.0