3
0
mirror of https://github.com/ergochat/ergo.git synced 2025-01-09 11:42:45 +01:00

Merge pull request #681 from slingamn/issue679_stacktrace.4

Assorted fixes
This commit is contained in:
Shivaram Lingamneni 2019-12-08 02:56:36 -05:00 committed by GitHub
commit 0da2d0036a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 124 deletions

View File

@ -684,13 +684,18 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
splitMessage := utils.MakeSplitMessage(message, true) splitMessage := utils.MakeSplitMessage(message, true)
details := client.Details() details := client.Details()
for _, member := range channel.Members() { params := make([]string, 1, 2)
member.sendFromClientInternal(false, splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", chname, message) params[0] = chname
if message != "" {
params = append(params, message)
} }
rb.AddFromClient(splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", chname, message) for _, member := range channel.Members() {
member.sendFromClientInternal(false, splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", params...)
}
rb.AddFromClient(splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", params...)
for _, session := range client.Sessions() { for _, session := range client.Sessions() {
if session != rb.session { if session != rb.session {
session.sendFromClientInternal(false, splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", chname, message) session.sendFromClientInternal(false, splitMessage.Time, splitMessage.Msgid, details.nickMask, details.accountName, nil, "PART", params...)
} }
} }
@ -1043,10 +1048,9 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
} }
func (channel *Channel) applyModeToMember(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) (result *modes.ModeChange) { func (channel *Channel) applyModeToMember(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) (result *modes.ModeChange) {
casefoldedName, err := CasefoldName(nick) target := channel.server.clients.Get(nick)
target := channel.server.clients.Get(casefoldedName) if target == nil {
if err != nil || target == nil { rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(nick), client.t("No such nick"))
rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.Nick(), nick, client.t("No such nick"))
return nil return nil
} }

View File

@ -21,31 +21,39 @@ type Command struct {
} }
// Run runs this command with the given client/message. // Run runs this command with the given client/message.
func (cmd *Command) Run(server *Server, client *Client, session *Session, msg ircmsg.IrcMessage) bool { func (cmd *Command) Run(server *Server, client *Client, session *Session, msg ircmsg.IrcMessage) (exiting bool) {
if !client.registered && !cmd.usablePreReg {
client.Send(nil, server.name, ERR_NOTREGISTERED, "*", client.t("You need to register before you can use that command"))
return false
}
if cmd.oper && !client.HasMode(modes.Operator) {
client.Send(nil, server.name, ERR_NOPRIVILEGES, client.nick, client.t("Permission Denied - You're not an IRC operator"))
return false
}
if len(cmd.capabs) > 0 && !client.HasRoleCapabs(cmd.capabs...) {
client.Send(nil, server.name, ERR_NOPRIVILEGES, client.nick, client.t("Permission Denied"))
return false
}
if len(msg.Params) < cmd.minParams {
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, client.t("Not enough parameters"))
return false
}
rb := NewResponseBuffer(session) rb := NewResponseBuffer(session)
rb.Label = GetLabel(msg) rb.Label = GetLabel(msg)
exiting := cmd.handler(server, client, msg, rb)
rb.Send(true) exiting = func() bool {
defer rb.Send(true)
if !client.registered && !cmd.usablePreReg {
rb.Add(nil, server.name, ERR_NOTREGISTERED, "*", client.t("You need to register before you can use that command"))
return false
}
if cmd.oper && !client.HasMode(modes.Operator) {
rb.Add(nil, server.name, ERR_NOPRIVILEGES, client.Nick(), client.t("Permission Denied - You're not an IRC operator"))
return false
}
if len(cmd.capabs) > 0 && !client.HasRoleCapabs(cmd.capabs...) {
rb.Add(nil, server.name, ERR_NOPRIVILEGES, client.Nick(), client.t("Permission Denied"))
return false
}
if len(msg.Params) < cmd.minParams {
rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, client.Nick(), msg.Command, rb.target.t("Not enough parameters"))
return false
}
return cmd.handler(server, client, msg, rb)
}()
if exiting {
return
}
// after each command, see if we can send registration to the client // after each command, see if we can send registration to the client
if !exiting && !client.registered { if !client.registered {
exiting = server.tryRegister(client, session) exiting = server.tryRegister(client, session)
} }

View File

@ -1162,7 +1162,7 @@ func historyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
if hist == nil { if hist == nil {
if channel == nil { if channel == nil {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), target, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(target), client.t("No such channel"))
} else { } else {
rb.Add(nil, server.name, ERR_NOTONCHANNEL, client.Nick(), target, client.t("You're not on that channel")) rb.Add(nil, server.name, ERR_NOTONCHANNEL, client.Nick(), target, client.t("You're not on that channel"))
} }
@ -1228,17 +1228,15 @@ func inviteHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
nickname := msg.Params[0] nickname := msg.Params[0]
channelName := msg.Params[1] channelName := msg.Params[1]
casefoldedNickname, err := CasefoldName(nickname) target := server.clients.Get(nickname)
target := server.clients.Get(casefoldedNickname) if target == nil {
if err != nil || target == nil { rb.Add(nil, server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(nickname), client.t("No such nick"))
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, nickname, client.t("No such nick"))
return false return false
} }
casefoldedChannelName, err := CasefoldChannel(channelName) channel := server.channels.Get(channelName)
channel := server.channels.Get(casefoldedChannelName) if channel == nil {
if err != nil || channel == nil { rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, utils.SafeErrorParam(channelName), client.t("No such channel"))
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, channelName, client.t("No such channel"))
return false return false
} }
@ -1280,6 +1278,9 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
config := server.Config() config := server.Config()
oper := client.Oper() oper := client.Oper()
for i, name := range channels { for i, name := range channels {
if name == "" {
continue // #679
}
if config.Channels.MaxChannelsPerClient <= client.NumChannels() && oper == nil { if config.Channels.MaxChannelsPerClient <= client.NumChannels() && oper == nil {
rb.Add(nil, server.name, ERR_TOOMANYCHANNELS, client.Nick(), name, client.t("You have joined too many channels")) rb.Add(nil, server.name, ERR_TOOMANYCHANNELS, client.Nick(), name, client.t("You have joined too many channels"))
return false return false
@ -1290,7 +1291,7 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
} }
err := server.channels.Join(client, name, key, false, rb) err := server.channels.Join(client, name, key, false, rb)
if err == errNoSuchChannel { if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), name, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(name), client.t("No such channel"))
} }
} }
return false return false
@ -1310,7 +1311,7 @@ func sajoinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
} else { } else {
target = server.clients.Get(msg.Params[0]) target = server.clients.Get(msg.Params[0])
if target == nil { if target == nil {
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.Nick(), msg.Params[0], "No such nick") rb.Add(nil, server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(msg.Params[0]), "No such nick")
return false return false
} }
channelString = msg.Params[1] channelString = msg.Params[1]
@ -1333,12 +1334,19 @@ func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
return false return false
} }
var kicks [][]string type kickCmd struct {
channel string
nick string
}
kicks := make([]kickCmd, 0, len(channels))
for index, channel := range channels { for index, channel := range channels {
if channel == "" {
continue // #679
}
if len(users) == 1 { if len(users) == 1 {
kicks = append(kicks, []string{channel, users[0]}) kicks = append(kicks, kickCmd{channel, users[0]})
} else { } else {
kicks = append(kicks, []string{channel, users[index]}) kicks = append(kicks, kickCmd{channel, users[index]})
} }
} }
@ -1346,25 +1354,21 @@ func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
if len(msg.Params) > 2 { if len(msg.Params) > 2 {
comment = msg.Params[2] comment = msg.Params[2]
} }
for _, info := range kicks { for _, kick := range kicks {
chname := info[0] channel := server.channels.Get(kick.channel)
nickname := info[1] if channel == nil {
casefoldedChname, err := CasefoldChannel(chname) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, utils.SafeErrorParam(kick.channel), client.t("No such channel"))
channel := server.channels.Get(casefoldedChname)
if err != nil || channel == nil {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel"))
continue continue
} }
casefoldedNickname, err := CasefoldName(nickname) target := server.clients.Get(kick.nick)
target := server.clients.Get(casefoldedNickname) if target == nil {
if err != nil || target == nil { rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, utils.SafeErrorParam(kick.nick), client.t("No such nick"))
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, nickname, client.t("No such nick"))
continue continue
} }
if comment == "" { if comment == "" {
comment = nickname comment = kick.nick
} }
channel.Kick(client, target, comment, rb) channel.Kick(client, target, comment, rb)
} }
@ -1379,10 +1383,9 @@ func killHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
comment = msg.Params[1] comment = msg.Params[1]
} }
casefoldedNickname, err := CasefoldName(nickname) target := server.clients.Get(nickname)
target := server.clients.Get(casefoldedNickname) if target == nil {
if err != nil || target == nil { rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, utils.SafeErrorParam(nickname), client.t("No such nick"))
rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nickname, client.t("No such nick"))
return false return false
} }
@ -1647,11 +1650,10 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
} }
for _, chname := range channels { for _, chname := range channels {
casefoldedChname, err := CasefoldChannel(chname) channel := server.channels.Get(chname)
channel := server.channels.Get(casefoldedChname) if channel == nil || (!clientIsOp && channel.flags.HasMode(modes.Secret)) {
if err != nil || channel == nil || (!clientIsOp && channel.flags.HasMode(modes.Secret)) {
if len(chname) > 0 { if len(chname) > 0 {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, utils.SafeErrorParam(chname), client.t("No such channel"))
} }
continue continue
} }
@ -1672,9 +1674,7 @@ func lusersHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
// MODE <target> [<modestring> [<mode arguments>...]] // MODE <target> [<modestring> [<mode arguments>...]]
func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
_, errChan := CasefoldChannel(msg.Params[0]) if 0 < len(msg.Params[0]) && msg.Params[0][0] == '#' {
if errChan == nil {
return cmodeHandler(server, client, msg, rb) return cmodeHandler(server, client, msg, rb)
} }
return umodeHandler(server, client, msg, rb) return umodeHandler(server, client, msg, rb)
@ -1682,11 +1682,10 @@ func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
// MODE <channel> [<modestring> [<mode arguments>...]] // MODE <channel> [<modestring> [<mode arguments>...]]
func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
channelName, err := CasefoldChannel(msg.Params[0]) channel := server.channels.Get(msg.Params[0])
channel := server.channels.Get(channelName)
if err != nil || channel == nil { if channel == nil {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
return false return false
} }
@ -1745,12 +1744,9 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
// MODE <client> [<modestring> [<mode arguments>...]] // MODE <client> [<modestring> [<mode arguments>...]]
func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
cDetails := client.Details() cDetails := client.Details()
nickname, err := CasefoldName(msg.Params[0]) target := server.clients.Get(msg.Params[0])
target := server.clients.Get(nickname) if target == nil {
if err != nil || target == nil { rb.Add(nil, server.name, ERR_NOSUCHNICK, cDetails.nick, utils.SafeErrorParam(msg.Params[0]), client.t("No such nick"))
if len(msg.Params[0]) > 0 {
rb.Add(nil, server.name, ERR_NOSUCHNICK, cDetails.nick, msg.Params[0], client.t("No such nick"))
}
return false return false
} }
@ -2052,7 +2048,7 @@ func messageHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
channel := server.channels.Get(targetString) channel := server.channels.Get(targetString)
if channel == nil { if channel == nil {
if histType != history.Notice { if histType != history.Notice {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, cnick, targetString, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, cnick, utils.SafeErrorParam(targetString), client.t("No such channel"))
} }
continue continue
} }
@ -2224,15 +2220,18 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
// PART <channel>{,<channel>} [<reason>] // PART <channel>{,<channel>} [<reason>]
func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
channels := strings.Split(msg.Params[0], ",") channels := strings.Split(msg.Params[0], ",")
var reason string //TODO(dan): if this isn't supplied here, make sure the param doesn't exist in the PART message sent to other users var reason string
if len(msg.Params) > 1 { if len(msg.Params) > 1 {
reason = msg.Params[1] reason = msg.Params[1]
} }
for _, chname := range channels { for _, chname := range channels {
if chname == "" {
continue // #679
}
err := server.channels.Part(client, chname, reason, rb) err := server.channels.Part(client, chname, reason, rb)
if err == errNoSuchChannel { if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, utils.SafeErrorParam(chname), client.t("No such channel"))
} }
} }
return false return false
@ -2305,9 +2304,6 @@ func rehashHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) (result bool) { func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) (result bool) {
result = false result = false
oldName, newName := msg.Params[0], msg.Params[1] oldName, newName := msg.Params[0], msg.Params[1]
if newName == "" {
newName = "<empty>" // intentionally invalid channel name, will error as expected
}
var reason string var reason string
if 2 < len(msg.Params) { if 2 < len(msg.Params) {
reason = msg.Params[2] reason = msg.Params[2]
@ -2315,7 +2311,7 @@ func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
channel := server.channels.Get(oldName) channel := server.channels.Get(oldName)
if channel == nil { if channel == nil {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), oldName, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(oldName), client.t("No such channel"))
return false return false
} }
if !(channel.ClientIsAtLeast(client, modes.Operator) || client.HasRoleCapabs("chanreg")) { if !(channel.ClientIsAtLeast(client, modes.Operator) || client.HasRoleCapabs("chanreg")) {
@ -2332,11 +2328,11 @@ func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
// perform the channel rename // perform the channel rename
err := server.channels.Rename(oldName, newName) err := server.channels.Rename(oldName, newName)
if err == errInvalidChannelName { if err == errInvalidChannelName {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), newName, client.t(err.Error())) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(newName), client.t(err.Error()))
} else if err == errChannelNameInUse { } else if err == errChannelNameInUse {
rb.Add(nil, server.name, ERR_CHANNAMEINUSE, client.Nick(), newName, client.t(err.Error())) rb.Add(nil, server.name, ERR_CHANNAMEINUSE, client.Nick(), utils.SafeErrorParam(newName), client.t(err.Error()))
} else if err != nil { } else if err != nil {
rb.Add(nil, server.name, ERR_CANNOTRENAME, client.Nick(), oldName, newName, client.t("Cannot rename channel")) rb.Add(nil, server.name, ERR_CANNOTRENAME, client.Nick(), oldName, utils.SafeErrorParam(newName), client.t("Cannot rename channel"))
} }
if err != nil { if err != nil {
return false return false
@ -2456,12 +2452,9 @@ func timeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
// TOPIC <channel> [<topic>] // TOPIC <channel> [<topic>]
func topicHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func topicHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
name, err := CasefoldChannel(msg.Params[0]) channel := server.channels.Get(msg.Params[0])
channel := server.channels.Get(name) if channel == nil {
if err != nil || channel == nil { rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
if len(msg.Params[0]) > 0 {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], client.t("No such channel"))
}
return false return false
} }
@ -2559,25 +2552,24 @@ func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
// USERHOST <nickname>{ <nickname>} // USERHOST <nickname>{ <nickname>}
func userhostHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func userhostHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
returnedNicks := make(map[string]bool) returnedClients := make(ClientSet)
var tl utils.TokenLineBuilder
tl.Initialize(400, " ")
for i, nickname := range msg.Params { for i, nickname := range msg.Params {
if i >= 10 { if i >= 10 {
break break
} }
casefoldedNickname, err := CasefoldName(nickname) target := server.clients.Get(nickname)
target := server.clients.Get(casefoldedNickname) if target == nil {
if err != nil || target == nil {
rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nickname, client.t("No such nick"))
return false
}
if returnedNicks[casefoldedNickname] {
continue continue
} }
// to prevent returning multiple results for a single nick // to prevent returning multiple results for a single nick
returnedNicks[casefoldedNickname] = true if returnedClients.Has(target) {
continue
}
returnedClients.Add(target)
var isOper, isAway string var isOper, isAway string
@ -2589,7 +2581,17 @@ func userhostHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *
} else { } else {
isAway = "+" isAway = "+"
} }
rb.Add(nil, client.server.name, RPL_USERHOST, client.nick, fmt.Sprintf("%s%s=%s%s@%s", target.nick, isOper, isAway, target.username, target.hostname)) details := target.Details()
tl.Add(fmt.Sprintf("%s%s=%s%s@%s", details.nick, isOper, isAway, details.username, details.hostname))
}
lines := tl.Lines()
if lines == nil {
lines = []string{""}
}
nick := client.Nick()
for _, line := range lines {
rb.Add(nil, client.server.name, RPL_USERHOST, nick, line)
} }
return false return false
@ -2725,11 +2727,6 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
masksString = msg.Params[0] masksString = msg.Params[0]
} }
if len(strings.TrimSpace(masksString)) < 1 {
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, client.t("No masks given"))
return false
}
handleService := func(nick string) bool { handleService := func(nick string) bool {
cfnick, _ := CasefoldName(nick) cfnick, _ := CasefoldName(nick)
service, ok := OragonoServices[cfnick] service, ok := OragonoServices[cfnick]
@ -2749,7 +2746,7 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
for _, mask := range strings.Split(masksString, ",") { for _, mask := range strings.Split(masksString, ",") {
matches := server.clients.FindAll(mask) matches := server.clients.FindAll(mask)
if len(matches) == 0 && !handleService(mask) { if len(matches) == 0 && !handleService(mask) {
rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, mask, client.t("No such nick")) rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(mask), client.t("No such nick"))
continue continue
} }
for mclient := range matches { for mclient := range matches {
@ -2763,11 +2760,11 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
if mclient != nil { if mclient != nil {
client.getWhoisOf(mclient, rb) client.getWhoisOf(mclient, rb)
} else if !handleService(nick) { } else if !handleService(nick) {
rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, masksString, client.t("No such nick")) rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(masksString), client.t("No such nick"))
} }
// fall through, ENDOFWHOIS is always sent // fall through, ENDOFWHOIS is always sent
} }
rb.Add(nil, server.name, RPL_ENDOFWHOIS, client.nick, masksString, client.t("End of /WHOIS list")) rb.Add(nil, server.name, RPL_ENDOFWHOIS, client.nick, utils.SafeErrorParam(masksString), client.t("End of /WHOIS list"))
return false return false
} }
@ -2776,9 +2773,12 @@ func whowasHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
nicknames := strings.Split(msg.Params[0], ",") nicknames := strings.Split(msg.Params[0], ",")
// 0 means "all the entries", as does a negative number // 0 means "all the entries", as does a negative number
var count uint64 var count int
if len(msg.Params) > 1 { if len(msg.Params) > 1 {
count, _ = strconv.ParseUint(msg.Params[1], 10, 64) count, _ = strconv.Atoi(msg.Params[1])
if count < 0 {
count = 0
}
} }
//var target string //var target string
//if len(msg.Params) > 2 { //if len(msg.Params) > 2 {
@ -2786,19 +2786,18 @@ func whowasHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
//} //}
cnick := client.Nick() cnick := client.Nick()
for _, nickname := range nicknames { for _, nickname := range nicknames {
results := server.whoWas.Find(nickname, int(count)) if len(nickname) == 0 {
continue
}
results := server.whoWas.Find(nickname, count)
if len(results) == 0 { if len(results) == 0 {
if len(nickname) > 0 { rb.Add(nil, server.name, ERR_WASNOSUCHNICK, cnick, utils.SafeErrorParam(nickname), client.t("There was no such nickname"))
rb.Add(nil, server.name, ERR_WASNOSUCHNICK, cnick, nickname, client.t("There was no such nickname"))
}
} else { } else {
for _, whoWas := range results { for _, whoWas := range results {
rb.Add(nil, server.name, RPL_WHOWASUSER, cnick, whoWas.nick, whoWas.username, whoWas.hostname, "*", whoWas.realname) rb.Add(nil, server.name, RPL_WHOWASUSER, cnick, whoWas.nick, whoWas.username, whoWas.hostname, "*", whoWas.realname)
} }
} }
if len(nickname) > 0 { rb.Add(nil, server.name, RPL_ENDOFWHOWAS, cnick, utils.SafeErrorParam(nickname), client.t("End of WHOWAS"))
rb.Add(nil, server.name, RPL_ENDOFWHOWAS, cnick, nickname, client.t("End of WHOWAS"))
}
} }
return false return false
} }

