Bläddra i källkod

Get labeled-reply working just fine

tags/v0.11.0-beta
Daniel Oaks 6 år sedan
förälder
incheckning
e0fa97d344
14 ändrade filer med 526 tillägg och 472 borttagningar
  1. 4
    4
      irc/accounts.go
  2. 92
    64
      irc/channel.go
  3. 4
    4
      irc/channelmanager.go
  4. 16
    16
      irc/chanserv.go
  5. 2
    2
      irc/client.go
  6. 329
    281
      irc/handlers.go
  7. 4
    4
      irc/help.go
  8. 4
    4
      irc/modes.go
  9. 1
    1
      irc/monitor.go
  10. 5
    5
      irc/nickname.go
  11. 25
    25
      irc/nickserv.go
  12. 6
    1
      irc/responsebuffer.go
  13. 13
    9
      irc/roleplay.go
  14. 21
    52
      irc/server.go

+ 4
- 4
irc/accounts.go Visa fil

27
 var (
27
 var (
28
 	// EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
28
 	// EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
29
 	// This can be moved to some other data structure/place if we need to load/unload mechs later.
29
 	// This can be moved to some other data structure/place if we need to load/unload mechs later.
30
-	EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte) bool{
30
+	EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte, *ResponseBuffer) bool{
31
 		"PLAIN":    authPlainHandler,
31
 		"PLAIN":    authPlainHandler,
32
 		"EXTERNAL": authExternalHandler,
32
 		"EXTERNAL": authExternalHandler,
33
 	}
33
 	}
128
 }
128
 }
129
 
129
 
130
 // successfulSaslAuth means that a SASL auth attempt completed successfully, and is used to dispatch messages.
130
 // successfulSaslAuth means that a SASL auth attempt completed successfully, and is used to dispatch messages.
131
-func (client *Client) successfulSaslAuth() {
132
-	client.Send(nil, client.server.name, RPL_LOGGEDIN, client.nick, client.nickMaskString, client.account.Name, fmt.Sprintf("You are now logged in as %s", client.account.Name))
133
-	client.Send(nil, client.server.name, RPL_SASLSUCCESS, client.nick, client.t("SASL authentication successful"))
131
+func (client *Client) successfulSaslAuth(rb *ResponseBuffer) {
132
+	rb.Add(nil, client.server.name, RPL_LOGGEDIN, client.nick, client.nickMaskString, client.account.Name, fmt.Sprintf("You are now logged in as %s", client.account.Name))
133
+	rb.Add(nil, client.server.name, RPL_SASLSUCCESS, client.nick, client.t("SASL authentication successful"))
134
 
134
 
135
 	// dispatch account-notify
135
 	// dispatch account-notify
136
 	for friend := range client.Friends(caps.AccountNotify) {
136
 	for friend := range client.Friends(caps.AccountNotify) {

+ 92
- 64
irc/channel.go Visa fil

171
 }
171
 }
172
 
172
 
173
 // Names sends the list of users joined to the channel to the given client.
173
 // Names sends the list of users joined to the channel to the given client.
174
-func (channel *Channel) Names(client *Client) {
174
+func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
175
 	currentNicks := channel.nicks(client)
175
 	currentNicks := channel.nicks(client)
176
 	// assemble and send replies
176
 	// assemble and send replies
177
 	maxNamLen := 480 - len(client.server.name) - len(client.nick)
177
 	maxNamLen := 480 - len(client.server.name) - len(client.nick)
183
 		}
183
 		}
184
 
184
 
185
 		if len(buffer)+1+len(nick) > maxNamLen {
185
 		if len(buffer)+1+len(nick) > maxNamLen {
186
-			client.Send(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
186
+			rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
187
 			buffer = nick
187
 			buffer = nick
188
 			continue
188
 			continue
189
 		}
189
 		}
192
 		buffer += nick
192
 		buffer += nick
193
 	}
193
 	}
194
 
194
 
195
-	client.Send(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
196
-	client.Send(nil, client.server.name, RPL_ENDOFNAMES, client.nick, channel.name, client.t("End of NAMES list"))
195
+	rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
196
+	rb.Add(nil, client.server.name, RPL_ENDOFNAMES, client.nick, channel.name, client.t("End of NAMES list"))
197
 }
197
 }
198
 
198
 
199
 // ClientIsAtLeast returns whether the client has at least the given channel privilege.
199
 // ClientIsAtLeast returns whether the client has at least the given channel privilege.
349
 
349
 
350
 // Join joins the given client to this channel (if they can be joined).
350
 // Join joins the given client to this channel (if they can be joined).
351
 //TODO(dan): /SAJOIN and maybe a ForceJoin function?
351
 //TODO(dan): /SAJOIN and maybe a ForceJoin function?
