diff --git a/vendor/github.com/lrstanley/girc/cap.go b/vendor/github.com/lrstanley/girc/cap.go index 751135b3..a63dfe9d 100644 --- a/vendor/github.com/lrstanley/girc/cap.go +++ b/vendor/github.com/lrstanley/girc/cap.go @@ -136,7 +136,7 @@ func handleCAP(c *Client, e Event) { } // Let them know which ones we'd like to enable. - c.write(&Event{Command: CAP, Params: []string{CAP_REQ}, Trailing: strings.Join(c.state.tmpCap, " ")}) + c.write(&Event{Command: CAP, Params: []string{CAP_REQ}, Trailing: strings.Join(c.state.tmpCap, " "), EmptyTrailing: true}) // Re-initialize the tmpCap, so if we get multiple 'CAP LS' requests // due to cap-notify, we can re-evaluate what we can support. diff --git a/vendor/github.com/lrstanley/girc/client.go b/vendor/github.com/lrstanley/girc/client.go index 1a4d4ac2..403a7aec 100644 --- a/vendor/github.com/lrstanley/girc/client.go +++ b/vendor/github.com/lrstanley/girc/client.go @@ -191,18 +191,6 @@ func (conf *Config) isValid() error { // connected. var ErrNotConnected = errors.New("client is not connected to server") -// ErrDisconnected is called when Config.Retries is less than 1, and we -// non-intentionally disconnected from the server. -var ErrDisconnected = errors.New("unexpectedly disconnected") - -// ErrInvalidTarget should be returned if the target which you are -// attempting to send an event to is invalid or doesn't match RFC spec. -type ErrInvalidTarget struct { - Target string -} - -func (e *ErrInvalidTarget) Error() string { return "invalid target: " + e.Target } - // New creates a new IRC client with the specified server, name and config. func New(config Config) *Client { c := &Client{ @@ -253,6 +241,37 @@ func (c *Client) String() string { ) } +// TLSConnectionState returns the TLS connection state from tls.Conn{}, which +// is useful to return needed TLS fingerprint info, certificates, verify cert +// expiration dates, etc. Will only return an error if the underlying +// connection wasn't established using TLS (see ErrConnNotTLS), or if the +// client isn't connected. +func (c *Client) TLSConnectionState() (*tls.ConnectionState, error) { + c.mu.RLock() + defer c.mu.RUnlock() + if c.conn == nil { + return nil, ErrNotConnected + } + + c.conn.mu.RLock() + defer c.conn.mu.RUnlock() + + if !c.conn.connected { + return nil, ErrNotConnected + } + + if tlsConn, ok := c.conn.sock.(*tls.Conn); ok { + cs := tlsConn.ConnectionState() + return &cs, nil + } + + return nil, ErrConnNotTLS +} + +// ErrConnNotTLS is returned when Client.TLSConnectionState() is called, and +// the connection to the server wasn't made with TLS. +var ErrConnNotTLS = errors.New("underlying connection is not tls") + // Close closes the network connection to the server, and sends a STOPPED // event. This should cause Connect() to return with nil. This should be // safe to call multiple times. See Connect()'s documentation on how @@ -387,7 +406,7 @@ func (c *Client) ConnSince() (since *time.Duration, err error) { } // IsConnected returns true if the client is connected to the server. -func (c *Client) IsConnected() (connected bool) { +func (c *Client) IsConnected() bool { c.mu.RLock() if c.conn == nil { c.mu.RUnlock() @@ -395,7 +414,7 @@ func (c *Client) IsConnected() (connected bool) { } c.conn.mu.RLock() - connected = c.conn.connected + connected := c.conn.connected c.conn.mu.RUnlock() c.mu.RUnlock() @@ -562,30 +581,30 @@ func (c *Client) NetworkName() (name string) { // supplied this information during connection. May be empty if the server // does not support RPL_MYINFO. Will panic if used when tracking has been // disabled. -func (c *Client) ServerVersion() (version string) { +func (c *Client) ServerVersion() string { c.panicIfNotTracking() - version, _ = c.GetServerOption("VERSION") + version, _ := c.GetServerOption("VERSION") return version } // ServerMOTD returns the servers message of the day, if the server has sent // it upon connect. Will panic if used when tracking has been disabled. -func (c *Client) ServerMOTD() (motd string) { +func (c *Client) ServerMOTD() string { c.panicIfNotTracking() c.state.RLock() - motd = c.state.motd + motd := c.state.motd c.state.RUnlock() return motd } -// Lag is the latency between the server and the client. This is measured by -// determining the difference in time between when we ping the server, and +// Latency is the latency between the server and the client. This is measured +// by determining the difference in time between when we ping the server, and // when we receive a pong. -func (c *Client) Lag() time.Duration { +func (c *Client) Latency() time.Duration { c.mu.RLock() c.conn.mu.RLock() delta := c.conn.lastPong.Sub(c.conn.lastPing) diff --git a/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go b/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go index 71bb9f89..a45a42f3 100644 --- a/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go +++ b/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go @@ -12,8 +12,9 @@ import ( // Input is a wrapper for events, based around private messages. type Input struct { - Origin *girc.Event - Args []string + Origin *girc.Event + Args []string + RawArgs string } // Command is an IRC command, supporting aliases, help documentation and easy @@ -189,8 +190,9 @@ func (ch *CmdHandler) Execute(client *girc.Client, event girc.Event) { } in := &Input{ - Origin: &event, - Args: args, + Origin: &event, + Args: args, + RawArgs: parsed[2], } go cmd.Fn(client, in) diff --git a/vendor/github.com/lrstanley/girc/commands.go b/vendor/github.com/lrstanley/girc/commands.go index bce25322..3f7d3bdc 100644 --- a/vendor/github.com/lrstanley/girc/commands.go +++ b/vendor/github.com/lrstanley/girc/commands.go @@ -16,18 +16,13 @@ type Commands struct { } // Nick changes the client nickname. -func (cmd *Commands) Nick(name string) error { - if !IsValidNick(name) { - return &ErrInvalidTarget{Target: name} - } - +func (cmd *Commands) Nick(name string) { cmd.c.Send(&Event{Command: NICK, Params: []string{name}}) - return nil } // Join attempts to enter a list of IRC channels, at bulk if possible to // prevent sending extensive JOIN commands. -func (cmd *Commands) Join(channels ...string) error { +func (cmd *Commands) Join(channels ...string) { // We can join multiple channels at once, however we need to ensure that // we are not exceeding the line length. (see maxLength) max := maxLength - len(JOIN) - 1 @@ -35,10 +30,6 @@ func (cmd *Commands) Join(channels ...string) error { var buffer string for i := 0; i < len(channels); i++ { - if !IsValidChannel(channels[i]) { - return &ErrInvalidTarget{Target: channels[i]} - } - if len(buffer+","+channels[i]) > max { cmd.c.Send(&Event{Command: JOIN, Params: []string{buffer}}) buffer = "" @@ -53,91 +44,74 @@ func (cmd *Commands) Join(channels ...string) error { if i == len(channels)-1 { cmd.c.Send(&Event{Command: JOIN, Params: []string{buffer}}) - return nil + return } } - - return nil } // JoinKey attempts to enter an IRC channel with a password. -func (cmd *Commands) JoinKey(channel, password string) error { - if !IsValidChannel(channel) { - return &ErrInvalidTarget{Target: channel} - } - +func (cmd *Commands) JoinKey(channel, password string) { cmd.c.Send(&Event{Command: JOIN, Params: []string{channel, password}}) - return nil } // Part leaves an IRC channel. -func (cmd *Commands) Part(channel, message string) error { - if !IsValidChannel(channel) { - return &ErrInvalidTarget{Target: channel} +func (cmd *Commands) Part(channels ...string) { + for i := 0; i < len(channels); i++ { + cmd.c.Send(&Event{Command: PART, Params: []string{channels[i]}}) } - - cmd.c.Send(&Event{Command: JOIN, Params: []string{channel}}) - return nil } // PartMessage leaves an IRC channel with a specified leave message. -func (cmd *Commands) PartMessage(channel, message string) error { - if !IsValidChannel(channel) { - return &ErrInvalidTarget{Target: channel} - } - - cmd.c.Send(&Event{Command: JOIN, Params: []string{channel}, Trailing: message}) - return nil +func (cmd *Commands) PartMessage(channel, message string) { + cmd.c.Send(&Event{Command: PART, Params: []string{channel}, Trailing: message, EmptyTrailing: true}) } // SendCTCP sends a CTCP request to target. Note that this method uses -// PRIVMSG specifically. -func (cmd *Commands) SendCTCP(target, ctcpType, message string) error { +// PRIVMSG specifically. ctcpType is the CTCP command, e.g. "FINGER", "TIME", +// "VERSION", etc. +func (cmd *Commands) SendCTCP(target, ctcpType, message string) { out := encodeCTCPRaw(ctcpType, message) if out == "" { - return errors.New("invalid CTCP") + panic(fmt.Sprintf("invalid CTCP: %s -> %s: %s", target, ctcpType, message)) } - return cmd.Message(target, out) + cmd.Message(target, out) } // SendCTCPf sends a CTCP request to target using a specific format. Note that -// this method uses PRIVMSG specifically. -func (cmd *Commands) SendCTCPf(target, ctcpType, format string, a ...interface{}) error { - return cmd.SendCTCP(target, ctcpType, fmt.Sprintf(format, a...)) +// this method uses PRIVMSG specifically. ctcpType is the CTCP command, e.g. +// "FINGER", "TIME", "VERSION", etc. +func (cmd *Commands) SendCTCPf(target, ctcpType, format string, a ...interface{}) { + cmd.SendCTCP(target, ctcpType, fmt.Sprintf(format, a...)) } // SendCTCPReplyf sends a CTCP response to target using a specific format. -// Note that this method uses NOTICE specifically. -func (cmd *Commands) SendCTCPReplyf(target, ctcpType, format string, a ...interface{}) error { - return cmd.SendCTCPReply(target, ctcpType, fmt.Sprintf(format, a...)) +// Note that this method uses NOTICE specifically. ctcpType is the CTCP +// command, e.g. "FINGER", "TIME", "VERSION", etc. +func (cmd *Commands) SendCTCPReplyf(target, ctcpType, format string, a ...interface{}) { + cmd.SendCTCPReply(target, ctcpType, fmt.Sprintf(format, a...)) } // SendCTCPReply sends a CTCP response to target. Note that this method uses // NOTICE specifically. -func (cmd *Commands) SendCTCPReply(target, ctcpType, message string) error { +func (cmd *Commands) SendCTCPReply(target, ctcpType, message string) { out := encodeCTCPRaw(ctcpType, message) if out == "" { - return errors.New("invalid CTCP") + panic(fmt.Sprintf("invalid CTCP: %s -> %s: %s", target, ctcpType, message)) } - return cmd.Notice(target, out) + cmd.Notice(target, out) } // Message sends a PRIVMSG to target (either channel, service, or user). -func (cmd *Commands) Message(target, message string) error { - if !IsValidNick(target) && !IsValidChannel(target) { - return &ErrInvalidTarget{Target: target} - } - - cmd.c.Send(&Event{Command: PRIVMSG, Params: []string{target}, Trailing: message}) - return nil +func (cmd *Commands) Message(target, message string) { + cmd.c.Send(&Event{Command: PRIVMSG, Params: []string{target}, Trailing: message, EmptyTrailing: true}) } // Messagef sends a formated PRIVMSG to target (either channel, service, or // user). -func (cmd *Commands) Messagef(target, format string, a ...interface{}) error { - return cmd.Message(target, fmt.Sprintf(format, a...)) +func (cmd *Commands) Messagef(target, format string, a ...interface{}) { + cmd.Message(target, fmt.Sprintf(format, a...)) } // ErrInvalidSource is returned when a method needs to know the origin of an @@ -146,94 +120,95 @@ func (cmd *Commands) Messagef(target, format string, a ...interface{}) error { var ErrInvalidSource = errors.New("event has nil or invalid source address") // Reply sends a reply to channel or user, based on where the supplied event -// originated from. See also ReplyTo(). -func (cmd *Commands) Reply(event Event, message string) error { +// originated from. See also ReplyTo(). Panics if the incoming event has no +// source. +func (cmd *Commands) Reply(event Event, message string) { if event.Source == nil { - return ErrInvalidSource + panic(ErrInvalidSource) } if len(event.Params) > 0 && IsValidChannel(event.Params[0]) { - return cmd.Message(event.Params[0], message) + cmd.Message(event.Params[0], message) + return } - return cmd.Message(event.Source.Name, message) + cmd.Message(event.Source.Name, message) } // Replyf sends a reply to channel or user with a format string, based on -// where the supplied event originated from. See also ReplyTof(). -func (cmd *Commands) Replyf(event Event, format string, a ...interface{}) error { - return cmd.Reply(event, fmt.Sprintf(format, a...)) +// where the supplied event originated from. See also ReplyTof(). Panics if +// the incoming event has no source. +func (cmd *Commands) Replyf(event Event, format string, a ...interface{}) { + cmd.Reply(event, fmt.Sprintf(format, a...)) } // ReplyTo sends a reply to a channel or user, based on where the supplied // event originated from. ReplyTo(), when originating from a channel will -// default to replying with ", ". See also Reply(). -func (cmd *Commands) ReplyTo(event Event, message string) error { +// default to replying with ", ". See also Reply(). Panics if +// the incoming event has no source. +func (cmd *Commands) ReplyTo(event Event, message string) { if event.Source == nil { - return ErrInvalidSource + panic(ErrInvalidSource) } if len(event.Params) > 0 && IsValidChannel(event.Params[0]) { - return cmd.Message(event.Params[0], event.Source.Name+", "+message) + cmd.Message(event.Params[0], event.Source.Name+", "+message) + return } - return cmd.Message(event.Source.Name, message) + cmd.Message(event.Source.Name, message) } // ReplyTof sends a reply to a channel or user with a format string, based // on where the supplied event originated from. ReplyTo(), when originating // from a channel will default to replying with ", ". See -// also Replyf(). -func (cmd *Commands) ReplyTof(event Event, format string, a ...interface{}) error { - return cmd.ReplyTo(event, fmt.Sprintf(format, a...)) +// also Replyf(). Panics if the incoming event has no source. +func (cmd *Commands) ReplyTof(event Event, format string, a ...interface{}) { + cmd.ReplyTo(event, fmt.Sprintf(format, a...)) } // Action sends a PRIVMSG ACTION (/me) to target (either channel, service, // or user). -func (cmd *Commands) Action(target, message string) error { - if !IsValidNick(target) && !IsValidChannel(target) { - return &ErrInvalidTarget{Target: target} - } - +func (cmd *Commands) Action(target, message string) { cmd.c.Send(&Event{ Command: PRIVMSG, Params: []string{target}, Trailing: fmt.Sprintf("\001ACTION %s\001", message), }) - return nil } // Actionf sends a formated PRIVMSG ACTION (/me) to target (either channel, // service, or user). -func (cmd *Commands) Actionf(target, format string, a ...interface{}) error { - return cmd.Action(target, fmt.Sprintf(format, a...)) +func (cmd *Commands) Actionf(target, format string, a ...interface{}) { + cmd.Action(target, fmt.Sprintf(format, a...)) } // Notice sends a NOTICE to target (either channel, service, or user). -func (cmd *Commands) Notice(target, message string) error { - if !IsValidNick(target) && !IsValidChannel(target) { - return &ErrInvalidTarget{Target: target} - } - - cmd.c.Send(&Event{Command: NOTICE, Params: []string{target}, Trailing: message}) - return nil +func (cmd *Commands) Notice(target, message string) { + cmd.c.Send(&Event{Command: NOTICE, Params: []string{target}, Trailing: message, EmptyTrailing: true}) } // Noticef sends a formated NOTICE to target (either channel, service, or // user). -func (cmd *Commands) Noticef(target, format string, a ...interface{}) error { - return cmd.Notice(target, fmt.Sprintf(format, a...)) +func (cmd *Commands) Noticef(target, format string, a ...interface{}) { + cmd.Notice(target, fmt.Sprintf(format, a...)) } -// SendRaw sends a raw string back to the server, without carriage returns -// or newlines. -func (cmd *Commands) SendRaw(raw string) error { - e := ParseEvent(raw) - if e == nil { - return errors.New("invalid event: " + raw) +// SendRaw sends a raw string (or multiple) to the server, without carriage +// returns or newlines. Returns an error if one of the raw strings cannot be +// properly parsed. +func (cmd *Commands) SendRaw(raw ...string) error { + var event *Event + + for i := 0; i < len(raw); i++ { + event = ParseEvent(raw[i]) + if event == nil { + return errors.New("invalid event: " + raw[i]) + } + + cmd.c.Send(event) } - cmd.c.Send(e) return nil } @@ -246,31 +221,26 @@ func (cmd *Commands) SendRawf(format string, a ...interface{}) error { // Topic sets the topic of channel to message. Does not verify the length // of the topic. func (cmd *Commands) Topic(channel, message string) { - cmd.c.Send(&Event{Command: TOPIC, Params: []string{channel}, Trailing: message}) + cmd.c.Send(&Event{Command: TOPIC, Params: []string{channel}, Trailing: message, EmptyTrailing: true}) } // Who sends a WHO query to the server, which will attempt WHOX by default. // See http://faerion.sourceforge.net/doc/irc/whox.var for more details. This // sends "%tcuhnr,2" per default. Do not use "1" as this will conflict with // girc's builtin tracking functionality. -func (cmd *Commands) Who(target string) error { - if !IsValidNick(target) && !IsValidChannel(target) && !IsValidUser(target) { - return &ErrInvalidTarget{Target: target} +func (cmd *Commands) Who(users ...string) { + for i := 0; i < len(users); i++ { + cmd.c.Send(&Event{Command: WHO, Params: []string{users[i], "%tcuhnr,2"}}) } - - cmd.c.Send(&Event{Command: WHO, Params: []string{target, "%tcuhnr,2"}}) - return nil } -// Whois sends a WHOIS query to the server, targeted at a specific user. -// as WHOIS is a bit slower, you may want to use WHO for brief user info. -func (cmd *Commands) Whois(nick string) error { - if !IsValidNick(nick) { - return &ErrInvalidTarget{Target: nick} +// Whois sends a WHOIS query to the server, targeted at a specific user (or +// set of users). As WHOIS is a bit slower, you may want to use WHO for brief +// user info. +func (cmd *Commands) Whois(users ...string) { + for i := 0; i < len(users); i++ { + cmd.c.Send(&Event{Command: WHOIS, Params: []string{users[i]}}) } - - cmd.c.Send(&Event{Command: WHOIS, Params: []string{nick}}) - return nil } // Ping sends a PING query to the server, with a specific identifier that @@ -294,36 +264,19 @@ func (cmd *Commands) Oper(user, pass string) { // Kick sends a KICK query to the server, attempting to kick nick from // channel, with reason. If reason is blank, one will not be sent to the // server. -func (cmd *Commands) Kick(channel, nick, reason string) error { - if !IsValidChannel(channel) { - return &ErrInvalidTarget{Target: channel} - } - - if !IsValidNick(nick) { - return &ErrInvalidTarget{Target: nick} - } - +func (cmd *Commands) Kick(channel, user, reason string) { if reason != "" { - cmd.c.Send(&Event{Command: KICK, Params: []string{channel, nick}, Trailing: reason}) - return nil + cmd.c.Send(&Event{Command: KICK, Params: []string{channel, user}, Trailing: reason, EmptyTrailing: true}) } - cmd.c.Send(&Event{Command: KICK, Params: []string{channel, nick}}) - return nil + cmd.c.Send(&Event{Command: KICK, Params: []string{channel, user}}) } // Invite sends a INVITE query to the server, to invite nick to channel. -func (cmd *Commands) Invite(channel, nick string) error { - if !IsValidChannel(channel) { - return &ErrInvalidTarget{Target: channel} +func (cmd *Commands) Invite(channel string, users ...string) { + for i := 0; i < len(users); i++ { + cmd.c.Send(&Event{Command: INVITE, Params: []string{users[i], channel}}) } - - if !IsValidNick(nick) { - return &ErrInvalidTarget{Target: nick} - } - - cmd.c.Send(&Event{Command: INVITE, Params: []string{nick, channel}}) - return nil } // Away sends a AWAY query to the server, suggesting that the client is no @@ -348,10 +301,10 @@ func (cmd *Commands) Back() { // Supports multiple channels at once, in hopes it will reduce extensive // LIST queries to the server. Supply no channels to run a list against the // entire server (warning, that may mean LOTS of channels!) -func (cmd *Commands) List(channels ...string) error { +func (cmd *Commands) List(channels ...string) { if len(channels) == 0 { cmd.c.Send(&Event{Command: LIST}) - return nil + return } // We can LIST multiple channels at once, however we need to ensure that @@ -361,10 +314,6 @@ func (cmd *Commands) List(channels ...string) error { var buffer string for i := 0; i < len(channels); i++ { - if !IsValidChannel(channels[i]) { - return &ErrInvalidTarget{Target: channels[i]} - } - if len(buffer+","+channels[i]) > max { cmd.c.Send(&Event{Command: LIST, Params: []string{buffer}}) buffer = "" @@ -379,20 +328,13 @@ func (cmd *Commands) List(channels ...string) error { if i == len(channels)-1 { cmd.c.Send(&Event{Command: LIST, Params: []string{buffer}}) - return nil + return } } - - return nil } // Whowas sends a WHOWAS query to the server. amount is the amount of results // you want back. -func (cmd *Commands) Whowas(nick string, amount int) error { - if !IsValidNick(nick) { - return &ErrInvalidTarget{Target: nick} - } - - cmd.c.Send(&Event{Command: WHOWAS, Params: []string{nick, string(amount)}}) - return nil +func (cmd *Commands) Whowas(user string, amount int) { + cmd.c.Send(&Event{Command: WHOWAS, Params: []string{user, string(amount)}}) } diff --git a/vendor/github.com/lrstanley/girc/format.go b/vendor/github.com/lrstanley/girc/format.go index 5d32f8ad..16639938 100644 --- a/vendor/github.com/lrstanley/girc/format.go +++ b/vendor/github.com/lrstanley/girc/format.go @@ -233,6 +233,7 @@ func IsValidNick(nick string) bool { for i := 1; i < len(nick); i++ { if (nick[i] < 0x41 || nick[i] > 0x7D) && (nick[i] < 0x30 || nick[i] > 0x39) && nick[i] != 0x2D { + fmt.Println(nick[i], i, nick) // a-z, A-Z, 0-9, -, and _\[]{}^| return false } @@ -291,7 +292,9 @@ func IsValidUser(name string) bool { // ToRFC1459 converts a string to the stripped down conversion within RFC // 1459. This will do things like replace an "A" with an "a", "[]" with "{}", // and so forth. Useful to compare two nicknames or channels. -func ToRFC1459(input string) (out string) { +func ToRFC1459(input string) string { + var out string + for i := 0; i < len(input); i++ { if input[i] >= 65 && input[i] <= 94 { out += string(rune(input[i]) + 32) diff --git a/vendor/manifest b/vendor/manifest index 0a97122b..680cc709 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -282,7 +282,7 @@ "importpath": "github.com/lrstanley/girc", "repository": "https://github.com/lrstanley/girc", "vcs": "git", - "revision": "055075db54ebd311be5946efb3f62502846089ff", + "revision": "e698f0468e166574e122130ffd2f579aba7e2abc", "branch": "master", "notests": true },