Browse Source

modes: Continue overhauling

tags/v0.7.0
Daniel Oaks 7 years ago
parent
commit
05074e966d
5 changed files with 213 additions and 193 deletions
  1. 21
    21
      irc/channel.go
  2. 2
    2
      irc/client.go
  3. 180
    160
      irc/modes.go
  4. 4
    4
      irc/server.go
  5. 6
    6
      irc/types.go

+ 21
- 21
irc/channel.go View File

@@ -18,8 +18,8 @@ import (
18 18
 )
19 19
 
20 20
 type Channel struct {
21
-	flags          ChannelModeSet
22
-	lists          map[ChannelMode]*UserMaskSet
21
+	flags          ModeSet
22
+	lists          map[Mode]*UserMaskSet
23 23
 	key            string
24 24
 	membersMutex   sync.RWMutex
25 25
 	members        MemberSet
@@ -43,8 +43,8 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel {
43 43
 	}
44 44
 
45 45
 	channel := &Channel{
46
-		flags: make(ChannelModeSet),
47
-		lists: map[ChannelMode]*UserMaskSet{
46
+		flags: make(ModeSet),
47
+		lists: map[Mode]*UserMaskSet{
48 48
 			BanMask:    NewUserMaskSet(),
49 49
 			ExceptMask: NewUserMaskSet(),
50 50
 			InviteMask: NewUserMaskSet(),
@@ -110,14 +110,14 @@ func (channel *Channel) namesNoMutex(client *Client) {
110 110
 }
111 111
 
112 112
 // ClientIsAtLeast returns whether the client has at least the given channel privilege.
113
-func (channel *Channel) ClientIsAtLeast(client *Client, permission ChannelMode) bool {
113
+func (channel *Channel) ClientIsAtLeast(client *Client, permission Mode) bool {
114 114
 	channel.membersMutex.RLock()
115 115
 	defer channel.membersMutex.RUnlock()
116 116
 
117 117
 	return channel.clientIsAtLeastNoMutex(client, permission)
118 118
 }
119 119
 
120
-func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission ChannelMode) bool {
120
+func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission Mode) bool {
121 121
 	// requires RLock()
122 122
 
123 123
 	// get voice, since it's not a part of ChannelPrivModes
@@ -140,7 +140,7 @@ func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission Channe
140 140
 }
141 141
 
142 142
 // Prefixes returns a list of prefixes for the given set of channel modes.
143
-func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string {
143
+func (modes ModeSet) Prefixes(isMultiPrefix bool) string {
144 144
 	var prefixes string
145 145
 
146 146
 	// add prefixes in order from highest to lowest privs
@@ -394,11 +394,11 @@ func (channel *Channel) CanSpeak(client *Client) bool {
394 394
 }
395 395
 
396 396
 // TagMsg sends a tag message to everyone in this channel who can accept them.
397
-func (channel *Channel) TagMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
397
+func (channel *Channel) TagMsg(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
398 398
 	channel.sendMessage(msgid, "TAGMSG", []Capability{MessageTags}, minPrefix, clientOnlyTags, client, nil)
399 399
 }
400 400
 
401
-func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
401
+func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
402 402
 	if !channel.CanSpeak(client) {
403 403
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
404 404
 		return
@@ -408,7 +408,7 @@ func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability
408 408
 	defer channel.membersMutex.RUnlock()
409 409
 
410 410
 	// for STATUSMSG
411
-	var minPrefixMode ChannelMode
411
+	var minPrefixMode Mode
412 412
 	if minPrefix != nil {
413 413
 		minPrefixMode = *minPrefix
414 414
 	}
@@ -445,16 +445,16 @@ func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability
445 445
 }
446 446
 
447 447
 // SplitPrivMsg sends a private message to everyone in this channel.
448
-func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
448
+func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
449 449
 	channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message)
450 450
 }
451 451
 
452 452
 // SplitNotice sends a private message to everyone in this channel.
453
-func (channel *Channel) SplitNotice(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
453
+func (channel *Channel) SplitNotice(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
454 454
 	channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message)
455 455
 }
456 456
 
457
-func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
457
+func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
458 458
 	if !channel.CanSpeak(client) {
459 459
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
460 460
 		return
@@ -464,7 +464,7 @@ func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMo
464 464
 	defer channel.membersMutex.RUnlock()
465 465
 
466 466
 	// for STATUSMSG
467
-	var minPrefixMode ChannelMode
467
+	var minPrefixMode Mode
468 468
 	if minPrefix != nil {
469 469
 		minPrefixMode = *minPrefix
470 470
 	}
@@ -489,7 +489,7 @@ func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMo
489 489
 	}
490 490
 }
491 491
 
492
-func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
492
+func (channel *Channel) applyModeFlag(client *Client, mode Mode,
493 493
 	op ModeOp) bool {
494 494
 	if !channel.ClientIsAtLeast(client, ChannelOperator) {
495 495
 		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
@@ -514,8 +514,8 @@ func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
514 514
 	return false
515 515
 }
516 516
 
517
-func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
518
-	op ModeOp, nick string) *ChannelModeChange {
517
+func (channel *Channel) applyModeMemberNoMutex(client *Client, mode Mode,
518
+	op ModeOp, nick string) *ModeChange {
519 519
 	// requires Lock()
520 520
 
521 521
 	if nick == "" {
@@ -542,7 +542,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
542 542
 			return nil
543 543
 		}
544 544
 		channel.members[target][mode] = true
545
-		return &ChannelModeChange{
545
+		return &ModeChange{
546 546
 			op:   Add,
547 547
 			mode: mode,
548 548
 			arg:  nick,
@@ -553,7 +553,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
553 553
 			return nil
554 554
 		}
555 555
 		channel.members[target][mode] = false
556
-		return &ChannelModeChange{
556
+		return &ModeChange{
557 557
 			op:   Remove,
558 558
 			mode: mode,
559 559
 			arg:  nick,
@@ -562,7 +562,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
562 562
 	return nil
563 563
 }
564 564
 
565
-func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) {
565
+func (channel *Channel) ShowMaskList(client *Client, mode Mode) {
566 566
 	//TODO(dan): WE NEED TO fiX this PROPERLY
567 567
 	log.Fatal("Implement ShowMaskList")
568 568
 	/*
@@ -572,7 +572,7 @@ func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) {
572 572
 		client.RplEndOfMaskList(mode, channel)*/
573 573
 }
574 574
 
575
-func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeOp, mask string) bool {
575
+func (channel *Channel) applyModeMask(client *Client, mode Mode, op ModeOp, mask string) bool {
576 576
 	list := channel.lists[mode]
577 577
 	if list == nil {
578 578
 		// This should never happen, but better safe than panicky.

+ 2
- 2
irc/client.go View File

@@ -43,7 +43,7 @@ type Client struct {
43 43
 	channels           ChannelSet
44 44
 	class              *OperClass
45 45
 	ctime              time.Time
46
-	flags              map[UserMode]bool
46
+	flags              map[Mode]bool
47 47
 	isDestroyed        bool
48 48
 	isQuitting         bool
49 49
 	hasQuit            bool
@@ -83,7 +83,7 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
83 83
 		capVersion:     Cap301,
84 84
 		channels:       make(ChannelSet),
85 85
 		ctime:          now,
86
-		flags:          make(map[UserMode]bool),
86
+		flags:          make(map[Mode]bool),
87 87
 		monitoring:     make(map[string]bool),
88 88
 		server:         server,
89 89
 		socket:         &socket,

+ 180
- 160
irc/modes.go View File

@@ -178,8 +178,8 @@ func SplitChannelMembershipPrefixes(target string) (prefixes string, name string
178 178
 }
179 179
 
180 180
 // GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes.
181
-func GetLowestChannelModePrefix(prefixes string) *ChannelMode {
182
-	var lowest *ChannelMode
181
+func GetLowestChannelModePrefix(prefixes string) *Mode {
182
+	var lowest *Mode
183 183
 
184 184
 	if strings.Contains(prefixes, "+") {
185 185
 		lowest = &Voice
@@ -208,8 +208,8 @@ func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
208 208
 	return umodeHandler(server, client, msg)
209 209
 }
210 210
 
211
-// applyModeChanges applies the given changes, and returns the applied changes.
212
-func (client *Client) applyModeChanges(ModeChanges) ModeChanges {
211
+// applyUserModeChanges applies the given changes, and returns the applied changes.
212
+func (client *Client) applyUserModeChanges(changes ModeChanges) ModeChanges {
213 213
 	applied := make(ModeChanges, 0)
214 214
 
215 215
 	for _, change := range changes {
@@ -289,13 +289,13 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
289 289
 				op = ModeOp(mode)
290 290
 				continue
291 291
 			}
292
-			changes = append(changes, &ModeChange{
292
+			changes = append(changes, ModeChange{
293 293
 				mode: Mode(mode),
294 294
 				op:   op,
295 295
 			})
296 296
 		}
297 297
 
298
-		applied := target.applyModeChanges(changes)
298
+		applied = target.applyUserModeChanges(changes)
299 299
 	}
300 300
 
301 301
 	if len(applied) > 0 {
@@ -306,68 +306,45 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
306 306
 	return false
307 307
 }
308 308
 
309
-//////
310
-//////
311
-//////
312
-//////
313
-//////
314
-//////
315
-//////
316
-//////
317
-//////
318
-
319
-// MODE <target> [<modestring> [<mode arguments>...]]
320
-func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
321
-	channelName, err := CasefoldChannel(msg.Params[0])
322
-	channel := server.channels.Get(channelName)
323
-
324
-	channel.membersMutex.Lock()
325
-	defer channel.membersMutex.Unlock()
326
-
327
-	if err != nil || channel == nil {
328
-		client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
329
-		return false
330
-	}
331
-
332
-	// assemble changes
333
-	//TODO(dan): split out assembling changes into func that returns changes, err
334
-	changes := make(ChannelModeChanges, 0)
335
-	applied := make(ChannelModeChanges, 0)
309
+// ParseChannelModeChanges returns the valid changes, and the list of unknown chars.
310
+func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
311
+	changes := make(ModeChanges, 0)
312
+	unknown := make(map[rune]bool)
336 313
 
337
-	// TODO(dan): look at separating these into the type A/B/C/D args and using those lists here
338
-	if len(msg.Params) > 1 {
339
-		modeArg := msg.Params[1]
314
+	if len(params) > 1 {
315
+		modeArg := params[0]
340 316
 		op := ModeOp(modeArg[0])
341 317
 		if (op == Add) || (op == Remove) {
342 318
 			modeArg = modeArg[1:]
343 319
 		} else {
344
-			client.Send(nil, server.name, ERR_UNKNOWNMODE, client.nick, string(modeArg[0]), "is an unknown mode character to me")
345
-			return false
320
+			unknown[rune(modeArg[0])] = true
321
+			return changes, unknown
346 322
 		}
347 323
 
348
-		skipArgs := 2
324
+		skipArgs := 1
325
+
349 326
 		for _, mode := range modeArg {
350 327
 			if mode == '-' || mode == '+' {
351 328
 				op = ModeOp(mode)
352 329
 				continue
353 330
 			}
354
-			change := ChannelModeChange{
355
-				mode: ChannelMode(mode),
331
+			change := ModeChange{
332
+				mode: Mode(mode),
356 333
 				op:   op,
357 334
 			}
358 335
 
359 336
 			// put arg into modechange if needed
360
-			switch ChannelMode(mode) {
337
+			switch Mode(mode) {
361 338
 			case BanMask, ExceptMask, InviteMask:
362
-				if len(msg.Params) > skipArgs {
363
-					change.arg = msg.Params[skipArgs]
339
+				if len(params) > skipArgs {
340
+					change.arg = params[skipArgs]
364 341
 					skipArgs++
365 342
 				} else {
366 343
 					change.op = List
367 344
 				}
368 345
 			case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
369
-				if len(msg.Params) > skipArgs {
370
-					change.arg = msg.Params[skipArgs]
346
+				if len(params) > skipArgs {
347
+					change.arg = params[skipArgs]
371 348
 					skipArgs++
372 349
 				} else {
373 350
 					continue
@@ -375,164 +352,207 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
375 352
 			case Key, UserLimit:
376 353
 				// don't require value when removing
377 354
 				if change.op == Add {
378
-					if len(msg.Params) > skipArgs {
379
-						change.arg = msg.Params[skipArgs]
355
+					if len(params) > skipArgs {
356
+						change.arg = params[skipArgs]
380 357
 						skipArgs++
381 358
 					} else {
382 359
 						continue
383 360
 					}
384 361
 				}
362
+			default:
363
+				unknown[mode] = true
385 364
 			}
386 365
 
387
-			changes = append(changes, &change)
366
+			changes = append(changes, change)
388 367
 		}
368
+	}
389 369
 
390
-		// so we only output one warning for each list type when full
391
-		listFullWarned := make(map[ChannelMode]bool)
370
+	return changes, unknown
371
+}
392 372
 
393
-		clientIsOp := channel.clientIsAtLeastNoMutex(client, ChannelOperator)
394
-		var alreadySentPrivError bool
373
+// ApplyChannelModeChanges applies a given set of mode changes.
374
+func ApplyChannelModeChanges(channel *Channel, client *Client, isSamode bool, changes ModeChanges) ModeChanges {
375
+	// so we only output one warning for each list type when full
376
+	listFullWarned := make(map[Mode]bool)
395 377
 
396
-		for _, change := range changes {
397
-			// chan priv modes are checked specially so ignore them
398
-			// means regular users can't view ban/except lists... but I'm not worried about that
399
-			if msg.Command != "SAMODE" && ChannelModePrefixes[change.mode] == "" && !clientIsOp {
400
-				if !alreadySentPrivError {
401
-					alreadySentPrivError = true
402
-					client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
403
-				}
404
-				continue
378
+	clientIsOp := channel.clientIsAtLeastNoMutex(client, ChannelOperator)
379
+	var alreadySentPrivError bool
380
+
381
+	applied := make(ModeChanges, 0)
382
+
383
+	for _, change := range changes {
384
+		// chan priv modes are checked specially so ignore them
385
+		// means regular users can't view ban/except lists... but I'm not worried about that
386
+		if isSamode && ChannelModePrefixes[change.mode] == "" && !clientIsOp {
387
+			if !alreadySentPrivError {
388
+				alreadySentPrivError = true
389
+				client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
405 390
 			}
391
+			continue
392
+		}
406 393
 
407
-			switch change.mode {
408
-			case BanMask, ExceptMask, InviteMask:
409
-				mask := change.arg
410
-				list := channel.lists[change.mode]
411
-				if list == nil {
412
-					// This should never happen, but better safe than panicky.
413
-					client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "MODE", "Could not complete MODE command")
414
-					return false
415
-				}
394
+		switch change.mode {
395
+		case BanMask, ExceptMask, InviteMask:
396
+			mask := change.arg
397
+			list := channel.lists[change.mode]
398
+			if list == nil {
399
+				// This should never happen, but better safe than panicky.
400
+				client.Send(nil, client.server.name, ERR_UNKNOWNERROR, client.nick, "MODE", "Could not complete MODE command")
401
+				return changes
402
+			}
416 403
 
417
-				if (change.op == List) || (mask == "") {
418
-					channel.ShowMaskList(client, change.mode)
419
-					continue
420
-				}
404
+			if (change.op == List) || (mask == "") {
405
+				channel.ShowMaskList(client, change.mode)
406
+				continue
407
+			}
408
+
409
+			// confirm mask looks valid
410
+			mask, err := Casefold(mask)
411
+			if err != nil {
412
+				continue
413
+			}
421 414
 
422
-				// confirm mask looks valid
423
-				mask, err = Casefold(mask)
424
-				if err != nil {
415
+			switch change.op {
416
+			case Add:
417
+				if len(list.masks) >= client.server.limits.ChanListModes {
418
+					if !listFullWarned[change.mode] {
419
+						client.Send(nil, client.server.name, ERR_BANLISTFULL, client.nick, channel.name, change.mode.String(), "Channel list is full")
420
+						listFullWarned[change.mode] = true
421
+					}
425 422
 					continue
426 423
 				}
427 424
 
428
-				switch change.op {
429
-				case Add:
430
-					if len(list.masks) >= server.limits.ChanListModes {
431
-						if !listFullWarned[change.mode] {
432
-							client.Send(nil, server.name, ERR_BANLISTFULL, client.nick, channel.name, change.mode.String(), "Channel list is full")
433
-							listFullWarned[change.mode] = true
434
-						}
435
-						continue
436
-					}
425
+				list.Add(mask)
426
+				applied = append(applied, change)
437 427
 
438
-					list.Add(mask)
439
-					applied = append(applied, change)
428
+			case Remove:
429
+				list.Remove(mask)
430
+				applied = append(applied, change)
431
+			}
440 432
 
441
-				case Remove:
442
-					list.Remove(mask)
433
+		case UserLimit:
434
+			switch change.op {
435
+			case Add:
436
+				val, err := strconv.ParseUint(change.arg, 10, 64)
437
+				if err == nil {
438
+					channel.userLimit = val
443 439
 					applied = append(applied, change)
444 440
 				}
445 441
 
446
-			case UserLimit:
447
-				switch change.op {
448
-				case Add:
449
-					val, err := strconv.ParseUint(change.arg, 10, 64)
450
-					if err == nil {
451
-						channel.userLimit = val
452
-						applied = append(applied, change)
453
-					}
442
+			case Remove:
443
+				channel.userLimit = 0
444
+				applied = append(applied, change)
445
+			}
454 446
 
455
-				case Remove:
456
-					channel.userLimit = 0
457
-					applied = append(applied, change)
458
-				}
447
+		case Key:
448
+			switch change.op {
449
+			case Add:
450
+				channel.key = change.arg
459 451
 
460
-			case Key:
461
-				switch change.op {
462
-				case Add:
463
-					channel.key = change.arg
452
+			case Remove:
453
+				channel.key = ""
454
+			}
455
+			applied = append(applied, change)
464 456
 
465
-				case Remove:
466
-					channel.key = ""
457
+		case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Secret, ChanRoleplaying:
458
+			switch change.op {
459
+			case Add:
460
+				if channel.flags[change.mode] {
461
+					continue
467 462
 				}
463
+				channel.flags[change.mode] = true
468 464
 				applied = append(applied, change)
469 465
 
470
-			case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Secret, ChanRoleplaying:
471
-				switch change.op {
472
-				case Add:
473
-					if channel.flags[change.mode] {
474
-						continue
475
-					}
476
-					channel.flags[change.mode] = true
477
-					applied = append(applied, change)
478
-
479
-				case Remove:
480
-					if !channel.flags[change.mode] {
481
-						continue
482
-					}
483
-					delete(channel.flags, change.mode)
484
-					applied = append(applied, change)
466
+			case Remove:
467
+				if !channel.flags[change.mode] {
468
+					continue
485 469
 				}
470
+				delete(channel.flags, change.mode)
471
+				applied = append(applied, change)
472
+			}
486 473
 
487
-			case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
488
-				// make sure client has privs to edit the given prefix
489
-				var hasPrivs bool
474
+		case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
475
+			// make sure client has privs to edit the given prefix
476
+			hasPrivs := isSamode
490 477
 
491
-				if msg.Command == "SAMODE" {
492
-					hasPrivs = true
493
-				} else {
494
-					for _, mode := range ChannelPrivModes {
495
-						if channel.members[client][mode] {
496
-							hasPrivs = true
497
-
498
-							// Admins can't give other people Admin or remove it from others,
499
-							// standard for that channel mode, we worry about this later
500
-							if mode == ChannelAdmin && change.mode == ChannelAdmin {
501
-								hasPrivs = false
502
-							}
503
-
504
-							break
505
-						} else if mode == change.mode {
506
-							break
478
+			if !hasPrivs {
479
+				for _, mode := range ChannelPrivModes {
480
+					if channel.members[client][mode] {
481
+						hasPrivs = true
482
+
483
+						// Admins can't give other people Admin or remove it from others,
484
+						// standard for that channel mode, we worry about this later
485
+						if mode == ChannelAdmin && change.mode == ChannelAdmin {
486
+							hasPrivs = false
507 487
 						}
488
+
489
+						break
490
+					} else if mode == change.mode {
491
+						break
508 492
 					}
509 493
 				}
494
+			}
510 495
 
511
-				casefoldedName, err := CasefoldName(change.arg)
512
-				if err != nil {
513
-					continue
514
-				}
496
+			casefoldedName, err := CasefoldName(change.arg)
497
+			if err != nil {
498
+				continue
499
+			}
515 500
 
516
-				if !hasPrivs {
517
-					if change.op == Remove && casefoldedName == client.nickCasefolded {
518
-						// success!
519
-					} else {
520
-						if !alreadySentPrivError {
521
-							alreadySentPrivError = true
522
-							client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
523
-						}
524
-						continue
501
+			if !hasPrivs {
502
+				if change.op == Remove && casefoldedName == client.nickCasefolded {
503
+					// success!
504
+				} else {
505
+					if !alreadySentPrivError {
506
+						alreadySentPrivError = true
507
+						client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
525 508
 					}
509
+					continue
526 510
 				}
511
+			}
527 512
 
528
-				change := channel.applyModeMemberNoMutex(client, change.mode, change.op, change.arg)
529
-				if change != nil {
530
-					applied = append(applied, change)
531
-				}
513
+			change := channel.applyModeMemberNoMutex(client, change.mode, change.op, change.arg)
514
+			if change != nil {
515
+				applied = append(applied, *change)
532 516
 			}
533 517
 		}
534 518
 	}
535 519
 
520
+	return applied
521
+}
522
+
523
+// MODE <target> [<modestring> [<mode arguments>...]]
524
+func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
525
+	channelName, err := CasefoldChannel(msg.Params[0])
526
+	channel := server.channels.Get(channelName)
527
+
528
+	channel.membersMutex.Lock()
529
+	defer channel.membersMutex.Unlock()
530
+
531
+	if err != nil || channel == nil {
532
+		client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
533
+		return false
534
+	}
535
+
536
+	// applied mode changes
537
+	applied := make(ModeChanges, 0)
538
+
539
+	if 1 < len(msg.Params) {
540
+		// parse out real mode changes
541
+		params := msg.Params[1:]
542
+		changes, unknown := ParseChannelModeChanges(params...)
543
+
544
+		// alert for unknown mode changes
545
+		for char := range unknown {
546
+			client.Send(nil, server.name, ERR_UNKNOWNMODE, client.nick, string(char), "is an unknown mode character to me")
547
+		}
548
+		if len(unknown) == 1 && len(changes) == 0 {
549
+			return false
550
+		}
551
+
552
+		// apply mode changes
553
+		applied = ApplyChannelModeChanges(channel, client, msg.Command == "SAMODE", changes)
554
+	}
555
+
536 556
 	if len(applied) > 0 {
537 557
 		//TODO(dan): we should change the name of String and make it return a slice here
538 558
 		args := append([]string{channel.name}, strings.Split(applied.String(), " ")...)

+ 4
- 4
irc/server.go View File

@@ -339,7 +339,7 @@ func (server *Server) setISupport() {
339 339
 	server.isupport = NewISupportList()
340 340
 	server.isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
341 341
 	server.isupport.Add("CASEMAPPING", casemappingName)
342
-	server.isupport.Add("CHANMODES", strings.Join([]string{ChannelModes{BanMask, ExceptMask, InviteMask}.String(), "", ChannelModes{UserLimit, Key}.String(), ChannelModes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret}.String()}, ","))
342
+	server.isupport.Add("CHANMODES", strings.Join([]string{Modes{BanMask, ExceptMask, InviteMask}.String(), "", Modes{UserLimit, Key}.String(), Modes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret}.String()}, ","))
343 343
 	server.isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
344 344
 	server.isupport.Add("CHANTYPES", "#")
345 345
 	server.isupport.Add("EXCEPTS", "")
@@ -376,7 +376,7 @@ func (server *Server) setISupport() {
376 376
 	server.isupport.RegenerateCachedReply()
377 377
 }
378 378
 
379
-func loadChannelList(channel *Channel, list string, maskMode ChannelMode) {
379
+func loadChannelList(channel *Channel, list string, maskMode Mode) {
380 380
 	if list == "" {
381 381
 		return
382 382
 	}
@@ -1242,7 +1242,7 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1242 1242
 
1243 1243
 	client.Send(nil, server.name, RPL_YOUREOPER, client.nick, "You are now an IRC operator")
1244 1244
 	//TODO(dan): Should this be sent automagically as part of setting the flag/mode?
1245
-	modech := ModeChanges{&ModeChange{
1245
+	modech := ModeChanges{ModeChange{
1246 1246
 		mode: Operator,
1247 1247
 		op:   Add,
1248 1248
 	}}
@@ -1521,7 +1521,7 @@ func awayHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1521 1521
 		client.Send(nil, server.name, RPL_UNAWAY, client.nick, "You are no longer marked as being away")
1522 1522
 	}
1523 1523
 	//TODO(dan): Should this be sent automagically as part of setting the flag/mode?
1524
-	modech := ModeChanges{&ModeChange{
1524
+	modech := ModeChanges{ModeChange{
1525 1525
 		mode: Away,
1526 1526
 		op:   op,
1527 1527
 	}}

+ 6
- 6
irc/types.go View File

@@ -39,9 +39,9 @@ func (channels ChannelNameMap) Remove(channel *Channel) error {
39 39
 	return nil
40 40
 }
41 41
 
42
-type ChannelModeSet map[ChannelMode]bool
42
+type ModeSet map[Mode]bool
43 43
 
44
-func (set ChannelModeSet) String() string {
44
+func (set ModeSet) String() string {
45 45
 	if len(set) == 0 {
46 46
 		return ""
47 47
 	}
@@ -68,10 +68,10 @@ func (clients ClientSet) Has(client *Client) bool {
68 68
 	return clients[client]
69 69
 }
70 70
 
71
-type MemberSet map[*Client]ChannelModeSet
71
+type MemberSet map[*Client]ModeSet
72 72
 
73 73
 func (members MemberSet) Add(member *Client) {
74
-	members[member] = make(ChannelModeSet)
74
+	members[member] = make(ModeSet)
75 75
 }
76 76
 
77 77
 func (members MemberSet) Remove(member *Client) {
@@ -83,7 +83,7 @@ func (members MemberSet) Has(member *Client) bool {
83 83
 	return ok
84 84
 }
85 85
 
86
-func (members MemberSet) HasMode(member *Client, mode ChannelMode) bool {
86
+func (members MemberSet) HasMode(member *Client, mode Mode) bool {
87 87
 	modes, ok := members[member]
88 88
 	if !ok {
89 89
 		return false
@@ -91,7 +91,7 @@ func (members MemberSet) HasMode(member *Client, mode ChannelMode) bool {
91 91
 	return modes[mode]
92 92
 }
93 93
 
94
-func (members MemberSet) AnyHasMode(mode ChannelMode) bool {
94
+func (members MemberSet) AnyHasMode(mode Mode) bool {
95 95
 	for _, modes := range members {
96 96
 		if modes[mode] {
97 97
 			return true

Loading…
Cancel
Save