Browse Source

fix #874

tags/v2.1.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
2d908eac8b
3 changed files with 108 additions and 2 deletions
  1. 1
    1
      irc/config.go
  2. 18
    1
      irc/modes/modes.go
  3. 89
    0
      irc/modes/modes_test.go

+ 1
- 1
irc/config.go View File

@@ -1113,7 +1113,7 @@ func (config *Config) generateISupport() (err error) {
1113 1113
 	isupport.Add("AWAYLEN", strconv.Itoa(config.Limits.AwayLen))
1114 1114
 	isupport.Add("CASEMAPPING", "ascii")
1115 1115
 	isupport.Add("CHANLIMIT", fmt.Sprintf("%s:%d", chanTypes, config.Channels.MaxChannelsPerClient))
1116
-	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, modes.NoCTCP, modes.RegisteredOnly}.String()}, ","))
1116
+	isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), modes.Modes{modes.Key}.String(), modes.Modes{modes.UserLimit}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret, modes.NoCTCP, modes.RegisteredOnly}.String()}, ","))
1117 1117
 	if config.History.Enabled && config.History.ChathistoryMax > 0 {
1118 1118
 		isupport.Add("draft/CHATHISTORY", strconv.Itoa(config.History.ChathistoryMax))
1119 1119
 	}

+ 18
- 1
irc/modes/modes.go View File

@@ -281,7 +281,7 @@ func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
281 281
 				} else {
282 282
 					continue
283 283
 				}
284
-			case Key, UserLimit:
284
+			case UserLimit:
285 285
 				// don't require value when removing
286 286
 				if change.Op == Add {
287 287
 					if len(params) > skipArgs {
@@ -291,6 +291,23 @@ func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
291 291
 						continue
292 292
 					}
293 293
 				}
294
+			case Key:
295
+				// #874: +k is technically a type B mode, requiring a parameter
296
+				// both for add and remove. so attempt to consume a parameter,
297
+				// but allow remove (but not add) even if no parameter is available.
298
+				// however, the remove parameter should always display as "*", matching
299
+				// the freenode behavior.
300
+				if len(params) > skipArgs {
301
+					if change.Op == Add {
302
+						change.Arg = params[skipArgs]
303
+					}
304
+					skipArgs++
305
+				} else if change.Op == Add {
306
+					continue
307
+				}
308
+				if change.Op == Remove {
309
+					change.Arg = "*"
310
+				}
294 311
 			}
295 312
 
296 313
 			var isKnown bool

+ 89
- 0
irc/modes/modes_test.go View File

@@ -8,6 +8,95 @@ import (
8 8
 	"testing"
9 9
 )
10 10
 