352
-func (channel *Channel) Join(client *Client, key string) {
352
+func (channel *Channel) Join(client *Client, key string, rb *ResponseBuffer) {
353
 	if channel.hasClient(client) {
353
 	if channel.hasClient(client) {
354
 		// already joined, no message needs to be sent
354
 		// already joined, no message needs to be sent
355
 		return
355
 		return
356
 	}
356
 	}
357
 
357
 
358
 	if channel.IsFull() {
358
 	if channel.IsFull() {
359
-		client.Send(nil, client.server.name, ERR_CHANNELISFULL, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
359
+		rb.Add(nil, client.server.name, ERR_CHANNELISFULL, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
360
 		return
360
 		return
361
 	}
361
 	}
362
 
362
 
363
 	if !channel.CheckKey(key) {
363
 	if !channel.CheckKey(key) {
364
-		client.Send(nil, client.server.name, ERR_BADCHANNELKEY, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
364
+		rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
365
 		return
365
 		return
366
 	}
366
 	}
367
 
367
 
368
 	isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded)
368
 	isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded)
369
 	if channel.flags[modes.InviteOnly] && !isInvited {
369
 	if channel.flags[modes.InviteOnly] && !isInvited {
370
-		client.Send(nil, client.server.name, ERR_INVITEONLYCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
370
+		rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
371
 		return
371
 		return
372
 	}
372
 	}
373
 
373
 
374
 	if channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) &&
374
 	if channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) &&
375
 		!isInvited &&
375
 		!isInvited &&
376
 		!channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) {
376
 		!channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) {
377
-		client.Send(nil, client.server.name, ERR_BANNEDFROMCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
377
+		rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
378
 		return
378
 		return
379
 	}
379
 	}
380
 
380
 
381
 	client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", client.nick, channel.name))
381
 	client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", client.nick, channel.name))
382
 
382
 
383
 	for _, member := range channel.Members() {
383
 	for _, member := range channel.Members() {
384
-		if member.capabilities.Has(caps.ExtendedJoin) {
385
-			member.Send(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
384
+		if member == client {
385
+			if member.capabilities.Has(caps.ExtendedJoin) {
386
+				rb.Add(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
387
+			} else {
388
+				rb.Add(nil, client.nickMaskString, "JOIN", channel.name)
389
+			}
386
 		} else {
390
 		} else {
387
-			member.Send(nil, client.nickMaskString, "JOIN", channel.name)
391
+			if member.capabilities.Has(caps.ExtendedJoin) {
392
+				member.Send(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
393
+			} else {
394
+				member.Send(nil, client.nickMaskString, "JOIN", channel.name)
395
+			}
388
 		}
396
 		}
389
 	}
397
 	}
390
 
398
 
411
 	}
419
 	}
412
 
420
 
413
 	if client.capabilities.Has(caps.ExtendedJoin) {
421
 	if client.capabilities.Has(caps.ExtendedJoin) {
414
-		client.Send(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
422
+		rb.Add(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
415
 	} else {
423
 	} else {
416
-		client.Send(nil, client.nickMaskString, "JOIN", channel.name)
424
+		rb.Add(nil, client.nickMaskString, "JOIN", channel.name)
417
 	}
425
 	}
418
 	// don't send topic when it's an entirely new channel
426
 	// don't send topic when it's an entirely new channel
419
 	if !newChannel {
427
 	if !newChannel {
420
-		channel.SendTopic(client)
428
+		channel.SendTopic(client, rb)
421
 	}
429
 	}
422
-	channel.Names(client)
430
+	channel.Names(client, rb)
423
 	if givenMode != nil {
431
 	if givenMode != nil {
424
 		for _, member := range channel.Members() {
432
 		for _, member := range channel.Members() {
425
-			member.Send(nil, client.server.name, "MODE", channel.name, fmt.Sprintf("+%v", *givenMode), client.nick)
433
+			if member == client {
434
+				rb.Add(nil, client.server.name, "MODE", channel.name, fmt.Sprintf("+%v", *givenMode), client.nick)
435
+			} else {
436
+				member.Send(nil, client.server.name, "MODE", channel.name, fmt.Sprintf("+%v", *givenMode), client.nick)
437
+			}
426
 		}
438
 		}
427
 	}
439
 	}
428
 }
440
 }
429
 
441
 
430
 // Part parts the given client from this channel, with the given message.
442
 // Part parts the given client from this channel, with the given message.
431
-func (channel *Channel) Part(client *Client, message string) {
443
+func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
432
 	if !channel.hasClient(client) {
444
 	if !channel.hasClient(client) {
433
-		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
445
+		rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
434
 		return
446
 		return
435
 	}
447
 	}
436
 
448
 
437
 	for _, member := range channel.Members() {
449
 	for _, member := range channel.Members() {
438
-		member.Send(nil, client.nickMaskString, "PART", channel.name, message)
450
+		if member == client {
451
+			rb.Add(nil, client.nickMaskString, "PART", channel.name, message)
452
+		} else {
453
+			member.Send(nil, client.nickMaskString, "PART", channel.name, message)
454
+		}
439
 	}
455
 	}
440
 	channel.Quit(client)
456
 	channel.Quit(client)
441
 
457
 
443
 }
459
 }
444
 
460
 
445
 // SendTopic sends the channel topic to the given client.
461
 // SendTopic sends the channel topic to the given client.
446
-func (channel *Channel) SendTopic(client *Client) {
462
+func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer) {
447
 	if !channel.hasClient(client) {
463
 	if !channel.hasClient(client) {
448
-		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
464
+		rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
449
 		return
465
 		return
450
 	}
466
 	}
451
 
467
 
457
 	channel.stateMutex.RUnlock()
473
 	channel.stateMutex.RUnlock()
458
 
474
 
459
 	if topic == "" {
475
 	if topic == "" {
460
-		client.Send(nil, client.server.name, RPL_NOTOPIC, client.nick, name, client.t("No topic is set"))
476
+		rb.Add(nil, client.server.name, RPL_NOTOPIC, client.nick, name, client.t("No topic is set"))
461
 		return
477
 		return
462
 	}
478
 	}
463
 
479
 
464
-	client.Send(nil, client.server.name, RPL_TOPIC, client.nick, name, topic)
465
-	client.Send(nil, client.server.name, RPL_TOPICTIME, client.nick, name, topicSetBy, strconv.FormatInt(topicSetTime.Unix(), 10))
480
+	rb.Add(nil, client.server.name, RPL_TOPIC, client.nick, name, topic)
481
+	rb.Add(nil, client.server.name, RPL_TOPICTIME, client.nick, name, topicSetBy, strconv.FormatInt(topicSetTime.Unix(), 10))
466
 }
482
 }
467
 
483
 
468
 // SetTopic sets the topic of this channel, if the client is allowed to do so.
484
 // SetTopic sets the topic of this channel, if the client is allowed to do so.
469
-func (channel *Channel) SetTopic(client *Client, topic string) {
485
+func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) {
470
 	if !(client.flags[modes.Operator] || channel.hasClient(client)) {
486
 	if !(client.flags[modes.Operator] || channel.hasClient(client)) {
471
-		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
487
+		rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
472
 		return
488
 		return
473
 	}
489
 	}
474
 
490
 
475
 	if channel.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
491
 	if channel.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
476
-		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
492
+		rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
477
 		return
493
 		return
478
 	}
494
 	}
479
 
495
 
488
 	channel.stateMutex.Unlock()
504
 	channel.stateMutex.Unlock()
489
 
505
 
490
 	for _, member := range channel.Members() {
506
 	for _, member := range channel.Members() {
491
-		member.Send(nil, client.nickMaskString, "TOPIC", channel.name, topic)
507
+		if member == client {
508
+			rb.Add(nil, client.nickMaskString, "TOPIC", channel.name, topic)
509
+		} else {
510
+			member.Send(nil, client.nickMaskString, "TOPIC", channel.name, topic)
511
+		}
492
 	}
512
 	}
493
 
513
 
494
 	go channel.server.channelRegistry.StoreChannel(channel, false)
514
 	go channel.server.channelRegistry.StoreChannel(channel, false)
513
 }
533
 }
514
 
534
 
515
 // TagMsg sends a tag message to everyone in this channel who can accept them.
535
 // TagMsg sends a tag message to everyone in this channel who can accept them.
516
-func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
517
-	channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil)
536
+func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, rb *ResponseBuffer) {
537
+	channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil, rb)
518
 }
538
 }
519
 
539
 
520
 // sendMessage sends a given message to everyone on this channel.
540
 // sendMessage sends a given message to everyone on this channel.
521
-func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
541
+func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string, rb *ResponseBuffer) {
522
 	if !channel.CanSpeak(client) {
542
 	if !channel.CanSpeak(client) {
523
-		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
543
+		rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
524
 		return
544
 		return
525
 	}
545
 	}
526
 
546
 
554
 		}
574
 		}
555
 
575
 
556
 		if message == nil {
576
 		if message == nil {
557
-			member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
577
+			rb.AddFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
558
 		} else {
578
 		} else {
559
-			member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name, *message)
579
+			rb.AddFromClient(msgid, client, messageTagsToUse, cmd, channel.name, *message)
560
 		}
580
 		}
561
 	}
581
 	}
562
 }
582
 }
563
 
583
 
564
 // SplitPrivMsg sends a private message to everyone in this channel.
584
 // SplitPrivMsg sends a private message to everyone in this channel.
565
-func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
566
-	channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message)
585
+func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage, rb *ResponseBuffer) {
586
+	channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message, rb)
567
 }
587
 }
568
 
588
 
569
 // SplitNotice sends a private message to everyone in this channel.
589
 // SplitNotice sends a private message to everyone in this channel.
570
-func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
571
-	channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message)
590
+func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage, rb *ResponseBuffer) {
591
+	channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message, rb)
572
 }
592
 }
573
 
593
 
