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.

channel.go 31KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  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. "bytes"
  8. "fmt"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "sync"
  13. "github.com/goshuirc/irc-go/ircmsg"
  14. "github.com/oragono/oragono/irc/caps"
  15. "github.com/oragono/oragono/irc/history"
  16. "github.com/oragono/oragono/irc/modes"
  17. "github.com/oragono/oragono/irc/utils"
  18. )
  19. // Channel represents a channel that clients can join.
  20. type Channel struct {
  21. flags *modes.ModeSet
  22. lists map[modes.Mode]*UserMaskSet
  23. key string
  24. members MemberSet
  25. membersCache []*Client // allow iteration over channel members without holding the lock
  26. name string
  27. nameCasefolded string
  28. server *Server
  29. createdTime time.Time
  30. registeredFounder string
  31. registeredTime time.Time
  32. stateMutex sync.RWMutex // tier 1
  33. joinPartMutex sync.Mutex // tier 3
  34. topic string
  35. topicSetBy string
  36. topicSetTime time.Time
  37. userLimit int
  38. accountToUMode map[string]modes.Mode
  39. history history.Buffer
  40. }
  41. // NewChannel creates a new channel from a `Server` and a `name`
  42. // string, which must be unique on the server.
  43. func NewChannel(s *Server, name string, regInfo *RegisteredChannel) *Channel {
  44. casefoldedName, err := CasefoldChannel(name)
  45. if err != nil {
  46. s.logger.Error("internal", "Bad channel name", name, err.Error())
  47. return nil
  48. }
  49. channel := &Channel{
  50. createdTime: time.Now(), // may be overwritten by applyRegInfo
  51. flags: modes.NewModeSet(),
  52. lists: map[modes.Mode]*UserMaskSet{
  53. modes.BanMask: NewUserMaskSet(),
  54. modes.ExceptMask: NewUserMaskSet(),
  55. modes.InviteMask: NewUserMaskSet(),
  56. },
  57. members: make(MemberSet),
  58. name: name,
  59. nameCasefolded: casefoldedName,
  60. server: s,
  61. accountToUMode: make(map[string]modes.Mode),
  62. }
  63. config := s.Config()
  64. if regInfo != nil {
  65. channel.applyRegInfo(regInfo)
  66. } else {
  67. for _, mode := range config.Channels.defaultModes {
  68. channel.flags.SetMode(mode, true)
  69. }
  70. }
  71. channel.history.Initialize(config.History.ChannelLength)
  72. return channel
  73. }
  74. // read in channel state that was persisted in the DB
  75. func (channel *Channel) applyRegInfo(chanReg *RegisteredChannel) {
  76. channel.registeredFounder = chanReg.Founder
  77. channel.registeredTime = chanReg.RegisteredAt
  78. channel.topic = chanReg.Topic
  79. channel.topicSetBy = chanReg.TopicSetBy
  80. channel.topicSetTime = chanReg.TopicSetTime
  81. channel.name = chanReg.Name
  82. channel.createdTime = chanReg.RegisteredAt
  83. channel.key = chanReg.Key
  84. for _, mode := range chanReg.Modes {
  85. channel.flags.SetMode(mode, true)
  86. }
  87. for _, mask := range chanReg.Banlist {
  88. channel.lists[modes.BanMask].Add(mask)
  89. }
  90. for _, mask := range chanReg.Exceptlist {
  91. channel.lists[modes.ExceptMask].Add(mask)
  92. }
  93. for _, mask := range chanReg.Invitelist {
  94. channel.lists[modes.InviteMask].Add(mask)
  95. }
  96. for account, mode := range chanReg.AccountToUMode {
  97. channel.accountToUMode[account] = mode
  98. }
  99. }
  100. // obtain a consistent snapshot of the channel state that can be persisted to the DB
  101. func (channel *Channel) ExportRegistration(includeFlags uint) (info RegisteredChannel) {
  102. channel.stateMutex.RLock()
  103. defer channel.stateMutex.RUnlock()
  104. info.Name = channel.name
  105. info.Founder = channel.registeredFounder
  106. info.RegisteredAt = channel.registeredTime
  107. if includeFlags&IncludeTopic != 0 {
  108. info.Topic = channel.topic
  109. info.TopicSetBy = channel.topicSetBy
  110. info.TopicSetTime = channel.topicSetTime
  111. }
  112. if includeFlags&IncludeModes != 0 {
  113. info.Key = channel.key
  114. info.Modes = channel.flags.AllModes()
  115. }
  116. if includeFlags&IncludeLists != 0 {
  117. for mask := range channel.lists[modes.BanMask].masks {
  118. info.Banlist = append(info.Banlist, mask)
  119. }
  120. for mask := range channel.lists[modes.ExceptMask].masks {
  121. info.Exceptlist = append(info.Exceptlist, mask)
  122. }
  123. for mask := range channel.lists[modes.InviteMask].masks {
  124. info.Invitelist = append(info.Invitelist, mask)
  125. }
  126. info.AccountToUMode = make(map[string]modes.Mode)
  127. for account, mode := range channel.accountToUMode {
  128. info.AccountToUMode[account] = mode
  129. }
  130. }
  131. return
  132. }
  133. // SetRegistered registers the channel, returning an error if it was already registered.
  134. func (channel *Channel) SetRegistered(founder string) error {
  135. channel.stateMutex.Lock()
  136. defer channel.stateMutex.Unlock()
  137. if channel.registeredFounder != "" {
  138. return errChannelAlreadyRegistered
  139. }
  140. channel.registeredFounder = founder
  141. channel.registeredTime = time.Now()
  142. channel.accountToUMode[founder] = modes.ChannelFounder
  143. return nil
  144. }
  145. // SetUnregistered deletes the channel's registration information.
  146. func (channel *Channel) SetUnregistered() {
  147. channel.stateMutex.Lock()
  148. defer channel.stateMutex.Unlock()
  149. channel.registeredFounder = ""
  150. var zeroTime time.Time
  151. channel.registeredTime = zeroTime
  152. channel.accountToUMode = make(map[string]modes.Mode)
  153. }
  154. // IsRegistered returns whether the channel is registered.
  155. func (channel *Channel) IsRegistered() bool {
  156. channel.stateMutex.RLock()
  157. defer channel.stateMutex.RUnlock()
  158. return channel.registeredFounder != ""
  159. }
  160. func (channel *Channel) regenerateMembersCache() {
  161. channel.stateMutex.RLock()
  162. result := make([]*Client, len(channel.members))
  163. i := 0
  164. for client := range channel.members {
  165. result[i] = client
  166. i++
  167. }
  168. channel.stateMutex.RUnlock()
  169. channel.stateMutex.Lock()
  170. channel.membersCache = result
  171. channel.stateMutex.Unlock()
  172. }
  173. // Names sends the list of users joined to the channel to the given client.
  174. func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
  175. isMultiPrefix := client.capabilities.Has(caps.MultiPrefix)
  176. isUserhostInNames := client.capabilities.Has(caps.UserhostInNames)
  177. maxNamLen := 480 - len(client.server.name) - len(client.Nick())
  178. var namesLines []string
  179. var buffer bytes.Buffer
  180. for _, target := range channel.Members() {
  181. var nick string
  182. if isUserhostInNames {
  183. nick = target.NickMaskString()
  184. } else {
  185. nick = target.Nick()
  186. }
  187. channel.stateMutex.RLock()
  188. modes := channel.members[target]
  189. channel.stateMutex.RUnlock()
  190. if modes == nil {
  191. continue
  192. }
  193. prefix := modes.Prefixes(isMultiPrefix)
  194. if buffer.Len()+len(nick)+len(prefix)+1 > maxNamLen {
  195. namesLines = append(namesLines, buffer.String())
  196. buffer.Reset()
  197. }
  198. if buffer.Len() > 0 {
  199. buffer.WriteString(" ")
  200. }
  201. buffer.WriteString(prefix)
  202. buffer.WriteString(nick)
  203. }
  204. if buffer.Len() > 0 {
  205. namesLines = append(namesLines, buffer.String())
  206. }
  207. for _, line := range namesLines {
  208. if buffer.Len() > 0 {
  209. rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, line)
  210. }
  211. }
  212. rb.Add(nil, client.server.name, RPL_ENDOFNAMES, client.nick, channel.name, client.t("End of NAMES list"))
  213. }
  214. // ClientIsAtLeast returns whether the client has at least the given channel privilege.
  215. func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) bool {
  216. channel.stateMutex.RLock()
  217. clientModes := channel.members[client]
  218. channel.stateMutex.RUnlock()
  219. if clientModes == nil {
  220. return false
  221. }
  222. for _, mode := range modes.ChannelUserModes {
  223. if clientModes.HasMode(mode) {
  224. return true
  225. }
  226. if mode == permission {
  227. break
  228. }
  229. }
  230. return false
  231. }
  232. func (channel *Channel) ClientPrefixes(client *Client, isMultiPrefix bool) string {
  233. channel.stateMutex.RLock()
  234. defer channel.stateMutex.RUnlock()
  235. modes, present := channel.members[client]
  236. if !present {
  237. return ""
  238. } else {
  239. return modes.Prefixes(isMultiPrefix)
  240. }
  241. }
  242. func (channel *Channel) ClientHasPrivsOver(client *Client, target *Client) bool {
  243. channel.stateMutex.RLock()
  244. defer channel.stateMutex.RUnlock()
  245. clientModes := channel.members[client]
  246. targetModes := channel.members[target]
  247. result := false
  248. for _, mode := range modes.ChannelPrivModes {
  249. if clientModes.HasMode(mode) {
  250. result = true
  251. // admins cannot kick other admins
  252. if mode == modes.ChannelAdmin && targetModes.HasMode(modes.ChannelAdmin) {
  253. result = false
  254. }
  255. break
  256. } else if targetModes.HasMode(mode) {
  257. break
  258. }
  259. }
  260. return result
  261. }
  262. func (channel *Channel) hasClient(client *Client) bool {
  263. channel.stateMutex.RLock()
  264. defer channel.stateMutex.RUnlock()
  265. _, present := channel.members[client]
  266. return present
  267. }
  268. // <mode> <mode params>
  269. func (channel *Channel) modeStrings(client *Client) (result []string) {
  270. isMember := client.HasMode(modes.Operator) || channel.hasClient(client)
  271. showKey := isMember && (channel.key != "")
  272. showUserLimit := channel.userLimit > 0
  273. mods := "+"
  274. // flags with args
  275. if showKey {
  276. mods += modes.Key.String()
  277. }
  278. if showUserLimit {
  279. mods += modes.UserLimit.String()
  280. }
  281. mods += channel.flags.String()
  282. channel.stateMutex.RLock()
  283. defer channel.stateMutex.RUnlock()
  284. result = []string{mods}
  285. // args for flags with args: The order must match above to keep
  286. // positional arguments in place.
  287. if showKey {
  288. result = append(result, channel.key)
  289. }
  290. if showUserLimit {
  291. result = append(result, strconv.Itoa(channel.userLimit))
  292. }
  293. return
  294. }
  295. func (channel *Channel) IsEmpty() bool {
  296. channel.stateMutex.RLock()
  297. defer channel.stateMutex.RUnlock()
  298. return len(channel.members) == 0
  299. }
  300. // Join joins the given client to this channel (if they can be joined).
  301. func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *ResponseBuffer) {
  302. details := client.Details()
  303. channel.stateMutex.RLock()
  304. chname := channel.name
  305. chcfname := channel.nameCasefolded
  306. founder := channel.registeredFounder
  307. chkey := channel.key
  308. limit := channel.userLimit
  309. chcount := len(channel.members)
  310. _, alreadyJoined := channel.members[client]
  311. persistentMode := channel.accountToUMode[details.account]
  312. channel.stateMutex.RUnlock()
  313. if alreadyJoined {
  314. // no message needs to be sent
  315. return
  316. }
  317. // the founder can always join (even if they disabled auto +q on join);
  318. // anyone who automatically receives halfop or higher can always join
  319. hasPrivs := isSajoin || (founder != "" && founder == details.account) || (persistentMode != 0 && persistentMode != modes.Voice)
  320. if !hasPrivs && limit != 0 && chcount >= limit {
  321. rb.Add(nil, client.server.name, ERR_CHANNELISFULL, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
  322. return
  323. }
  324. if !hasPrivs && chkey != "" && !utils.SecretTokensMatch(chkey, key) {
  325. rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
  326. return
  327. }
  328. isInvited := client.CheckInvited(chcfname) || channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded)
  329. if !hasPrivs && channel.flags.HasMode(modes.InviteOnly) && !isInvited {
  330. rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
  331. return
  332. }
  333. if !hasPrivs && channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
  334. !isInvited &&
  335. !channel.lists[modes.ExceptMask].Match(details.nickMaskCasefolded) {
  336. rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
  337. return
  338. }
  339. client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", details.nick, chname))
  340. newChannel, givenMode := func() (newChannel bool, givenMode modes.Mode) {
  341. channel.joinPartMutex.Lock()
  342. defer channel.joinPartMutex.Unlock()
  343. func() {
  344. channel.stateMutex.Lock()
  345. defer channel.stateMutex.Unlock()
  346. channel.members.Add(client)
  347. firstJoin := len(channel.members) == 1
  348. newChannel = firstJoin && channel.registeredFounder == ""
  349. if newChannel {
  350. givenMode = modes.ChannelOperator
  351. } else {
  352. givenMode = persistentMode
  353. }
  354. if givenMode != 0 {
  355. channel.members[client].SetMode(givenMode, true)
  356. }
  357. }()
  358. channel.regenerateMembersCache()
  359. channel.history.Add(history.Item{
  360. Type: history.Join,
  361. Nick: details.nickMask,
  362. AccountName: details.accountName,
  363. Msgid: details.realname,
  364. })
  365. return
  366. }()
  367. client.addChannel(channel)
  368. var modestr string
  369. if givenMode != 0 {
  370. modestr = fmt.Sprintf("+%v", givenMode)
  371. }
  372. for _, member := range channel.Members() {
  373. if member == client {
  374. continue
  375. }
  376. if member.capabilities.Has(caps.ExtendedJoin) {
  377. member.Send(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
  378. } else {
  379. member.Send(nil, details.nickMask, "JOIN", chname)
  380. }
  381. if givenMode != 0 {
  382. member.Send(nil, client.server.name, "MODE", chname, modestr, details.nick)
  383. }
  384. }
  385. if client.capabilities.Has(caps.ExtendedJoin) {
  386. rb.Add(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
  387. } else {
  388. rb.Add(nil, details.nickMask, "JOIN", chname)
  389. }
  390. // don't send topic when it's an entirely new channel
  391. if !newChannel {
  392. channel.SendTopic(client, rb)
  393. }
  394. channel.Names(client, rb)
  395. // TODO #259 can be implemented as Flush(false) (i.e., nonblocking) while holding joinPartMutex
  396. rb.Flush(true)
  397. replayLimit := channel.server.Config().History.AutoreplayOnJoin
  398. if replayLimit > 0 {
  399. items := channel.history.Latest(replayLimit)
  400. channel.replayHistoryItems(rb, items)
  401. rb.Flush(true)
  402. }
  403. }
  404. // Part parts the given client from this channel, with the given message.
  405. func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
  406. chname := channel.Name()
  407. if !channel.hasClient(client) {
  408. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, chname, client.t("You're not on that channel"))
  409. return
  410. }
  411. channel.Quit(client)
  412. details := client.Details()
  413. for _, member := range channel.Members() {
  414. member.Send(nil, details.nickMask, "PART", chname, message)
  415. }
  416. rb.Add(nil, details.nickMask, "PART", chname, message)
  417. channel.history.Add(history.Item{
  418. Type: history.Part,
  419. Nick: details.nickMask,
  420. AccountName: details.accountName,
  421. Message: utils.MakeSplitMessage(message, true),
  422. })
  423. client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
  424. }
  425. // Resume is called after a successful global resume to:
  426. // 1. Replace the old client with the new in the channel's data structures
  427. // 2. Send JOIN and MODE lines to channel participants (including the new client)
  428. // 3. Replay missed message history to the client
  429. func (channel *Channel) Resume(newClient, oldClient *Client, timestamp time.Time) {
  430. now := time.Now()
  431. channel.resumeAndAnnounce(newClient, oldClient)
  432. if !timestamp.IsZero() {
  433. channel.replayHistoryForResume(newClient, timestamp, now)
  434. }
  435. }
  436. func (channel *Channel) resumeAndAnnounce(newClient, oldClient *Client) {
  437. var oldModeSet *modes.ModeSet
  438. func() {
  439. channel.joinPartMutex.Lock()
  440. defer channel.joinPartMutex.Unlock()
  441. defer channel.regenerateMembersCache()
  442. channel.stateMutex.Lock()
  443. defer channel.stateMutex.Unlock()
  444. newClient.channels[channel] = true
  445. oldModeSet = channel.members[oldClient]
  446. if oldModeSet == nil {
  447. oldModeSet = modes.NewModeSet()
  448. }
  449. channel.members.Remove(oldClient)
  450. channel.members[newClient] = oldModeSet
  451. }()
  452. // construct fake modestring if necessary
  453. oldModes := oldModeSet.String()
  454. if 0 < len(oldModes) {
  455. oldModes = "+" + oldModes
  456. }
  457. // send join for old clients
  458. nick := newClient.Nick()
  459. nickMask := newClient.NickMaskString()
  460. accountName := newClient.AccountName()
  461. realName := newClient.Realname()
  462. for _, member := range channel.Members() {
  463. if member.capabilities.Has(caps.Resume) {
  464. continue
  465. }
  466. if member.capabilities.Has(caps.ExtendedJoin) {
  467. member.Send(nil, nickMask, "JOIN", channel.name, accountName, realName)
  468. } else {
  469. member.Send(nil, nickMask, "JOIN", channel.name)
  470. }
  471. if 0 < len(oldModes) {
  472. member.Send(nil, channel.server.name, "MODE", channel.name, oldModes, nick)
  473. }
  474. }
  475. rb := NewResponseBuffer(newClient)
  476. // use blocking i/o to synchronize with the later history replay
  477. if newClient.capabilities.Has(caps.ExtendedJoin) {
  478. rb.Add(nil, nickMask, "JOIN", channel.name, accountName, realName)
  479. } else {
  480. rb.Add(nil, nickMask, "JOIN", channel.name)
  481. }
  482. channel.SendTopic(newClient, rb)
  483. channel.Names(newClient, rb)
  484. if 0 < len(oldModes) {
  485. rb.Add(nil, newClient.server.name, "MODE", channel.name, oldModes, nick)
  486. }
  487. rb.Send(true)
  488. }
  489. func (channel *Channel) replayHistoryForResume(newClient *Client, after time.Time, before time.Time) {
  490. items, complete := channel.history.Between(after, before, false, 0)
  491. rb := NewResponseBuffer(newClient)
  492. channel.replayHistoryItems(rb, items)
  493. if !complete && !newClient.resumeDetails.HistoryIncomplete {
  494. // warn here if we didn't warn already
  495. rb.Add(nil, "HistServ", "NOTICE", channel.Name(), newClient.t("Some additional message history may have been lost"))
  496. }
  497. rb.Send(true)
  498. }
  499. func stripMaskFromNick(nickMask string) (nick string) {
  500. index := strings.Index(nickMask, "!")
  501. if index == -1 {
  502. return
  503. }
  504. return nickMask[0:index]
  505. }
  506. func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item) {
  507. chname := channel.Name()
  508. client := rb.target
  509. serverTime := client.capabilities.Has(caps.ServerTime)
  510. for _, item := range items {
  511. var tags Tags
  512. if serverTime {
  513. tags = ensureTag(tags, "time", item.Time.Format(IRCv3TimestampFormat))
  514. }
  515. switch item.Type {
  516. case history.Privmsg:
  517. rb.AddSplitMessageFromClient(item.Msgid, item.Nick, item.AccountName, tags, "PRIVMSG", chname, item.Message)
  518. case history.Notice:
  519. rb.AddSplitMessageFromClient(item.Msgid, item.Nick, item.AccountName, tags, "NOTICE", chname, item.Message)
  520. case history.Join:
  521. nick := stripMaskFromNick(item.Nick)
  522. var message string
  523. if item.AccountName == "*" {
  524. message = fmt.Sprintf(client.t("%s joined the channel"), nick)
  525. } else {
  526. message = fmt.Sprintf(client.t("%s [account: %s] joined the channel"), nick, item.AccountName)
  527. }
  528. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  529. case history.Part:
  530. nick := stripMaskFromNick(item.Nick)
  531. message := fmt.Sprintf(client.t("%s left the channel (%s)"), nick, item.Message.Original)
  532. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  533. case history.Quit:
  534. nick := stripMaskFromNick(item.Nick)
  535. message := fmt.Sprintf(client.t("%s quit (%s)"), nick, item.Message.Original)
  536. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  537. case history.Kick:
  538. nick := stripMaskFromNick(item.Nick)
  539. // XXX Msgid is the kick target
  540. message := fmt.Sprintf(client.t("%s kicked %s (%s)"), nick, item.Msgid, item.Message.Original)
  541. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  542. }
  543. }
  544. }
  545. // SendTopic sends the channel topic to the given client.
  546. func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer) {
  547. if !channel.hasClient(client) {
  548. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
  549. return
  550. }
  551. channel.stateMutex.RLock()
  552. name := channel.name
  553. topic := channel.topic
  554. topicSetBy := channel.topicSetBy
  555. topicSetTime := channel.topicSetTime
  556. channel.stateMutex.RUnlock()
  557. if topic == "" {
  558. rb.Add(nil, client.server.name, RPL_NOTOPIC, client.nick, name, client.t("No topic is set"))
  559. return
  560. }
  561. rb.Add(nil, client.server.name, RPL_TOPIC, client.nick, name, topic)
  562. rb.Add(nil, client.server.name, RPL_TOPICTIME, client.nick, name, topicSetBy, strconv.FormatInt(topicSetTime.Unix(), 10))
  563. }
  564. // SetTopic sets the topic of this channel, if the client is allowed to do so.
  565. func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) {
  566. if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
  567. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
  568. return
  569. }
  570. if channel.flags.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  571. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
  572. return
  573. }
  574. topicLimit := client.server.Limits().TopicLen
  575. if len(topic) > topicLimit {
  576. topic = topic[:topicLimit]
  577. }
  578. channel.stateMutex.Lock()
  579. channel.topic = topic
  580. channel.topicSetBy = client.nickMaskString
  581. channel.topicSetTime = time.Now()
  582. channel.stateMutex.Unlock()
  583. for _, member := range channel.Members() {
  584. if member == client {
  585. rb.Add(nil, client.nickMaskString, "TOPIC", channel.name, topic)
  586. } else {
  587. member.Send(nil, client.nickMaskString, "TOPIC", channel.name, topic)
  588. }
  589. }
  590. go channel.server.channelRegistry.StoreChannel(channel, IncludeTopic)
  591. }
  592. // CanSpeak returns true if the client can speak on this channel.
  593. func (channel *Channel) CanSpeak(client *Client) bool {
  594. channel.stateMutex.RLock()
  595. defer channel.stateMutex.RUnlock()
  596. _, hasClient := channel.members[client]
  597. if channel.flags.HasMode(modes.NoOutside) && !hasClient {
  598. return false
  599. }
  600. if channel.flags.HasMode(modes.Moderated) && !channel.ClientIsAtLeast(client, modes.Voice) {
  601. return false
  602. }
  603. if channel.flags.HasMode(modes.RegisteredOnly) && client.Account() == "" {
  604. return false
  605. }
  606. return true
  607. }
  608. // TagMsg sends a tag message to everyone in this channel who can accept them.
  609. func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, rb *ResponseBuffer) {
  610. channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil, rb)
  611. }
  612. // sendMessage sends a given message to everyone on this channel.
  613. func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string, rb *ResponseBuffer) {
  614. if !channel.CanSpeak(client) {
  615. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
  616. return
  617. }
  618. // for STATUSMSG
  619. var minPrefixMode modes.Mode
  620. if minPrefix != nil {
  621. minPrefixMode = *minPrefix
  622. }
  623. // send echo-message
  624. if client.capabilities.Has(caps.EchoMessage) {
  625. var messageTagsToUse *map[string]ircmsg.TagValue
  626. if client.capabilities.Has(caps.MessageTags) {
  627. messageTagsToUse = clientOnlyTags
  628. }
  629. nickMaskString := client.NickMaskString()
  630. accountName := client.AccountName()
  631. if message == nil {
  632. rb.AddFromClient(msgid, nickMaskString, accountName, messageTagsToUse, cmd, channel.name)
  633. } else {
  634. rb.AddFromClient(msgid, nickMaskString, accountName, messageTagsToUse, cmd, channel.name, *message)
  635. }
  636. }
  637. for _, member := range channel.Members() {
  638. if minPrefix != nil && !channel.ClientIsAtLeast(member, minPrefixMode) {
  639. // STATUSMSG
  640. continue
  641. }
  642. // echo-message is handled above, so skip sending the msg to the user themselves as well
  643. if member == client {
  644. continue
  645. }
  646. canReceive := true
  647. for _, capName := range requiredCaps {
  648. if !member.capabilities.Has(capName) {
  649. canReceive = false
  650. }
  651. }
  652. if !canReceive {
  653. continue
  654. }
  655. var messageTagsToUse *map[string]ircmsg.TagValue
  656. if member.capabilities.Has(caps.MessageTags) {
  657. messageTagsToUse = clientOnlyTags
  658. }
  659. if message == nil {
  660. member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
  661. } else {
  662. member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name, *message)
  663. }
  664. }
  665. }
  666. // SplitPrivMsg sends a private message to everyone in this channel.
  667. func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
  668. channel.sendSplitMessage(msgid, "PRIVMSG", history.Privmsg, minPrefix, clientOnlyTags, client, &message, rb)
  669. }
  670. // SplitNotice sends a private message to everyone in this channel.
  671. func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
  672. channel.sendSplitMessage(msgid, "NOTICE", history.Notice, minPrefix, clientOnlyTags, client, &message, rb)
  673. }
  674. func (channel *Channel) sendSplitMessage(msgid, cmd string, histType history.ItemType, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *utils.SplitMessage, rb *ResponseBuffer) {
  675. if !channel.CanSpeak(client) {
  676. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
  677. return
  678. }
  679. // for STATUSMSG
  680. var minPrefixMode modes.Mode
  681. if minPrefix != nil {
  682. minPrefixMode = *minPrefix
  683. }
  684. // send echo-message
  685. if client.capabilities.Has(caps.EchoMessage) {
  686. var tagsToUse *map[string]ircmsg.TagValue
  687. if client.capabilities.Has(caps.MessageTags) {
  688. tagsToUse = clientOnlyTags
  689. }
  690. nickMaskString := client.NickMaskString()
  691. accountName := client.AccountName()
  692. if message == nil {
  693. rb.AddFromClient(msgid, nickMaskString, accountName, tagsToUse, cmd, channel.name)
  694. } else {
  695. rb.AddSplitMessageFromClient(msgid, nickMaskString, accountName, tagsToUse, cmd, channel.name, *message)
  696. }
  697. }
  698. nickmask := client.NickMaskString()
  699. account := client.AccountName()
  700. now := time.Now().UTC()
  701. for _, member := range channel.Members() {
  702. if minPrefix != nil && !channel.ClientIsAtLeast(member, minPrefixMode) {
  703. // STATUSMSG
  704. continue
  705. }
  706. // echo-message is handled above, so skip sending the msg to the user themselves as well
  707. if member == client {
  708. continue
  709. }
  710. var tagsToUse *map[string]ircmsg.TagValue
  711. if member.capabilities.Has(caps.MessageTags) {
  712. tagsToUse = clientOnlyTags
  713. }
  714. if message == nil {
  715. member.sendFromClientInternal(false, now, msgid, nickmask, account, tagsToUse, cmd, channel.name)
  716. } else {
  717. member.sendSplitMsgFromClientInternal(false, now, msgid, nickmask, account, tagsToUse, cmd, channel.name, *message)
  718. }
  719. }
  720. channel.history.Add(history.Item{
  721. Type: histType,
  722. Msgid: msgid,
  723. Message: *message,
  724. Nick: nickmask,
  725. AccountName: account,
  726. Time: now,
  727. })
  728. }
  729. func (channel *Channel) applyModeToMember(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) (result *modes.ModeChange) {
  730. casefoldedName, err := CasefoldName(nick)
  731. target := channel.server.clients.Get(casefoldedName)
  732. if err != nil || target == nil {
  733. rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nick, client.t("No such nick"))
  734. return nil
  735. }
  736. channel.stateMutex.Lock()
  737. modeset, exists := channel.members[target]
  738. if exists {
  739. if modeset.SetMode(mode, op == modes.Add) {
  740. result = &modes.ModeChange{
  741. Op: op,
  742. Mode: mode,
  743. Arg: nick,
  744. }
  745. }
  746. }
  747. channel.stateMutex.Unlock()
  748. if !exists {
  749. rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
  750. }
  751. return
  752. }
  753. // ShowMaskList shows the given list to the client.
  754. func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode, rb *ResponseBuffer) {
  755. // choose appropriate modes
  756. var rpllist, rplendoflist string
  757. if mode == modes.BanMask {
  758. rpllist = RPL_BANLIST
  759. rplendoflist = RPL_ENDOFBANLIST
  760. } else if mode == modes.ExceptMask {
  761. rpllist = RPL_EXCEPTLIST
  762. rplendoflist = RPL_ENDOFEXCEPTLIST
  763. } else if mode == modes.InviteMask {
  764. rpllist = RPL_INVITELIST
  765. rplendoflist = RPL_ENDOFINVITELIST
  766. }
  767. nick := client.Nick()
  768. channel.stateMutex.RLock()
  769. // XXX don't acquire any new locks in this section, besides Socket.Write
  770. for mask := range channel.lists[mode].masks {
  771. rb.Add(nil, client.server.name, rpllist, nick, channel.name, mask)
  772. }
  773. channel.stateMutex.RUnlock()
  774. rb.Add(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
  775. }
  776. func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string, rb *ResponseBuffer) bool {
  777. list := channel.lists[mode]
  778. if list == nil {
  779. // This should never happen, but better safe than panicky.
  780. return false
  781. }
  782. if (op == modes.List) || (mask == "") {
  783. channel.ShowMaskList(client, mode, rb)
  784. return false
  785. }
  786. if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  787. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
  788. return false
  789. }
  790. if op == modes.Add {
  791. return list.Add(mask)
  792. }
  793. if op == modes.Remove {
  794. return list.Remove(mask)
  795. }
  796. return false
  797. }
  798. // Quit removes the given client from the channel
  799. func (channel *Channel) Quit(client *Client) {
  800. channelEmpty := func() bool {
  801. channel.joinPartMutex.Lock()
  802. defer channel.joinPartMutex.Unlock()
  803. channel.stateMutex.Lock()
  804. channel.members.Remove(client)
  805. channelEmpty := len(channel.members) == 0
  806. channel.stateMutex.Unlock()
  807. channel.regenerateMembersCache()
  808. return channelEmpty
  809. }()
  810. if channelEmpty {
  811. client.server.channels.Cleanup(channel)
  812. }
  813. client.removeChannel(channel)
  814. }
  815. func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
  816. if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
  817. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
  818. return
  819. }
  820. if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  821. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
  822. return
  823. }
  824. if !channel.hasClient(target) {
  825. rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
  826. return
  827. }
  828. if !channel.ClientHasPrivsOver(client, target) {
  829. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You don't have enough channel privileges"))
  830. return
  831. }
  832. kicklimit := client.server.Limits().KickLen
  833. if len(comment) > kicklimit {
  834. comment = comment[:kicklimit]
  835. }
  836. clientMask := client.NickMaskString()
  837. targetNick := target.Nick()
  838. for _, member := range channel.Members() {
  839. member.Send(nil, clientMask, "KICK", channel.name, targetNick, comment)
  840. }
  841. channel.history.Add(history.Item{
  842. Type: history.Kick,
  843. Nick: clientMask,
  844. Message: utils.MakeSplitMessage(comment, true),
  845. AccountName: target.AccountName(),
  846. Msgid: targetNick, // XXX abuse this field
  847. })
  848. channel.Quit(target)
  849. }
  850. // Invite invites the given client to the channel, if the inviter can do so.
  851. func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
  852. chname := channel.Name()
  853. if channel.flags.HasMode(modes.InviteOnly) && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
  854. rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, chname, inviter.t("You're not a channel operator"))
  855. return
  856. }
  857. if !channel.hasClient(inviter) {
  858. rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, chname, inviter.t("You're not on that channel"))
  859. return
  860. }
  861. if channel.flags.HasMode(modes.InviteOnly) {
  862. invitee.Invite(channel.NameCasefolded())
  863. }
  864. for _, member := range channel.Members() {
  865. if member.capabilities.Has(caps.InviteNotify) && member != inviter && member != invitee && channel.ClientIsAtLeast(member, modes.Halfop) {
  866. member.Send(nil, inviter.NickMaskString(), "INVITE", invitee.Nick(), chname)
  867. }
  868. }
  869. rb.Add(nil, inviter.server.name, RPL_INVITING, inviter.Nick(), invitee.Nick(), chname)
  870. invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, chname)
  871. if invitee.HasMode(modes.Away) {
  872. rb.Add(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
  873. }
  874. }