You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

roleplay.go 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "fmt"
  6. "strings"
  7. "github.com/ergochat/ergo/irc/history"
  8. "github.com/ergochat/ergo/irc/modes"
  9. "github.com/ergochat/ergo/irc/utils"
  10. )
  11. const (
  12. npcNickMask = "*%s*!%s@npc.fakeuser.invalid"
  13. sceneNickMask = "=Scene=!%s@npc.fakeuser.invalid"
  14. )
  15. func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isScene, isAction bool, messageParts []string, rb *ResponseBuffer) {
  16. config := server.Config()
  17. if !config.Roleplay.Enabled {
  18. rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Roleplaying has been disabled by the server administrators"))
  19. return
  20. }
  21. if config.Roleplay.RequireOper && !client.HasRoleCapabs("roleplay") {
  22. rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Insufficient privileges"))
  23. return
  24. }
  25. var sourceMask string
  26. if isScene {
  27. sourceMask = fmt.Sprintf(sceneNickMask, client.Nick())
  28. } else {
  29. cfSource, cfSourceErr := CasefoldName(source)
  30. skelSource, skelErr := Skeleton(source)
  31. if cfSourceErr != nil || skelErr != nil ||
  32. restrictedCasefoldedNicks.Has(cfSource) || restrictedSkeletons.Has(skelSource) {
  33. rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Invalid roleplay name"))
  34. return
  35. }
  36. sourceMask = fmt.Sprintf(npcNickMask, source, client.Nick())
  37. }
  38. // block attempts to send CTCP messages to Tor clients
  39. if len(messageParts) > 0 && len(messageParts[0]) > 0 && messageParts[0][0] == '\x01' {
  40. return
  41. }
  42. var buf strings.Builder
  43. if isAction {
  44. buf.WriteString("\x01ACTION ")
  45. }
  46. for i, part := range messageParts {
  47. buf.WriteString(part)
  48. if i != len(messageParts)-1 {
  49. buf.WriteByte(' ')
  50. }
  51. }
  52. if config.Roleplay.addSuffix {
  53. buf.WriteString(" (")
  54. buf.WriteString(client.Nick())
  55. buf.WriteString(")")
  56. }
  57. if isAction {
  58. buf.WriteString("\x01")
  59. }
  60. splitMessage := utils.MakeMessage(buf.String())
  61. target, cerr := CasefoldChannel(targetString)
  62. if cerr == nil {
  63. channel := server.channels.Get(target)
  64. if channel == nil {
  65. rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, client.t("No such channel"))
  66. return
  67. }
  68. targetString = channel.Name()
  69. if canSpeak, mode := channel.CanSpeak(client); !canSpeak {
  70. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, targetString, fmt.Sprintf(client.t("Cannot send to channel (+%s)"), mode))
  71. return
  72. }
  73. if !channel.flags.HasMode(modes.ChanRoleplaying) {
  74. rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Channel doesn't have roleplaying mode available"))
  75. return
  76. }
  77. if config.Roleplay.RequireChanops && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  78. rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Insufficient privileges"))
  79. return
  80. }
  81. isBot := client.HasMode(modes.Bot)
  82. for _, member := range channel.Members() {
  83. for _, session := range member.Sessions() {
  84. // see discussion on #865: clients do not understand how to do local echo
  85. // of roleplay commands, so send them a copy whether they have echo-message
  86. // or not
  87. if rb.session == session {
  88. rb.AddSplitMessageFromClient(sourceMask, "*", isBot, nil, "PRIVMSG", targetString, splitMessage)
  89. } else {
  90. session.sendSplitMsgFromClientInternal(false, sourceMask, "*", isBot, nil, "PRIVMSG", targetString, splitMessage)
  91. }
  92. }
  93. }
  94. channel.AddHistoryItem(history.Item{
  95. Type: history.Privmsg,
  96. Message: splitMessage,
  97. Nick: sourceMask,
  98. }, client.Account())
  99. } else {
  100. target, err := CasefoldName(targetString)
  101. user := server.clients.Get(target)
  102. if err != nil || user == nil {
  103. rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, target, client.t("No such nick"))
  104. return
  105. }
  106. if !user.HasMode(modes.UserRoleplaying) {
  107. rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
  108. return
  109. }
  110. cnick := client.Nick()
  111. tnick := user.Nick()
  112. isBot := client.HasMode(modes.Bot)
  113. for _, session := range user.Sessions() {
  114. session.sendSplitMsgFromClientInternal(false, sourceMask, "*", isBot, nil, "PRIVMSG", tnick, splitMessage)
  115. }
  116. if away, awayMessage := user.Away(); away {
  117. //TODO(dan): possibly implement cooldown of away notifications to users
  118. rb.Add(nil, server.name, RPL_AWAY, cnick, tnick, awayMessage)
  119. }
  120. }
  121. }