Add WHO support
This commit is contained in:
parent
549fbf62b1
commit
54275c25ac
@ -169,49 +169,31 @@ func (dc *downstreamConn) marshalChannel(uc *upstreamConn, name string) string {
|
||||
return name + "/" + uc.network.GetName()
|
||||
}
|
||||
|
||||
func (dc *downstreamConn) unmarshalChannel(name string) (*upstreamConn, string, error) {
|
||||
func (dc *downstreamConn) unmarshalEntity(name string) (*upstreamConn, string, error) {
|
||||
if uc := dc.upstream(); uc != nil {
|
||||
return uc, name, nil
|
||||
}
|
||||
|
||||
network := ""
|
||||
if i := strings.LastIndexByte(name, '/'); i >= 0 {
|
||||
network = name[i+1:]
|
||||
name = name[:i]
|
||||
}
|
||||
|
||||
if network != "" {
|
||||
var conn *upstreamConn
|
||||
if i := strings.LastIndexByte(name, '/'); i >= 0 {
|
||||
network := name[i+1:]
|
||||
name = name[:i]
|
||||
|
||||
dc.forEachUpstream(func(uc *upstreamConn) {
|
||||
if network != uc.network.GetName() {
|
||||
return
|
||||
}
|
||||
conn = uc
|
||||
})
|
||||
return conn, name, nil
|
||||
}
|
||||
|
||||
var channel *upstreamChannel
|
||||
var err error
|
||||
dc.forEachUpstream(func(uc *upstreamConn) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ch, ok := uc.channels[name]; ok {
|
||||
if channel != nil {
|
||||
err = fmt.Errorf("ambiguous channel name %q", name)
|
||||
} else {
|
||||
channel = ch
|
||||
}
|
||||
}
|
||||
})
|
||||
if channel == nil {
|
||||
if conn == nil {
|
||||
return nil, "", ircError{&irc.Message{
|
||||
Command: irc.ERR_NOSUCHCHANNEL,
|
||||
Params: []string{name, "No such channel"},
|
||||
}}
|
||||
}
|
||||
return channel.conn, channel.Name, nil
|
||||
return conn, name, nil
|
||||
}
|
||||
|
||||
func (dc *downstreamConn) marshalNick(uc *upstreamConn, nick string) string {
|
||||
@ -843,7 +825,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
return err
|
||||
}
|
||||
|
||||
uc, upstreamName, err := dc.unmarshalChannel(name)
|
||||
uc, upstreamName, err := dc.unmarshalEntity(name)
|
||||
if err != nil {
|
||||
return ircError{&irc.Message{
|
||||
Command: irc.ERR_NOSUCHCHANNEL,
|
||||
@ -885,7 +867,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
}
|
||||
|
||||
if msg.Prefix.Name != name {
|
||||
uc, upstreamName, err := dc.unmarshalChannel(name)
|
||||
uc, upstreamName, err := dc.unmarshalEntity(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -933,6 +915,36 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
})
|
||||
}
|
||||
}
|
||||
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."},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: support WHO masks
|
||||
entity := msg.Params[0]
|
||||
|
||||
uc, upstreamName, err := dc.unmarshalEntity(entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var params []string
|
||||
if len(msg.Params) == 2 {
|
||||
params = []string{upstreamName, msg.Params[1]}
|
||||
} else {
|
||||
params = []string{upstreamName}
|
||||
}
|
||||
|
||||
uc.SendMessage(&irc.Message{
|
||||
Command: "WHO",
|
||||
Params: params,
|
||||
})
|
||||
case "PRIVMSG":
|
||||
var targetsStr, text string
|
||||
if err := parseMessageParams(msg, &targetsStr, &text); err != nil {
|
||||
@ -945,7 +957,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
continue
|
||||
}
|
||||
|
||||
uc, upstreamName, err := dc.unmarshalChannel(name)
|
||||
uc, upstreamName, err := dc.unmarshalEntity(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
49
upstream.go
49
upstream.go
@ -557,6 +557,55 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
|
||||
uc.forEachDownstream(func(dc *downstreamConn) {
|
||||
forwardChannel(dc, ch)
|
||||
})
|
||||
case irc.RPL_WHOREPLY:
|
||||
var channel, username, host, server, nick, mode, trailing string
|
||||
if err := parseMessageParams(msg, nil, &channel, &username, &host, &server, &nick, &mode, &trailing); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parts := strings.SplitN(trailing, " ", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("received malformed RPL_WHOREPLY: wrong trailing parameter: %s", trailing)
|
||||
}
|
||||
realname := parts[1]
|
||||
hops, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("received malformed RPL_WHOREPLY: wrong hop count: %s", parts[0])
|
||||
}
|
||||
hops++
|
||||
|
||||
trailing = strconv.Itoa(hops) + " " + realname
|
||||
|
||||
uc.forEachDownstream(func(dc *downstreamConn) {
|
||||
channel := channel
|
||||
if channel != "*" {
|
||||
channel = dc.marshalChannel(uc, channel)
|
||||
}
|
||||
nick := dc.marshalNick(uc, nick)
|
||||
dc.SendMessage(&irc.Message{
|
||||
Prefix: dc.srv.prefix(),
|
||||
Command: irc.RPL_WHOREPLY,
|
||||
Params: []string{dc.nick, channel, username, host, server, nick, mode, trailing},
|
||||
})
|
||||
})
|
||||
case irc.RPL_ENDOFWHO:
|
||||
var name string
|
||||
if err := parseMessageParams(msg, nil, &name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uc.forEachDownstream(func(dc *downstreamConn) {
|
||||
name := name
|
||||
if name != "*" {
|
||||
// TODO: support WHO masks
|
||||
name = dc.marshalEntity(uc, name)
|
||||
}
|
||||
dc.SendMessage(&irc.Message{
|
||||
Prefix: dc.srv.prefix(),
|
||||
Command: irc.RPL_ENDOFWHO,
|
||||
Params: []string{dc.nick, name, "End of /WHO list."},
|
||||
})
|
||||
})
|
||||
case "PRIVMSG":
|
||||
if msg.Prefix == nil {
|
||||
return fmt.Errorf("expected a prefix")
|
||||
|
Loading…
Reference in New Issue
Block a user