Migrate case-mapping to xirc
This commit is contained in:
parent
07cd1f2f5d
commit
3eb2679612
@ -365,7 +365,7 @@ func newDownstreamConn(srv *Server, ic ircConn, id uint64) *downstreamConn {
|
|||||||
monitored: newCasemapMap[struct{}](),
|
monitored: newCasemapMap[struct{}](),
|
||||||
registration: new(downstreamRegistration),
|
registration: new(downstreamRegistration),
|
||||||
}
|
}
|
||||||
dc.monitored.SetCasemapping(casemapASCII)
|
dc.monitored.SetCasemapping(xirc.CaseMappingASCII)
|
||||||
if host, _, err := net.SplitHostPort(remoteAddr); err == nil {
|
if host, _, err := net.SplitHostPort(remoteAddr); err == nil {
|
||||||
dc.hostname = host
|
dc.hostname = host
|
||||||
} else {
|
} else {
|
||||||
@ -1110,7 +1110,7 @@ func (dc *downstreamConn) updateNick() {
|
|||||||
Params: []string{nick},
|
Params: []string{nick},
|
||||||
})
|
})
|
||||||
dc.nick = nick
|
dc.nick = nick
|
||||||
dc.nickCM = casemapASCII(dc.nick)
|
dc.nickCM = xirc.CaseMappingASCII(dc.nick)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *downstreamConn) updateHost() {
|
func (dc *downstreamConn) updateHost() {
|
||||||
@ -1197,7 +1197,7 @@ func (dc *downstreamConn) updateAccount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dc *downstreamConn) updateCasemapping() {
|
func (dc *downstreamConn) updateCasemapping() {
|
||||||
cm := casemapASCII
|
cm := xirc.CaseMappingASCII
|
||||||
if dc.network != nil {
|
if dc.network != nil {
|
||||||
cm = dc.network.casemap
|
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"},
|
Params: []string{dc.nick, dc.registration.nick, "Nickname contains illegal characters"},
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
if casemapASCII(nick) == serviceNickCM {
|
if xirc.CaseMappingASCII(nick) == serviceNickCM {
|
||||||
return ircError{&irc.Message{
|
return ircError{&irc.Message{
|
||||||
Command: irc.ERR_NICKNAMEINUSE,
|
Command: irc.ERR_NICKNAMEINUSE,
|
||||||
Params: []string{dc.nick, dc.registration.nick, "Nickname reserved for bouncer service"},
|
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 {
|
} else {
|
||||||
dc.nick = dc.user.Username
|
dc.nick = dc.user.Username
|
||||||
}
|
}
|
||||||
dc.nickCM = casemapASCII(dc.nick)
|
dc.nickCM = xirc.CaseMappingASCII(dc.nick)
|
||||||
|
|
||||||
var isupport []string
|
var isupport []string
|
||||||
if dc.network != nil {
|
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"},
|
Params: []string{dc.nick, nick, "Nickname contains illegal characters"},
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
if casemapASCII(nick) == serviceNickCM {
|
if xirc.CaseMappingASCII(nick) == serviceNickCM {
|
||||||
return ircError{&irc.Message{
|
return ircError{&irc.Message{
|
||||||
Command: irc.ERR_NICKNAMEINUSE,
|
Command: irc.ERR_NICKNAMEINUSE,
|
||||||
Params: []string{dc.nick, nick, "Nickname reserved for bouncer service"},
|
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]
|
modeStr = msg.Params[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if casemapASCII(name) == dc.nickCM {
|
if xirc.CaseMappingASCII(name) == dc.nickCM {
|
||||||
if modeStr != "" {
|
if modeStr != "" {
|
||||||
if uc := dc.upstream(); uc != nil {
|
if uc := dc.upstream(); uc != nil {
|
||||||
uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
|
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)
|
fields, whoxToken := xirc.ParseWHOXOptions(options)
|
||||||
|
|
||||||
// TODO: support mixed bouncer/upstream WHO queries
|
// TODO: support mixed bouncer/upstream WHO queries
|
||||||
maskCM := casemapASCII(mask)
|
maskCM := xirc.CaseMappingASCII(mask)
|
||||||
if dc.network == nil && maskCM == dc.nickCM {
|
if dc.network == nil && maskCM == dc.nickCM {
|
||||||
// TODO: support AWAY (H/G) in self WHO reply
|
// TODO: support AWAY (H/G) in self WHO reply
|
||||||
flags := "H"
|
flags := "H"
|
||||||
@ -2274,7 +2274,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
mask = mask[:i]
|
mask = mask[:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
if dc.network == nil && casemapASCII(mask) == dc.nickCM {
|
if dc.network == nil && xirc.CaseMappingASCII(mask) == dc.nickCM {
|
||||||
dc.SendMessage(&irc.Message{
|
dc.SendMessage(&irc.Message{
|
||||||
Prefix: dc.srv.prefix(),
|
Prefix: dc.srv.prefix(),
|
||||||
Command: irc.RPL_WHOISUSER,
|
Command: irc.RPL_WHOISUSER,
|
||||||
@ -2304,7 +2304,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if casemapASCII(mask) == serviceNickCM {
|
if xirc.CaseMappingASCII(mask) == serviceNickCM {
|
||||||
dc.SendMessage(&irc.Message{
|
dc.SendMessage(&irc.Message{
|
||||||
Prefix: dc.srv.prefix(),
|
Prefix: dc.srv.prefix(),
|
||||||
Command: irc.RPL_WHOISUSER,
|
Command: irc.RPL_WHOISUSER,
|
||||||
@ -2391,7 +2391,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if dc.network == nil && casemapASCII(name) == dc.nickCM {
|
if dc.network == nil && xirc.CaseMappingASCII(name) == dc.nickCM {
|
||||||
dc.SendMessage(&irc.Message{
|
dc.SendMessage(&irc.Message{
|
||||||
Tags: msg.Tags.Copy(),
|
Tags: msg.Tags.Copy(),
|
||||||
Prefix: dc.prefix(),
|
Prefix: dc.prefix(),
|
||||||
@ -2401,7 +2401,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if casemapASCII(name) == serviceNickCM {
|
if xirc.CaseMappingASCII(name) == serviceNickCM {
|
||||||
if dc.caps.IsEnabled("echo-message") {
|
if dc.caps.IsEnabled("echo-message") {
|
||||||
echoTags := tags.Copy()
|
echoTags := tags.Copy()
|
||||||
echoTags["time"] = dc.user.FormatServerTime(time.Now())
|
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
|
// 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) {})
|
dc.SendBatch("chathistory", []string{target}, nil, func(batchRef string) {})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -2849,7 +2849,7 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We don't save read receipts for our service
|
// We don't save read receipts for our service
|
||||||
if casemapASCII(target) == serviceNickCM {
|
if xirc.CaseMappingASCII(target) == serviceNickCM {
|
||||||
dc.SendMessage(&irc.Message{
|
dc.SendMessage(&irc.Message{
|
||||||
Prefix: dc.prefix(),
|
Prefix: dc.prefix(),
|
||||||
Command: msg.Command,
|
Command: msg.Command,
|
||||||
|
76
irc.go
76
irc.go
@ -216,79 +216,11 @@ func copyClientTags(tags irc.Tags) irc.Tags {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
type casemapping func(string) string
|
var stdCaseMapping = xirc.CaseMappingRFC1459
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type casemapMap[V interface{}] struct {
|
type casemapMap[V interface{}] struct {
|
||||||
m map[string]casemapEntry[V]
|
m map[string]casemapEntry[V]
|
||||||
casemap casemapping
|
casemap xirc.CaseMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
type casemapEntry[V interface{}] struct {
|
type casemapEntry[V interface{}] struct {
|
||||||
@ -299,7 +231,7 @@ type casemapEntry[V interface{}] struct {
|
|||||||
func newCasemapMap[V interface{}]() casemapMap[V] {
|
func newCasemapMap[V interface{}]() casemapMap[V] {
|
||||||
return casemapMap[V]{
|
return casemapMap[V]{
|
||||||
m: make(map[string]casemapEntry[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
|
cm.casemap = newCasemap
|
||||||
m := make(map[string]casemapEntry[V], len(cm.m))
|
m := make(map[string]casemapEntry[V], len(cm.m))
|
||||||
for _, entry := range cm.m {
|
for _, entry := range cm.m {
|
||||||
|
@ -942,9 +942,9 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
|
|||||||
var err error
|
var err error
|
||||||
switch parameter {
|
switch parameter {
|
||||||
case "CASEMAPPING":
|
case "CASEMAPPING":
|
||||||
casemap, ok := parseCasemappingToken(value)
|
casemap := xirc.ParseCaseMapping(value)
|
||||||
if !ok {
|
if casemap == nil {
|
||||||
casemap = casemapRFC1459
|
casemap = xirc.CaseMappingRFC1459
|
||||||
}
|
}
|
||||||
uc.network.updateCasemapping(casemap)
|
uc.network.updateCasemapping(casemap)
|
||||||
case "CHANMODES":
|
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
|
// If upstream did not send any CASEMAPPING token, assume it
|
||||||
// implements the old RFCs with rfc1459.
|
// implements the old RFCs with rfc1459.
|
||||||
if uc.isupport["CASEMAPPING"] == nil {
|
if uc.isupport["CASEMAPPING"] == nil {
|
||||||
uc.network.updateCasemapping(casemapRFC1459)
|
uc.network.updateCasemapping(stdCaseMapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the server doesn't support MONITOR, periodically try to
|
// If the server doesn't support MONITOR, periodically try to
|
||||||
|
6
user.go
6
user.go
@ -151,7 +151,7 @@ type network struct {
|
|||||||
delivered deliveredStore
|
delivered deliveredStore
|
||||||
pushTargets casemapMap[time.Time]
|
pushTargets casemapMap[time.Time]
|
||||||
lastError error
|
lastError error
|
||||||
casemap casemapping
|
casemap xirc.CaseMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNetwork(user *user, record *database.Network, channels []database.Channel) *network {
|
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,
|
channels: m,
|
||||||
delivered: newDeliveredStore(),
|
delivered: newDeliveredStore(),
|
||||||
pushTargets: newCasemapMap[time.Time](),
|
pushTargets: newCasemapMap[time.Time](),
|
||||||
casemap: casemapRFC1459,
|
casemap: stdCaseMapping,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,7 +387,7 @@ func (net *network) deleteChannel(ctx context.Context, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (net *network) updateCasemapping(newCasemap casemapping) {
|
func (net *network) updateCasemapping(newCasemap xirc.CaseMapping) {
|
||||||
net.casemap = newCasemap
|
net.casemap = newCasemap
|
||||||
net.channels.SetCasemapping(newCasemap)
|
net.channels.SetCasemapping(newCasemap)
|
||||||
net.delivered.m.SetCasemapping(newCasemap)
|
net.delivered.m.SetCasemapping(newCasemap)
|
||||||
|
77
xirc/casemapping.go
Normal file
77
xirc/casemapping.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user