Переглянути джерело

Split modes into a subpackage (this is painful, but will force us to simplify and improve the API for interacting with modes)

tags/v0.11.0-beta
Daniel Oaks 6 роки тому
джерело
коміт
3634d0601e
12 змінених файлів з 541 додано та 517 видалено
  1. 65
    86
      irc/channel.go
  2. 3
    2
      irc/chanserv.go
  3. 5
    4
      irc/client.go
  4. 5
    2
      irc/commands.go
  5. 3
    2
      irc/gateways.go
  6. 8
    5
      irc/getters.go
  7. 48
    47
      irc/handlers.go
  8. 88
    327
      irc/modes.go
  9. 286
    0
      irc/modes/modes.go
  10. 4
    3
      irc/roleplay.go
  11. 21
    15
      irc/server.go
  12. 5
    24
      irc/types.go

+ 65
- 86
irc/channel.go Переглянути файл

15
 
15
 
16
 	"github.com/goshuirc/irc-go/ircmsg"
16
 	"github.com/goshuirc/irc-go/ircmsg"
17
 	"github.com/oragono/oragono/irc/caps"
17
 	"github.com/oragono/oragono/irc/caps"
18
+	"github.com/oragono/oragono/irc/modes"
18
 )
19
 )
19
 
20
 
20
 var (
21
 var (
23
 
24
 
24
 // Channel represents a channel that clients can join.
25
 // Channel represents a channel that clients can join.
25
 type Channel struct {
26
 type Channel struct {
26
-	flags             ModeSet
27
-	lists             map[Mode]*UserMaskSet
27
+	flags             modes.ModeSet
28
+	lists             map[modes.Mode]*UserMaskSet
28
 	key               string
29
 	key               string
29
 	members           MemberSet
30
 	members           MemberSet
30
 	membersCache      []*Client  // allow iteration over channel members without holding the lock
31
 	membersCache      []*Client  // allow iteration over channel members without holding the lock
53
 
54
 
54
 	channel := &Channel{
55
 	channel := &Channel{
55
 		createdTime: time.Now(), // may be overwritten by applyRegInfo
56
 		createdTime: time.Now(), // may be overwritten by applyRegInfo
56
-		flags:       make(ModeSet),
57
-		lists: map[Mode]*UserMaskSet{
58
-			BanMask:    NewUserMaskSet(),
59
-			ExceptMask: NewUserMaskSet(),
60
-			InviteMask: NewUserMaskSet(),
57
+		flags:       make(modes.ModeSet),
58
+		lists: map[modes.Mode]*UserMaskSet{
59
+			modes.BanMask:    NewUserMaskSet(),
60
+			modes.ExceptMask: NewUserMaskSet(),
61
+			modes.InviteMask: NewUserMaskSet(),
61
 		},
62
 		},
62
 		members:        make(MemberSet),
63
 		members:        make(MemberSet),
63
 		name:           name,
64
 		name:           name,
88
 	channel.name = chanReg.Name
89
 	channel.name = chanReg.Name
89
 	channel.createdTime = chanReg.RegisteredAt
90
 	channel.createdTime = chanReg.RegisteredAt
90
 	for _, mask := range chanReg.Banlist {
91
 	for _, mask := range chanReg.Banlist {
91
-		channel.lists[BanMask].Add(mask)
92
+		channel.lists[modes.BanMask].Add(mask)
92
 	}
93
 	}
93
 	for _, mask := range chanReg.Exceptlist {
94
 	for _, mask := range chanReg.Exceptlist {
94
-		channel.lists[ExceptMask].Add(mask)
95
+		channel.lists[modes.ExceptMask].Add(mask)
95
 	}
96
 	}
96
 	for _, mask := range chanReg.Invitelist {
97
 	for _, mask := range chanReg.Invitelist {
97
-		channel.lists[InviteMask].Add(mask)
98
+		channel.lists[modes.InviteMask].Add(mask)
98
 	}
99
 	}
99
 }
100
 }
100
 
101
 
111
 	info.RegisteredAt = channel.registeredTime
112
 	info.RegisteredAt = channel.registeredTime
112
 
113
 
113
 	if includeLists {
114
 	if includeLists {
114
-		for mask := range channel.lists[BanMask].masks {
115
+		for mask := range channel.lists[modes.BanMask].masks {
115
 			info.Banlist = append(info.Banlist, mask)
116
 			info.Banlist = append(info.Banlist, mask)
116
 		}
117
 		}
117
-		for mask := range channel.lists[ExceptMask].masks {
118
+		for mask := range channel.lists[modes.ExceptMask].masks {
118
 			info.Exceptlist = append(info.Exceptlist, mask)
119
 			info.Exceptlist = append(info.Exceptlist, mask)
119
 		}
120
 		}
120
-		for mask := range channel.lists[InviteMask].masks {
121
+		for mask := range channel.lists[modes.InviteMask].masks {
121
 			info.Invitelist = append(info.Invitelist, mask)
122
 			info.Invitelist = append(info.Invitelist, mask)
122
 		}
123
 		}
123
 	}
124
 	}
201
 }
202
 }
202
 
203
 
203
 // ClientIsAtLeast returns whether the client has at least the given channel privilege.
204
 // ClientIsAtLeast returns whether the client has at least the given channel privilege.
204
-func (channel *Channel) ClientIsAtLeast(client *Client, permission Mode) bool {
205
+func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) bool {
205
 	channel.stateMutex.RLock()
206
 	channel.stateMutex.RLock()
206
 	defer channel.stateMutex.RUnlock()
207
 	defer channel.stateMutex.RUnlock()
207
 
208
 
211
 	}
212
 	}
212
 
213
 
213
 	// check regular modes
214
 	// check regular modes
214
-	for _, mode := range ChannelPrivModes {
215
+	for _, mode := range modes.ChannelPrivModes {
215
 		if channel.members.HasMode(client, mode) {
216
 		if channel.members.HasMode(client, mode) {
216
 			return true
217
 			return true
217
 		}
218
 		}
224
 	return false
225
 	return false
225
 }
226
 }
226
 
227
 
227
-// Prefixes returns a list of prefixes for the given set of channel modes.
228
-func (modes ModeSet) Prefixes(isMultiPrefix bool) string {
229
-	var prefixes string
230
-
231
-	// add prefixes in order from highest to lowest privs
232
-	for _, mode := range ChannelPrivModes {
233
-		if modes[mode] {
234
-			prefixes += ChannelModePrefixes[mode]
235
-		}
236
-	}
237
-	if modes[Voice] {
238
-		prefixes += ChannelModePrefixes[Voice]
239
-	}
240
-
241
-	if !isMultiPrefix && len(prefixes) > 1 {
242
-		prefixes = string(prefixes[0])
243
-	}
244
-
245
-	return prefixes
246
-}
247
-
248
 func (channel *Channel) ClientPrefixes(client *Client, isMultiPrefix bool) string {
228
 func (channel *Channel) ClientPrefixes(client *Client, isMultiPrefix bool) string {
249
 	channel.stateMutex.RLock()
229
 	channel.stateMutex.RLock()
250
 	defer channel.stateMutex.RUnlock()
230
 	defer channel.stateMutex.RUnlock()
263
 	clientModes := channel.members[client]
243
 	clientModes := channel.members[client]
264
 	targetModes := channel.members[target]
244
 	targetModes := channel.members[target]
265
 	result := false
245
 	result := false
266
-	for _, mode := range ChannelPrivModes {
246
+	for _, mode := range modes.ChannelPrivModes {
267
 		if clientModes[mode] {
247
 		if clientModes[mode] {
268
 			result = true
248
 			result = true
269
 			// admins cannot kick other admins
249
 			// admins cannot kick other admins
270
-			if mode == ChannelAdmin && targetModes[ChannelAdmin] {
250
+			if mode == modes.ChannelAdmin && targetModes[modes.ChannelAdmin] {
271
 				result = false
251
 				result = false
272
 			}
252
 			}
273
 			break
253
 			break
318
 
298
 
319
 // <mode> <mode params>
299
 // <mode> <mode params>
320
 func (channel *Channel) modeStrings(client *Client) (result []string) {
300
 func (channel *Channel) modeStrings(client *Client) (result []string) {
321
-	isMember := client.HasMode(Operator) || channel.hasClient(client)
301
+	isMember := client.HasMode(modes.Operator) || channel.hasClient(client)
322
 	showKey := isMember && (channel.key != "")
302
 	showKey := isMember && (channel.key != "")
323
 	showUserLimit := channel.userLimit > 0
303
 	showUserLimit := channel.userLimit > 0
324
 
304
 
325
-	modes := "+"
305
+	mods := "+"
326
 
306
 
327
 	// flags with args
307
 	// flags with args
328
 	if showKey {
308
 	if showKey {
329
-		modes += Key.String()
309
+		mods += modes.Key.String()
330
 	}
310
 	}
331
 	if showUserLimit {
311
 	if showUserLimit {
332
-		modes += UserLimit.String()
312
+		mods += modes.UserLimit.String()
333
 	}
313
 	}
334
 
314
 
335
 	channel.stateMutex.RLock()
315
 	channel.stateMutex.RLock()
337
 
317
 
338
 	// flags
318
 	// flags
339
 	for mode := range channel.flags {
319
 	for mode := range channel.flags {
340
-		modes += mode.String()
320
+		mods += mode.String()
341
 	}
321
 	}
342
 
322
 
343
-	result = []string{modes}
323
+	result = []string{mods}
344
 
324
 
345
 	// args for flags with args: The order must match above to keep
325
 	// args for flags with args: The order must match above to keep
346
 	// positional arguments in place.
326
 	// positional arguments in place.
390
 		return
370
 		return
391
 	}
371
 	}
392
 
372
 
393
-	isInvited := channel.lists[InviteMask].Match(client.nickMaskCasefolded)
394
-	if channel.flags[InviteOnly] && !isInvited {
373
+	isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded)
374
+	if channel.flags[modes.InviteOnly] && !isInvited {
395
 		client.Send(nil, client.server.name, ERR_INVITEONLYCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
375
 		client.Send(nil, client.server.name, ERR_INVITEONLYCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
396
 		return
376
 		return
397
 	}
377
 	}
398
 
378
 
399
-	if channel.lists[BanMask].Match(client.nickMaskCasefolded) &&
379
+	if channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) &&
400
 		!isInvited &&
380
 		!isInvited &&
401
-		!channel.lists[ExceptMask].Match(client.nickMaskCasefolded) {
381
+		!channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) {
402
 		client.Send(nil, client.server.name, ERR_BANNEDFROMCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
382
 		client.Send(nil, client.server.name, ERR_BANNEDFROMCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
403
 		return
383
 		return
404
 	}
384
 	}
423
 
403
 
424
 	// give channel mode if necessary
404
 	// give channel mode if necessary
425
 	newChannel := firstJoin && !channel.IsRegistered()
405
 	newChannel := firstJoin && !channel.IsRegistered()
426
-	var givenMode *Mode
406
+	var givenMode *modes.Mode
427
 	if client.AccountName() == channel.registeredFounder {
407
 	if client.AccountName() == channel.registeredFounder {
428
-		givenMode = &ChannelFounder
408
+		givenMode = &modes.ChannelFounder
429
 	} else if newChannel {
409
 	} else if newChannel {
430
-		givenMode = &ChannelOperator
410
+		givenMode = &modes.ChannelOperator
431
 	}
411
 	}
432
 	if givenMode != nil {
412
 	if givenMode != nil {
433
 		channel.stateMutex.Lock()
413
 		channel.stateMutex.Lock()
492
 
472
 
493
 // SetTopic sets the topic of this channel, if the client is allowed to do so.
473
 // SetTopic sets the topic of this channel, if the client is allowed to do so.
494
 func (channel *Channel) SetTopic(client *Client, topic string) {
474
 func (channel *Channel) SetTopic(client *Client, topic string) {
495
-	if !(client.flags[Operator] || channel.hasClient(client)) {
475
+	if !(client.flags[modes.Operator] || channel.hasClient(client)) {
496
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
476
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
497
 		return
477
 		return
498
 	}
478
 	}
499
 
479
 
500
-	if channel.HasMode(OpOnlyTopic) && !channel.ClientIsAtLeast(client, ChannelOperator) {
480
+	if channel.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
501
 		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
481
 		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
502
 		return
482
 		return
503
 	}
483
 	}
525
 	defer channel.stateMutex.RUnlock()
505
 	defer channel.stateMutex.RUnlock()
526
 
506
 
527
 	_, hasClient := channel.members[client]
507
 	_, hasClient := channel.members[client]
528
-	if channel.flags[NoOutside] && !hasClient {
508
+	if channel.flags[modes.NoOutside] && !hasClient {
529
 		return false
509
 		return false
530
 	}
510
 	}
531
-	if channel.flags[Moderated] && !channel.ClientIsAtLeast(client, Voice) {
511
+	if channel.flags[modes.Moderated] && !channel.ClientIsAtLeast(client, modes.Voice) {
532
 		return false
512
 		return false
533
 	}
513
 	}
534
-	if channel.flags[RegisteredOnly] && client.account == &NoAccount {
514
+	if channel.flags[modes.RegisteredOnly] && client.account == &NoAccount {
535
 		return false
515
 		return false
536
 	}
516
 	}
537
 	return true
517
 	return true
538
 }
518
 }
539
 
519
 
540
 // TagMsg sends a tag message to everyone in this channel who can accept them.
520
 // TagMsg sends a tag message to everyone in this channel who can accept them.
541
-func (channel *Channel) TagMsg(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
521
+func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
542
 	channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil)
522
 	channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil)
543
 }
523
 }
544
 
524
 
545
 // sendMessage sends a given message to everyone on this channel.
525
 // sendMessage sends a given message to everyone on this channel.
546
-func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
526
+func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
547
 	if !channel.CanSpeak(client) {
527
 	if !channel.CanSpeak(client) {
548
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
528
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
549
 		return
529
 		return
550
 	}
530
 	}
551
 
531
 
552
 	// for STATUSMSG
532
 	// for STATUSMSG
553
-	var minPrefixMode Mode
533
+	var minPrefixMode modes.Mode
554
 	if minPrefix != nil {
534
 	if minPrefix != nil {
555
 		minPrefixMode = *minPrefix
535
 		minPrefixMode = *minPrefix
556
 	}
536
 	}
587
 }
567
 }
588
 
568
 
589
 // SplitPrivMsg sends a private message to everyone in this channel.
569
 // SplitPrivMsg sends a private message to everyone in this channel.
590
-func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
570
+func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
591
 	channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message)
571
 	channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message)
592
 }
572
 }
