mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-25 13:29:27 +01:00
Get labeled-reply working just fine
This commit is contained in:
parent
470109461b
commit
e0fa97d344
@ -27,7 +27,7 @@ const (
|
||||
var (
|
||||
// EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
|
||||
// This can be moved to some other data structure/place if we need to load/unload mechs later.
|
||||
EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte) bool{
|
||||
EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte, *ResponseBuffer) bool{
|
||||
"PLAIN": authPlainHandler,
|
||||
"EXTERNAL": authExternalHandler,
|
||||
}
|
||||
@ -128,9 +128,9 @@ func (client *Client) LogoutOfAccount() {
|
||||
}
|
||||
|
||||
// successfulSaslAuth means that a SASL auth attempt completed successfully, and is used to dispatch messages.
|
||||
func (client *Client) successfulSaslAuth() {
|
||||
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))
|
||||
client.Send(nil, client.server.name, RPL_SASLSUCCESS, client.nick, client.t("SASL authentication successful"))
|
||||
func (client *Client) successfulSaslAuth(rb *ResponseBuffer) {
|
||||
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))
|
||||
rb.Add(nil, client.server.name, RPL_SASLSUCCESS, client.nick, client.t("SASL authentication successful"))
|
||||
|
||||
// dispatch account-notify
|
||||
for friend := range client.Friends(caps.AccountNotify) {
|
||||
|
138
irc/channel.go
138
irc/channel.go
@ -171,7 +171,7 @@ func (channel *Channel) regenerateMembersCache(noLocksNeeded bool) {
|
||||
}
|
||||
|
||||
// Names sends the list of users joined to the channel to the given client.
|
||||
func (channel *Channel) Names(client *Client) {
|
||||
func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
|
||||
currentNicks := channel.nicks(client)
|
||||
// assemble and send replies
|
||||
maxNamLen := 480 - len(client.server.name) - len(client.nick)
|
||||
@ -183,7 +183,7 @@ func (channel *Channel) Names(client *Client) {
|
||||
}
|
||||
|
||||
if len(buffer)+1+len(nick) > maxNamLen {
|
||||
client.Send(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
|
||||
rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
|
||||
buffer = nick
|
||||
continue
|
||||
}
|
||||
@ -192,8 +192,8 @@ func (channel *Channel) Names(client *Client) {
|
||||
buffer += nick
|
||||
}
|
||||
|
||||
client.Send(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
|
||||
client.Send(nil, client.server.name, RPL_ENDOFNAMES, client.nick, channel.name, client.t("End of NAMES list"))
|
||||
rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", channel.name, buffer)
|
||||
rb.Add(nil, client.server.name, RPL_ENDOFNAMES, client.nick, channel.name, client.t("End of NAMES list"))
|
||||
}
|
||||
|
||||
// ClientIsAtLeast returns whether the client has at least the given channel privilege.
|
||||
@ -349,44 +349,52 @@ func (channel *Channel) IsEmpty() bool {
|
||||
|
||||
// Join joins the given client to this channel (if they can be joined).
|
||||
//TODO(dan): /SAJOIN and maybe a ForceJoin function?
|
||||
func (channel *Channel) Join(client *Client, key string) {
|
||||
func (channel *Channel) Join(client *Client, key string, rb *ResponseBuffer) {
|
||||
if channel.hasClient(client) {
|
||||
// already joined, no message needs to be sent
|
||||
return
|
||||
}
|
||||
|
||||
if channel.IsFull() {
|
||||
client.Send(nil, client.server.name, ERR_CHANNELISFULL, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANNELISFULL, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
|
||||
return
|
||||
}
|
||||
|
||||
if !channel.CheckKey(key) {
|
||||
client.Send(nil, client.server.name, ERR_BADCHANNELKEY, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
|
||||
rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
|
||||
return
|
||||
}
|
||||
|
||||
isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded)
|
||||
if channel.flags[modes.InviteOnly] && !isInvited {
|
||||
client.Send(nil, client.server.name, ERR_INVITEONLYCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
|
||||
rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
|
||||
return
|
||||
}
|
||||
|
||||
if channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) &&
|
||||
!isInvited &&
|
||||
!channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) {
|
||||
client.Send(nil, client.server.name, ERR_BANNEDFROMCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
|
||||
rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, channel.name, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
|
||||
return
|
||||
}
|
||||
|
||||
client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", client.nick, channel.name))
|
||||
|
||||
for _, member := range channel.Members() {
|
||||
if member == client {
|
||||
if member.capabilities.Has(caps.ExtendedJoin) {
|
||||
rb.Add(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
|
||||
} else {
|
||||
rb.Add(nil, client.nickMaskString, "JOIN", channel.name)
|
||||
}
|
||||
} else {
|
||||
if member.capabilities.Has(caps.ExtendedJoin) {
|
||||
member.Send(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
|
||||
} else {
|
||||
member.Send(nil, client.nickMaskString, "JOIN", channel.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
channel.stateMutex.Lock()
|
||||
channel.members.Add(client)
|
||||
@ -411,41 +419,49 @@ func (channel *Channel) Join(client *Client, key string) {
|
||||
}
|
||||
|
||||
if client.capabilities.Has(caps.ExtendedJoin) {
|
||||
client.Send(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
|
||||
rb.Add(nil, client.nickMaskString, "JOIN", channel.name, client.account.Name, client.realname)
|
||||
} else {
|
||||
client.Send(nil, client.nickMaskString, "JOIN", channel.name)
|
||||
rb.Add(nil, client.nickMaskString, "JOIN", channel.name)
|
||||
}
|
||||
// don't send topic when it's an entirely new channel
|
||||
if !newChannel {
|
||||
channel.SendTopic(client)
|
||||
channel.SendTopic(client, rb)
|
||||
}
|
||||
channel.Names(client)
|
||||
channel.Names(client, rb)
|
||||
if givenMode != nil {
|
||||
for _, member := range channel.Members() {
|
||||
if member == client {
|
||||
rb.Add(nil, client.server.name, "MODE", channel.name, fmt.Sprintf("+%v", *givenMode), client.nick)
|
||||
} else {
|
||||
member.Send(nil, client.server.name, "MODE", channel.name, fmt.Sprintf("+%v", *givenMode), client.nick)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Part parts the given client from this channel, with the given message.
|
||||
func (channel *Channel) Part(client *Client, message string) {
|
||||
func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer) {
|
||||
if !channel.hasClient(client) {
|
||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, member := range channel.Members() {
|
||||
if member == client {
|
||||
rb.Add(nil, client.nickMaskString, "PART", channel.name, message)
|
||||
} else {
|
||||
member.Send(nil, client.nickMaskString, "PART", channel.name, message)
|
||||
}
|
||||
}
|
||||
channel.Quit(client)
|
||||
|
||||
client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", client.nick, channel.name))
|
||||
}
|
||||
|
||||
// SendTopic sends the channel topic to the given client.
|
||||
func (channel *Channel) SendTopic(client *Client) {
|
||||
func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer) {
|
||||
if !channel.hasClient(client) {
|
||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -457,23 +473,23 @@ func (channel *Channel) SendTopic(client *Client) {
|
||||
channel.stateMutex.RUnlock()
|
||||
|
||||
if topic == "" {
|
||||
client.Send(nil, client.server.name, RPL_NOTOPIC, client.nick, name, client.t("No topic is set"))
|
||||
rb.Add(nil, client.server.name, RPL_NOTOPIC, client.nick, name, client.t("No topic is set"))
|
||||
return
|
||||
}
|
||||
|
||||
client.Send(nil, client.server.name, RPL_TOPIC, client.nick, name, topic)
|
||||
client.Send(nil, client.server.name, RPL_TOPICTIME, client.nick, name, topicSetBy, strconv.FormatInt(topicSetTime.Unix(), 10))
|
||||
rb.Add(nil, client.server.name, RPL_TOPIC, client.nick, name, topic)
|
||||
rb.Add(nil, client.server.name, RPL_TOPICTIME, client.nick, name, topicSetBy, strconv.FormatInt(topicSetTime.Unix(), 10))
|
||||
}
|
||||
|
||||
// SetTopic sets the topic of this channel, if the client is allowed to do so.
|
||||
func (channel *Channel) SetTopic(client *Client, topic string) {
|
||||
func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) {
|
||||
if !(client.flags[modes.Operator] || channel.hasClient(client)) {
|
||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
if channel.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -488,8 +504,12 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
|
||||
channel.stateMutex.Unlock()
|
||||
|
||||
for _, member := range channel.Members() {
|
||||
if member == client {
|
||||
rb.Add(nil, client.nickMaskString, "TOPIC", channel.name, topic)
|
||||
} else {
|
||||
member.Send(nil, client.nickMaskString, "TOPIC", channel.name, topic)
|
||||
}
|
||||
}
|
||||
|
||||
go channel.server.channelRegistry.StoreChannel(channel, false)
|
||||
}
|
||||
@ -513,14 +533,14 @@ func (channel *Channel) CanSpeak(client *Client) bool {
|
||||
}
|
||||
|
||||
// TagMsg sends a tag message to everyone in this channel who can accept them.
|
||||
func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
|
||||
channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil)
|
||||
func (channel *Channel) TagMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, rb *ResponseBuffer) {
|
||||
channel.sendMessage(msgid, "TAGMSG", []caps.Capability{caps.MessageTags}, minPrefix, clientOnlyTags, client, nil, rb)
|
||||
}
|
||||
|
||||
// sendMessage sends a given message to everyone on this channel.
|
||||
func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
|
||||
func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capability, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string, rb *ResponseBuffer) {
|
||||
if !channel.CanSpeak(client) {
|
||||
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -554,26 +574,26 @@ func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []caps.Capab
|
||||
}
|
||||
|
||||
if message == nil {
|
||||
member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
|
||||
rb.AddFromClient(msgid, client, messageTagsToUse, cmd, channel.name)
|
||||
} else {
|
||||
member.SendFromClient(msgid, client, messageTagsToUse, cmd, channel.name, *message)
|
||||
rb.AddFromClient(msgid, client, messageTagsToUse, cmd, channel.name, *message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SplitPrivMsg sends a private message to everyone in this channel.
|
||||
func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
|
||||
channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message)
|
||||
func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage, rb *ResponseBuffer) {
|
||||
channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message, rb)
|
||||
}
|
||||
|
||||
// SplitNotice sends a private message to everyone in this channel.
|
||||
func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
|
||||
channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message)
|
||||
func (channel *Channel) SplitNotice(msgid string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage, rb *ResponseBuffer) {
|
||||
channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message, rb)
|
||||
}
|
||||
|
||||
func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
|
||||
func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage, rb *ResponseBuffer) {
|
||||
if !channel.CanSpeak(client) {
|
||||
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -595,25 +615,33 @@ func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *modes.Mod
|
||||
tagsToUse = clientOnlyTags
|
||||
}
|
||||
|
||||
if member == client {
|
||||
if message == nil {
|
||||
rb.AddFromClient(msgid, client, tagsToUse, cmd, channel.name)
|
||||
} else {
|
||||
rb.AddSplitMessageFromClient(msgid, client, tagsToUse, cmd, channel.name, *message)
|
||||
}
|
||||
} else {
|
||||
if message == nil {
|
||||
member.SendFromClient(msgid, client, tagsToUse, cmd, channel.name)
|
||||
} else {
|
||||
member.SendSplitMsgFromClient(msgid, client, tagsToUse, cmd, channel.name, *message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode, op modes.ModeOp, nick string) *modes.ModeChange {
|
||||
func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode, op modes.ModeOp, nick string, rb *ResponseBuffer) *modes.ModeChange {
|
||||
if nick == "" {
|
||||
//TODO(dan): shouldn't this be handled before it reaches this function?
|
||||
client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
|
||||
rb.Add(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", client.t("Not enough parameters"))
|
||||
return nil
|
||||
}
|
||||
|
||||
casefoldedName, err := CasefoldName(nick)
|
||||
target := channel.server.clients.Get(casefoldedName)
|
||||
if err != nil || target == nil {
|
||||
client.Send(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nick, client.t("No such nick"))
|
||||
rb.Add(nil, client.server.name, ERR_NOSUCHNICK, client.nick, nick, client.t("No such nick"))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -628,7 +656,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode,
|
||||
channel.stateMutex.Unlock()
|
||||
|
||||
if !exists {
|
||||
client.Send(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
|
||||
return nil
|
||||
} else if already {
|
||||
return nil
|
||||
@ -642,7 +670,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode modes.Mode,
|
||||
}
|
||||
|
||||
// ShowMaskList shows the given list to the client.
|
||||
func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode) {
|
||||
func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode, rb *ResponseBuffer) {
|
||||
// choose appropriate modes
|
||||
var rpllist, rplendoflist string
|
||||
if mode == modes.BanMask {
|
||||
@ -660,14 +688,14 @@ func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode) {
|
||||
channel.stateMutex.RLock()
|
||||
// XXX don't acquire any new locks in this section, besides Socket.Write
|
||||
for mask := range channel.lists[mode].masks {
|
||||
client.Send(nil, client.server.name, rpllist, nick, channel.name, mask)
|
||||
rb.Add(nil, client.server.name, rpllist, nick, channel.name, mask)
|
||||
}
|
||||
channel.stateMutex.RUnlock()
|
||||
|
||||
client.Send(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
|
||||
rb.Add(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
|
||||
}
|
||||
|
||||
func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string) bool {
|
||||
func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string, rb *ResponseBuffer) bool {
|
||||
list := channel.lists[mode]
|
||||
if list == nil {
|
||||
// This should never happen, but better safe than panicky.
|
||||
@ -675,12 +703,12 @@ func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.
|
||||
}
|
||||
|
||||
if (op == modes.List) || (mask == "") {
|
||||
channel.ShowMaskList(client, mode)
|
||||
channel.ShowMaskList(client, mode, rb)
|
||||
return false
|
||||
}
|
||||
|
||||
if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -705,21 +733,21 @@ func (channel *Channel) Quit(client *Client) {
|
||||
client.removeChannel(channel)
|
||||
}
|
||||
|
||||
func (channel *Channel) Kick(client *Client, target *Client, comment string) {
|
||||
func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer) {
|
||||
if !(client.flags[modes.Operator] || channel.hasClient(client)) {
|
||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, client.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
return
|
||||
}
|
||||
if !channel.hasClient(target) {
|
||||
client.Send(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
|
||||
rb.Add(nil, client.server.name, ERR_USERNOTINCHANNEL, client.nick, channel.name, client.t("They aren't on that channel"))
|
||||
return
|
||||
}
|
||||
if !channel.ClientHasPrivsOver(client, target) {
|
||||
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -738,14 +766,14 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string) {
|
||||
}
|
||||
|
||||
// Invite invites the given client to the channel, if the inviter can do so.
|
||||
func (channel *Channel) Invite(invitee *Client, inviter *Client) {
|
||||
func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
|
||||
if channel.flags[modes.InviteOnly] && !channel.ClientIsAtLeast(inviter, modes.ChannelOperator) {
|
||||
inviter.Send(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator"))
|
||||
rb.Add(nil, inviter.server.name, ERR_CHANOPRIVSNEEDED, channel.name, inviter.t("You're not a channel operator"))
|
||||
return
|
||||
}
|
||||
|
||||
if !channel.hasClient(inviter) {
|
||||
inviter.Send(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, inviter.t("You're not on that channel"))
|
||||
rb.Add(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, inviter.t("You're not on that channel"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -764,9 +792,9 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
|
||||
}
|
||||
|
||||
//TODO(dan): should inviter.server.name here be inviter.nickMaskString ?
|
||||
inviter.Send(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name)
|
||||
rb.Add(nil, inviter.server.name, RPL_INVITING, invitee.nick, channel.name)
|
||||
invitee.Send(nil, inviter.nickMaskString, "INVITE", invitee.nick, channel.name)
|
||||
if invitee.flags[modes.Away] {
|
||||
inviter.Send(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
|
||||
rb.Add(nil, inviter.server.name, RPL_AWAY, invitee.nick, invitee.awayMessage)
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func (cm *ChannelManager) Get(name string) *Channel {
|
||||
}
|
||||
|
||||
// Join causes `client` to join the channel named `name`, creating it if necessary.
|
||||
func (cm *ChannelManager) Join(client *Client, name string, key string) error {
|
||||
func (cm *ChannelManager) Join(client *Client, name string, key string, rb *ResponseBuffer) error {
|
||||
server := client.server
|
||||
casefoldedName, err := CasefoldChannel(name)
|
||||
if err != nil || len(casefoldedName) > server.Limits().ChannelLen {
|
||||
@ -74,7 +74,7 @@ func (cm *ChannelManager) Join(client *Client, name string, key string) error {
|
||||
entry.pendingJoins += 1
|
||||
cm.Unlock()
|
||||
|
||||
entry.channel.Join(client, key)
|
||||
entry.channel.Join(client, key, rb)
|
||||
|
||||
cm.maybeCleanup(entry, true)
|
||||
|
||||
@ -107,7 +107,7 @@ func (cm *ChannelManager) maybeCleanup(entry *channelManagerEntry, afterJoin boo
|
||||
}
|
||||
|
||||
// Part parts `client` from the channel named `name`, deleting it if it's empty.
|
||||
func (cm *ChannelManager) Part(client *Client, name string, message string) error {
|
||||
func (cm *ChannelManager) Part(client *Client, name string, message string, rb *ResponseBuffer) error {
|
||||
casefoldedName, err := CasefoldChannel(name)
|
||||
if err != nil {
|
||||
return errNoSuchChannel
|
||||
@ -120,7 +120,7 @@ func (cm *ChannelManager) Part(client *Client, name string, message string) erro
|
||||
if entry == nil {
|
||||
return errNoSuchChannel
|
||||
}
|
||||
entry.channel.Part(client, message)
|
||||
entry.channel.Part(client, message, rb)
|
||||
cm.maybeCleanup(entry, false)
|
||||
return nil
|
||||
}
|
||||
|
@ -13,17 +13,17 @@ import (
|
||||
)
|
||||
|
||||
// ChanServNotice sends the client a notice from ChanServ.
|
||||
func (client *Client) ChanServNotice(text string) {
|
||||
client.Send(nil, fmt.Sprintf("ChanServ!services@%s", client.server.name), "NOTICE", client.nick, text)
|
||||
func (rb *ResponseBuffer) ChanServNotice(text string) {
|
||||
rb.Add(nil, fmt.Sprintf("ChanServ!services@%s", rb.target.server.name), "NOTICE", rb.target.nick, text)
|
||||
}
|
||||
|
||||
// chanservReceiveNotice handles NOTICEs that ChanServ receives.
|
||||
func (server *Server) chanservNoticeHandler(client *Client, message string) {
|
||||
func (server *Server) chanservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// chanservReceiveNotice handles NOTICEs that ChanServ receives.
|
||||
func (server *Server) chanservPrivmsgHandler(client *Client, message string) {
|
||||
func (server *Server) chanservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
|
||||
var params []string
|
||||
for _, p := range strings.Split(message, " ") {
|
||||
if len(p) > 0 {
|
||||
@ -31,7 +31,7 @@ func (server *Server) chanservPrivmsgHandler(client *Client, message string) {
|
||||
}
|
||||
}
|
||||
if len(params) < 1 {
|
||||
client.ChanServNotice(client.t("You need to run a command"))
|
||||
rb.ChanServNotice(client.t("You need to run a command"))
|
||||
//TODO(dan): dump CS help here
|
||||
return
|
||||
}
|
||||
@ -41,57 +41,57 @@ func (server *Server) chanservPrivmsgHandler(client *Client, message string) {
|
||||
|
||||
if command == "register" {
|
||||
if len(params) < 2 {
|
||||
client.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
|
||||
rb.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
|
||||
return
|
||||
}
|
||||
|
||||
server.chanservRegisterHandler(client, params[1])
|
||||
server.chanservRegisterHandler(client, params[1], rb)
|
||||
} else {
|
||||
client.ChanServNotice(client.t("Sorry, I don't know that command"))
|
||||
rb.ChanServNotice(client.t("Sorry, I don't know that command"))
|
||||
}
|
||||
}
|
||||
|
||||
// chanservRegisterHandler handles the ChanServ REGISTER subcommand.
|
||||
func (server *Server) chanservRegisterHandler(client *Client, channelName string) {
|
||||
func (server *Server) chanservRegisterHandler(client *Client, channelName string, rb *ResponseBuffer) {
|
||||
if !server.channelRegistrationEnabled {
|
||||
client.ChanServNotice(client.t("Channel registration is not enabled"))
|
||||
rb.ChanServNotice(client.t("Channel registration is not enabled"))
|
||||
return
|
||||
}
|
||||
|
||||
channelKey, err := CasefoldChannel(channelName)
|
||||
if err != nil {
|
||||
client.ChanServNotice(client.t("Channel name is not valid"))
|
||||
rb.ChanServNotice(client.t("Channel name is not valid"))
|
||||
return
|
||||
}
|
||||
|
||||
channelInfo := server.channels.Get(channelKey)
|
||||
if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||
client.ChanServNotice(client.t("You must be an oper on the channel to register it"))
|
||||
rb.ChanServNotice(client.t("You must be an oper on the channel to register it"))
|
||||
return
|
||||
}
|
||||
|
||||
if client.account == &NoAccount {
|
||||
client.ChanServNotice(client.t("You must be logged in to register a channel"))
|
||||
rb.ChanServNotice(client.t("You must be logged in to register a channel"))
|
||||
return
|
||||
}
|
||||
|
||||
// this provides the synchronization that allows exactly one registration of the channel:
|
||||
err = channelInfo.SetRegistered(client.AccountName())
|
||||
if err != nil {
|
||||
client.ChanServNotice(err.Error())
|
||||
rb.ChanServNotice(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// registration was successful: make the database reflect it
|
||||
go server.channelRegistry.StoreChannel(channelInfo, true)
|
||||
|
||||
client.ChanServNotice(fmt.Sprintf(client.t("Channel %s successfully registered"), channelName))
|
||||
rb.ChanServNotice(fmt.Sprintf(client.t("Channel %s successfully registered"), channelName))
|
||||
|
||||
server.logger.Info("chanserv", fmt.Sprintf("Client %s registered channel %s", client.nick, channelName))
|
||||
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))
|
||||
|
||||
// give them founder privs
|
||||
change := channelInfo.applyModeMemberNoMutex(client, modes.ChannelFounder, modes.Add, client.NickCasefolded())
|
||||
change := channelInfo.applyModeMemberNoMutex(client, modes.ChannelFounder, modes.Add, client.NickCasefolded(), rb)
|
||||
if change != nil {
|
||||
//TODO(dan): we should change the name of String and make it return a slice here
|
||||
//TODO(dan): unify this code with code in modes.go
|
||||
|
@ -593,12 +593,12 @@ func (client *Client) LoggedIntoAccount() bool {
|
||||
}
|
||||
|
||||
// RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
|
||||
func (client *Client) RplISupport() {
|
||||
func (client *Client) RplISupport(rb *ResponseBuffer) {
|
||||
translatedISupport := client.t("are supported by this server")
|
||||
for _, tokenline := range client.server.ISupport().CachedReply {
|
||||
// ugly trickery ahead
|
||||
tokenline = append(tokenline, translatedISupport)
|
||||
client.Send(nil, client.server.name, RPL_ISUPPORT, append([]string{client.nick}, tokenline...)...)
|
||||
rb.Add(nil, client.server.name, RPL_ISUPPORT, append([]string{client.nick}, tokenline...)...)
|
||||
}
|
||||
}
|
||||
|
||||
|
602
irc/handlers.go
602
irc/handlers.go
File diff suppressed because it is too large
Load Diff
@ -658,7 +658,7 @@ func GenerateHelpIndices(lm *languages.Manager) error {
|
||||
}
|
||||
|
||||
// sendHelp sends the client help of the given string.
|
||||
func (client *Client) sendHelp(name string, text string) {
|
||||
func (client *Client) sendHelp(name string, text string, rb *ResponseBuffer) {
|
||||
splitName := strings.Split(name, " ")
|
||||
textLines := strings.Split(text, "\n")
|
||||
|
||||
@ -666,14 +666,14 @@ func (client *Client) sendHelp(name string, text string) {
|
||||
args := splitName
|
||||
args = append(args, line)
|
||||
if i == 0 {
|
||||
client.Send(nil, client.server.name, RPL_HELPSTART, args...)
|
||||
rb.Add(nil, client.server.name, RPL_HELPSTART, args...)
|
||||
} else {
|
||||
client.Send(nil, client.server.name, RPL_HELPTXT, args...)
|
||||
rb.Add(nil, client.server.name, RPL_HELPTXT, args...)
|
||||
}
|
||||
}
|
||||
args := splitName
|
||||
args = append(args, client.t("End of /HELPOP"))
|
||||
client.Send(nil, client.server.name, RPL_ENDOFHELP, args...)
|
||||
rb.Add(nil, client.server.name, RPL_ENDOFHELP, args...)
|
||||
}
|
||||
|
||||
// GetHelpIndex returns the help index for the given language.
|
||||
|
@ -169,7 +169,7 @@ func ParseChannelModeChanges(params ...string) (modes.ModeChanges, map[rune]bool
|
||||
}
|
||||
|
||||
// ApplyChannelModeChanges applies a given set of mode changes.
|
||||
func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges) modes.ModeChanges {
|
||||
func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, changes modes.ModeChanges, rb *ResponseBuffer) modes.ModeChanges {
|
||||
// so we only output one warning for each list type when full
|
||||
listFullWarned := make(map[modes.Mode]bool)
|
||||
|
||||
@ -222,7 +222,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
||||
switch change.Mode {
|
||||
case modes.BanMask, modes.ExceptMask, modes.InviteMask:
|
||||
if isListOp(change) {
|
||||
channel.ShowMaskList(client, change.Mode)
|
||||
channel.ShowMaskList(client, change.Mode, rb)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -236,7 +236,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
||||
case modes.Add:
|
||||
if channel.lists[change.Mode].Length() >= client.server.Limits().ChanListModes {
|
||||
if !listFullWarned[change.Mode] {
|
||||
client.Send(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
|
||||
rb.Add(nil, client.server.name, ERR_BANLISTFULL, client.Nick(), channel.Name(), change.Mode.String(), client.t("Channel list is full"))
|
||||
listFullWarned[change.Mode] = true
|
||||
}
|
||||
continue
|
||||
@ -289,7 +289,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
||||
continue
|
||||
}
|
||||
|
||||
change := channel.applyModeMemberNoMutex(client, change.Mode, change.Op, change.Arg)
|
||||
change := channel.applyModeMemberNoMutex(client, change.Mode, change.Op, change.Arg, rb)
|
||||
if change != nil {
|
||||
applied = append(applied, *change)
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func (manager *MonitorManager) List(client *Client) (nicks []string) {
|
||||
}
|
||||
|
||||
var (
|
||||
metadataSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.IrcMessage) bool{
|
||||
metadataSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool{
|
||||
"-": monitorRemoveHandler,
|
||||
"+": monitorAddHandler,
|
||||
"c": monitorClearHandler,
|
||||
|
@ -20,17 +20,17 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func performNickChange(server *Server, client *Client, target *Client, newnick string) bool {
|
||||
func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
|
||||
nickname := strings.TrimSpace(newnick)
|
||||
cfnick, err := CasefoldName(nickname)
|
||||
|
||||
if len(nickname) < 1 {
|
||||
client.Send(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, client.t("No nickname given"))
|
||||
rb.Add(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, client.t("No nickname given"))
|
||||
return false
|
||||
}
|
||||
|
||||
if err != nil || len(nickname) > server.Limits().NickLen || restrictedNicknames[cfnick] {
|
||||
client.Send(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nickname, client.t("Erroneous nickname"))
|
||||
rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nickname, client.t("Erroneous nickname"))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -43,10 +43,10 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
|
||||
origNickMask := target.NickMaskString()
|
||||
err = client.server.clients.SetNick(target, nickname)
|
||||
if err == errNicknameInUse {
|
||||
client.Send(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
|
||||
rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
|
||||
return false
|
||||
} else if err != nil {
|
||||
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -39,18 +39,18 @@ func extractParam(line string) (string, string) {
|
||||
}
|
||||
|
||||
// nickservNoticeHandler handles NOTICEs that NickServ receives.
|
||||
func (server *Server) nickservNoticeHandler(client *Client, message string) {
|
||||
func (server *Server) nickservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// nickservPrivmsgHandler handles PRIVMSGs that NickServ receives.
|
||||
func (server *Server) nickservPrivmsgHandler(client *Client, message string) {
|
||||
func (server *Server) nickservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
|
||||
command, params := extractParam(message)
|
||||
command = strings.ToLower(command)
|
||||
|
||||
if command == "help" {
|
||||
for _, line := range strings.Split(nickservHelp, "\n") {
|
||||
client.Notice(line)
|
||||
rb.Notice(line)
|
||||
}
|
||||
} else if command == "register" {
|
||||
// get params
|
||||
@ -58,30 +58,30 @@ func (server *Server) nickservPrivmsgHandler(client *Client, message string) {
|
||||
|
||||
// fail out if we need to
|
||||
if username == "" {
|
||||
client.Notice(client.t("No username supplied"))
|
||||
rb.Notice(client.t("No username supplied"))
|
||||
return
|
||||
}
|
||||
|
||||
server.nickservRegisterHandler(client, username, passphrase)
|
||||
server.nickservRegisterHandler(client, username, passphrase, rb)
|
||||
} else if command == "identify" {
|
||||
// get params
|
||||
username, passphrase := extractParam(params)
|
||||
|
||||
server.nickservIdentifyHandler(client, username, passphrase)
|
||||
server.nickservIdentifyHandler(client, username, passphrase, rb)
|
||||
} else {
|
||||
client.Notice(client.t("Command not recognised. To see the available commands, run /NS HELP"))
|
||||
rb.Notice(client.t("Command not recognised. To see the available commands, run /NS HELP"))
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) nickservRegisterHandler(client *Client, username, passphrase string) {
|
||||
func (server *Server) nickservRegisterHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
|
||||
certfp := client.certfp
|
||||
if passphrase == "" && certfp == "" {
|
||||
client.Notice(client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
|
||||
rb.Notice(client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
|
||||
return
|
||||
}
|
||||
|
||||
if !server.accountRegistration.Enabled {
|
||||
client.Notice(client.t("Account registration has been disabled"))
|
||||
rb.Notice(client.t("Account registration has been disabled"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
|
||||
if server.accountRegistration.AllowMultiplePerConnection {
|
||||
client.LogoutOfAccount()
|
||||
} else {
|
||||
client.Notice(client.t("You're already logged into an account"))
|
||||
rb.Notice(client.t("You're already logged into an account"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -99,7 +99,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
|
||||
casefoldedAccount, err := CasefoldName(account)
|
||||
// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
|
||||
if err != nil || username == "*" {
|
||||
client.Notice(client.t("Account name is not valid"))
|
||||
rb.Notice(client.t("Account name is not valid"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
|
||||
_, err := tx.Get(accountKey)
|
||||
if err != buntdb.ErrNotFound {
|
||||
//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
|
||||
client.Notice(client.t("Account already exists"))
|
||||
rb.Notice(client.t("Account already exists"))
|
||||
return errAccountCreation
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
|
||||
// account could not be created and relevant numerics have been dispatched, abort
|
||||
if err != nil {
|
||||
if err != errAccountCreation {
|
||||
client.Notice(client.t("Account registration failed"))
|
||||
rb.Notice(client.t("Account registration failed"))
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -178,7 +178,7 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
|
||||
if err == errCertfpAlreadyExists {
|
||||
errMsg = "An account already exists for your certificate fingerprint"
|
||||
}
|
||||
client.Notice(errMsg)
|
||||
rb.Notice(errMsg)
|
||||
removeFailedAccRegisterData(server.store, casefoldedAccount)
|
||||
return
|
||||
}
|
||||
@ -196,23 +196,23 @@ func (server *Server) nickservRegisterHandler(client *Client, username, passphra
|
||||
server.accounts[casefoldedAccount] = &account
|
||||
client.account = &account
|
||||
|
||||
client.Notice(client.t("Account created"))
|
||||
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))
|
||||
client.Send(nil, server.name, RPL_SASLSUCCESS, client.nick, client.t("Authentication successful"))
|
||||
rb.Notice(client.t("Account created"))
|
||||
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))
|
||||
rb.Add(nil, server.name, RPL_SASLSUCCESS, client.nick, client.t("Authentication successful"))
|
||||
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))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
client.Notice(client.t("Account registration failed"))
|
||||
rb.Notice(client.t("Account registration failed"))
|
||||
removeFailedAccRegisterData(server.store, casefoldedAccount)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string) {
|
||||
func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
|
||||
// fail out if we need to
|
||||
if !server.accountAuthenticationEnabled {
|
||||
client.Notice(client.t("Login has been disabled"))
|
||||
rb.Notice(client.t("Login has been disabled"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ func (server *Server) nickservIdentifyHandler(client *Client, username, passphra
|
||||
// keep it the same as in the ACC CREATE stage
|
||||
accountKey, err := CasefoldName(username)
|
||||
if err != nil {
|
||||
client.Notice(client.t("Could not login with your username/password"))
|
||||
rb.Notice(client.t("Could not login with your username/password"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ func (server *Server) nickservIdentifyHandler(client *Client, username, passphra
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
client.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
|
||||
rb.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -306,10 +306,10 @@ func (server *Server) nickservIdentifyHandler(client *Client, username, passphra
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
client.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
|
||||
rb.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), accountName))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
client.Notice(client.t("Could not login with your TLS certificate or supplied username/password"))
|
||||
rb.Notice(client.t("Could not login with your TLS certificate or supplied username/password"))
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func (rb *ResponseBuffer) AddSplitMessageFromClient(msgid string, from *Client,
|
||||
func (rb *ResponseBuffer) Send() error {
|
||||
// fall out if no messages to send
|
||||
if len(rb.messages) == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// make batch and all if required
|
||||
@ -126,3 +126,8 @@ func (rb *ResponseBuffer) Send() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Notice sends the client the given notice from the server.
|
||||
func (rb *ResponseBuffer) Notice(text string) {
|
||||
rb.Add(nil, rb.target.server.name, "NOTICE", rb.target.nick, text)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ const (
|
||||
sceneNickMask = "=Scene=!%s@npc.fakeuser.invalid"
|
||||
)
|
||||
|
||||
func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isAction bool, message string) {
|
||||
func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isAction bool, message string, rb *ResponseBuffer) {
|
||||
if isAction {
|
||||
message = fmt.Sprintf("\x01ACTION %s (%s)\x01", message, client.nick)
|
||||
} else {
|
||||
@ -26,17 +26,17 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
|
||||
if cerr == nil {
|
||||
channel := server.channels.Get(target)
|
||||
if channel == nil {
|
||||
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, client.t("No such channel"))
|
||||
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, client.t("No such channel"))
|
||||
return
|
||||
}
|
||||
|
||||
if !channel.CanSpeak(client) {
|
||||
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, client.t("Cannot send to channel"))
|
||||
return
|
||||
}
|
||||
|
||||
if !channel.flags[modes.ChanRoleplaying] {
|
||||
client.Send(nil, client.server.name, ERR_CANNOTSENDRP, channel.name, client.t("Channel doesn't have roleplaying mode available"))
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, channel.name, client.t("Channel doesn't have roleplaying mode available"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -44,28 +44,32 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
|
||||
if member == client && !client.capabilities.Has(caps.EchoMessage) {
|
||||
continue
|
||||
}
|
||||
if member == client {
|
||||
rb.Add(nil, source, "PRIVMSG", channel.name, message)
|
||||
} else {
|
||||
member.Send(nil, source, "PRIVMSG", channel.name, message)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target, err := CasefoldName(targetString)
|
||||
user := server.clients.Get(target)
|
||||
if err != nil || user == nil {
|
||||
client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, target, client.t("No such nick"))
|
||||
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, target, client.t("No such nick"))
|
||||
return
|
||||
}
|
||||
|
||||
if !user.flags[modes.UserRoleplaying] {
|
||||
client.Send(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
|
||||
rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, user.nick, client.t("User doesn't have roleplaying mode enabled"))
|
||||
return
|
||||
}
|
||||
|
||||
user.Send(nil, source, "PRIVMSG", user.nick, message)
|
||||
if client.capabilities.Has(caps.EchoMessage) {
|
||||
client.Send(nil, source, "PRIVMSG", user.nick, message)
|
||||
rb.Add(nil, source, "PRIVMSG", user.nick, message)
|
||||
}
|
||||
if user.flags[modes.Away] {
|
||||
//TODO(dan): possibly implement cooldown of away notifications to users
|
||||
client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
|
||||
rb.Add(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,8 +458,12 @@ func (server *Server) tryRegister(c *Client) {
|
||||
c.Send(nil, server.name, RPL_CREATED, c.nick, fmt.Sprintf(c.t("This server was created %s"), server.ctime.Format(time.RFC1123)))
|
||||
//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
|
||||
c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
|
||||
c.RplISupport()
|
||||
server.MOTD(c)
|
||||
|
||||
rb := NewResponseBuffer(c)
|
||||
c.RplISupport(rb)
|
||||
server.MOTD(c, rb)
|
||||
rb.Send()
|
||||
|
||||
c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
|
||||
if server.logger.IsLoggingRawIO() {
|
||||
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) {
|
||||
} else {
|
||||
c.Send(nil, c.nickMaskString, "JOIN", channel.name)
|
||||
}
|
||||
channel.SendTopic(c)
|
||||
channel.Names(c)
|
||||
// reuse the last rb
|
||||
channel.SendTopic(c, rb)
|
||||
channel.Names(c, rb)
|
||||
rb.Send()
|
||||
|
||||
// construct and send fake modestring if necessary
|
||||
c.stateMutex.RLock()
|
||||
@ -511,21 +517,21 @@ func (client *Client) t(originalString string) string {
|
||||
}
|
||||
|
||||
// MOTD serves the Message of the Day.
|
||||
func (server *Server) MOTD(client *Client) {
|
||||
func (server *Server) MOTD(client *Client, rb *ResponseBuffer) {
|
||||
server.configurableStateMutex.RLock()
|
||||
motdLines := server.motdLines
|
||||
server.configurableStateMutex.RUnlock()
|
||||
|
||||
if len(motdLines) < 1 {
|
||||
client.Send(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
|
||||
rb.Add(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
|
||||
return
|
||||
}
|
||||
|
||||
client.Send(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
|
||||
rb.Add(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
|
||||
for _, line := range motdLines {
|
||||
client.Send(nil, server.name, RPL_MOTD, client.nick, line)
|
||||
rb.Add(nil, server.name, RPL_MOTD, client.nick, line)
|
||||
}
|
||||
client.Send(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
|
||||
rb.Add(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// rplWhoReply returns the WHO reply between one user and another channel/user.
|
||||
// <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
|
||||
// :<hopcount> <real name>
|
||||
func (target *Client) rplWhoReply(channel *Channel, client *Client) {
|
||||
func (target *Client) rplWhoReply(channel *Channel, client *Client, rb *ResponseBuffer) {
|
||||
channelName := "*"
|
||||
flags := ""
|
||||
|
||||
@ -667,13 +673,13 @@ func (target *Client) rplWhoReply(channel *Channel, client *Client) {
|
||||
flags += channel.ClientPrefixes(client, target.capabilities.Has(caps.MultiPrefix))
|
||||
channelName = channel.name
|
||||
}
|
||||
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())
|
||||
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())
|
||||
}
|
||||
|
||||
func whoChannel(client *Client, channel *Channel, friends ClientSet) {
|
||||
func whoChannel(client *Client, channel *Channel, friends ClientSet, rb *ResponseBuffer) {
|
||||
for _, member := range channel.Members() {
|
||||
if !client.flags[modes.Invisible] || friends[client] {
|
||||
client.rplWhoReply(channel, member)
|
||||
client.rplWhoReply(channel, member, rb)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1140,7 +1146,7 @@ func (matcher *elistMatcher) Matches(channel *Channel) bool {
|
||||
}
|
||||
|
||||
// RplList returns the RPL_LIST numeric for the given channel.
|
||||
func (target *Client) RplList(channel *Channel) {
|
||||
func (target *Client) RplList(channel *Channel, rb *ResponseBuffer) {
|
||||
// get the correct number of channel members
|
||||
var memberCount int
|
||||
if target.flags[modes.Operator] || channel.hasClient(target) {
|
||||
@ -1153,44 +1159,7 @@ func (target *Client) RplList(channel *Channel) {
|
||||
}
|
||||
}
|
||||
|
||||
target.Send(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
|
||||
}
|
||||
|
||||
// NAMES [<channel>{,<channel>}]
|
||||
func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
var channels []string
|
||||
if len(msg.Params) > 0 {
|
||||
channels = strings.Split(msg.Params[0], ",")
|
||||
}
|
||||
//var target string
|
||||
//if len(msg.Params) > 1 {
|
||||
// target = msg.Params[1]
|
||||
//}
|
||||
|
||||
if len(channels) == 0 {
|
||||
for _, channel := range server.channels.Channels() {
|
||||
channel.Names(client)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// limit regular users to only listing one channel
|
||||
if !client.flags[modes.Operator] {
|
||||
channels = channels[:1]
|
||||
}
|
||||
|
||||
for _, chname := range channels {
|
||||
casefoldedChname, err := CasefoldChannel(chname)
|
||||
channel := server.channels.Get(casefoldedChname)
|
||||
if err != nil || channel == nil {
|
||||
if len(chname) > 0 {
|
||||
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
channel.Names(client)
|
||||
}
|
||||
return false
|
||||
rb.Add(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
|
||||
}
|
||||
|
||||
// ResumeDetails are the details that we use to resume connections.
|
||||
|
Loading…
Reference in New Issue
Block a user