Bladeren bron

partial implementation of #729

This propagates CS AMODE changes to the actual modes, but not the other
way around.

Also fixes #909.
tags/v2.1.0-rc1
Shivaram Lingamneni 4 jaren geleden
bovenliggende
commit
f5fe580d22
6 gewijzigde bestanden met toevoegingen van 94 en 77 verwijderingen
  1. 8
    10
      irc/channel.go
  2. 27
    17
      irc/chanserv.go
  3. 14
    25
      irc/handlers.go
  4. 18
    3
      irc/modes.go
  5. 11
    22
      irc/modes/modes.go
  6. 16
    0
      irc/modes/modes_test.go

+ 8
- 10
irc/channel.go Bestand weergeven

@@ -1260,22 +1260,20 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
1260 1260
 	})
1261 1261
 }
1262 1262
 
1263
-func (channel *Channel) applyModeToMember(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) (result *modes.ModeChange) {
1264
-	target := channel.server.clients.Get(nick)
1263
+func (channel *Channel) applyModeToMember(client *Client, change modes.ModeChange, rb *ResponseBuffer) (applied bool, result modes.ModeChange) {
1264
+	target := channel.server.clients.Get(change.Arg)
1265 1265
 	if target == nil {
1266
-		rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(nick), client.t("No such nick"))
1267
-		return nil
1266
+		rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.Nick(), utils.SafeErrorParam(change.Arg), client.t("No such nick"))
1267
+		return
1268 1268
 	}
1269
+	change.Arg = target.Nick()
1269 1270
 
1270 1271
 	channel.stateMutex.Lock()
1271 1272
 	modeset, exists := channel.members[target]
1272 1273
 	if exists {
1273
-		if modeset.SetMode(mode, op == modes.Add) {
1274
-			result = &modes.ModeChange{
1275
-				Op:   op,
1276
-				Mode: mode,
1277
-				Arg:  nick,
1278
-			}
1274
+		if modeset.SetMode(change.Mode, change.Op == modes.Add) {
1275
+			applied = true
1276
+			result = change
1279 1277
 		}
1280 1278
 	}
1281 1279
 	channel.stateMutex.Unlock()

+ 27
- 17
irc/chanserv.go Bestand weergeven

@@ -238,7 +238,16 @@ func csAmodeHandler(server *Server, client *Client, command string, params []str
238 238
 		}
239 239
 	case modes.Add, modes.Remove:
240 240
 		if len(affectedModes) > 0 {
241
-			csNotice(rb, fmt.Sprintf(client.t("Successfully set mode %s"), change.String()))
241
+			csNotice(rb, fmt.Sprintf(client.t("Successfully set persistent mode %s%s on %s"), string(change.Op), string(change.Mode), change.Arg))
242
+			// #729: apply change to current membership
243
+			for _, member := range channel.Members() {
244
+				if member.Account() == change.Arg {
245
+					applied, change := channel.applyModeToMember(client, change, rb)
246
+					if applied {
247
+						announceCmodeChanges(channel, modes.ModeChanges{change}, chanservMask, rb)
248
+					}
249
+				}
250
+			}
242 251
 		} else {
243 252
 			csNotice(rb, client.t("No changes were made"))
244 253
 		}
@@ -275,14 +284,14 @@ func csOpHandler(server *Server, client *Client, command string, params []string
275 284
 	if clientAccount == target.Account() {
276 285
 		givenMode = modes.ChannelFounder
277 286
 	}
278
-	change := channelInfo.applyModeToMember(client, givenMode, modes.Add, target.NickCasefolded(), rb)
279
-	if change != nil {
280
-		//TODO(dan): we should change the name of String and make it return a slice here
281
-		//TODO(dan): unify this code with code in modes.go
282
-		args := append([]string{channelName}, strings.Split(change.String(), " ")...)
283
-		for _, member := range channelInfo.Members() {
284
-			member.Send(nil, fmt.Sprintf("ChanServ!services@%s", client.server.name), "MODE", args...)
285
-		}
287
+	applied, change := channelInfo.applyModeToMember(client,
288
+		modes.ModeChange{Mode: givenMode,
289
+			Op:  modes.Add,
290
+			Arg: target.NickCasefolded(),
291
+		},
292
+		rb)
293
+	if applied {
294
+		announceCmodeChanges(channelInfo, modes.ModeChanges{change}, chanservMask, rb)
286 295
 	}
287 296
 
288 297
 	csNotice(rb, fmt.Sprintf(client.t("Successfully op'd in channel %s"), channelName))
@@ -326,14 +335,15 @@ func csRegisterHandler(server *Server, client *Client, command string, params []
326 335
 	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))
327 336
 
328 337
 	// give them founder privs
329
-	change := channelInfo.applyModeToMember(client, modes.ChannelFounder, modes.Add, client.NickCasefolded(), rb)
330
-	if change != nil {
331
-		//TODO(dan): we should change the name of String and make it return a slice here
332
-		//TODO(dan): unify this code with code in modes.go
333
-		args := append([]string{channelName}, strings.Split(change.String(), " ")...)
334
-		for _, member := range channelInfo.Members() {
335
-			member.Send(nil, fmt.Sprintf("ChanServ!services@%s", client.server.name), "MODE", args...)
336
-		}
338
+	applied, change := channelInfo.applyModeToMember(client,
339
+		modes.ModeChange{
340
+			Mode: modes.ChannelFounder,
341
+			Op:   modes.Add,
342
+			Arg:  client.NickCasefolded(),
343
+		},
344
+		rb)
345
+	if applied {
346
+		announceCmodeChanges(channelInfo, modes.ModeChanges{change}, chanservMask, rb)
337 347
 	}
338 348
 }
339 349
 

+ 14
- 25
irc/handlers.go Bestand weergeven

@@ -1530,38 +1530,25 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1530 1530
 	}
1531 1531
 	// process mode changes, include list operations (an empty set of changes does a list)
1532 1532
 	applied := channel.ApplyChannelModeChanges(client, msg.Command == "SAMODE", changes, rb)
1533
+	announceCmodeChanges(channel, applied, client.NickMaskString(), rb)
1533 1534
 
1534
-	// save changes
1535
-	var includeFlags uint
1536
-	for _, change := range applied {
1537
-		includeFlags |= IncludeModes
1538
-		if change.Mode == modes.BanMask || change.Mode == modes.ExceptMask || change.Mode == modes.InviteMask {
1539
-			includeFlags |= IncludeLists
1540
-		}
1541
-	}
1542
-
1543
-	if includeFlags != 0 {
1544
-		channel.MarkDirty(includeFlags)
1545
-	}
1535
+	return false
1536
+}
1546 1537
 
