summaryrefslogtreecommitdiff
path: root/vendor/github.com/fluffle/goirc/client/line.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/fluffle/goirc/client/line.go')
-rw-r--r--vendor/github.com/fluffle/goirc/client/line.go216
1 files changed, 0 insertions, 216 deletions
diff --git a/vendor/github.com/fluffle/goirc/client/line.go b/vendor/github.com/fluffle/goirc/client/line.go
deleted file mode 100644
index bfa473a..0000000
--- a/vendor/github.com/fluffle/goirc/client/line.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package client
-
-import (
- "runtime"
- "strings"
- "time"
-
- "github.com/fluffle/goirc/logging"
-)
-
-var tagsReplacer = strings.NewReplacer("\\:", ";", "\\s", " ", "\\r", "\r", "\\n", "\n")
-
-// We parse an incoming line into this struct. Line.Cmd is used as the trigger
-// name for incoming event handlers and is the IRC verb, the first sequence
-// of non-whitespace characters after ":nick!user@host", e.g. PRIVMSG.
-// Raw =~ ":nick!user@host cmd args[] :text"
-// Src == "nick!user@host"
-// Cmd == e.g. PRIVMSG, 332
-type Line struct {
- Tags map[string]string
- Nick, Ident, Host, Src string
- Cmd, Raw string
- Args []string
- Time time.Time
-}
-
-// Copy returns a deep copy of the Line.
-func (l *Line) Copy() *Line {
- nl := *l
- nl.Args = make([]string, len(l.Args))
- copy(nl.Args, l.Args)
- if l.Tags != nil {
- nl.Tags = make(map[string]string)
- for k, v := range l.Tags {
- nl.Tags[k] = v
- }
- }
- return &nl
-}
-
-// Text returns the contents of the text portion of a line. This only really
-// makes sense for lines with a :text part, but there are a lot of them.
-func (line *Line) Text() string {
- if len(line.Args) > 0 {
- return line.Args[len(line.Args)-1]
- }
- return ""
-}
-
-// Target returns the contextual target of the line, usually the first Arg
-// for the IRC verb. If the line was broadcast from a channel, the target
-// will be that channel. If the line was sent directly by a user, the target
-// will be that user.
-func (line *Line) Target() string {
- // TODO(fluffle): Add 005 CHANTYPES parsing for this?
- switch line.Cmd {
- case PRIVMSG, NOTICE, ACTION:
- if !line.Public() {
- return line.Nick
- }
- case CTCP, CTCPREPLY:
- if !line.Public() {
- return line.Nick
- }
- return line.Args[1]
- }
- if len(line.Args) > 0 {
- return line.Args[0]
- }
- return ""
-}
-
-// Public returns true if the line is the result of an IRC user sending
-// a message to a channel the client has joined instead of directly
-// to the client.
-//
-// NOTE: This is very permissive, allowing all 4 RFC channel types even if
-// your server doesn't technically support them.
-func (line *Line) Public() bool {
- switch line.Cmd {
- case PRIVMSG, NOTICE, ACTION:
- switch line.Args[0][0] {
- case '#', '&', '+', '!':
- return true
- }
- case CTCP, CTCPREPLY:
- // CTCP prepends the CTCP verb to line.Args, thus for the message
- // :nick!user@host PRIVMSG #foo :\001BAR baz\001
- // line.Args contains: []string{"BAR", "#foo", "baz"}
- // TODO(fluffle): Arguably this is broken, and we should have
- // line.Args containing: []string{"#foo", "BAR", "baz"}
- // ... OR change conn.Ctcp()'s argument order to be consistent.
- switch line.Args[1][0] {
- case '#', '&', '+', '!':
- return true
- }
- }
- return false
-}
-
-// ParseLine creates a Line from an incoming message from the IRC server.
-//
-// It contains special casing for CTCP messages, most notably CTCP ACTION.
-// All CTCP messages have the \001 bytes stripped from the message and the
-// CTCP command separated from any subsequent text. Then, CTCP ACTIONs are
-// rewritten such that Line.Cmd == ACTION. Other CTCP messages have Cmd
-// set to CTCP or CTCPREPLY, and the CTCP command prepended to line.Args.
-//
-// ParseLine also parses IRCv3 tags, if received. If a line does not have
-// the tags section, Line.Tags will be nil. Tags are optional, and will
-// only be included after the correct CAP command.
-//
-// http://ircv3.net/specs/core/capability-negotiation-3.1.html
-// http://ircv3.net/specs/core/message-tags-3.2.html
-func ParseLine(s string) *Line {
- line := &Line{Raw: s}
-
- if s == "" {
- return nil
- }
-
- if s[0] == '@' {
- var rawTags string
- line.Tags = make(map[string]string)
- if idx := strings.Index(s, " "); idx != -1 {
- rawTags, s = s[1:idx], s[idx+1:]
- } else {
- return nil
- }
-
- // ; is represented as \: in a tag, so it's safe to split on ;
- for _, tag := range strings.Split(rawTags, ";") {
- if tag == "" {
- continue
- }
-
- pair := strings.SplitN(tagsReplacer.Replace(tag), "=", 2)
- if len(pair) < 2 {
- line.Tags[tag] = ""
- } else {
- line.Tags[pair[0]] = pair[1]
- }
- }
- }
-
- if s[0] == ':' {
- // remove a source and parse it
- if idx := strings.Index(s, " "); idx != -1 {
- line.Src, s = s[1:idx], s[idx+1:]
- } else {
- // pretty sure we shouldn't get here ...
- return nil
- }
-
- // src can be the hostname of the irc server or a nick!user@host
- line.Host = line.Src
- nidx, uidx := strings.Index(line.Src, "!"), strings.Index(line.Src, "@")
- if uidx != -1 && nidx != -1 {
- line.Nick = line.Src[:nidx]
- line.Ident = line.Src[nidx+1 : uidx]
- line.Host = line.Src[uidx+1:]
- }
- }
-
- // now we're here, we've parsed a :nick!user@host or :server off
- // s should contain "cmd args[] :text"
- args := strings.SplitN(s, " :", 2)
- if len(args) > 1 {
- args = append(strings.Fields(args[0]), args[1])
- } else {
- args = strings.Fields(args[0])
- }
- line.Cmd = strings.ToUpper(args[0])
- if len(args) > 1 {
- line.Args = args[1:]
- }
-
- // So, I think CTCP and (in particular) CTCP ACTION are better handled as
- // separate events as opposed to forcing people to have gargantuan
- // handlers to cope with the possibilities.
- if (line.Cmd == PRIVMSG || line.Cmd == NOTICE) &&
- len(line.Args[1]) > 2 &&
- strings.HasPrefix(line.Args[1], "\001") &&
- strings.HasSuffix(line.Args[1], "\001") {
- // WOO, it's a CTCP message
- t := strings.SplitN(strings.Trim(line.Args[1], "\001"), " ", 2)
- if len(t) > 1 {
- // Replace the line with the unwrapped CTCP
- line.Args[1] = t[1]
- }
- if c := strings.ToUpper(t[0]); c == ACTION && line.Cmd == PRIVMSG {
- // make a CTCP ACTION it's own event a-la PRIVMSG
- line.Cmd = c
- } else {
- // otherwise, dispatch a generic CTCP/CTCPREPLY event that
- // contains the type of CTCP in line.Args[0]
- if line.Cmd == PRIVMSG {
- line.Cmd = CTCP
- } else {
- line.Cmd = CTCPREPLY
- }
- line.Args = append([]string{c}, line.Args...)
- }
- }
- return line
-}
-
-func (line *Line) argslen(minlen int) bool {
- pc, _, _, _ := runtime.Caller(1)
- fn := runtime.FuncForPC(pc)
- if len(line.Args) <= minlen {
- logging.Warn("%s: too few arguments: %s", fn.Name(), strings.Join(line.Args, " "))
- return false
- }
- return true
-}