From 5d55bc03e829afdad427f7539c1e08e65b88d409 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 6 Jul 2019 18:59:20 +0200 Subject: drop vendor --- vendor/github.com/fluffle/goirc/LICENSE | 27 - vendor/github.com/fluffle/goirc/client/commands.go | 304 ----------- .../github.com/fluffle/goirc/client/connection.go | 587 --------------------- vendor/github.com/fluffle/goirc/client/dispatch.go | 202 ------- vendor/github.com/fluffle/goirc/client/doc.go | 34 -- vendor/github.com/fluffle/goirc/client/handlers.go | 105 ---- vendor/github.com/fluffle/goirc/client/line.go | 216 -------- .../fluffle/goirc/client/state_handlers.go | 262 --------- vendor/github.com/fluffle/goirc/logging/logging.go | 44 -- vendor/github.com/fluffle/goirc/state/channel.go | 360 ------------- .../github.com/fluffle/goirc/state/mock_tracker.go | 201 ------- vendor/github.com/fluffle/goirc/state/nick.go | 205 ------- vendor/github.com/fluffle/goirc/state/tracker.go | 369 ------------- 13 files changed, 2916 deletions(-) delete mode 100644 vendor/github.com/fluffle/goirc/LICENSE delete mode 100644 vendor/github.com/fluffle/goirc/client/commands.go delete mode 100644 vendor/github.com/fluffle/goirc/client/connection.go delete mode 100644 vendor/github.com/fluffle/goirc/client/dispatch.go delete mode 100644 vendor/github.com/fluffle/goirc/client/doc.go delete mode 100644 vendor/github.com/fluffle/goirc/client/handlers.go delete mode 100644 vendor/github.com/fluffle/goirc/client/line.go delete mode 100644 vendor/github.com/fluffle/goirc/client/state_handlers.go delete mode 100644 vendor/github.com/fluffle/goirc/logging/logging.go delete mode 100644 vendor/github.com/fluffle/goirc/state/channel.go delete mode 100644 vendor/github.com/fluffle/goirc/state/mock_tracker.go delete mode 100644 vendor/github.com/fluffle/goirc/state/nick.go delete mode 100644 vendor/github.com/fluffle/goirc/state/tracker.go (limited to 'vendor/github.com/fluffle') diff --git a/vendor/github.com/fluffle/goirc/LICENSE b/vendor/github.com/fluffle/goirc/LICENSE deleted file mode 100644 index e1b4d5c..0000000 --- a/vendor/github.com/fluffle/goirc/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009+ Alex Bramley. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fluffle/goirc/client/commands.go b/vendor/github.com/fluffle/goirc/client/commands.go deleted file mode 100644 index 101c7d3..0000000 --- a/vendor/github.com/fluffle/goirc/client/commands.go +++ /dev/null @@ -1,304 +0,0 @@ -package client - -import ( - "fmt" - "strings" -) - -const ( - REGISTER = "REGISTER" - CONNECTED = "CONNECTED" - DISCONNECTED = "DISCONNECTED" - ACTION = "ACTION" - AWAY = "AWAY" - CAP = "CAP" - CTCP = "CTCP" - CTCPREPLY = "CTCPREPLY" - ERROR = "ERROR" - INVITE = "INVITE" - JOIN = "JOIN" - KICK = "KICK" - MODE = "MODE" - NICK = "NICK" - NOTICE = "NOTICE" - OPER = "OPER" - PART = "PART" - PASS = "PASS" - PING = "PING" - PONG = "PONG" - PRIVMSG = "PRIVMSG" - QUIT = "QUIT" - TOPIC = "TOPIC" - USER = "USER" - VERSION = "VERSION" - VHOST = "VHOST" - WHO = "WHO" - WHOIS = "WHOIS" - defaultSplit = 450 -) - -// cutNewLines() pares down a string to the part before the first "\r" or "\n". -func cutNewLines(s string) string { - r := strings.SplitN(s, "\r", 2) - r = strings.SplitN(r[0], "\n", 2) - return r[0] -} - -// indexFragment looks for the last sentence split-point (defined as one of -// the punctuation characters .:;,!?"' followed by a space) in the string s -// and returns the index in the string after that split-point. If no split- -// point is found it returns the index after the last space in s, or -1. -func indexFragment(s string) int { - max := -1 - for _, sep := range []string{". ", ": ", "; ", ", ", "! ", "? ", "\" ", "' "} { - if idx := strings.LastIndex(s, sep); idx > max { - max = idx - } - } - if max > 0 { - return max + 2 - } - if idx := strings.LastIndex(s, " "); idx > 0 { - return idx + 1 - } - return -1 -} - -// splitMessage splits a message > splitLen chars at: -// 1. the end of the last sentence fragment before splitLen -// 2. the end of the last word before splitLen -// 3. splitLen itself -func splitMessage(msg string, splitLen int) (msgs []string) { - // This is quite short ;-) - if splitLen < 13 { - splitLen = defaultSplit - } - for len(msg) > splitLen { - idx := indexFragment(msg[:splitLen-3]) - if idx < 0 { - idx = splitLen - 3 - } - msgs = append(msgs, msg[:idx]+"...") - msg = msg[idx:] - } - return append(msgs, msg) -} - -// Raw sends a raw line to the server, should really only be used for -// debugging purposes but may well come in handy. -func (conn *Conn) Raw(rawline string) { - // Avoid command injection by enforcing one command per line. - conn.out <- cutNewLines(rawline) -} - -// Pass sends a PASS command to the server. -// PASS password -func (conn *Conn) Pass(password string) { conn.Raw(PASS + " " + password) } - -// Nick sends a NICK command to the server. -// NICK nick -func (conn *Conn) Nick(nick string) { conn.Raw(NICK + " " + nick) } - -// User sends a USER command to the server. -// USER ident 12 * :name -func (conn *Conn) User(ident, name string) { - conn.Raw(USER + " " + ident + " 12 * :" + name) -} - -// Join sends a JOIN command to the server with an optional key. -// JOIN channel [key] -func (conn *Conn) Join(channel string, key ...string) { - k := "" - if len(key) > 0 { - k = " " + key[0] - } - conn.Raw(JOIN + " " + channel + k) -} - -// Part sends a PART command to the server with an optional part message. -// PART channel [:message] -func (conn *Conn) Part(channel string, message ...string) { - msg := strings.Join(message, " ") - if msg != "" { - msg = " :" + msg - } - conn.Raw(PART + " " + channel + msg) -} - -// Kick sends a KICK command to remove a nick from a channel. -// KICK channel nick [:message] -func (conn *Conn) Kick(channel, nick string, message ...string) { - msg := strings.Join(message, " ") - if msg != "" { - msg = " :" + msg - } - conn.Raw(KICK + " " + channel + " " + nick + msg) -} - -// Quit sends a QUIT command to the server with an optional quit message. -// QUIT [:message] -func (conn *Conn) Quit(message ...string) { - msg := strings.Join(message, " ") - if msg == "" { - msg = conn.cfg.QuitMessage - } - conn.Raw(QUIT + " :" + msg) -} - -// Whois sends a WHOIS command to the server. -// WHOIS nick -func (conn *Conn) Whois(nick string) { conn.Raw(WHOIS + " " + nick) } - -// Who sends a WHO command to the server. -// WHO nick -func (conn *Conn) Who(nick string) { conn.Raw(WHO + " " + nick) } - -// Privmsg sends a PRIVMSG to the target nick or channel t. -// If msg is longer than Config.SplitLen characters, multiple PRIVMSGs -// will be sent to the target containing sequential parts of msg. -// PRIVMSG t :msg -func (conn *Conn) Privmsg(t, msg string) { - prefix := PRIVMSG + " " + t + " :" - for _, s := range splitMessage(msg, conn.cfg.SplitLen) { - conn.Raw(prefix + s) - } -} - -// Privmsgln is the variadic version of Privmsg that formats the message -// that is sent to the target nick or channel t using the -// fmt.Sprintln function. -// Note: Privmsgln doesn't add the '\n' character at the end of the message. -func (conn *Conn) Privmsgln(t string, a ...interface{}) { - msg := fmt.Sprintln(a...) - // trimming the new-line character added by the fmt.Sprintln function, - // since it's irrelevant. - msg = msg[:len(msg)-1] - conn.Privmsg(t, msg) -} - -// Privmsgf is the variadic version of Privmsg that formats the message -// that is sent to the target nick or channel t using the -// fmt.Sprintf function. -func (conn *Conn) Privmsgf(t, format string, a ...interface{}) { - msg := fmt.Sprintf(format, a...) - conn.Privmsg(t, msg) -} - -// Notice sends a NOTICE to the target nick or channel t. -// If msg is longer than Config.SplitLen characters, multiple NOTICEs -// will be sent to the target containing sequential parts of msg. -// NOTICE t :msg -func (conn *Conn) Notice(t, msg string) { - for _, s := range splitMessage(msg, conn.cfg.SplitLen) { - conn.Raw(NOTICE + " " + t + " :" + s) - } -} - -// Ctcp sends a (generic) CTCP message to the target nick -// or channel t, with an optional argument. -// PRIVMSG t :\001CTCP arg\001 -func (conn *Conn) Ctcp(t, ctcp string, arg ...string) { - // We need to split again here to ensure - for _, s := range splitMessage(strings.Join(arg, " "), conn.cfg.SplitLen) { - if s != "" { - s = " " + s - } - // Using Raw rather than PRIVMSG here to avoid double-split problems. - conn.Raw(PRIVMSG + " " + t + " :\001" + strings.ToUpper(ctcp) + s + "\001") - } -} - -// CtcpReply sends a (generic) CTCP reply to the target nick -// or channel t, with an optional argument. -// NOTICE t :\001CTCP arg\001 -func (conn *Conn) CtcpReply(t, ctcp string, arg ...string) { - for _, s := range splitMessage(strings.Join(arg, " "), conn.cfg.SplitLen) { - if s != "" { - s = " " + s - } - // Using Raw rather than NOTICE here to avoid double-split problems. - conn.Raw(NOTICE + " " + t + " :\001" + strings.ToUpper(ctcp) + s + "\001") - } -} - -// Version sends a CTCP "VERSION" to the target nick or channel t. -func (conn *Conn) Version(t string) { conn.Ctcp(t, VERSION) } - -// Action sends a CTCP "ACTION" to the target nick or channel t. -func (conn *Conn) Action(t, msg string) { conn.Ctcp(t, ACTION, msg) } - -// Topic() sends a TOPIC command for a channel. -// If no topic is provided this requests that a 332 response is sent by the -// server for that channel, which can then be handled to retrieve the current -// channel topic. If a topic is provided the channel's topic will be set. -// TOPIC channel -// TOPIC channel :topic -func (conn *Conn) Topic(channel string, topic ...string) { - t := strings.Join(topic, " ") - if t != "" { - t = " :" + t - } - conn.Raw(TOPIC + " " + channel + t) -} - -// Mode sends a MODE command for a target nick or channel t. -// If no mode strings are provided this requests that a 324 response is sent -// by the server for the target. Otherwise the mode strings are concatenated -// with spaces and sent to the server. This allows e.g. -// conn.Mode("#channel", "+nsk", "mykey") -// -// MODE t -// MODE t modestring -func (conn *Conn) Mode(t string, modestring ...string) { - mode := strings.Join(modestring, " ") - if mode != "" { - mode = " " + mode - } - conn.Raw(MODE + " " + t + mode) -} - -// Away sends an AWAY command to the server. -// If a message is provided it sets the client's away status with that message, -// otherwise it resets the client's away status. -// AWAY -// AWAY :message -func (conn *Conn) Away(message ...string) { - msg := strings.Join(message, " ") - if msg != "" { - msg = " :" + msg - } - conn.Raw(AWAY + msg) -} - -// Invite sends an INVITE command to the server. -// INVITE nick channel -func (conn *Conn) Invite(nick, channel string) { - conn.Raw(INVITE + " " + nick + " " + channel) -} - -// Oper sends an OPER command to the server. -// OPER user pass -func (conn *Conn) Oper(user, pass string) { conn.Raw(OPER + " " + user + " " + pass) } - -// VHost sends a VHOST command to the server. -// VHOST user pass -func (conn *Conn) VHost(user, pass string) { conn.Raw(VHOST + " " + user + " " + pass) } - -// Ping sends a PING command to the server, which should PONG. -// PING :message -func (conn *Conn) Ping(message string) { conn.Raw(PING + " :" + message) } - -// Pong sends a PONG command to the server. -// PONG :message -func (conn *Conn) Pong(message string) { conn.Raw(PONG + " :" + message) } - -// Cap sends a CAP command to the server. -// CAP subcommand -// CAP subcommand :message -func (conn *Conn) Cap(subcommmand string, capabilities ...string) { - if len(capabilities) == 0 { - conn.Raw(CAP + " " + subcommmand) - } else { - conn.Raw(CAP + " " + subcommmand + " :" + strings.Join(capabilities, " ")) - } -} diff --git a/vendor/github.com/fluffle/goirc/client/connection.go b/vendor/github.com/fluffle/goirc/client/connection.go deleted file mode 100644 index 12d0e59..0000000 --- a/vendor/github.com/fluffle/goirc/client/connection.go +++ /dev/null @@ -1,587 +0,0 @@ -package client - -import ( - "bufio" - "crypto/tls" - "fmt" - "io" - "net" - "net/url" - "strings" - "sync" - "time" - - "github.com/fluffle/goirc/logging" - "github.com/fluffle/goirc/state" - "golang.org/x/net/proxy" -) - -// Conn encapsulates a connection to a single IRC server. Create -// one with Client or SimpleClient. -type Conn struct { - // For preventing races on (dis)connect. - mu sync.RWMutex - - // Contains parameters that people can tweak to change client behaviour. - cfg *Config - - // Handlers - intHandlers *hSet - fgHandlers *hSet - bgHandlers *hSet - - // State tracker for nicks and channels - st state.Tracker - stRemovers []Remover - - // I/O stuff to server - dialer *net.Dialer - proxyDialer proxy.Dialer - sock net.Conn - io *bufio.ReadWriter - in chan *Line - out chan string - connected bool - - // Control channel and WaitGroup for goroutines - die chan struct{} - wg sync.WaitGroup - - // Internal counters for flood protection - badness time.Duration - lastsent time.Time -} - -// Config contains options that can be passed to Client to change the -// behaviour of the library during use. It is recommended that NewConfig -// is used to create this struct rather than instantiating one directly. -// Passing a Config with no Nick in the Me field to Client will result -// in unflattering consequences. -type Config struct { - // Set this to provide the Nick, Ident and Name for the client to use. - // It is recommended to call Conn.Me to get up-to-date information - // about the current state of the client's IRC nick after connecting. - Me *state.Nick - - // Hostname to connect to and optional connect password. - // Changing these after connection will have no effect until the - // client reconnects. - Server, Pass string - - // Are we connecting via SSL? Do we care about certificate validity? - // Changing these after connection will have no effect until the - // client reconnects. - SSL bool - SSLConfig *tls.Config - - // To connect via proxy set the proxy url here. - // Changing these after connection will have no effect until the - // client reconnects. - Proxy string - - // Local address to bind to when connecting to the server. - LocalAddr string - - // To attempt RFC6555 parallel IPv4 and IPv6 connections if both - // address families are returned for a hostname, set this to true. - // Passed through to https://golang.org/pkg/net/#Dialer - DualStack bool - - // Replaceable function to customise the 433 handler's new nick. - // By default an underscore "_" is appended to the current nick. - NewNick func(string) string - - // Client->server ping frequency, in seconds. Defaults to 3m. - // Set to 0 to disable client-side pings. - PingFreq time.Duration - - // The duration before a connection timeout is triggered. Defaults to 1m. - // Set to 0 to wait indefinitely. - Timeout time.Duration - - // Set this to true to disable flood protection and false to re-enable. - Flood bool - - // Sent as the reply to a CTCP VERSION message. - Version string - - // Sent as the default QUIT message if Quit is called with no args. - QuitMessage string - - // Configurable panic recovery for all handlers. - // Defaults to logging an error, see LogPanic. - Recover func(*Conn, *Line) - - // Split PRIVMSGs, NOTICEs and CTCPs longer than SplitLen characters - // over multiple lines. Default to 450 if not set. - SplitLen int -} - -// NewConfig creates a Config struct containing sensible defaults. -// It takes one required argument: the nick to use for the client. -// Subsequent string arguments set the client's ident and "real" -// name, but these are optional. -func NewConfig(nick string, args ...string) *Config { - cfg := &Config{ - Me: &state.Nick{Nick: nick}, - PingFreq: 3 * time.Minute, - NewNick: func(s string) string { return s + "_" }, - Recover: (*Conn).LogPanic, // in dispatch.go - SplitLen: defaultSplit, - Timeout: 60 * time.Second, - } - cfg.Me.Ident = "goirc" - if len(args) > 0 && args[0] != "" { - cfg.Me.Ident = args[0] - } - cfg.Me.Name = "Powered by GoIRC" - if len(args) > 1 && args[1] != "" { - cfg.Me.Name = args[1] - } - cfg.Version = "Powered by GoIRC" - cfg.QuitMessage = "GoBye!" - return cfg -} - -// SimpleClient creates a new Conn, passing its arguments to NewConfig. -// If you don't need to change any client options and just want to get -// started quickly, this is a convenient shortcut. -func SimpleClient(nick string, args ...string) *Conn { - conn := Client(NewConfig(nick, args...)) - return conn -} - -// Client takes a Config struct and returns a new Conn ready to have -// handlers added and connect to a server. -func Client(cfg *Config) *Conn { - if cfg == nil { - cfg = NewConfig("__idiot__") - } - if cfg.Me == nil || cfg.Me.Nick == "" || cfg.Me.Ident == "" { - cfg.Me = &state.Nick{Nick: "__idiot__"} - cfg.Me.Ident = "goirc" - cfg.Me.Name = "Powered by GoIRC" - } - - dialer := new(net.Dialer) - dialer.Timeout = cfg.Timeout - dialer.DualStack = cfg.DualStack - if cfg.LocalAddr != "" { - if !hasPort(cfg.LocalAddr) { - cfg.LocalAddr += ":0" - } - - local, err := net.ResolveTCPAddr("tcp", cfg.LocalAddr) - if err == nil { - dialer.LocalAddr = local - } else { - logging.Error("irc.Client(): Cannot resolve local address %s: %s", cfg.LocalAddr, err) - } - } - - conn := &Conn{ - cfg: cfg, - dialer: dialer, - intHandlers: handlerSet(), - fgHandlers: handlerSet(), - bgHandlers: handlerSet(), - stRemovers: make([]Remover, 0, len(stHandlers)), - lastsent: time.Now(), - } - conn.addIntHandlers() - return conn -} - -// Connected returns true if the client is successfully connected to -// an IRC server. It becomes true when the TCP connection is established, -// and false again when the connection is closed. -func (conn *Conn) Connected() bool { - conn.mu.RLock() - defer conn.mu.RUnlock() - return conn.connected -} - -// Config returns a pointer to the Config struct used by the client. -// Many of the elements of Config may be changed at any point to -// affect client behaviour. To disable flood protection temporarily, -// for example, a handler could do: -// -// conn.Config().Flood = true -// // Send many lines to the IRC server, risking "excess flood" -// conn.Config().Flood = false -// -func (conn *Conn) Config() *Config { - return conn.cfg -} - -// Me returns a state.Nick that reflects the client's IRC nick at the -// time it is called. If state tracking is enabled, this comes from -// the tracker, otherwise it is equivalent to conn.cfg.Me. -func (conn *Conn) Me() *state.Nick { - if conn.st != nil { - conn.cfg.Me = conn.st.Me() - } - return conn.cfg.Me -} - -// StateTracker returns the state tracker being used by the client, -// if tracking is enabled, and nil otherwise. -func (conn *Conn) StateTracker() state.Tracker { - return conn.st -} - -// EnableStateTracking causes the client to track information about -// all channels it is joined to, and all the nicks in those channels. -// This can be rather handy for a number of bot-writing tasks. See -// the state package for more details. -// -// NOTE: Calling this while connected to an IRC server may cause the -// state tracker to become very confused all over STDERR if logging -// is enabled. State tracking should enabled before connecting or -// at a pinch while the client is not joined to any channels. -func (conn *Conn) EnableStateTracking() { - conn.mu.Lock() - defer conn.mu.Unlock() - if conn.st == nil { - n := conn.cfg.Me - conn.st = state.NewTracker(n.Nick) - conn.st.NickInfo(n.Nick, n.Ident, n.Host, n.Name) - conn.cfg.Me = conn.st.Me() - conn.addSTHandlers() - } -} - -// DisableStateTracking causes the client to stop tracking information -// about the channels and nicks it knows of. It will also wipe current -// state from the state tracker. -func (conn *Conn) DisableStateTracking() { - conn.mu.Lock() - defer conn.mu.Unlock() - if conn.st != nil { - conn.cfg.Me = conn.st.Me() - conn.delSTHandlers() - conn.st.Wipe() - conn.st = nil - } -} - -// Per-connection state initialisation. -func (conn *Conn) initialise() { - conn.io = nil - conn.sock = nil - conn.in = make(chan *Line, 32) - conn.out = make(chan string, 32) - conn.die = make(chan struct{}) - if conn.st != nil { - conn.st.Wipe() - } -} - -// ConnectTo connects the IRC client to "host[:port]", which should be either -// a hostname or an IP address, with an optional port. It sets the client's -// Config.Server to host, Config.Pass to pass if one is provided, and then -// calls Connect. -func (conn *Conn) ConnectTo(host string, pass ...string) error { - conn.cfg.Server = host - if len(pass) > 0 { - conn.cfg.Pass = pass[0] - } - return conn.Connect() -} - -// Connect connects the IRC client to the server configured in Config.Server. -// To enable explicit SSL on the connection to the IRC server, set Config.SSL -// to true before calling Connect(). The port will default to 6697 if SSL is -// enabled, and 6667 otherwise. -// To enable connecting via a proxy server, set Config.Proxy to the proxy URL -// (example socks5://localhost:9000) before calling Connect(). -// -// Upon successful connection, Connected will return true and a REGISTER event -// will be fired. This is mostly for internal use; it is suggested that a -// handler for the CONNECTED event is used to perform any initial client work -// like joining channels and sending messages. -func (conn *Conn) Connect() error { - // We don't want to hold conn.mu while firing the REGISTER event, - // and it's much easier and less error prone to defer the unlock, - // so the connect mechanics have been delegated to internalConnect. - err := conn.internalConnect() - if err == nil { - conn.dispatch(&Line{Cmd: REGISTER, Time: time.Now()}) - } - return err -} - -// internalConnect handles the work of actually connecting to the server. -func (conn *Conn) internalConnect() error { - conn.mu.Lock() - defer conn.mu.Unlock() - conn.initialise() - - if conn.cfg.Server == "" { - return fmt.Errorf("irc.Connect(): cfg.Server must be non-empty") - } - if conn.connected { - return fmt.Errorf("irc.Connect(): Cannot connect to %s, already connected.", conn.cfg.Server) - } - - if !hasPort(conn.cfg.Server) { - if conn.cfg.SSL { - conn.cfg.Server = net.JoinHostPort(conn.cfg.Server, "6697") - } else { - conn.cfg.Server = net.JoinHostPort(conn.cfg.Server, "6667") - } - } - - if conn.cfg.Proxy != "" { - proxyURL, err := url.Parse(conn.cfg.Proxy) - if err != nil { - return err - } - conn.proxyDialer, err = proxy.FromURL(proxyURL, conn.dialer) - if err != nil { - return err - } - - logging.Info("irc.Connect(): Connecting to %s.", conn.cfg.Server) - if s, err := conn.proxyDialer.Dial("tcp", conn.cfg.Server); err == nil { - conn.sock = s - } else { - return err - } - } else { - logging.Info("irc.Connect(): Connecting to %s.", conn.cfg.Server) - if s, err := conn.dialer.Dial("tcp", conn.cfg.Server); err == nil { - conn.sock = s - } else { - return err - } - } - - if conn.cfg.SSL { - logging.Info("irc.Connect(): Performing SSL handshake.") - s := tls.Client(conn.sock, conn.cfg.SSLConfig) - if err := s.Handshake(); err != nil { - return err - } - conn.sock = s - } - - conn.postConnect(true) - conn.connected = true - return nil -} - -// postConnect performs post-connection setup, for ease of testing. -func (conn *Conn) postConnect(start bool) { - conn.io = bufio.NewReadWriter( - bufio.NewReader(conn.sock), - bufio.NewWriter(conn.sock)) - if start { - conn.wg.Add(3) - go conn.send() - go conn.recv() - go conn.runLoop() - if conn.cfg.PingFreq > 0 { - conn.wg.Add(1) - go conn.ping() - } - } -} - -// hasPort returns true if the string hostname has a :port suffix. -// It was copied from net/http for great justice. -func hasPort(s string) bool { - return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") -} - -// send is started as a goroutine after a connection is established. -// It shuttles data from the output channel to write(), and is killed -// when Conn.die is closed. -func (conn *Conn) send() { - for { - select { - case line := <-conn.out: - if err := conn.write(line); err != nil { - logging.Error("irc.send(): %s", err.Error()) - // We can't defer this, because Close() waits for it. - conn.wg.Done() - conn.Close() - return - } - case <-conn.die: - // control channel closed, bail out - conn.wg.Done() - return - } - } -} - -// recv is started as a goroutine after a connection is established. -// It receives "\r\n" terminated lines from the server, parses them into -// Lines, and sends them to the input channel. -func (conn *Conn) recv() { - for { - s, err := conn.io.ReadString('\n') - if err != nil { - if err != io.EOF { - logging.Error("irc.recv(): %s", err.Error()) - } - // We can't defer this, because Close() waits for it. - conn.wg.Done() - conn.Close() - return - } - s = strings.Trim(s, "\r\n") - logging.Debug("<- %s", s) - - if line := ParseLine(s); line != nil { - line.Time = time.Now() - conn.in <- line - } else { - logging.Warn("irc.recv(): problems parsing line:\n %s", s) - } - } -} - -// ping is started as a goroutine after a connection is established, as -// long as Config.PingFreq >0. It pings the server every PingFreq seconds. -func (conn *Conn) ping() { - defer conn.wg.Done() - tick := time.NewTicker(conn.cfg.PingFreq) - for { - select { - case <-tick.C: - conn.Ping(fmt.Sprintf("%d", time.Now().UnixNano())) - case <-conn.die: - // control channel closed, bail out - tick.Stop() - return - } - } -} - -// runLoop is started as a goroutine after a connection is established. -// It pulls Lines from the input channel and dispatches them to any -// handlers that have been registered for that IRC verb. -func (conn *Conn) runLoop() { - defer conn.wg.Done() - for { - select { - case line := <-conn.in: - conn.dispatch(line) - case <-conn.die: - // control channel closed, bail out - return - } - } -} - -// write writes a \r\n terminated line of output to the connected server, -// using Hybrid's algorithm to rate limit if conn.cfg.Flood is false. -func (conn *Conn) write(line string) error { - if !conn.cfg.Flood { - if t := conn.rateLimit(len(line)); t != 0 { - // sleep for the current line's time value before sending it - logging.Info("irc.rateLimit(): Flood! Sleeping for %.2f secs.", - t.Seconds()) - <-time.After(t) - } - } - - if _, err := conn.io.WriteString(line + "\r\n"); err != nil { - return err - } - if err := conn.io.Flush(); err != nil { - return err - } - if strings.HasPrefix(line, "PASS") { - line = "PASS **************" - } - logging.Debug("-> %s", line) - return nil -} - -// rateLimit implements Hybrid's flood control algorithm for outgoing lines. -func (conn *Conn) rateLimit(chars int) time.Duration { - // Hybrid's algorithm allows for 2 seconds per line and an additional - // 1/120 of a second per character on that line. - linetime := 2*time.Second + time.Duration(chars)*time.Second/120 - elapsed := time.Now().Sub(conn.lastsent) - if conn.badness += linetime - elapsed; conn.badness < 0 { - // negative badness times are badness... - conn.badness = 0 - } - conn.lastsent = time.Now() - // If we've sent more than 10 second's worth of lines according to the - // calculation above, then we're at risk of "Excess Flood". - if conn.badness > 10*time.Second { - return linetime - } - return 0 -} - -// Close tears down all connection-related state. It is called when either -// the sending or receiving goroutines encounter an error. -// It may also be used to forcibly shut down the connection to the server. -func (conn *Conn) Close() error { - // Guard against double-call of Close() if we get an error in send() - // as calling sock.Close() will cause recv() to receive EOF in readstring() - conn.mu.Lock() - if !conn.connected { - conn.mu.Unlock() - return nil - } - logging.Info("irc.Close(): Disconnected from server.") - conn.connected = false - err := conn.sock.Close() - close(conn.die) - // Drain both in and out channels to avoid a deadlock if the buffers - // have filled. See TestSendDeadlockOnFullBuffer in connection_test.go. - conn.drainIn() - conn.drainOut() - conn.wg.Wait() - conn.mu.Unlock() - // Dispatch after closing connection but before reinit - // so event handlers can still access state information. - conn.dispatch(&Line{Cmd: DISCONNECTED, Time: time.Now()}) - return err -} - -// drainIn sends all data buffered in conn.in to /dev/null. -func (conn *Conn) drainIn() { - for { - select { - case <-conn.in: - default: - return - } - } -} - -// drainOut does the same for conn.out. Generics! -func (conn *Conn) drainOut() { - for { - select { - case <-conn.out: - default: - return - } - } -} - -// Dumps a load of information about the current state of the connection to a -// string for debugging state tracking and other such things. -func (conn *Conn) String() string { - str := "GoIRC Connection\n" - str += "----------------\n\n" - if conn.Connected() { - str += "Connected to " + conn.cfg.Server + "\n\n" - } else { - str += "Not currently connected!\n\n" - } - str += conn.Me().String() + "\n" - if conn.st != nil { - str += conn.st.String() + "\n" - } - return str -} diff --git a/vendor/github.com/fluffle/goirc/client/dispatch.go b/vendor/github.com/fluffle/goirc/client/dispatch.go deleted file mode 100644 index 4a5deb9..0000000 --- a/vendor/github.com/fluffle/goirc/client/dispatch.go +++ /dev/null @@ -1,202 +0,0 @@ -package client - -import ( - "runtime" - "strings" - "sync" - - "github.com/fluffle/goirc/logging" -) - -// Handlers are triggered on incoming Lines from the server, with the handler -// "name" being equivalent to Line.Cmd. Read the RFCs for details on what -// replies could come from the server. They'll generally be things like -// "PRIVMSG", "JOIN", etc. but all the numeric replies are left as ascii -// strings of digits like "332" (mainly because I really didn't feel like -// putting massive constant tables in). -// -// Foreground handlers have a guarantee of protocol consistency: all the -// handlers for one event will have finished before the handlers for the -// next start processing. They are run in parallel but block the event -// loop, so care should be taken to ensure these handlers are quick :-) -// -// Background handlers are run in parallel and do not block the event loop. -// This is useful for things that may need to do significant work. -type Handler interface { - Handle(*Conn, *Line) -} - -// Removers allow for a handler that has been previously added to the client -// to be removed. -type Remover interface { - Remove() -} - -// HandlerFunc allows a bare function with this signature to implement the -// Handler interface. It is used by Conn.HandleFunc. -type HandlerFunc func(*Conn, *Line) - -func (hf HandlerFunc) Handle(conn *Conn, line *Line) { - hf(conn, line) -} - -// Handlers are organised using a map of linked-lists, with each map -// key representing an IRC verb or numeric, and the linked list values -// being handlers that are executed in parallel when a Line from the -// server with that verb or numeric arrives. -type hSet struct { - set map[string]*hList - sync.RWMutex -} - -type hList struct { - start, end *hNode -} - -// Storing the forward and backward links in the node allows O(1) removal. -// This probably isn't strictly necessary but I think it's kinda nice. -type hNode struct { - next, prev *hNode - set *hSet - event string - handler Handler -} - -// A hNode implements both Handler (with configurable panic recovery)... -func (hn *hNode) Handle(conn *Conn, line *Line) { - defer conn.cfg.Recover(conn, line) - hn.handler.Handle(conn, line) -} - -// ... and Remover. -func (hn *hNode) Remove() { - hn.set.remove(hn) -} - -func handlerSet() *hSet { - return &hSet{set: make(map[string]*hList)} -} - -// When a new Handler is added for an event, it is wrapped in a hNode and -// returned as a Remover so the caller can remove it at a later time. -func (hs *hSet) add(ev string, h Handler) Remover { - hs.Lock() - defer hs.Unlock() - ev = strings.ToLower(ev) - l, ok := hs.set[ev] - if !ok { - l = &hList{} - } - hn := &hNode{ - set: hs, - event: ev, - handler: h, - } - if !ok { - l.start = hn - } else { - hn.prev = l.end - l.end.next = hn - } - l.end = hn - hs.set[ev] = l - return hn -} - -func (hs *hSet) remove(hn *hNode) { - hs.Lock() - defer hs.Unlock() - l, ok := hs.set[hn.event] - if !ok { - logging.Error("Removing node for unknown event '%s'", hn.event) - return - } - if hn.next == nil { - l.end = hn.prev - } else { - hn.next.prev = hn.prev - } - if hn.prev == nil { - l.start = hn.next - } else { - hn.prev.next = hn.next - } - hn.next = nil - hn.prev = nil - hn.set = nil - if l.start == nil || l.end == nil { - delete(hs.set, hn.event) - } -} - -func (hs *hSet) getHandlers(ev string) []*hNode { - hs.RLock() - defer hs.RUnlock() - list, ok := hs.set[ev] - if !ok { - return nil - } - // Copy current list of handlers to a temporary slice under the lock. - handlers := make([]*hNode, 0) - for hn := list.start; hn != nil; hn = hn.next { - handlers = append(handlers, hn) - } - return handlers -} - -func (hs *hSet) dispatch(conn *Conn, line *Line) { - ev := strings.ToLower(line.Cmd) - wg := &sync.WaitGroup{} - for _, hn := range hs.getHandlers(ev) { - wg.Add(1) - go func(hn *hNode) { - hn.Handle(conn, line.Copy()) - wg.Done() - }(hn) - } - wg.Wait() -} - -// Handle adds the provided handler to the foreground set for the named event. -// It will return a Remover that allows that handler to be removed again. -func (conn *Conn) Handle(name string, h Handler) Remover { - return conn.fgHandlers.add(name, h) -} - -// HandleBG adds the provided handler to the background set for the named -// event. It may go away in the future. -// It will return a Remover that allows that handler to be removed again. -func (conn *Conn) HandleBG(name string, h Handler) Remover { - return conn.bgHandlers.add(name, h) -} - -func (conn *Conn) handle(name string, h Handler) Remover { - return conn.intHandlers.add(name, h) -} - -// HandleFunc adds the provided function as a handler in the foreground set -// for the named event. -// It will return a Remover that allows that handler to be removed again. -func (conn *Conn) HandleFunc(name string, hf HandlerFunc) Remover { - return conn.Handle(name, hf) -} - -func (conn *Conn) dispatch(line *Line) { - // We run the internal handlers first, including all state tracking ones. - // This ensures that user-supplied handlers that use the tracker have a - // consistent view of the connection state in handlers that mutate it. - conn.intHandlers.dispatch(conn, line) - go conn.bgHandlers.dispatch(conn, line) - conn.fgHandlers.dispatch(conn, line) -} - -// LogPanic is used as the default panic catcher for the client. If, like me, -// you are not good with computer, and you'd prefer your bot not to vanish into -// the ether whenever you make unfortunate programming mistakes, you may find -// this useful: it will recover panics from handler code and log the errors. -func (conn *Conn) LogPanic(line *Line) { - if err := recover(); err != nil { - _, f, l, _ := runtime.Caller(2) - logging.Error("%s:%d: panic: %v", f, l, err) - } -} diff --git a/vendor/github.com/fluffle/goirc/client/doc.go b/vendor/github.com/fluffle/goirc/client/doc.go deleted file mode 100644 index 08a79dd..0000000 --- a/vendor/github.com/fluffle/goirc/client/doc.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package client implements an IRC client. It handles protocol basics -// such as initial connection and responding to server PINGs, and has -// optional state tracking support which will keep tabs on every nick -// present in the same channels as the client. Other features include -// SSL support, automatic splitting of long lines, and panic recovery -// for handlers. -// -// Incoming IRC messages are parsed into client.Line structs and trigger -// events based on the IRC verb (e.g. PRIVMSG) of the message. Handlers -// for these events conform to the client.Handler interface; a HandlerFunc -// type to wrap bare functions is provided a-la the net/http package. -// -// Creating a client, adding a handler and connecting to a server looks -// soemthing like this, for the simple case: -// -// // Create a new client, which will connect with the nick "myNick" -// irc := client.SimpleClient("myNick") -// -// // Add a handler that waits for the "disconnected" event and -// // closes a channel to signal everything is done. -// disconnected := make(chan struct{}) -// c.HandleFunc("disconnected", func(c *client.Conn, l *client.Line) { -// close(disconnected) -// }) -// -// // Connect to an IRC server. -// if err := c.ConnectTo("irc.freenode.net"); err != nil { -// log.Fatalf("Connection error: %v\n", err) -// } -// -// // Wait for disconnection. -// <-disconnected -// -package client diff --git a/vendor/github.com/fluffle/goirc/client/handlers.go b/vendor/github.com/fluffle/goirc/client/handlers.go deleted file mode 100644 index b538579..0000000 --- a/vendor/github.com/fluffle/goirc/client/handlers.go +++ /dev/null @@ -1,105 +0,0 @@ -package client - -// this file contains the basic set of event handlers -// to manage tracking an irc connection etc. - -import ( - "strings" - "time" -) - -// sets up the internal event handlers to do essential IRC protocol things -var intHandlers = map[string]HandlerFunc{ - REGISTER: (*Conn).h_REGISTER, - "001": (*Conn).h_001, - "433": (*Conn).h_433, - CTCP: (*Conn).h_CTCP, - NICK: (*Conn).h_NICK, - PING: (*Conn).h_PING, -} - -func (conn *Conn) addIntHandlers() { - for n, h := range intHandlers { - // internal handlers are essential for the IRC client - // to function, so we don't save their Removers here - conn.handle(n, h) - } -} - -// Basic ping/pong handler -func (conn *Conn) h_PING(line *Line) { - conn.Pong(line.Args[0]) -} - -// Handler for initial registration with server once tcp connection is made. -func (conn *Conn) h_REGISTER(line *Line) { - if conn.cfg.Pass != "" { - conn.Pass(conn.cfg.Pass) - } - conn.Nick(conn.cfg.Me.Nick) - conn.User(conn.cfg.Me.Ident, conn.cfg.Me.Name) -} - -// Handler to trigger a CONNECTED event on receipt of numeric 001 -func (conn *Conn) h_001(line *Line) { - // we're connected! - conn.dispatch(&Line{Cmd: CONNECTED, Time: time.Now()}) - // and we're being given our hostname (from the server's perspective) - t := line.Args[len(line.Args)-1] - if idx := strings.LastIndex(t, " "); idx != -1 { - t = t[idx+1:] - if idx = strings.Index(t, "@"); idx != -1 { - if conn.st != nil { - me := conn.Me() - conn.st.NickInfo(me.Nick, me.Ident, t[idx+1:], me.Name) - } else { - conn.cfg.Me.Host = t[idx+1:] - } - } - } -} - -// XXX: do we need 005 protocol support message parsing here? -// probably in the future, but I can't quite be arsed yet. -/* - :irc.pl0rt.org 005 GoTest CMDS=KNOCK,MAP,DCCALLOW,USERIP UHNAMES NAMESX SAFELIST HCN MAXCHANNELS=20 CHANLIMIT=#:20 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 :are supported by this server - :irc.pl0rt.org 005 GoTest MAXTARGETS=20 WALLCHOPS WATCH=128 WATCHOPTS=A SILENCE=15 MODES=12 CHANTYPES=# PREFIX=(qaohv)~&@%+ CHANMODES=beI,kfL,lj,psmntirRcOAQKVCuzNSMT NETWORK=bb101.net CASEMAPPING=ascii EXTBAN=~,cqnr ELIST=MNUCT :are supported by this server - :irc.pl0rt.org 005 GoTest STATUSMSG=~&@%+ EXCEPTS INVEX :are supported by this server -*/ - -// Handler to deal with "433 :Nickname already in use" -func (conn *Conn) h_433(line *Line) { - // Args[1] is the new nick we were attempting to acquire - me := conn.Me() - neu := conn.cfg.NewNick(line.Args[1]) - conn.Nick(neu) - if !line.argslen(1) { - return - } - // if this is happening before we're properly connected (i.e. the nick - // we sent in the initial NICK command is in use) we will not receive - // a NICK message to confirm our change of nick, so ReNick here... - if line.Args[1] == me.Nick { - if conn.st != nil { - conn.cfg.Me = conn.st.ReNick(me.Nick, neu) - } else { - conn.cfg.Me.Nick = neu - } - } -} - -// Handle VERSION requests and CTCP PING -func (conn *Conn) h_CTCP(line *Line) { - if line.Args[0] == VERSION { - conn.CtcpReply(line.Nick, VERSION, conn.cfg.Version) - } else if line.Args[0] == PING && line.argslen(2) { - conn.CtcpReply(line.Nick, PING, line.Args[2]) - } -} - -// Handle updating our own NICK if we're not using the state tracker -func (conn *Conn) h_NICK(line *Line) { - if conn.st == nil && line.Nick == conn.cfg.Me.Nick { - conn.cfg.Me.Nick = line.Args[0] - } -} 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 -} diff --git a/vendor/github.com/fluffle/goirc/client/state_handlers.go b/vendor/github.com/fluffle/goirc/client/state_handlers.go deleted file mode 100644 index 847679c..0000000 --- a/vendor/github.com/fluffle/goirc/client/state_handlers.go +++ /dev/null @@ -1,262 +0,0 @@ -package client - -// this file contains the extra set of event handlers -// to manage tracking state for an IRC connection - -import ( - "strings" - - "github.com/fluffle/goirc/logging" -) - -var stHandlers = map[string]HandlerFunc{ - "JOIN": (*Conn).h_JOIN, - "KICK": (*Conn).h_KICK, - "MODE": (*Conn).h_MODE, - "NICK": (*Conn).h_STNICK, - "PART": (*Conn).h_PART, - "QUIT": (*Conn).h_QUIT, - "TOPIC": (*Conn).h_TOPIC, - "311": (*Conn).h_311, - "324": (*Conn).h_324, - "332": (*Conn).h_332, - "352": (*Conn).h_352, - "353": (*Conn).h_353, - "671": (*Conn).h_671, -} - -func (conn *Conn) addSTHandlers() { - for n, h := range stHandlers { - conn.stRemovers = append(conn.stRemovers, conn.handle(n, h)) - } -} - -func (conn *Conn) delSTHandlers() { - for _, h := range conn.stRemovers { - h.Remove() - } - conn.stRemovers = conn.stRemovers[:0] -} - -// Handle NICK messages that need to update the state tracker -func (conn *Conn) h_STNICK(line *Line) { - // all nicks should be handled the same way, our own included - conn.st.ReNick(line.Nick, line.Args[0]) -} - -// Handle JOINs to channels to maintain state -func (conn *Conn) h_JOIN(line *Line) { - ch := conn.st.GetChannel(line.Args[0]) - nk := conn.st.GetNick(line.Nick) - if ch == nil { - // first we've seen of this channel, so should be us joining it - // NOTE this will also take care of nk == nil && ch == nil - if !conn.Me().Equals(nk) { - logging.Warn("irc.JOIN(): JOIN to unknown channel %s received "+ - "from (non-me) nick %s", line.Args[0], line.Nick) - return - } - conn.st.NewChannel(line.Args[0]) - // since we don't know much about this channel, ask server for info - // we get the channel users automatically in 353 and the channel - // topic in 332 on join, so we just need to get the modes - conn.Mode(line.Args[0]) - // sending a WHO for the channel is MUCH more efficient than - // triggering a WHOIS on every nick from the 353 handler - conn.Who(line.Args[0]) - } - if nk == nil { - // this is the first we've seen of this nick - conn.st.NewNick(line.Nick) - conn.st.NickInfo(line.Nick, line.Ident, line.Host, "") - // since we don't know much about this nick, ask server for info - conn.Who(line.Nick) - } - // this takes care of both nick and channel linking \o/ - conn.st.Associate(line.Args[0], line.Nick) -} - -// Handle PARTs from channels to maintain state -func (conn *Conn) h_PART(line *Line) { - conn.st.Dissociate(line.Args[0], line.Nick) -} - -// Handle KICKs from channels to maintain state -func (conn *Conn) h_KICK(line *Line) { - if !line.argslen(1) { - return - } - // XXX: this won't handle autorejoining channels on KICK - // it's trivial to do this in a seperate handler... - conn.st.Dissociate(line.Args[0], line.Args[1]) -} - -// Handle other people's QUITs -func (conn *Conn) h_QUIT(line *Line) { - conn.st.DelNick(line.Nick) -} - -// Handle MODE changes for channels we know about (and our nick personally) -func (conn *Conn) h_MODE(line *Line) { - if !line.argslen(1) { - return - } - if ch := conn.st.GetChannel(line.Args[0]); ch != nil { - // channel modes first - conn.st.ChannelModes(line.Args[0], line.Args[1], line.Args[2:]...) - } else if nk := conn.st.GetNick(line.Args[0]); nk != nil { - // nick mode change, should be us - if !conn.Me().Equals(nk) { - logging.Warn("irc.MODE(): recieved MODE %s for (non-me) nick %s", - line.Args[1], line.Args[0]) - return - } - conn.st.NickModes(line.Args[0], line.Args[1]) - } else { - logging.Warn("irc.MODE(): not sure what to do with MODE %s", - strings.Join(line.Args, " ")) - } -} - -// Handle TOPIC changes for channels -func (conn *Conn) h_TOPIC(line *Line) { - if !line.argslen(1) { - return - } - if ch := conn.st.GetChannel(line.Args[0]); ch != nil { - conn.st.Topic(line.Args[0], line.Args[1]) - } else { - logging.Warn("irc.TOPIC(): topic change on unknown channel %s", - line.Args[0]) - } -} - -// Handle 311 whois reply -func (conn *Conn) h_311(line *Line) { - if !line.argslen(5) { - return - } - if nk := conn.st.GetNick(line.Args[1]); (nk != nil) && !conn.Me().Equals(nk) { - conn.st.NickInfo(line.Args[1], line.Args[2], line.Args[3], line.Args[5]) - } else { - logging.Warn("irc.311(): received WHOIS info for unknown nick %s", - line.Args[1]) - } -} - -// Handle 324 mode reply -func (conn *Conn) h_324(line *Line) { - if !line.argslen(2) { - return - } - if ch := conn.st.GetChannel(line.Args[1]); ch != nil { - conn.st.ChannelModes(line.Args[1], line.Args[2], line.Args[3:]...) - } else { - logging.Warn("irc.324(): received MODE settings for unknown channel %s", - line.Args[1]) - } -} - -// Handle 332 topic reply on join to channel -func (conn *Conn) h_332(line *Line) { - if !line.argslen(2) { - return - } - if ch := conn.st.GetChannel(line.Args[1]); ch != nil { - conn.st.Topic(line.Args[1], line.Args[2]) - } else { - logging.Warn("irc.332(): received TOPIC value for unknown channel %s", - line.Args[1]) - } -} - -// Handle 352 who reply -func (conn *Conn) h_352(line *Line) { - if !line.argslen(5) { - return - } - nk := conn.st.GetNick(line.Args[5]) - if nk == nil { - logging.Warn("irc.352(): received WHO reply for unknown nick %s", - line.Args[5]) - return - } - if conn.Me().Equals(nk) { - return - } - // XXX: do we care about the actual server the nick is on? - // or the hop count to this server? - // last arg contains " " - a := strings.SplitN(line.Args[len(line.Args)-1], " ", 2) - conn.st.NickInfo(nk.Nick, line.Args[2], line.Args[3], a[1]) - if !line.argslen(6) { - return - } - if idx := strings.Index(line.Args[6], "*"); idx != -1 { - conn.st.NickModes(nk.Nick, "+o") - } - if idx := strings.Index(line.Args[6], "B"); idx != -1 { - conn.st.NickModes(nk.Nick, "+B") - } - if idx := strings.Index(line.Args[6], "H"); idx != -1 { - conn.st.NickModes(nk.Nick, "+i") - } -} - -// Handle 353 names reply -func (conn *Conn) h_353(line *Line) { - if !line.argslen(2) { - return - } - if ch := conn.st.GetChannel(line.Args[2]); ch != nil { - nicks := strings.Split(line.Args[len(line.Args)-1], " ") - for _, nick := range nicks { - // UnrealIRCd's coders are lazy and leave a trailing space - if nick == "" { - continue - } - switch c := nick[0]; c { - case '~', '&', '@', '%', '+': - nick = nick[1:] - fallthrough - default: - if conn.st.GetNick(nick) == nil { - // we don't know this nick yet! - conn.st.NewNick(nick) - } - if _, ok := conn.st.IsOn(ch.Name, nick); !ok { - // This nick isn't associated with this channel yet! - conn.st.Associate(ch.Name, nick) - } - switch c { - case '~': - conn.st.ChannelModes(ch.Name, "+q", nick) - case '&': - conn.st.ChannelModes(ch.Name, "+a", nick) - case '@': - conn.st.ChannelModes(ch.Name, "+o", nick) - case '%': - conn.st.ChannelModes(ch.Name, "+h", nick) - case '+': - conn.st.ChannelModes(ch.Name, "+v", nick) - } - } - } - } else { - logging.Warn("irc.353(): received NAMES list for unknown channel %s", - line.Args[2]) - } -} - -// Handle 671 whois reply (nick connected via SSL) -func (conn *Conn) h_671(line *Line) { - if !line.argslen(1) { - return - } - if nk := conn.st.GetNick(line.Args[1]); nk != nil { - conn.st.NickModes(nk.Nick, "+z") - } else { - logging.Warn("irc.671(): received WHOIS SSL info for unknown nick %s", - line.Args[1]) - } -} diff --git a/vendor/github.com/fluffle/goirc/logging/logging.go b/vendor/github.com/fluffle/goirc/logging/logging.go deleted file mode 100644 index f939fce..0000000 --- a/vendor/github.com/fluffle/goirc/logging/logging.go +++ /dev/null @@ -1,44 +0,0 @@ -package logging - -// The IRC client will log things using these methods -type Logger interface { - // Debug logging of raw socket comms to/from server. - Debug(format string, args ...interface{}) - // Informational logging about client behaviour. - Info(format string, args ...interface{}) - // Warnings of inconsistent or unexpected data, mostly - // related to state tracking of IRC nicks/chans. - Warn(format string, args ...interface{}) - // Errors, mostly to do with network communication. - Error(format string, args ...interface{}) -} - -// By default we do no logging. Logging is enabled or disabled -// at the package level, since I'm lazy and re-re-reorganising -// my code to pass a per-client-struct Logger around to all the -// state objects is a pain in the arse. -var logger Logger = nullLogger{} - -// SetLogger sets the internal goirc Logger to l. If l is nil, -// a dummy logger that does nothing is installed instead. -func SetLogger(l Logger) { - if l == nil { - logger = nullLogger{} - } else { - logger = l - } -} - -// A nullLogger does nothing while fulfilling Logger. -type nullLogger struct{} - -func (nl nullLogger) Debug(f string, a ...interface{}) {} -func (nl nullLogger) Info(f string, a ...interface{}) {} -func (nl nullLogger) Warn(f string, a ...interface{}) {} -func (nl nullLogger) Error(f string, a ...interface{}) {} - -// Shim functions so that the package can be used directly -func Debug(f string, a ...interface{}) { logger.Debug(f, a...) } -func Info(f string, a ...interface{}) { logger.Info(f, a...) } -func Warn(f string, a ...interface{}) { logger.Warn(f, a...) } -func Error(f string, a ...interface{}) { logger.Error(f, a...) } diff --git a/vendor/github.com/fluffle/goirc/state/channel.go b/vendor/github.com/fluffle/goirc/state/channel.go deleted file mode 100644 index e45b6c8..0000000 --- a/vendor/github.com/fluffle/goirc/state/channel.go +++ /dev/null @@ -1,360 +0,0 @@ -package state - -import ( - "github.com/fluffle/goirc/logging" - - "reflect" - "strconv" -) - -// A Channel is returned from the state tracker and contains -// a copy of the channel state at a particular time. -type Channel struct { - Name, Topic string - Modes *ChanMode - Nicks map[string]*ChanPrivs -} - -// Internal bookkeeping struct for channels. -type channel struct { - name, topic string - modes *ChanMode - lookup map[string]*nick - nicks map[*nick]*ChanPrivs -} - -// A struct representing the modes of an IRC Channel -// (the ones we care about, at least). -// http://www.unrealircd.com/files/docs/unreal32docs.html#userchannelmodes -type ChanMode struct { - // MODE +p, +s, +t, +n, +m - Private, Secret, ProtectedTopic, NoExternalMsg, Moderated bool - - // MODE +i, +O, +z - InviteOnly, OperOnly, SSLOnly bool - - // MODE +r, +Z - Registered, AllSSL bool - - // MODE +k - Key string - - // MODE +l - Limit int -} - -// A struct representing the modes a Nick can have on a Channel -type ChanPrivs struct { - // MODE +q, +a, +o, +h, +v - Owner, Admin, Op, HalfOp, Voice bool -} - -// Map ChanMode fields to IRC mode characters -var StringToChanMode = map[string]string{} -var ChanModeToString = map[string]string{ - "Private": "p", - "Secret": "s", - "ProtectedTopic": "t", - "NoExternalMsg": "n", - "Moderated": "m", - "InviteOnly": "i", - "OperOnly": "O", - "SSLOnly": "z", - "Registered": "r", - "AllSSL": "Z", - "Key": "k", - "Limit": "l", -} - -// Map *irc.ChanPrivs fields to IRC mode characters -var StringToChanPriv = map[string]string{} -var ChanPrivToString = map[string]string{ - "Owner": "q", - "Admin": "a", - "Op": "o", - "HalfOp": "h", - "Voice": "v", -} - -// Map *irc.ChanPrivs fields to the symbols used to represent these modes -// in NAMES and WHOIS responses -var ModeCharToChanPriv = map[byte]string{} -var ChanPrivToModeChar = map[string]byte{ - "Owner": '~', - "Admin": '&', - "Op": '@', - "HalfOp": '%', - "Voice": '+', -} - -// Init function to fill in reverse mappings for *toString constants. -func init() { - for k, v := range ChanModeToString { - StringToChanMode[v] = k - } - for k, v := range ChanPrivToString { - StringToChanPriv[v] = k - } - for k, v := range ChanPrivToModeChar { - ModeCharToChanPriv[v] = k - } -} - -/******************************************************************************\ - * Channel methods for state management -\******************************************************************************/ - -func newChannel(name string) *channel { - return &channel{ - name: name, - modes: new(ChanMode), - nicks: make(map[*nick]*ChanPrivs), - lookup: make(map[string]*nick), - } -} - -// Returns a copy of the internal tracker channel state at this time. -// Relies on tracker-level locking for concurrent access. -func (ch *channel) Channel() *Channel { - c := &Channel{ - Name: ch.name, - Topic: ch.topic, - Modes: ch.modes.Copy(), - Nicks: make(map[string]*ChanPrivs), - } - for n, cp := range ch.nicks { - c.Nicks[n.nick] = cp.Copy() - } - return c -} - -func (ch *channel) isOn(nk *nick) (*ChanPrivs, bool) { - cp, ok := ch.nicks[nk] - return cp.Copy(), ok -} - -// Associates a Nick with a Channel -func (ch *channel) addNick(nk *nick, cp *ChanPrivs) { - if _, ok := ch.nicks[nk]; !ok { - ch.nicks[nk] = cp - ch.lookup[nk.nick] = nk - } else { - logging.Warn("Channel.addNick(): %s already on %s.", nk.nick, ch.name) - } -} - -// Disassociates a Nick from a Channel. -func (ch *channel) delNick(nk *nick) { - if _, ok := ch.nicks[nk]; ok { - delete(ch.nicks, nk) - delete(ch.lookup, nk.nick) - } else { - logging.Warn("Channel.delNick(): %s not on %s.", nk.nick, ch.name) - } -} - -// Parses mode strings for a channel. -func (ch *channel) parseModes(modes string, modeargs ...string) { - var modeop bool // true => add mode, false => remove mode - var modestr string - for i := 0; i < len(modes); i++ { - switch m := modes[i]; m { - case '+': - modeop = true - modestr = string(m) - case '-': - modeop = false - modestr = string(m) - case 'i': - ch.modes.InviteOnly = modeop - case 'm': - ch.modes.Moderated = modeop - case 'n': - ch.modes.NoExternalMsg = modeop - case 'p': - ch.modes.Private = modeop - case 'r': - ch.modes.Registered = modeop - case 's': - ch.modes.Secret = modeop - case 't': - ch.modes.ProtectedTopic = modeop - case 'z': - ch.modes.SSLOnly = modeop - case 'Z': - ch.modes.AllSSL = modeop - case 'O': - ch.modes.OperOnly = modeop - case 'k': - if modeop && len(modeargs) != 0 { - ch.modes.Key, modeargs = modeargs[0], modeargs[1:] - } else if !modeop { - ch.modes.Key = "" - } else { - logging.Warn("Channel.ParseModes(): not enough arguments to "+ - "process MODE %s %s%c", ch.name, modestr, m) - } - case 'l': - if modeop && len(modeargs) != 0 { - ch.modes.Limit, _ = strconv.Atoi(modeargs[0]) - modeargs = modeargs[1:] - } else if !modeop { - ch.modes.Limit = 0 - } else { - logging.Warn("Channel.ParseModes(): not enough arguments to "+ - "process MODE %s %s%c", ch.name, modestr, m) - } - case 'q', 'a', 'o', 'h', 'v': - if len(modeargs) != 0 { - if nk, ok := ch.lookup[modeargs[0]]; ok { - cp := ch.nicks[nk] - switch m { - case 'q': - cp.Owner = modeop - case 'a': - cp.Admin = modeop - case 'o': - cp.Op = modeop - case 'h': - cp.HalfOp = modeop - case 'v': - cp.Voice = modeop - } - modeargs = modeargs[1:] - } else { - logging.Warn("Channel.ParseModes(): untracked nick %s "+ - "received MODE on channel %s", modeargs[0], ch.name) - } - } else { - logging.Warn("Channel.ParseModes(): not enough arguments to "+ - "process MODE %s %s%c", ch.name, modestr, m) - } - default: - logging.Info("Channel.ParseModes(): unknown mode char %c", m) - } - } -} - -// Returns true if the Nick is associated with the Channel -func (ch *Channel) IsOn(nk string) (*ChanPrivs, bool) { - cp, ok := ch.Nicks[nk] - return cp, ok -} - -// Test Channel equality. -func (ch *Channel) Equals(other *Channel) bool { - return reflect.DeepEqual(ch, other) -} - -// Duplicates a ChanMode struct. -func (cm *ChanMode) Copy() *ChanMode { - if cm == nil { - return nil - } - c := *cm - return &c -} - -// Test ChanMode equality. -func (cm *ChanMode) Equals(other *ChanMode) bool { - return reflect.DeepEqual(cm, other) -} - -// Duplicates a ChanPrivs struct. -func (cp *ChanPrivs) Copy() *ChanPrivs { - if cp == nil { - return nil - } - c := *cp - return &c -} - -// Test ChanPrivs equality. -func (cp *ChanPrivs) Equals(other *ChanPrivs) bool { - return reflect.DeepEqual(cp, other) -} - -// Returns a string representing the channel. Looks like: -// Channel: e.g. #moo -// Topic: e.g. Discussing the merits of cows! -// Mode: e.g. +nsti -// Nicks: -// : e.g. CowMaster: +o -// ... -func (ch *Channel) String() string { - str := "Channel: " + ch.Name + "\n\t" - str += "Topic: " + ch.Topic + "\n\t" - str += "Modes: " + ch.Modes.String() + "\n\t" - str += "Nicks: \n" - for nk, cp := range ch.Nicks { - str += "\t\t" + nk + ": " + cp.String() + "\n" - } - return str -} - -func (ch *channel) String() string { - return ch.Channel().String() -} - -// Returns a string representing the channel modes. Looks like: -// +npk key -func (cm *ChanMode) String() string { - if cm == nil { - return "No modes set" - } - str := "+" - a := make([]string, 0) - v := reflect.Indirect(reflect.ValueOf(cm)) - t := v.Type() - for i := 0; i < v.NumField(); i++ { - switch f := v.Field(i); f.Kind() { - case reflect.Bool: - if f.Bool() { - str += ChanModeToString[t.Field(i).Name] - } - case reflect.String: - if f.String() != "" { - str += ChanModeToString[t.Field(i).Name] - a = append(a, f.String()) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if f.Int() != 0 { - str += ChanModeToString[t.Field(i).Name] - a = append(a, strconv.FormatInt(f.Int(), 10)) - } - } - } - for _, s := range a { - if s != "" { - str += " " + s - } - } - if str == "+" { - str = "No modes set" - } - return str -} - -// Returns a string representing the channel privileges. Looks like: -// +o -func (cp *ChanPrivs) String() string { - if cp == nil { - return "No modes set" - } - str := "+" - v := reflect.Indirect(reflect.ValueOf(cp)) - t := v.Type() - for i := 0; i < v.NumField(); i++ { - switch f := v.Field(i); f.Kind() { - // only bools here at the mo too! - case reflect.Bool: - if f.Bool() { - str += ChanPrivToString[t.Field(i).Name] - } - } - } - if str == "+" { - str = "No modes set" - } - return str -} diff --git a/vendor/github.com/fluffle/goirc/state/mock_tracker.go b/vendor/github.com/fluffle/goirc/state/mock_tracker.go deleted file mode 100644 index aa594c4..0000000 --- a/vendor/github.com/fluffle/goirc/state/mock_tracker.go +++ /dev/null @@ -1,201 +0,0 @@ -// Automatically generated by MockGen. DO NOT EDIT! -// Source: tracker.go - -package state - -import ( - gomock "github.com/golang/mock/gomock" -) - -// Mock of Tracker interface -type MockTracker struct { - ctrl *gomock.Controller - recorder *_MockTrackerRecorder -} - -// Recorder for MockTracker (not exported) -type _MockTrackerRecorder struct { - mock *MockTracker -} - -func NewMockTracker(ctrl *gomock.Controller) *MockTracker { - mock := &MockTracker{ctrl: ctrl} - mock.recorder = &_MockTrackerRecorder{mock} - return mock -} - -func (_m *MockTracker) EXPECT() *_MockTrackerRecorder { - return _m.recorder -} - -func (_m *MockTracker) NewNick(nick string) *Nick { - ret := _m.ctrl.Call(_m, "NewNick", nick) - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) NewNick(arg0 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "NewNick", arg0) -} - -func (_m *MockTracker) GetNick(nick string) *Nick { - ret := _m.ctrl.Call(_m, "GetNick", nick) - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) GetNick(arg0 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "GetNick", arg0) -} - -func (_m *MockTracker) ReNick(old string, neu string) *Nick { - ret := _m.ctrl.Call(_m, "ReNick", old, neu) - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) ReNick(arg0, arg1 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "ReNick", arg0, arg1) -} - -func (_m *MockTracker) DelNick(nick string) *Nick { - ret := _m.ctrl.Call(_m, "DelNick", nick) - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) DelNick(arg0 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "DelNick", arg0) -} - -func (_m *MockTracker) NickInfo(nick string, ident string, host string, name string) *Nick { - ret := _m.ctrl.Call(_m, "NickInfo", nick, ident, host, name) - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) NickInfo(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "NickInfo", arg0, arg1, arg2, arg3) -} - -func (_m *MockTracker) NickModes(nick string, modestr string) *Nick { - ret := _m.ctrl.Call(_m, "NickModes", nick, modestr) - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) NickModes(arg0, arg1 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "NickModes", arg0, arg1) -} - -func (_m *MockTracker) NewChannel(channel string) *Channel { - ret := _m.ctrl.Call(_m, "NewChannel", channel) - ret0, _ := ret[0].(*Channel) - return ret0 -} - -func (_mr *_MockTrackerRecorder) NewChannel(arg0 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "NewChannel", arg0) -} - -func (_m *MockTracker) GetChannel(channel string) *Channel { - ret := _m.ctrl.Call(_m, "GetChannel", channel) - ret0, _ := ret[0].(*Channel) - return ret0 -} - -func (_mr *_MockTrackerRecorder) GetChannel(arg0 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "GetChannel", arg0) -} - -func (_m *MockTracker) DelChannel(channel string) *Channel { - ret := _m.ctrl.Call(_m, "DelChannel", channel) - ret0, _ := ret[0].(*Channel) - return ret0 -} - -func (_mr *_MockTrackerRecorder) DelChannel(arg0 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "DelChannel", arg0) -} - -func (_m *MockTracker) Topic(channel string, topic string) *Channel { - ret := _m.ctrl.Call(_m, "Topic", channel, topic) - ret0, _ := ret[0].(*Channel) - return ret0 -} - -func (_mr *_MockTrackerRecorder) Topic(arg0, arg1 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "Topic", arg0, arg1) -} - -func (_m *MockTracker) ChannelModes(channel string, modestr string, modeargs ...string) *Channel { - _s := []interface{}{channel, modestr} - for _, _x := range modeargs { - _s = append(_s, _x) - } - ret := _m.ctrl.Call(_m, "ChannelModes", _s...) - ret0, _ := ret[0].(*Channel) - return ret0 -} - -func (_mr *_MockTrackerRecorder) ChannelModes(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { - _s := append([]interface{}{arg0, arg1}, arg2...) - return _mr.mock.ctrl.RecordCall(_mr.mock, "ChannelModes", _s...) -} - -func (_m *MockTracker) Me() *Nick { - ret := _m.ctrl.Call(_m, "Me") - ret0, _ := ret[0].(*Nick) - return ret0 -} - -func (_mr *_MockTrackerRecorder) Me() *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "Me") -} - -func (_m *MockTracker) IsOn(channel string, nick string) (*ChanPrivs, bool) { - ret := _m.ctrl.Call(_m, "IsOn", channel, nick) - ret0, _ := ret[0].(*ChanPrivs) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -func (_mr *_MockTrackerRecorder) IsOn(arg0, arg1 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "IsOn", arg0, arg1) -} - -func (_m *MockTracker) Associate(channel string, nick string) *ChanPrivs { - ret := _m.ctrl.Call(_m, "Associate", channel, nick) - ret0, _ := ret[0].(*ChanPrivs) - return ret0 -} - -func (_mr *_MockTrackerRecorder) Associate(arg0, arg1 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "Associate", arg0, arg1) -} - -func (_m *MockTracker) Dissociate(channel string, nick string) { - _m.ctrl.Call(_m, "Dissociate", channel, nick) -} - -func (_mr *_MockTrackerRecorder) Dissociate(arg0, arg1 interface{}) *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "Dissociate", arg0, arg1) -} - -func (_m *MockTracker) Wipe() { - _m.ctrl.Call(_m, "Wipe") -} - -func (_mr *_MockTrackerRecorder) Wipe() *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "Wipe") -} - -func (_m *MockTracker) String() string { - ret := _m.ctrl.Call(_m, "String") - ret0, _ := ret[0].(string) - return ret0 -} - -func (_mr *_MockTrackerRecorder) String() *gomock.Call { - return _mr.mock.ctrl.RecordCall(_mr.mock, "String") -} diff --git a/vendor/github.com/fluffle/goirc/state/nick.go b/vendor/github.com/fluffle/goirc/state/nick.go deleted file mode 100644 index b29d98a..0000000 --- a/vendor/github.com/fluffle/goirc/state/nick.go +++ /dev/null @@ -1,205 +0,0 @@ -package state - -import ( - "github.com/fluffle/goirc/logging" - - "reflect" -) - -// A Nick is returned from the state tracker and contains -// a copy of the nick state at a particular time. -type Nick struct { - Nick, Ident, Host, Name string - Modes *NickMode - Channels map[string]*ChanPrivs -} - -// Internal bookkeeping struct for nicks. -type nick struct { - nick, ident, host, name string - modes *NickMode - lookup map[string]*channel - chans map[*channel]*ChanPrivs -} - -// A struct representing the modes of an IRC Nick (User Modes) -// (again, only the ones we care about) -// -// This is only really useful for me, as we can't see other people's modes -// without IRC operator privileges (and even then only on some IRCd's). -type NickMode struct { - // MODE +B, +i, +o, +w, +x, +z - Bot, Invisible, Oper, WallOps, HiddenHost, SSL bool -} - -// Map *irc.NickMode fields to IRC mode characters and vice versa -var StringToNickMode = map[string]string{} -var NickModeToString = map[string]string{ - "Bot": "B", - "Invisible": "i", - "Oper": "o", - "WallOps": "w", - "HiddenHost": "x", - "SSL": "z", -} - -func init() { - for k, v := range NickModeToString { - StringToNickMode[v] = k - } -} - -/******************************************************************************\ - * nick methods for state management -\******************************************************************************/ - -func newNick(n string) *nick { - return &nick{ - nick: n, - modes: new(NickMode), - chans: make(map[*channel]*ChanPrivs), - lookup: make(map[string]*channel), - } -} - -// Returns a copy of the internal tracker nick state at this time. -// Relies on tracker-level locking for concurrent access. -func (nk *nick) Nick() *Nick { - n := &Nick{ - Nick: nk.nick, - Ident: nk.ident, - Host: nk.host, - Name: nk.name, - Modes: nk.modes.Copy(), - Channels: make(map[string]*ChanPrivs), - } - for c, cp := range nk.chans { - n.Channels[c.name] = cp.Copy() - } - return n -} - -func (nk *nick) isOn(ch *channel) (*ChanPrivs, bool) { - cp, ok := nk.chans[ch] - return cp.Copy(), ok -} - -// Associates a Channel with a Nick. -func (nk *nick) addChannel(ch *channel, cp *ChanPrivs) { - if _, ok := nk.chans[ch]; !ok { - nk.chans[ch] = cp - nk.lookup[ch.name] = ch - } else { - logging.Warn("Nick.addChannel(): %s already on %s.", nk.nick, ch.name) - } -} - -// Disassociates a Channel from a Nick. -func (nk *nick) delChannel(ch *channel) { - if _, ok := nk.chans[ch]; ok { - delete(nk.chans, ch) - delete(nk.lookup, ch.name) - } else { - logging.Warn("Nick.delChannel(): %s not on %s.", nk.nick, ch.name) - } -} - -// Parse mode strings for a Nick. -func (nk *nick) parseModes(modes string) { - var modeop bool // true => add mode, false => remove mode - for i := 0; i < len(modes); i++ { - switch m := modes[i]; m { - case '+': - modeop = true - case '-': - modeop = false - case 'B': - nk.modes.Bot = modeop - case 'i': - nk.modes.Invisible = modeop - case 'o': - nk.modes.Oper = modeop - case 'w': - nk.modes.WallOps = modeop - case 'x': - nk.modes.HiddenHost = modeop - case 'z': - nk.modes.SSL = modeop - default: - logging.Info("Nick.ParseModes(): unknown mode char %c", m) - } - } -} - -// Returns true if the Nick is associated with the Channel. -func (nk *Nick) IsOn(ch string) (*ChanPrivs, bool) { - cp, ok := nk.Channels[ch] - return cp, ok -} - -// Tests Nick equality. -func (nk *Nick) Equals(other *Nick) bool { - return reflect.DeepEqual(nk, other) -} - -// Duplicates a NickMode struct. -func (nm *NickMode) Copy() *NickMode { - if nm == nil { - return nil - } - n := *nm - return &n -} - -// Tests NickMode equality. -func (nm *NickMode) Equals(other *NickMode) bool { - return reflect.DeepEqual(nm, other) -} - -// Returns a string representing the nick. Looks like: -// Nick: e.g. CowMaster -// Hostmask: e.g. moo@cows.org -// Real Name: e.g. Steve "CowMaster" Bush -// Modes: e.g. +z -// Channels: -// : e.g. #moo: +o -// ... -func (nk *Nick) String() string { - str := "Nick: " + nk.Nick + "\n\t" - str += "Hostmask: " + nk.Ident + "@" + nk.Host + "\n\t" - str += "Real Name: " + nk.Name + "\n\t" - str += "Modes: " + nk.Modes.String() + "\n\t" - str += "Channels: \n" - for ch, cp := range nk.Channels { - str += "\t\t" + ch + ": " + cp.String() + "\n" - } - return str -} - -func (nk *nick) String() string { - return nk.Nick().String() -} - -// Returns a string representing the nick modes. Looks like: -// +iwx -func (nm *NickMode) String() string { - if nm == nil { - return "No modes set" - } - str := "+" - v := reflect.Indirect(reflect.ValueOf(nm)) - t := v.Type() - for i := 0; i < v.NumField(); i++ { - switch f := v.Field(i); f.Kind() { - // only bools here at the mo! - case reflect.Bool: - if f.Bool() { - str += NickModeToString[t.Field(i).Name] - } - } - } - if str == "+" { - str = "No modes set" - } - return str -} diff --git a/vendor/github.com/fluffle/goirc/state/tracker.go b/vendor/github.com/fluffle/goirc/state/tracker.go deleted file mode 100644 index 209c7cf..0000000 --- a/vendor/github.com/fluffle/goirc/state/tracker.go +++ /dev/null @@ -1,369 +0,0 @@ -package state - -import ( - "github.com/fluffle/goirc/logging" - - "sync" -) - -// The state manager interface -type Tracker interface { - // Nick methods - NewNick(nick string) *Nick - GetNick(nick string) *Nick - ReNick(old, neu string) *Nick - DelNick(nick string) *Nick - NickInfo(nick, ident, host, name string) *Nick - NickModes(nick, modestr string) *Nick - // Channel methods - NewChannel(channel string) *Channel - GetChannel(channel string) *Channel - DelChannel(channel string) *Channel - Topic(channel, topic string) *Channel - ChannelModes(channel, modestr string, modeargs ...string) *Channel - // Information about ME! - Me() *Nick - // And the tracking operations - IsOn(channel, nick string) (*ChanPrivs, bool) - Associate(channel, nick string) *ChanPrivs - Dissociate(channel, nick string) - Wipe() - // The state tracker can output a debugging string - String() string -} - -// ... and a struct to implement it ... -type stateTracker struct { - // Map of channels we're on - chans map[string]*channel - // Map of nicks we know about - nicks map[string]*nick - - // We need to keep state on who we are :-) - me *nick - - // And we need to protect against data races *cough*. - mu sync.Mutex -} - -var _ Tracker = (*stateTracker)(nil) - -// ... and a constructor to make it ... -func NewTracker(mynick string) *stateTracker { - st := &stateTracker{ - chans: make(map[string]*channel), - nicks: make(map[string]*nick), - } - st.me = newNick(mynick) - st.nicks[mynick] = st.me - return st -} - -// ... and a method to wipe the state clean. -func (st *stateTracker) Wipe() { - st.mu.Lock() - defer st.mu.Unlock() - // Deleting all the channels implicitly deletes every nick but me. - for _, ch := range st.chans { - st.delChannel(ch) - } -} - -/******************************************************************************\ - * tracker methods to create/look up nicks/channels -\******************************************************************************/ - -// Creates a new nick, initialises it, and stores it so it -// can be properly tracked for state management purposes. -func (st *stateTracker) NewNick(n string) *Nick { - if n == "" { - logging.Warn("Tracker.NewNick(): Not tracking empty nick.") - return nil - } - st.mu.Lock() - defer st.mu.Unlock() - if _, ok := st.nicks[n]; ok { - logging.Warn("Tracker.NewNick(): %s already tracked.", n) - return nil - } - st.nicks[n] = newNick(n) - return st.nicks[n].Nick() -} - -// Returns a nick for the nick n, if we're tracking it. -func (st *stateTracker) GetNick(n string) *Nick { - st.mu.Lock() - defer st.mu.Unlock() - if nk, ok := st.nicks[n]; ok { - return nk.Nick() - } - return nil -} - -// Signals to the tracker that a nick should be tracked -// under a "neu" nick rather than the old one. -func (st *stateTracker) ReNick(old, neu string) *Nick { - st.mu.Lock() - defer st.mu.Unlock() - nk, ok := st.nicks[old] - if !ok { - logging.Warn("Tracker.ReNick(): %s not tracked.", old) - return nil - } - if _, ok := st.nicks[neu]; ok { - logging.Warn("Tracker.ReNick(): %s already exists.", neu) - return nil - } - - nk.nick = neu - delete(st.nicks, old) - st.nicks[neu] = nk - for ch, _ := range nk.chans { - // We also need to update the lookup maps of all the channels - // the nick is on, to keep things in sync. - delete(ch.lookup, old) - ch.lookup[neu] = nk - } - return nk.Nick() -} - -// Removes a nick from being tracked. -func (st *stateTracker) DelNick(n string) *Nick { - st.mu.Lock() - defer st.mu.Unlock() - if nk, ok := st.nicks[n]; ok { - if nk == st.me { - logging.Warn("Tracker.DelNick(): won't delete myself.") - return nil - } - st.delNick(nk) - return nk.Nick() - } - logging.Warn("Tracker.DelNick(): %s not tracked.", n) - return nil -} - -func (st *stateTracker) delNick(nk *nick) { - // st.mu lock held by DelNick, DelChannel or Wipe - if nk == st.me { - // Shouldn't get here => internal state tracking code is fubar. - logging.Error("Tracker.DelNick(): TRYING TO DELETE ME :-(") - return - } - delete(st.nicks, nk.nick) - for ch, _ := range nk.chans { - nk.delChannel(ch) - ch.delNick(nk) - if len(ch.nicks) == 0 { - // Deleting a nick from tracking shouldn't empty any channels as - // *we* should be on the channel with them to be tracking them. - logging.Error("Tracker.delNick(): deleting nick %s emptied "+ - "channel %s, this shouldn't happen!", nk.nick, ch.name) - } - } -} - -// Sets ident, host and "real" name for the nick. -func (st *stateTracker) NickInfo(n, ident, host, name string) *Nick { - st.mu.Lock() - defer st.mu.Unlock() - nk, ok := st.nicks[n] - if !ok { - return nil - } - nk.ident = ident - nk.host = host - nk.name = name - return nk.Nick() -} - -// Sets user modes for the nick. -func (st *stateTracker) NickModes(n, modes string) *Nick { - st.mu.Lock() - defer st.mu.Unlock() - nk, ok := st.nicks[n] - if !ok { - return nil - } - nk.parseModes(modes) - return nk.Nick() -} - -// Creates a new Channel, initialises it, and stores it so it -// can be properly tracked for state management purposes. -func (st *stateTracker) NewChannel(c string) *Channel { - if c == "" { - logging.Warn("Tracker.NewChannel(): Not tracking empty channel.") - return nil - } - st.mu.Lock() - defer st.mu.Unlock() - if _, ok := st.chans[c]; ok { - logging.Warn("Tracker.NewChannel(): %s already tracked.", c) - return nil - } - st.chans[c] = newChannel(c) - return st.chans[c].Channel() -} - -// Returns a Channel for the channel c, if we're tracking it. -func (st *stateTracker) GetChannel(c string) *Channel { - st.mu.Lock() - defer st.mu.Unlock() - if ch, ok := st.chans[c]; ok { - return ch.Channel() - } - return nil -} - -// Removes a Channel from being tracked. -func (st *stateTracker) DelChannel(c string) *Channel { - st.mu.Lock() - defer st.mu.Unlock() - if ch, ok := st.chans[c]; ok { - st.delChannel(ch) - return ch.Channel() - } - logging.Warn("Tracker.DelChannel(): %s not tracked.", c) - return nil -} - -func (st *stateTracker) delChannel(ch *channel) { - // st.mu lock held by DelChannel or Wipe - delete(st.chans, ch.name) - for nk, _ := range ch.nicks { - ch.delNick(nk) - nk.delChannel(ch) - if len(nk.chans) == 0 && nk != st.me { - // We're no longer in any channels with this nick. - st.delNick(nk) - } - } -} - -// Sets the topic of a channel. -func (st *stateTracker) Topic(c, topic string) *Channel { - st.mu.Lock() - defer st.mu.Unlock() - ch, ok := st.chans[c] - if !ok { - return nil - } - ch.topic = topic - return ch.Channel() -} - -// Sets modes for a channel, including privileges like +o. -func (st *stateTracker) ChannelModes(c, modes string, args ...string) *Channel { - st.mu.Lock() - defer st.mu.Unlock() - ch, ok := st.chans[c] - if !ok { - return nil - } - ch.parseModes(modes, args...) - return ch.Channel() -} - -// Returns the Nick the state tracker thinks is Me. -// NOTE: Nick() requires the mutex to be held. -func (st *stateTracker) Me() *Nick { - st.mu.Lock() - defer st.mu.Unlock() - return st.me.Nick() -} - -// Returns true if both the channel c and the nick n are tracked -// and the nick is associated with the channel. -func (st *stateTracker) IsOn(c, n string) (*ChanPrivs, bool) { - st.mu.Lock() - defer st.mu.Unlock() - nk, nok := st.nicks[n] - ch, cok := st.chans[c] - if nok && cok { - return nk.isOn(ch) - } - return nil, false -} - -// Associates an already known nick with an already known channel. -func (st *stateTracker) Associate(c, n string) *ChanPrivs { - st.mu.Lock() - defer st.mu.Unlock() - nk, nok := st.nicks[n] - ch, cok := st.chans[c] - - if !cok { - // As we can implicitly delete both nicks and channels from being - // tracked by dissociating one from the other, we should verify that - // we're not being passed an old Nick or Channel. - logging.Error("Tracker.Associate(): channel %s not found in "+ - "internal state.", c) - return nil - } else if !nok { - logging.Error("Tracker.Associate(): nick %s not found in "+ - "internal state.", n) - return nil - } else if _, ok := nk.isOn(ch); ok { - logging.Warn("Tracker.Associate(): %s already on %s.", - nk, ch) - return nil - } - cp := new(ChanPrivs) - ch.addNick(nk, cp) - nk.addChannel(ch, cp) - return cp.Copy() -} - -// Dissociates an already known nick from an already known channel. -// Does some tidying up to stop tracking nicks we're no longer on -// any common channels with, and channels we're no longer on. -func (st *stateTracker) Dissociate(c, n string) { - st.mu.Lock() - defer st.mu.Unlock() - nk, nok := st.nicks[n] - ch, cok := st.chans[c] - - if !cok { - // As we can implicitly delete both nicks and channels from being - // tracked by dissociating one from the other, we should verify that - // we're not being passed an old Nick or Channel. - logging.Error("Tracker.Dissociate(): channel %s not found in "+ - "internal state.", c) - } else if !nok { - logging.Error("Tracker.Dissociate(): nick %s not found in "+ - "internal state.", n) - } else if _, ok := nk.isOn(ch); !ok { - logging.Warn("Tracker.Dissociate(): %s not on %s.", - nk.nick, ch.name) - } else if nk == st.me { - // I'm leaving the channel for some reason, so it won't be tracked. - st.delChannel(ch) - } else { - // Remove the nick from the channel and the channel from the nick. - ch.delNick(nk) - nk.delChannel(ch) - if len(nk.chans) == 0 { - // We're no longer in any channels with this nick. - st.delNick(nk) - } - } -} - -func (st *stateTracker) String() string { - st.mu.Lock() - defer st.mu.Unlock() - str := "GoIRC Channels\n" - str += "--------------\n\n" - for _, ch := range st.chans { - str += ch.String() + "\n" - } - str += "GoIRC NickNames\n" - str += "---------------\n\n" - for _, n := range st.nicks { - if n != st.me { - str += n.String() + "\n" - } - } - return str -} -- cgit v1.2.3