1538
+func announceCmodeChanges(channel *Channel, applied modes.ModeChanges, source string, rb *ResponseBuffer) {
1547 1539
 	// send out changes
1548 1540
 	if len(applied) > 0 {
1549
-		prefix := client.NickMaskString()
1550 1541
 		//TODO(dan): we should change the name of String and make it return a slice here
1551
-		args := append([]string{channel.name}, strings.Split(applied.String(), " ")...)
1552
-		rb.Add(nil, prefix, "MODE", args...)
1553
-		for _, session := range client.Sessions() {
1554
-			if session != rb.session {
1555
-				session.Send(nil, prefix, "MODE", args...)
1556
-			}
1557
-		}
1542
+		args := append([]string{channel.name}, applied.Strings()...)
1543
+		rb.Add(nil, source, "MODE", args...)
1558 1544
 		for _, member := range channel.Members() {
1559
-			if member != client {
1560
-				member.Send(nil, prefix, "MODE", args...)
1545
+			for _, session := range member.Sessions() {
1546
+				if session != rb.session {
1547
+					session.Send(nil, source, "MODE", args...)
1548
+				}
1561 1549
 			}
1562 1550
 		}
1563 1551
 	}
1564
-	return false
1565 1552
 }
1566 1553
 
1567 1554
 // MODE <client> [<modestring> [<mode arguments>...]]
@@ -1606,7 +1593,8 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1606 1593
 	}
1607 1594
 
1608 1595
 	if len(applied) > 0 {
1609
-		rb.Add(nil, cDetails.nickMask, "MODE", targetNick, applied.String())
1596
+		args := append([]string{targetNick}, applied.Strings()...)
1597
+		rb.Add(nil, cDetails.nickMask, "MODE", args...)
1610 1598
 	} else if hasPrivs {
1611 1599
 		rb.Add(nil, server.name, RPL_UMODEIS, targetNick, target.ModeString())
1612 1600
 		if target.HasMode(modes.LocalOperator) || target.HasMode(modes.Operator) {
@@ -2122,7 +2110,8 @@ func applyOper(client *Client, oper *Oper, rb *ResponseBuffer) {
2122 2110
 		client.server.snomasks.Send(sno.LocalOpers, fmt.Sprintf(ircfmt.Unescape("Client opered up $c[grey][$r%s$c[grey], $r%s$c[grey]]"), newDetails.nickMask, oper.Name))
2123 2111
 
2124 2112
 		rb.Broadcast(nil, client.server.name, RPL_YOUREOPER, details.nick, client.t("You are now an IRC operator"))
2125
-		rb.Broadcast(nil, client.server.name, "MODE", details.nick, applied.String())
2113
+		args := append([]string{details.nick}, applied.Strings()...)
2114
+		rb.Broadcast(nil, client.server.name, "MODE", args...)
2126 2115
 	} else {
2127 2116
 		client.server.snomasks.Send(sno.LocalOpers, fmt.Sprintf(ircfmt.Unescape("Client deopered $c[grey][$r%s$c[grey]]"), newDetails.nickMask))
2128 2117
 	}

+ 18
- 3
irc/modes.go Bestand weergeven

@@ -256,13 +256,28 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
256 256
 				continue
257 257
 			}
258 258
 
259
-			change := channel.applyModeToMember(client, change.Mode, change.Op, nick, rb)
260
-			if change != nil {
261
-				applied = append(applied, *change)
259
+			success, change := channel.applyModeToMember(client, change, rb)
260
+			if success {
261
+				applied = append(applied, change)
262 262
 			}
263 263
 		}
264 264
 	}
