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()
|
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 {
|
if uc := dc.upstream(); uc != nil {
|
||||||
return uc, name, nil
|
return uc, name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
network := ""
|
var conn *upstreamConn
|
||||||
if i := strings.LastIndexByte(name, '/'); i >= 0 {
|
if i := strings.LastIndexByte(name, '/'); i >= 0 {
|
||||||
network = name[i+1:]
|
network := name[i+1:]
|
||||||
name = name[:i]
|
name = name[:i]
|
||||||
}
|
|
||||||
|
|
||||||
if network != "" {
|
|
||||||
var conn *upstreamConn
|
|
||||||
dc.forEachUpstream(func(uc *upstreamConn) {
|
dc.forEachUpstream(func(uc *upstreamConn) {
|
||||||
if network != uc.network.GetName() {
|
if network != uc.network.GetName() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = uc
|
conn = uc
|
||||||
})
|
})
|
||||||
return conn, name, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var channel *upstreamChannel
|
if conn == nil {
|
||||||
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 {
|
|
||||||
return nil, "", ircError{&irc.Message{
|
return nil, "", ircError{&irc.Message{
|
||||||
Command: irc.ERR_NOSUCHCHANNEL,
|
Command: irc.ERR_NOSUCHCHANNEL,
|
||||||
Params: []string{name, "No such channel"},
|
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 {
|
func (dc *downstreamConn) marshalNick(uc *upstreamConn, nick string) string {
|
||||||
@ -843,7 +825,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
uc, upstreamName, err := dc.unmarshalChannel(name)
|
uc, upstreamName, err := dc.unmarshalEntity(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ircError{&irc.Message{
|
return ircError{&irc.Message{
|
||||||
Command: irc.ERR_NOSUCHCHANNEL,
|
Command: irc.ERR_NOSUCHCHANNEL,
|
||||||
@ -885,7 +867,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if msg.Prefix.Name != name {
|
if msg.Prefix.Name != name {
|
||||||
uc, upstreamName, err := dc.unmarshalChannel(name)
|
uc, upstreamName, err := dc.unmarshalEntity(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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":
|
case "PRIVMSG":
|
||||||
var targetsStr, text string
|
var targetsStr, text string
|
||||||
if err := parseMessageParams(msg, &targetsStr, &text); err != nil {
|
if err := parseMessageParams(msg, &targetsStr, &text); err != nil {
|
||||||
@ -945,7 +957,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
uc, upstreamName, err := dc.unmarshalChannel(name)
|
uc, upstreamName, err := dc.unmarshalEntity(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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) {
|
uc.forEachDownstream(func(dc *downstreamConn) {
|
||||||
forwardChannel(dc, ch)
|
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":
|
case "PRIVMSG":
|
||||||
if msg.Prefix == nil {
|
if msg.Prefix == nil {
|
||||||
return fmt.Errorf("expected a prefix")
|
return fmt.Errorf("expected a prefix")
|
||||||
|
Loading…
Reference in New Issue
Block a user