574
-func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
594
+func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage, rb *ResponseBuffer) {
575
 	if !channel.CanSpeak(client) {
595
 	if !channel.CanSpeak(client) {
576
-		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
596
+		rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
577
 		return
597
 		return
578
 	}
598
 	}
579
 
599
 
595
 			tagsToUse = clientOnlyTags
615
 			tagsToUse = clientOnlyTags
596
 		}
616
 		}
597
 
617
 
598
-		if message == nil {
599
-			member.SendFromClient(msgid, client, tagsToUse, cmd, channel.name)
618
+		if member == client {
619
+			if message == nil {
620
+				rb.AddFromClient(msgid, client, tagsToUse, cmd, channel.name)
621
+			} else {
622
+				rb.AddSplitMessageFromClient(msgid, client, tagsToUse, cmd, channel.name, *message)
623
+			}
600
 		} else {
624
 		} else {
601
-			member.SendSplitMsgFromClient(msgid, client, tagsToUse, cmd, channel.name, *message)
625
+			if message == nil {
626
+				member.SendFromClient(msgid, client, tagsToUse, cmd, channel.name)
627
+			} else {
628
+				member.SendSplitMsgFromClient(msgid, client, tagsToUse, cmd, channel.name, *message)
629
+			}
602
 		}
630
 		}
603
 	}
631
 	}
604
 }
632
 }
605
 
633
 
606
-func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode, op modes.ModeOp, nick string) *modes.ModeChange {
634
+func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) *modes.ModeChange {
607
 	if nick == "" {
635
 	if nick == "" {
608
 		//TODO(dan): shouldn't this be handled before it reaches this function?
636
 		//TODO(dan): shouldn't this be handled before it reaches this function?
609
-		client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
637
+		rb.Add(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
610
 		return nil
638
 		return nil
611
 	}
639
 	}
612
 
640
 
613
 	casefoldedName, err := CasefoldName(nick)
641
 	casefoldedName, err := CasefoldName(nick)
614
 	target := channel.server.clients.Get(casefoldedName)
642
 	target := channel.server.clients.Get(casefoldedName)
615
 	if err != nil || target == nil {
643
 	if err != nil || target == nil {
616
-		client.Send(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nick, client.t("No such nick"))
644
+		rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nick, client.t("No such nick"))
617
 		return nil
645
 		return nil
618
 	}
646
 	}
619
 
647
 
628
 	channel.stateMutex.Unlock()
656
 	channel.stateMutex.Unlock()
629
 
657
 
630
 	if !exists {
658
 	if !exists {
631
-		client.Send(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
659
+		rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
632
 		return nil
660
 		return nil
633
 	} else if already {
661
 	} else if already {
634
 		return nil
662
 		return nil
642
 }
670
 }
643
 
671
 
644
 // ShowMaskList shows the given list to the client.
672
 // ShowMaskList shows the given list to the client.
645
-func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode) {
673
+func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode, rb *ResponseBuffer) {
646
 	// choose appropriate modes
674
 	// choose appropriate modes
647
 	var rpllist, rplendoflist string
675
 	var rpllist, rplendoflist string
648
 	if mode == modes.BanMask {
676
 	if mode == modes.BanMask {
660
 	channel.stateMutex.RLock()
688
 	channel.stateMutex.RLock()
661
 	// XXX don't acquire any new locks in this section, besides Socket.Write
689
 	// XXX don't acquire any new locks in this section, besides Socket.Write
662
 	for mask := range channel.lists[mode].masks {
690
 	for mask := range channel.lists[mode].masks {
663
-		client.Send(nil, client.server.name, rpllist, nick, channel.name, mask)
691
+		rb.Add(nil, client.server.name, rpllist, nick, channel.name, mask)
664
 	}
692
 	}
665
 	channel.stateMutex.RUnlock()
693
 	channel.stateMutex.RUnlock()
666
 
694
 
667
-	client.Send(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
695
+	rb.Add(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
668
 }
696
 }
669
 
697
 
670
-func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string) bool {
698
+func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string, rb *ResponseBuffer) bool {
671
 	list := channel.lists[mode]
699
 	list := channel.lists[mode]
672
 	if list == nil {
700
 	if list == nil {
673
 		// This should never happen, but better safe than panicky.
701
 		// This should never happen, but better safe than panicky.
675
 	}
703
 	}
676
 
704
 
677
 	if (op == modes.List) || (mask == "") {
705
 	if (op == modes.List) || (mask == "") {
678
-		channel.ShowMaskList(client, mode)
706
+		channel.ShowMaskList(client, mode, rb)
679
 		return false
707
 		return false
680
 	}
708
 	}
681
 
709
 
682
 	if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
710
 	if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
683
-		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
711
+		rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
684
 		return false
712
 		return false
685
 	}
713
 	}
686
 
714
 
705
 	client.removeChannel(channel)
733
 	client.removeChannel(channel)
706
 }
734
 }
707
 
735
 
708
-func (channel *Channel) Kick(client *Client, target *Client, comment string) {
736
+func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
709
 	if !(client.flags[modes.Operator] || channel.hasClient(client)) {
737
 	if !(client.flags[modes.Operator] || channel.hasClient(client)) {
710
-		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
738
+		rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
711
 		return
739
 		return
712
 	}
740
 	}
713
 	if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
741
 	if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
714
-		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
742
+		rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
715
 		return
743
 		return
716
 	}
744
 	}
717
 	if !channel.hasClient(target) {
745
 	if !channel.hasClient(target) {
718
-		client.Send(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
746
+		rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
719
 		return
747
 		return
720
 	}
748
 	}
721
 	if !channel.ClientHasPrivsOver(client, target) {
749
 	if !channel.ClientHasPrivsOver(client, target) {
722
-		client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
750
+		rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
723
 		return
751
 		return
724
 	}
752
 	}
725
 
753
 
738
 }
766
 }
739
 
767
 
740
 // Invite invites the given client to the channel, if the inviter can do so.
768
 // Invite invites the given client to the channel, if the inviter can do so.
741
-func (channel *Channel) Invite(invitee *Client, inviter *Client) {
769
+func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
742
 	if channel.flags[modes.InviteOnly] && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
770
 	if channel.flags[modes.InviteOnly] && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
743
-		inviter.Send(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator"))
771
+		rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator"))
744
 		return
772
 		return
745
 	}
773
 	}
746
 
774
 
747
 	if !channel.hasClient(inviter) {
775
 	if !channel.hasClient(inviter) {
748
-		inviter.Send(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, inviter.t("You're not on that channel"))
776
+		rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, inviter.t("You're not on that channel"))
749
 		return
777
 		return
750
 	}
778
 	}
751
 
779
 
764
 	}
792
 	}
765
 
793
 
766
 	//TODO(dan): should inviter.server.name here be inviter.nickMaskString ?
794
 	//TODO(dan): should inviter.server.name here be inviter.nickMaskString ?
767
-	inviter.Send(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name)
795
+	rb.Add(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name)
768
 	invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name)
796
 	invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name)
769
 	if invitee.flags[modes.Away] {
797
 	if invitee.flags[modes.Away] {
770
-		inviter.Send(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
798
+		rb.Add(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
771
 	}
799
 	}
772
 }
800
 }

+ 4
- 4
irc/channelmanager.go Visa fil

45
 }
45
 }
46
 
46
 
47
 // Join causes `client` to join the channel named `name`, creating it if necessary.
47
 // Join causes `client` to join the channel named `name`, creating it if necessary.
