summaryrefslogtreecommitdiff
path: root/vendor/github.com/fluffle
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/fluffle')
-rw-r--r--vendor/github.com/fluffle/goirc/LICENSE27
-rw-r--r--vendor/github.com/fluffle/goirc/client/commands.go304
-rw-r--r--vendor/github.com/fluffle/goirc/client/connection.go587
-rw-r--r--vendor/github.com/fluffle/goirc/client/dispatch.go202
-rw-r--r--vendor/github.com/fluffle/goirc/client/doc.go34
-rw-r--r--vendor/github.com/fluffle/goirc/client/handlers.go105
-rw-r--r--vendor/github.com/fluffle/goirc/client/line.go216
-rw-r--r--vendor/github.com/fluffle/goirc/client/state_handlers.go262
-rw-r--r--vendor/github.com/fluffle/goirc/logging/logging.go44
-rw-r--r--vendor/github.com/fluffle/goirc/state/channel.go360
-rw-r--r--vendor/github.com/fluffle/goirc/state/mock_tracker.go201
-rw-r--r--vendor/github.com/fluffle/goirc/state/nick.go205
-rw-r--r--vendor/github.com/fluffle/goirc/state/tracker.go369
13 files changed, 0 insertions, 2916 deletions
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 "<hop count> <real name>"
- 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: <channel name> e.g. #moo
-// Topic: <channel topic> e.g. Discussing the merits of cows!
-// Mode: <channel modes> e.g. +nsti
-// Nicks:
-// <nick>: <privs> 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: <nick name> e.g. CowMaster
-// Hostmask: <ident@host> e.g. moo@cows.org
-// Real Name: <real name> e.g. Steve "CowMaster" Bush
-// Modes: <nick modes> e.g. +z
-// Channels:
-// <channel>: <privs> 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
-}