aboutsummaryrefslogtreecommitdiff
path: root/msg.go
diff options
context:
space:
mode:
Diffstat (limited to 'msg.go')
-rw-r--r--msg.go125
1 files changed, 125 insertions, 0 deletions
diff --git a/msg.go b/msg.go
new file mode 100644
index 0000000..ff4b3a4
--- /dev/null
+++ b/msg.go
@@ -0,0 +1,125 @@
+package main
+
+import (
+ "strings"
+)
+
+type Msg struct {
+ RawMessage string
+ RawSource string
+ Command string
+ Tags map[string]string
+ Params []string
+}
+
+// Partially adapted from https://github.com/ergochat/irc-go.git
+func parseIRCMsg(line string) (msg Msg, err error) {
+ msg = Msg{
+ RawMessage: line,
+ }
+
+ line = strings.TrimSuffix(line, "\n")
+ line = strings.TrimSuffix(line, "\r")
+
+ if len(line) == 0 {
+ err = ErrEmptyMessage
+ return
+ }
+
+ for _, v := range line {
+ if v == '\x00' || v == '\r' || v == '\n' {
+ err = ErrIllegalByte
+ return
+ }
+ }
+
+ // IRCv3 tags
+ if line[0] == '@' {
+ tagEnd := strings.IndexByte(line, ' ')
+ if tagEnd == -1 {
+ err = ErrEmptyMessage
+ return
+ }
+ tagsString := line[1:tagEnd]
+ if 0 < MaxlenTagData && MaxlenTagData < len(tagsString) {
+ err = ErrTagsTooLong
+ return
+ }
+ msg.Tags, err = parseTags(tagsString)
+ if err != nil {
+ return
+ }
+ // Skip over the tags and the separating space
+ line = line[tagEnd+1:]
+ }
+
+ if len(line) > MaxlenBody {
+ err = ErrBodyTooLong
+ line = line[:MaxlenBody]
+ }
+
+ line = trimInitialSpaces(line)
+
+ // Source
+ if 0 < len(line) && line[0] == ':' {
+ sourceEnd := strings.IndexByte(line, ' ')
+ if sourceEnd == -1 {
+ err = ErrEmptyMessage
+ return
+ }
+ msg.RawSource = line[1:sourceEnd]
+ // Skip over the source and the separating space
+ line = line[sourceEnd+1:]
+ }
+
+ // Command
+ commandEnd := strings.IndexByte(line, ' ')
+ paramStart := commandEnd + 1
+ if commandEnd == -1 {
+ commandEnd = len(line)
+ paramStart = len(line)
+ }
+ baseCommand := line[:commandEnd]
+ if len(baseCommand) == 0 {
+ err = ErrEmptyMessage
+ return
+ }
+ // TODO: Actually must be either letters or a 3-digit numeric
+ if !isASCII(baseCommand) {
+ err = ErrIllegalByte
+ return
+ }
+ msg.Command = strings.ToUpper(baseCommand)
+ line = line[paramStart:]
+
+ // Other arguments
+ for {
+ line = trimInitialSpaces(line)
+ if len(line) == 0 {
+ break
+ }
+ // Trailing
+ if line[0] == ':' {
+ msg.Params = append(msg.Params, line[1:])
+ break
+ }
+ paramEnd := strings.IndexByte(line, ' ')
+ if paramEnd == -1 {
+ msg.Params = append(msg.Params, line)
+ break
+ }
+ msg.Params = append(msg.Params, line[:paramEnd])
+ line = line[paramEnd+1:]
+ }
+
+ return
+}
+
+func isASCII(str string) bool {
+ for i := 0; i < len(str); i++ {
+ if str[i] > 127 {
+ return false
+ }
+ }
+ return true
+}