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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  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. if givenMode != 0 {
  396. rb.Add(nil, client.server.name, "MODE", chname, modestr, details.nick)
  397. }
  398. // TODO #259 can be implemented as Flush(false) (i.e., nonblocking) while holding joinPartMutex
  399. rb.Flush(true)
  400. replayLimit := channel.server.Config().History.AutoreplayOnJoin
  401. if replayLimit > 0 {
  402. items := channel.history.Latest(replayLimit)
  403. channel.replayHistoryItems(rb, items)
  404. rb.Flush(true)
  405. }
  406. }
  407. // Part parts the given client from this channel, with the given message.
  408. func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
  409. chname := channel.Name()
  410. if !channel.hasClient(client) {
  411. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, chname, client.t("You're not on that channel"))
  412. return
  413. }
  414. channel.Quit(client)
  415. details := client.Details()
  416. for _, member := range channel.Members() {
  417. member.Send(nil, details.nickMask, "PART", chname, message)
  418. }
  419. rb.Add(nil, details.nickMask, "PART", chname, message)
  420. channel.history.Add(history.Item{
  421. Type: history.Part,
  422. Nick: details.nickMask,
  423. AccountName: details.accountName,
  424. Message: utils.MakeSplitMessage(message, true),
  425. })
  426. client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
  427. }
  428. // Resume is called after a successful global resume to:
  429. // 1. Replace the old client with the new in the channel's data structures
  430. // 2. Send JOIN and MODE lines to channel participants (including the new client)
  431. // 3. Replay missed message history to the client
  432. func (channel *Channel) Resume(newClient, oldClient *Client, timestamp time.Time) {
  433. now := time.Now()
  434. channel.resumeAndAnnounce(newClient, oldClient)
  435. if !timestamp.IsZero() {
  436. channel.replayHistoryForResume(newClient, timestamp, now)
  437. }
  438. }
  439. func (channel *Channel) resumeAndAnnounce(newClient, oldClient *Client) {
  440. var oldModeSet *modes.ModeSet
  441. func() {
  442. channel.joinPartMutex.Lock()
  443. defer channel.joinPartMutex.Unlock()
  444. defer channel.regenerateMembersCache()
  445. channel.stateMutex.Lock()
  446. defer channel.stateMutex.Unlock()
  447. newClient.channels[channel] = true
  448. oldModeSet = channel.members[oldClient]
  449. if oldModeSet == nil {
  450. oldModeSet = modes.NewModeSet()
  451. }
  452. channel.members.Remove(oldClient)
  453. channel.members[newClient] = oldModeSet
  454. }()
  455. // construct fake modestring if necessary
  456. oldModes := oldModeSet.String()
  457. if 0 < len(oldModes) {
  458. oldModes = "+" + oldModes
  459. }
  460. // send join for old clients
  461. nick := newClient.Nick()
  462. nickMask := newClient.NickMaskString()
  463. accountName := newClient.AccountName()
  464. realName := newClient.Realname()
  465. for _, member := range channel.Members() {
  466. if member.capabilities.Has(caps.Resume) {
  467. continue
  468. }
  469. if member.capabilities.Has(caps.ExtendedJoin) {
  470. member.Send(nil, nickMask, "JOIN", channel.name, accountName, realName)
  471. } else {
  472. member.Send(nil, nickMask, "JOIN", channel.name)
  473. }
  474. if 0 < len(oldModes) {
  475. member.Send(nil, channel.server.name, "MODE", channel.name, oldModes, nick)
  476. }
  477. }
  478. rb := NewResponseBuffer(newClient)
  479. // use blocking i/o to synchronize with the later history replay
  480. if newClient.capabilities.Has(caps.ExtendedJoin) {
  481. rb.Add(nil, nickMask, "JOIN", channel.name, accountName, realName)
  482. } else {
  483. rb.Add(nil, nickMask, "JOIN", channel.name)
  484. }
  485. channel.SendTopic(newClient, rb)
  486. channel.Names(newClient, rb)
  487. if 0 < len(oldModes) {
  488. rb.Add(nil, newClient.server.name, "MODE", channel.name, oldModes, nick)
  489. }
  490. rb.Send(true)
  491. }
  492. func (channel *Channel) replayHistoryForResume(newClient *Client, after time.Time, before time.Time) {
  493. items, complete := channel.history.Between(after, before)
  494. rb := NewResponseBuffer(newClient)
  495. channel.replayHistoryItems(rb, items)
  496. if !complete && !newClient.resumeDetails.HistoryIncomplete {
  497. // warn here if we didn't warn already
  498. rb.Add(nil, "HistServ", "NOTICE", channel.Name(), newClient.t("Some additional message history may have been lost"))
  499. }
  500. rb.Send(true)
  501. }
  502. func stripMaskFromNick(nickMask string) (nick string) {
  503. index := strings.Index(nickMask, "!")
  504. if index == -1 {
  505. return
  506. }
  507. return nickMask[0:index]
  508. }
  509. func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item) {
  510. chname := channel.Name()
  511. client := rb.target
  512. serverTime := client.capabilities.Has(caps.ServerTime)
  513. for _, item := range items {
  514. var tags Tags
  515. if serverTime {
  516. tags = ensureTag(tags, "time", item.Time.Format(IRCv3TimestampFormat))
  517. }
  518. switch item.Type {
  519. case history.Privmsg:
  520. rb.AddSplitMessageFromClient(item.Msgid, item.Nick, item.AccountName, tags, "PRIVMSG", chname, item.Message)
  521. case history.Notice:
  522. rb.AddSplitMessageFromClient(item.Msgid, item.Nick, item.AccountName, tags, "NOTICE", chname, item.Message)
  523. case history.Join:
  524. nick := stripMaskFromNick(item.Nick)
  525. var message string
  526. if item.AccountName == "*" {
  527. message = fmt.Sprintf(client.t("%s joined the channel"), nick)
  528. } else {
  529. message = fmt.Sprintf(client.t("%s [account: %s] joined the channel"), nick, item.AccountName)
  530. }
  531. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  532. case history.Part:
  533. nick := stripMaskFromNick(item.Nick)
  534. message := fmt.Sprintf(client.t("%s left the channel (%s)"), nick, item.Message.Original)
  535. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  536. case history.Quit:
  537. nick := stripMaskFromNick(item.Nick)
  538. message := fmt.Sprintf(client.t("%s quit (%s)"), nick, item.Message.Original)
  539. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  540. case history.Kick:
  541. nick := stripMaskFromNick(item.Nick)
  542. // XXX Msgid is the kick target
  543. message := fmt.Sprintf(client.t("%s kicked %s (%s)"), nick, item.Msgid, item.Message.Original)
  544. rb.Add(tags, "HistServ", "PRIVMSG", chname, message)
  545. }
  546. }
  547. }
  548. // SendTopic sends the channel topic to the given client.
  549. func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer) {
  550. if !channel.hasClient(client) {
  551. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
  552. return
  553. }
  554. channel.stateMutex.RLock()
  555. name := channel.name
  556. topic := channel.topic
  557. topicSetBy := channel.topicSetBy
  558. topicSetTime := channel.topicSetTime
  559. channel.stateMutex.RUnlock()
  560. if topic == "" {
  561. rb.Add(nil, client.server.name, RPL_NOTOPIC, client.nick, name, client.t("No topic is set"))
  562. return
  563. }
  564. rb.Add(nil, client.server.name, RPL_TOPIC, client.nick, name, topic)
  565. rb.Add(nil, client.server.name, RPL_TOPICTIME, client.nick, name, topicSetBy, strconv.FormatInt(topicSetTime.Unix(), 10))
  566. }
  567. // SetTopic sets the topic of this channel, if the client is allowed to do so.
  568. func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) {
  569. if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
  570. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
  571. return
  572. }
  573. if channel.flags.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  574. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
  575. return
  576. }
  577. topicLimit := client.server.Limits().TopicLen
  578. if len(topic) > topicLimit {
  579. topic = topic[:topicLimit]
  580. }
  581. channel.stateMutex.Lock()
  582. channel.topic = topic
  583. channel.topicSetBy = client.nickMaskString
  584. channel.topicSetTime = time.Now()
  585. channel.stateMutex.Unlock()
  586. for _, member := range channel.Members() {
  587. if member == client {
  588. rb.Add(nil, client.nickMaskString, "TOPIC", channel.name, topic)
  589. } else {
  590. member.Send(nil, client.nickMaskString, "TOPIC", channel.name, topic)
  591. }
  592. }
  593. go channel.server.channelRegistry.StoreChannel(channel, IncludeTopic)
  594. }
  595. // CanSpeak returns true if the client can speak on this channel.
  596. func (channel *Channel) CanSpeak(client *Client) bool {
  597. channel.stateMutex.RLock()
  598. defer channel.stateMutex.RUnlock()
  599. _, hasClient := channel.members[client]
  600. if channel.flags.HasMode(modes.NoOutside) && !hasClient {
  601. return false
  602. }
  603. if channel.flags.HasMode(modes.Moderated) && !channel.ClientIsAtLeast(client, modes.Voice) {
  604. return false
  605. }
  606. if channel.flags.HasMode(modes.RegisteredOnly) && client.Account() == "" {
  607. return false
  608. }
  609. return true
  610. }
  611. // TagMsg sends a tag message to everyone in this channel who can accept them.
  612. func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, rb *ResponseBuffer) {
  613. channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil, rb)
  614. }
  615. // sendMessage sends a given message to everyone on this channel.
  616. func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string, rb *ResponseBuffer) {
  617. if !channel.CanSpeak(client) {
  618. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
  619. return
  620. }
  621. // for STATUSMSG
  622. var minPrefixMode modes.Mode
  623. if minPrefix != nil {
  624. minPrefixMode = *minPrefix
  625. }
  626. // send echo-message
  627. if client.capabilities.Has(caps.EchoMessage) {
  628. var messageTagsToUse *map[string]ircmsg.TagValue
  629. if client.capabilities.Has(caps.MessageTags) {
  630. messageTagsToUse = clientOnlyTags
  631. }
  632. nickMaskString := client.NickMaskString()
  633. accountName := client.AccountName()
  634. if message == nil {
  635. rb.AddFromClient(msgid, nickMaskString, accountName, messageTagsToUse, cmd, channel.name)
  636. } else {
  637. rb.AddFromClient(msgid, nickMaskString, accountName, messageTagsToUse, cmd, channel.name, *message)
  638. }
  639. }
  640. for _, member := range channel.Members() {
  641. if minPrefix != nil && !channel.ClientIsAtLeast(member, minPrefixMode) {
  642. // STATUSMSG
  643. continue
  644. }
  645. // echo-message is handled above, so skip sending the msg to the user themselves as well
  646. if member == client {
  647. continue
  648. }
  649. canReceive := true
  650. for _, capName := range requiredCaps {
  651. if !member.capabilities.Has(capName) {
  652. canReceive = false
  653. }
  654. }
  655. if !canReceive {
  656. continue
  657. }
  658. var messageTagsToUse *map[string]ircmsg.TagValue
  659. if member.capabilities.Has(caps.MessageTags) {
  660. messageTagsToUse = clientOnlyTags
  661. }
  662. if message == nil {
  663. member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
  664. } else {
  665. member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name, *message)
  666. }
  667. }
  668. }
  669. // SplitPrivMsg sends a private message to everyone in this channel.
  670. func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
  671. channel.sendSplitMessage(msgid, "PRIVMSG", history.Privmsg, minPrefix, clientOnlyTags, client, &message, rb)
  672. }
  673. // SplitNotice sends a private message to everyone in this channel.
  674. func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message utils.SplitMessage, rb *ResponseBuffer) {
  675. channel.sendSplitMessage(msgid, "NOTICE", history.Notice, minPrefix, clientOnlyTags, client, &message, rb)
  676. }
  677. 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) {
  678. if !channel.CanSpeak(client) {
  679. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
  680. return
  681. }
  682. // for STATUSMSG
  683. var minPrefixMode modes.Mode
  684. if minPrefix != nil {
  685. minPrefixMode = *minPrefix
  686. }
  687. // send echo-message
  688. if client.capabilities.Has(caps.EchoMessage) {
  689. var tagsToUse *map[string]ircmsg.TagValue
  690. if client.capabilities.Has(caps.MessageTags) {
  691. tagsToUse = clientOnlyTags
  692. }
  693. nickMaskString := client.NickMaskString()
  694. accountName := client.AccountName()
  695. if message == nil {
  696. rb.AddFromClient(msgid, nickMaskString, accountName, tagsToUse, cmd, channel.name)
  697. } else {
  698. rb.AddSplitMessageFromClient(msgid, nickMaskString, accountName, tagsToUse, cmd, channel.name, *message)
  699. }
  700. }
  701. nickmask := client.NickMaskString()
  702. account := client.AccountName()
  703. now := time.Now().UTC()
  704. for _, member := range channel.Members() {
  705. if minPrefix != nil && !channel.ClientIsAtLeast(member, minPrefixMode) {
  706. // STATUSMSG
  707. continue
  708. }
  709. // echo-message is handled above, so skip sending the msg to the user themselves as well
  710. if member == client {
  711. continue
  712. }
  713. var tagsToUse *map[string]ircmsg.TagValue
  714. if member.capabilities.Has(caps.MessageTags) {
  715. tagsToUse = clientOnlyTags
  716. }
  717. if message == nil {
  718. member.sendFromClientInternal(false, now, msgid, nickmask, account, tagsToUse, cmd, channel.name)
  719. } else {
  720. member.sendSplitMsgFromClientInternal(false, now, msgid, nickmask, account, tagsToUse, cmd, channel.name, *message)
  721. }
  722. }
  723. channel.history.Add(history.Item{
  724. Type: histType,
  725. Msgid: msgid,
  726. Message: *message,
  727. Nick: nickmask,
  728. AccountName: account,
  729. Time: now,
  730. })
  731. }
  732. func (channel *Channel) applyModeToMember(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) (result *modes.ModeChange) {
  733. casefoldedName, err := CasefoldName(nick)
  734. target := channel.server.clients.Get(casefoldedName)
  735. if err != nil || target == nil {
  736. rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nick, client.t("No such nick"))
  737. return nil
  738. }
  739. channel.stateMutex.Lock()
  740. modeset, exists := channel.members[target]
  741. if exists {
  742. if modeset.SetMode(mode, op == modes.Add) {
  743. result = &modes.ModeChange{
  744. Op: op,
  745. Mode: mode,
  746. Arg: nick,
  747. }
  748. }
  749. }
  750. channel.stateMutex.Unlock()
  751. if !exists {
  752. rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
  753. }
  754. return
  755. }
  756. // ShowMaskList shows the given list to the client.
  757. func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode, rb *ResponseBuffer) {
  758. // choose appropriate modes
  759. var rpllist, rplendoflist string
  760. if mode == modes.BanMask {
  761. rpllist = RPL_BANLIST
  762. rplendoflist = RPL_ENDOFBANLIST
  763. } else if mode == modes.ExceptMask {
  764. rpllist = RPL_EXCEPTLIST
  765. rplendoflist = RPL_ENDOFEXCEPTLIST
  766. } else if mode == modes.InviteMask {
  767. rpllist = RPL_INVITELIST
  768. rplendoflist = RPL_ENDOFINVITELIST
  769. }
  770. nick := client.Nick()
  771. channel.stateMutex.RLock()
  772. // XXX don't acquire any new locks in this section, besides Socket.Write
  773. for mask := range channel.lists[mode].masks {
  774. rb.Add(nil, client.server.name, rpllist, nick, channel.name, mask)
  775. }
  776. channel.stateMutex.RUnlock()
  777. rb.Add(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
  778. }
  779. func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string, rb *ResponseBuffer) bool {
  780. list := channel.lists[mode]
  781. if list == nil {
  782. // This should never happen, but better safe than panicky.
  783. return false
  784. }
  785. if (op == modes.List) || (mask == "") {
  786. channel.ShowMaskList(client, mode, rb)
  787. return false
  788. }
  789. if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  790. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
  791. return false
  792. }
  793. if op == modes.Add {
  794. return list.Add(mask)
  795. }
  796. if op == modes.Remove {
  797. return list.Remove(mask)
  798. }
  799. return false
  800. }
  801. // Quit removes the given client from the channel
  802. func (channel *Channel) Quit(client *Client) {
  803. channelEmpty := func() bool {
  804. channel.joinPartMutex.Lock()
  805. defer channel.joinPartMutex.Unlock()
  806. channel.stateMutex.Lock()
  807. channel.members.Remove(client)
  808. channelEmpty := len(channel.members) == 0
  809. channel.stateMutex.Unlock()
  810. channel.regenerateMembersCache()
  811. return channelEmpty
  812. }()
  813. if channelEmpty {
  814. client.server.channels.Cleanup(channel)
  815. }
  816. client.removeChannel(channel)
  817. }
  818. func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
  819. if !(client.HasMode(modes.Operator) || channel.hasClient(client)) {
  820. rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
  821. return
  822. }
  823. if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
  824. rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
  825. return
  826. }
  827. if !channel.hasClient(target) {
  828. rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
  829. return
  830. }
  831. if !channel.ClientHasPrivsOver(client, target) {
  832. rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You don't have enough channel privileges"))
  833. return
  834. }
  835. kicklimit := client.server.Limits().KickLen
  836. if len(comment) > kicklimit {
  837. comment = comment[:kicklimit]
  838. }
  839. clientMask := client.NickMaskString()
  840. targetNick := target.Nick()
  841. for _, member := range channel.Members() {
  842. member.Send(nil, clientMask, "KICK", channel.name, targetNick, comment)
  843. }
  844. channel.history.Add(history.Item{
  845. Type: history.Kick,
  846. Nick: clientMask,
  847. Message: utils.MakeSplitMessage(comment, true),
  848. AccountName: target.AccountName(),
  849. Msgid: targetNick, // XXX abuse this field
  850. })
  851. channel.Quit(target)
  852. }
  853. // Invite invites the given client to the channel, if the inviter can do so.
  854. func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
  855. chname := channel.Name()
  856. if channel.flags.HasMode(modes.InviteOnly) && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
  857. rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, chname, inviter.t("You're not a channel operator"))
  858. return
  859. }
  860. if !channel.hasClient(inviter) {
  861. rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, chname, inviter.t("You're not on that channel"))
  862. return
  863. }
  864. if channel.flags.HasMode(modes.InviteOnly) {
  865. invitee.Invite(channel.NameCasefolded())
  866. }
  867. for _, member := range channel.Members() {
  868. if member.capabilities.Has(caps.InviteNotify) && member != inviter && member != invitee && channel.ClientIsAtLeast(member, modes.Halfop) {
  869. member.Send(nil, inviter.NickMaskString(), "INVITE", invitee.Nick(), chname)
  870. }
  871. }
  872. rb.Add(nil, inviter.server.name, RPL_INVITING, inviter.Nick(), invitee.Nick(), chname)
  873. invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, chname)
  874. if invitee.HasMode(modes.Away) {
  875. rb.Add(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
  876. }
  877. }