48
-func (cm *ChannelManager) Join(client *Client, name string, key string) error {
48
+func (cm *ChannelManager) Join(client *Client, name string, key string, rb *ResponseBuffer) error {
49
 	server := client.server
49
 	server := client.server
50
 	casefoldedName, err := CasefoldChannel(name)
50
 	casefoldedName, err := CasefoldChannel(name)
51
 	if err != nil || len(casefoldedName) > server.Limits().ChannelLen {
51
 	if err != nil || len(casefoldedName) > server.Limits().ChannelLen {
74
 	entry.pendingJoins += 1
74
 	entry.pendingJoins += 1
75
 	cm.Unlock()
75
 	cm.Unlock()
76
 
76
 
77
-	entry.channel.Join(client, key)
77
+	entry.channel.Join(client, key, rb)
78
 
78
 
79
 	cm.maybeCleanup(entry, true)
79
 	cm.maybeCleanup(entry, true)
80
 
80
 
107
 }
107
 }
108
 
108
 
109
 // Part parts `client` from the channel named `name`, deleting it if it's empty.
109
 // Part parts `client` from the channel named `name`, deleting it if it's empty.
110
-func (cm *ChannelManager) Part(client *Client, name string, message string) error {
110
+func (cm *ChannelManager) Part(client *Client, name string, message string, rb *ResponseBuffer) error {
111
 	casefoldedName, err := CasefoldChannel(name)
111
 	casefoldedName, err := CasefoldChannel(name)
112
 	if err != nil {
112
 	if err != nil {
113
 		return errNoSuchChannel
113
 		return errNoSuchChannel
120
 	if entry == nil {
120
 	if entry == nil {
121
 		return errNoSuchChannel
121
 		return errNoSuchChannel
122
 	}
122
 	}
123
-	entry.channel.Part(client, message)
123
+	entry.channel.Part(client, message, rb)
124
 	cm.maybeCleanup(entry, false)
124
 	cm.maybeCleanup(entry, false)
125
 	return nil
125
 	return nil
126
 }
126
 }

+ 16
- 16
irc/chanserv.go Visa fil

13
 )
13
 )
14
 
14
 
15
 // ChanServNotice sends the client a notice from ChanServ.
15
 // ChanServNotice sends the client a notice from ChanServ.
16
-func (client *Client) ChanServNotice(text string) {
17
-	client.Send(nil, fmt.Sprintf("ChanServ!services@%s", client.server.name), "NOTICE", client.nick, text)
16
+func (rb *ResponseBuffer) ChanServNotice(text string) {
17
+	rb.Add(nil, fmt.Sprintf("ChanServ!services@%s", rb.target.server.name), "NOTICE", rb.target.nick, text)
18
 }
18
 }
19
 
19
 
20
 // chanservReceiveNotice handles NOTICEs that ChanServ receives.
20
 // chanservReceiveNotice handles NOTICEs that ChanServ receives.
21
-func (server *Server) chanservNoticeHandler(client *Client, message string) {
21
+func (server *Server) chanservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
22
 	// do nothing
22
 	// do nothing
23
 }
23
 }
24
 
24
 
25
 // chanservReceiveNotice handles NOTICEs that ChanServ receives.
25
 // chanservReceiveNotice handles NOTICEs that ChanServ receives.
26
-func (server *Server) chanservPrivmsgHandler(client *Client, message string) {
26
+func (server *Server) chanservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
27
 	var params []string
27
 	var params []string
28
 	for _, p := range strings.Split(message, " ") {
28
 	for _, p := range strings.Split(message, " ") {
29
 		if len(p) > 0 {
29
 		if len(p) > 0 {
31
 		}
31
 		}
32
 	}
32
 	}
33
 	if len(params) < 1 {
33
 	if len(params) < 1 {
34
-		client.ChanServNotice(client.t("You need to run a command"))
34
+		rb.ChanServNotice(client.t("You need to run a command"))
35
 		//TODO(dan): dump CS help here
35
 		//TODO(dan): dump CS help here
36
 		return
36
 		return
37
 	}
37
 	}
41
 
41
 
42
 	if command == "register" {
42
 	if command == "register" {
43
 		if len(params) < 2 {
43
 		if len(params) < 2 {
44
-			client.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
44
+			rb.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
45
 			return
45
 			return
46
 		}
46
 		}
47
 
47
 
48
-		server.chanservRegisterHandler(client, params[1])
48
+		server.chanservRegisterHandler(client, params[1], rb)
49
 	} else {
49
 	} else {
50
-		client.ChanServNotice(client.t("Sorry, I don't know that command"))
50
+		rb.ChanServNotice(client.t("Sorry, I don't know that command"))
51
 	}
51
 	}
52
 }
52
 }
53
 
53
 
54
 // chanservRegisterHandler handles the ChanServ REGISTER subcommand.
54
 // chanservRegisterHandler handles the ChanServ REGISTER subcommand.
55
-func (server *Server) chanservRegisterHandler(client *Client, channelName string) {
55
+func (server *Server) chanservRegisterHandler(client *Client, channelName string, rb *ResponseBuffer) {
56
 	if !server.channelRegistrationEnabled {
56
 	if !server.channelRegistrationEnabled {
57
-		client.ChanServNotice(client.t("Channel registration is not enabled"))
57
+		rb.ChanServNotice(client.t("Channel registration is not enabled"))
58
 		return
58
 		return
59
 	}
59
 	}
60
 
60
 
61
 	channelKey, err := CasefoldChannel(channelName)
61
 	channelKey, err := CasefoldChannel(channelName)
62
 	if err != nil {
62
 	if err != nil {
63
-		client.ChanServNotice(client.t("Channel name is not valid"))
63
+		rb.ChanServNotice(client.t("Channel name is not valid"))
64
 		return
64
 		return
65
 	}
65
 	}
66
 
66
 
67
 	channelInfo := server.channels.Get(channelKey)
67
 	channelInfo := server.channels.Get(channelKey)
68
 	if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, modes.ChannelOperator) {
68
 	if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, modes.ChannelOperator) {
69
-		client.ChanServNotice(client.t("You must be an oper on the channel to register it"))
69
+		rb.ChanServNotice(client.t("You must be an oper on the channel to register it"))
70
 		return
70
 		return
71
 	}
71
 	}
72
 
72
 
73
 	if client.account == &NoAccount {
73
 	if client.account == &NoAccount {
74
-		client.ChanServNotice(client.t("You must be logged in to register a channel"))
74
+		rb.ChanServNotice(client.t("You must be logged in to register a channel"))
75
 		return
75
 		return
76
 	}
76
 	}
77
 
77
 
78
 	// this provides the synchronization that allows exactly one registration of the channel:
78
 	// this provides the synchronization that allows exactly one registration of the channel:
79
 	err = channelInfo.SetRegistered(client.AccountName())
79
 	err = channelInfo.SetRegistered(client.AccountName())
80
 	if err != nil {
80
 	if err != nil {
81
-		client.ChanServNotice(err.Error())
81
+		rb.ChanServNotice(err.Error())
82
 		return
82
 		return
83
 	}
83
 	}
84
 
84
 
85
 	// registration was successful: make the database reflect it
85
 	// registration was successful: make the database reflect it
86
 	go server.channelRegistry.StoreChannel(channelInfo, true)
86
 	go server.channelRegistry.StoreChannel(channelInfo, true)
