From 51b2476af7041d6e09592222a2924b5e094767ac Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Tue, 19 May 2026 03:08:39 +0000 Subject: [PATCH] fix #2402 Labeled QUIT from the client should receive a labeled QUIT in return --- irc/accounts.go | 4 ++-- irc/client.go | 18 +++++++++++------- irc/gateways.go | 2 +- irc/handlers.go | 14 +++++++------- irc/nickserv.go | 2 +- irc/server.go | 4 ++-- irc/uban.go | 4 ++-- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/irc/accounts.go b/irc/accounts.go index 64226bf6..12bd75d3 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -1791,7 +1791,7 @@ func (am *AccountManager) Suspend(accountName string, duration time.Duration, op suspension.AccountName = accountName for _, client := range clients { client.Logout() - client.Quit(suspensionToString(client, suspension), nil) + client.Quit(suspensionToString(client, suspension), nil, nil) client.destroy(nil) } return nil @@ -1800,7 +1800,7 @@ func (am *AccountManager) Suspend(accountName string, duration time.Duration, op func (am *AccountManager) killClients(clients []*Client) { for _, client := range clients { client.Logout() - client.Quit(client.t("You are no longer authorized to be on this server"), nil) + client.Quit(client.t("You are no longer authorized to be on this server"), nil, nil) client.destroy(nil) } } diff --git a/irc/client.go b/irc/client.go index d9aac5d9..395689d2 100644 --- a/irc/client.go +++ b/irc/client.go @@ -709,7 +709,7 @@ func (client *Client) run(session *Session) { default: quitMessage = "connection closed" } - client.Quit(quitMessage, session) + client.Quit(quitMessage, session, nil) break } @@ -773,7 +773,7 @@ func (client *Client) run(session *Session) { if strings.HasPrefix(line, utf8BOM) { message = "Received UTF-8 byte-order mark, which is invalid at the start of an IRC protocol message" } - client.Quit(message, session) + client.Quit(message, session, nil) break } @@ -893,7 +893,7 @@ func (session *Session) handleIdleTimeout() { var shouldDestroy, shouldSendPing bool defer func() { if shouldDestroy { - session.client.Quit(fmt.Sprintf("Ping timeout: %v", totalTimeout), session) + session.client.Quit(fmt.Sprintf("Ping timeout: %v", totalTimeout), session, nil) session.client.destroy(session) } else if shouldSendPing { session.Ping() @@ -1246,7 +1246,7 @@ func (client *Client) LoggedIntoAccount() bool { // Quit sets the given quit message for the client. // (You must ensure separately that destroy() is called, e.g., by returning `true` from // the command handler or calling it yourself.) -func (client *Client) Quit(message string, session *Session) { +func (client *Client) Quit(message string, session *Session, rb *ResponseBuffer) { nuh := client.NickMaskString() now := time.Now().UTC() @@ -1259,7 +1259,11 @@ func (client *Client) Quit(message string, session *Session) { if sess.capabilities.Has(caps.ServerTime) { quitMsg.SetTag("time", now.Format(utils.IRCv3TimestampFormat)) } - finalData, _ = quitMsg.LineBytesStrict(false, MaxLineLen) + if rb != nil { + rb.AddMessage(quitMsg) + } else { + finalData, _ = quitMsg.LineBytesStrict(false, MaxLineLen) + } } errorMsg := ircmsg.MakeMessage(nil, "", "ERROR", message) @@ -1355,7 +1359,7 @@ func (client *Client) destroy(session *Session) { } session.stopIdleTimer() // send quit/error message to client if they haven't been sent already - client.Quit("", session) + client.Quit("", session, nil) quitMessage = session.quitMessage // doesn't need synch, we already detached session.socket.Close() @@ -1860,7 +1864,7 @@ func (client *Client) privmsgsBetween(startTime, endTime time.Time, targetLimit, } func (client *Client) handleRegisterTimeout() { - client.Quit(fmt.Sprintf("Registration timeout: %v", RegisterTimeout), nil) + client.Quit(fmt.Sprintf("Registration timeout: %v", RegisterTimeout), nil, nil) client.destroy(nil) } diff --git a/irc/gateways.go b/irc/gateways.go index e8ab60ab..cc53fea1 100644 --- a/irc/gateways.go +++ b/irc/gateways.go @@ -119,7 +119,7 @@ func handleProxyCommand(server *Server, client *Client, session *Session, line s if quitMsg == "" { quitMsg = client.t("Bad or unauthorized PROXY command") } - client.Quit(quitMsg, session) + client.Quit(quitMsg, session, nil) } }() diff --git a/irc/handlers.go b/irc/handlers.go index 4173525f..1ca439fc 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -676,7 +676,7 @@ func capHandler(server *Server, client *Client, msg ircmsg.Message, rb *Response rb.Add(nil, server.name, "CAP", details.nick, "NAK", capString) return false } else if toAdd.Has(caps.Nope) && !client.registered { - client.Quit(fmt.Sprintf(client.t("Requesting the %s client capability is forbidden"), caps.Nope.Name()), rb.session) + client.Quit(fmt.Sprintf(client.t("Requesting the %s client capability is forbidden"), caps.Nope.Name()), rb.session, nil) return true } @@ -1123,7 +1123,7 @@ func dlineHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon for _, session := range sessionsToKill { mcl := session.client - mcl.Quit(fmt.Sprintf(mcl.t("You have been banned from this server (%s)"), reason), session) + mcl.Quit(fmt.Sprintf(mcl.t("You have been banned from this server (%s)"), reason), session, nil) if session == rb.session { killClient = true } else { @@ -1572,7 +1572,7 @@ func killHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons } server.snomasks.Send(sno.LocalKills, snoLine) - target.Quit(quitMsg, nil) + target.Quit(quitMsg, nil, nil) target.destroy(nil) return false } @@ -1703,7 +1703,7 @@ func klineHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon } for _, mcl := range clientsToKill { - mcl.Quit(fmt.Sprintf(mcl.t("You have been banned from this server (%s)"), reason), nil) + mcl.Quit(fmt.Sprintf(mcl.t("You have been banned from this server (%s)"), reason), nil, nil) if mcl == client { killClient = true } else { @@ -2964,7 +2964,7 @@ func quitHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons if len(msg.Params) > 0 { reason += ": " + msg.Params[0] } - client.Quit(reason, rb.session) + client.Quit(reason, rb.session, rb) return true } @@ -3973,7 +3973,7 @@ func webircHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo candidateIP := msg.Params[3] err, quitMsg := client.ApplyProxiedIP(rb.session, net.ParseIP(candidateIP), secure) if err != nil { - client.Quit(quitMsg, rb.session) + client.Quit(quitMsg, rb.session, rb) return true } else { if info.AcceptHostname { @@ -3992,7 +3992,7 @@ func webircHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo } } - client.Quit(client.t("WEBIRC command is not usable from your address or incorrect password given"), rb.session) + client.Quit(client.t("WEBIRC command is not usable from your address or incorrect password given"), rb.session, rb) return true } diff --git a/irc/nickserv.go b/irc/nickserv.go index 3679a15c..110bac25 100644 --- a/irc/nickserv.go +++ b/irc/nickserv.go @@ -802,7 +802,7 @@ func nsGhostHandler(service *ircService, server *Server, client *Client, command return } - ghost.Quit(fmt.Sprintf(ghost.t("GHOSTed by %s"), client.Nick()), nil) + ghost.Quit(fmt.Sprintf(ghost.t("GHOSTed by %s"), client.Nick()), nil, nil) ghost.destroy(nil) } diff --git a/irc/server.go b/irc/server.go index aeeb639c..efe23ee5 100644 --- a/irc/server.go +++ b/irc/server.go @@ -414,7 +414,7 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) { c.Send(nil, c.server.name, "FAIL", "*", "ACCOUNT_REQUIRED", quitMessage) } if authOutcome != authSuccess { - c.Quit(quitMessage, nil) + c.Quit(quitMessage, nil, nil) return true } c.requireSASLMessage = "" @@ -463,7 +463,7 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) { isBanned, info := server.klines.CheckMasks(c.AllNickmasks()...) if isBanned && !(info.RequireSASL && session.client.Account() != "") { c.setKlined() - c.Quit(info.BanMessage(c.t("You are banned from this server (%s)")), nil) + c.Quit(info.BanMessage(c.t("You are banned from this server (%s)")), nil, nil) server.logger.Info("connect", session.connID, "Client rejected by k-line", c.NickMaskString()) return true } diff --git a/irc/uban.go b/irc/uban.go index f828e0c1..699cae23 100644 --- a/irc/uban.go +++ b/irc/uban.go @@ -229,7 +229,7 @@ func ubanAddCIDR(client *Client, target ubanTarget, duration time.Duration, requ sessions, nicks := sessionsForCIDR(client.server, target.cidr, rb.session, requireSASL) for _, session := range sessions { - session.client.Quit("You have been banned from this server", session) + session.client.Quit("You have been banned from this server", session, nil) session.client.destroy(session) } @@ -258,7 +258,7 @@ func ubanAddNickmask(client *Client, target ubanTarget, duration time.Duration, if mcl != client && target.matcher.MatchString(mcl.NickMaskCasefolded()) { if !mcl.AlwaysOn() { killed = append(killed, mcl.Nick()) - mcl.Quit("You have been banned from this server", nil) + mcl.Quit("You have been banned from this server", nil, nil) mcl.destroy(nil) } else { alwaysOn = append(alwaysOn, mcl.Nick())