593
 
573
 
594
 // SplitNotice sends a private message to everyone in this channel.
574
 // SplitNotice sends a private message to everyone in this channel.
595
-func (channel *Channel) SplitNotice(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
575
+func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
596
 	channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message)
576
 	channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message)
597
 }
577
 }
598
 
578
 
599
-func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
579
+func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
600
 	if !channel.CanSpeak(client) {
580
 	if !channel.CanSpeak(client) {
601
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
581
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
602
 		return
582
 		return
603
 	}
583
 	}
604
 
584
 
605
 	// for STATUSMSG
585
 	// for STATUSMSG
606
-	var minPrefixMode Mode
586
+	var minPrefixMode modes.Mode
607
 	if minPrefix != nil {
587
 	if minPrefix != nil {
608
 		minPrefixMode = *minPrefix
588
 		minPrefixMode = *minPrefix
609
 	}
589
 	}
628
 	}
608
 	}
629
 }
609
 }
630
 
610
 
631
-func (channel *Channel) applyModeMemberNoMutex(client *Client, mode Mode,
632
-	op ModeOp, nick string) *ModeChange {
611
+func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode, op modes.ModeOp, nick string) *modes.ModeChange {
633
 	if nick == "" {
612
 	if nick == "" {
634
 		//TODO(dan): shouldn't this be handled before it reaches this function?
613
 		//TODO(dan): shouldn't this be handled before it reaches this function?
635
 		client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
614
 		client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
647
 	modeset, exists := channel.members[target]
626
 	modeset, exists := channel.members[target]
648
 	var already bool
627
 	var already bool
649
 	if exists {
628
 	if exists {
650
-		enable := op == Add
629
+		enable := op == modes.Add
651
 		already = modeset[mode] == enable
630
 		already = modeset[mode] == enable
652
 		modeset[mode] = enable
631
 		modeset[mode] = enable
653
 	}
632
 	}
659
 	} else if already {
638
 	} else if already {
660
 		return nil
639
 		return nil
661
 	} else {
640
 	} else {
662
-		return &ModeChange{
663
-			op:   op,
664
-			mode: mode,
665
-			arg:  nick,
641
+		return &modes.ModeChange{
642
+			Op:   op,
643
+			Mode: mode,
644
+			Arg:  nick,
666
 		}
645
 		}
667
 	}
646
 	}
668
 }
647
 }
669
 
648
 
670
 // ShowMaskList shows the given list to the client.
649
 // ShowMaskList shows the given list to the client.
671
-func (channel *Channel) ShowMaskList(client *Client, mode Mode) {
650
+func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode) {
672
 	// choose appropriate modes
651
 	// choose appropriate modes
673
 	var rpllist, rplendoflist string
652
 	var rpllist, rplendoflist string
674
-	if mode == BanMask {
653
+	if mode == modes.BanMask {
675
 		rpllist = RPL_BANLIST
654
 		rpllist = RPL_BANLIST
676
 		rplendoflist = RPL_ENDOFBANLIST
655
 		rplendoflist = RPL_ENDOFBANLIST
677
-	} else if mode == ExceptMask {
656
+	} else if mode == modes.ExceptMask {
678
 		rpllist = RPL_EXCEPTLIST
657
 		rpllist = RPL_EXCEPTLIST
679
 		rplendoflist = RPL_ENDOFEXCEPTLIST
658
 		rplendoflist = RPL_ENDOFEXCEPTLIST
680
-	} else if mode == InviteMask {
659
+	} else if mode == modes.InviteMask {
681
 		rpllist = RPL_INVITELIST
660
 		rpllist = RPL_INVITELIST
682
 		rplendoflist = RPL_ENDOFINVITELIST
661
 		rplendoflist = RPL_ENDOFINVITELIST
683
 	}
662
 	}
693
 	client.Send(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
672
 	client.Send(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
694
 }
673
 }
695
 
674
 
696
-func (channel *Channel) applyModeMask(client *Client, mode Mode, op ModeOp, mask string) bool {
675
+func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string) bool {
697
 	list := channel.lists[mode]
676
 	list := channel.lists[mode]
698
 	if list == nil {
677
 	if list == nil {
699
 		// This should never happen, but better safe than panicky.
678
 		// This should never happen, but better safe than panicky.
700
 		return false
679
 		return false
701
 	}
680
 	}
702
 
681
 
703
-	if (op == List) || (mask == "") {
682
+	if (op == modes.List) || (mask == "") {
704
 		channel.ShowMaskList(client, mode)
683
 		channel.ShowMaskList(client, mode)
705
 		return false
684
 		return false
706
 	}
685
 	}
707
 
686
 
708
-	if !channel.ClientIsAtLeast(client, ChannelOperator) {
687
+	if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
709
 		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
688
 		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
710
 		return false
689
 		return false
711
 	}
690
 	}
712
 
691
 
713
-	if op == Add {
692
+	if op == modes.Add {
714
 		return list.Add(mask)
693
 		return list.Add(mask)
715
 	}
694
 	}
716
 
695
 
717
-	if op == Remove {
696
+	if op == modes.Remove {
718
 		return list.Remove(mask)
697
 		return list.Remove(mask)
719
 	}
698
 	}
720
 
699
 
732
 }
711
 }
733
 
712
 
734
 func (channel *Channel) Kick(client *Client, target *Client, comment string) {
713
 func (channel *Channel) Kick(client *Client, target *Client, comment string) {
735
-	if !(client.flags[Operator] || channel.hasClient(client)) {
714
+	if !(client.flags[modes.Operator] || channel.hasClient(client)) {
736
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
715
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
737
 		return
716
 		return
738
 	}
717
 	}
739
-	if !channel.ClientIsAtLeast(client, ChannelOperator) {
718
+	if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
740
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
719
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
741
 		return
720
 		return
742
 	}
721
 	}
765
 
744
 
766
 // Invite invites the given client to the channel, if the inviter can do so.
745
 // Invite invites the given client to the channel, if the inviter can do so.
767
 func (channel *Channel) Invite(invitee *Client, inviter *Client) {
746
 func (channel *Channel) Invite(invitee *Client, inviter *Client) {
768
-	if channel.flags[InviteOnly] && !channel.ClientIsAtLeast(inviter, ChannelOperator) {
747
+	if channel.flags[modes.InviteOnly] && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
769
 		inviter.Send(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator"))
748
 		inviter.Send(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator"))
770
 		return
749
 		return
771
 	}
750
 	}
776
 	}
755
 	}
777
 
756
 
778
 	//TODO(dan): handle this more nicely, keep a list of last X invited channels on invitee rather than explicitly modifying the invite list?
757
 	//TODO(dan): handle this more nicely, keep a list of last X invited channels on invitee rather than explicitly modifying the invite list?
779
-	if channel.flags[InviteOnly] {
758
+	if channel.flags[modes.InviteOnly] {
780
 		nmc := invitee.NickCasefolded()
759
 		nmc := invitee.NickCasefolded()
781
 		channel.stateMutex.Lock()
760
 		channel.stateMutex.Lock()
782
-		channel.lists[InviteMask].Add(nmc)
761
+		channel.lists[modes.InviteMask].Add(nmc)
783
 		channel.stateMutex.Unlock()
762
 		channel.stateMutex.Unlock()
784
 	}
763
 	}
785
 
764
 
786
 	for _, member := range channel.Members() {
765
 	for _, member := range channel.Members() {
787
-		if member.capabilities.Has(caps.InviteNotify) && member != inviter && member != invitee && channel.ClientIsAtLeast(member, Halfop) {
766
+		if member.capabilities.Has(caps.InviteNotify) && member != inviter && member != invitee && channel.ClientIsAtLeast(member, modes.Halfop) {
788
 			member.Send(nil, inviter.NickMaskString(), "INVITE", invitee.Nick(), channel.name)
767
 			member.Send(nil, inviter.NickMaskString(), "INVITE", invitee.Nick(), channel.name)
789
 		}
768
 		}
790
 	}
769
 	}
792
 	//TODO(dan): should inviter.server.name here be inviter.nickMaskString ?
771
 	//TODO(dan): should inviter.server.name here be inviter.nickMaskString ?
793
 	inviter.Send(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name)
772
 	inviter.Send(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name)
794
 	invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name)
773
 	invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name)
795
-	if invitee.flags[Away] {
774
+	if invitee.flags[modes.Away] {
796
 		inviter.Send(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
775
 		inviter.Send(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
797
 	}
776
 	}
798
 }
777
 }

+ 3
- 2
irc/chanserv.go Переглянути файл

8
 	"strings"
8
 	"strings"
9
 
9
 
10
 	"github.com/goshuirc/irc-go/ircfmt"
10
 	"github.com/goshuirc/irc-go/ircfmt"
11
+	"github.com/oragono/oragono/irc/modes"
11
 	"github.com/oragono/oragono/irc/sno"
12
 	"github.com/oragono/oragono/irc/sno"
12
 )
13
 )
13
 
14
 
55
 		}
56
 		}
56
 
57
 
57
 		channelInfo := server.channels.Get(channelKey)
58
 		channelInfo := server.channels.Get(channelKey)
58
-		if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, ChannelOperator) {
59
+		if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, modes.ChannelOperator) {
59
 			client.ChanServNotice(client.t("You must be an oper on the channel to register it"))
60
 			client.ChanServNotice(client.t("You must be an oper on the channel to register it"))
60
 			return
61
 			return
61
 		}
62
 		}
81
 		server.snomasks.Send(sno.LocalChannels, fmt.Sprintf(ircfmt.Unescape("Channel registered $c[grey][$r%s$c[grey]] by $c[grey][$r%s$c[grey]]"), channelName, client.nickMaskString))
82
 		server.snomasks.Send(sno.LocalChannels, fmt.Sprintf(ircfmt.Unescape("Channel registered $c[grey][$r%s$c[grey]] by $c[grey][$r%s$c[grey]]"), channelName, client.nickMaskString))
82
 
83
 
83
 		// give them founder privs
84
 		// give them founder privs
84
-		change := channelInfo.applyModeMemberNoMutex(client, ChannelFounder, Add, client.NickCasefolded())
85
+		change := channelInfo.applyModeMemberNoMutex(client, modes.ChannelFounder, modes.Add, client.NickCasefolded())
85
 		if change != nil {
86
 		if change != nil {
86
 			//TODO(dan): we should change the name of String and make it return a slice here
87
 			//TODO(dan): we should change the name of String and make it return a slice here
87
 			//TODO(dan): unify this code with code in modes.go
88
 			//TODO(dan): unify this code with code in modes.go

+ 5
- 4
irc/client.go Переглянути файл

21
 	"github.com/goshuirc/irc-go/ircmsg"
21
 	"github.com/goshuirc/irc-go/ircmsg"
22
 	ident "github.com/oragono/go-ident"
22
 	ident "github.com/oragono/go-ident"
23
 	"github.com/oragono/oragono/irc/caps"
23
 	"github.com/oragono/oragono/irc/caps"
24
+	"github.com/oragono/oragono/irc/modes"
24
 	"github.com/oragono/oragono/irc/sno"
25
 	"github.com/oragono/oragono/irc/sno"
25
 	"github.com/oragono/oragono/irc/utils"
26
 	"github.com/oragono/oragono/irc/utils"
26
 )
27
 )
