Migrate case-mapping to xirc

This commit is contained in:
Simon Ser 2023-03-01 13:30:47 +01:00
parent 07cd1f2f5d
commit 3eb2679612
5 changed files with 102 additions and 93 deletions

View File

@ -365,7 +365,7 @@ func newDownstreamConn(srv *Server, ic ircConn, id uint64) *downstreamConn {
monitored: newCasemapMap[struct{}](),
registration: new(downstreamRegistration),
}
dc.monitored.SetCasemapping(casemapASCII)
dc.monitored.SetCasemapping(xirc.CaseMappingASCII)
if host, _, err := net.SplitHostPort(remoteAddr); err == nil {
dc.hostname = host
} else {
@ -1110,7 +1110,7 @@ func (dc *downstreamConn) updateNick() {
Params: []string{nick},
})
dc.nick = nick
dc.nickCM = casemapASCII(dc.nick)
dc.nickCM = xirc.CaseMappingASCII(dc.nick)
}
func (dc *downstreamConn) updateHost() {
@ -1197,7 +1197,7 @@ func (dc *downstreamConn) updateAccount() {
}
func (dc *downstreamConn) updateCasemapping() {
cm := casemapASCII
cm := xirc.CaseMappingASCII
if dc.network != nil {
cm = dc.network.casemap
}
@ -1397,7 +1397,7 @@ func (dc *downstreamConn) loadNetwork(ctx context.Context) error {
Params: []string{dc.nick, dc.registration.nick, "Nickname contains illegal characters"},
}}
}
if casemapASCII(nick) == serviceNickCM {
if xirc.CaseMappingASCII(nick) == serviceNickCM {
return ircError{&irc.Message{
Command: irc.ERR_NICKNAMEINUSE,
Params: []string{dc.nick, dc.registration.nick, "Nickname reserved for bouncer service"},
@ -1446,7 +1446,7 @@ func (dc *downstreamConn) welcome(ctx context.Context) error {
} else {
dc.nick = dc.user.Username
}
dc.nickCM = casemapASCII(dc.nick)
dc.nickCM = xirc.CaseMappingASCII(dc.nick)
var isupport []string
if dc.network != nil {
@ -1761,7 +1761,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
Params: []string{dc.nick, nick, "Nickname contains illegal characters"},
}}
}
if casemapASCII(nick) == serviceNickCM {
if xirc.CaseMappingASCII(nick) == serviceNickCM {
return ircError{&irc.Message{
Command: irc.ERR_NICKNAMEINUSE,
Params: []string{dc.nick, nick, "Nickname reserved for bouncer service"},
@ -2000,7 +2000,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
modeStr = msg.Params[1]
}
if casemapASCII(name) == dc.nickCM {
if xirc.CaseMappingASCII(name) == dc.nickCM {
if modeStr != "" {
if uc := dc.upstream(); uc != nil {
uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
@ -2165,7 +2165,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
fields, whoxToken := xirc.ParseWHOXOptions(options)
// TODO: support mixed bouncer/upstream WHO queries
maskCM := casemapASCII(mask)
maskCM := xirc.CaseMappingASCII(mask)
if dc.network == nil && maskCM == dc.nickCM {
// TODO: support AWAY (H/G) in self WHO reply
flags := "H"
@ -2274,7 +2274,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
mask = mask[:i]
}
if dc.network == nil && casemapASCII(mask) == dc.nickCM {
if dc.network == nil && xirc.CaseMappingASCII(mask) == dc.nickCM {
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.RPL_WHOISUSER,
@ -2304,7 +2304,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
})
return nil
}
if casemapASCII(mask) == serviceNickCM {
if xirc.CaseMappingASCII(mask) == serviceNickCM {
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.RPL_WHOISUSER,
@ -2391,7 +2391,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
continue
}
if dc.network == nil && casemapASCII(name) == dc.nickCM {
if dc.network == nil && xirc.CaseMappingASCII(name) == dc.nickCM {
dc.SendMessage(&irc.Message{
Tags: msg.Tags.Copy(),
Prefix: dc.prefix(),
@ -2401,7 +2401,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
continue
}
if casemapASCII(name) == serviceNickCM {
if xirc.CaseMappingASCII(name) == serviceNickCM {
if dc.caps.IsEnabled("echo-message") {
echoTags := tags.Copy()
echoTags["time"] = dc.user.FormatServerTime(time.Now())
@ -2724,7 +2724,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
}
// We don't save history for our service
if casemapASCII(target) == serviceNickCM {
if xirc.CaseMappingASCII(target) == serviceNickCM {
dc.SendBatch("chathistory", []string{target}, nil, func(batchRef string) {})
return nil
}
@ -2849,7 +2849,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
}
// We don't save read receipts for our service
if casemapASCII(target) == serviceNickCM {
if xirc.CaseMappingASCII(target) == serviceNickCM {
dc.SendMessage(&irc.Message{
Prefix: dc.prefix(),
Command: msg.Command,

76
irc.go
View File

@ -216,79 +216,11 @@ func copyClientTags(tags irc.Tags) irc.Tags {
return t
}
type casemapping func(string) string
func casemapNone(name string) string {
return name
}
// CasemapASCII of name is the canonical representation of name according to the
// ascii casemapping.
func casemapASCII(name string) string {
nameBytes := []byte(name)
for i, r := range nameBytes {
if 'A' <= r && r <= 'Z' {
nameBytes[i] = r + 'a' - 'A'
}
}
return string(nameBytes)
}
// casemapRFC1459 of name is the canonical representation of name according to the
// rfc1459 casemapping.
func casemapRFC1459(name string) string {
nameBytes := []byte(name)
for i, r := range nameBytes {
if 'A' <= r && r <= 'Z' {
nameBytes[i] = r + 'a' - 'A'
} else if r == '{' {
nameBytes[i] = '['
} else if r == '}' {
nameBytes[i] = ']'
} else if r == '\\' {
nameBytes[i] = '|'
} else if r == '~' {
nameBytes[i] = '^'
}
}
return string(nameBytes)
}
// casemapRFC1459Strict of name is the canonical representation of name
// according to the rfc1459-strict casemapping.
func casemapRFC1459Strict(name string) string {
nameBytes := []byte(name)
for i, r := range nameBytes {
if 'A' <= r && r <= 'Z' {
nameBytes[i] = r + 'a' - 'A'
} else if r == '{' {
nameBytes[i] = '['
} else if r == '}' {
nameBytes[i] = ']'
} else if r == '\\' {
nameBytes[i] = '|'
}
}
return string(nameBytes)
}
func parseCasemappingToken(tokenValue string) (casemap casemapping, ok bool) {
switch tokenValue {
case "ascii":
casemap = casemapASCII
case "rfc1459":
casemap = casemapRFC1459
case "rfc1459-strict":
casemap = casemapRFC1459Strict
default:
return nil, false
}
return casemap, true
}
var stdCaseMapping = xirc.CaseMappingRFC1459
type casemapMap[V interface{}] struct {
m map[string]casemapEntry[V]
casemap casemapping
casemap xirc.CaseMapping
}
type casemapEntry[V interface{}] struct {
@ -299,7 +231,7 @@ type casemapEntry[V interface{}] struct {
func newCasemapMap[V interface{}]() casemapMap[V] {
return casemapMap[V]{
m: make(map[string]casemapEntry[V]),
casemap: casemapNone,
casemap: xirc.CaseMappingNone,
}
}
@ -345,7 +277,7 @@ func (cm *casemapMap[V]) ForEach(f func(string, V)) {
}
}
func (cm *casemapMap[V]) SetCasemapping(newCasemap casemapping) {
func (cm *casemapMap[V]) SetCasemapping(newCasemap xirc.CaseMapping) {
cm.casemap = newCasemap
m := make(map[string]casemapEntry[V], len(cm.m))
for _, entry := range cm.m {

View File

@ -942,9 +942,9 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
var err error
switch parameter {
case "CASEMAPPING":
casemap, ok := parseCasemappingToken(value)
if !ok {
casemap = casemapRFC1459
casemap := xirc.ParseCaseMapping(value)
if casemap == nil {
casemap = xirc.CaseMappingRFC1459
}
uc.network.updateCasemapping(casemap)
case "CHANMODES":
@ -992,7 +992,7 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
// If upstream did not send any CASEMAPPING token, assume it
// implements the old RFCs with rfc1459.
if uc.isupport["CASEMAPPING"] == nil {
uc.network.updateCasemapping(casemapRFC1459)
uc.network.updateCasemapping(stdCaseMapping)
}
// If the server doesn't support MONITOR, periodically try to

View File

@ -151,7 +151,7 @@ type network struct {
delivered deliveredStore
pushTargets casemapMap[time.Time]
lastError error
casemap casemapping
casemap xirc.CaseMapping
}
func newNetwork(user *user, record *database.Network, channels []database.Channel) *network {
@ -171,7 +171,7 @@ func newNetwork(user *user, record *database.Network, channels []database.Channe
channels: m,
delivered: newDeliveredStore(),
pushTargets: newCasemapMap[time.Time](),
casemap: casemapRFC1459,
casemap: stdCaseMapping,
}
}
@ -387,7 +387,7 @@ func (net *network) deleteChannel(ctx context.Context, name string) error {
return nil
}
func (net *network) updateCasemapping(newCasemap casemapping) {
func (net *network) updateCasemapping(newCasemap xirc.CaseMapping) {
net.casemap = newCasemap
net.channels.SetCasemapping(newCasemap)
net.delivered.m.SetCasemapping(newCasemap)

77
xirc/casemapping.go Normal file
View File

@ -0,0 +1,77 @@
package xirc
func casemapNone(name string) string {
return name
}
// CasemapASCII of name is the canonical representation of name according to the
// ascii casemapping.
func casemapASCII(name string) string {
nameBytes := []byte(name)
for i, r := range nameBytes {
if 'A' <= r && r <= 'Z' {
nameBytes[i] = r + 'a' - 'A'
}
}
return string(nameBytes)
}
// casemapRFC1459 of name is the canonical representation of name according to the
// rfc1459 casemapping.
func casemapRFC1459(name string) string {
nameBytes := []byte(name)
for i, r := range nameBytes {
if 'A' <= r && r <= 'Z' {
nameBytes[i] = r + 'a' - 'A'
} else if r == '{' {
nameBytes[i] = '['
} else if r == '}' {
nameBytes[i] = ']'
} else if r == '\\' {
nameBytes[i] = '|'
} else if r == '~' {
nameBytes[i] = '^'
}
}
return string(nameBytes)
}
// casemapRFC1459Strict of name is the canonical representation of name
// according to the rfc1459-strict casemapping.
func casemapRFC1459Strict(name string) string {
nameBytes := []byte(name)
for i, r := range nameBytes {
if 'A' <= r && r <= 'Z' {
nameBytes[i] = r + 'a' - 'A'
} else if r == '{' {
nameBytes[i] = '['
} else if r == '}' {
nameBytes[i] = ']'
} else if r == '\\' {
nameBytes[i] = '|'
}
}
return string(nameBytes)
}
type CaseMapping func(string) string
var (
CaseMappingNone CaseMapping = casemapNone
CaseMappingASCII CaseMapping = casemapASCII
CaseMappingRFC1459 CaseMapping = casemapRFC1459
CaseMappingRFC1459Strict CaseMapping = casemapRFC1459Strict
)
func ParseCaseMapping(s string) CaseMapping {
var cm CaseMapping
switch s {
case "ascii":
cm = CaseMappingASCII
case "rfc1459":
cm = CaseMappingRFC1459
case "rfc1459-strict":
cm = CaseMappingRFC1459Strict
}
return cm
}