Переглянути джерело

Get labeled-reply working just fine

tags/v0.11.0-beta
Daniel Oaks 6 роки тому
джерело
коміт
e0fa97d344
14 змінених файлів з 526 додано та 472 видалено
  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 Переглянути файл

@@ -27,7 +27,7 @@ const (
27 27
 var (
28 28
 	// EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
29 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 31
 		"PLAIN":    authPlainHandler,
32 32
 		"EXTERNAL": authExternalHandler,
33 33
 	}
@@ -128,9 +128,9 @@ func (client *Client) LogoutOfAccount() {
128 128
 }
129 129
 
130 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 135
 	// dispatch account-notify
136 136
 	for friend := range client.Friends(caps.AccountNotify) {

+ 92
- 64
irc/channel.go Переглянути файл

@@ -171,7 +171,7 @@ func (channel *Channel) regenerateMembersCache(noLocksNeeded bool) {
171 171
 }
172 172
 
173 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 175
 	currentNicks := channel.nicks(client)
176 176
 	// assemble and send replies
177 177
 	maxNamLen := 480 - len(client.server.name) - len(client.nick)
@@ -183,7 +183,7 @@ func (channel *Channel) Names(client *Client) {
183 183
 		}
184 184
 
185 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 187
 			buffer = nick
188 188
 			continue
189 189
 		}
@@ -192,8 +192,8 @@ func (channel *Channel) Names(client *Client) {
192 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 199
 // ClientIsAtLeast returns whether the client has at least the given channel privilege.
@@ -349,42 +349,50 @@ func (channel *Channel) IsEmpty() bool {
349 349
 
350 350
 // Join joins the given client to this channel (if they can be joined).
351 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 353
 	if channel.hasClient(client) {
354 354
 		// already joined, no message needs to be sent
355 355
 		return
356 356
 	}
357 357
 
358 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 360
 		return
361 361
 	}
362 362
 
363 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 365
 		return
366 366
 	}
367 367
 
368 368
 	isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded)
369 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 371
 		return
372 372
 	}
373 373
 
374 374
 	if channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) &&
375 375
 		!isInvited &&
376 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 378
 		return
379 379
 	}
380 380
 
381 381
 	client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", client.nick, channel.name))
382 382
 
383 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 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,31 +419,39 @@ func (channel *Channel) Join(client *Client, key string) {
411 419
 	}
412 420
 
413 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 423
 	} else {
416
-		client.Send(nil, client.nickMaskString, "JOIN", channel.name)
424
+		rb.Add(nil, client.nickMaskString, "JOIN", channel.name)
417 425
 	}
418 426
 	// don't send topic when it's an entirely new channel
419 427
 	if !newChannel {
420
-		channel.SendTopic(client)
428
+		channel.SendTopic(client, rb)
421 429
 	}
422
-	channel.Names(client)
430
+	channel.Names(client, rb)
423 431
 	if givenMode != nil {
424 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 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 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 446
 		return
435 447
 	}
436 448
 
437 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 456
 	channel.Quit(client)
441 457
 
@@ -443,9 +459,9 @@ func (channel *Channel) Part(client *Client, message string) {
443 459
 }
444 460
 
445 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 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 465
 		return
450 466
 	}
451 467
 
@@ -457,23 +473,23 @@ func (channel *Channel) SendTopic(client *Client) {
457 473
 	channel.stateMutex.RUnlock()
458 474
 
459 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 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 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 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 488
 		return
473 489
 	}
474 490
 
475 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 493
 		return
478 494
 	}
479 495
 
@@ -488,7 +504,11 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
488 504
 	channel.stateMutex.Unlock()
489 505
 
490 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 514
 	go channel.server.channelRegistry.StoreChannel(channel, false)
@@ -513,14 +533,14 @@ func (channel *Channel) CanSpeak(client *Client) bool {
513 533
 }
514 534
 
515 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 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 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 544
 		return
525 545
 	}
526 546
 
@@ -554,26 +574,26 @@ func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capab
554 574
 		}
555 575
 
556 576
 		if message == nil {
557
-			member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
577
+			rb.AddFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
558 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 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 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 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 597
 		return
578 598
 	}
579 599
 
