From e31fe5d24df9341842c90ed4825fe6313a02458f Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 9 Aug 2015 12:56:44 -0700 Subject: [PATCH] NAMES responses for global added. When no parameter is passed all channels and global are returned Now prevents invisible users from being revealed --- channel.go | 19 ++++++++++------- client.go | 4 ++-- commands.go | 60 +++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/channel.go b/channel.go index c33f698..0077190 100644 --- a/channel.go +++ b/channel.go @@ -84,13 +84,15 @@ func (c *Channel) Join(client *Client, key string) { } // Names responds to to IRC NAMES command for the channel -func (c *Channel) Names(client *Client) { +func (c *Channel) Names(client *Client) []string { - if c.HasMode(ChannelModeSecret) && !c.HasMember(client) { // If channel is secret and client isn't a member, don't reveal it - return + var named []string + isMember := c.HasMember(client) + if c.HasMode(ChannelModeSecret) && !isMember { // If channel is secret and client isn't a member, don't reveal it + return named } - if c.HasMode(ChannelModePrivate) && !c.HasMember(client) { // If channel is private and client isn't a member, don't reply - return + if c.HasMode(ChannelModePrivate) && !isMember { // If channel is private and client isn't a member, don't reply + return named } allMembers := make([]string, len(c.members)) @@ -120,6 +122,9 @@ func (c *Channel) Names(client *Client) { for _, member := range allMembers[i*20 : end] { mClient, _ := client.Server.GetClientByNick(member) + if mClient.HasMode(UserModeInvisible) && !isMember { //the requesting client shouldn't know about this client + continue + } if mClient != nil { if c.MemberHasMode(mClient, ChannelModeOperator) { @@ -128,6 +133,7 @@ func (c *Channel) Names(client *Client) { memberStr += "+" } memberStr += mClient.Nickname + " " + named = append(named, mClient.Nickname) } @@ -137,8 +143,7 @@ func (c *Channel) Names(client *Client) { } - m := irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_ENDOFNAMES, Params: []string{client.Nickname, c.Name}, Trailing: "End of NAMES list"} - client.Encode(&m) + return named } // Part handles when a client leaves a channel diff --git a/client.go b/client.go index 876a47d..21acc06 100644 --- a/client.go +++ b/client.go @@ -273,8 +273,8 @@ func (c *Client) SendMessagetoVisible(m *irc.Message) { } } -// SendWho rmanages responding to the WHO request for all visible clients of this client -func (c *Client) SendWho() { +// Who rmanages responding to the WHO request for all visible clients of this client +func (c *Client) Who() { clients := map[string]*Client{} for name, client := range c.Server.clientsByNick { if client.HasMode(UserModeInvisible) { diff --git a/commands.go b/commands.go index 470390b..7f35784 100644 --- a/commands.go +++ b/commands.go @@ -315,7 +315,7 @@ func NoticeHandler(message *irc.Message, client *Client) { func WhoHandler(message *irc.Message, client *Client) { if len(message.Params) == 0 || len(message.Params[0]) == 0 || message.Params[0][0] == '*' { //return listing of all visible users - visible people and people in channels with this client - client.SendWho() + client.Who() return } @@ -786,18 +786,56 @@ func ChannelModeHandler(message *irc.Message, client *Client) { // Implemented according to RFC 1459 Section 4.2.5 and RFC 2812 Section 3.2.5 func NamesHandler(message *irc.Message, client *Client) { if len(message.Params) == 0 { // Send NAMES response for all channels - for _, ch := range client.Server.channels { - ch.Names(client) - } - } else { - channelNames := strings.Split(message.Params[0], ",") - for _, channelName := range channelNames { - ch, ok := client.Server.GetChannel(channelName) - if ok { - ch.Names(client) - } + named := map[string]interface{}{} + for _, ch := range client.Server.channels { + n := ch.Names(client) + for _, k := range n { + named[k] = nil + } } + count := 0 + memberStr := "" + for n, cl := range client.Server.clientsByNick { + _, alreadyNamed := named[n] + if !alreadyNamed && !cl.HasMode(UserModeInvisible) { //don't name people that are already named or that shouldn't be named + count++ + if cl != nil { + if cl.HasMode(UserModeOperator) || cl.HasMode(UserModeLocalOperator) { + memberStr += "@" + } + memberStr += cl.Nickname + " " + + } + if count%20 == 0 { // String is long enough, send message + m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_NAMREPLY, Params: []string{client.Nickname, "*", "*"}, Trailing: memberStr} + client.Encode(&m) + memberStr = "" + } + + } + } + m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_NAMREPLY, Params: []string{client.Nickname, "*", "*"}, Trailing: memberStr} + client.Encode(&m) + m = irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_ENDOFNAMES, Params: []string{client.Nickname, "*"}, Trailing: "End of NAMES list"} + client.Encode(&m) + return + } + if len(message.Params) == 2 { //Client has provided target server for the request + m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOSUCHSERVER, Params: []string{client.Nickname, message.Params[0]}, Trailing: "No such server"} + client.Encode(&m) + return + } + + channelNames := strings.Split(message.Params[0], ",") + for _, channelName := range channelNames { + ch, ok := client.Server.GetChannel(channelName) + if ok { + ch.Names(client) + m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_ENDOFNAMES, Params: []string{client.Nickname, ch.Name}, Trailing: "End of NAMES list"} + client.Encode(&m) + } + } }