From 713df3a34d1b6c64292e3090e21415d1fa6e3fb3 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Mon, 11 Mar 2019 07:03:51 -0400 Subject: [PATCH] fix #300 Also upgrade RENAME to latest draft specification --- irc/errors.go | 8 ++--- irc/handlers.go | 92 +++++++++++++++++++++++-------------------------- irc/numerics.go | 2 ++ 3 files changed, 50 insertions(+), 52 deletions(-) diff --git a/irc/errors.go b/irc/errors.go index b8d5a310..c3169151 100644 --- a/irc/errors.go +++ b/irc/errors.go @@ -28,15 +28,15 @@ var ( errCallbackFailed = errors.New("Account verification could not be sent") errCertfpAlreadyExists = errors.New(`An account already exists for your certificate fingerprint`) errChannelAlreadyRegistered = errors.New("Channel is already registered") - errChannelNameInUse = errors.New("Channel name in use") - errInvalidChannelName = errors.New("Invalid channel name") + errChannelNameInUse = errors.New(`Channel name in use`) + errInvalidChannelName = errors.New(`Invalid channel name`) errMonitorLimitExceeded = errors.New("Monitor limit exceeded") errNickMissing = errors.New("nick missing") errNicknameInUse = errors.New("nickname in use") errNicknameReserved = errors.New("nickname is reserved") errNoExistingBan = errors.New("Ban does not exist") - errNoSuchChannel = errors.New("No such channel") - errRenamePrivsNeeded = errors.New("Only chanops can rename channels") + errNoSuchChannel = errors.New(`No such channel`) + errRenamePrivsNeeded = errors.New(`Only chanops can rename channels`) errInsufficientPrivs = errors.New("Insufficient privileges") errSaslFail = errors.New("SASL failed") errResumeTokenAlreadySet = errors.New("Client was already assigned a resume token") diff --git a/irc/handlers.go b/irc/handlers.go index 791a75e7..1e87bf51 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -2208,65 +2208,43 @@ func rehashHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re // RENAME [] func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) (result bool) { result = false - - errorResponse := func(err error, name string) { - // TODO: send correct error codes, e.g., ERR_CANNOTRENAME, ERR_CHANNAMEINUSE - var code string - switch err { - case errNoSuchChannel: - code = ERR_NOSUCHCHANNEL - case errRenamePrivsNeeded: - code = ERR_CHANOPRIVSNEEDED - case errInvalidChannelName: - code = ERR_UNKNOWNERROR - case errChannelNameInUse: - code = ERR_UNKNOWNERROR - default: - code = ERR_UNKNOWNERROR - } - rb.Add(nil, server.name, code, client.Nick(), "RENAME", name, err.Error()) + oldName, newName := msg.Params[0], msg.Params[1] + if newName == "" { + newName = "" // intentionally invalid channel name, will error as expected } - - oldName := strings.TrimSpace(msg.Params[0]) - newName := strings.TrimSpace(msg.Params[1]) - if oldName == "" || newName == "" { - errorResponse(errInvalidChannelName, "") - return - } - casefoldedOldName, err := CasefoldChannel(oldName) - if err != nil { - errorResponse(errInvalidChannelName, oldName) - return - } - - reason := "No reason" + var reason string if 2 < len(msg.Params) { reason = msg.Params[2] } channel := server.channels.Get(oldName) if channel == nil { - errorResponse(errNoSuchChannel, oldName) - return + rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), oldName, client.t("No such channel")) + return false } - //TODO(dan): allow IRCops to do this? - if !channel.ClientIsAtLeast(client, modes.Operator) { - errorResponse(errRenamePrivsNeeded, oldName) - return + casefoldedOldName := channel.NameCasefolded() + if !(channel.ClientIsAtLeast(client, modes.Operator) || client.HasRoleCapabs("chanreg")) { + rb.Add(nil, server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), oldName, client.t("You're not a channel operator")) + return false } founder := channel.Founder() if founder != "" && founder != client.Account() { - //TODO(dan): Change this to ERR_CANNOTRENAME - rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", oldName, client.t("Only channel founders can change registered channels")) + rb.Add(nil, server.name, ERR_CANNOTRENAME, client.Nick(), oldName, newName, client.t("Only channel founders can change registered channels")) return false } // perform the channel rename - err = server.channels.Rename(oldName, newName) + err := server.channels.Rename(oldName, newName) + if err == errInvalidChannelName { + rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), newName, client.t(err.Error())) + } else if err == errChannelNameInUse { + rb.Add(nil, server.name, ERR_CHANNAMEINUSE, client.Nick(), newName, client.t(err.Error())) + } else if err != nil { + rb.Add(nil, server.name, ERR_CANNOTRENAME, client.Nick(), oldName, newName, client.t("Cannot rename channel")) + } if err != nil { - errorResponse(err, newName) - return + return false } // rename succeeded, persist it @@ -2274,15 +2252,33 @@ func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re // send RENAME messages for _, mcl := range channel.Members() { + targetRb := rb + if mcl != client { + targetRb = NewResponseBuffer(mcl) + } + prefix := mcl.NickMaskString() if mcl.capabilities.Has(caps.Rename) { - mcl.Send(nil, client.nickMaskString, "RENAME", oldName, newName, reason) - } else { - mcl.Send(nil, mcl.nickMaskString, "PART", oldName, fmt.Sprintf(mcl.t("Channel renamed: %s"), reason)) - if mcl.capabilities.Has(caps.ExtendedJoin) { - mcl.Send(nil, mcl.nickMaskString, "JOIN", newName, mcl.AccountName(), mcl.realname) + if reason != "" { + targetRb.Add(nil, prefix, "RENAME", oldName, newName, reason) } else { - mcl.Send(nil, mcl.nickMaskString, "JOIN", newName) + targetRb.Add(nil, prefix, "RENAME", oldName, newName) } + } else { + if reason != "" { + targetRb.Add(nil, prefix, "PART", oldName, fmt.Sprintf(mcl.t("Channel renamed: %s"), reason)) + } else { + targetRb.Add(nil, prefix, "PART", oldName, fmt.Sprintf(mcl.t("Channel renamed"))) + } + if mcl.capabilities.Has(caps.ExtendedJoin) { + targetRb.Add(nil, prefix, "JOIN", newName, mcl.AccountName(), mcl.Realname()) + } else { + targetRb.Add(nil, prefix, "JOIN", newName) + } + channel.SendTopic(mcl, targetRb, false) + channel.Names(mcl, targetRb) + } + if mcl != client { + targetRb.Send(false) } } diff --git a/irc/numerics.go b/irc/numerics.go index 05c4ff21..36e861df 100644 --- a/irc/numerics.go +++ b/irc/numerics.go @@ -165,6 +165,8 @@ const ( RPL_WHOISSECURE = "671" RPL_YOURLANGUAGESARE = "687" RPL_WHOISLANGUAGE = "690" + ERR_CHANNAMEINUSE = "692" + ERR_CANNOTRENAME = "693" RPL_HELPSTART = "704" RPL_HELPTXT = "705" RPL_ENDOFHELP = "706"