@@ -595,25 +615,33 @@ func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mod
595 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 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 635
 	if nick == "" {
608 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 638
 		return nil
611 639
 	}
612 640
 
613 641
 	casefoldedName, err := CasefoldName(nick)
614 642
 	target := channel.server.clients.Get(casefoldedName)
615 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 645
 		return nil
618 646
 	}
619 647
 
@@ -628,7 +656,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode,
628 656
 	channel.stateMutex.Unlock()
629 657
 
630 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 660
 		return nil
633 661
 	} else if already {
634 662
 		return nil
@@ -642,7 +670,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode,
642 670
 }
643 671
 
644 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 674
 	// choose appropriate modes
647 675
 	var rpllist, rplendoflist string
648 676
 	if mode == modes.BanMask {
@@ -660,14 +688,14 @@ func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode) {
660 688
 	channel.stateMutex.RLock()
661 689
 	// XXX don't acquire any new locks in this section, besides Socket.Write
662 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 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 699
 	list := channel.lists[mode]
672 700
 	if list == nil {
673 701
 		// This should never happen, but better safe than panicky.
@@ -675,12 +703,12 @@ func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.
675 703
 	}
676 704
 
677 705
 	if (op == modes.List) || (mask == "") {
678
-		channel.ShowMaskList(client, mode)
706
+		channel.ShowMaskList(client, mode, rb)
679 707
 		return false
680 708
 	}
681 709
 
682 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 712
 		return false
685 713
 	}
686 714
 
@@ -705,21 +733,21 @@ func (channel *Channel) Quit(client *Client) {
705 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 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 739
 		return
712 740
 	}
713 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 743
 		return
716 744
 	}
717 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 747
 		return
720 748
 	}
721 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 751
 		return
724 752
 	}
725 753
 
@@ -738,14 +766,14 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string) {
738 766
 }
739 767
 
740 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 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 772
 		return
745 773
 	}
746 774
 
747 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 777
 		return
750 778
 	}
751 779
 
@@ -764,9 +792,9 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
764 792
 	}
765 793
 
766 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 796
 	invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name)
769 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 Переглянути файл

@@ -45,7 +45,7 @@ func (cm *ChannelManager) Get(name string) *Channel {
45 45
 }
46 46
 
47 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 49
 	server := client.server
50 50
 	casefoldedName, err := CasefoldChannel(name)
51 51
 	if err != nil || len(casefoldedName) > server.Limits().ChannelLen {
@@ -74,7 +74,7 @@ func (cm *ChannelManager) Join(client *Client, name string, key string) error {
74 74
 	entry.pendingJoins += 1
75 75
 	cm.Unlock()
76 76
 
77
-	entry.channel.Join(client, key)
77
+	entry.channel.Join(client, key, rb)
78 78
 
79 79
 	cm.maybeCleanup(entry, true)
80 80
 
@@ -107,7 +107,7 @@ func (cm *ChannelManager) maybeCleanup(entry *channelManagerEntry, afterJoin boo
107 107
 }
108 108
 
109 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 111
 	casefoldedName, err := CasefoldChannel(name)
112 112
 	if err != nil {
113 113
 		return errNoSuchChannel
@@ -120,7 +120,7 @@ func (cm *ChannelManager) Part(client *Client, name string, message string) erro
120 120
 	if entry == nil {
121 121
 		return errNoSuchChannel
122 122
 	}
123
-	entry.channel.Part(client, message)
123
+	entry.channel.Part(client, message, rb)
124 124
 	cm.maybeCleanup(entry, false)
125 125
 	return nil
126 126
 }

+ 16
- 16
irc/chanserv.go Переглянути файл

@@ -13,17 +13,17 @@ import (
13 13
 )
14 14
 
15 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 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 22
 	// do nothing
23 23
 }
24 24
 
25 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 27
 	var params []string
28 28
 	for _, p := range strings.Split(message, " ") {
29 29
 		if len(p) > 0 {
@@ -31,7 +31,7 @@ func (server *Server) chanservPrivmsgHandler(client *Client, message string) {
31 31
 		}
32 32
 	}
33 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 35
 		//TODO(dan): dump CS help here
36 36
 		return
37 37
 	}
@@ -41,57 +41,57 @@ func (server *Server) chanservPrivmsgHandler(client *Client, message string) {
41 41
 
42 42
 	if command == "register" {
43 43
 		if len(params) < 2 {
44
-			client.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
44
+			rb.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
45 45
 			return
46 46
 		}
47 47
 
48
-		server.chanservRegisterHandler(client, params[1])
48
+		server.chanservRegisterHandler(client, params[1], rb)
49 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 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 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 58
 		return
59 59
 	}
60 60
 
61 61
 	channelKey, err := CasefoldChannel(channelName)
62 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 64
 		return
65 65
 	}
66 66
 
67 67
 	channelInfo := server.channels.Get(channelKey)
68 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 70
 		return
71 71
 	}
