Selaa lähdekoodia

modes: Fix modes, re-add channel modes

tags/v0.1.0
Daniel Oaks 8 vuotta sitten
vanhempi
commit
e19c1527a4
3 muutettua tiedostoa jossa 185 lisäystä ja 160 poistoa
  1. 31
    144
      irc/channel.go
  2. 153
    16
      irc/modes.go
  3. 1
    0
      irc/numerics.go

+ 31
- 144
irc/channel.go Näytä tiedosto

6
 package irc
6
 package irc
7
 
7
 
8
 import (
8
 import (
9
-	"fmt"
10
 	"log"
9
 	"log"
11
 	"strconv"
10
 	"strconv"
12
 )
11
 )
66
 		}
65
 		}
67
 
66
 
68
 		if len(buffer)+1+len(nick) > maxNamLen {
67
 		if len(buffer)+1+len(nick) > maxNamLen {
69
-			client.Send(nil, client.server.nameString, RPL_NAMREPLY, "=", channel.nameString, buffer)
68
+			client.Send(nil, client.server.nameString, RPL_NAMREPLY, client.nickString, "=", channel.nameString, buffer)
70
 			buffer = nick
69
 			buffer = nick
71
 			continue
70
 			continue
72
 		}
71
 		}
75
 		buffer += nick
74
 		buffer += nick
76
 	}
75
 	}
77
 
76
 
78
-	client.Send(nil, client.server.nameString, RPL_NAMREPLY, "=", channel.nameString, buffer)
79
-	client.Send(nil, client.server.nameString, RPL_ENDOFNAMES, channel.nameString, "End of NAMES list")
77
+	client.Send(nil, client.server.nameString, RPL_NAMREPLY, client.nickString, "=", channel.nameString, buffer)
78
+	client.Send(nil, client.server.nameString, RPL_ENDOFNAMES, client.nickString, channel.nameString, "End of NAMES list")
80
 }
79
 }
81
 
80
 
82
 func (channel *Channel) ClientIsOperator(client *Client) bool {
81
 func (channel *Channel) ClientIsOperator(client *Client) bool {
158
 		str += " " + strconv.FormatUint(channel.userLimit, 10)
157
 		str += " " + strconv.FormatUint(channel.userLimit, 10)
159
 	}
158
 	}
160
 
159
 
161
-	return
160
+	return str
162
 }
161
 }
163
 
162
 
164
 func (channel *Channel) IsFull() bool {
163
 func (channel *Channel) IsFull() bool {
199
 		return
198
 		return
200
 	}
199
 	}
201
 
200
 
201
+	for member := range channel.members {
202
+		member.Send(nil, client.nickMaskString, "JOIN", channel.nameString)
203
+	}
204
+
202
 	client.channels.Add(channel)
205
 	client.channels.Add(channel)
203
 	channel.members.Add(client)
206
 	channel.members.Add(client)
204
 	if !channel.flags[Persistent] && (len(channel.members) == 1) {
207
 	if !channel.flags[Persistent] && (len(channel.members) == 1) {
207
 	}
210
 	}
208
 
211
 
209
 	client.Send(nil, client.nickMaskString, "JOIN", channel.nameString)
212
 	client.Send(nil, client.nickMaskString, "JOIN", channel.nameString)
210
-	return
211
-	//TODO(dan): should we be continuing here????
212
-	// return was above this originally, is it required?
213
-	/*
214
-		for member := range channel.members {
215
-			member.Reply(reply)
216
-		}
217
-		channel.GetTopic(client)
218
-		channel.Names(client)
219
-	*/
213
+	channel.GetTopic(client)
214
+	channel.Names(client)
220
 }
215
 }
221
 
216
 
