package ircv3 import ( "errors" "io" "strings" ) type Message struct { Source *NUH Command string Params []string Tags Tags } func NewMessage(command string, params ...string) *Message { return &Message{ Source: nil, Command: command, Params: params, Tags: make(Tags), } } func (m *Message) SetSource(nuh *NUH) *Message { m.Source = nuh return m } func (m *Message) Param(i int) string { if len(m.Params) > i { return m.Params[i] } return "" } func (msg *Message) String() string { sb := new(strings.Builder) msg.Encode(sb) return sb.String() } func (msg *Message) Encode(w io.Writer) error { if msg.Command == "" { return nil } if msg.Tags != nil && len(msg.Tags) > 0 { _, err := msg.Tags.WriteTo(w) if err != nil { return err } _, err = w.Write([]byte(" ")) if err != nil { return err } } if msg.Source != nil { if _, err := w.Write([]byte(":")); err != nil { return err } if _, err := w.Write([]byte(msg.Source.String())); err != nil { return err } if _, err := w.Write([]byte(" ")); err != nil { return err } } // now write command if _, err := w.Write([]byte(msg.Command)); err != nil { return err } if len(msg.Params) > 0 { if _, err := w.Write([]byte(" ")); err != nil { return err } } for idx, v := range msg.Params { if idx != 0 { if _, err := w.Write([]byte(" ")); err != nil { return err } } // now write any params if len(msg.Params)-1 == idx && strings.Contains(v, " ") { if _, err := w.Write([]byte(":")); err != nil { return err } } if _, err := w.Write([]byte(v)); err != nil { return err } } return nil } type NUH struct { Name string User string Host string } var ( MalformedNUH = errors.New("NUH is malformed") ) // ParseNUH parses a NUH source of an IRC message into its constituent parts; // name (nickname or server name), username, and hostname. func ParseNUH(in string) (out NUH, err error) { if len(in) == 0 { return out, MalformedNUH } hostStart := strings.IndexByte(in, '@') if hostStart != -1 { out.Host = in[hostStart+1:] in = in[:hostStart] } userStart := strings.IndexByte(in, '!') if userStart != -1 { out.User = in[userStart+1:] in = in[:userStart] } out.Name = in return } // Canonical returns the canonical string representation of the NUH. func (nuh *NUH) String() (result string) { var out strings.Builder out.Grow(len(nuh.Name) + len(nuh.User) + len(nuh.Host) + 2) out.WriteString(nuh.Name) if len(nuh.User) != 0 { out.WriteByte('!') out.WriteString(nuh.User) } if len(nuh.Host) != 0 { out.WriteByte('@') out.WriteString(nuh.Host) } return out.String() }