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 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 irc
  6. import (
  7. "strconv"
  8. "strings"
  9. "github.com/oragono/oragono/irc/modes"
  10. "github.com/oragono/oragono/irc/sno"
  11. )
  12. var (
  13. // DefaultChannelModes are enabled on brand new channels when they're created.
  14. // this can be overridden in the `channels` config, with the `default-modes` key
  15. DefaultChannelModes = modes.Modes{
  16. modes.NoOutside, modes.OpOnlyTopic,
  17. }
  18. )
  19. // applyUserModeChanges applies the given changes, and returns the applied changes.
  20. func (client *Client) applyUserModeChanges(force bool, changes modes.ModeChanges) modes.ModeChanges {
  21. applied := make(modes.ModeChanges, 0)
  22. for _, change := range changes {
  23. switch change.Mode {
  24. case modes.Bot, modes.Invisible, modes.WallOps, modes.UserRoleplaying, modes.Operator, modes.LocalOperator, modes.RegisteredOnly:
  25. switch change.Op {
  26. case modes.Add:
  27. if change.Mode == modes.Operator || change.Mode == modes.LocalOperator {
  28. client.server.stats.ChangeOperators(1)
  29. }
  30. if !force && (change.Mode == modes.Operator || change.Mode == modes.LocalOperator) {
  31. continue
  32. }
  33. if client.flags[change.Mode] {
  34. continue
  35. }
  36. if change.Mode == modes.Invisible {
  37. client.server.stats.ChangeInvisible(1)
  38. }
  39. client.flags[change.Mode] = true
  40. applied = append(applied, change)
  41. case modes.Remove:
  42. if !client.flags[change.Mode] {
  43. continue
  44. }
  45. if change.Mode == modes.Invisible {
  46. client.server.stats.ChangeInvisible(-1)
  47. }
  48. if change.Mode == modes.Operator || change.Mode == modes.LocalOperator {
  49. client.server.stats.ChangeOperators(-1)
  50. }
  51. delete(client.flags, change.Mode)
  52. applied = append(applied, change)
  53. }
  54. case modes.ServerNotice:
  55. if !client.flags[modes.Operator] {
  56. continue
  57. }
  58. var masks []sno.Mask
  59. if change.Op == modes.Add || change.Op == modes.Remove {
  60. var newArg string
  61. for _, char := range change.Arg {
  62. mask := sno.Mask(char)
  63. if sno.ValidMasks[mask] {
  64. masks = append(masks, mask)
  65. newArg += string(char)
  66. }
  67. }
  68. change.Arg = newArg
  69. }
  70. if change.Op == modes.Add {
  71. client.server.snomasks.AddMasks(client, masks...)
  72. applied = append(applied, change)
  73. } else if change.Op == modes.Remove {
  74. client.server.snomasks.RemoveMasks(client, masks...)
  75. applied = append(applied, change)
  76. }
  77. }
  78. // can't do anything to TLS mode
  79. }
  80. // return the changes we could actually apply
  81. return applied
  82. }
  83. // ParseDefaultChannelModes parses the `default-modes` line of the config
  84. func ParseDefaultChannelModes(config *Config) modes.Modes {
  85. if config.Channels.DefaultModes == nil {
  86. // not present in config, fall back to compile-time default
  87. return DefaultChannelModes
  88. }
  89. modeChangeStrings := strings.Split(strings.TrimSpace(*config.Channels.DefaultModes), " ")
  90. modeChanges, _ := ParseChannelModeChanges(modeChangeStrings...)
  91. defaultChannelModes := make(modes.Modes, 0)
  92. for _, modeChange := range modeChanges {
  93. if modeChange.Op == modes.Add {
  94. defaultChannelModes = append(defaultChannelModes, modeChange.Mode)
  95. }
  96. }
  97. return defaultChannelModes
  98. }
  99. // ParseChannelModeChanges returns the valid changes, and the list of unknown chars.
  100. func ParseChannelModeChanges(params ...string) (modes.ModeChanges, map[rune]bool) {
  101. changes := make(modes.ModeChanges, 0)
  102. unknown := make(map[rune]bool)
  103. op := modes.List
  104. if 0 < len(params) {
  105. modeArg := params[0]
  106. skipArgs := 1
  107. for _, mode := range modeArg {
  108. if mode == '-' || mode == '+' {
  109. op = modes.ModeOp(mode)
  110. continue
  111. }
  112. change := modes.ModeChange{
  113. Mode: modes.Mode(mode),
  114. Op: op,
  115. }
  116. // put arg into modechange if needed
  117. switch modes.Mode(mode) {
  118. case modes.BanMask, modes.ExceptMask, modes.InviteMask:
  119. if len(params) > skipArgs {
  120. change.Arg = params[skipArgs]
  121. skipArgs++
  122. } else {
  123. change.Op = modes.List
  124. }
  125. case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
  126. if len(params) > skipArgs {
  127. change.Arg = params[skipArgs]
  128. skipArgs++
  129. } else {
  130. continue
  131. }
  132. case modes.Key, modes.UserLimit:
  133. // don't require value when removing
  134. if change.Op == modes.Add {
  135. if len(params) > skipArgs {
  136. change.Arg = params[skipArgs]
  137. skipArgs++
  138. } else {
  139. continue
  140. }
  141. }
  142. }
  143. var isKnown bool
  144. for _, supportedMode := range modes.SupportedChannelModes {
  145. if rune(supportedMode) == mode {
  146. isKnown = true
  147. break
  148. }
  149. }
  150. for _, supportedMode := range modes.ChannelPrivModes {
  151. if rune(supportedMode) == mode {
  152. isKnown = true
  153. break
  154. }
  155. }
  156. if mode == rune(modes.Voice) {
  157. isKnown = true
  158. }
  159. if !isKnown {
  160. unknown[mode] = true
  161. continue
  162. }
  163. changes = append(changes, change)
  164. }
  165. }
  166. return changes, unknown
  167. }
  168. // ApplyChannelModeChanges applies a given set of mode changes.
  169. func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges, rb *ResponseBuffer) modes.ModeChanges {
  170. // so we only output one warning for each list type when full
  171. listFullWarned := make(map[modes.Mode]bool)
  172. clientIsOp := channel.ClientIsAtLeast(client, modes.ChannelOperator)
  173. var alreadySentPrivError bool
  174. applied := make(modes.ModeChanges, 0)
  175. isListOp := func(change modes.ModeChange) bool {
  176. return (change.Op == modes.List) || (change.Arg == "")
  177. }
  178. hasPrivs := func(change modes.ModeChange) bool {
  179. if isSamode {
  180. return true
  181. }
  182. switch change.Mode {
  183. case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
  184. // Admins can't give other people Admin or remove it from others
  185. if change.Mode == modes.ChannelAdmin {
  186. return false
  187. }
  188. if change.Op == modes.List {
  189. return true
  190. }
  191. cfarg, _ := CasefoldName(change.Arg)
  192. if change.Op == modes.Remove && cfarg == client.nickCasefolded {
  193. // "There is no restriction, however, on anyone `deopping' themselves"
  194. // <https://tools.ietf.org/html/rfc2812#section-3.1.5>
  195. return true
  196. }
  197. return channel.ClientIsAtLeast(client, change.Mode)
  198. case modes.BanMask:
  199. // #163: allow unprivileged users to list ban masks
  200. return clientIsOp || isListOp(change)
  201. default:
  202. return clientIsOp
  203. }
  204. }
  205. for _, change := range changes {
  206. if !hasPrivs(change) {
  207. if !alreadySentPrivError {
  208. alreadySentPrivError = true
  209. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
  210. }
  211. continue
  212. }
  213. switch change.Mode {
  214. case modes.BanMask, modes.ExceptMask, modes.InviteMask:
  215. if isListOp(change) {
  216. channel.ShowMaskList(client, change.Mode, rb)
  217. continue
  218. }
  219. // confirm mask looks valid
  220. mask, err := Casefold(change.Arg)
  221. if err != nil {
  222. continue
  223. }
  224. switch change.Op {
  225. case modes.Add:
  226. if channel.lists[change.Mode].Length() >= client.server.Limits().ChanListModes {
  227. if !listFullWarned[change.Mode] {
  228. rb.Add(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
  229. listFullWarned[change.Mode] = true
  230. }
  231. continue
  232. }
  233. channel.lists[change.Mode].Add(mask)
  234. applied = append(applied, change)
  235. case modes.Remove:
  236. channel.lists[change.Mode].Remove(mask)
  237. applied = append(applied, change)
  238. }
  239. case modes.UserLimit:
  240. switch change.Op {
  241. case modes.Add:
  242. val, err := strconv.ParseUint(change.Arg, 10, 64)
  243. if err == nil {
  244. channel.setUserLimit(val)
  245. applied = append(applied, change)
  246. }
  247. case modes.Remove:
  248. channel.setUserLimit(0)
  249. applied = append(applied, change)
  250. }
  251. case modes.Key:
  252. switch change.Op {
  253. case modes.Add:
  254. channel.setKey(change.Arg)
  255. case modes.Remove:
  256. channel.setKey("")
  257. }
  258. applied = append(applied, change)
  259. case modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.RegisteredOnly, modes.Secret, modes.ChanRoleplaying:
  260. if change.Op == modes.List {
  261. continue
  262. }
  263. already := channel.setMode(change.Mode, change.Op == modes.Add)
  264. if !already {
  265. applied = append(applied, change)
  266. }
  267. case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
  268. if change.Op == modes.List {
  269. continue
  270. }
  271. change := channel.applyModeMemberNoMutex(client, change.Mode, change.Op, change.Arg, rb)
  272. if change != nil {
  273. applied = append(applied, *change)
  274. }
  275. }
  276. }
  277. return applied
  278. }