Shivaram Lingamneni před 4 roky
rodič
revize
82c5041225
5 změnil soubory, kde provedl 73 přidání a 41 odebrání
  1. 10
    9
      irc/client_lookup_set.go
  2. 6
    12
      irc/handlers.go
  3. 41
    20
      irc/modes.go
  4. 13
    0
      irc/modes/modes_test.go
  5. 3
    0
      irc/numerics.go

+ 10
- 9
irc/client_lookup_set.go Zobrazit soubor

@@ -268,10 +268,10 @@ func NewUserMaskSet() *UserMaskSet {
268 268
 }
269 269
 
270 270
 // Add adds the given mask to this set.
271
-func (set *UserMaskSet) Add(mask, creatorNickmask, creatorAccount string) (added bool) {
271
+func (set *UserMaskSet) Add(mask, creatorNickmask, creatorAccount string) (maskAdded string, err error) {
272 272
 	casefoldedMask, err := CanonicalizeMaskWildcard(mask)
273 273
 	if err != nil {
274
-		return false
274
+		return
275 275
 	}
276 276
 
277 277
 	set.Lock()
@@ -279,8 +279,8 @@ func (set *UserMaskSet) Add(mask, creatorNickmask, creatorAccount string) (added
279 279
 		set.masks = make(map[string]MaskInfo)
280 280
 	}
281 281
 	_, present := set.masks[casefoldedMask]
282
-	added = !present
283
-	if added {
282
+	if !present {
283
+		maskAdded = casefoldedMask
284 284
 		set.masks[casefoldedMask] = MaskInfo{
285 285
 			TimeCreated:     time.Now().UTC(),
286 286
 			CreatorNickmask: creatorNickmask,
@@ -289,22 +289,23 @@ func (set *UserMaskSet) Add(mask, creatorNickmask, creatorAccount string) (added
289 289
 	}
290 290
 	set.Unlock()
291 291
 
292
-	if added {
292
+	if !present {
293 293
 		set.setRegexp()
294 294
 	}
295 295
 	return
296 296
 }
297 297
 
298 298
 // Remove removes the given mask from this set.
299
-func (set *UserMaskSet) Remove(mask string) (removed bool) {
300
-	mask, err := CanonicalizeMaskWildcard(mask)
299
+func (set *UserMaskSet) Remove(mask string) (maskRemoved string, err error) {
300
+	mask, err = CanonicalizeMaskWildcard(mask)
301 301
 	if err != nil {
302
-		return false
302
+		return
303 303
 	}
304 304
 
305 305
 	set.Lock()
306
-	_, removed = set.masks[mask]
306
+	_, removed := set.masks[mask]
307 307
 	if removed {
308
+		maskRemoved = mask
308 309
 		delete(set.masks, mask)
309 310
 	}
310 311
 	set.Unlock()

+ 6
- 12
irc/handlers.go Zobrazit soubor

@@ -1685,13 +1685,12 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1685 1685
 		return false
1686 1686
 	}
1687 1687
 
1688
-	// applied mode changes
1689
-	applied := make(modes.ModeChanges, 0)
1690
-
1688
+	var changes modes.ModeChanges
1691 1689
 	if 1 < len(msg.Params) {
1692 1690
 		// parse out real mode changes
1693 1691
 		params := msg.Params[1:]
1694
-		changes, unknown := modes.ParseChannelModeChanges(params...)
1692
+		var unknown map[rune]bool
1693
+		changes, unknown = modes.ParseChannelModeChanges(params...)
1695 1694
 
1696 1695
 		// alert for unknown mode changes
1697 1696
 		for char := range unknown {
@@ -1700,10 +1699,9 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1700 1699
 		if len(unknown) == 1 && len(changes) == 0 {
1701 1700
 			return false
1702 1701
 		}
1703
-
1704
-		// apply mode changes
1705
-		applied = channel.ApplyChannelModeChanges(client, msg.Command == "SAMODE", changes, rb)
1706 1702
 	}
1703
+	// process mode changes, include list operations (an empty set of changes does a list)
1704
+	applied := channel.ApplyChannelModeChanges(client, msg.Command == "SAMODE", changes, rb)
1707 1705
 
1708 1706
 	// save changes
1709 1707
 	var includeFlags uint
@@ -1719,8 +1717,8 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1719 1717
 	}
1720 1718
 
1721 1719
 	// send out changes
1722
-	prefix := client.NickMaskString()
1723 1720
 	if len(applied) > 0 {
1721
+		prefix := client.NickMaskString()
1724 1722
 		//TODO(dan): we should change the name of String and make it return a slice here
1725 1723
 		args := append([]string{channel.name}, strings.Split(applied.String(), " ")...)
1726 1724
 		for _, member := range channel.Members() {
@@ -1735,10 +1733,6 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1735 1733
 				member.Send(nil, prefix, "MODE", args...)
1736 1734
 			}
1737 1735
 		}
1738
-	} else {
1739
-		args := append([]string{client.nick, channel.name}, channel.modeStrings(client)...)
1740
-		rb.Add(nil, prefix, RPL_CHANNELMODEIS, args...)
1741
-		rb.Add(nil, client.nickMaskString, RPL_CREATIONTIME, client.nick, channel.name, strconv.FormatInt(channel.createdTime.Unix(), 10))
1742 1736
 	}
1743 1737
 	return false
1744 1738
 }

+ 41
- 20
irc/modes.go Zobrazit soubor

@@ -6,6 +6,7 @@
6 6
 package irc
7 7
 
8 8
 import (
9
+	"fmt"
9 10
 	"strconv"
10 11
 	"strings"
11 12
 
@@ -104,17 +105,15 @@ func ParseDefaultChannelModes(rawModes *string) modes.Modes {
104 105
 }
105 106
 
106 107
 // ApplyChannelModeChanges applies a given set of mode changes.
107
-func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges, rb *ResponseBuffer) modes.ModeChanges {
108
+func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges, rb *ResponseBuffer) (applied modes.ModeChanges) {
108 109
 	// so we only output one warning for each list type when full
109 110
 	listFullWarned := make(map[modes.Mode]bool)
110 111
 
111 112
 	var alreadySentPrivError bool
112 113
 
113
-	applied := make(modes.ModeChanges, 0)
114
-
115
-	isListOp := func(change modes.ModeChange) bool {
116
-		return (change.Op == modes.List) || (change.Arg == "")
117
-	}
114
+	maskOpCount := 0
115
+	chname := channel.Name()
116
+	details := client.Details()
118 117
 
119 118
 	hasPrivs := func(change modes.ModeChange) bool {
120 119
 		if isSamode {
@@ -127,18 +126,19 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
127 126
 				return true
128 127
 			}
129 128
 			cfarg, _ := CasefoldName(change.Arg)
130
-			isSelfChange := cfarg == client.NickCasefolded()
129
+			isSelfChange := cfarg == details.nickCasefolded
131 130
 			if change.Op == modes.Remove && isSelfChange {
132 131
 				// "There is no restriction, however, on anyone `deopping' themselves"
133 132
 				// <https://tools.ietf.org/html/rfc2812#section-3.1.5>
134 133
 				return true
135 134
 			}
136 135
 			return channelUserModeHasPrivsOver(channel.HighestUserMode(client), change.Mode)
137
-		case modes.BanMask:
138
-			// #163: allow unprivileged users to list ban masks
139
-			return isListOp(change) || channel.ClientIsAtLeast(client, modes.ChannelOperator)
140
-		default:
136
+		case modes.InviteMask, modes.ExceptMask:
137
+			// listing these requires privileges
141 138
 			return channel.ClientIsAtLeast(client, modes.ChannelOperator)
139
+		default:
140
+			// #163: allow unprivileged users to list ban masks, and any other modes
141
+			return change.Op == modes.List || channel.ClientIsAtLeast(client, modes.ChannelOperator)
142 142
 		}
143 143
 	}
144 144
 
@@ -146,14 +146,15 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
146 146
 		if !hasPrivs(change) {
147 147
 			if !alreadySentPrivError {
148 148
 				alreadySentPrivError = true
149
-				rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.name, client.t("You're not a channel operator"))
149
+				rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, details.nick, channel.name, client.t("You're not a channel operator"))
150 150
 			}
151 151
 			continue
152 152
 		}
153 153
 
154 154
 		switch change.Mode {
155 155
 		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
156
-			if isListOp(change) {
156
+			maskOpCount += 1
157
+			if change.Op == modes.List {
157 158
 				channel.ShowMaskList(client, change.Mode, rb)
158 159
 				continue
159 160
 			}
@@ -163,20 +164,33 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
163 164
 			case modes.Add:
164 165
 				if channel.lists[change.Mode].Length() >= client.server.Config().Limits.ChanListModes {
165 166
 					if !listFullWarned[change.Mode] {
166
-						rb.Add(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
167
+						rb.Add(nil, client.server.name, ERR_BANLISTFULL, details.nick, chname, change.Mode.String(), client.t("Channel list is full"))
167 168
 						listFullWarned[change.Mode] = true
168 169
 					}
169 170
 					continue
170 171
 				}
171 172
 
172
-				details := client.Details()
173
-				if success := channel.lists[change.Mode].Add(mask, details.nickMask, details.accountName); success {
174
-					applied = append(applied, change)
173
+				maskAdded, err := channel.lists[change.Mode].Add(mask, details.nickMask, details.accountName)
174
+				if maskAdded != "" {
175
+					appliedChange := change
176
+					appliedChange.Arg = maskAdded
177
+					applied = append(applied, appliedChange)
178
+				} else if err != nil {
179
+					rb.Add(nil, client.server.name, ERR_INVALIDMODEPARAM, details.nick, mask, fmt.Sprintf(client.t("Invalid mode %s parameter: %s"), string(change.Mode), mask))
180
+				} else {
181
+					rb.Add(nil, client.server.name, ERR_LISTMODEALREADYSET, chname, mask, string(change.Mode), fmt.Sprintf(client.t("Channel %s list already contains %s"), chname, mask))
175 182
 				}
176 183
 
177 184
 			case modes.Remove:
178
-				if success := channel.lists[change.Mode].Remove(mask); success {
179
-					applied = append(applied, change)
185
+				maskRemoved, err := channel.lists[change.Mode].Remove(mask)
186
+				if maskRemoved != "" {
187
+					appliedChange := change
188
+					appliedChange.Arg = maskRemoved
189
+					applied = append(applied, appliedChange)
190
+				} else if err != nil {
191
+					rb.Add(nil, client.server.name, ERR_INVALIDMODEPARAM, details.nick, mask, fmt.Sprintf(client.t("Invalid mode %s parameter: %s"), string(change.Mode), mask))
192
+				} else {
193
+					rb.Add(nil, client.server.name, ERR_LISTMODENOTSET, chname, mask, string(change.Mode), fmt.Sprintf(client.t("Channel %s list does not contain %s"), chname, mask))
180 194
 				}
181 195
 			}
182 196
 
@@ -221,7 +235,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
221 235
 			nick := change.Arg
222 236
 			if nick == "" {
223 237
 				rb.Add(nil, client.server.name, ERR_NEEDMOREPARAMS, client.Nick(), "MODE", client.t("Not enough parameters"))
224
-				return nil
238
+				continue
225 239
 			}
226 240
 
227 241
 			change := channel.applyModeToMember(client, change.Mode, change.Op, nick, rb)
@@ -231,6 +245,13 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
231 245
 		}
232 246
 	}
233 247
 
248
+	// #649: don't send 324 RPL_CHANNELMODEIS if we were only working with mask lists
249
+	if len(applied) == 0 && !alreadySentPrivError && (maskOpCount == 0 || maskOpCount < len(changes)) {
250
+		args := append([]string{details.nick, chname}, channel.modeStrings(client)...)
251
+		rb.Add(nil, client.server.name, RPL_CHANNELMODEIS, args...)
252
+		rb.Add(nil, client.server.name, RPL_CREATIONTIME, details.nick, chname, strconv.FormatInt(channel.createdTime.Unix(), 10))
253
+	}
254
+
234 255
 	return applied
235 256
 }
236 257
 

+ 13
- 0
irc/modes/modes_test.go Zobrazit soubor

@@ -47,6 +47,19 @@ func TestParseChannelModeChanges(t *testing.T) {
47 47
 	if len(modes) != 1 || modes[0] != expected {
48 48
 		t.Errorf("unexpected mode change: %v", modes)
49 49
 	}
50
+
51
+	modes, unknown = ParseChannelModeChanges("+b")
52
+	if len(unknown) > 0 {
53
+		t.Errorf("unexpected unknown mode change: %v", unknown)
54
+	}
55
+	// +b with no argument becomes a list operation
56
+	expectedChanges := ModeChanges{{
57
+		Op:   List,
58
+		Mode: BanMask,
59
+	}}
60
+	if !reflect.DeepEqual(modes, expectedChanges) {
61
+		t.Errorf("unexpected mode change: %v instead of %v", modes, expectedChanges)
62
+	}
50 63
 }
51 64
 
52 65
 func TestSetMode(t *testing.T) {

+ 3
- 0
irc/numerics.go Zobrazit soubor

@@ -169,6 +169,9 @@ const (
169 169
 	RPL_YOURLANGUAGESARE          = "687"
170 170
 	ERR_CHANNAMEINUSE             = "692"
171 171
 	ERR_CANNOTRENAME              = "693"
172
+	ERR_INVALIDMODEPARAM          = "696"
173
+	ERR_LISTMODEALREADYSET        = "697"
174
+	ERR_LISTMODENOTSET            = "698"
172 175
 	RPL_HELPSTART                 = "704"
173 176
 	RPL_HELPTXT                   = "705"
174 177
 	RPL_ENDOFHELP                 = "706"

Načítá se…
Zrušit
Uložit