mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-23 03:02:48 +01:00
parent
29db70fa7b
commit
18a8b075ea
@ -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)
|
hasPrivs := isSajoin || (founder != "" && founder == details.account) || (persistentMode != 0 && persistentMode != modes.Voice)
|
||||||
|
|
||||||
if !hasPrivs && limit != 0 && chcount >= limit {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasPrivs && chkey != "" && !utils.SecretTokensMatch(chkey, key) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded)
|
isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded)
|
||||||
if !hasPrivs && channel.flags.HasMode(modes.InviteOnly) && !isInvited {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasPrivs && channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
|
if !hasPrivs && channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
|
||||||
!isInvited &&
|
!isInvited &&
|
||||||
!channel.lists[modes.ExceptMask].Match(details.nickMaskCasefolded) {
|
!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
|
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) {
|
func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
|
||||||
chname := channel.Name()
|
chname := channel.Name()
|
||||||
if !channel.hasClient(client) {
|
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
|
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
|
// `sendNoTopic` controls whether RPL_NOTOPIC is sent when the topic is unset
|
||||||
func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer, sendNoTopic bool) {
|
func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer, sendNoTopic bool) {
|
||||||
if !channel.hasClient(client) {
|
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
|
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.
|
// 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) {
|
func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) {
|
||||||
if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.flags.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,22 +719,30 @@ func (channel *Channel) CanSpeak(client *Client) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) SendSplitMessage(command string, minPrefix *modes.Mode, clientOnlyTags map[string]string, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
|
func msgCommandToHistType(server *Server, command string) (history.ItemType, error) {
|
||||||
var histType history.ItemType
|
|
||||||
switch command {
|
switch command {
|
||||||
case "PRIVMSG":
|
case "PRIVMSG":
|
||||||
histType = history.Privmsg
|
return history.Privmsg, nil
|
||||||
case "NOTICE":
|
case "NOTICE":
|
||||||
histType = history.Notice
|
return history.Notice, nil
|
||||||
case "TAGMSG":
|
case "TAGMSG":
|
||||||
histType = history.Tagmsg
|
return history.Tagmsg, nil
|
||||||
default:
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !channel.CanSpeak(client) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,7 +759,7 @@ func (channel *Channel) SendSplitMessage(command string, minPrefix *modes.Mode,
|
|||||||
}
|
}
|
||||||
nickMaskString := client.NickMaskString()
|
nickMaskString := client.NickMaskString()
|
||||||
accountName := client.AccountName()
|
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)
|
rb.AddFromClient(message.Msgid, nickMaskString, accountName, tagsToUse, command, channel.name)
|
||||||
} else {
|
} else {
|
||||||
rb.AddSplitMessageFromClient(nickMaskString, accountName, tagsToUse, command, channel.name, message)
|
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
|
var tagsToUse map[string]string
|
||||||
if member.capabilities.Has(caps.MessageTags) {
|
if member.capabilities.Has(caps.MessageTags) {
|
||||||
tagsToUse = clientOnlyTags
|
tagsToUse = clientOnlyTags
|
||||||
} else if command == "TAGMSG" {
|
} else if histType == history.Tagmsg {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if command == "TAGMSG" {
|
if histType == history.Tagmsg {
|
||||||
member.sendFromClientInternal(false, now, message.Msgid, nickmask, account, tagsToUse, command, channel.name)
|
member.sendFromClientInternal(false, now, message.Msgid, nickmask, account, tagsToUse, command, channel.name)
|
||||||
} else {
|
} else {
|
||||||
member.sendSplitMsgFromClientInternal(false, now, nickmask, account, tagsToUse, command, channel.name, message)
|
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) {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,15 +906,15 @@ func (channel *Channel) Quit(client *Client) {
|
|||||||
|
|
||||||
func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
|
func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
|
||||||
if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
|
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
|
return
|
||||||
}
|
}
|
||||||
if !channel.hasClient(target) {
|
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
|
return
|
||||||
}
|
}
|
||||||
if !channel.ClientHasPrivsOver(client, target) {
|
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
|
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) {
|
func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
|
||||||
chname := channel.Name()
|
chname := channel.Name()
|
||||||
if channel.flags.HasMode(modes.InviteOnly) && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !channel.hasClient(inviter) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ func (client *Client) run() {
|
|||||||
if err == ircmsg.ErrorLineIsEmpty {
|
if err == ircmsg.ErrorLineIsEmpty {
|
||||||
continue
|
continue
|
||||||
} else if err == ircmsg.ErrorLineTooLong {
|
} 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
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
client.Quit(client.t("Received malformed line"))
|
client.Quit(client.t("Received malformed line"))
|
||||||
@ -335,9 +335,9 @@ func (client *Client) run() {
|
|||||||
cmd, exists := Commands[msg.Command]
|
cmd, exists := Commands[msg.Command]
|
||||||
if !exists {
|
if !exists {
|
||||||
if len(msg.Command) > 0 {
|
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 {
|
} 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
|
continue
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ 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, msg ircmsg.IrcMessage) bool {
|
func (cmd *Command) Run(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
if !client.registered && !cmd.usablePreReg {
|
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
|
return false
|
||||||
}
|
}
|
||||||
if cmd.oper && !client.HasMode(modes.Operator) {
|
if cmd.oper && !client.HasMode(modes.Operator) {
|
||||||
@ -184,7 +184,7 @@ func init() {
|
|||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
"NOTICE": {
|
"NOTICE": {
|
||||||
handler: noticeHandler,
|
handler: messageHandler,
|
||||||
minParams: 2,
|
minParams: 2,
|
||||||
},
|
},
|
||||||
"NPC": {
|
"NPC": {
|
||||||
@ -221,7 +221,7 @@ func init() {
|
|||||||
leaveClientIdle: true,
|
leaveClientIdle: true,
|
||||||
},
|
},
|
||||||
"PRIVMSG": {
|
"PRIVMSG": {
|
||||||
handler: privmsgHandler,
|
handler: messageHandler,
|
||||||
minParams: 2,
|
minParams: 2,
|
||||||
},
|
},
|
||||||
"RENAME": {
|
"RENAME": {
|
||||||
@ -257,7 +257,7 @@ func init() {
|
|||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
"TAGMSG": {
|
"TAGMSG": {
|
||||||
handler: tagmsgHandler,
|
handler: messageHandler,
|
||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
"QUIT": {
|
"QUIT": {
|
||||||
|
250
irc/handlers.go
250
irc/handlers.go
@ -242,7 +242,7 @@ func accVerifyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
sendSuccessfulRegResponse(client, rb, false)
|
sendSuccessfulRegResponse(client, rb, false)
|
||||||
} else {
|
} 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
|
return false
|
||||||
@ -1873,17 +1873,38 @@ func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTICE <target>{,<target>} <message>
|
// NOTICE <target>{,<target>} <message>
|
||||||
func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
cnick := client.Nick()
|
||||||
clientOnlyTags := msg.ClientOnlyTags()
|
clientOnlyTags := msg.ClientOnlyTags()
|
||||||
|
if histType == history.Tagmsg && len(clientOnlyTags) == 0 {
|
||||||
|
// nothing to do
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
targets := strings.Split(msg.Params[0], ",")
|
targets := strings.Split(msg.Params[0], ",")
|
||||||
message := msg.Params[1]
|
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 client.isTor && isRestrictedCTCPMessage(message) {
|
||||||
|
if histType != history.Notice {
|
||||||
rb.Add(nil, server.name, "NOTICE", client.t("CTCP messages are disabled over Tor"))
|
rb.Add(nil, server.name, "NOTICE", client.t("CTCP messages are disabled over Tor"))
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
splitMsg := utils.MakeSplitMessage(message, !client.capabilities.Has(caps.MaxLine))
|
splitMsg := utils.MakeSplitMessage(message, !client.capabilities.Has(caps.MaxLine))
|
||||||
|
now := time.Now().UTC()
|
||||||
|
|
||||||
for i, targetString := range targets {
|
for i, targetString := range targets {
|
||||||
// max of four targets per privmsg
|
// max of four targets per privmsg
|
||||||
@ -1893,52 +1914,66 @@ func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
|||||||
prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
|
prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
|
||||||
lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
|
lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
|
||||||
|
|
||||||
target, cerr := CasefoldChannel(targetString)
|
if len(targetString) == 0 {
|
||||||
if cerr == nil {
|
continue
|
||||||
channel := server.channels.Get(target)
|
} else if targetString[0] == '#' {
|
||||||
|
channel := server.channels.Get(targetString)
|
||||||
if channel == nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
if !channel.CanSpeak(client) {
|
channel.SendSplitMessage(msg.Command, lowestPrefix, clientOnlyTags, client, splitMsg, rb)
|
||||||
// errors silently ignored with NOTICE as per RFC
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
channel.SendSplitMessage("NOTICE", lowestPrefix, clientOnlyTags, client, splitMsg, rb)
|
|
||||||
} else {
|
} else {
|
||||||
target, err := CasefoldName(targetString)
|
if service, isService := OragonoServices[strings.ToLower(targetString)]; isService {
|
||||||
if err != nil {
|
// NOTICE and TAGMSG to services are ignored
|
||||||
|
if histType == history.Privmsg {
|
||||||
|
servicePrivmsgHandler(service, server, client, message, rb)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTICEs sent to services are ignored
|
user := server.clients.Get(targetString)
|
||||||
if _, isService := OragonoServices[target]; isService {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
user := server.clients.Get(target)
|
|
||||||
if user == nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
if !user.capabilities.Has(caps.MessageTags) {
|
tnick := user.Nick()
|
||||||
clientOnlyTags = nil
|
|
||||||
|
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
|
// restrict messages appropriately when +R is set
|
||||||
// intentionally make the sending user think the message went through fine
|
// intentionally make the sending user think the message went through fine
|
||||||
allowedPlusR := !user.HasMode(modes.RegisteredOnly) || client.LoggedIntoAccount()
|
allowedPlusR := !user.HasMode(modes.RegisteredOnly) || client.LoggedIntoAccount()
|
||||||
allowedTor := !user.isTor || !isRestrictedCTCPMessage(message)
|
allowedTor := !user.isTor || !isRestrictedCTCPMessage(message)
|
||||||
if allowedPlusR && allowedTor {
|
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) {
|
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{
|
user.history.Add(history.Item{
|
||||||
Type: history.Notice,
|
Type: histType,
|
||||||
Message: splitMsg,
|
Message: splitMsg,
|
||||||
Nick: nickMaskString,
|
Nick: nickMaskString,
|
||||||
AccountName: accountName,
|
AccountName: accountName,
|
||||||
@ -1988,7 +2023,7 @@ func npcaHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
// OPER <name> <password>
|
// OPER <name> <password>
|
||||||
func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
if client.HasMode(modes.Operator) == true {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1999,7 +2034,7 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
authorized = (bcrypt.CompareHashAndPassword(oper.Pass, password) == nil)
|
authorized = (bcrypt.CompareHashAndPassword(oper.Pass, password) == nil)
|
||||||
}
|
}
|
||||||
if !authorized {
|
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"))
|
client.Quit(client.t("Password incorrect"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -2090,90 +2125,6 @@ func isRestrictedCTCPMessage(message string) bool {
|
|||||||
return strings.HasPrefix(message, "\x01") && !strings.HasPrefix(message, "\x01ACTION")
|
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>]
|
// QUIT [<reason>]
|
||||||
func quitHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func quitHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
reason := "Quit"
|
reason := "Quit"
|
||||||
@ -2346,71 +2297,6 @@ func setnameHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
|||||||
return false
|
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
|
// TIME
|
||||||
func timeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
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))
|
rb.Add(nil, server.name, RPL_TIME, client.nick, server.name, time.Now().Format(time.RFC1123))
|
||||||
@ -2502,7 +2388,7 @@ func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
|
|||||||
// USER <username> * 0 <realname>
|
// USER <username> * 0 <realname>
|
||||||
func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
if client.registered {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2513,7 +2399,7 @@ func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
if client.preregNick == msg.Params[0] {
|
if client.preregNick == msg.Params[0] {
|
||||||
client.SetNames("user", msg.Params[3], false)
|
client.SetNames("user", msg.Params[3], false)
|
||||||
} else {
|
} 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 +2517,7 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
if len(msg.Params) > 0 {
|
if len(msg.Params) > 0 {
|
||||||
casefoldedMask, err := Casefold(msg.Params[0])
|
casefoldedMask, err := Casefold(msg.Params[0])
|
||||||
if err != nil {
|
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
|
return false
|
||||||
}
|
}
|
||||||
mask = casefoldedMask
|
mask = casefoldedMask
|
||||||
|
@ -150,7 +150,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
|||||||
if !hasPrivs(change) {
|
if !hasPrivs(change) {
|
||||||
if !alreadySentPrivError {
|
if !alreadySentPrivError {
|
||||||
alreadySentPrivError = true
|
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
|
continue
|
||||||
}
|
}
|
||||||
@ -226,7 +226,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
|||||||
|
|
||||||
nick := change.Arg
|
nick := change.Arg
|
||||||
if nick == "" {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,14 +26,15 @@ var (
|
|||||||
func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
|
func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
|
||||||
nickname := strings.TrimSpace(newnick)
|
nickname := strings.TrimSpace(newnick)
|
||||||
cfnick, err := CasefoldName(nickname)
|
cfnick, err := CasefoldName(nickname)
|
||||||
|
currentNick := client.Nick()
|
||||||
|
|
||||||
if len(nickname) < 1 {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil || len(nickname) > server.Limits().NickLen || restrictedNicknames[cfnick] {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,13 +47,13 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
|
|||||||
whowas := client.WhoWas()
|
whowas := client.WhoWas()
|
||||||
err = client.server.clients.SetNick(target, nickname)
|
err = client.server.clients.SetNick(target, nickname)
|
||||||
if err == errNicknameInUse {
|
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
|
return false
|
||||||
} else if err == errNicknameReserved {
|
} 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
|
return false
|
||||||
} else if err != nil {
|
} 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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user