Browse Source

mask lists (ban, except, invite)

tags/v0.1.0
Jeremy Latt 10 years ago
parent
commit
d4093e7f8b
4 changed files with 120 additions and 15 deletions
  1. 53
    13
      irc/channel.go
  2. 57
    0
      irc/client_lookup_set.go
  3. 10
    0
      irc/reply.go
  4. 0
    2
      irc/types.go

+ 53
- 13
irc/channel.go View File

8
 
8
 
9
 type Channel struct {
9
 type Channel struct {
10
 	flags     ChannelModeSet
10
 	flags     ChannelModeSet
11
-	lists     map[ChannelMode]UserMaskSet
11
+	lists     map[ChannelMode]*UserMaskSet
12
 	key       string
12
 	key       string
13
 	members   MemberSet
13
 	members   MemberSet
14
 	name      string
14
 	name      string
26
 func NewChannel(s *Server, name string) *Channel {
26
 func NewChannel(s *Server, name string) *Channel {
27
 	channel := &Channel{
27
 	channel := &Channel{
28
 		flags: make(ChannelModeSet),
28
 		flags: make(ChannelModeSet),
29
-		lists: map[ChannelMode]UserMaskSet{
30
-			BanMask:    make(UserMaskSet),
31
-			ExceptMask: make(UserMaskSet),
32
-			InviteMask: make(UserMaskSet),
29
+		lists: map[ChannelMode]*UserMaskSet{
30
+			BanMask:    NewUserMaskSet(),
31
+			ExceptMask: NewUserMaskSet(),
32
+			InviteMask: NewUserMaskSet(),
33
 		},
33
 		},
34
 		members: make(MemberSet),
34
 		members: make(MemberSet),
35
 		name:    strings.ToLower(name),
35
 		name:    strings.ToLower(name),
151
 		return
151
 		return
152
 	}
152
 	}
153
 
153
 
154
+	isInvited := channel.lists[InviteMask].Match(client.UserHost())
155
+	if channel.flags[InviteOnly] && !isInvited {
156
+		client.ErrInviteOnlyChan(channel)
157
+		return
158
+	}
159
+
160
+	if channel.lists[BanMask].Match(client.UserHost()) &&
161
+		!isInvited &&
162
+		!channel.lists[ExceptMask].Match(client.UserHost()) {
163
+		client.ErrBannedFromChan(channel)
164
+		return
165
+	}
166
+
154
 	client.channels.Add(channel)
167
 	client.channels.Add(channel)
155
 	channel.members.Add(client)
168
 	channel.members.Add(client)
156
 	if !channel.flags[Persistent] && (len(channel.members) == 1) {
169
 	if !channel.flags[Persistent] && (len(channel.members) == 1) {
213
 	}
226
 	}
214
 
227
 
215
 	if err := channel.Persist(); err != nil {
228
 	if err := channel.Persist(); err != nil {
216
-		log.Println(err)
229
+		log.Println("Channel.Persist:", channel, err)
217
 	}
230
 	}
218
 }
231
 }
219
 
232
 
310
 	return false
323
 	return false
311
 }
324
 }
312
 
325
 
326
+func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeOp, mask string) bool {
327
+	if !channel.ClientIsOperator(client) {
328
+		client.ErrChanOPrivIsNeeded(channel)
329
+		return false
330
+	}
331
+
332
+	list := channel.lists[mode]
333
+	if list == nil {
334
+		// This should never happen, but better safe than panicky.
335
+		return false
336
+	}
337
+
338
+	if op == Add {
339
+		list.Add(mask)
340
+	} else if op == Remove {
341
+		list.Remove(mask)
342
+	}
343
+
344
+	for lmask := range channel.lists[mode].masks {
345
+		client.RplMaskList(mode, channel, lmask)
346
+	}
347
+	client.RplEndOfMaskList(mode, channel)
348
+	return true
349
+}
350
+
313
 func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) bool {
351
 func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) bool {
314
 	switch change.mode {
352
 	switch change.mode {
315
 	case BanMask, ExceptMask, InviteMask:
353
 	case BanMask, ExceptMask, InviteMask:
316
-		// TODO add/remove
317
-
318
-		for mask := range channel.lists[change.mode] {
319
-			client.RplMaskList(change.mode, channel, mask)
320
-		}
321
-		client.RplEndOfMaskList(change.mode, channel)
354
+		return channel.applyModeMask(client, change.mode, change.op, change.arg)
322
 
355
 
323
 	case Moderated, NoOutside, OpOnlyTopic, Persistent, Private:
356
 	case Moderated, NoOutside, OpOnlyTopic, Persistent, Private:
324
 		return channel.applyModeFlag(client, change.mode, change.op)
357
 		return channel.applyModeFlag(client, change.mode, change.op)
390
 		}
423
 		}
391
 
424
 
392
 		if err := channel.Persist(); err != nil {
425
 		if err := channel.Persist(); err != nil {
393
-			log.Println(err)
426
+			log.Println("Channel.Persist:", channel, err)
394
 		}
427
 		}
395
 	}