222
 func (channel *Channel) Part(client *Client, message string) {
217
 func (channel *Channel) Part(client *Client, message string) {
233
 
228
 
234
 func (channel *Channel) GetTopic(client *Client) {
229
 func (channel *Channel) GetTopic(client *Client) {
235
 	if !channel.members.Has(client) {
230
 	if !channel.members.Has(client) {
236
-		client.Send(nil, client.server.nameString, ERR_NOTONCHANNEL, channel.nameString, "You're not on that channel")
231
+		client.Send(nil, client.server.nameString, ERR_NOTONCHANNEL, client.nickString, channel.nameString, "You're not on that channel")
237
 		return
232
 		return
238
 	}
233
 	}
239
 
234
 
240
 	if channel.topic == "" {
235
 	if channel.topic == "" {
241
-		// clients appear not to expect this
242
-		//replier.Reply(RplNoTopic(channel))
236
+		client.Send(nil, client.server.nameString, RPL_NOTOPIC, client.nickString, channel.nameString, "No topic is set")
243
 		return
237
 		return
244
 	}
238
 	}
245
 
239
 
246
-	client.Send(nil, client.server.nameString, RPL_TOPIC, channel.nameString, channel.topic)
240
+	client.Send(nil, client.server.nameString, RPL_TOPIC, client.nickString, channel.nameString, channel.topic)
241
+	//TODO(dan): show topic time and setter here too
247
 }
242
 }
248
 
243
 
249
 func (channel *Channel) SetTopic(client *Client, topic string) {
244
 func (channel *Channel) SetTopic(client *Client, topic string) {
322
 }
317
 }
323
 
318
 
324
 func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
319
 func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
325
-	op ModeOp, nick string) bool {
326
-	if !channel.ClientIsOperator(client) {
327
-		client.Send(nil, client.server.nameString, ERR_CHANOPRIVSNEEDED, channel.nameString, "You're not a channel operator")
328
-		return false
329
-	}
330
-
320
+	op ModeOp, nick string) *ChannelModeChange {
331
 	if nick == "" {
321
 	if nick == "" {
332
 		//TODO(dan): shouldn't this be handled before it reaches this function?
322
 		//TODO(dan): shouldn't this be handled before it reaches this function?
333
 		client.Send(nil, client.server.nameString, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
323
 		client.Send(nil, client.server.nameString, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
334
-		return false
324
+		return nil
335
 	}
325
 	}
336
 
326
 
337
 	target := channel.server.clients.Get(Name(nick))
327
 	target := channel.server.clients.Get(Name(nick))
339
 		//TODO(dan): investigate using NOSUCHNICK and NOSUCHCHANNEL specifically as that other IRCd (insp?) does,
329
 		//TODO(dan): investigate using NOSUCHNICK and NOSUCHCHANNEL specifically as that other IRCd (insp?) does,
340
 		// since I think that would make sense
330
 		// since I think that would make sense
341
 		client.Send(nil, client.server.nameString, ERR_NOSUCHNICK, nick, "No such nick")
331
 		client.Send(nil, client.server.nameString, ERR_NOSUCHNICK, nick, "No such nick")
342
-		return false
332
+		return nil
343
 	}
333
 	}
344
 
334
 
345
 	if !channel.members.Has(target) {
335
 	if !channel.members.Has(target) {
346
 		client.Send(nil, client.server.nameString, ERR_USERNOTINCHANNEL, client.nickString, channel.nameString, "They aren't on that channel")
336
 		client.Send(nil, client.server.nameString, ERR_USERNOTINCHANNEL, client.nickString, channel.nameString, "They aren't on that channel")
347
-		return false
337
+		return nil
348
 	}
338
 	}
349
 
339
 
350
 	switch op {
340
 	switch op {
351
 	case Add:
341
 	case Add:
352
 		if channel.members[target][mode] {
342
 		if channel.members[target][mode] {
353
-			return false
343
+			return nil
354
 		}
344
 		}
355
 		channel.members[target][mode] = true
345
 		channel.members[target][mode] = true
356
-		return true
346
+		return &ChannelModeChange{
347
+			op:   Add,
348
+			mode: mode,
349
+			arg:  nick,
350
+		}
357
 
351
 
358
 	case Remove:
352
 	case Remove:
359
 		if !channel.members[target][mode] {
353
 		if !channel.members[target][mode] {
360
-			return false
354
+			return nil
361
 		}
355
 		}
362
 		channel.members[target][mode] = false
356
 		channel.members[target][mode] = false
363
-		return true
357
+		return &ChannelModeChange{
358
+			op:   Remove,
359
+			mode: mode,
360
+			arg:  nick,
361
+		}
364
 	}
362
 	}
365
-	return false
363
+	return nil
366
 }
364
 }
367
 
365
 
368
 func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) {
366
 func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) {
404
 	return false
402
 	return false
405
 }
403
 }
406
 
404
 
