diff --git a/bridge.go b/bridge.go index 8c3e62d..3782a7b 100644 --- a/bridge.go +++ b/bridge.go @@ -26,8 +26,14 @@ func forwardChannel(dc *downstreamConn, ch *upstreamChannel) { } // TODO: rpl_topicwhotime + sendNames(dc, ch) +} +func sendNames(dc *downstreamConn, ch *upstreamChannel) { // TODO: send multiple members in each message + + downstreamName := dc.marshalChannel(ch.conn, ch.Name) + for nick, membership := range ch.Members { s := membership.String() + dc.marshalNick(ch.conn, nick) diff --git a/downstream.go b/downstream.go index d6dbeb8..dcf0c4e 100644 --- a/downstream.go +++ b/downstream.go @@ -913,13 +913,41 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { Params: params, }) } + case "NAMES": + if len(msg.Params) == 0 { + dc.SendMessage(&irc.Message{ + Prefix: dc.srv.prefix(), + Command: irc.RPL_ENDOFNAMES, + Params: []string{dc.nick, "*", "End of /NAMES list"}, + }) + return nil + } + + channels := strings.Split(msg.Params[0], ",") + for _, channel := range channels { + uc, upstreamChannel, err := dc.unmarshalEntity(channel) + if err != nil { + return err + } + + ch, ok := uc.channels[upstreamChannel] + if ok { + sendNames(dc, ch) + } else { + // NAMES on a channel we have not joined, ask upstream + uc.SendMessage(&irc.Message{ + Command: "NAMES", + Params: []string{upstreamChannel}, + }) + } + } case "WHO": if len(msg.Params) == 0 { // TODO: support WHO without parameters dc.SendMessage(&irc.Message{ Prefix: dc.srv.prefix(), Command: irc.RPL_ENDOFWHO, - Params: []string{dc.nick, "*", "End of /WHO list."}, + Params: []string{dc.nick, "*", "End of /WHO list"}, }) return nil } diff --git a/upstream.go b/upstream.go index 87ef279..5136ff4 100644 --- a/upstream.go +++ b/upstream.go @@ -651,9 +651,26 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error { if err := parseMessageParams(msg, nil, &statusStr, &name, &members); err != nil { return err } - ch, err := uc.getChannel(name) - if err != nil { - return err + + ch, ok := uc.channels[name] + if !ok { + // NAMES on a channel we have not joined, forward to downstream + uc.forEachDownstream(func(dc *downstreamConn) { + channel := dc.marshalChannel(uc, name) + members := strings.Split(members, " ") + for i, member := range members { + membership, nick := uc.parseMembershipPrefix(member) + members[i] = membership.String() + dc.marshalNick(uc, nick) + } + memberStr := strings.Join(members, " ") + + dc.SendMessage(&irc.Message{ + Prefix: dc.srv.prefix(), + Command: irc.RPL_NAMREPLY, + Params: []string{dc.nick, statusStr, channel, memberStr}, + }) + }) + return nil } status, err := parseChannelStatus(statusStr) @@ -671,9 +688,20 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error { if err := parseMessageParams(msg, nil, &name); err != nil { return err } - ch, err := uc.getChannel(name) - if err != nil { - return err + + ch, ok := uc.channels[name] + if !ok { + // NAMES on a channel we have not joined, forward to downstream + uc.forEachDownstream(func(dc *downstreamConn) { + channel := dc.marshalChannel(uc, name) + + dc.SendMessage(&irc.Message{ + Prefix: dc.srv.prefix(), + Command: irc.RPL_ENDOFNAMES, + Params: []string{dc.nick, channel, "End of /NAMES list"}, + }) + }) + return nil } if ch.complete {