Add IRCv3 tag parsing
This commit is contained in:
parent
62e115498f
commit
33e0f67766
|
@ -8,6 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
|
Tags map[string]string
|
||||||
Prefix string
|
Prefix string
|
||||||
Nick string
|
Nick string
|
||||||
Command string
|
Command string
|
||||||
|
@ -24,17 +25,40 @@ func (m *Message) LastParam() string {
|
||||||
func parseMessage(line string) *Message {
|
func parseMessage(line string) *Message {
|
||||||
line = strings.Trim(line, "\r\n ")
|
line = strings.Trim(line, "\r\n ")
|
||||||
msg := Message{}
|
msg := Message{}
|
||||||
cmdStart := 0
|
|
||||||
cmdEnd := len(line)
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, ":") {
|
if strings.HasPrefix(line, "@") {
|
||||||
cmdStart = strings.Index(line, " ") + 1
|
next := strings.Index(line, " ")
|
||||||
|
if next == -1 {
|
||||||
if cmdStart > 0 {
|
|
||||||
msg.Prefix = line[1 : cmdStart-1]
|
|
||||||
} else {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
tags := strings.Split(line[1:next], ";")
|
||||||
|
|
||||||
|
if len(tags) > 0 {
|
||||||
|
msg.Tags = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tag := range tags {
|
||||||
|
key, val := splitParam(tag)
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != "" {
|
||||||
|
msg.Tags[key] = unescapeTag(val)
|
||||||
|
} else {
|
||||||
|
msg.Tags[key] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line = line[next+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(line, ":") {
|
||||||
|
next := strings.Index(line, " ")
|
||||||
|
if next == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
msg.Prefix = line[1:next]
|
||||||
|
|
||||||
if i := strings.Index(msg.Prefix, "!"); i > 0 {
|
if i := strings.Index(msg.Prefix, "!"); i > 0 {
|
||||||
msg.Nick = msg.Prefix[:i]
|
msg.Nick = msg.Prefix[:i]
|
||||||
|
@ -43,16 +67,18 @@ func parseMessage(line string) *Message {
|
||||||
} else {
|
} else {
|
||||||
msg.Nick = msg.Prefix
|
msg.Nick = msg.Prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line = line[next+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
var trailing string
|
cmdEnd := len(line)
|
||||||
|
trailing := ""
|
||||||
if i := strings.Index(line, " :"); i > 0 {
|
if i := strings.Index(line, " :"); i > 0 {
|
||||||
cmdEnd = i
|
cmdEnd = i
|
||||||
trailing = line[i+2:]
|
trailing = line[i+2:]
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := strings.Fields(line[cmdStart:cmdEnd])
|
cmd := strings.Fields(line[:cmdEnd])
|
||||||
if len(cmd) == 0 {
|
if len(cmd) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -61,7 +87,6 @@ func parseMessage(line string) *Message {
|
||||||
if len(cmd) > 1 {
|
if len(cmd) > 1 {
|
||||||
msg.Params = cmd[1:]
|
msg.Params = cmd[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmdEnd != len(line) {
|
if cmdEnd != len(line) {
|
||||||
msg.Params = append(msg.Params, trailing)
|
msg.Params = append(msg.Params, trailing)
|
||||||
}
|
}
|
||||||
|
@ -83,17 +108,15 @@ func newISupport() *iSupport {
|
||||||
func (i *iSupport) parse(params []string) {
|
func (i *iSupport) parse(params []string) {
|
||||||
i.lock.Lock()
|
i.lock.Lock()
|
||||||
for _, param := range params[1 : len(params)-1] {
|
for _, param := range params[1 : len(params)-1] {
|
||||||
parts := strings.SplitN(param, "=", 2)
|
key, val := splitParam(param)
|
||||||
if parts[0] == "" {
|
if key == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if parts[0][0] == '-' {
|
if key[0] == '-' {
|
||||||
delete(i.support, parts[0][1:])
|
delete(i.support, key[1:])
|
||||||
} else if len(parts) == 2 {
|
|
||||||
i.support[parts[0]] = parts[1]
|
|
||||||
} else {
|
} else {
|
||||||
i.support[param] = ""
|
i.support[key] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.lock.Unlock()
|
i.lock.Unlock()
|
||||||
|
@ -119,3 +142,20 @@ func (i *iSupport) GetInt(key string) int {
|
||||||
i.lock.Unlock()
|
i.lock.Unlock()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func splitParam(param string) (string, string) {
|
||||||
|
parts := strings.SplitN(param, "=", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
return parts[0], parts[1]
|
||||||
|
}
|
||||||
|
return parts[0], ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func unescapeTag(s string) string {
|
||||||
|
s = strings.Replace(s, "\\:", ";", -1)
|
||||||
|
s = strings.Replace(s, "\\s", " ", -1)
|
||||||
|
s = strings.Replace(s, "\\\\", "\\", -1)
|
||||||
|
s = strings.Replace(s, "\\r", "\r", -1)
|
||||||
|
s = strings.Replace(s, "\\n", "\n", -1)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
|
@ -100,6 +100,53 @@ func TestParseMessage(t *testing.T) {
|
||||||
Command: "CMD",
|
Command: "CMD",
|
||||||
Params: []string{"#cake", "pie!"},
|
Params: []string{"#cake", "pie!"},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
"@x=y CMD\r\n",
|
||||||
|
&Message{
|
||||||
|
Tags: map[string]string{
|
||||||
|
"x": "y",
|
||||||
|
},
|
||||||
|
Command: "CMD",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"@x=y :nick!user@host.com CMD\r\n",
|
||||||
|
&Message{
|
||||||
|
Tags: map[string]string{
|
||||||
|
"x": "y",
|
||||||
|
},
|
||||||
|
Prefix: "nick!user@host.com",
|
||||||
|
Nick: "nick",
|
||||||
|
Command: "CMD",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"@x=y :nick!user@host.com CMD :pie and cake\r\n",
|
||||||
|
&Message{
|
||||||
|
Tags: map[string]string{
|
||||||
|
"x": "y",
|
||||||
|
},
|
||||||
|
Prefix: "nick!user@host.com",
|
||||||
|
Nick: "nick",
|
||||||
|
Command: "CMD",
|
||||||
|
Params: []string{"pie and cake"},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"@x=y;a=b CMD\r\n",
|
||||||
|
&Message{
|
||||||
|
Tags: map[string]string{
|
||||||
|
"x": "y",
|
||||||
|
"a": "b",
|
||||||
|
},
|
||||||
|
Command: "CMD",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"@x=y;a=\\\\\\:\\s\\r\\n CMD\r\n",
|
||||||
|
&Message{
|
||||||
|
Tags: map[string]string{
|
||||||
|
"x": "y",
|
||||||
|
"a": "\\; \r\n",
|
||||||
|
},
|
||||||
|
Command: "CMD",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +161,9 @@ func TestLastParam(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBadMessagePanic(t *testing.T) {
|
func TestBadMessagePanic(t *testing.T) {
|
||||||
|
parseMessage("@\r\n")
|
||||||
|
parseMessage("@ :\r\n")
|
||||||
|
parseMessage("@ :\r\n")
|
||||||
parseMessage(":user\r\n")
|
parseMessage(":user\r\n")
|
||||||
parseMessage(":\r\n")
|
parseMessage(":\r\n")
|
||||||
parseMessage(":")
|
parseMessage(":")
|
||||||
|
|
Loading…
Reference in New Issue