aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hid/main.go84
1 files changed, 66 insertions, 18 deletions
diff --git a/hid/main.go b/hid/main.go
index 1c72fca..eec67d9 100644
--- a/hid/main.go
+++ b/hid/main.go
@@ -296,17 +296,72 @@ func ircFnmatch(pattern string, s string) bool {
return matched
}
-// TODO: We will need to add support for IRCv3 tags.
var reMsg = regexp.MustCompile(
- `^(?::([^! ]*)(?:!([^@]*)@([^ ]*))? +)?([^ ]+)(.*)?$`)
+ `^(?:@[^ ]* +)(?::([^! ]*)(?:!([^@]*)@([^ ]*))? +)?([^ ]+)(.*)?$`)
var reArgs = regexp.MustCompile(`:.*| [^: ][^ ]*`)
type message struct {
- nick string // optional nickname
- user string // optional username
- host string // optional hostname or IP address
- command string // command name
- params []string // arguments
+ tags map[string]string // IRC 3.2 message tags
+ nick string // optional nickname
+ user string // optional username
+ host string // optional hostname or IP address
+ command string // command name
+ params []string // arguments
+}
+
+func ircUnescapeMessageTag(value string) string {
+ var buf []byte
+ escape := false
+ for i := 0; i < len(value); i++ {
+ if escape {
+ switch value[i] {
+ case ':':
+ buf = append(buf, ';')
+ case 's':
+ buf = append(buf, ' ')
+ case 'r':
+ buf = append(buf, '\r')
+ case 'n':
+ buf = append(buf, '\n')
+ default:
+ buf = append(buf, value[i])
+ }
+ escape = false
+ } else if value[i] == '\\' {
+ escape = true
+ } else {
+ buf = append(buf, value[i])
+ }
+ }
+ return string(buf)
+}
+
+func ircParseMessageTags(tags string, out map[string]string) {
+ for _, tag := range splitString(tags, ";", true /* ignoreEmpty */) {
+ if equal := strings.IndexByte(tag, '='); equal < 0 {
+ out[tag] = ""
+ } else {
+ out[tag[:equal]] = ircUnescapeMessageTag(tag[equal+1:])
+ }
+ }
+}
+
+func ircParseMessage(line string) *message {
+ m := reMsg.FindStringSubmatch(line)
+ if m == nil {
+ return nil
+ }
+
+ msg := message{nil, m[2], m[3], m[4], m[5], nil}
+ if m[1] != "" {
+ msg.tags = make(map[string]string)
+ ircParseMessageTags(m[1], msg.tags)
+ }
+ for _, x := range reArgs.FindAllString(m[6], -1) {
+ msg.params = append(msg.params, x[1:])
+ }
+ return &msg
+
}
// Everything as per RFC 2812
@@ -2627,23 +2682,16 @@ func (c *client) onRead(data []byte, readErr error) {
break
}
+ // XXX: And since it accepts LF, we miscalculate receivedBytes within.
c.recvQ = c.recvQ[advance:]
line := string(token)
log.Printf("-> %s\n", line)
- m := reMsg.FindStringSubmatch(line)
- if m == nil {
+ if msg := ircParseMessage(line); msg == nil {
log.Println("error: invalid line")
- continue
- }
-
- msg := message{m[1], m[2], m[3], m[4], nil}
- for _, x := range reArgs.FindAllString(m[5], -1) {
- msg.params = append(msg.params, x[1:])
+ } else {
+ ircProcessMessage(c, msg, line)
}
-
- // XXX: And since it accepts LF, we miscalculate receivedBytes within.
- ircProcessMessage(c, &msg, line)
}
if readErr != nil {