265 265
 
266
+	var includeFlags uint
267
+	for _, change := range applied {
268
+		switch change.Mode {
269
+		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
270
+			includeFlags |= IncludeLists
271
+		case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
272
+			// these are never persisted currently, but might be in the future (see discussion on #729)
273
+		default:
274
+			includeFlags |= IncludeModes
275
+		}
276
+	}
277
+	if includeFlags != 0 {
278
+		channel.MarkDirty(includeFlags)
279
+	}
280
+
266 281
 	// #649: don't send 324 RPL_CHANNELMODEIS if we were only working with mask lists
267 282
 	if len(applied) == 0 && !alreadySentPrivError && (maskOpCount == 0 || maskOpCount < len(changes)) {
268 283
 		args := append([]string{details.nick, chname}, channel.modeStrings(client)...)

+ 11
- 22
irc/modes/modes.go Bestand weergeven

@@ -28,10 +28,6 @@ var (
28 28
 // ModeOp is an operation performed with modes
29 29
 type ModeOp rune
30 30
 
31
-func (op ModeOp) String() string {
32
-	return string(op)
33
-}
34
-
35 31
 const (
36 32
 	// Add is used when adding the given key.
37 33
 	Add ModeOp = '+'
@@ -55,43 +51,36 @@ type ModeChange struct {
55 51
 	Arg  string
56 52
 }
57 53
 
58
-func (change *ModeChange) String() (str string) {
59
-	if (change.Op == Add) || (change.Op == Remove) {
60
-		str = change.Op.String()
61
-	}
62
-	str += change.Mode.String()
63
-	if change.Arg != "" {
64
-		str += " " + change.Arg
65
-	}
66
-	return
67
-}
68
-
69 54
 // ModeChanges are a collection of 'ModeChange's
70 55
 type ModeChanges []ModeChange
71 56
 
72
-func (changes ModeChanges) String() string {
57
+func (changes ModeChanges) Strings() (result []string) {
73 58
 	if len(changes) == 0 {
74
-		return ""
59
+		return
75 60
 	}
76 61
 
62
+	var builder strings.Builder
63
+
77 64
 	op := changes[0].Op
78
-	str := changes[0].Op.String()
65
+	builder.WriteRune(rune(op))
79 66
 
80 67
 	for _, change := range changes {
81 68
 		if change.Op != op {
82 69
 			op = change.Op
83
-			str += change.Op.String()
70
+			builder.WriteRune(rune(op))
84 71
 		}
85
-		str += change.Mode.String()
72
+		builder.WriteRune(rune(change.Mode))
86 73
 	}
87 74
 
75
+	result = append(result, builder.String())
76
+
88 77
 	for _, change := range changes {
89 78
 		if change.Arg == "" {
90 79
 			continue
91 80
 		}
92
-		str += " " + change.Arg
81
+		result = append(result, change.Arg)
93 82
 	}
94
-	return str
83
+	return
95 84
 }
96 85
 
97 86
 // Modes is just a raw list of modes

+ 16
- 0
irc/modes/modes_test.go Bestand weergeven

@@ -219,6 +219,22 @@ func TestHighestChannelUserMode(t *testing.T) {
219 219
 	}
220 220
 }
221 221
 
222
+func TestModeChangesString(t *testing.T) {
223
+	m := ModeChanges{
224
+		ModeChange{Op: Add, Mode: RegisteredOnly},
225
+		ModeChange{Op: Add, Mode: Key, Arg: "beer"},
226
+		ModeChange{Op: Add, Mode: BanMask, Arg: "shivaram"},
227
+	}
228
+	assertEqual(m.Strings(), []string{"+Rkb", "beer", "shivaram"}, t)
229
+
230
+	m = ModeChanges{
231
+		ModeChange{Op: Add, Mode: RegisteredOnly},
232
+		ModeChange{Op: Remove, Mode: Key, Arg: "beer"},
233
+		ModeChange{Op: Add, Mode: BanMask, Arg: "shivaram"},
234
+	}
235
+	assertEqual(m.Strings(), []string{"+R-k+b", "beer", "shivaram"}, t)
236
+}
237
+
222 238
 func BenchmarkModeString(b *testing.B) {
223 239
 	set := NewModeSet()
224 240
 	set.SetMode('A', true)

Laden…
Annuleren
Opslaan