87
 
87
 
88
-	client.ChanServNotice(fmt.Sprintf(client.t("Channel %s successfully registered"), channelName))
88
+	rb.ChanServNotice(fmt.Sprintf(client.t("Channel %s successfully registered"), channelName))
89
 
89
 
90
 	server.logger.Info("chanserv", fmt.Sprintf("Client %s registered channel %s", client.nick, channelName))
90
 	server.logger.Info("chanserv", fmt.Sprintf("Client %s registered channel %s", client.nick, channelName))
91
 	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))
91
 	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))
92
 
92
 
93
 	// give them founder privs
93
 	// give them founder privs
94
-	change := channelInfo.applyModeMemberNoMutex(client, modes.ChannelFounder, modes.Add, client.NickCasefolded())
94
+	change := channelInfo.applyModeMemberNoMutex(client, modes.ChannelFounder, modes.Add, client.NickCasefolded(), rb)
95
 	if change != nil {
95
 	if change != nil {
96
 		//TODO(dan): we should change the name of String and make it return a slice here
96
 		//TODO(dan): we should change the name of String and make it return a slice here
97
 		//TODO(dan): unify this code with code in modes.go
97
 		//TODO(dan): unify this code with code in modes.go

+ 2
- 2
irc/client.go Visa fil

593
 }
593
 }
594
 
594
 
595
 // RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
595
 // RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
596
-func (client *Client) RplISupport() {
596
+func (client *Client) RplISupport(rb *ResponseBuffer) {
597
 	translatedISupport := client.t("are supported by this server")
597
 	translatedISupport := client.t("are supported by this server")
598
 	for _, tokenline := range client.server.ISupport().CachedReply {
598
 	for _, tokenline := range client.server.ISupport().CachedReply {
599
 		// ugly trickery ahead
599
 		// ugly trickery ahead
600
 		tokenline = append(tokenline, translatedISupport)
600
 		tokenline = append(tokenline, translatedISupport)
601
-		client.Send(nil, client.server.name, RPL_ISUPPORT, append([]string{client.nick}, tokenline...)...)
601
+		rb.Add(nil, client.server.name, RPL_ISUPPORT, append([]string{client.nick}, tokenline...)...)
602
 	}
602
 	}
603
 }
603
 }
604
 
604
 

+ 329
- 281
irc/handlers.go
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 4
- 4
irc/help.go Visa fil

658
 }
658
 }
659
 
659
 
660
 // sendHelp sends the client help of the given string.
660
 // sendHelp sends the client help of the given string.
661
-func (client *Client) sendHelp(name string, text string) {
661
+func (client *Client) sendHelp(name string, text string, rb *ResponseBuffer) {
662
 	splitName := strings.Split(name, " ")
662
 	splitName := strings.Split(name, " ")
663
 	textLines := strings.Split(text, "\n")
663
 	textLines := strings.Split(text, "\n")
664
 
664
 
666
 		args := splitName
666
 		args := splitName
667
 		args = append(args, line)
667
 		args = append(args, line)
668
 		if i == 0 {
668
 		if i == 0 {
669
-			client.Send(nil, client.server.name, RPL_HELPSTART, args...)
669
+			rb.Add(nil, client.server.name, RPL_HELPSTART, args...)
670
 		} else {
670
 		} else {
671
-			client.Send(nil, client.server.name, RPL_HELPTXT, args...)
671
+			rb.Add(nil, client.server.name, RPL_HELPTXT, args...)
672
 		}
672
 		}
673
 	}
673
 	}
674
 	args := splitName
674
 	args := splitName
675
 	args = append(args, client.t("End of /HELPOP"))
675
 	args = append(args, client.t("End of /HELPOP"))
676
-	client.Send(nil, client.server.name, RPL_ENDOFHELP, args...)
676
+	rb.Add(nil, client.server.name, RPL_ENDOFHELP, args...)
677
 }
677
 }
678
 
678
 
679
 // GetHelpIndex returns the help index for the given language.
679
 // GetHelpIndex returns the help index for the given language.

+ 4
- 4
irc/modes.go Visa fil

169
 }
169
 }
170
 
170
 
171
 // ApplyChannelModeChanges applies a given set of mode changes.
171
 // ApplyChannelModeChanges applies a given set of mode changes.
172
-func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges) modes.ModeChanges {
172
+func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges, rb *ResponseBuffer) modes.ModeChanges {
173
 	// so we only output one warning for each list type when full
173
 	// so we only output one warning for each list type when full
174
 	listFullWarned := make(map[modes.Mode]bool)
174
 	listFullWarned := make(map[modes.Mode]bool)
175
 
175
 
222
 		switch change.Mode {
222
 		switch change.Mode {
223
 		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
223
 		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
224
 			if isListOp(change) {
224
 			if isListOp(change) {
225
-				channel.ShowMaskList(client, change.Mode)
225
+				channel.ShowMaskList(client, change.Mode, rb)
226
 				continue
226
 				continue
227
 			}
227
 			}
228
 
228
 
236
 			case modes.Add:
236
 			case modes.Add:
237
 				if channel.lists[change.Mode].Length() >= client.server.Limits().ChanListModes {
237
 				if channel.lists[change.Mode].Length() >= client.server.Limits().ChanListModes {
238
 					if !listFullWarned[change.Mode] {
238
 					if !listFullWarned[change.Mode] {
239
-						client.Send(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
239
+						rb.Add(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
240
 						listFullWarned[change.Mode] = true
240
 						listFullWarned[change.Mode] = true
241
 					}
241
 					}
242
 					continue
242
 					continue
289
 				continue
289
 				continue
290
 			}
290
 			}
291
 
291
 
292
-			change := channel.applyModeMemberNoMutex(client, change.Mode, change.Op, change.Arg)
292
+			change := channel.applyModeMemberNoMutex(client, change.Mode, change.Op, change.Arg, rb)
293
 			if change != nil {
293
 			if change != nil {
294
 				applied = append(applied, *change)
294
 				applied = append(applied, *change)
295
 			}
295
 			}

+ 1
- 1
irc/monitor.go Visa fil

103
 }
103
 }
104
 
104
 
105
 var (
105
 var (
106
-	metadataSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.IrcMessage) bool{
106
+	metadataSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool{
107
 		"-": monitorRemoveHandler,
107
 		"-": monitorRemoveHandler,
108
 		"+": monitorAddHandler,
108
 		"+": monitorAddHandler,
109
 		"c": monitorClearHandler,
109
 		"c": monitorClearHandler,

+ 5
- 5
irc/nickname.go Visa fil

20
 	}
20
 	}
21
 )
21
 )
22
 
22
 
23
-func performNickChange(server *Server, client *Client, target *Client, newnick string) bool {
23
+func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
24
 	nickname := strings.TrimSpace(newnick)
24
 	nickname := strings.TrimSpace(newnick)
25
 	cfnick, err := CasefoldName(nickname)
25
 	cfnick, err := CasefoldName(nickname)
26
 
26
 
27
 	if len(nickname) < 1 {
27
 	if len(nickname) < 1 {
28
-		client.Send(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, client.t("No nickname given"))
28
+		rb.Add(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, client.t("No nickname given"))
29
 		return false
29
 		return false
30
 	}
30
 	}
31
 
31
 
32
 	if err != nil || len(nickname) > server.Limits().NickLen || restrictedNicknames[cfnick] {
32
 	if err != nil || len(nickname) > server.Limits().NickLen || restrictedNicknames[cfnick] {
33
-		client.Send(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nickname, client.t("Erroneous nickname"))
33
+		rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nickname, client.t("Erroneous nickname"))
34
 		return false
34
 		return false
35
 	}
35
 	}
36
 
36
 
43
 	origNickMask := target.NickMaskString()
43
 	origNickMask := target.NickMaskString()
44
 	err = client.server.clients.SetNick(target, nickname)
44
 	err = client.server.clients.SetNick(target, nickname)
45
 	if err == errNicknameInUse {
45
 	if err == errNicknameInUse {
46
-		client.Send(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
46
+		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
47
 		return false
47
 		return false
48
 	} else if err != nil {
48
 	} else if err != nil {
49
-		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
49
+		rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
50
 		return false
50
 		return false
51
 	}
51
 	}
52
 
52
 

+ 25
- 25
irc/nickserv.go Visa fil

39
 }
39
 }
40
 
40
 
41
 // nickservNoticeHandler handles NOTICEs that NickServ receives.
41
 // nickservNoticeHandler handles NOTICEs that NickServ receives.
42
-func (server *Server) nickservNoticeHandler(client *Client, message string) {
42
+func (server *Server) nickservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
43
 	// do nothing
43
 	// do nothing
44
 }
44
 }