View File

@ -49,7 +49,7 @@ func performNickChange(server *Server, client *Client, target *Client, session *
} else if err == errNicknameReserved { } else if err == errNicknameReserved {
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, currentNick, nickname, client.t("Nickname is reserved by a different account")) rb.Add(nil, server.name, ERR_NICKNAMEINUSE, currentNick, nickname, client.t("Nickname is reserved by a different account"))
} else if err == errNicknameInvalid { } else if err == errNicknameInvalid {
rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, currentNick, nickname, client.t("Erroneous nickname")) rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, currentNick, utils.SafeErrorParam(nickname), client.t("Erroneous nickname"))
} else if err != nil { } else if err != nil {
rb.Add(nil, server.name, ERR_UNKNOWNERROR, currentNick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error())) rb.Add(nil, server.name, ERR_UNKNOWNERROR, currentNick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
} }

View File

@ -7,12 +7,14 @@ package irc
import "github.com/oragono/oragono/irc/modes" import "github.com/oragono/oragono/irc/modes"
type empty struct{}
// ClientSet is a set of clients. // ClientSet is a set of clients.
type ClientSet map[*Client]bool type ClientSet map[*Client]empty
// Add adds the given client to this set. // Add adds the given client to this set.
func (clients ClientSet) Add(client *Client) { func (clients ClientSet) Add(client *Client) {
clients[client] = true clients[client] = empty{}
} }
// Remove removes the given client from this set. // Remove removes the given client from this set.
@ -22,7 +24,8 @@ func (clients ClientSet) Remove(client *Client) {
// Has returns true if the given client is in this set. // Has returns true if the given client is in this set.
func (clients ClientSet) Has(client *Client) bool { func (clients ClientSet) Has(client *Client) bool {
return clients[client] _, ok := clients[client]
return ok
} }
// MemberSet is a set of members with modes. // MemberSet is a set of members with modes.

View File

@ -54,3 +54,12 @@ func StringToBool(str string) (result bool, err error) {
} }
return return
} }
// Checks that a parameter can be passed as a non-trailing, and returns "*"
// if it can't. See #697.
func SafeErrorParam(param string) string {
if param == "" || param[0] == ':' || strings.IndexByte(param, ' ') != -1 {
return "*"
}
return param
}

View File

@ -21,3 +21,12 @@ func TestStringToBool(t *testing.T) {
val, err = StringToBool("default") val, err = StringToBool("default")
assertEqual(err, ErrInvalidParams, t) assertEqual(err, ErrInvalidParams, t)
} }
func TestSafeErrorParam(t *testing.T) {
assertEqual(SafeErrorParam("hi"), "hi", t)
assertEqual(SafeErrorParam("#hi"), "#hi", t)
assertEqual(SafeErrorParam("#hi there"), "*", t)
assertEqual(SafeErrorParam(":"), "*", t)
assertEqual(SafeErrorParam("#hi:there"), "#hi:there", t)
assertEqual(SafeErrorParam(""), "*", t)
}