2024-05-14 05:51:42 +00:00
|
|
|
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
|
|
|
|
}
|
2024-05-15 09:28:02 +00:00
|
|
|
|
2024-05-14 05:51:42 +00:00
|
|
|
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 {
|
2024-05-15 09:28:02 +00:00
|
|
|
if _, err := w.Write([]byte(":")); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-05-14 05:51:42 +00:00
|
|
|
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
|
|
|
|
}
|
2024-05-15 09:28:02 +00:00
|
|
|
if len(msg.Params) > 0 {
|
|
|
|
if _, err := w.Write([]byte(" ")); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-05-14 05:51:42 +00:00
|
|
|
}
|
|
|
|
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()
|
|
|
|
}
|