45
 
45
 
46
 // nickservPrivmsgHandler handles PRIVMSGs that NickServ receives.
46
 // nickservPrivmsgHandler handles PRIVMSGs that NickServ receives.
47
-func (server *Server) nickservPrivmsgHandler(client *Client, message string) {
47
+func (server *Server) nickservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
48
 	command, params := extractParam(message)
48
 	command, params := extractParam(message)
49
 	command = strings.ToLower(command)
49
 	command = strings.ToLower(command)
50
 
50
 
51
 	if command == "help" {
51
 	if command == "help" {
52
 		for _, line := range strings.Split(nickservHelp, "\n") {
52
 		for _, line := range strings.Split(nickservHelp, "\n") {
53
-			client.Notice(line)
53
+			rb.Notice(line)
54
 		}
54
 		}
55
 	} else if command == "register" {
55
 	} else if command == "register" {
56
 		// get params
56
 		// get params
58
 
58
 
59
 		// fail out if we need to
59
 		// fail out if we need to
60
 		if username == "" {
60
 		if username == "" {
61
-			client.Notice(client.t("No username supplied"))
61
+			rb.Notice(client.t("No username supplied"))
62
 			return
62
 			return
63
 		}
63
 		}
64
 
64
 
65
-		server.nickservRegisterHandler(client, username, passphrase)
65
+		server.nickservRegisterHandler(client, username, passphrase, rb)
66
 	} else if command == "identify" {
66
 	} else if command == "identify" {
67
 		// get params
67
 		// get params
68
 		username, passphrase := extractParam(params)
68
 		username, passphrase := extractParam(params)
69
 
69
 
70
-		server.nickservIdentifyHandler(client, username, passphrase)
70
+		server.nickservIdentifyHandler(client, username, passphrase, rb)
71
 	} else {
71
 	} else {
72
-		client.Notice(client.t("Command not recognised. To see the available commands, run /NS HELP"))
72
+		rb.Notice(client.t("Command not recognised. To see the available commands, run /NS HELP"))
73
 	}
73
 	}
74
 }
74
 }
75
 
75
 
76
-func (server *Server) nickservRegisterHandler(client *Client, username, passphrase string) {
76
+func (server *Server) nickservRegisterHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
77
 	certfp := client.certfp
77
 	certfp := client.certfp
78
 	if passphrase == "" && certfp == "" {
78
 	if passphrase == "" && certfp == "" {
79
-		client.Notice(client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
79
+		rb.Notice(client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
80
 		return
80
 		return
81
 	}
81
 	}
82
 
82
 
83
 	if !server.accountRegistration.Enabled {
83
 	if !server.accountRegistration.Enabled {
84
-		client.Notice(client.t("Account registration has been disabled"))
84
+		rb.Notice(client.t("Account registration has been disabled"))
85
 		return
85
 		return
86
 	}
86
 	}
87
 
87
 
89
 		if server.accountRegistration.AllowMultiplePerConnection {
89
 		if server.accountRegistration.AllowMultiplePerConnection {
90
 			client.LogoutOfAccount()
90
 			client.LogoutOfAccount()
91
 		} else {
91
 		} else {
92
-			client.Notice(client.t("You're already logged into an account"))
92
+			rb.Notice(client.t("You're already logged into an account"))
93
 			return
93
 			return
94
 		}
94
 		}
95
 	}
95
 	}
99
 	casefoldedAccount, err := CasefoldName(account)
99
 	casefoldedAccount, err := CasefoldName(account)
100
 	// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
100
 	// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
101
 	if err != nil || username == "*" {
101
 	if err != nil || username == "*" {
102
-		client.Notice(client.t("Account name is not valid"))
102
+		rb.Notice(client.t("Account name is not valid"))
103
 		return
103
 		return
104
 	}
104
 	}
105
 
105
 
111
 		_, err := tx.Get(accountKey)
111
 		_, err := tx.Get(accountKey)
112
 		if err != buntdb.ErrNotFound {
112
 		if err != buntdb.ErrNotFound {
113
 			//TODO(dan): if account verified key doesn't exist account is not verified, calc the maximum time without verification and expire and continue if need be
113
 			//TODO(dan): if account verified key doesn't exist account is not verified, calc the maximum time without verification and expire and continue if need be
114
-			client.Notice(client.t("Account already exists"))
114
+			rb.Notice(client.t("Account already exists"))
115
 			return errAccountCreation
115
 			return errAccountCreation
116
 		}
116
 		}
117
 
117
 
126
 	// account could not be created and relevant numerics have been dispatched, abort
126
 	// account could not be created and relevant numerics have been dispatched, abort
127
 	if err != nil {
127
 	if err != nil {
128
 		if err != errAccountCreation {
128
 		if err != errAccountCreation {
129
-			client.Notice(client.t("Account registration failed"))
129
+			rb.Notice(client.t("Account registration failed"))
130
 		}
130
 		}
131
 		return
131
 		return
132
 	}
132
 	}
178
 		if err == errCertfpAlreadyExists {
178
 		if err == errCertfpAlreadyExists {
179
 			errMsg = "An account already exists for your certificate fingerprint"
179
 			errMsg = "An account already exists for your certificate fingerprint"
180
 		}
180
 		}
181
-		client.Notice(errMsg)
181
+		rb.Notice(errMsg)
182
 		removeFailedAccRegisterData(server.store, casefoldedAccount)
182
 		removeFailedAccRegisterData(server.store, casefoldedAccount)
183
 		return
183
 		return
184
 	}
184
 	}
196
 		server.accounts[casefoldedAccount] = &account
196
 		server.accounts[casefoldedAccount] = &account
197
 		client.account = &account
197
 		client.account = &account
198
 
198
 
