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.

modes.go 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package modes
  6. import (
  7. "strings"
  8. )
  9. var (
  10. // SupportedUserModes are the user modes that we actually support (modifying).
  11. SupportedUserModes = Modes{
  12. Away, Bot, Invisible, Operator, RegisteredOnly, ServerNotice, UserRoleplaying,
  13. }
  14. // SupportedChannelModes are the channel modes that we support.
  15. SupportedChannelModes = Modes{
  16. BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
  17. Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, Secret, UserLimit,
  18. }
  19. )
  20. // ModeOp is an operation performed with modes
  21. type ModeOp rune
  22. func (op ModeOp) String() string {
  23. return string(op)
  24. }
  25. const (
  26. // Add is used when adding the given key.
  27. Add ModeOp = '+'
  28. // List is used when listing modes (for instance, listing the current bans on a channel).
  29. List ModeOp = '='
  30. // Remove is used when taking away the given key.
  31. Remove ModeOp = '-'
  32. )
  33. // Mode represents a user/channel/server mode
  34. type Mode rune
  35. func (mode Mode) String() string {
  36. return string(mode)
  37. }
  38. // ModeChange is a single mode changing
  39. type ModeChange struct {
  40. Mode Mode
  41. Op ModeOp
  42. Arg string
  43. }
  44. func (change *ModeChange) String() (str string) {
  45. if (change.Op == Add) || (change.Op == Remove) {
  46. str = change.Op.String()
  47. }
  48. str += change.Mode.String()
  49. if change.Arg != "" {
  50. str += " " + change.Arg
  51. }
  52. return
  53. }
  54. // ModeChanges are a collection of 'ModeChange's
  55. type ModeChanges []ModeChange
  56. func (changes ModeChanges) String() string {
  57. if len(changes) == 0 {
  58. return ""
  59. }
  60. op := changes[0].Op
  61. str := changes[0].Op.String()
  62. for _, change := range changes {
  63. if change.Op != op {
  64. op = change.Op
  65. str += change.Op.String()
  66. }
  67. str += change.Mode.String()
  68. }
  69. for _, change := range changes {
  70. if change.Arg == "" {
  71. continue
  72. }
  73. str += " " + change.Arg
  74. }
  75. return str
  76. }
  77. // Modes is just a raw list of modes
  78. type Modes []Mode
  79. func (modes Modes) String() string {
  80. strs := make([]string, len(modes))
  81. for index, mode := range modes {
  82. strs[index] = mode.String()
  83. }
  84. return strings.Join(strs, "")
  85. }
  86. // User Modes
  87. const (
  88. Away Mode = 'a'
  89. Bot Mode = 'B'
  90. Invisible Mode = 'i'
  91. LocalOperator Mode = 'O'
  92. Operator Mode = 'o'
  93. Restricted Mode = 'r'
  94. RegisteredOnly Mode = 'R'
  95. ServerNotice Mode = 's'
  96. TLS Mode = 'Z'
  97. UserRoleplaying Mode = 'E'
  98. WallOps Mode = 'w'
  99. )
  100. // Channel Modes
  101. const (
  102. BanMask Mode = 'b' // arg
  103. ChanRoleplaying Mode = 'E' // flag
  104. ExceptMask Mode = 'e' // arg
  105. InviteMask Mode = 'I' // arg
  106. InviteOnly Mode = 'i' // flag
  107. Key Mode = 'k' // flag arg
  108. Moderated Mode = 'm' // flag
  109. NoOutside Mode = 'n' // flag
  110. OpOnlyTopic Mode = 't' // flag
  111. // RegisteredOnly mode is reused here from umode definition
  112. Secret Mode = 's' // flag
  113. UserLimit Mode = 'l' // flag arg
  114. )
  115. var (
  116. ChannelFounder Mode = 'q' // arg
  117. ChannelAdmin Mode = 'a' // arg
  118. ChannelOperator Mode = 'o' // arg
  119. Halfop Mode = 'h' // arg
  120. Voice Mode = 'v' // arg
  121. // ChannelPrivModes holds the list of modes that are privileged, ie founder/op/halfop, in order.
  122. // voice is not in this list because it cannot perform channel operator actions.
  123. ChannelPrivModes = Modes{
  124. ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
  125. }
  126. ChannelModePrefixes = map[Mode]string{
  127. ChannelFounder: "~",
  128. ChannelAdmin: "&",
  129. ChannelOperator: "@",
  130. Halfop: "%",
  131. Voice: "+",
  132. }
  133. )
  134. //
  135. // channel membership prefixes
  136. //
  137. // SplitChannelMembershipPrefixes takes a target and returns the prefixes on it, then the name.
  138. func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) {
  139. name = target
  140. for {
  141. if len(name) > 0 && strings.Contains("~&@%+", string(name[0])) {
  142. prefixes += string(name[0])
  143. name = name[1:]
  144. } else {
  145. break
  146. }
  147. }
  148. return prefixes, name
  149. }
  150. // GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes.
  151. func GetLowestChannelModePrefix(prefixes string) *Mode {
  152. var lowest *Mode
  153. if strings.Contains(prefixes, "+") {
  154. lowest = &Voice
  155. } else {
  156. for i, mode := range ChannelPrivModes {
  157. if strings.Contains(prefixes, ChannelModePrefixes[mode]) {
  158. lowest = &ChannelPrivModes[i]
  159. }
  160. }
  161. }
  162. return lowest
  163. }
  164. //
  165. // commands
  166. //
  167. // ParseUserModeChanges returns the valid changes, and the list of unknown chars.
  168. func ParseUserModeChanges(params ...string) (ModeChanges, map[rune]bool) {
  169. changes := make(ModeChanges, 0)
  170. unknown := make(map[rune]bool)
  171. op := List
  172. if 0 < len(params) {
  173. modeArg := params[0]
  174. skipArgs := 1
  175. for _, mode := range modeArg {
  176. if mode == '-' || mode == '+' {
  177. op = ModeOp(mode)
  178. continue
  179. }
  180. change := ModeChange{
  181. Mode: Mode(mode),
  182. Op: op,
  183. }
  184. // put arg into modechange if needed
  185. switch Mode(mode) {
  186. case ServerNotice:
  187. // always require arg
  188. if len(params) > skipArgs {
  189. change.Arg = params[skipArgs]
  190. skipArgs++
  191. } else {
  192. continue
  193. }
  194. }
  195. var isKnown bool
  196. for _, supportedMode := range SupportedUserModes {
  197. if rune(supportedMode) == mode {
  198. isKnown = true
  199. break
  200. }
  201. }
  202. if !isKnown {
  203. unknown[mode] = true
  204. continue
  205. }
  206. changes = append(changes, change)
  207. }
  208. }
  209. return changes, unknown
  210. }
  211. // ModeSet holds a set of modes.
  212. type ModeSet map[Mode]bool
  213. // String returns the modes in this set.
  214. func (set ModeSet) String() string {
  215. if len(set) == 0 {
  216. return ""
  217. }
  218. strs := make([]string, len(set))
  219. index := 0
  220. for mode := range set {
  221. strs[index] = mode.String()
  222. index++
  223. }
  224. return strings.Join(strs, "")
  225. }
  226. // Prefixes returns a list of prefixes for the given set of channel modes.
  227. func (set ModeSet) Prefixes(isMultiPrefix bool) string {
  228. var prefixes string
  229. // add prefixes in order from highest to lowest privs
  230. for _, mode := range ChannelPrivModes {
  231. if set[mode] {
  232. prefixes += ChannelModePrefixes[mode]
  233. }
  234. }
  235. if set[Voice] {
  236. prefixes += ChannelModePrefixes[Voice]
  237. }
  238. if !isMultiPrefix && len(prefixes) > 1 {
  239. prefixes = string(prefixes[0])
  240. }
  241. return prefixes
  242. }