50
 	class              *OperClass
51
 	class              *OperClass
51
 	ctime              time.Time
52
 	ctime              time.Time
52
 	exitedSnomaskSent  bool
53
 	exitedSnomaskSent  bool
53
-	flags              map[Mode]bool
54
+	flags              map[modes.Mode]bool
54
 	hasQuit            bool
55
 	hasQuit            bool
55
 	hops               int
56
 	hops               int
56
 	hostname           string
57
 	hostname           string
95
 		capVersion:     caps.Cap301,
96
 		capVersion:     caps.Cap301,
96
 		channels:       make(ChannelSet),
97
 		channels:       make(ChannelSet),
97
 		ctime:          now,
98
 		ctime:          now,
98
-		flags:          make(map[Mode]bool),
99
+		flags:          make(map[modes.Mode]bool),
99
 		server:         server,
100
 		server:         server,
100
 		socket:         &socket,
101
 		socket:         &socket,
101
 		account:        &NoAccount,
102
 		account:        &NoAccount,
107
 
108
 
108
 	client.recomputeMaxlens()
109
 	client.recomputeMaxlens()
109
 	if isTLS {
110
 	if isTLS {
110
-		client.flags[TLS] = true
111
+		client.flags[modes.TLS] = true
111
 
112
 
112
 		// error is not useful to us here anyways so we can ignore it
113
 		// error is not useful to us here anyways so we can ignore it
113
 		client.certfp, _ = client.socket.CertFP()
114
 		client.certfp, _ = client.socket.CertFP()
348
 		return
349
 		return
349
 	}
350
 	}
350
 
351
 
351
-	if !oldClient.HasMode(TLS) || !client.HasMode(TLS) {
352
+	if !oldClient.HasMode(modes.TLS) || !client.HasMode(modes.TLS) {
352
 		client.Send(nil, server.name, ERR_CANNOT_RESUME, oldnick, client.t("Cannot resume connection, old and new clients must have TLS"))
353
 		client.Send(nil, server.name, ERR_CANNOT_RESUME, oldnick, client.t("Cannot resume connection, old and new clients must have TLS"))
353
 		return
354
 		return
354
 	}
355
 	}

+ 5
- 2
irc/commands.go Переглянути файл

5
 
5
 
6
 package irc
6
 package irc
7
 
7
 
8
-import "github.com/goshuirc/irc-go/ircmsg"
8
+import (
9
+	"github.com/goshuirc/irc-go/ircmsg"
10
+	"github.com/oragono/oragono/irc/modes"
11
+)
9
 
12
 
10
 // Command represents a command accepted from a client.
13
 // Command represents a command accepted from a client.
11
 type Command struct {
14
 type Command struct {
24
 		client.Send(nil, server.name, ERR_NOTREGISTERED, client.nick, client.t("You need to register before you can use that command"))
27
 		client.Send(nil, server.name, ERR_NOTREGISTERED, client.nick, client.t("You need to register before you can use that command"))
25
 		return false
28
 		return false
26
 	}
29
 	}
27
-	if cmd.oper && !client.flags[Operator] {
30
+	if cmd.oper && !client.flags[modes.Operator] {
28
 		client.Send(nil, server.name, ERR_NOPRIVILEGES, client.nick, client.t("Permission Denied - You're not an IRC operator"))
31
 		client.Send(nil, server.name, ERR_NOPRIVILEGES, client.nick, client.t("Permission Denied - You're not an IRC operator"))
29
 		return false
32
 		return false
30
 	}
33
 	}

+ 3
- 2
irc/gateways.go Переглянути файл

10
 	"fmt"
10
 	"fmt"
11
 	"net"
11
 	"net"
12
 
12
 
13
+	"github.com/oragono/oragono/irc/modes"
13
 	"github.com/oragono/oragono/irc/passwd"
14
 	"github.com/oragono/oragono/irc/passwd"
14
 	"github.com/oragono/oragono/irc/utils"
15
 	"github.com/oragono/oragono/irc/utils"
15
 )
16
 )
82
 	// set tls info
83
 	// set tls info
83
 	client.certfp = ""
84
 	client.certfp = ""
84
 	if tls {
85
 	if tls {
85
-		client.flags[TLS] = true
86
+		client.flags[modes.TLS] = true
86
 	} else {
87
 	} else {
87
-		delete(client.flags, TLS)
88
+		delete(client.flags, modes.TLS)
88
 	}
89
 	}
89
 
90
 
90
 	return false
91
 	return false

+ 8
- 5
irc/getters.go Переглянути файл

3
 
3
 
4
 package irc
4
 package irc
5
 
5
 
6
-import "github.com/oragono/oragono/irc/isupport"
6
+import (
7
+	"github.com/oragono/oragono/irc/isupport"
8
+	"github.com/oragono/oragono/irc/modes"
9
+)
7
 
10
 
8
 func (server *Server) ISupport() *isupport.List {
11
 func (server *Server) ISupport() *isupport.List {
9
 	server.configurableStateMutex.RLock()
12
 	server.configurableStateMutex.RLock()
41
 	return server.webirc
44
 	return server.webirc
42
 }
45
 }
43
 
46
 
44
-func (server *Server) DefaultChannelModes() Modes {
47
+func (server *Server) DefaultChannelModes() modes.Modes {
45
 	server.configurableStateMutex.RLock()
48
 	server.configurableStateMutex.RLock()
46
 	defer server.configurableStateMutex.RUnlock()
49
 	defer server.configurableStateMutex.RUnlock()
47
 	return server.defaultChannelModes
50
 	return server.defaultChannelModes
107
 	return client.account.Name
110
 	return client.account.Name
108
 }
111
 }
109
 
112
 
110
-func (client *Client) HasMode(mode Mode) bool {
113
+func (client *Client) HasMode(mode modes.Mode) bool {
111
 	client.stateMutex.RLock()
114
 	client.stateMutex.RLock()
112
 	defer client.stateMutex.RUnlock()
115
 	defer client.stateMutex.RUnlock()
113
 	return client.flags[mode]
116
 	return client.flags[mode]
180
 	channel.stateMutex.Unlock()
183
 	channel.stateMutex.Unlock()
181
 }
184
 }
182
 
185
 
183
-func (channel *Channel) HasMode(mode Mode) bool {
186
+func (channel *Channel) HasMode(mode modes.Mode) bool {
184
 	channel.stateMutex.RLock()
187
 	channel.stateMutex.RLock()
185
 	defer channel.stateMutex.RUnlock()
188
 	defer channel.stateMutex.RUnlock()
186
 	return channel.flags[mode]
189
 	return channel.flags[mode]
193
 }
196
 }
194
 
197
 
195
 // set a channel mode, return whether it was already set
198
 // set a channel mode, return whether it was already set