199
-		client.Notice(client.t("Account created"))
200
-		client.Send(nil, server.name, RPL_LOGGEDIN, client.nick, client.nickMaskString, account.Name, fmt.Sprintf(client.t("You are now logged in as %s"), account.Name))
201
-		client.Send(nil, server.name, RPL_SASLSUCCESS, client.nick, client.t("Authentication successful"))
199
+		rb.Notice(client.t("Account created"))
200
+		rb.Add(nil, server.name, RPL_LOGGEDIN, client.nick, client.nickMaskString, account.Name, fmt.Sprintf(client.t("You are now logged in as %s"), account.Name))
201
+		rb.Add(nil, server.name, RPL_SASLSUCCESS, client.nick, client.t("Authentication successful"))
202
 		server.snomasks.Send(sno.LocalAccounts, fmt.Sprintf(ircfmt.Unescape("Account registered $c[grey][$r%s$c[grey]] by $c[grey][$r%s$c[grey]]"), account.Name, client.nickMaskString))
202
 		server.snomasks.Send(sno.LocalAccounts, fmt.Sprintf(ircfmt.Unescape("Account registered $c[grey][$r%s$c[grey]] by $c[grey][$r%s$c[grey]]"), account.Name, client.nickMaskString))
203
 		return nil
203
 		return nil
204
 	})
204
 	})
205
 	if err != nil {
205
 	if err != nil {
206
-		client.Notice(client.t("Account registration failed"))
206
+		rb.Notice(client.t("Account registration failed"))
207
 		removeFailedAccRegisterData(server.store, casefoldedAccount)
207
 		removeFailedAccRegisterData(server.store, casefoldedAccount)
208
 		return
208
 		return
209
 	}
209
 	}
210
 }
210
 }
211
 
211
 
212
-func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string) {
212
+func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
213
 	// fail out if we need to
213
 	// fail out if we need to
214
 	if !server.accountAuthenticationEnabled {
214
 	if !server.accountAuthenticationEnabled {
215
-		client.Notice(client.t("Login has been disabled"))
215
+		rb.Notice(client.t("Login has been disabled"))
216
 		return
216
 		return
217
 	}
217
 	}
218
 
218
 
221
 		// keep it the same as in the ACC CREATE stage
221
 		// keep it the same as in the ACC CREATE stage
222
 		accountKey, err := CasefoldName(username)
222
 		accountKey, err := CasefoldName(username)
223
 		if err != nil {
223
 		if err != nil {
224
-			client.Notice(client.t("Could not login with your username/password"))
224
+			rb.Notice(client.t("Could not login with your username/password"))
225
 			return
225
 			return
226
 		}
226
 		}
227
 
227
 
259
 		})
259
 		})
260
 
260
 
261
 		if err == nil {
261
 		if err == nil {
262
-			client.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
262
+			rb.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
263
 			return
263
 			return
264
 		}
264
 		}
265
 	}
265
 	}
306
 		})
306
 		})
307
 
307
 
308
 		if err == nil {
308
 		if err == nil {
309
-			client.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
309
+			rb.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
310
 			return
310
 			return
311
 		}
311
 		}
312
 	}
312
 	}
313
 
313
 
314
-	client.Notice(client.t("Could not login with your TLS certificate or supplied username/password"))
314
+	rb.Notice(client.t("Could not login with your TLS certificate or supplied username/password"))
315
 }
315
 }

+ 6
- 1
irc/responsebuffer.go Visa fil

77
 func (rb *ResponseBuffer) Send() error {
77
 func (rb *ResponseBuffer) Send() error {
78
 	// fall out if no messages to send
78
 	// fall out if no messages to send
79
 	if len(rb.messages) == 0 {
79
 	if len(rb.messages) == 0 {
80
-		return
80
+		return nil
81
 	}
81
 	}
82
 
82
 
83
 	// make batch and all if required
83
 	// make batch and all if required
126
 
126
 
127
 	return nil
127
 	return nil
128
 }
128
 }
129
+
130
+// Notice sends the client the given notice from the server.
131
+func (rb *ResponseBuffer) Notice(text string) {
132
+	rb.Add(nil, rb.target.server.name, "NOTICE", rb.target.nick, text)
133
+}

+ 13
- 9
irc/roleplay.go Visa fil

15
 	sceneNickMask = "=Scene=!%s@npc.fakeuser.invalid"
15
 	sceneNickMask = "=Scene=!%s@npc.fakeuser.invalid"
16
 )
16
 )
17
 
17
 
18
-func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isAction bool, message string) {
18
+func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isAction bool, message string, rb *ResponseBuffer) {
19
 	if isAction {
19
 	if isAction {
20
 		message = fmt.Sprintf("\x01ACTION %s (%s)\x01", message, client.nick)
20
 		message = fmt.Sprintf("\x01ACTION %s (%s)\x01", message, client.nick)
21
 	} else {
21
 	} else {
26
 	if cerr == nil {
26
 	if cerr == nil {
27
 		channel := server.channels.Get(target)
27
 		channel := server.channels.Get(target)
28
 		if channel == nil {
28
 		if channel == nil {
29
-			client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, client.t("No such channel"))
29
+			rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, client.t("No such channel"))
30
 			return
30
 			return
31
 		}
31
 		}
32
 
32
 
33
 		if !channel.CanSpeak(client) {
33
 		if !channel.CanSpeak(client) {
34
-			client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
34
+			rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
35
 			return
35
 			return
36
 		}
36
 		}
37
 
37
 
38
 		if !channel.flags[modes.ChanRoleplaying] {
38
 		if !channel.flags[modes.ChanRoleplaying] {
39
-			client.Send(nil, client.server.name, ERR_CANNOTSENDRP, channel.name, client.t("Channel doesn't have roleplaying mode available"))
39
+			rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, channel.name, client.t("Channel doesn't have roleplaying mode available"))
40
 			return
40
 			return
41
 		}
41
 		}
42
 
42
 
44
 			if member == client && !client.capabilities.Has(caps.EchoMessage) {
44
 			if member == client && !client.capabilities.Has(caps.EchoMessage) {
45
 				continue
45
 				continue
46
 			}
46
 			}
47
-			member.Send(nil, source, "PRIVMSG", channel.name, message)
47
+			if member == client {
48
+				rb.Add(nil, source, "PRIVMSG", channel.name, message)
49
+			} else {
50
+				member.Send(nil, source, "PRIVMSG", channel.name, message)
51
+			}
48
 		}
52
 		}
49
 	} else {
53
 	} else {
50
 		target, err := CasefoldName(targetString)
54
 		target, err := CasefoldName(targetString)
51
 		user := server.clients.Get(target)
55
 		user := server.clients.Get(target)
52
 		if err != nil || user == nil {
56
 		if err != nil || user == nil {
53
-			client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, target, client.t("No such nick"))
57
+			rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, target, client.t("No such nick"))
54
 			return
58
 			return
55
 		}
59
 		}
56
 
60
 
57
 		if !user.flags[modes.UserRoleplaying] {
61
 		if !user.flags[modes.UserRoleplaying] {
58
-			client.Send(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
62
+			rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
59
 			return
63
 			return
60
 		}
64
 		}
61
 
65
 
62
 		user.Send(nil, source, "PRIVMSG", user.nick, message)
66
 		user.Send(nil, source, "PRIVMSG", user.nick, message)
63
 		if client.capabilities.Has(caps.EchoMessage) {
67
 		if client.capabilities.Has(caps.EchoMessage) {
64
-			client.Send(nil, source, "PRIVMSG", user.nick, message)
68
+			rb.Add(nil, source, "PRIVMSG", user.nick, message)
65
 		}
69
 		}
66
 		if user.flags[modes.Away] {
70
 		if user.flags[modes.Away] {
67
 			//TODO(dan): possibly implement cooldown of away notifications to users
71
 			//TODO(dan): possibly implement cooldown of away notifications to users
68
-			client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
72
+			rb.Add(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
69
 		}
73
 		}
70
 	}
74
 	}