428
 	}
396
 }
429
 }
464
 		return
497
 		return
465
 	}
498
 	}
466
 
499
 
500
+	if channel.flags[InviteOnly] {
501
+		channel.lists[InviteMask].Add(invitee.UserHost())
502
+		if err := channel.Persist(); err != nil {
503
+			log.Println("Channel.Persist:", channel, err)
504
+		}
505
+	}
506
+
467
 	inviter.RplInviting(invitee, channel.name)
507
 	inviter.RplInviting(invitee, channel.name)
468
 	invitee.Reply(RplInviteMsg(inviter, invitee, channel.name))
508
 	invitee.Reply(RplInviteMsg(inviter, invitee, channel.name))
469
 	if invitee.flags[Away] {
509
 	if invitee.flags[Away] {

+ 57
- 0
irc/client_lookup_set.go View File

178
 		}
178
 		}
179
 	}
179
 	}
180
 }
180
 }
181
+
182
+//
183
+// usermask to regexp
184
+//
185
+
186
+type UserMaskSet struct {
187
+	masks  map[string]bool
188
+	regexp *regexp.Regexp
189
+}
190
+
191
+func NewUserMaskSet() *UserMaskSet {
192
+	return &UserMaskSet{
193
+		masks: make(map[string]bool),
194
+	}
195
+}
196
+
197
+func (set *UserMaskSet) Add(mask string) {
198
+	set.masks[mask] = true
199
+	set.setRegexp()
200
+}
201
+
202
+func (set *UserMaskSet) Remove(mask string) {
203
+	delete(set.masks, mask)
204
+	set.setRegexp()
205
+}
206
+
207
+func (set *UserMaskSet) Match(userhost string) bool {
208
+	if set.regexp == nil {
209
+		return false
210
+	}
211
+	return set.regexp.MatchString(userhost)
212
+}
213
+
214
+func (set *UserMaskSet) setRegexp() {
215
+	if len(set.masks) == 0 {
216
+		set.regexp = nil
217
+		return
218
+	}
219
+
220
+	maskExprs := make([]string, len(set.masks))
221
+	index := 0
222
+	for mask := range set.masks {
223
+		manyParts := strings.Split(mask, "*")
224
+		manyExprs := make([]string, len(manyParts))
225
+		for mindex, manyPart := range manyParts {
226
+			oneParts := strings.Split(manyPart, "?")
227
+			oneExprs := make([]string, len(oneParts))
228
+			for oindex, onePart := range oneParts {
229
+				oneExprs[oindex] = regexp.QuoteMeta(onePart)
230
+			}
231
+			manyExprs[mindex] = strings.Join(oneExprs, ".")
232
+		}
233
+		maskExprs[index] = strings.Join(manyExprs, ".*")
234
+	}
235
+	expr := "^" + strings.Join(maskExprs, "|") + "$"
236
+	set.regexp, _ = regexp.Compile(expr)
237
+}

+ 10
- 0
irc/reply.go View File

541
 	target.NumericReply(ERR_INVALIDCAPCMD,
541
 	target.NumericReply(ERR_INVALIDCAPCMD,
542
 		"%s :Invalid CAP subcommand", subCommand)
542
 		"%s :Invalid CAP subcommand", subCommand)
543
 }
543
 }
544
+
545
+func (target *Client) ErrBannedFromChan(channel *Channel) {
546
+	target.NumericReply(ERR_BANNEDFROMCHAN,
547
+		"%s :Cannot join channel (+b)", channel)
548
+}
549
+
550
+func (target *Client) ErrInviteOnlyChan(channel *Channel) {
551
+	target.NumericReply(ERR_INVITEONLYCHAN,
552
+		"%s :Cannot join channel (+i)", channel)
553
+}

+ 0
- 2
irc/types.go View File

9
 // simple types
9
 // simple types
10
 //
10
 //
11
 
11
 
12
-type UserMaskSet map[string]bool
13
-
14
 type CapSubCommand string
12
 type CapSubCommand string
15
 
13
 
16
 type Capability string
14
 type Capability string

Loading…
Cancel
Save