407
-func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) bool {
408
-	switch change.mode {
409
-	case BanMask, ExceptMask, InviteMask:
410
-		return channel.applyModeMask(client, change.mode, change.op,
411
-			NewName(change.arg))
412
-
413
-	case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Persistent, Secret:
414
-		return channel.applyModeFlag(client, change.mode, change.op)
415
-
416
-	case Key:
417
-		if !channel.ClientIsOperator(client) {
418
-			client.Send(nil, client.server.nameString, ERR_CHANOPRIVSNEEDED, channel.nameString, "You're not a channel operator")
419
-			return false
420
-		}
421
-
422
-		switch change.op {
423
-		case Add:
424
-			if change.arg == "" {
425
-				client.Send(nil, client.server.nameString, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
426
-				return false
427
-			}
428
-			key := change.arg
429
-			if key == channel.key {
430
-				return false
431
-			}
432
-
433
-			channel.key = key
434
-			return true
435
-
436
-		case Remove:
437
-			channel.key = ""
438
-			return true
439
-		}
440
-
441
-	case UserLimit:
442
-		limit, err := strconv.ParseUint(change.arg, 10, 64)
443
-		if err != nil {
444
-			client.Send(nil, client.server.nameString, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
445
-			return false
446
-		}
447
-		if (limit == 0) || (limit == channel.userLimit) {
448
-			return false
449
-		}
450
-
451
-		channel.userLimit = limit
452
-		return true
453
-
454
-	case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
455
-		var hasPrivs bool
456
-
457
-		// make sure client has privs to edit the given prefix
458
-		for _, mode := range ChannelPrivModes {
459
-			if channel.members[client][mode] {
460
-				hasPrivs = true
461
-
462
-				// Admins can't give other people Admin or remove it from others,
463
-				// standard for that channel mode, we worry about this later
464
-				if mode == ChannelAdmin && change.mode == ChannelAdmin {
465
-					hasPrivs = false
466
-				}
467
-
468
-				break
469
-			} else if mode == change.mode {
470
-				break
471
-			}
472
-		}
473
-
474
-		name := NewName(change.arg)
475
-
476
-		if !hasPrivs {
477
-			if change.op == Remove && name.ToLower() == client.nick.ToLower() {
478
-				// success!
479
-			} else {
480
-				client.Send(nil, client.server.nameString, ERR_CHANOPRIVSNEEDED, channel.nameString, "You're not a channel operator")
481
-				return false
482
-			}
483
-		}
484
-
485
-		return channel.applyModeMember(client, change.mode, change.op, name.String())
486
-
487
-	default:
488
-		client.Send(nil, client.server.nameString, ERR_UNKNOWNMODE, change.mode.String(), fmt.Sprintf(":is an unknown mode char to me for %s", channel))
489
-	}
490
-	return false
491
-}
492
-
493
-func (channel *Channel) Mode(client *Client, changes ChannelModeChanges) {
494
-	if len(changes) == 0 {
495
-		client.Send(nil, client.server.nameString, RPL_CHANNELMODEIS, channel.nameString, channel.ModeString(client))
496
-		return
497
-	}
498
-
499
-	applied := make(ChannelModeChanges, 0)
500
-	for _, change := range changes {
501
-		if channel.applyMode(client, change) {
502
-			applied = append(applied, change)
503
-		}
504
-	}
505
-
506
-	if len(applied) > 0 {
507
-		appliedString := applied.String()
508
-		for member := range channel.members {
509
-			member.Send(nil, client.nickMaskString, "MODE", channel.nameString, appliedString)
510
-		}
511
-
512
-		if err := channel.Persist(); err != nil {
513
-			log.Println("Channel.Persist:", channel, err)
514
-		}
515
-	}
516
-}
517
-
518
 func (channel *Channel) Persist() (err error) {
405
 func (channel *Channel) Persist() (err error) {
519
 	if channel.flags[Persistent] {
406
 	if channel.flags[Persistent] {
520
 		_, err = channel.server.db.Exec(`
407
 		_, err = channel.server.db.Exec(`

+ 153
- 16
irc/modes.go Näytä tiedosto

132
 func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
132
 func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
133
 	name := NewName(msg.Params[0])
133
 	name := NewName(msg.Params[0])
134
 	if name.IsChannel() {
134
 	if name.IsChannel() {
135
-		// return cmodeHandler(server, client, msg)
136
-		client.Notice("CMODEs are not yet supported!")
137
-		return false
135
+		return cmodeHandler(server, client, msg)
138
 	} else {
136
 	} else {
139
 		return umodeHandler(server, client, msg)
137
 		return umodeHandler(server, client, msg)
140
 	}
138
 	}
164
 
162
 
165
 	// assemble changes
163
 	// assemble changes
166
 	changes := make(ModeChanges, 0)
164
 	changes := make(ModeChanges, 0)
165
+	applied := make(ModeChanges, 0)
167
 
166
 
168
 	if len(msg.Params) > 1 {
167
 	if len(msg.Params) > 1 {
169
-		modeArg := msg.Params[0]
168
+		modeArg := msg.Params[1]
170
 		op := ModeOp(modeArg[0])
169
 		op := ModeOp(modeArg[0])
171
 		if (op == Add) || (op == Remove) {
170
 		if (op == Add) || (op == Remove) {
172
 			modeArg = modeArg[1:]
171
 			modeArg = modeArg[1:]
173
 		} else {
172
 		} else {
174
-			client.Send(nil, server.nameString, ERR_UNKNOWNERROR, client.nickString, "MODE", "Mode string could not be parsed correctly")
173
+			client.Send(nil, server.nameString, ERR_UNKNOWNMODE, client.nickString, string(modeArg[1]), "is an unknown mode character to me")
175
 			return false
174
 			return false
176
 		}
175
 		}
177
 
176
 
195
 						continue
194
 						continue
196
 					}
195
 					}
197
 					target.flags[change.mode] = true
196
 					target.flags[change.mode] = true
198
-					changes = append(changes, change)
197
+					applied = append(applied, change)
199
 
198
 
200
 				case Remove:
199
 				case Remove:
201
 					if !target.flags[change.mode] {
200
 					if !target.flags[change.mode] {
202
 						continue
201
 						continue
203
 					}
202
 					}
204
 					delete(target.flags, change.mode)
203
 					delete(target.flags, change.mode)
205
-					changes = append(changes, change)
204
+					applied = append(applied, change)
206
 				}
205
 				}
207
 
206
 
208
 			case Operator, LocalOperator:
207
 			case Operator, LocalOperator:
211
 						continue
210
 						continue
212
 					}
211
 					}
213
 					delete(target.flags, change.mode)
212
 					delete(target.flags, change.mode)
214
-					changes = append(changes, change)
213
+					applied = append(applied, change)
215
 				}
214
 				}
216
 			}