71
 }
75
 }

+ 21
- 52
irc/server.go Visa fil

458
 	c.Send(nil, server.name, RPL_CREATED, c.nick, fmt.Sprintf(c.t("This server was created %s"), server.ctime.Format(time.RFC1123)))
458
 	c.Send(nil, server.name, RPL_CREATED, c.nick, fmt.Sprintf(c.t("This server was created %s"), server.ctime.Format(time.RFC1123)))
459
 	//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
459
 	//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
460
 	c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
460
 	c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
461
-	c.RplISupport()
462
-	server.MOTD(c)
461
+
462
+	rb := NewResponseBuffer(c)
463
+	c.RplISupport(rb)
464
+	server.MOTD(c, rb)
465
+	rb.Send()
466
+
463
 	c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
467
 	c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
464
 	if server.logger.IsLoggingRawIO() {
468
 	if server.logger.IsLoggingRawIO() {
465
 		c.Notice(c.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
469
 		c.Notice(c.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
478
 			} else {
482
 			} else {
479
 				c.Send(nil, c.nickMaskString, "JOIN", channel.name)
483
 				c.Send(nil, c.nickMaskString, "JOIN", channel.name)
480
 			}
484
 			}
481
-			channel.SendTopic(c)
482
-			channel.Names(c)
485
+			// reuse the last rb
486
+			channel.SendTopic(c, rb)
487
+			channel.Names(c, rb)
488
+			rb.Send()
483
 
489
 
484
 			// construct and send fake modestring if necessary
490
 			// construct and send fake modestring if necessary
485
 			c.stateMutex.RLock()
491
 			c.stateMutex.RLock()
511
 }
517
 }
512
 
518
 
513
 // MOTD serves the Message of the Day.
519
 // MOTD serves the Message of the Day.
514
-func (server *Server) MOTD(client *Client) {
520
+func (server *Server) MOTD(client *Client, rb *ResponseBuffer) {
515
 	server.configurableStateMutex.RLock()
521
 	server.configurableStateMutex.RLock()
516
 	motdLines := server.motdLines
522
 	motdLines := server.motdLines
517
 	server.configurableStateMutex.RUnlock()
523
 	server.configurableStateMutex.RUnlock()
518
 
524
 
519
 	if len(motdLines) < 1 {
525
 	if len(motdLines) < 1 {
520
-		client.Send(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
526
+		rb.Add(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
521
 		return
527
 		return
522
 	}
528
 	}
523
 
529
 
524
-	client.Send(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
530
+	rb.Add(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
525
 	for _, line := range motdLines {
531
 	for _, line := range motdLines {
526
-		client.Send(nil, server.name, RPL_MOTD, client.nick, line)
532
+		rb.Add(nil, server.name, RPL_MOTD, client.nick, line)
527
 	}
533
 	}
528
-	client.Send(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
534
+	rb.Add(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
529
 }
535
 }
530
 
536
 
531
 // wordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
537
 // wordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
650
 // rplWhoReply returns the WHO reply between one user and another channel/user.
656
 // rplWhoReply returns the WHO reply between one user and another channel/user.
651
 // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
657
 // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
652
 // :<hopcount> <real name>
658
 // :<hopcount> <real name>
653
-func (target *Client) rplWhoReply(channel *Channel, client *Client) {
659
+func (target *Client) rplWhoReply(channel *Channel, client *Client, rb *ResponseBuffer) {
654
 	channelName := "*"
660
 	channelName := "*"
655
 	flags := ""
661
 	flags := ""
656
 
662
 
667
 		flags += channel.ClientPrefixes(client, target.capabilities.Has(caps.MultiPrefix))
673
 		flags += channel.ClientPrefixes(client, target.capabilities.Has(caps.MultiPrefix))
668
 		channelName = channel.name
674
 		channelName = channel.name
669
 	}
675
 	}
670
-	target.Send(nil, target.server.name, RPL_WHOREPLY, target.nick, channelName, client.Username(), client.Hostname(), client.server.name, client.Nick(), flags, strconv.Itoa(client.hops)+" "+client.Realname())
676
+	rb.Add(nil, target.server.name, RPL_WHOREPLY, target.nick, channelName, client.Username(), client.Hostname(), client.server.name, client.Nick(), flags, strconv.Itoa(client.hops)+" "+client.Realname())
671
 }
677
 }
672
 
678
 
673
-func whoChannel(client *Client, channel *Channel, friends ClientSet) {
679
+func whoChannel(client *Client, channel *Channel, friends ClientSet, rb *ResponseBuffer) {
674
 	for _, member := range channel.Members() {
680
 	for _, member := range channel.Members() {
675
 		if !client.flags[modes.Invisible] || friends[client] {
681
 		if !client.flags[modes.Invisible] || friends[client] {
676
-			client.rplWhoReply(channel, member)
682
+			client.rplWhoReply(channel, member, rb)
677
 		}
683
 		}
678
 	}
684
 	}
679
 }
685
 }
1140
 }
1146
 }
1141
 
1147
 
1142
 // RplList returns the RPL_LIST numeric for the given channel.
1148
 // RplList returns the RPL_LIST numeric for the given channel.
1143
-func (target *Client) RplList(channel *Channel) {
1149
+func (target *Client) RplList(channel *Channel, rb *ResponseBuffer) {
1144
 	// get the correct number of channel members
1150
 	// get the correct number of channel members
1145
 	var memberCount int
1151
 	var memberCount int
1146
 	if target.flags[modes.Operator] || channel.hasClient(target) {
1152
 	if target.flags[modes.Operator] || channel.hasClient(target) {
1153
 		}
1159
 		}
1154
 	}
1160
 	}
1155
 
1161
 
1156
-	target.Send(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
1157
-}
1158
-
1159
-// NAMES [<channel>{,<channel>}]
1160
-func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1161
-	var channels []string
1162
-	if len(msg.Params) > 0 {
1163
-		channels = strings.Split(msg.Params[0], ",")
1164
-	}
1165
-	//var target string
1166
-	//if len(msg.Params) > 1 {
1167
-	//	target = msg.Params[1]
1168
-	//}
1169
-
1170
-	if len(channels) == 0 {
1171
-		for _, channel := range server.channels.Channels() {
1172
-			channel.Names(client)
1173
-		}
1174
-		return false
1175
-	}
1176
-
1177
-	// limit regular users to only listing one channel
1178
-	if !client.flags[modes.Operator] {
1179
-		channels = channels[:1]
1180
-	}
1181
-
1182
-	for _, chname := range channels {
1183
-		casefoldedChname, err := CasefoldChannel(chname)
1184
-		channel := server.channels.Get(casefoldedChname)
1185
-		if err != nil || channel == nil {
1186
-			if len(chname) > 0 {
1187
-				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel"))
1188
-			}
1189
-			continue
1190
-		}
1191
-		channel.Names(client)
1192
-	}
1193
-	return false
1162
+	rb.Add(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
1194
 }
1163
 }
1195
 
1164
 
1196
 // ResumeDetails are the details that we use to resume connections.
1165
 // ResumeDetails are the details that we use to resume connections.

Laddar…
Avbryt
Spara