2017-03-27 14:15:02 +02:00
|
|
|
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
|
2016-11-01 14:56:21 +01:00
|
|
|
// released under the MIT license
|
|
|
|
|
|
|
|
package irc
|
|
|
|
|
|
|
|
import (
|
2020-09-16 18:03:06 +02:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2016-11-01 14:56:21 +01:00
|
|
|
|
2020-03-19 22:09:52 +01:00
|
|
|
"github.com/oragono/oragono/irc/history"
|
2018-02-03 11:21:32 +01:00
|
|
|
"github.com/oragono/oragono/irc/modes"
|
2020-03-19 22:09:52 +01:00
|
|
|
"github.com/oragono/oragono/irc/utils"
|
2016-11-01 14:56:21 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2016-11-01 15:42:25 +01:00
|
|
|
npcNickMask = "*%s*!%s@npc.fakeuser.invalid"
|
2016-11-01 14:56:21 +01:00
|
|
|
sceneNickMask = "=Scene=!%s@npc.fakeuser.invalid"
|
|
|
|
)
|
|
|
|
|
2020-09-16 18:03:06 +02:00
|
|
|
func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isScene, isAction bool, messageParts []string, rb *ResponseBuffer) {
|
2020-03-19 22:09:52 +01:00
|
|
|
config := server.Config()
|
2020-09-16 17:32:52 +02:00
|
|
|
if !config.Roleplay.Enabled {
|
2020-03-19 22:09:52 +01:00
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Roleplaying has been disabled by the server administrators"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if config.Roleplay.RequireOper && !client.HasRoleCapabs("roleplay") {
|
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Insufficient privileges"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-16 18:03:06 +02:00
|
|
|
var sourceMask string
|
|
|
|
if isScene {
|
|
|
|
sourceMask = fmt.Sprintf(sceneNickMask, client.Nick())
|
|
|
|
} else {
|
|
|
|
cfSource, cfSourceErr := CasefoldName(source)
|
|
|
|
skelSource, skelErr := Skeleton(source)
|
|
|
|
if cfSourceErr != nil || skelErr != nil ||
|
|
|
|
restrictedCasefoldedNicks.Has(cfSource) || restrictedSkeletons.Has(skelSource) {
|
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Invalid roleplay name"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
sourceMask = fmt.Sprintf(npcNickMask, source, client.Nick())
|
|
|
|
}
|
|
|
|
|
2020-03-19 22:09:52 +01:00
|
|
|
// block attempts to send CTCP messages to Tor clients
|
|
|
|
if len(messageParts) > 0 && len(messageParts[0]) > 0 && messageParts[0][0] == '\x01' {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-16 18:03:06 +02:00
|
|
|
var buf strings.Builder
|
2016-11-01 14:56:21 +01:00
|
|
|
if isAction {
|
2020-03-19 22:09:52 +01:00
|
|
|
buf.WriteString("\x01ACTION ")
|
|
|
|
}
|
|
|
|
for i, part := range messageParts {
|
|
|
|
buf.WriteString(part)
|
|
|
|
if i != len(messageParts)-1 {
|
|
|
|
buf.WriteByte(' ')
|
2019-02-26 03:50:43 +01:00
|
|
|
}
|
2020-03-19 22:09:52 +01:00
|
|
|
}
|
|
|
|
if config.Roleplay.addSuffix {
|
|
|
|
buf.WriteString(" (")
|
|
|
|
buf.WriteString(client.Nick())
|
|
|
|
buf.WriteString(")")
|
2016-11-01 14:56:21 +01:00
|
|
|
}
|
|
|
|
|
2020-03-19 22:09:52 +01:00
|
|
|
splitMessage := utils.MakeMessage(buf.String())
|
|
|
|
|
2016-11-01 14:56:21 +01:00
|
|
|
target, cerr := CasefoldChannel(targetString)
|
|
|
|
if cerr == nil {
|
|
|
|
channel := server.channels.Get(target)
|
|
|
|
if channel == nil {
|
2018-02-05 15:21:08 +01:00
|
|
|
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, client.t("No such channel"))
|
2016-11-01 14:56:21 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-03-19 22:09:52 +01:00
|
|
|
targetString = channel.Name()
|
2016-11-01 14:56:21 +01:00
|
|
|
if !channel.CanSpeak(client) {
|
2020-03-19 22:09:52 +01:00
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, targetString, client.t("Cannot send to channel"))
|
2016-11-01 14:56:21 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-04-23 00:47:10 +02:00
|
|
|
if !channel.flags.HasMode(modes.ChanRoleplaying) {
|
2020-03-19 22:09:52 +01:00
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Channel doesn't have roleplaying mode available"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.Roleplay.RequireChanops && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Insufficient privileges"))
|
2016-11-01 15:42:25 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-10-23 01:50:16 +02:00
|
|
|
for _, member := range channel.Members() {
|
2019-04-12 06:08:46 +02:00
|
|
|
for _, session := range member.Sessions() {
|
2020-03-19 17:19:42 +01:00
|
|
|
// see discussion on #865: clients do not understand how to do local echo
|
|
|
|
// of roleplay commands, so send them a copy whether they have echo-message
|
|
|
|
// or not
|
|
|
|
if rb.session == session {
|
2020-09-16 18:03:06 +02:00
|
|
|
rb.AddSplitMessageFromClient(sourceMask, "", nil, "PRIVMSG", targetString, splitMessage)
|
2020-03-19 17:19:42 +01:00
|
|
|
} else {
|
2020-09-16 18:03:06 +02:00
|
|
|
session.sendSplitMsgFromClientInternal(false, sourceMask, "*", nil, "PRIVMSG", targetString, splitMessage)
|
2019-04-12 06:08:46 +02:00
|
|
|
}
|
2018-02-05 15:21:08 +01:00
|
|
|
}
|
2016-11-01 14:56:21 +01:00
|
|
|
}
|
2020-03-19 22:09:52 +01:00
|
|
|
|
|
|
|
channel.AddHistoryItem(history.Item{
|
|
|
|
Type: history.Privmsg,
|
|
|
|
Message: splitMessage,
|
2020-09-16 18:03:06 +02:00
|
|
|
Nick: sourceMask,
|
2020-05-12 18:05:40 +02:00
|
|
|
}, client.Account())
|
2016-11-01 14:56:21 +01:00
|
|
|
} else {
|
|
|
|
target, err := CasefoldName(targetString)
|
|
|
|
user := server.clients.Get(target)
|
|
|
|
if err != nil || user == nil {
|
2018-02-05 15:21:08 +01:00
|
|
|
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, target, client.t("No such nick"))
|
2016-11-01 14:56:21 +01:00
|
|
|
return
|
|
|
|
}
|
2016-11-01 15:42:25 +01:00
|
|
|
|
2018-04-23 00:47:10 +02:00
|
|
|
if !user.HasMode(modes.UserRoleplaying) {
|
2018-02-05 15:21:08 +01:00
|
|
|
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
|
2016-11-01 15:42:25 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-17 20:29:04 +01:00
|
|
|
cnick := client.Nick()
|
|
|
|
tnick := user.Nick()
|
2020-03-19 22:09:52 +01:00
|
|
|
for _, session := range user.Sessions() {
|
2020-09-16 18:03:06 +02:00
|
|
|
session.sendSplitMsgFromClientInternal(false, sourceMask, "*", nil, "PRIVMSG", tnick, splitMessage)
|
2016-11-01 14:56:21 +01:00
|
|
|
}
|
2020-07-17 07:55:13 +02:00
|
|
|
if away, awayMessage := user.Away(); away {
|
2016-11-01 14:56:21 +01:00
|
|
|
//TODO(dan): possibly implement cooldown of away notifications to users
|
2020-07-17 07:55:13 +02:00
|
|
|
rb.Add(nil, server.name, RPL_AWAY, cnick, tnick, awayMessage)
|
2016-11-01 14:56:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|