215
 			}
217
 		}
216
 		}
225
 	return false
224
 	return false
226
 }
225
 }
227
 
226
 
228
-/*
229
-func (msg *ChannelModeCommand) HandleServer(server *Server) {
230
-	client := msg.Client()
231
-	channel := server.channels.Get(msg.channel)
227
+// MODE <target> [<modestring> [<mode arguments>...]]
228
+func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
229
+	channelName := NewName(msg.Params[0])
230
+	channel := server.channels.Get(channelName)
231
+
232
 	if channel == nil {
232
 	if channel == nil {
233
-		client.ErrNoSuchChannel(msg.channel)
234
-		return
233
+		client.Send(nil, server.nameString, ERR_NOSUCHCHANNEL, client.nickString, msg.Params[0], "No such channel")
234
+		return false
235
 	}
235
 	}
236
 
236
 
237
-	channel.Mode(client, msg.changes)
237
+	// assemble changes
238
+	//TODO(dan): split out assembling changes into func that returns changes, err
239
+	changes := make(ChannelModeChanges, 0)
240
+	applied := make(ChannelModeChanges, 0)
241
+
242
+	if len(msg.Params) > 1 {
243
+		modeArg := msg.Params[1]
244
+		op := ModeOp(modeArg[0])
245
+		if (op == Add) || (op == Remove) {
246
+			modeArg = modeArg[1:]
247
+		} else {
248
+			client.Send(nil, server.nameString, ERR_UNKNOWNMODE, client.nickString, string(modeArg[1]), "is an unknown mode character to me")
249
+			return false
250
+		}
251
+
252
+		skipArgs := 2
253
+		for _, mode := range modeArg {
254
+			if mode == '-' || mode == '+' {
255
+				op = ModeOp(mode)
256
+				continue
257
+			}
258
+			change := ChannelModeChange{
259
+				mode: ChannelMode(mode),
260
+				op:   op,
261
+			}
262
+
263
+			// put arg into modechange if needed
264
+			switch ChannelMode(mode) {
265
+			case BanMask, ExceptMask, InviteMask:
266
+				if len(msg.Params) > skipArgs {
267
+					change.arg = msg.Params[skipArgs]
268
+					skipArgs += 1
269
+				} else {
270
+					change.op = List
271
+				}
272
+			case Key, UserLimit, ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
273
+				if len(msg.Params) > skipArgs {
274
+					change.arg = msg.Params[skipArgs]
275
+					skipArgs += 1
276
+				} else {
277
+					continue
278
+				}
279
+			}
280
+
281
+			applied = append(applied, &change)
282
+		}
283
+
284
+		for _, change := range changes {
285
+			switch change.mode {
286
+			case BanMask, ExceptMask, InviteMask:
287
+				mask := change.arg
288
+				list := channel.lists[change.mode]
289
+				if list == nil {
290
+					// This should never happen, but better safe than panicky.
291
+					client.Send(nil, server.nameString, ERR_UNKNOWNERROR, client.nickString, "MODE", "Could not complete MODE command")
292
+					return false
293
+				}
294
+
295
+				if (change.op == List) || (mask == "") {
296
+					channel.ShowMaskList(client, change.mode)
297
+					continue
298
+				}
299
+
300
+				switch change.op {
301
+				case Add:
302
+					list.Add(Name(mask))
303
+					applied = append(applied, change)
304
+
305
+				case Remove:
306
+					list.Remove(Name(mask))
307
+					applied = append(applied, change)
308
+				}
309
+
310
+			case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Persistent, Secret:
311
+				switch change.op {
312
+				case Add:
313
+					if channel.flags[change.mode] {
314
+						continue
315
+					}
316
+					channel.flags[change.mode] = true
317
+					applied = append(applied, change)
318
+
319
+				case Remove:
320
+					if !channel.flags[change.mode] {
321
+						continue
322
+					}
323
+					delete(channel.flags, change.mode)
324
+					applied = append(applied, change)
325
+				}
326
+
327
+			case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
328
+				// make sure client has privs to edit the given prefix
329
+				var hasPrivs bool
330
+
331
+				for _, mode := range ChannelPrivModes {
332
+					if channel.members[client][mode] {
333
+						hasPrivs = true
334
+
335
+						// Admins can't give other people Admin or remove it from others,
336
+						// standard for that channel mode, we worry about this later
337
+						if mode == ChannelAdmin && change.mode == ChannelAdmin {
338
+							hasPrivs = false
339
+						}
340
+
341
+						break
342
+					} else if mode == change.mode {
343
+						break
344
+					}
345
+				}
346
+
347
+				name := NewName(change.arg)
348
+
349
+				if !hasPrivs {
350
+					if change.op == Remove && name.ToLower() == client.nick.ToLower() {
351
+						// success!
352
+					} else {
353
+						client.Send(nil, client.server.nameString, ERR_CHANOPRIVSNEEDED, channel.nameString, "You're not a channel operator")
354
+						continue
355
+					}
356
+				}
357
+
358
+				change := channel.applyModeMember(client, change.mode, change.op, change.arg)
359
+				if change != nil {
360
+					applied = append(changes, change)
361
+				}
362
+			}
363
+		}
364
+	}
365
+
366
+	if len(applied) > 0 {
367
+		//TODO(dan): we should change the name of String and make it return a slice here
368
+		args := append([]string{channel.nameString}, strings.Split(applied.String(), " ")...)
369
+		client.Send(nil, client.nickMaskString, "MODE", args...)
370
+	} else {
371
+		//TODO(dan): we should just make ModeString return a slice here
372
+		args := append([]string{client.nickString, channel.nameString}, strings.Split(channel.ModeString(client), " ")...)
373
+		client.Send(nil, client.nickMaskString, RPL_CHANNELMODEIS, args...)
374
+	}
375
+	return false
238
 }
376
 }
239
-*/

+ 1
- 0
irc/numerics.go Näytä tiedosto

60
 	RPL_LISTEND           = "323"
60
 	RPL_LISTEND           = "323"
61
 	RPL_CHANNELMODEIS     = "324"
61
 	RPL_CHANNELMODEIS     = "324"
62
 	RPL_UNIQOPIS          = "325"
62
 	RPL_UNIQOPIS          = "325"
63
+	RPL_CREATIONTIME      = "329"
63
 	RPL_NOTOPIC           = "331"
64
 	RPL_NOTOPIC           = "331"
64
 	RPL_TOPIC             = "332"
65
 	RPL_TOPIC             = "332"
65
 	RPL_INVITING          = "341"
66
 	RPL_INVITING          = "341"

Loading…
Peruuta
Tallenna