|
@@ -11,6 +11,8 @@ import (
|
11
|
11
|
"strconv"
|
12
|
12
|
"time"
|
13
|
13
|
|
|
14
|
+ "sync"
|
|
15
|
+
|
14
|
16
|
"github.com/DanielOaks/girc-go/ircmsg"
|
15
|
17
|
)
|
16
|
18
|
|
|
@@ -18,6 +20,7 @@ type Channel struct {
|
18
|
20
|
flags ChannelModeSet
|
19
|
21
|
lists map[ChannelMode]*UserMaskSet
|
20
|
22
|
key string
|
|
23
|
+ membersMutex sync.RWMutex
|
21
|
24
|
members MemberSet
|
22
|
25
|
name string
|
23
|
26
|
nameCasefolded string
|
|
@@ -63,6 +66,8 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel {
|
63
|
66
|
}
|
64
|
67
|
|
65
|
68
|
func (channel *Channel) IsEmpty() bool {
|
|
69
|
+ channel.membersMutex.RLock()
|
|
70
|
+ defer channel.membersMutex.RUnlock()
|
66
|
71
|
return len(channel.members) == 0
|
67
|
72
|
}
|
68
|
73
|
|
|
@@ -93,6 +98,9 @@ func (channel *Channel) Names(client *Client) {
|
93
|
98
|
|
94
|
99
|
// ClientIsAtLeast returns whether the client has at least the given channel privilege.
|
95
|
100
|
func (channel *Channel) ClientIsAtLeast(client *Client, permission ChannelMode) bool {
|
|
101
|
+ channel.membersMutex.RLock()
|
|
102
|
+ defer channel.membersMutex.RUnlock()
|
|
103
|
+
|
96
|
104
|
// get voice, since it's not a part of ChannelPrivModes
|
97
|
105
|
if channel.members.HasMode(client, permission) {
|
98
|
106
|
return true
|
|
@@ -134,6 +142,9 @@ func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string {
|
134
|
142
|
}
|
135
|
143
|
|
136
|
144
|
func (channel *Channel) Nicks(target *Client) []string {
|
|
145
|
+ channel.membersMutex.RLock()
|
|
146
|
+ defer channel.membersMutex.RUnlock()
|
|
147
|
+
|
137
|
148
|
isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
|
138
|
149
|
isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
|
139
|
150
|
nicks := make([]string, len(channel.members))
|
|
@@ -160,7 +171,9 @@ func (channel *Channel) Nick() string {
|
160
|
171
|
|
161
|
172
|
// <mode> <mode params>
|
162
|
173
|
func (channel *Channel) ModeString(client *Client) (str string) {
|
|
174
|
+ channel.membersMutex.RLock()
|
163
|
175
|
isMember := client.flags[Operator] || channel.members.Has(client)
|
|
176
|
+ channel.membersMutex.RUnlock()
|
164
|
177
|
showKey := isMember && (channel.key != "")
|
165
|
178
|
showUserLimit := channel.userLimit > 0
|
166
|
179
|
|
|
@@ -192,6 +205,9 @@ func (channel *Channel) ModeString(client *Client) (str string) {
|
192
|
205
|
}
|
193
|
206
|
|
194
|
207
|
func (channel *Channel) IsFull() bool {
|
|
208
|
+ channel.membersMutex.RLock()
|
|
209
|
+ defer channel.membersMutex.RUnlock()
|
|
210
|
+
|
195
|
211
|
return (channel.userLimit > 0) &&
|
196
|
212
|
(uint64(len(channel.members)) >= channel.userLimit)
|
197
|
213
|
}
|
|
@@ -201,6 +217,9 @@ func (channel *Channel) CheckKey(key string) bool {
|
201
|
217
|
}
|
202
|
218
|
|
203
|
219
|
func (channel *Channel) Join(client *Client, key string) {
|
|
220
|
+ channel.membersMutex.Lock()
|
|
221
|
+ defer channel.membersMutex.Unlock()
|
|
222
|
+
|
204
|
223
|
if channel.members.Has(client) {
|
205
|
224
|
// already joined, no message?
|
206
|
225
|
return
|
|
@@ -256,6 +275,9 @@ func (channel *Channel) Join(client *Client, key string) {
|
256
|
275
|
}
|
257
|
276
|
|
258
|
277
|
func (channel *Channel) Part(client *Client, message string) {
|
|
278
|
+ channel.membersMutex.RLock()
|
|
279
|
+ defer channel.membersMutex.RUnlock()
|
|
280
|
+
|
259
|
281
|
if !channel.members.Has(client) {
|
260
|
282
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
261
|
283
|
return
|
|
@@ -268,6 +290,9 @@ func (channel *Channel) Part(client *Client, message string) {
|
268
|
290
|
}
|
269
|
291
|
|
270
|
292
|
func (channel *Channel) GetTopic(client *Client) {
|
|
293
|
+ channel.membersMutex.RLock()
|
|
294
|
+ defer channel.membersMutex.RUnlock()
|
|
295
|
+
|
271
|
296
|
if !channel.members.Has(client) {
|
272
|
297
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
|
273
|
298
|
return
|
|
@@ -283,6 +308,9 @@ func (channel *Channel) GetTopic(client *Client) {
|
283
|
308
|
}
|
284
|
309
|
|
285
|
310
|
func (channel *Channel) SetTopic(client *Client, topic string) {
|
|
311
|
+ channel.membersMutex.RLock()
|
|
312
|
+ defer channel.membersMutex.RUnlock()
|
|
313
|
+
|
286
|
314
|
if !(client.flags[Operator] || channel.members.Has(client)) {
|
287
|
315
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
288
|
316
|
return
|
|
@@ -307,6 +335,9 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
|
307
|
335
|
}
|
308
|
336
|
|
309
|
337
|
func (channel *Channel) CanSpeak(client *Client) bool {
|
|
338
|
+ channel.membersMutex.RLock()
|
|
339
|
+ defer channel.membersMutex.RUnlock()
|
|
340
|
+
|
310
|
341
|
if client.flags[Operator] {
|
311
|
342
|
return true
|
312
|
343
|
}
|
|
@@ -335,6 +366,10 @@ func (channel *Channel) sendMessage(cmd string, minPrefix *ChannelMode, clientOn
|
335
|
366
|
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
|
336
|
367
|
return
|
337
|
368
|
}
|
|
369
|
+
|
|
370
|
+ channel.membersMutex.RLock()
|
|
371
|
+ defer channel.membersMutex.RUnlock()
|
|
372
|
+
|
338
|
373
|
// for STATUSMSG
|
339
|
374
|
var minPrefixMode ChannelMode
|
340
|
375
|
if minPrefix != nil {
|
|
@@ -383,6 +418,9 @@ func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
|
383
|
418
|
|
384
|
419
|
func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
|
385
|
420
|
op ModeOp, nick string) *ChannelModeChange {
|
|
421
|
+ channel.membersMutex.Lock()
|
|
422
|
+ defer channel.membersMutex.Unlock()
|
|
423
|
+
|
386
|
424
|
if nick == "" {
|
387
|
425
|
//TODO(dan): shouldn't this be handled before it reaches this function?
|
388
|
426
|
client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
|
|
@@ -466,6 +504,9 @@ func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeO
|
466
|
504
|
}
|
467
|
505
|
|
468
|
506
|
func (channel *Channel) Quit(client *Client) {
|
|
507
|
+ channel.membersMutex.Lock()
|
|
508
|
+ defer channel.membersMutex.Unlock()
|
|
509
|
+
|
469
|
510
|
channel.members.Remove(client)
|
470
|
511
|
client.channels.Remove(channel)
|
471
|
512
|
|
|
@@ -475,6 +516,9 @@ func (channel *Channel) Quit(client *Client) {
|
475
|
516
|
}
|
476
|
517
|
|
477
|
518
|
func (channel *Channel) Kick(client *Client, target *Client, comment string) {
|
|
519
|
+ channel.membersMutex.Lock()
|
|
520
|
+ defer channel.membersMutex.Unlock()
|
|
521
|
+
|
478
|
522
|
if !(client.flags[Operator] || channel.members.Has(client)) {
|
479
|
523
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
480
|
524
|
return
|
|
@@ -504,6 +548,9 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
|
504
|
548
|
return
|
505
|
549
|
}
|
506
|
550
|
|
|
551
|
+ channel.membersMutex.RLock()
|
|
552
|
+ defer channel.membersMutex.RUnlock()
|
|
553
|
+
|
507
|
554
|
if !channel.members.Has(inviter) {
|
508
|
555
|
inviter.Send(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
509
|
556
|
return
|