mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
commit
63ac37748d
@ -377,25 +377,25 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
||||
hasPrivs := isSajoin || (founder != "" && founder == details.account) || (persistentMode != 0 && persistentMode != modes.Voice)
|
||||
|
||||
if !hasPrivs && limit != 0 && chcount >= limit {
|
||||
rb.Add(nil, client.server.name, ERR_CHANNELISFULL, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANNELISFULL, details.nick, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
|
||||
return
|
||||
}
|
||||
|
||||
if !hasPrivs && chkey != "" && !utils.SecretTokensMatch(chkey, key) {
|
||||
rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
|
||||
rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, details.nick, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
|
||||
return
|
||||
}
|
||||
|
||||
isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded)
|
||||
if !hasPrivs && channel.flags.HasMode(modes.InviteOnly) && !isInvited {
|
||||
rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
|
||||
rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, details.nick, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
|
||||
return
|
||||
}
|
||||
|
||||
if !hasPrivs && channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
|
||||
!isInvited &&
|
||||
!channel.lists[modes.ExceptMask].Match(details.nickMaskCasefolded) {
|
||||
rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
|
||||
rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, details.nick, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -482,7 +482,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
||||
func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
|
||||
chname := channel.Name()
|
||||
if !channel.hasClient(client) {
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, chname, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), chname, client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -645,7 +645,7 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
|
||||
// `sendNoTopic` controls whether RPL_NOTOPIC is sent when the topic is unset
|
||||
func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer, sendNoTopic bool) {
|
||||
if !channel.hasClient(client) {
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), channel.name, client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -670,12 +670,12 @@ func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer, sendNoTopi
|
||||
// SetTopic sets the topic of this channel, if the client is allowed to do so.
|
||||
func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) {
|
||||
if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), channel.Name(), client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
if channel.flags.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.Name(), client.t("You're not a channel operator"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -719,22 +719,30 @@ func (channel *Channel) CanSpeak(client *Client) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (channel *Channel) SendSplitMessage(command string, minPrefix *modes.Mode, clientOnlyTags map[string]string, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
|
||||
var histType history.ItemType
|
||||
func msgCommandToHistType(server *Server, command string) (history.ItemType, error) {
|
||||
switch command {
|
||||
case "PRIVMSG":
|
||||
histType = history.Privmsg
|
||||
return history.Privmsg, nil
|
||||
case "NOTICE":
|
||||
histType = history.Notice
|
||||
return history.Notice, nil
|
||||
case "TAGMSG":
|
||||
histType = history.Tagmsg
|
||||
return history.Tagmsg, nil
|
||||
default:
|
||||
channel.server.logger.Error("internal", "unrecognized Channel.SendSplitMessage command", command)
|
||||
server.logger.Error("internal", "unrecognized messaging command", command)
|
||||
return history.ItemType(0), errInvalidParams
|
||||
}
|
||||
}
|
||||
|
||||
func (channel *Channel) SendSplitMessage(command string, minPrefix *modes.Mode, clientOnlyTags map[string]string, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
|
||||
histType, err := msgCommandToHistType(channel.server, command)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !channel.CanSpeak(client) {
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
if histType != history.Notice {
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, client.Nick(), channel.Name(), client.t("Cannot send to channel"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -751,7 +759,7 @@ func (channel *Channel) SendSplitMessage(command string, minPrefix *modes.Mode,
|
||||
}
|
||||
nickMaskString := client.NickMaskString()
|
||||
accountName := client.AccountName()
|
||||
if command == "TAGMSG" && client.capabilities.Has(caps.MessageTags) {
|
||||
if histType == history.Tagmsg && client.capabilities.Has(caps.MessageTags) {
|
||||
rb.AddFromClient(message.Msgid, nickMaskString, accountName, tagsToUse, command, channel.name)
|
||||
} else {
|
||||
rb.AddSplitMessageFromClient(nickMaskString, accountName, tagsToUse, command, channel.name, message)
|
||||
@ -775,11 +783,11 @@ func (channel *Channel) SendSplitMessage(command string, minPrefix *modes.Mode,
|
||||
var tagsToUse map[string]string
|
||||
if member.capabilities.Has(caps.MessageTags) {
|
||||
tagsToUse = clientOnlyTags
|
||||
} else if command == "TAGMSG" {
|
||||
} else if histType == history.Tagmsg {
|
||||
continue
|
||||
}
|
||||
|
||||
if command == "TAGMSG" {
|
||||
if histType == history.Tagmsg {
|
||||
member.sendFromClientInternal(false, now, message.Msgid, nickmask, account, tagsToUse, command, channel.name)
|
||||
} else {
|
||||
member.sendSplitMsgFromClientInternal(false, now, nickmask, account, tagsToUse, command, channel.name, message)
|
||||
@ -861,7 +869,7 @@ func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.
|
||||
}
|
||||
|
||||
if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.Name(), client.t("You're not a channel operator"))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -898,15 +906,15 @@ func (channel *Channel) Quit(client *Client) {
|
||||
|
||||
func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
|
||||
if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), channel.Name(), client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
if !channel.hasClient(target) {
|
||||
rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.Nick(), channel.Name(), client.t("They aren't on that channel"))
|
||||
return
|
||||
}
|
||||
if !channel.ClientHasPrivsOver(client, target) {
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You don't have enough channel privileges"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.Name(), client.t("You don't have enough channel privileges"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -938,12 +946,12 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string, rb
|
||||
func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
|
||||
chname := channel.Name()
|
||||
if channel.flags.HasMode(modes.InviteOnly) && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
|
||||
rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, chname, inviter.t("You're not a channel operator"))
|
||||
rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, inviter.Nick(), channel.Name(), inviter.t("You're not a channel operator"))
|
||||
return
|
||||
}
|
||||
|
||||
if !channel.hasClient(inviter) {
|
||||
rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, chname, inviter.t("You're not on that channel"))
|
||||
rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, inviter.Nick(), channel.Name(), inviter.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -325,7 +325,7 @@ func (client *Client) run() {
|
||||
if err == ircmsg.ErrorLineIsEmpty {
|
||||
continue
|
||||
} else if err == ircmsg.ErrorLineTooLong {
|
||||
client.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.nick, client.t("Input line too long"))
|
||||
client.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Input line too long"))
|
||||
continue
|
||||
} else if err != nil {
|
||||
client.Quit(client.t("Received malformed line"))
|
||||
@ -335,9 +335,9 @@ func (client *Client) run() {
|
||||
cmd, exists := Commands[msg.Command]
|
||||
if !exists {
|
||||
if len(msg.Command) > 0 {
|
||||
client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, client.t("Unknown command"))
|
||||
client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.Nick(), msg.Command, client.t("Unknown command"))
|
||||
} else {
|
||||
client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, "lastcmd", client.t("No command given"))
|
||||
client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.Nick(), "lastcmd", client.t("No command given"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ type Command struct {
|
||||
// Run runs this command with the given client/message.
|
||||
func (cmd *Command) Run(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
if !client.registered && !cmd.usablePreReg {
|
||||
client.Send(nil, server.name, ERR_NOTREGISTERED, client.nick, client.t("You need to register before you can use that command"))
|
||||
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) {
|
||||
@ -184,7 +184,7 @@ func init() {
|
||||
minParams: 1,
|
||||
},
|
||||
"NOTICE": {
|
||||
handler: noticeHandler,
|
||||
handler: messageHandler,
|
||||
minParams: 2,
|
||||
},
|
||||
"NPC": {
|
||||
@ -221,7 +221,7 @@ func init() {
|
||||
leaveClientIdle: true,
|
||||
},
|
||||
"PRIVMSG": {
|
||||
handler: privmsgHandler,
|
||||
handler: messageHandler,
|
||||
minParams: 2,
|
||||
},
|
||||
"RENAME": {
|
||||
@ -257,7 +257,7 @@ func init() {
|
||||
minParams: 1,
|
||||
},
|
||||
"TAGMSG": {
|
||||
handler: tagmsgHandler,
|
||||
handler: messageHandler,
|
||||
minParams: 1,
|
||||
},
|
||||
"QUIT": {
|
||||
|
263
irc/handlers.go
263
irc/handlers.go
@ -242,7 +242,7 @@ func accVerifyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb
|
||||
if err == nil {
|
||||
sendSuccessfulRegResponse(client, rb, false)
|
||||
} else {
|
||||
rb.Add(nil, server.name, code, client.nick, account, client.t(message))
|
||||
rb.Add(nil, server.name, code, client.Nick(), account, client.t(message))
|
||||
}
|
||||
|
||||
return false
|
||||
@ -1873,19 +1873,41 @@ func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
}
|
||||
|
||||
// NOTICE <target>{,<target>} <message>
|
||||
func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
clientOnlyTags := msg.ClientOnlyTags()
|
||||
targets := strings.Split(msg.Params[0], ",")
|
||||
message := msg.Params[1]
|
||||
|
||||
if client.isTor && isRestrictedCTCPMessage(message) {
|
||||
rb.Add(nil, server.name, "NOTICE", client.t("CTCP messages are disabled over Tor"))
|
||||
// PRIVMSG <target>{,<target>} <message>
|
||||
// TAGMSG <target>{,<target>}
|
||||
func messageHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
histType, err := msgCommandToHistType(server, msg.Command)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
splitMsg := utils.MakeSplitMessage(message, !client.capabilities.Has(caps.MaxLine))
|
||||
cnick := client.Nick()
|
||||
clientOnlyTags := msg.ClientOnlyTags()
|
||||
if histType == history.Tagmsg && len(clientOnlyTags) == 0 {
|
||||
// nothing to do
|
||||
return false
|
||||
}
|
||||
|
||||
targets := strings.Split(msg.Params[0], ",")
|
||||
var message string
|
||||
if len(msg.Params) > 1 {
|
||||
message = msg.Params[1]
|
||||
}
|
||||
|
||||
// note that error replies are never sent for NOTICE
|
||||
|
||||
if client.isTor && isRestrictedCTCPMessage(message) {
|
||||
if histType != history.Notice {
|
||||
rb.Add(nil, server.name, "NOTICE", client.t("CTCP messages are disabled over Tor"))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for i, targetString := range targets {
|
||||
// each target gets distinct msgids
|
||||
splitMsg := utils.MakeSplitMessage(message, !client.capabilities.Has(caps.MaxLine))
|
||||
now := time.Now().UTC()
|
||||
|
||||
// max of four targets per privmsg
|
||||
if i > maxTargets-1 {
|
||||
break
|
||||
@ -1893,52 +1915,66 @@ func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
||||
prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
|
||||
lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
|
||||
|
||||
target, cerr := CasefoldChannel(targetString)
|
||||
if cerr == nil {
|
||||
channel := server.channels.Get(target)
|
||||
if len(targetString) == 0 {
|
||||
continue
|
||||
} else if targetString[0] == '#' {
|
||||
channel := server.channels.Get(targetString)
|
||||
if channel == nil {
|
||||
// errors silently ignored with NOTICE as per RFC
|
||||
if histType != history.Notice {
|
||||
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, cnick, targetString, client.t("No such channel"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !channel.CanSpeak(client) {
|
||||
// errors silently ignored with NOTICE as per RFC
|
||||
continue
|
||||
}
|
||||
channel.SendSplitMessage("NOTICE", lowestPrefix, clientOnlyTags, client, splitMsg, rb)
|
||||
channel.SendSplitMessage(msg.Command, lowestPrefix, clientOnlyTags, client, splitMsg, rb)
|
||||
} else {
|
||||
target, err := CasefoldName(targetString)
|
||||
if err != nil {
|
||||
if service, isService := OragonoServices[strings.ToLower(targetString)]; isService {
|
||||
// NOTICE and TAGMSG to services are ignored
|
||||
if histType == history.Privmsg {
|
||||
servicePrivmsgHandler(service, server, client, message, rb)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// NOTICEs sent to services are ignored
|
||||
if _, isService := OragonoServices[target]; isService {
|
||||
continue
|
||||
}
|
||||
|
||||
user := server.clients.Get(target)
|
||||
user := server.clients.Get(targetString)
|
||||
if user == nil {
|
||||
// errors silently ignored with NOTICE as per RFC
|
||||
if histType != history.Notice {
|
||||
rb.Add(nil, server.name, ERR_NOSUCHNICK, cnick, targetString, "No such nick")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !user.capabilities.Has(caps.MessageTags) {
|
||||
clientOnlyTags = nil
|
||||
tnick := user.Nick()
|
||||
|
||||
if histType == history.Tagmsg && !user.capabilities.Has(caps.MessageTags) {
|
||||
continue // nothing to do
|
||||
}
|
||||
|
||||
nickMaskString := client.NickMaskString()
|
||||
accountName := client.AccountName()
|
||||
// restrict messages appropriately when +R is set
|
||||
// intentionally make the sending user think the message went through fine
|
||||
allowedPlusR := !user.HasMode(modes.RegisteredOnly) || client.LoggedIntoAccount()
|
||||
allowedTor := !user.isTor || !isRestrictedCTCPMessage(message)
|
||||
if allowedPlusR && allowedTor {
|
||||
user.SendSplitMsgFromClient(client, clientOnlyTags, "NOTICE", user.nick, splitMsg)
|
||||
if histType == history.Tagmsg {
|
||||
user.sendFromClientInternal(false, now, splitMsg.Msgid, nickMaskString, accountName, clientOnlyTags, msg.Command, tnick)
|
||||
} else {
|
||||
user.SendSplitMsgFromClient(client, clientOnlyTags, msg.Command, tnick, splitMsg)
|
||||
}
|
||||
}
|
||||
nickMaskString := client.NickMaskString()
|
||||
accountName := client.AccountName()
|
||||
if client.capabilities.Has(caps.EchoMessage) {
|
||||
rb.AddSplitMessageFromClient(nickMaskString, accountName, clientOnlyTags, "NOTICE", user.nick, splitMsg)
|
||||
if histType == history.Tagmsg && client.capabilities.Has(caps.MessageTags) {
|
||||
rb.AddFromClient(splitMsg.Msgid, nickMaskString, accountName, clientOnlyTags, msg.Command, tnick)
|
||||
} else {
|
||||
rb.AddSplitMessageFromClient(nickMaskString, accountName, clientOnlyTags, msg.Command, tnick, splitMsg)
|
||||
}
|
||||
}
|
||||
if histType != history.Notice && user.HasMode(modes.Away) {
|
||||
//TODO(dan): possibly implement cooldown of away notifications to users
|
||||
rb.Add(nil, server.name, RPL_AWAY, cnick, tnick, user.AwayMessage())
|
||||
}
|
||||
|
||||
user.history.Add(history.Item{
|
||||
Type: history.Notice,
|
||||
Type: histType,
|
||||
Message: splitMsg,
|
||||
Nick: nickMaskString,
|
||||
AccountName: accountName,
|
||||
@ -1988,7 +2024,7 @@ func npcaHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
// OPER <name> <password>
|
||||
func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
if client.HasMode(modes.Operator) == true {
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, "OPER", client.t("You're already opered-up!"))
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "OPER", client.t("You're already opered-up!"))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1999,7 +2035,7 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
authorized = (bcrypt.CompareHashAndPassword(oper.Pass, password) == nil)
|
||||
}
|
||||
if !authorized {
|
||||
rb.Add(nil, server.name, ERR_PASSWDMISMATCH, client.nick, client.t("Password incorrect"))
|
||||
rb.Add(nil, server.name, ERR_PASSWDMISMATCH, client.Nick(), client.t("Password incorrect"))
|
||||
client.Quit(client.t("Password incorrect"))
|
||||
return true
|
||||
}
|
||||
@ -2090,90 +2126,6 @@ func isRestrictedCTCPMessage(message string) bool {
|
||||
return strings.HasPrefix(message, "\x01") && !strings.HasPrefix(message, "\x01ACTION")
|
||||
}
|
||||
|
||||
// PRIVMSG <target>{,<target>} <message>
|
||||
func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
clientOnlyTags := msg.ClientOnlyTags()
|
||||
targets := strings.Split(msg.Params[0], ",")
|
||||
message := msg.Params[1]
|
||||
|
||||
if client.isTor && isRestrictedCTCPMessage(message) {
|
||||
rb.Add(nil, server.name, "NOTICE", client.t("CTCP messages are disabled over Tor"))
|
||||
return false
|
||||
}
|
||||
|
||||
// split privmsg
|
||||
splitMsg := utils.MakeSplitMessage(message, !client.capabilities.Has(caps.MaxLine))
|
||||
|
||||
cnick := client.Nick()
|
||||
for i, targetString := range targets {
|
||||
// max of four targets per privmsg
|
||||
if i > maxTargets-1 {
|
||||
break
|
||||
}
|
||||
prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
|
||||
lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
|
||||
|
||||
// eh, no need to notify them
|
||||
if len(targetString) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
target, err := CasefoldChannel(targetString)
|
||||
if err == nil {
|
||||
channel := server.channels.Get(target)
|
||||
if channel == nil {
|
||||
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, cnick, targetString, client.t("No such channel"))
|
||||
continue
|
||||
}
|
||||
if !channel.CanSpeak(client) {
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
continue
|
||||
}
|
||||
channel.SendSplitMessage("PRIVMSG", lowestPrefix, clientOnlyTags, client, splitMsg, rb)
|
||||
} else {
|
||||
target, err = CasefoldName(targetString)
|
||||
if service, isService := OragonoServices[target]; isService {
|
||||
servicePrivmsgHandler(service, server, client, message, rb)
|
||||
continue
|
||||
}
|
||||
user := server.clients.Get(target)
|
||||
if err != nil || user == nil {
|
||||
if len(target) > 0 {
|
||||
client.Send(nil, server.name, ERR_NOSUCHNICK, cnick, target, "No such nick")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !user.capabilities.Has(caps.MessageTags) {
|
||||
clientOnlyTags = nil
|
||||
}
|
||||
// restrict messages appropriately when +R is set
|
||||
// intentionally make the sending user think the message went through fine
|
||||
allowedPlusR := !user.HasMode(modes.RegisteredOnly) || client.LoggedIntoAccount()
|
||||
allowedTor := !user.isTor || !isRestrictedCTCPMessage(message)
|
||||
if allowedPlusR && allowedTor {
|
||||
user.SendSplitMsgFromClient(client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
|
||||
}
|
||||
nickMaskString := client.NickMaskString()
|
||||
accountName := client.AccountName()
|
||||
if client.capabilities.Has(caps.EchoMessage) {
|
||||
rb.AddSplitMessageFromClient(nickMaskString, accountName, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
|
||||
}
|
||||
if user.HasMode(modes.Away) {
|
||||
//TODO(dan): possibly implement cooldown of away notifications to users
|
||||
rb.Add(nil, server.name, RPL_AWAY, cnick, user.Nick(), user.AwayMessage())
|
||||
}
|
||||
|
||||
user.history.Add(history.Item{
|
||||
Type: history.Privmsg,
|
||||
Message: splitMsg,
|
||||
Nick: nickMaskString,
|
||||
AccountName: accountName,
|
||||
})
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// QUIT [<reason>]
|
||||
func quitHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
reason := "Quit"
|
||||
@ -2346,71 +2298,6 @@ func setnameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
||||
return false
|
||||
}
|
||||
|
||||
// TAGMSG <target>{,<target>}
|
||||
func tagmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
clientOnlyTags := msg.ClientOnlyTags()
|
||||
// no client-only tags, so we can drop it
|
||||
if clientOnlyTags == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
targets := strings.Split(msg.Params[0], ",")
|
||||
|
||||
cnick := client.Nick()
|
||||
message := utils.MakeSplitMessage("", true) // assign consistent message ID
|
||||
for i, targetString := range targets {
|
||||
// max of four targets per privmsg
|
||||
if i > maxTargets-1 {
|
||||
break
|
||||
}
|
||||
prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
|
||||
lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
|
||||
|
||||
// eh, no need to notify them
|
||||
if len(targetString) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
target, err := CasefoldChannel(targetString)
|
||||
if err == nil {
|
||||
channel := server.channels.Get(target)
|
||||
if channel == nil {
|
||||
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, cnick, targetString, client.t("No such channel"))
|
||||
continue
|
||||
}
|
||||
if !channel.CanSpeak(client) {
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
continue
|
||||
}
|
||||
channel.SendSplitMessage("TAGMSG", lowestPrefix, clientOnlyTags, client, message, rb)
|
||||
} else {
|
||||
target, err = CasefoldName(targetString)
|
||||
user := server.clients.Get(target)
|
||||
if err != nil || user == nil {
|
||||
if len(target) > 0 {
|
||||
client.Send(nil, server.name, ERR_NOSUCHNICK, cnick, target, client.t("No such nick"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// end user can't receive tagmsgs
|
||||
if !user.capabilities.Has(caps.MessageTags) {
|
||||
continue
|
||||
}
|
||||
unick := user.Nick()
|
||||
user.SendSplitMsgFromClient(client, clientOnlyTags, "TAGMSG", unick, message)
|
||||
if client.capabilities.Has(caps.EchoMessage) {
|
||||
rb.AddSplitMessageFromClient(client.NickMaskString(), client.AccountName(), clientOnlyTags, "TAGMSG", unick, message)
|
||||
}
|
||||
if user.HasMode(modes.Away) {
|
||||
//TODO(dan): possibly implement cooldown of away notifications to users
|
||||
rb.Add(nil, server.name, RPL_AWAY, cnick, unick, user.AwayMessage())
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TIME
|
||||
func timeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
rb.Add(nil, server.name, RPL_TIME, client.nick, server.name, time.Now().Format(time.RFC1123))
|
||||
@ -2502,7 +2389,7 @@ func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
||||
// USER <username> * 0 <realname>
|
||||
func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||
if client.registered {
|
||||
rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
|
||||
rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.Nick(), client.t("You may not reregister"))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -2513,7 +2400,7 @@ func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
if client.preregNick == msg.Params[0] {
|
||||
client.SetNames("user", msg.Params[3], false)
|
||||
} else {
|
||||
rb.Add(nil, server.name, ERR_INVALIDUSERNAME, client.t("Malformed username"))
|
||||
rb.Add(nil, server.name, ERR_INVALIDUSERNAME, client.Nick(), client.t("Malformed username"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -2631,7 +2518,7 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
||||
if len(msg.Params) > 0 {
|
||||
casefoldedMask, err := Casefold(msg.Params[0])
|
||||
if err != nil {
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, "WHO", client.t("Mask isn't valid"))
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "WHO", client.t("Mask isn't valid"))
|
||||
return false
|
||||
}
|
||||
mask = casefoldedMask
|
||||
|
@ -150,7 +150,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
||||
if !hasPrivs(change) {
|
||||
if !alreadySentPrivError {
|
||||
alreadySentPrivError = true
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.name, client.t("You're not a channel operator"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -226,7 +226,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
||||
|
||||
nick := change.Arg
|
||||
if nick == "" {
|
||||
rb.Add(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
|
||||
rb.Add(nil, client.server.name, ERR_NEEDMOREPARAMS, client.Nick(), "MODE", client.t("Not enough parameters"))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -26,14 +26,15 @@ var (
|
||||
func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
|
||||
nickname := strings.TrimSpace(newnick)
|
||||
cfnick, err := CasefoldName(nickname)
|
||||
currentNick := client.Nick()
|
||||
|
||||
if len(nickname) < 1 {
|
||||
rb.Add(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, client.t("No nickname given"))
|
||||
rb.Add(nil, server.name, ERR_NONICKNAMEGIVEN, currentNick, client.t("No nickname given"))
|
||||
return false
|
||||
}
|
||||
|
||||
if err != nil || len(nickname) > server.Limits().NickLen || restrictedNicknames[cfnick] {
|
||||
rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nickname, client.t("Erroneous nickname"))
|
||||
rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, currentNick, nickname, client.t("Erroneous nickname"))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -46,13 +47,13 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
|
||||
whowas := client.WhoWas()
|
||||
err = client.server.clients.SetNick(target, nickname)
|
||||
if err == errNicknameInUse {
|
||||
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
|
||||
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, currentNick, nickname, client.t("Nickname is already in use"))
|
||||
return false
|
||||
} else if err == errNicknameReserved {
|
||||
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, 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"))
|
||||
return false
|
||||
} else if err != nil {
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "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()))
|
||||
return false
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user