72 72
 
73 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 75
 		return
76 76
 	}
77 77
 
78 78
 	// this provides the synchronization that allows exactly one registration of the channel:
79 79
 	err = channelInfo.SetRegistered(client.AccountName())
80 80
 	if err != nil {
81
-		client.ChanServNotice(err.Error())
81
+		rb.ChanServNotice(err.Error())
82 82
 		return
83 83
 	}
84 84
 
85 85
 	// registration was successful: make the database reflect it
86 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 90
 	server.logger.Info("chanserv", fmt.Sprintf("Client %s registered channel %s", client.nick, channelName))
91 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 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 95
 	if change != nil {
96 96
 		//TODO(dan): we should change the name of String and make it return a slice here
97 97
 		//TODO(dan): unify this code with code in modes.go

+ 2
- 2
irc/client.go Переглянути файл

@@ -593,12 +593,12 @@ func (client *Client) LoggedIntoAccount() bool {
593 593
 }
594 594
 
595 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 597
 	translatedISupport := client.t("are supported by this server")
598 598
 	for _, tokenline := range client.server.ISupport().CachedReply {
599 599
 		// ugly trickery ahead
600 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
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 4
- 4
irc/help.go Переглянути файл

@@ -658,7 +658,7 @@ func GenerateHelpIndices(lm *languages.Manager) error {
658 658
 }
659 659
 
660 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 662
 	splitName := strings.Split(name, " ")
663 663
 	textLines := strings.Split(text, "\n")
664 664
 
@@ -666,14 +666,14 @@ func (client *Client) sendHelp(name string, text string) {
666 666
 		args := splitName
667 667
 		args = append(args, line)
668 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 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 674
 	args := splitName
675 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 679
 // GetHelpIndex returns the help index for the given language.

+ 4
- 4
irc/modes.go Переглянути файл

@@ -169,7 +169,7 @@ func ParseChannelModeChanges(params ...string) (modes.ModeChanges, map[rune]bool
169 169
 }
170 170
 
171 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 173
 	// so we only output one warning for each list type when full
174 174
 	listFullWarned := make(map[modes.Mode]bool)
175 175
 
@@ -222,7 +222,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
222 222
 		switch change.Mode {
223 223
 		case modes.BanMask, modes.ExceptMask, modes.InviteMask:
224 224
 			if isListOp(change) {
225
-				channel.ShowMaskList(client, change.Mode)
225
+				channel.ShowMaskList(client, change.Mode, rb)
226 226
 				continue
227 227
 			}
228 228
 
@@ -236,7 +236,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
236 236
 			case modes.Add:
237 237
 				if channel.lists[change.Mode].Length() >= client.server.Limits().ChanListModes {
238 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 240
 						listFullWarned[change.Mode] = true
241 241
 					}
242 242
 					continue
@@ -289,7 +289,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
289 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 293
 			if change != nil {
294 294
 				applied = append(applied, *change)
295 295
 			}

+ 1
- 1
irc/monitor.go Переглянути файл

@@ -103,7 +103,7 @@ func (manager *MonitorManager) List(client *Client) (nicks []string) {
103 103
 }
104 104
 
105 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 107
 		"-": monitorRemoveHandler,
108 108
 		"+": monitorAddHandler,
109 109
 		"c": monitorClearHandler,

+ 5
- 5
irc/nickname.go Переглянути файл

@@ -20,17 +20,17 @@ var (
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 24
 	nickname := strings.TrimSpace(newnick)
25 25
 	cfnick, err := CasefoldName(nickname)
26 26
 
27 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 29
 		return false
30 30
 	}
31 31
 
32 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 34
 		return false
35 35
 	}
36 36
 
@@ -43,10 +43,10 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
43 43
 	origNickMask := target.NickMaskString()
44 44
 	err = client.server.clients.SetNick(target, nickname)
45 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 47
 		return false
48 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 50
 		return false
51 51
 	}
52 52
 

+ 25
- 25
irc/nickserv.go Переглянути файл

@@ -39,18 +39,18 @@ func extractParam(line string) (string, string) {
39 39
 }
40 40
 
41 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 43
 	// do nothing
44 44
 }
45 45
 
46 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 48
 	command, params := extractParam(message)
49 49
 	command = strings.ToLower(command)
50 50
 
51 51
 	if command == "help" {
52 52
 		for _, line := range strings.Split(nickservHelp, "\n") {
53
-			client.Notice(line)
53
+			rb.Notice(line)
54 54
 		}
55 55
 	} else if command == "register" {
56 56
 		// get params
@@ -58,30 +58,30 @@ func (server *Server) nickservPrivmsgHandler(client *Client, message string) {
58 58
 
59 59
 		// fail out if we need to
60 60
 		if username == "" {
61
-			client.Notice(client.t("No username supplied"))
61
+			rb.Notice(client.t("No username supplied"))
62 62
 			return
63 63
 		}
64 64
 
65
-		server.nickservRegisterHandler(client, username, passphrase)
65
+		server.nickservRegisterHandler(client, username, passphrase, rb)
66 66
 	} else if command == "identify" {
67 67
 		// get params
68 68
 		username, passphrase := extractParam(params)
69 69
 
70
-		server.nickservIdentifyHandler(client, username, passphrase)
70
+		server.nickservIdentifyHandler(client, username, passphrase, rb)
71 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 77
 	certfp := client.certfp
78 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 80
 		return
81 81
 	}
82 82
 
83 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 85
 		return
86 86
 	}
87 87
 
@@ -89,7 +89,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
89 89
 		if server.accountRegistration.AllowMultiplePerConnection {
90 90
 			client.LogoutOfAccount()
91 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 93
 			return
94 94
 		}
95 95
 	}