11
+func assertEqual(supplied, expected interface{}, t *testing.T) {
12
+	if !reflect.DeepEqual(supplied, expected) {
13
+		t.Errorf("expected %v but got %v", expected, supplied)
14
+	}
15
+}
16
+
17
+func TestIssue874(t *testing.T) {
18
+	emptyUnknown := make(map[rune]bool)
19
+	modes, unknown := ParseChannelModeChanges("+k")
20
+	assertEqual(unknown, emptyUnknown, t)
21
+	assertEqual(modes, ModeChanges{}, t)
22
+
23
+	modes, unknown = ParseChannelModeChanges("+k", "beer")
24
+	assertEqual(unknown, emptyUnknown, t)
25
+	assertEqual(modes, ModeChanges{ModeChange{Op: Add, Mode: Key, Arg: "beer"}}, t)
26
+
27
+	modes, unknown = ParseChannelModeChanges("-k")
28
+	assertEqual(unknown, emptyUnknown, t)
29
+	assertEqual(modes, ModeChanges{ModeChange{Op: Remove, Mode: Key, Arg: "*"}}, t)
30
+
31
+	modes, unknown = ParseChannelModeChanges("-k", "beer")
32
+	assertEqual(unknown, emptyUnknown, t)
33
+	assertEqual(modes, ModeChanges{ModeChange{Op: Remove, Mode: Key, Arg: "*"}}, t)
34
+
35
+	modes, unknown = ParseChannelModeChanges("+kb", "beer")
36
+	assertEqual(unknown, emptyUnknown, t)
37
+	assertEqual(modes, ModeChanges{
38
+		ModeChange{Op: Add, Mode: Key, Arg: "beer"},
39
+		ModeChange{Op: List, Mode: BanMask, Arg: ""},
40
+	}, t)
41
+
42
+	modes, unknown = ParseChannelModeChanges("+kb", "beer")
43
+	assertEqual(unknown, emptyUnknown, t)
44
+	assertEqual(modes, ModeChanges{
45
+		ModeChange{Op: Add, Mode: Key, Arg: "beer"},
46
+		ModeChange{Op: List, Mode: BanMask, Arg: ""},
47
+	}, t)
48
+
49
+	modes, unknown = ParseChannelModeChanges("-kb", "beer")
50
+	assertEqual(unknown, emptyUnknown, t)
51
+	assertEqual(modes, ModeChanges{
52
+		ModeChange{Op: Remove, Mode: Key, Arg: "*"},
53
+		ModeChange{Op: List, Mode: BanMask, Arg: ""},
54
+	}, t)
55
+
56
+	// "beer" is the ban arg, +k with no arg should be ignored
57
+	modes, unknown = ParseChannelModeChanges("+bk", "beer")
58
+	assertEqual(unknown, emptyUnknown, t)
59
+	assertEqual(modes, ModeChanges{
60
+		ModeChange{Op: Add, Mode: BanMask, Arg: "beer"},
61
+	}, t)
62
+
63
+	// "beer" is the ban arg again
64
+	modes, unknown = ParseChannelModeChanges("-bk", "beer")
65
+	assertEqual(unknown, emptyUnknown, t)
66
+	assertEqual(modes, ModeChanges{
67
+		ModeChange{Op: Remove, Mode: BanMask, Arg: "beer"},
68
+		ModeChange{Op: Remove, Mode: Key, Arg: "*"},
69
+	}, t)
70
+
71
+	modes, unknown = ParseChannelModeChanges("+bk", "shivaram", "beer")
72
+	assertEqual(unknown, emptyUnknown, t)
73
+	assertEqual(modes, ModeChanges{
74
+		ModeChange{Op: Add, Mode: BanMask, Arg: "shivaram"},
75
+		ModeChange{Op: Add, Mode: Key, Arg: "beer"},
76
+	}, t)
77
+
78
+	modes, unknown = ParseChannelModeChanges("+kb", "beer", "shivaram")
79
+	assertEqual(unknown, emptyUnknown, t)
80
+	assertEqual(modes, ModeChanges{
81
+		ModeChange{Op: Add, Mode: Key, Arg: "beer"},
82
+		ModeChange{Op: Add, Mode: BanMask, Arg: "shivaram"},
83
+	}, t)
84
+
85
+	modes, unknown = ParseChannelModeChanges("-bk", "shivaram", "beer")
86
+	assertEqual(unknown, emptyUnknown, t)
87
+	assertEqual(modes, ModeChanges{
88
+		ModeChange{Op: Remove, Mode: BanMask, Arg: "shivaram"},
89
+		ModeChange{Op: Remove, Mode: Key, Arg: "*"},
90
+	}, t)
91
+
92
+	modes, unknown = ParseChannelModeChanges("-kb", "beer", "shivaram")
93
+	assertEqual(unknown, emptyUnknown, t)
94
+	assertEqual(modes, ModeChanges{
95
+		ModeChange{Op: Remove, Mode: Key, Arg: "*"},
96
+		ModeChange{Op: Remove, Mode: BanMask, Arg: "shivaram"},
97
+	}, t)
98
+}
99
+
11 100
 func TestParseChannelModeChanges(t *testing.T) {
12 101
 	modes, unknown := ParseChannelModeChanges("+h", "wrmsr")
13 102
 	if len(unknown) > 0 {

Loading…
Cancel
Save