Explorar el Código

fix #649

tags/v1.2.0-rc1
Shivaram Lingamneni hace 4 años
padre
commit
82c5041225
Se han modificado 5 ficheros con 73 adiciones y 41 borrados
  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 Ver fichero

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

+ 6
- 12
irc/handlers.go Ver fichero

1685
 		return false
1685
 		return false
1686
 	}
1686
 	}
1687
 
1687
 
1688
-	// applied mode changes
1689
-	applied := make(modes.ModeChanges, 0)
1690
-
1688
+	var changes modes.ModeChanges
1691
 	if 1 < len(msg.Params) {
1689
 	if 1 < len(msg.Params) {
1692
 		// parse out real mode changes
1690
 		// parse out real mode changes
1693
 		params := msg.Params[1:]
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
 		// alert for unknown mode changes
1695
 		// alert for unknown mode changes
1697
 		for char := range unknown {
1696
 		for char := range unknown {
1700
 		if len(unknown) == 1 && len(changes) == 0 {
1699
 		if len(unknown) == 1 && len(changes) == 0 {
1701
 			return false
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
 	// save changes
1706
 	// save changes
1709
 	var includeFlags uint
1707
 	var includeFlags uint
1719
 	}
1717
 	}
1720
 
1718
 
1721
 	// send out changes
1719
 	// send out changes
1722
-	prefix := client.NickMaskString()
1723
 	if len(applied) > 0 {
1720
 	if len(applied) > 0 {
1721
+		prefix := client.NickMaskString()
1724
 		//TODO(dan): we should change the name of String and make it return a slice here
1722
 		//TODO(dan): we should change the name of String and make it return a slice here
1725
 		args := append([]string{channel.name}, strings.Split(applied.String(), " ")...)
1723
 		args := append([]string{channel.name}, strings.Split(applied.String(), " ")...)
1726
 		for _, member := range channel.Members() {
1724
 		for _, member := range channel.Members() {
1735
 				member.Send(nil, prefix, "MODE", args...)
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
 	return false
1737
 	return false
1744
 }
1738
 }

+ 41
- 20
irc/modes.go Ver fichero

6
 package irc
6
 package irc
7
 
7
 
8
 import (
8
 import (
9
+	"fmt"
9
 	"strconv"
10
 	"strconv"
10
 	"strings"
11
 	"strings"
11
 
12
 
104
 }
105
 }
105
 
106
 
106
 // ApplyChannelModeChanges applies a given set of mode changes.
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
 	// so we only output one warning for each list type when full
109
 	// so we only output one warning for each list type when full
109
 	listFullWarned := make(map[modes.Mode]bool)
110
 	listFullWarned := make(map[modes.Mode]bool)
110
 
111
 
111
 	var alreadySentPrivError bool
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
 	hasPrivs := func(change modes.ModeChange) bool {
118
 	hasPrivs := func(change modes.ModeChange) bool {
120
 		if isSamode {
119
 		if isSamode {
127
 				return true
126
 				return true
128
 			}
127
 			}
129
 			cfarg, _ := CasefoldName(change.Arg)
128
 			cfarg, _ := CasefoldName(change.Arg)
130
-			isSelfChange := cfarg == client.NickCasefolded()
129
+			isSelfChange := cfarg == details.nickCasefolded
131
 			if change.Op == modes.Remove && isSelfChange {
130
 			if change.Op == modes.Remove && isSelfChange {
132
 				// "There is no restriction, however, on anyone `deopping' themselves"
131
 				// "There is no restriction, however, on anyone `deopping' themselves"
133
 				// <https://tools.ietf.org/html/rfc2812#section-3.1.5>
132
 				// <https://tools.ietf.org/html/rfc2812#section-3.1.5>
134
 				return true
133
 				return true
135
 			}
134
 			}
136
 			return channelUserModeHasPrivsOver(channel.HighestUserMode(client), change.Mode)
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
 			return channel.ClientIsAtLeast(client, modes.ChannelOperator)
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
 		if !hasPrivs(change) {
146
 		if !hasPrivs(change) {
147
 			if !alreadySentPrivError {
147
 			if !alreadySentPrivError {
148
 				alreadySentPrivError = true
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
 			continue
151
 			continue
152
 		}
152
 		}
153
 
153
 
154
 		switch change.Mode {
154
 		switch change.Mode {
155
 		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
155
 		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
156
-			if isListOp(change) {
156
+			maskOpCount += 1
157
+			if change.Op == modes.List {
157
 				channel.ShowMaskList(client, change.Mode, rb)
158
 				channel.ShowMaskList(client, change.Mode, rb)
158
 				continue
159
 				continue
159
 			}
160
 			}
163
 			case modes.Add:
164
 			case modes.Add:
164
 				if channel.lists[change.Mode].Length() >= client.server.Config().Limits.ChanListModes {
165
 				if channel.lists[change.Mode].Length() >= client.server.Config().Limits.ChanListModes {
165
 					if !listFullWarned[change.Mode] {
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
 						listFullWarned[change.Mode] = true
168
 						listFullWarned[change.Mode] = true
168
 					}
169
 					}
169
 					continue
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
 			case modes.Remove:
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
 			nick := change.Arg
235
 			nick := change.Arg
222
 			if nick == "" {
236
 			if nick == "" {
223
 				rb.Add(nil, client.server.name, ERR_NEEDMOREPARAMS, client.Nick(), "MODE", client.t("Not enough parameters"))
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
 			change := channel.applyModeToMember(client, change.Mode, change.Op, nick, rb)
241
 			change := channel.applyModeToMember(client, change.Mode, change.Op, nick, rb)
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
 	return applied
255
 	return applied
235
 }
256
 }
236
 
257
 

+ 13
- 0
irc/modes/modes_test.go Ver fichero

47
 	if len(modes) != 1 || modes[0] != expected {
47
 	if len(modes) != 1 || modes[0] != expected {
48
 		t.Errorf("unexpected mode change: %v", modes)
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
 func TestSetMode(t *testing.T) {
65
 func TestSetMode(t *testing.T) {

+ 3
- 0
irc/numerics.go Ver fichero

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

Loading…
Cancelar
Guardar