@@ -99,7 +99,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
99 99
 	casefoldedAccount, err := CasefoldName(account)
100 100
 	// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
101 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 103
 		return
104 104
 	}
105 105
 
@@ -111,7 +111,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
111 111
 		_, err := tx.Get(accountKey)
112 112
 		if err != buntdb.ErrNotFound {
113 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 115
 			return errAccountCreation
116 116
 		}
117 117
 
@@ -126,7 +126,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
126 126
 	// account could not be created and relevant numerics have been dispatched, abort
127 127
 	if err != nil {
128 128
 		if err != errAccountCreation {
129
-			client.Notice(client.t("Account registration failed"))
129
+			rb.Notice(client.t("Account registration failed"))
130 130
 		}
131 131
 		return
132 132
 	}
@@ -178,7 +178,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
178 178
 		if err == errCertfpAlreadyExists {
179 179
 			errMsg = "An account already exists for your certificate fingerprint"
180 180
 		}
181
-		client.Notice(errMsg)
181
+		rb.Notice(errMsg)
182 182
 		removeFailedAccRegisterData(server.store, casefoldedAccount)
183 183
 		return
184 184
 	}
@@ -196,23 +196,23 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
196 196
 		server.accounts[casefoldedAccount] = &account
197 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 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 203
 		return nil
204 204
 	})
205 205
 	if err != nil {
206
-		client.Notice(client.t("Account registration failed"))
206
+		rb.Notice(client.t("Account registration failed"))
207 207
 		removeFailedAccRegisterData(server.store, casefoldedAccount)
208 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 213
 	// fail out if we need to
214 214
 	if !server.accountAuthenticationEnabled {
215
-		client.Notice(client.t("Login has been disabled"))
215
+		rb.Notice(client.t("Login has been disabled"))
216 216
 		return
217 217
 	}
218 218
 
@@ -221,7 +221,7 @@ func (server *Server) nickservIdentifyHandler(client *Client, username, passphra
221 221
 		// keep it the same as in the ACC CREATE stage
222 222
 		accountKey, err := CasefoldName(username)
223 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 225
 			return
226 226
 		}
227 227
 
@@ -259,7 +259,7 @@ func (server *Server) nickservIdentifyHandler(client *Client, username, passphra
259 259
 		})