196
-func (channel *Channel) setMode(mode Mode, enable bool) (already bool) {
199
+func (channel *Channel) setMode(mode modes.Mode, enable bool) (already bool) {
197
 	channel.stateMutex.Lock()
200
 	channel.stateMutex.Lock()
198
 	already = (channel.flags[mode] == enable)
201
 	already = (channel.flags[mode] == enable)
199
 	if !already {
202
 	if !already {

+ 48
- 47
irc/handlers.go Переглянути файл

27
 	"github.com/goshuirc/irc-go/ircmsg"
27
 	"github.com/goshuirc/irc-go/ircmsg"
28
 	"github.com/oragono/oragono/irc/caps"
28
 	"github.com/oragono/oragono/irc/caps"
29
 	"github.com/oragono/oragono/irc/custime"
29
 	"github.com/oragono/oragono/irc/custime"
30
+	"github.com/oragono/oragono/irc/modes"
30
 	"github.com/oragono/oragono/irc/passwd"
31
 	"github.com/oragono/oragono/irc/passwd"
31
 	"github.com/oragono/oragono/irc/sno"
32
 	"github.com/oragono/oragono/irc/sno"
32
 	"github.com/oragono/oragono/irc/utils"
33
 	"github.com/oragono/oragono/irc/utils"
480
 	}
481
 	}
481
 
482
 
482
 	if isAway {
483
 	if isAway {
483
-		client.flags[Away] = true
484
+		client.flags[modes.Away] = true
484
 	} else {
485
 	} else {
485
-		delete(client.flags, Away)
486
+		delete(client.flags, modes.Away)
486
 	}
487
 	}
487
 	client.awayMessage = text
488
 	client.awayMessage = text
488
 
489
 
489
-	var op ModeOp
490
-	if client.flags[Away] {
491
-		op = Add
490
+	var op modes.ModeOp
491
+	if client.flags[modes.Away] {
492
+		op = modes.Add
492
 		client.Send(nil, server.name, RPL_NOWAWAY, client.nick, client.t("You have been marked as being away"))
493
 		client.Send(nil, server.name, RPL_NOWAWAY, client.nick, client.t("You have been marked as being away"))
493
 	} else {
494
 	} else {
494
-		op = Remove
495
+		op = modes.Remove
495
 		client.Send(nil, server.name, RPL_UNAWAY, client.nick, client.t("You are no longer marked as being away"))
496
 		client.Send(nil, server.name, RPL_UNAWAY, client.nick, client.t("You are no longer marked as being away"))
496
 	}
497
 	}
497
 	//TODO(dan): Should this be sent automagically as part of setting the flag/mode?
498
 	//TODO(dan): Should this be sent automagically as part of setting the flag/mode?
498
-	modech := ModeChanges{ModeChange{
499
-		mode: Away,
500
-		op:   op,
499
+	modech := modes.ModeChanges{modes.ModeChange{
500
+		Mode: modes.Away,
501
+		Op:   op,
501
 	}}
502
 	}}
502
 	client.Send(nil, server.name, "MODE", client.nick, modech.String())
503
 	client.Send(nil, server.name, "MODE", client.nick, modech.String())
503
 
504
 
504
 	// dispatch away-notify
505
 	// dispatch away-notify
505
 	for friend := range client.Friends(caps.AwayNotify) {
506
 	for friend := range client.Friends(caps.AwayNotify) {
506
-		if client.flags[Away] {
507
+		if client.flags[modes.Away] {
507
 			friend.SendFromClient("", client, nil, "AWAY", client.awayMessage)
508
 			friend.SendFromClient("", client, nil, "AWAY", client.awayMessage)
508
 		} else {
509
 		} else {
509
 			friend.SendFromClient("", client, nil, "AWAY")
510
 			friend.SendFromClient("", client, nil, "AWAY")
581
 
582
 
582
 // DEBUG GCSTATS/NUMGOROUTINE/etc
583
 // DEBUG GCSTATS/NUMGOROUTINE/etc
583
 func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
584
 func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
584
-	if !client.flags[Operator] {
585
+	if !client.flags[modes.Operator] {
585
 		return false
586
 		return false
586
 	}
587
 	}
587
 
588
 
854
 
855
 
855
 	// handle index
856
 	// handle index
856
 	if argument == "index" {
857
 	if argument == "index" {
857
-		if client.flags[Operator] {
858
+		if client.flags[modes.Operator] {
858
 			client.sendHelp("HELP", GetHelpIndex(client.languages, HelpIndexOpers))
859
 			client.sendHelp("HELP", GetHelpIndex(client.languages, HelpIndexOpers))
859
 		} else {
860
 		} else {
860
 			client.sendHelp("HELP", GetHelpIndex(client.languages, HelpIndex))
861
 			client.sendHelp("HELP", GetHelpIndex(client.languages, HelpIndex))
864
 
865
 
865
 	helpHandler, exists := Help[argument]
866
 	helpHandler, exists := Help[argument]
866
 
867
 
867
-	if exists && (!helpHandler.oper || (helpHandler.oper && client.flags[Operator])) {
868
+	if exists && (!helpHandler.oper || (helpHandler.oper && client.flags[modes.Operator])) {
868
 		if helpHandler.textGenerator != nil {
869
 		if helpHandler.textGenerator != nil {
869
 			client.sendHelp(strings.ToUpper(argument), client.t(helpHandler.textGenerator(client)))
870
 			client.sendHelp(strings.ToUpper(argument), client.t(helpHandler.textGenerator(client)))
870
 		} else {
871
 		} else {
1336
 
1337
 
1337
 	if len(channels) == 0 {
1338
 	if len(channels) == 0 {
1338
 		for _, channel := range server.channels.Channels() {
1339
 		for _, channel := range server.channels.Channels() {
1339
-			if !client.flags[Operator] && channel.flags[Secret] {
1340
+			if !client.flags[modes.Operator] && channel.flags[modes.Secret] {
1340
 				continue
1341
 				continue
1341
 			}
1342
 			}
1342
 			if matcher.Matches(channel) {
1343
 			if matcher.Matches(channel) {
1345
 		}
1346
 		}
1346
 	} else {
1347
 	} else {
1347
 		// limit regular users to only listing one channel
1348
 		// limit regular users to only listing one channel
1348
-		if !client.flags[Operator] {
1349
+		if !client.flags[modes.Operator] {
1349
 			channels = channels[:1]
1350
 			channels = channels[:1]
1350
 		}
1351
 		}
1351
 
1352
 
1352
 		for _, chname := range channels {
1353
 		for _, chname := range channels {
1353
 			casefoldedChname, err := CasefoldChannel(chname)
1354
 			casefoldedChname, err := CasefoldChannel(chname)
1354
 			channel := server.channels.Get(casefoldedChname)
1355
 			channel := server.channels.Get(casefoldedChname)
1355
-			if err != nil || channel == nil || (!client.flags[Operator] && channel.flags[Secret]) {
1356
+			if err != nil || channel == nil || (!client.flags[modes.Operator] && channel.flags[modes.Secret]) {
1356
 				if len(chname) > 0 {
1357
 				if len(chname) > 0 {
1357
 					client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel"))
1358
 					client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel"))
1358
 				}
1359
 				}
1374
 
1375
 
1375
 	for _, onlineusers := range server.clients.AllClients() {
1376
 	for _, onlineusers := range server.clients.AllClients() {
1376
 		totalcount++
1377
 		totalcount++
1377
-		if onlineusers.flags[Invisible] {
1378
+		if onlineusers.flags[modes.Invisible] {
1378
 			invisiblecount++
1379
 			invisiblecount++
1379
 		}
1380
 		}
1380
-		if onlineusers.flags[Operator] {
1381
+		if onlineusers.flags[modes.Operator] {
1381
 			opercount++
1382
 			opercount++
1382
 		}
1383
 		}
1383
 	}
1384
 	}
1409
 	}
1410
 	}
1410
 
1411
 
1411
 	// applied mode changes
1412
 	// applied mode changes
1412
-	applied := make(ModeChanges, 0)
1413
+	applied := make(modes.ModeChanges, 0)
1413
 
1414
 
1414
 	if 1 < len(msg.Params) {
1415
 	if 1 < len(msg.Params) {
1415
 		// parse out real mode changes
1416
 		// parse out real mode changes
1431
 	// save changes to banlist/exceptlist/invexlist
1432
 	// save changes to banlist/exceptlist/invexlist
1432
 	var banlistUpdated, exceptlistUpdated, invexlistUpdated bool
1433
 	var banlistUpdated, exceptlistUpdated, invexlistUpdated bool
1433
 	for _, change := range applied {
1434
 	for _, change := range applied {
1434
-		if change.mode == BanMask {
1435
+		if change.Mode == modes.BanMask {
1435
 			banlistUpdated = true
1436
 			banlistUpdated = true
1436
-		} else if change.mode == ExceptMask {
1437
+		} else if change.Mode == modes.ExceptMask {
1437
 			exceptlistUpdated = true
1438
 			exceptlistUpdated = true
1438
-		} else if change.mode == InviteMask {
1439
+		} else if change.Mode == modes.InviteMask {
1439
 			invexlistUpdated = true
1440
 			invexlistUpdated = true
1440
 		}
1441
 		}
1441
 	}
1442
 	}
1483
 	}
1484
 	}
1484
 
1485
 
1485
 	// applied mode changes
1486
 	// applied mode changes
1486
-	applied := make(ModeChanges, 0)
1487
+	applied := make(modes.ModeChanges, 0)
1487
 
1488
 
1488
 	if 1 < len(msg.Params) {
1489
 	if 1 < len(msg.Params) {
1489
 		// parse out real mode changes
1490
 		// parse out real mode changes
1490
 		params := msg.Params[1:]
1491
 		params := msg.Params[1:]
1491
-		changes, unknown := ParseUserModeChanges(params...)
1492
+		changes, unknown := modes.ParseUserModeChanges(params...)
1492
 
1493
 
1493
 		// alert for unknown mode changes
1494
 		// alert for unknown mode changes
1494
 		for char := range unknown {
1495
 		for char := range unknown {
1506
 		client.Send(nil, client.nickMaskString, "MODE", targetNick, applied.String())
1507
 		client.Send(nil, client.nickMaskString, "MODE", targetNick, applied.String())
1507
 	} else if hasPrivs {
1508
 	} else if hasPrivs {
1508
 		client.Send(nil, target.nickMaskString, RPL_UMODEIS, targetNick, target.ModeString())
1509
 		client.Send(nil, target.nickMaskString, RPL_UMODEIS, targetNick, target.ModeString())
1509
-		if client.flags[LocalOperator] || client.flags[Operator] {
1510
+		if client.flags[modes.LocalOperator] || client.flags[modes.Operator] {
1510
 			masks := server.snomasks.String(client)
1511
 			masks := server.snomasks.String(client)
1511
 			if 0 < len(masks) {
1512
 			if 0 < len(masks) {
1512
 				client.Send(nil, target.nickMaskString, RPL_SNOMASKIS, targetNick, masks, client.t("Server notice masks"))
1513
 				client.Send(nil, target.nickMaskString, RPL_SNOMASKIS, targetNick, masks, client.t("Server notice masks"))
1687
 		if i > maxTargets-1 {
1688
 		if i > maxTargets-1 {
1688
 			break
1689
 			break
1689
 		}
1690
 		}
1690
-		prefixes, targetString := SplitChannelMembershipPrefixes(targetString)
1691
-		lowestPrefix := GetLowestChannelModePrefix(prefixes)
1691
+		prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
1692
+		lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
1692
 
1693
 
1693
 		target, cerr := CasefoldChannel(targetString)
1694
 		target, cerr := CasefoldChannel(targetString)
1694
 		if cerr == nil {
1695
 		if cerr == nil {
1727
 			msgid := server.generateMessageID()
1728
 			msgid := server.generateMessageID()
1728
 			// restrict messages appropriately when +R is set
1729
 			// restrict messages appropriately when +R is set
1729
 			// intentionally make the sending user think the message went through fine
1730
 			// intentionally make the sending user think the message went through fine
1730
-			if !user.flags[RegisteredOnly] || client.registered {
1731
+			if !user.flags[modes.RegisteredOnly] || client.registered {
1731
 				user.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "NOTICE", user.nick, splitMsg)
1732
 				user.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "NOTICE", user.nick, splitMsg)
1732
 			}
1733
 			}
1733
 			if client.capabilities.Has(caps.EchoMessage) {
1734
 			if client.capabilities.Has(caps.EchoMessage) {
1788
 		client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, client.t("Password incorrect"))
1789
 		client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, client.t("Password incorrect"))
1789
 		return true
1790
 		return true
1790
 	}
1791
 	}
1791
-	if client.flags[Operator] == true {
1792
+	if client.flags[modes.Operator] == true {
1792
 		client.Send(nil, server.name, ERR_UNKNOWNERROR, "OPER", client.t("You're already opered-up!"))
1793
 		client.Send(nil, server.name, ERR_UNKNOWNERROR, "OPER", client.t("You're already opered-up!"))
1793
 		return false
1794
 		return false
1794
 	}
1795
 	}
1803
 		return true
1804
 		return true
1804
 	}
1805
 	}
1805
 
1806
 
1806
-	client.flags[Operator] = true
1807
+	client.flags[modes.Operator] = true
1807
 	client.operName = name
1808
 	client.operName = name
1808
 	client.class = oper.Class
1809
 	client.class = oper.Class
1809
 	client.whoisLine = oper.WhoisLine
1810
 	client.whoisLine = oper.WhoisLine
1819
 	}
1820
 	}
1820
 
1821
 
1821
 	// set new modes
1822
 	// set new modes
1822
-	var applied ModeChanges
1823
+	var applied modes.ModeChanges
1823
 	if 0 < len(oper.Modes) {
1824
 	if 0 < len(oper.Modes) {
1824
-		modeChanges, unknownChanges := ParseUserModeChanges(strings.Split(oper.Modes, " ")...)
1825
+		modeChanges, unknownChanges := modes.ParseUserModeChanges(strings.Split(oper.Modes, " ")...)
1825
 		applied = client.applyUserModeChanges(true, modeChanges)
1826
 		applied = client.applyUserModeChanges(true, modeChanges)
1826
 		if 0 < len(unknownChanges) {
1827
 		if 0 < len(unknownChanges) {
1827
 			var runes string
1828
 			var runes string
1834
 
1835
 
1835
 	client.Send(nil, server.name, RPL_YOUREOPER, client.nick, client.t("You are now an IRC operator"))
1836
 	client.Send(nil, server.name, RPL_YOUREOPER, client.nick, client.t("You are now an IRC operator"))
1836
 
1837
 
1837
-	applied = append(applied, ModeChange{
1838
-		mode: Operator,
1839
-		op:   Add,
1838
+	applied = append(applied, modes.ModeChange{
1839
+		Mode: modes.Operator,
1840
+		Op:   modes.Add,
1840
 	})
1841
 	})
1841
 	client.Send(nil, server.name, "MODE", client.nick, applied.String())
1842
 	client.Send(nil, server.name, "MODE", client.nick, applied.String())
1842
 
1843
 
1912
 		if i > maxTargets-1 {
1913
 		if i > maxTargets-1 {
1913
 			break
1914
 			break
1914
 		}
1915
 		}
1915
-		prefixes, targetString := SplitChannelMembershipPrefixes(targetString)
1916
-		lowestPrefix := GetLowestChannelModePrefix(prefixes)
1916
+		prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
1917
+		lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
1917
 
1918
 
1918
 		// eh, no need to notify them
1919
 		// eh, no need to notify them
1919
 		if len(targetString) < 1 {
1920
 		if len(targetString) < 1 {
1955
 			msgid := server.generateMessageID()
1956
 			msgid := server.generateMessageID()
1956
 			// restrict messages appropriately when +R is set
1957
 			// restrict messages appropriately when +R is set
1957
 			// intentionally make the sending user think the message went through fine
1958
 			// intentionally make the sending user think the message went through fine
1958
-			if !user.flags[RegisteredOnly] || client.registered {
1959
+			if !user.flags[modes.RegisteredOnly] || client.registered {
1959
 				user.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
1960
 				user.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
1960
 			}
1961
 			}
1961
 			if client.capabilities.Has(caps.EchoMessage) {
1962
 			if client.capabilities.Has(caps.EchoMessage) {
1962
 				client.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
1963
 				client.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
1963
 			}
1964
 			}
1964
-			if user.flags[Away] {
1965
+			if user.flags[modes.Away] {
1965
 				//TODO(dan): possibly implement cooldown of away notifications to users
1966
 				//TODO(dan): possibly implement cooldown of away notifications to users
1966
 				client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
1967
 				client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
1967
 			}
1968
 			}
2059
 		return
2060
 		return
2060
 	}
2061
 	}
2061
 	//TODO(dan): allow IRCops to do this?
2062
 	//TODO(dan): allow IRCops to do this?
2062
-	if !channel.ClientIsAtLeast(client, Operator) {
2063
+	if !channel.ClientIsAtLeast(client, modes.Operator) {
2063
 		errorResponse(RenamePrivsNeeded, oldName)
2064
 		errorResponse(RenamePrivsNeeded, oldName)
2064
 		return
2065
 		return
2065
 	}
2066
 	}
2171
 		if i > maxTargets-1 {
2172
 		if i > maxTargets-1 {
2172
 			break
2173
 			break
2173
 		}
2174
 		}
2174
-		prefixes, targetString := SplitChannelMembershipPrefixes(targetString)
2175
-		lowestPrefix := GetLowestChannelModePrefix(prefixes)
2175
+		prefixes, targetString := modes.SplitChannelMembershipPrefixes(targetString)
2176
+		lowestPrefix := modes.GetLowestChannelModePrefix(prefixes)
2176
 
2177
 
2177
 		// eh, no need to notify them
2178
 		// eh, no need to notify them
2178
 		if len(targetString) < 1 {
2179
 		if len(targetString) < 1 {
2212
 			if client.capabilities.Has(caps.EchoMessage) {
2213
 			if client.capabilities.Has(caps.EchoMessage) {
2213
 				client.SendFromClient(msgid, client, clientOnlyTags, "TAGMSG", user.nick)
2214
 				client.SendFromClient(msgid, client, clientOnlyTags, "TAGMSG", user.nick)
2214
 			}
2215
 			}
2215
-			if user.flags[Away] {
2216
+			if user.flags[modes.Away] {
2216
 				//TODO(dan): possibly implement cooldown of away notifications to users
2217
 				//TODO(dan): possibly implement cooldown of away notifications to users
2217
 				client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
2218
 				client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
2218
 			}
2219
 			}
2424
 
2425
 
2425
 		var isOper, isAway string
2426
 		var isOper, isAway string
2426
 
2427
 
2427
-		if target.flags[Operator] {
2428
+		if target.flags[modes.Operator] {
2428
 			isOper = "*"
2429
 			isOper = "*"
2429
 		}
2430
 		}
2430
-		if target.flags[Away] {
2431
+		if target.flags[modes.Away] {
2431
 			isAway = "-"
2432
 			isAway = "-"
2432
 		} else {
2433
 		} else {
2433
 			isAway = "+"
2434
 			isAway = "+"
2478
 			lkey := strings.ToLower(key)
2479
 			lkey := strings.ToLower(key)
2479
 			if lkey == "tls" || lkey == "secure" {
2480
 			if lkey == "tls" || lkey == "secure" {
2480
 				// only accept "tls" flag if the gateway's connection to us is secure as well
2481
 				// only accept "tls" flag if the gateway's connection to us is secure as well
2481
-				if client.flags[TLS] || utils.AddrIsLocal(client.socket.conn.RemoteAddr()) {
2482
+				if client.flags[modes.TLS] || utils.AddrIsLocal(client.socket.conn.RemoteAddr()) {
2482
 					secure = true
2483
 					secure = true
2483
 				}
2484
 				}
2484
 			}
2485
 			}
2567
 		return false
2568
 		return false
2568
 	}
2569
 	}
2569
 
2570
 
2570
-	if client.flags[Operator] {
2571
+	if client.flags[modes.Operator] {
2571
 		masks := strings.Split(masksString, ",")
2572
 		masks := strings.Split(masksString, ",")
2572
 		for _, mask := range masks {
2573
 		for _, mask := range masks {
2573
 			casefoldedMask, err := Casefold(mask)
2574
 			casefoldedMask, err := Casefold(mask)

+ 88
- 327
irc/modes.go Переглянути файл

9
 	"strconv"
9
 	"strconv"
10
 	"strings"
10
 	"strings"
11
 
11
 
12
+	"github.com/oragono/oragono/irc/modes"
12
 	"github.com/oragono/oragono/irc/sno"
13
 	"github.com/oragono/oragono/irc/sno"
13
 )
14
 )
14
 
15
 
15
-// ModeOp is an operation performed with modes
16
-type ModeOp rune
17
-
18
-func (op ModeOp) String() string {
19
-	return string(op)
20
-}
21
-
22
-const (
23
-	// Add is used when adding the given key.
24
-	Add ModeOp = '+'
25
-	// List is used when listing modes (for instance, listing the current bans on a channel).
26
-	List ModeOp = '='
27
-	// Remove is used when taking away the given key.
28
-	Remove ModeOp = '-'
29
-)
30
-
31
-// Mode represents a user/channel/server mode
32
-type Mode rune
33
-
34
-func (mode Mode) String() string {
35
-	return string(mode)
36
-}
37
-
38
-// ModeChange is a single mode changing
39
-type ModeChange struct {
40
-	mode Mode
41
-	op   ModeOp
42
-	arg  string
43
-}
44
-
45
-func (change *ModeChange) String() (str string) {
46
-	if (change.op == Add) || (change.op == Remove) {
47
-		str = change.op.String()
48
-	}
49
-	str += change.mode.String()
50
-	if change.arg != "" {
51
-		str += " " + change.arg
52
-	}
53
-	return
54
-}
55
-
56
-// ModeChanges are a collection of 'ModeChange's
57
-type ModeChanges []ModeChange
58
-
59
-func (changes ModeChanges) String() string {
60
-	if len(changes) == 0 {
61
-		return ""
62
-	}
63
-
64
-	op := changes[0].op
65
-	str := changes[0].op.String()
66
-
67
-	for _, change := range changes {
68
-		if change.op != op {
69
-			op = change.op
70
-			str += change.op.String()
71
-		}
72
-		str += change.mode.String()
73
-	}
74
-
75
-	for _, change := range changes {
76
-		if change.arg == "" {
77
-			continue
78
-		}
79
-		str += " " + change.arg
80
-	}
81
-	return str
82
-}
83
-
84
-// Modes is just a raw list of modes
85
-type Modes []Mode
86
-
87
-func (modes Modes) String() string {
88
-	strs := make([]string, len(modes))
89
-	for index, mode := range modes {
90
-		strs[index] = mode.String()
91
-	}
92
-	return strings.Join(strs, "")
93
-}
94
-
95
-// User Modes
96
-const (
97
-	Away            Mode = 'a'
98
-	Bot             Mode = 'B'
99
-	Invisible       Mode = 'i'
100
-	LocalOperator   Mode = 'O'
101
-	Operator        Mode = 'o'
102
-	Restricted      Mode = 'r'
103
-	RegisteredOnly  Mode = 'R'
104
-	ServerNotice    Mode = 's'
105
-	TLS             Mode = 'Z'
106
-	UserRoleplaying Mode = 'E'
107
-	WallOps         Mode = 'w'
108
-)
109
-
110
-var (
111
-	// SupportedUserModes are the user modes that we actually support (modifying).
112
-	SupportedUserModes = Modes{
113
-		Away, Bot, Invisible, Operator, RegisteredOnly, ServerNotice, UserRoleplaying,
114
-	}
115
-	// supportedUserModesString acts as a cache for when we introduce users
116
-	supportedUserModesString = SupportedUserModes.String()
117
-)
118
-
119
-// Channel Modes
120
-const (
121
-	BanMask         Mode = 'b' // arg
122
-	ChanRoleplaying Mode = 'E' // flag
123
-	ExceptMask      Mode = 'e' // arg
124
-	InviteMask      Mode = 'I' // arg
125
-	InviteOnly      Mode = 'i' // flag
126
-	Key             Mode = 'k' // flag arg
127
-	Moderated       Mode = 'm' // flag
128
-	NoOutside       Mode = 'n' // flag
129
-	OpOnlyTopic     Mode = 't' // flag
130
-	// RegisteredOnly mode is reused here from umode definition
131
-	Secret    Mode = 's' // flag
132
-	UserLimit Mode = 'l' // flag arg
133
-)
134
-
135
 var (
16
 var (
136
-	ChannelFounder  Mode = 'q' // arg
137
-	ChannelAdmin    Mode = 'a' // arg
138
-	ChannelOperator Mode = 'o' // arg
139
-	Halfop          Mode = 'h' // arg
140
-	Voice           Mode = 'v' // arg
141
-
142
-	// SupportedChannelModes are the channel modes that we support.
143
-	SupportedChannelModes = Modes{
144
-		BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
145
-		Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, Secret, UserLimit,
146
-	}
147
-	// supportedChannelModesString acts as a cache for when we introduce users
148
-	supportedChannelModesString = SupportedChannelModes.String()
149
-
150
 	// DefaultChannelModes are enabled on brand new channels when they're created.
17
 	// DefaultChannelModes are enabled on brand new channels when they're created.
151
 	// this can be overridden in the `channels` config, with the `default-modes` key
18
 	// this can be overridden in the `channels` config, with the `default-modes` key
152
-	DefaultChannelModes = Modes{
153
-		NoOutside, OpOnlyTopic,
154
-	}
155
-
156
-	// ChannelPrivModes holds the list of modes that are privileged, ie founder/op/halfop, in order.
157
-	// voice is not in this list because it cannot perform channel operator actions.
158
-	ChannelPrivModes = Modes{
159
-		ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
160
-	}
161
-
162
-	ChannelModePrefixes = map[Mode]string{
163
-		ChannelFounder:  "~",
164
-		ChannelAdmin:    "&",
165
-		ChannelOperator: "@",
166
-		Halfop:          "%",
167
-		Voice:           "+",
19
+	DefaultChannelModes = modes.Modes{
20
+		modes.NoOutside, modes.OpOnlyTopic,
168
 	}
21
 	}
169
 )
22
 )
170
 
23
 
171
-//
172
-// channel membership prefixes
173
-//
174
-
175
-// SplitChannelMembershipPrefixes takes a target and returns the prefixes on it, then the name.
176
-func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) {
177
-	name = target
178
-	for {
179
-		if len(name) > 0 && strings.Contains("~&@%+", string(name[0])) {
180
-			prefixes += string(name[0])
181
-			name = name[1:]
182
-		} else {
183
-			break
184
-		}
185
-	}
186
-
187
-	return prefixes, name
188
-}
189
-
190
-// GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes.
191
-func GetLowestChannelModePrefix(prefixes string) *Mode {
192
-	var lowest *Mode
193
-
194
-	if strings.Contains(prefixes, "+") {
195
-		lowest = &Voice
196
-	} else {
197
-		for i, mode := range ChannelPrivModes {
198
-			if strings.Contains(prefixes, ChannelModePrefixes[mode]) {
199
-				lowest = &ChannelPrivModes[i]
200
-			}
201
-		}
202
-	}
203
-
204
-	return lowest
205
-}
206
-
207
-//
208
-// commands
209
-//
210
-
211
-// ParseUserModeChanges returns the valid changes, and the list of unknown chars.
212
-func ParseUserModeChanges(params ...string) (ModeChanges, map[rune]bool) {
213
-	changes := make(ModeChanges, 0)
214
-	unknown := make(map[rune]bool)
215
-
216
-	op := List
217
-
218
-	if 0 < len(params) {
219
-		modeArg := params[0]
220
-		skipArgs := 1
221
-
222
-		for _, mode := range modeArg {
223
-			if mode == '-' || mode == '+' {
224
-				op = ModeOp(mode)
225
-				continue
226
-			}
227
-			change := ModeChange{
228
-				mode: Mode(mode),
229
-				op:   op,
230
-			}
231
-
232
-			// put arg into modechange if needed
233
-			switch Mode(mode) {
234
-			case ServerNotice:
235
-				// always require arg
236
-				if len(params) > skipArgs {
237
-					change.arg = params[skipArgs]
238
-					skipArgs++
239
-				} else {
240
-					continue
241
-				}
242
-			}
243
-
244
-			var isKnown bool
245
-			for _, supportedMode := range SupportedUserModes {
246
-				if rune(supportedMode) == mode {
247
-					isKnown = true
248
-					break
249
-				}
250
-			}
251
-			if !isKnown {
252
-				unknown[mode] = true
253
-				continue
254
-			}
255
-
256
-			changes = append(changes, change)
257
-		}
258
-	}
259
-
260
-	return changes, unknown
261
-}
262
-
263
 // applyUserModeChanges applies the given changes, and returns the applied changes.
24
 // applyUserModeChanges applies the given changes, and returns the applied changes.
264
-func (client *Client) applyUserModeChanges(force bool, changes ModeChanges) ModeChanges {
265
-	applied := make(ModeChanges, 0)
25
+func (client *Client) applyUserModeChanges(force bool, changes modes.ModeChanges) modes.ModeChanges {
26
+	applied := make(modes.ModeChanges, 0)
266
 
27
 
267
 	for _, change := range changes {
28
 	for _, change := range changes {
268
-		switch change.mode {
269
-		case Bot, Invisible, WallOps, UserRoleplaying, Operator, LocalOperator, RegisteredOnly:
270
-			switch change.op {
271
-			case Add:
272
-				if !force && (change.mode == Operator || change.mode == LocalOperator) {
29
+		switch change.Mode {
30
+		case modes.Bot, modes.Invisible, modes.WallOps, modes.UserRoleplaying, modes.Operator, modes.LocalOperator, modes.RegisteredOnly:
31
+			switch change.Op {
32
+			case modes.Add:
33
+				if !force && (change.Mode == modes.Operator || change.Mode == modes.LocalOperator) {
273
 					continue
34
 					continue
274
 				}
35
 				}
275
 
36
 
276
-				if client.flags[change.mode] {
37
+				if client.flags[change.Mode] {
277
 					continue
38
 					continue
278
 				}
39
 				}
279
-				client.flags[change.mode] = true
40
+				client.flags[change.Mode] = true
280
 				applied = append(applied, change)
41
 				applied = append(applied, change)
281
 
42
 
282
-			case Remove:
283
-				if !client.flags[change.mode] {
43
+			case modes.Remove:
44
+				if !client.flags[change.Mode] {
284
 					continue
45
 					continue
285
 				}
46
 				}
286
-				delete(client.flags, change.mode)
47
+				delete(client.flags, change.Mode)
287
 				applied = append(applied, change)
48
 				applied = append(applied, change)
288
 			}
49
 			}
289
 
50
 
290
-		case ServerNotice:
291
-			if !client.flags[Operator] {
51
+		case modes.ServerNotice:
52
+			if !client.flags[modes.Operator] {
292
 				continue
53
 				continue
293
 			}
54
 			}
294
 			var masks []sno.Mask
55
 			var masks []sno.Mask
295
-			if change.op == Add || change.op == Remove {
296
-				for _, char := range change.arg {
56
+			if change.Op == modes.Add || change.Op == modes.Remove {
57
+				for _, char := range change.Arg {
297
 					masks = append(masks, sno.Mask(char))
58
 					masks = append(masks, sno.Mask(char))
298
 				}
59
 				}
299
 			}
60
 			}
300
-			if change.op == Add {
61
+			if change.Op == modes.Add {
301
 				client.server.snomasks.AddMasks(client, masks...)
62
 				client.server.snomasks.AddMasks(client, masks...)
302
 				applied = append(applied, change)
63
 				applied = append(applied, change)
303
-			} else if change.op == Remove {
64
+			} else if change.Op == modes.Remove {
304
 				client.server.snomasks.RemoveMasks(client, masks...)
65
 				client.server.snomasks.RemoveMasks(client, masks...)
305
 				applied = append(applied, change)
66
 				applied = append(applied, change)
306
 			}
67
 			}
314
 }
75
 }
315
 
76
 
316
 // ParseDefaultChannelModes parses the `default-modes` line of the config
77
 // ParseDefaultChannelModes parses the `default-modes` line of the config
317
-func ParseDefaultChannelModes(config *Config) Modes {
78
+func ParseDefaultChannelModes(config *Config) modes.Modes {
318
 	if config.Channels.DefaultModes == nil {
79
 	if config.Channels.DefaultModes == nil {
319
 		// not present in config, fall back to compile-time default
80
 		// not present in config, fall back to compile-time default
320
 		return DefaultChannelModes
81
 		return DefaultChannelModes
321
 	}
82
 	}
322
 	modeChangeStrings := strings.Split(strings.TrimSpace(*config.Channels.DefaultModes), " ")
83
 	modeChangeStrings := strings.Split(strings.TrimSpace(*config.Channels.DefaultModes), " ")
323
 	modeChanges, _ := ParseChannelModeChanges(modeChangeStrings...)
84
 	modeChanges, _ := ParseChannelModeChanges(modeChangeStrings...)
324
-	defaultChannelModes := make(Modes, 0)
85
+	defaultChannelModes := make(modes.Modes, 0)
325
 	for _, modeChange := range modeChanges {
86
 	for _, modeChange := range modeChanges {
326
-		if modeChange.op == Add {
327
-			defaultChannelModes = append(defaultChannelModes, modeChange.mode)
87
+		if modeChange.Op == modes.Add {
88
+			defaultChannelModes = append(defaultChannelModes, modeChange.Mode)
328
 		}
89
 		}
329
 	}
90
 	}
330
 	return defaultChannelModes
91
 	return defaultChannelModes
331
 }
92
 }
332
 
93
 
333
 // ParseChannelModeChanges returns the valid changes, and the list of unknown chars.
94
 // ParseChannelModeChanges returns the valid changes, and the list of unknown chars.
334
-func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
335
-	changes := make(ModeChanges, 0)
95
+func ParseChannelModeChanges(params ...string) (modes.ModeChanges, map[rune]bool) {
96
+	changes := make(modes.ModeChanges, 0)
336
 	unknown := make(map[rune]bool)
97
 	unknown := make(map[rune]bool)
337
 
98
 
338
-	op := List
99
+	op := modes.List
339
 
100
 
340
 	if 0 < len(params) {
101
 	if 0 < len(params) {
341
 		modeArg := params[0]
102
 		modeArg := params[0]
343
 
104
 
344
 		for _, mode := range modeArg {
105
 		for _, mode := range modeArg {
345
 			if mode == '-' || mode == '+' {
106
 			if mode == '-' || mode == '+' {
346
-				op = ModeOp(mode)
107
+				op = modes.ModeOp(mode)
347
 				continue
108
 				continue
348
 			}
109
 			}
349
-			change := ModeChange{
350
-				mode: Mode(mode),
351
-				op:   op,
110
+			change := modes.ModeChange{
111
+				Mode: modes.Mode(mode),
112
+				Op:   op,
352
 			}
113
 			}
353
 
114
 
354
 			// put arg into modechange if needed
115
 			// put arg into modechange if needed
355
-			switch Mode(mode) {
356
-			case BanMask, ExceptMask, InviteMask:
116
+			switch modes.Mode(mode) {
117
+			case modes.BanMask, modes.ExceptMask, modes.InviteMask:
357
 				if len(params) > skipArgs {
118
 				if len(params) > skipArgs {
358
-					change.arg = params[skipArgs]
119
+					change.Arg = params[skipArgs]
359
 					skipArgs++
120
 					skipArgs++
360
 				} else {
121
 				} else {
361
-					change.op = List
122
+					change.Op = modes.List
362
 				}
123
 				}
363
-			case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
124
+			case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
364
 				if len(params) > skipArgs {
125
 				if len(params) > skipArgs {
365
-					change.arg = params[skipArgs]
126
+					change.Arg = params[skipArgs]
366
 					skipArgs++
127
 					skipArgs++
367
 				} else {
128
 				} else {
368
 					continue
129
 					continue
369
 				}
130
 				}
370
-			case Key, UserLimit:
131
+			case modes.Key, modes.UserLimit:
371
 				// don't require value when removing
132
 				// don't require value when removing
372
-				if change.op == Add {
133
+				if change.Op == modes.Add {
373
 					if len(params) > skipArgs {
134
 					if len(params) > skipArgs {
374
-						change.arg = params[skipArgs]
135
+						change.Arg = params[skipArgs]
375
 						skipArgs++
136
 						skipArgs++
376
 					} else {
137
 					} else {
377
 						continue
138
 						continue
380
 			}
141
 			}
381
 
142
 
382
 			var isKnown bool
143
 			var isKnown bool
383
-			for _, supportedMode := range SupportedChannelModes {
144
+			for _, supportedMode := range modes.SupportedChannelModes {
384
 				if rune(supportedMode) == mode {
145
 				if rune(supportedMode) == mode {
385
 					isKnown = true
146
 					isKnown = true
386
 					break
147
 					break
387
 				}
148
 				}
388
 			}
149
 			}
389
-			for _, supportedMode := range ChannelPrivModes {
150
+			for _, supportedMode := range modes.ChannelPrivModes {
390
 				if rune(supportedMode) == mode {
151
 				if rune(supportedMode) == mode {
391
 					isKnown = true
152
 					isKnown = true
392
 					break
153
 					break
393
 				}
154
 				}
394
 			}
155
 			}
395
-			if mode == rune(Voice) {
156
+			if mode == rune(modes.Voice) {
396
 				isKnown = true
157
 				isKnown = true
397
 			}
158
 			}
398
 			if !isKnown {
159
 			if !isKnown {
408
 }
169
 }
409
 
170
 
410
 // ApplyChannelModeChanges applies a given set of mode changes.
171
 // ApplyChannelModeChanges applies a given set of mode changes.
411
-func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes ModeChanges) ModeChanges {
172
+func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges) modes.ModeChanges {
412
 	// so we only output one warning for each list type when full
173
 	// so we only output one warning for each list type when full
413
-	listFullWarned := make(map[Mode]bool)
174
+	listFullWarned := make(map[modes.Mode]bool)
414
 
175
 
415
-	clientIsOp := channel.ClientIsAtLeast(client, ChannelOperator)
176
+	clientIsOp := channel.ClientIsAtLeast(client, modes.ChannelOperator)
416
 	var alreadySentPrivError bool
177
 	var alreadySentPrivError bool
417
 
178
 
418
-	applied := make(ModeChanges, 0)
179
+	applied := make(modes.ModeChanges, 0)
419
 
180
 
420
-	isListOp := func(change ModeChange) bool {
421
-		return (change.op == List) || (change.arg == "")
181
+	isListOp := func(change modes.ModeChange) bool {
182
+		return (change.Op == modes.List) || (change.Arg == "")
422
 	}
183
 	}
423
 
184
 
424
-	hasPrivs := func(change ModeChange) bool {
185
+	hasPrivs := func(change modes.ModeChange) bool {
425
 		if isSamode {
186
 		if isSamode {
426
 			return true
187
 			return true
427
 		}
188
 		}
428
-		switch change.mode {
429
-		case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
189
+		switch change.Mode {
190
+		case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
430
 			// Admins can't give other people Admin or remove it from others
191
 			// Admins can't give other people Admin or remove it from others
431
-			if change.mode == ChannelAdmin {
192
+			if change.Mode == modes.ChannelAdmin {
432
 				return false
193
 				return false
433
 			}
194
 			}
434
-			if change.op == List {
195
+			if change.Op == modes.List {
435
 				return true
196
 				return true
436
 			}
197
 			}
437
-			cfarg, _ := CasefoldName(change.arg)
438
-			if change.op == Remove && cfarg == client.nickCasefolded {
198
+			cfarg, _ := CasefoldName(change.Arg)
199
+			if change.Op == modes.Remove && cfarg == client.nickCasefolded {
439
 				// "There is no restriction, however, on anyone `deopping' themselves"
200
 				// "There is no restriction, however, on anyone `deopping' themselves"
440
 				// <https://tools.ietf.org/html/rfc2812#section-3.1.5>
201
 				// <https://tools.ietf.org/html/rfc2812#section-3.1.5>
441
 				return true
202
 				return true
442
 			}
203
 			}
443
-			return channel.ClientIsAtLeast(client, change.mode)
444
-		case BanMask:
204
+			return channel.ClientIsAtLeast(client, change.Mode)
205
+		case modes.BanMask:
445
 			// #163: allow unprivileged users to list ban masks
206
 			// #163: allow unprivileged users to list ban masks
446
 			return clientIsOp || isListOp(change)
207
 			return clientIsOp || isListOp(change)
447
 		default:
208
 		default:
458
 			continue
219
 			continue
459
 		}
220
 		}
460
 
221
 
461
-		switch change.mode {
462
-		case BanMask, ExceptMask, InviteMask:
222
+		switch change.Mode {
223
+		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
463
 			if isListOp(change) {
224
 			if isListOp(change) {
464
-				channel.ShowMaskList(client, change.mode)
225
+				channel.ShowMaskList(client, change.Mode)
465
 				continue
226
 				continue
466
 			}
227
 			}
467
 
228
 
468
 			// confirm mask looks valid
229
 			// confirm mask looks valid
469
-			mask, err := Casefold(change.arg)
230
+			mask, err := Casefold(change.Arg)
470
 			if err != nil {
231
 			if err != nil {
471
 				continue
232
 				continue
472
 			}
233
 			}
473
 
234
 
474
-			switch change.op {
475
-			case Add:
476
-				if channel.lists[change.mode].Length() >= client.server.Limits().ChanListModes {
477
-					if !listFullWarned[change.mode] {
478
-						client.Send(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.mode.String(), client.t("Channel list is full"))
479
-						listFullWarned[change.mode] = true
235
+			switch change.Op {
236
+			case modes.Add:
237
+				if channel.lists[change.Mode].Length() >= client.server.Limits().ChanListModes {
238
+					if !listFullWarned[change.Mode] {
239
+						client.Send(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
240
+						listFullWarned[change.Mode] = true
480
 					}
241
 					}
481
 					continue
242
 					continue
482
 				}
243
 				}
483
 
244
 
484
-				channel.lists[change.mode].Add(mask)
245
+				channel.lists[change.Mode].Add(mask)
485
 				applied = append(applied, change)
246
 				applied = append(applied, change)
486
 
247
 
487
-			case Remove:
488
-				channel.lists[change.mode].Remove(mask)
248
+			case modes.Remove:
249
+				channel.lists[change.Mode].Remove(mask)
489
 				applied = append(applied, change)
250
 				applied = append(applied, change)
490
 			}
251
 			}
491
 
252
 
492
-		case UserLimit:
493
-			switch change.op {
494
-			case Add:
495
-				val, err := strconv.ParseUint(change.arg, 10, 64)
253
+		case modes.UserLimit:
254
+			switch change.Op {
255
+			case modes.Add:
256
+				val, err := strconv.ParseUint(change.Arg, 10, 64)
496
 				if err == nil {
257
 				if err == nil {
497
 					channel.setUserLimit(val)
258
 					channel.setUserLimit(val)
498
 					applied = append(applied, change)
259
 					applied = append(applied, change)
499
 				}
260
 				}
500
 
261
 
501
-			case Remove:
262
+			case modes.Remove:
502
 				channel.setUserLimit(0)
263
 				channel.setUserLimit(0)
503
 				applied = append(applied, change)
264
 				applied = append(applied, change)
504
 			}
265
 			}
505
 
266
 
506
-		case Key:
507
-			switch change.op {
508
-			case Add:
509
-				channel.setKey(change.arg)
267
+		case modes.Key:
268
+			switch change.Op {
269
+			case modes.Add:
270
+				channel.setKey(change.Arg)
510
 
271
 
511
-			case Remove:
272
+			case modes.Remove:
512
 				channel.setKey("")
273
 				channel.setKey("")
513
 			}
274
 			}
514
 			applied = append(applied, change)
275
 			applied = append(applied, change)
515
 
276
 
516
-		case InviteOnly, Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, Secret, ChanRoleplaying:
517
-			if change.op == List {
277
+		case modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.RegisteredOnly, modes.Secret, modes.ChanRoleplaying:
278
+			if change.Op == modes.List {
518
 				continue
279
 				continue
519
 			}
280
 			}
520
 
281
 
521
-			already := channel.setMode(change.mode, change.op == Add)
282
+			already := channel.setMode(change.Mode, change.Op == modes.Add)
522
 			if !already {
283
 			if !already {
523
 				applied = append(applied, change)
284
 				applied = append(applied, change)
524
 			}
285
 			}
525
 
286
 
526
-		case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
527
-			if change.op == List {
287
+		case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
288
+			if change.Op == modes.List {
528
 				continue
289
 				continue
529
 			}
290
 			}
530
 
291
 
531
-			change := channel.applyModeMemberNoMutex(client, change.mode, change.op, change.arg)
292
+			change := channel.applyModeMemberNoMutex(client, change.Mode, change.Op, change.Arg)
532
 			if change != nil {
293
 			if change != nil {
533
 				applied = append(applied, *change)
294
 				applied = append(applied, *change)
534
 			}
295
 			}

+ 286
- 0
irc/modes/modes.go Переглянути файл

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
+
6
+package modes
7
+
8
+import (
9
+	"strings"
10
+)
11
+
12
+var (
13
+	// SupportedUserModes are the user modes that we actually support (modifying).
14
+	SupportedUserModes = Modes{
15
+		Away, Bot, Invisible, Operator, RegisteredOnly, ServerNotice, UserRoleplaying,
16
+	}
17
+
18
+	// SupportedChannelModes are the channel modes that we support.
19
+	SupportedChannelModes = Modes{
20
+		BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
21
+		Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, Secret, UserLimit,
22
+	}
23
+)
24
+
25
+// ModeOp is an operation performed with modes
26
+type ModeOp rune
27
+
28
+func (op ModeOp) String() string {
29
+	return string(op)
30
+}
31
+
32
+const (
33
+	// Add is used when adding the given key.
34
+	Add ModeOp = '+'
35
+	// List is used when listing modes (for instance, listing the current bans on a channel).
36
+	List ModeOp = '='
37
+	// Remove is used when taking away the given key.
38
+	Remove ModeOp = '-'
39
+)
40
+
41
+// Mode represents a user/channel/server mode
42
+type Mode rune
43
+
44
+func (mode Mode) String() string {
45
+	return string(mode)
46
+}
47
+
48
+// ModeChange is a single mode changing
49
+type ModeChange struct {
50
+	Mode Mode
51
+	Op   ModeOp
52
+	Arg  string
53
+}
54
+
55
+func (change *ModeChange) String() (str string) {
56
+	if (change.Op == Add) || (change.Op == Remove) {
57
+		str = change.Op.String()
58
+	}
59
+	str += change.Mode.String()
60
+	if change.Arg != "" {
61
+		str += " " + change.Arg
62
+	}
63
+	return
64
+}
65
+
66
+// ModeChanges are a collection of 'ModeChange's
67
+type ModeChanges []ModeChange
68
+
69
+func (changes ModeChanges) String() string {
70
+	if len(changes) == 0 {
71
+		return ""
72
+	}
73
+
74
+	op := changes[0].Op
75
+	str := changes[0].Op.String()
76
+
77
+	for _, change := range changes {
78
+		if change.Op != op {
79
+			op = change.Op
80
+			str += change.Op.String()
81
+		}
82
+		str += change.Mode.String()
83
+	}
84
+
85
+	for _, change := range changes {
86
+		if change.Arg == "" {
87
+			continue
88
+		}
89
+		str += " " + change.Arg
90
+	}
91
+	return str
92
+}
93
+
94
+// Modes is just a raw list of modes
95
+type Modes []Mode
96
+
97
+func (modes Modes) String() string {
98
+	strs := make([]string, len(modes))
99
+	for index, mode := range modes {
100
+		strs[index] = mode.String()
101
+	}
102
+	return strings.Join(strs, "")
103
+}
104
+
105
+// User Modes
106
+const (
107
+	Away            Mode = 'a'
108
+	Bot             Mode = 'B'
109
+	Invisible       Mode = 'i'
110
+	LocalOperator   Mode = 'O'
111
+	Operator        Mode = 'o'
112
+	Restricted      Mode = 'r'
113
+	RegisteredOnly  Mode = 'R'
114
+	ServerNotice    Mode = 's'
115
+	TLS             Mode = 'Z'
116
+	UserRoleplaying Mode = 'E'
117
+	WallOps         Mode = 'w'
118
+)
119
+
120
+// Channel Modes
121
+const (
122
+	BanMask         Mode = 'b' // arg
123
+	ChanRoleplaying Mode = 'E' // flag
124
+	ExceptMask      Mode = 'e' // arg
125
+	InviteMask      Mode = 'I' // arg
126
+	InviteOnly      Mode = 'i' // flag
127
+	Key             Mode = 'k' // flag arg
128
+	Moderated       Mode = 'm' // flag
129
+	NoOutside       Mode = 'n' // flag
130
+	OpOnlyTopic     Mode = 't' // flag
131
+	// RegisteredOnly mode is reused here from umode definition
132
+	Secret    Mode = 's' // flag
133
+	UserLimit Mode = 'l' // flag arg
134
+)
135
+
136
+var (
137
+	ChannelFounder  Mode = 'q' // arg
138
+	ChannelAdmin    Mode = 'a' // arg
139
+	ChannelOperator Mode = 'o' // arg
140
+	Halfop          Mode = 'h' // arg
141
+	Voice           Mode = 'v' // arg
142
+
143
+	// ChannelPrivModes holds the list of modes that are privileged, ie founder/op/halfop, in order.
144
+	// voice is not in this list because it cannot perform channel operator actions.
145
+	ChannelPrivModes = Modes{
146
+		ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
147
+	}
148
+
149
+	ChannelModePrefixes = map[Mode]string{
150
+		ChannelFounder:  "~",
151
+		ChannelAdmin:    "&",
152
+		ChannelOperator: "@",
153
+		Halfop:          "%",
154
+		Voice:           "+",
155
+	}
156
+)
157
+
158
+//
159
+// channel membership prefixes
160
+//
161
+
162
+// SplitChannelMembershipPrefixes takes a target and returns the prefixes on it, then the name.
163
+func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) {
164
+	name = target
165
+	for {
166
+		if len(name) > 0 && strings.Contains("~&@%+", string(name[0])) {
167
+			prefixes += string(name[0])
168
+			name = name[1:]
169
+		} else {
170
+			break
171
+		}
172
+	}
173
+
174
+	return prefixes, name
175
+}
176
+
177
+// GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes.
178
+func GetLowestChannelModePrefix(prefixes string) *Mode {
179
+	var lowest *Mode
180
+
181
+	if strings.Contains(prefixes, "+") {
182
+		lowest = &Voice
183
+	} else {
184
+		for i, mode := range ChannelPrivModes {
185
+			if strings.Contains(prefixes, ChannelModePrefixes[mode]) {
186
+				lowest = &ChannelPrivModes[i]
187
+			}
188
+		}
189
+	}
190
+
191
+	return lowest
192
+}
193
+
194
+//
195
+// commands
196
+//
197
+
198
+// ParseUserModeChanges returns the valid changes, and the list of unknown chars.
199
+func ParseUserModeChanges(params ...string) (ModeChanges, map[rune]bool) {
200
+	changes := make(ModeChanges, 0)
201
+	unknown := make(map[rune]bool)
202
+
203
+	op := List
204
+
205
+	if 0 < len(params) {
206
+		modeArg := params[0]
207
+		skipArgs := 1
208
+
209
+		for _, mode := range modeArg {
210
+			if mode == '-' || mode == '+' {
211
+				op = ModeOp(mode)
212
+				continue
213
+			}
214
+			change := ModeChange{
215
+				Mode: Mode(mode),
216
+				Op:   op,
217
+			}
218
+
219
+			// put arg into modechange if needed
220
+			switch Mode(mode) {
221
+			case ServerNotice:
222
+				// always require arg
223
+				if len(params) > skipArgs {
224
+					change.Arg = params[skipArgs]
225
+					skipArgs++
226
+				} else {
227
+					continue
228
+				}
229
+			}
230
+
231
+			var isKnown bool
232
+			for _, supportedMode := range SupportedUserModes {
233
+				if rune(supportedMode) == mode {
234
+					isKnown = true
235
+					break
236
+				}
237
+			}
238
+			if !isKnown {
239
+				unknown[mode] = true
240
+				continue
241
+			}
242
+
243
+			changes = append(changes, change)
244
+		}
245
+	}
246
+
247
+	return changes, unknown
248
+}
249
+
250
+// ModeSet holds a set of modes.
251
+type ModeSet map[Mode]bool
252
+
253
+// String returns the modes in this set.
254
+func (set ModeSet) String() string {
255
+	if len(set) == 0 {
256
+		return ""
257
+	}
258
+	strs := make([]string, len(set))
259
+	index := 0
260
+	for mode := range set {
261
+		strs[index] = mode.String()
262
+		index++
263
+	}
264
+	return strings.Join(strs, "")
265
+}
266
+
267
+// Prefixes returns a list of prefixes for the given set of channel modes.
268
+func (set ModeSet) Prefixes(isMultiPrefix bool) string {
269
+	var prefixes string
270
+
271
+	// add prefixes in order from highest to lowest privs
272
+	for _, mode := range ChannelPrivModes {
273
+		if set[mode] {
274
+			prefixes += ChannelModePrefixes[mode]
275
+		}
276
+	}
277
+	if set[Voice] {
278
+		prefixes += ChannelModePrefixes[Voice]
279
+	}
280
+
281
+	if !isMultiPrefix && len(prefixes) > 1 {
282
+		prefixes = string(prefixes[0])
283
+	}
284
+
285
+	return prefixes
286
+}

+ 4
- 3
irc/roleplay.go Переглянути файл

7
 	"fmt"
7
 	"fmt"
8
 
8
 
9
 	"github.com/oragono/oragono/irc/caps"
9
 	"github.com/oragono/oragono/irc/caps"
10
+	"github.com/oragono/oragono/irc/modes"
10
 )
11
 )
11
 
12
 
12
 const (
13
 const (
34
 			return
35
 			return
35
 		}
36
 		}
36
 
37
 
37
-		if !channel.flags[ChanRoleplaying] {
38
+		if !channel.flags[modes.ChanRoleplaying] {
38
 			client.Send(nil, client.server.name, ERR_CANNOTSENDRP, channel.name, client.t("Channel doesn't have roleplaying mode available"))
39
 			client.Send(nil, client.server.name, ERR_CANNOTSENDRP, channel.name, client.t("Channel doesn't have roleplaying mode available"))
39
 			return
40
 			return
40
 		}
41
 		}
53
 			return
54
 			return
54
 		}
55
 		}
55
 
56
 
56
-		if !user.flags[UserRoleplaying] {
57
+		if !user.flags[modes.UserRoleplaying] {
57
 			client.Send(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
58
 			client.Send(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
58
 			return
59
 			return
59
 		}
60
 		}
62
 		if client.capabilities.Has(caps.EchoMessage) {
63
 		if client.capabilities.Has(caps.EchoMessage) {
63
 			client.Send(nil, source, "PRIVMSG", user.nick, message)
64
 			client.Send(nil, source, "PRIVMSG", user.nick, message)
64
 		}
65
 		}
65
-		if user.flags[Away] {
66
+		if user.flags[modes.Away] {
66
 			//TODO(dan): possibly implement cooldown of away notifications to users
67
 			//TODO(dan): possibly implement cooldown of away notifications to users
67
 			client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
68
 			client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
68
 		}
69
 		}

+ 21
- 15
irc/server.go Переглянути файл

29
 	"github.com/oragono/oragono/irc/isupport"
29
 	"github.com/oragono/oragono/irc/isupport"
30
 	"github.com/oragono/oragono/irc/languages"
30
 	"github.com/oragono/oragono/irc/languages"
31
 	"github.com/oragono/oragono/irc/logger"
31
 	"github.com/oragono/oragono/irc/logger"
32
+	"github.com/oragono/oragono/irc/modes"
32
 	"github.com/oragono/oragono/irc/passwd"
33
 	"github.com/oragono/oragono/irc/passwd"
33
 	"github.com/oragono/oragono/irc/sno"
34
 	"github.com/oragono/oragono/irc/sno"
34
 	"github.com/oragono/oragono/irc/utils"
35
 	"github.com/oragono/oragono/irc/utils"
43
 	couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
44
 	couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
44
 
45
 
45
 	RenamePrivsNeeded = errors.New("Only chanops can rename channels")
46
 	RenamePrivsNeeded = errors.New("Only chanops can rename channels")
47
+
48
+	// supportedUserModesString acts as a cache for when we introduce users
49
+	supportedUserModesString = modes.SupportedUserModes.String()
50
+	// supportedChannelModesString acts as a cache for when we introduce users
51
+	supportedChannelModesString = modes.SupportedChannelModes.String()
46
 )
52
 )
47
 
53
 
48
 // Limits holds the maximum limits for various things such as topic lengths.
54
 // Limits holds the maximum limits for various things such as topic lengths.
89
 	connectionLimiter            *connection_limits.Limiter
95
 	connectionLimiter            *connection_limits.Limiter
90
 	connectionThrottler          *connection_limits.Throttler
96
 	connectionThrottler          *connection_limits.Throttler
91
 	ctime                        time.Time
97
 	ctime                        time.Time
92
-	defaultChannelModes          Modes
98
+	defaultChannelModes          modes.Modes
93
 	dlines                       *DLineManager
99
 	dlines                       *DLineManager
94
 	loggingRawIO                 bool
100
 	loggingRawIO                 bool
95
 	isupport                     *isupport.List
101
 	isupport                     *isupport.List
179
 	isupport := isupport.NewList()
185
 	isupport := isupport.NewList()
180
 	isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
186
 	isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
181
 	isupport.Add("CASEMAPPING", "ascii")
187
 	isupport.Add("CASEMAPPING", "ascii")
182
-	isupport.Add("CHANMODES", strings.Join([]string{Modes{BanMask, ExceptMask, InviteMask}.String(), "", Modes{UserLimit, Key}.String(), Modes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret}.String()}, ","))
188
+	isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), "", modes.Modes{modes.UserLimit, modes.Key}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret}.String()}, ","))
183
 	isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
189
 	isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
184
 	isupport.Add("CHANTYPES", "#")
190
 	isupport.Add("CHANTYPES", "#")
185
 	isupport.Add("ELIST", "U")
191
 	isupport.Add("ELIST", "U")
224
 	server.configurableStateMutex.Unlock()
230
 	server.configurableStateMutex.Unlock()
225
 }
231
 }
226
 
232
 
227
-func loadChannelList(channel *Channel, list string, maskMode Mode) {
233
+func loadChannelList(channel *Channel, list string, maskMode modes.Mode) {
228
 	if list == "" {
234
 	if list == "" {
229
 		return
235
 		return
230
 	}
236
 	}
584
 	var chstrs []string
590
 	var chstrs []string
585
 	for _, channel := range client.Channels() {
591
 	for _, channel := range client.Channels() {
586
 		// channel is secret and the target can't see it
592
 		// channel is secret and the target can't see it
587
-		if !target.flags[Operator] && channel.HasMode(Secret) && !channel.hasClient(target) {
593
+		if !target.flags[modes.Operator] && channel.HasMode(modes.Secret) && !channel.hasClient(target) {
588
 			continue
594
 			continue
589
 		}
595
 		}
590
 		chstrs = append(chstrs, channel.ClientPrefixes(client, isMultiPrefix)+channel.name)
596
 		chstrs = append(chstrs, channel.ClientPrefixes(client, isMultiPrefix)+channel.name)
605
 	if target.class != nil {
611
 	if target.class != nil {
606
 		client.Send(nil, client.server.name, RPL_WHOISOPERATOR, client.nick, target.nick, target.whoisLine)
612
 		client.Send(nil, client.server.name, RPL_WHOISOPERATOR, client.nick, target.nick, target.whoisLine)
607
 	}
613
 	}
608
-	if client.flags[Operator] || client == target {
614
+	if client.flags[modes.Operator] || client == target {
609
 		client.Send(nil, client.server.name, RPL_WHOISACTUALLY, client.nick, target.nick, fmt.Sprintf("%s@%s", target.username, utils.LookupHostname(target.IPString())), target.IPString(), client.t("Actual user@host, Actual IP"))
615
 		client.Send(nil, client.server.name, RPL_WHOISACTUALLY, client.nick, target.nick, fmt.Sprintf("%s@%s", target.username, utils.LookupHostname(target.IPString())), target.IPString(), client.t("Actual user@host, Actual IP"))
610
 	}
616
 	}
611
-	if target.flags[TLS] {
617
+	if target.flags[modes.TLS] {
612
 		client.Send(nil, client.server.name, RPL_WHOISSECURE, client.nick, target.nick, client.t("is using a secure connection"))
618
 		client.Send(nil, client.server.name, RPL_WHOISSECURE, client.nick, target.nick, client.t("is using a secure connection"))
613
 	}
619
 	}
614
 	accountName := target.AccountName()
620
 	accountName := target.AccountName()
615
 	if accountName != "" {
621
 	if accountName != "" {
616
 		client.Send(nil, client.server.name, RPL_WHOISACCOUNT, client.nick, accountName, client.t("is logged in as"))
622
 		client.Send(nil, client.server.name, RPL_WHOISACCOUNT, client.nick, accountName, client.t("is logged in as"))
617
 	}
623
 	}
618
-	if target.flags[Bot] {
624
+	if target.flags[modes.Bot] {
619
 		client.Send(nil, client.server.name, RPL_WHOISBOT, client.nick, target.nick, ircfmt.Unescape(fmt.Sprintf(client.t("is a $bBot$b on %s"), client.server.networkName)))
625
 		client.Send(nil, client.server.name, RPL_WHOISBOT, client.nick, target.nick, ircfmt.Unescape(fmt.Sprintf(client.t("is a $bBot$b on %s"), client.server.networkName)))
620
 	}
626
 	}
621
 
627
 
628
 		client.Send(nil, client.server.name, RPL_WHOISLANGUAGE, params...)
634
 		client.Send(nil, client.server.name, RPL_WHOISLANGUAGE, params...)
629
 	}
635
 	}
630
 
636
 
631
-	if target.certfp != "" && (client.flags[Operator] || client == target) {
637
+	if target.certfp != "" && (client.flags[modes.Operator] || client == target) {
632
 		client.Send(nil, client.server.name, RPL_WHOISCERTFP, client.nick, target.nick, fmt.Sprintf(client.t("has client certificate fingerprint %s"), target.certfp))
638
 		client.Send(nil, client.server.name, RPL_WHOISCERTFP, client.nick, target.nick, fmt.Sprintf(client.t("has client certificate fingerprint %s"), target.certfp))
633
 	}
639
 	}
634
 	client.Send(nil, client.server.name, RPL_WHOISIDLE, client.nick, target.nick, strconv.FormatUint(target.IdleSeconds(), 10), strconv.FormatInt(target.SignonTime(), 10), client.t("seconds idle, signon time"))
640
 	client.Send(nil, client.server.name, RPL_WHOISIDLE, client.nick, target.nick, strconv.FormatUint(target.IdleSeconds(), 10), strconv.FormatInt(target.SignonTime(), 10), client.t("seconds idle, signon time"))
641
 	channelName := "*"
647
 	channelName := "*"
642
 	flags := ""
648
 	flags := ""
643
 
649
 
644
-	if client.HasMode(Away) {
650
+	if client.HasMode(modes.Away) {
645
 		flags = "G"
651
 		flags = "G"
646
 	} else {
652
 	} else {
647
 		flags = "H"
653
 		flags = "H"
648
 	}
654
 	}
649
-	if client.HasMode(Operator) {
655
+	if client.HasMode(modes.Operator) {
650
 		flags += "*"
656
 		flags += "*"
651
 	}
657
 	}
652
 
658
 
659
 
665
 
660
 func whoChannel(client *Client, channel *Channel, friends ClientSet) {
666
 func whoChannel(client *Client, channel *Channel, friends ClientSet) {
661
 	for _, member := range channel.Members() {
667
 	for _, member := range channel.Members() {
662
-		if !client.flags[Invisible] || friends[client] {
668
+		if !client.flags[modes.Invisible] || friends[client] {
663
 			client.rplWhoReply(channel, member)
669
 			client.rplWhoReply(channel, member)
664
 		}
670
 		}
665
 	}
671
 	}
1095
 }
1101
 }
1096
 
1102
 
1097
 // GetDefaultChannelModes returns our default channel modes.
1103
 // GetDefaultChannelModes returns our default channel modes.
1098
-func (server *Server) GetDefaultChannelModes() Modes {
1104
+func (server *Server) GetDefaultChannelModes() modes.Modes {
1099
 	server.configurableStateMutex.RLock()
1105
 	server.configurableStateMutex.RLock()
1100
 	defer server.configurableStateMutex.RUnlock()
1106
 	defer server.configurableStateMutex.RUnlock()
1101
 	return server.defaultChannelModes
1107
 	return server.defaultChannelModes
1130
 func (target *Client) RplList(channel *Channel) {
1136
 func (target *Client) RplList(channel *Channel) {
1131
 	// get the correct number of channel members
1137
 	// get the correct number of channel members
1132
 	var memberCount int
1138
 	var memberCount int
1133
-	if target.flags[Operator] || channel.hasClient(target) {
1139
+	if target.flags[modes.Operator] || channel.hasClient(target) {
1134
 		memberCount = len(channel.Members())
1140
 		memberCount = len(channel.Members())
1135
 	} else {
1141
 	} else {
1136
 		for _, member := range channel.Members() {
1142
 		for _, member := range channel.Members() {
1137
-			if !member.HasMode(Invisible) {
1143
+			if !member.HasMode(modes.Invisible) {
1138
 				memberCount++
1144
 				memberCount++
1139
 			}
1145
 			}
1140
 		}
1146
 		}
1162
 	}
1168
 	}
1163
 
1169
 
1164
 	// limit regular users to only listing one channel
1170
 	// limit regular users to only listing one channel
1165
-	if !client.flags[Operator] {
1171
+	if !client.flags[modes.Operator] {
1166
 		channels = channels[:1]
1172
 		channels = channels[:1]
1167
 	}
1173
 	}
1168
 
1174
 

+ 5
- 24
irc/types.go Переглянути файл

5
 
5
 
6
 package irc
6
 package irc
7
 
7
 
8
-import (
9
-	"strings"
10
-)
11
-
12
-// ModeSet holds a set of modes.
13
-type ModeSet map[Mode]bool
14
-
15
-// String returns the modes in this set.
16
-func (set ModeSet) String() string {
17
-	if len(set) == 0 {
18
-		return ""
19
-	}
20
-	strs := make([]string, len(set))
21
-	index := 0
22
-	for mode := range set {
23
-		strs[index] = mode.String()
24
-		index++
25
-	}
26
-	return strings.Join(strs, "")
27
-}
8
+import "github.com/oragono/oragono/irc/modes"
28
 
9
 
29
 // ClientSet is a set of clients.
10
 // ClientSet is a set of clients.
30
 type ClientSet map[*Client]bool
11
 type ClientSet map[*Client]bool
45
 }
26
 }
46
 
27
 
47
 // MemberSet is a set of members with modes.
28
 // MemberSet is a set of members with modes.
48
-type MemberSet map[*Client]ModeSet
29
+type MemberSet map[*Client]modes.ModeSet
49
 
30
 
50
 // Add adds the given client to this set.
31
 // Add adds the given client to this set.
51
 func (members MemberSet) Add(member *Client) {
32
 func (members MemberSet) Add(member *Client) {
52
-	members[member] = make(ModeSet)
33
+	members[member] = make(modes.ModeSet)
53
 }
34
 }
54
 
35
 
55
 // Remove removes the given client from this set.
36
 // Remove removes the given client from this set.
64
 }
45
 }
65
 
46
 
66
 // HasMode returns true if the given client is in this set with the given mode.
47
 // HasMode returns true if the given client is in this set with the given mode.
67
-func (members MemberSet) HasMode(member *Client, mode Mode) bool {
48
+func (members MemberSet) HasMode(member *Client, mode modes.Mode) bool {
68
 	modes, ok := members[member]
49
 	modes, ok := members[member]
69
 	if !ok {
50
 	if !ok {
70
 		return false
51
 		return false
73
 }
54
 }
74
 
55
 
75
 // AnyHasMode returns true if any of our clients has the given mode.
56
 // AnyHasMode returns true if any of our clients has the given mode.
76
-func (members MemberSet) AnyHasMode(mode Mode) bool {
57
+func (members MemberSet) AnyHasMode(mode modes.Mode) bool {
77
 	for _, modes := range members {
58
 	for _, modes := range members {
78
 		if modes[mode] {
59
 		if modes[mode] {
79
 			return true
60
 			return true

Завантаження…
Відмінити
Зберегти