Passthrough some ISUPPORT tokens

This commit is contained in:
Simon Ser 2021-03-15 23:41:37 +01:00
parent 3f005d481d
commit fa047123b9
3 changed files with 86 additions and 9 deletions

View file

@ -81,6 +81,33 @@ var needAllDownstreamCaps = map[string]string{
"multi-prefix": "", "multi-prefix": "",
} }
// passthroughIsupport is the set of ISUPPORT tokens that are directly passed
// through from the upstream server to downstream clients.
//
// This is only effective in single-upstream mode.
var passthroughIsupport = map[string]bool{
"AWAYLEN": true,
"CHANLIMIT": true,
"CHANMODES": true,
"CHANNELLEN": true,
"CHANTYPES": true,
"EXCEPTS": true,
"EXTBAN": true,
"HOSTLEN": true,
"INVEX": true,
"KICKLEN": true,
"MAXLIST": true,
"MAXTARGETS": true,
"MODES": true,
"NETWORK": true,
"NICKLEN": true,
"PREFIX": true,
"SAFELIST": true,
"TARGMAX": true,
"TOPICLEN": true,
"USERLEN": true,
}
type downstreamConn struct { type downstreamConn struct {
conn conn
@ -880,8 +907,18 @@ func (dc *downstreamConn) welcome() error {
fmt.Sprintf("CHATHISTORY=%v", dc.srv.HistoryLimit), fmt.Sprintf("CHATHISTORY=%v", dc.srv.HistoryLimit),
} }
if uc := dc.upstream(); uc != nil && uc.isupport["NETWORK"] != nil { if uc := dc.upstream(); uc != nil {
isupport = append(isupport, fmt.Sprintf("NETWORK=%v", *uc.isupport["NETWORK"])) for k := range passthroughIsupport {
v, ok := uc.isupport[k]
if !ok {
continue
}
if v != nil {
isupport = append(isupport, fmt.Sprintf("%v=%v", k, *v))
} else {
isupport = append(isupport, k)
}
}
} }
dc.SendMessage(&irc.Message{ dc.SendMessage(&irc.Message{
@ -904,12 +941,9 @@ func (dc *downstreamConn) welcome() error {
Command: irc.RPL_MYINFO, Command: irc.RPL_MYINFO,
Params: []string{dc.nick, dc.srv.Hostname, "soju", "aiwroO", "OovaimnqpsrtklbeI"}, Params: []string{dc.nick, dc.srv.Hostname, "soju", "aiwroO", "OovaimnqpsrtklbeI"},
}) })
// TODO: other RPL_ISUPPORT tokens for _, msg := range generateIsupport(dc.srv.prefix(), dc.nick, isupport) {
dc.SendMessage(&irc.Message{ dc.SendMessage(msg)
Prefix: dc.srv.prefix(), }
Command: irc.RPL_ISUPPORT,
Params: append(append([]string{dc.nick}, isupport...), "are supported"),
})
dc.SendMessage(&irc.Message{ dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(), Prefix: dc.srv.prefix(),
Command: irc.ERR_NOMOTD, Command: irc.ERR_NOMOTD,

29
irc.go
View file

@ -17,7 +17,10 @@ const (
err_invalidcapcmd = "410" err_invalidcapcmd = "410"
) )
const maxMessageLength = 512 const (
maxMessageLength = 512
maxMessageParams = 15
)
// The server-time layout, as defined in the IRCv3 spec. // The server-time layout, as defined in the IRCv3 spec.
const serverTimeLayout = "2006-01-02T15:04:05.000Z" const serverTimeLayout = "2006-01-02T15:04:05.000Z"
@ -348,6 +351,30 @@ func join(channels, keys []string) []*irc.Message {
return msgs return msgs
} }
func generateIsupport(prefix *irc.Prefix, nick string, tokens []string) []*irc.Message {
maxTokens := maxMessageParams - 2 // 2 reserved params: nick + text
var msgs []*irc.Message
for len(tokens) > 0 {
var msgTokens []string
if len(tokens) > maxTokens {
msgTokens = tokens[:maxTokens]
tokens = tokens[maxTokens:]
} else {
msgTokens = tokens
tokens = nil
}
msgs = append(msgs, &irc.Message{
Prefix: prefix,
Command: irc.RPL_ISUPPORT,
Params: append(append([]string{nick}, msgTokens...), "are supported"),
})
}
return msgs
}
type joinSorter struct { type joinSorter struct {
channels []string channels []string
keys []string keys []string

View file

@ -613,6 +613,8 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
if err := parseMessageParams(msg, nil, nil); err != nil { if err := parseMessageParams(msg, nil, nil); err != nil {
return err return err
} }
var downstreamIsupport []string
for _, token := range msg.Params[1 : len(msg.Params)-1] { for _, token := range msg.Params[1 : len(msg.Params)-1] {
parameter := token parameter := token
var negate, hasValue bool var negate, hasValue bool
@ -658,7 +660,21 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
if err != nil { if err != nil {
return err return err
} }
if passthroughIsupport[parameter] {
downstreamIsupport = append(downstreamIsupport, token)
} }
}
uc.forEachDownstream(func(dc *downstreamConn) {
if dc.network == nil {
return
}
msgs := generateIsupport(dc.srv.prefix(), dc.nick, downstreamIsupport)
for _, msg := range msgs {
dc.SendMessage(msg)
}
})
case "BATCH": case "BATCH":
var tag string var tag string
if err := parseMessageParams(msg, &tag); err != nil { if err := parseMessageParams(msg, &tag); err != nil {