260 260
 
261 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 263
 			return
264 264
 		}
265 265
 	}
@@ -306,10 +306,10 @@ func (server *Server) nickservIdentifyHandler(client *Client, username, passphra
306 306
 		})
307 307
 
308 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 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 Переглянути файл

@@ -77,7 +77,7 @@ func (rb *ResponseBuffer) AddSplitMessageFromClient(msgid string, from *Client,
77 77
 func (rb *ResponseBuffer) Send() error {
78 78
 	// fall out if no messages to send
79 79
 	if len(rb.messages) == 0 {
80
-		return
80
+		return nil
81 81
 	}
82 82
 
83 83
 	// make batch and all if required
@@ -126,3 +126,8 @@ func (rb *ResponseBuffer) Send() error {
126 126
 
127 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 Переглянути файл

@@ -15,7 +15,7 @@ const (
15 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 19
 	if isAction {
20 20
 		message = fmt.Sprintf("\x01ACTION %s (%s)\x01", message, client.nick)
21 21
 	} else {
@@ -26,17 +26,17 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
26 26
 	if cerr == nil {
27 27
 		channel := server.channels.Get(target)
28 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 30
 			return
31 31
 		}
32 32
 
33 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 35
 			return
36 36
 		}
37 37
 
38 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 40
 			return
41 41
 		}
42 42
 
@@ -44,28 +44,32 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
44 44
 			if member == client && !client.capabilities.Has(caps.EchoMessage) {
45 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 53
 	} else {
50 54
 		target, err := CasefoldName(targetString)
51 55
 		user := server.clients.Get(target)
52 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 58
 			return
55 59
 		}
56 60
 
57 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 63
 			return
60 64
 		}
61 65
 
62 66
 		user.Send(nil, source, "PRIVMSG", user.nick, message)
63 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 70
 		if user.flags[modes.Away] {
67 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 Переглянути файл

@@ -458,8 +458,12 @@ func (server *Server) tryRegister(c *Client) {
458 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 459
 	//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
460 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 467
 	c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
464 468
 	if server.logger.IsLoggingRawIO() {
465 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,8 +482,10 @@ func (server *Server) tryRegister(c *Client) {
478 482
 			} else {
479 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 490
 			// construct and send fake modestring if necessary
485 491
 			c.stateMutex.RLock()
@@ -511,21 +517,21 @@ func (client *Client) t(originalString string) string {
511 517
 }
512 518
 
513 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 521
 	server.configurableStateMutex.RLock()
516 522
 	motdLines := server.motdLines
517 523
 	server.configurableStateMutex.RUnlock()
518 524
 
519 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 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 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 537
 // wordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
@@ -650,7 +656,7 @@ func (client *Client) getWhoisOf(target *Client, rb *ResponseBuffer) {
650 656
 // rplWhoReply returns the WHO reply between one user and another channel/user.
651 657
 // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
652 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 660
 	channelName := "*"
655 661
 	flags := ""
656 662
 
@@ -667,13 +673,13 @@ func (target *Client) rplWhoReply(channel *Channel, client *Client) {
667 673
 		flags += channel.ClientPrefixes(client, target.capabilities.Has(caps.MultiPrefix))
668 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 680
 	for _, member := range channel.Members() {
675 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,7 +1146,7 @@ func (matcher *elistMatcher) Matches(channel *Channel) bool {
1140 1146
 }
1141 1147
 
1142 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 1150
 	// get the correct number of channel members
1145 1151
 	var memberCount int
1146 1152
 	if target.flags[modes.Operator] || channel.hasClient(target) {
@@ -1153,44 +1159,7 @@ func (target *Client) RplList(channel *Channel) {
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 1165
 // ResumeDetails are the details that we use to resume connections.

Завантаження…
Відмінити
Зберегти