diff --git a/src/shuo-irc.com/irc/LICENSE b/src/shuo-irc.com/irc/LICENSE deleted file mode 100644 index d6bf357..0000000 --- a/src/shuo-irc.com/irc/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2009 Thomas Jager. 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/src/shuo-irc.com/irc/README.markdown b/src/shuo-irc.com/irc/README.markdown deleted file mode 100644 index 3b4eefb..0000000 --- a/src/shuo-irc.com/irc/README.markdown +++ /dev/null @@ -1,65 +0,0 @@ -Description ------------ - -Event based irc client library. - - -Features --------- -* Event based. Register Callbacks for the events you need to handle. -* Handles basic irc demands for you - * Standard CTCP - * Reconnections on errors - * Detect stoned servers - -Install -------- - $ go get github.com/thoj/go-ircevent - -Example -------- -See test/irc_test.go - -Events for callbacks --------------------- -* 001 Welcome -* PING -* CTCP Unknown CTCP -* CTCP_VERSION Version request (Handled internaly) -* CTCP_USERINFO -* CTCP_CLIENTINFO -* CTCP_TIME -* CTCP_PING -* CTCP_ACTION (/me) -* PRIVMSG -* MODE -* JOIN - -+Many more - - -AddCallback Example -------------------- - ircobj.AddCallback("PRIVMSG", func(event *irc.Event) { - //event.Message() contains the message - //event.Nick Contains the sender - //event.Arguments[0] Contains the channel - }); - -Commands --------- - ircobj := irc.IRC("", "") //Create new ircobj - //Set options - ircobj.UseTLS = true //default is false - //ircobj.TLSOptions //set ssl options - ircobj.Password = "[server password]" - //Commands - ircobj.Connect("irc.someserver.com:6667") //Connect to server - ircobj.SendRaw("") //sends string to server. Adds \r\n - ircobj.SendRawf("", ...) //sends formatted string to server.n - ircobj.Join("<#channel> [password]") - ircobj.Nick("newnick") - ircobj.Privmsg("", "msg") - ircobj.Privmsgf(, "", ...) - ircobj.Notice("", "msg") - ircobj.Noticef("", "", ...) diff --git a/src/shuo-irc.com/irc/irc.go b/src/shuo-irc.com/irc/irc.go deleted file mode 100644 index 2218a39..0000000 --- a/src/shuo-irc.com/irc/irc.go +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright 2009 Thomas Jager All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -This package provides an event based IRC client library. It allows to -register callbacks for the events you need to handle. Its features -include handling standard CTCP, reconnecting on errors and detecting -stones servers. -Details of the IRC protocol can be found in the following RFCs: -https://tools.ietf.org/html/rfc1459 -https://tools.ietf.org/html/rfc2810 -https://tools.ietf.org/html/rfc2811 -https://tools.ietf.org/html/rfc2812 -https://tools.ietf.org/html/rfc2813 -The details of the client-to-client protocol (CTCP) can be found here: http://www.irchelp.org/irchelp/rfc/ctcpspec.html -*/ - -package irc - -import ( - "bufio" - "bytes" - "crypto/tls" - "errors" - "fmt" - "log" - "net" - "os" - "strconv" - "strings" - "time" -) - -const ( - VERSION = "go-ircevent v2.1" -) - -var ErrDisconnected = errors.New("Disconnect Called") - -// Read data from a connection. To be used as a goroutine. -func (irc *Connection) readLoop() { - defer irc.Done() - br := bufio.NewReaderSize(irc.socket, 512) - - errChan := irc.ErrorChan() - - for { - select { - case <-irc.end: - return - default: - // Set a read deadline based on the combined timeout and ping frequency - // We should ALWAYS have received a response from the server within the timeout - // after our own pings - if irc.socket != nil { - irc.socket.SetReadDeadline(time.Now().Add(irc.Timeout + irc.PingFreq)) - } - - msg, err := br.ReadString('\n') - - // We got past our blocking read, so bin timeout - if irc.socket != nil { - var zero time.Time - irc.socket.SetReadDeadline(zero) - } - - if err != nil { - errChan <- err - break - } - - if irc.Debug { - irc.Log.Printf("<-- %s\n", strings.TrimSpace(msg)) - } - - irc.lastMessage = time.Now() - event, err := parseToEvent(msg) - event.Connection = irc - if err == nil { - /* XXX: len(args) == 0: args should be empty */ - irc.RunCallbacks(event) - } - } - } - return -} - -//Parse raw irc messages -func parseToEvent(msg string) (*Event, error) { - msg = strings.TrimSuffix(msg, "\n") //Remove \r\n - msg = strings.TrimSuffix(msg, "\r") - event := &Event{Raw: msg} - if len(msg) < 5 { - return nil, errors.New("Malformed msg from server") - } - if msg[0] == ':' { - if i := strings.Index(msg, " "); i > -1 { - event.Source = msg[1:i] - msg = msg[i+1 : len(msg)] - - } else { - return nil, errors.New("Malformed msg from server") - } - - if i, j := strings.Index(event.Source, "!"), strings.Index(event.Source, "@"); i > -1 && j > -1 && i < j { - event.Nick = event.Source[0:i] - event.User = event.Source[i+1 : j] - event.Host = event.Source[j+1 : len(event.Source)] - } - } - - split := strings.SplitN(msg, " :", 2) - args := strings.Split(split[0], " ") - event.Code = strings.ToUpper(args[0]) - event.Arguments = args[1:] - if len(split) > 1 { - event.Arguments = append(event.Arguments, split[1]) - } - return event, nil - -} - -// Loop to write to a connection. To be used as a goroutine. -func (irc *Connection) writeLoop() { - defer irc.Done() - errChan := irc.ErrorChan() - for { - select { - case <-irc.end: - return - default: - b, ok := <-irc.pwrite - if !ok || b == "" || irc.socket == nil { - return - } - - if irc.Debug { - irc.Log.Printf("--> %s\n", strings.TrimSpace(b)) - } - - // Set a write deadline based on the time out - irc.socket.SetWriteDeadline(time.Now().Add(irc.Timeout)) - - _, err := irc.socket.Write([]byte(b)) - - // Past blocking write, bin timeout - var zero time.Time - irc.socket.SetWriteDeadline(zero) - - if err != nil { - errChan <- err - return - } - } - } - return -} - -// Pings the server if we have not received any messages for 5 minutes -// to keep the connection alive. To be used as a goroutine. -func (irc *Connection) pingLoop() { - defer irc.Done() - ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring - ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency. - for { - select { - case <-ticker.C: - //Ping if we haven't received anything from the server within the keep alive period - if time.Since(irc.lastMessage) >= irc.KeepAlive { - irc.SendRawf("PING %d", time.Now().UnixNano()) - } - case <-ticker2.C: - //Ping at the ping frequency - irc.SendRawf("PING %d", time.Now().UnixNano()) - //Try to recapture nickname if it's not as configured. - if irc.nick != irc.nickcurrent { - irc.nickcurrent = irc.nick - irc.SendRawf("NICK %s", irc.nick) - } - case <-irc.end: - ticker.Stop() - ticker2.Stop() - return - } - } -} - -// Main loop to control the connection. -func (irc *Connection) Loop() { - errChan := irc.ErrorChan() - for !irc.stopped { - err := <-errChan - if irc.stopped { - break - } - irc.Log.Printf("Error, disconnected: %s\n", err) - for !irc.stopped { - if err = irc.Reconnect(); err != nil { - irc.Log.Printf("Error while reconnecting: %s\n", err) - time.Sleep(1 * time.Second) - } else { - break - } - } - } -} - -// Quit the current connection and disconnect from the server -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1.6 -func (irc *Connection) Quit() { - irc.SendRaw("QUIT") - irc.stopped = true -} - -// Use the connection to join a given channel. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.1 -func (irc *Connection) Join(channel string) { - irc.pwrite <- fmt.Sprintf("JOIN %s\r\n", channel) -} - -// Leave a given channel. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.2 -func (irc *Connection) Part(channel string) { - irc.pwrite <- fmt.Sprintf("PART %s\r\n", channel) -} - -// Send a notification to a nickname. This is similar to Privmsg but must not receive replies. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.2 -func (irc *Connection) Notice(target, message string) { - irc.pwrite <- fmt.Sprintf("NOTICE %s :%s\r\n", target, message) -} - -// Send a formated notification to a nickname. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.2 -func (irc *Connection) Noticef(target, format string, a ...interface{}) { - irc.Notice(target, fmt.Sprintf(format, a...)) -} - -// Send (action) message to a target (channel or nickname). -// No clear RFC on this one... -func (irc *Connection) Action(target, message string) { - irc.pwrite <- fmt.Sprintf("PRIVMSG %s :\001ACTION %s\001\r\n", target, message) -} - -// Send formatted (action) message to a target (channel or nickname). -func (irc *Connection) Actionf(target, format string, a ...interface{}) { - irc.Action(target, fmt.Sprintf(format, a...)) -} - -// Send (private) message to a target (channel or nickname). -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.1 -func (irc *Connection) Privmsg(target, message string) { - irc.pwrite <- fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message) -} - -// Send formated string to specified target (channel or nickname). -func (irc *Connection) Privmsgf(target, format string, a ...interface{}) { - irc.Privmsg(target, fmt.Sprintf(format, a...)) -} - -// Kick from with . For no message, pass empty string ("") -func (irc *Connection) Kick(user, channel, msg string) { - var cmd bytes.Buffer - cmd.WriteString(fmt.Sprintf("KICK %s %s", channel, user)) - if msg != "" { - cmd.WriteString(fmt.Sprintf(" :%s", msg)) - } - cmd.WriteString("\r\n") - irc.pwrite <- cmd.String() -} - -// Kick all from with . For no message, pass -// empty string ("") -func (irc *Connection) MultiKick(users []string, channel string, msg string) { - var cmd bytes.Buffer - cmd.WriteString(fmt.Sprintf("KICK %s %s", channel, strings.Join(users, ","))) - if msg != "" { - cmd.WriteString(fmt.Sprintf(" :%s", msg)) - } - cmd.WriteString("\r\n") - irc.pwrite <- cmd.String() -} - -// Send raw string. -func (irc *Connection) SendRaw(message string) { - irc.pwrite <- message + "\r\n" -} - -// Send raw formated string. -func (irc *Connection) SendRawf(format string, a ...interface{}) { - irc.SendRaw(fmt.Sprintf(format, a...)) -} - -// Set (new) nickname. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1.2 -func (irc *Connection) Nick(n string) { - irc.nick = n - irc.SendRawf("NICK %s", n) -} - -// Determine nick currently used with the connection. -func (irc *Connection) GetNick() string { - return irc.nickcurrent -} - -// Query information about a particular nickname. -// RFC 1459: https://tools.ietf.org/html/rfc1459#section-4.5.2 -func (irc *Connection) Whois(nick string) { - irc.SendRawf("WHOIS %s", nick) -} - -// Query information about a given nickname in the server. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.5.1 -func (irc *Connection) Who(nick string) { - irc.SendRawf("WHO %s", nick) -} - -// Set different modes for a target (channel or nickname). -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.3 -func (irc *Connection) Mode(target string, modestring ...string) { - if len(modestring) > 0 { - mode := strings.Join(modestring, " ") - irc.SendRawf("MODE %s %s", target, mode) - return - } - irc.SendRawf("MODE %s", target) -} - -func (irc *Connection) ErrorChan() chan error { - return irc.Error -} - -// Returns true if the connection is connected to an IRC server. -func (irc *Connection) Connected() bool { - return !irc.stopped -} - -// A disconnect sends all buffered messages (if possible), -// stops all goroutines and then closes the socket. -func (irc *Connection) Disconnect() { - for event := range irc.events { - irc.ClearCallback(event) - } - if irc.end != nil { - close(irc.end) - } - - irc.end = nil - - if irc.pwrite != nil { - close(irc.pwrite) - } - - irc.Wait() - if irc.socket != nil { - irc.socket.Close() - } - irc.socket = nil - irc.ErrorChan() <- ErrDisconnected -} - -// Reconnect to a server using the current connection. -func (irc *Connection) Reconnect() error { - if irc.end != nil { - close(irc.end) - } - - irc.end = nil - - irc.Wait() //make sure that wait group is cleared ensuring that all spawned goroutines have completed - - irc.end = make(chan struct{}) - return irc.Connect(irc.Server) -} - -// Connect to a given server using the current connection configuration. -// This function also takes care of identification if a password is provided. -// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1 -func (irc *Connection) Connect(server string) error { - irc.Server = server - // mark Server as stopped since there can be an error during connect - irc.stopped = true - - // make sure everything is ready for connection - if len(irc.Server) == 0 { - return errors.New("empty 'server'") - } - if strings.Count(irc.Server, ":") != 1 { - return errors.New("wrong number of ':' in address") - } - if strings.Index(irc.Server, ":") == 0 { - return errors.New("hostname is missing") - } - if strings.Index(irc.Server, ":") == len(irc.Server)-1 { - return errors.New("port missing") - } - // check for valid range - ports := strings.Split(irc.Server, ":")[1] - port, err := strconv.Atoi(ports) - if err != nil { - return errors.New("extracting port failed") - } - if !((port >= 0) && (port <= 65535)) { - return errors.New("port number outside valid range") - } - if irc.Log == nil { - return errors.New("'Log' points to nil") - } - if len(irc.nick) == 0 { - return errors.New("empty 'nick'") - } - if len(irc.user) == 0 { - return errors.New("empty 'user'") - } - - if irc.UseTLS { - dialer := &net.Dialer{Timeout: irc.Timeout} - irc.socket, err = tls.DialWithDialer(dialer, "tcp", irc.Server, irc.TLSConfig) - } else { - irc.socket, err = net.DialTimeout("tcp", irc.Server, irc.Timeout) - } - if err != nil { - return err - } - - irc.stopped = false - irc.Log.Printf("Connected to %s (%s)\n", irc.Server, irc.socket.RemoteAddr()) - - irc.pwrite = make(chan string, 10) - irc.Error = make(chan error, 2) - irc.Add(3) - go irc.readLoop() - go irc.writeLoop() - go irc.pingLoop() - if len(irc.Password) > 0 { - irc.pwrite <- fmt.Sprintf("PASS %s\r\n", irc.Password) - } - irc.pwrite <- fmt.Sprintf("NICK %s\r\n", irc.nick) - irc.pwrite <- fmt.Sprintf("USER %s 0.0.0.0 0.0.0.0 :%s\r\n", irc.user, irc.user) - return nil -} - -// Create a connection with the (publicly visible) nickname and username. -// The nickname is later used to address the user. Returns nil if nick -// or user are empty. -func IRC(nick, user string) *Connection { - // catch invalid values - if len(nick) == 0 { - return nil - } - if len(user) == 0 { - return nil - } - - irc := &Connection{ - nick: nick, - nickcurrent: nick, - user: user, - Log: log.New(os.Stdout, "", log.LstdFlags), - end: make(chan struct{}), - Version: VERSION, - KeepAlive: 4 * time.Minute, - Timeout: 1 * time.Minute, - PingFreq: 15 * time.Minute, - } - irc.setupCallbacks() - return irc -} diff --git a/src/shuo-irc.com/irc/irc_callback.go b/src/shuo-irc.com/irc/irc_callback.go deleted file mode 100644 index fad0d11..0000000 --- a/src/shuo-irc.com/irc/irc_callback.go +++ /dev/null @@ -1,229 +0,0 @@ -package irc - -import ( - "crypto/sha1" - "fmt" - "math/rand" - "reflect" - "strconv" - "strings" - "time" -) - -// Register a callback to a connection and event code. A callback is a function -// which takes only an Event pointer as parameter. Valid event codes are all -// IRC/CTCP commands and error/response codes. This function returns the ID of -// the registered callback for later management. -func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) string { - eventcode = strings.ToUpper(eventcode) - - if _, ok := irc.events[eventcode]; !ok { - irc.events[eventcode] = make(map[string]func(*Event)) - } - h := sha1.New() - rawId := []byte(fmt.Sprintf("%v%d", reflect.ValueOf(callback).Pointer(), rand.Int63())) - h.Write(rawId) - id := fmt.Sprintf("%x", h.Sum(nil)) - irc.events[eventcode][id] = callback - return id -} - -// Remove callback i (ID) from the given event code. This functions returns -// true upon success, false if any error occurs. -func (irc *Connection) RemoveCallback(eventcode string, i string) bool { - eventcode = strings.ToUpper(eventcode) - - if event, ok := irc.events[eventcode]; ok { - if _, ok := event[i]; ok { - delete(irc.events[eventcode], i) - return true - } - irc.Log.Printf("Event found, but no callback found at id %s\n", i) - return false - } - - irc.Log.Println("Event not found") - return false -} - -// Remove all callbacks from a given event code. It returns true -// if given event code is found and cleared. -func (irc *Connection) ClearCallback(eventcode string) bool { - eventcode = strings.ToUpper(eventcode) - - if _, ok := irc.events[eventcode]; ok { - irc.events[eventcode] = make(map[string]func(*Event)) - return true - } - - irc.Log.Println("Event not found") - return false -} - -// Replace callback i (ID) associated with a given event code with a new callback function. -func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func(*Event)) { - eventcode = strings.ToUpper(eventcode) - - if event, ok := irc.events[eventcode]; ok { - if _, ok := event[i]; ok { - event[i] = callback - return - } - irc.Log.Printf("Event found, but no callback found at id %s\n", i) - } - irc.Log.Printf("Event not found. Use AddCallBack\n") -} - -// Execute all callbacks associated with a given event. -func (irc *Connection) RunCallbacks(event *Event) { - msg := event.Message() - if event.Code == "PRIVMSG" && len(msg) > 2 && msg[0] == '\x01' { - event.Code = "CTCP" //Unknown CTCP - - if i := strings.LastIndex(msg, "\x01"); i > 0 { - msg = msg[1:i] - } else { - irc.Log.Printf("Invalid CTCP Message: %s\n", strconv.Quote(msg)) - return - } - - if msg == "VERSION" { - event.Code = "CTCP_VERSION" - - } else if msg == "TIME" { - event.Code = "CTCP_TIME" - - } else if strings.HasPrefix(msg, "PING") { - event.Code = "CTCP_PING" - - } else if msg == "USERINFO" { - event.Code = "CTCP_USERINFO" - - } else if msg == "CLIENTINFO" { - event.Code = "CTCP_CLIENTINFO" - - } else if strings.HasPrefix(msg, "ACTION") { - event.Code = "CTCP_ACTION" - if len(msg) > 6 { - msg = msg[7:] - } else { - msg = "" - } - } - - event.Arguments[len(event.Arguments)-1] = msg - } - - if callbacks, ok := irc.events[event.Code]; ok { - if irc.VerboseCallbackHandler { - irc.Log.Printf("%v (%v) >> %#v\n", event.Code, len(callbacks), event) - } - - for _, callback := range callbacks { - go callback(event) - } - } else if irc.VerboseCallbackHandler { - irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) - } - - if callbacks, ok := irc.events["*"]; ok { - if irc.VerboseCallbackHandler { - irc.Log.Printf("Wildcard %v (%v) >> %#v\n", event.Code, len(callbacks), event) - } - - for _, callback := range callbacks { - go callback(event) - } - } -} - -// Set up some initial callbacks to handle the IRC/CTCP protocol. -func (irc *Connection) setupCallbacks() { - irc.events = make(map[string]map[string]func(*Event)) - - //Handle error events - irc.AddCallback("ERROR", func(e *Event) { irc.Disconnect() }) - - //Handle ping events - irc.AddCallback("PING", func(e *Event) { irc.SendRaw("PONG :" + e.Message()) }) - - //Version handler - irc.AddCallback("CTCP_VERSION", func(e *Event) { - irc.SendRawf("NOTICE %s :\x01VERSION %s\x01", e.Nick, irc.Version) - }) - - irc.AddCallback("CTCP_USERINFO", func(e *Event) { - irc.SendRawf("NOTICE %s :\x01USERINFO %s\x01", e.Nick, irc.user) - }) - - irc.AddCallback("CTCP_CLIENTINFO", func(e *Event) { - irc.SendRawf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", e.Nick) - }) - - irc.AddCallback("CTCP_TIME", func(e *Event) { - ltime := time.Now() - irc.SendRawf("NOTICE %s :\x01TIME %s\x01", e.Nick, ltime.String()) - }) - - irc.AddCallback("CTCP_PING", func(e *Event) { irc.SendRawf("NOTICE %s :\x01%s\x01", e.Nick, e.Message()) }) - - // 437: ERR_UNAVAILRESOURCE " :Nick/channel is temporarily unavailable" - // Add a _ to current nick. If irc.nickcurrent is empty this cannot - // work. It has to be set somewhere first in case the nick is already - // taken or unavailable from the beginning. - irc.AddCallback("437", func(e *Event) { - // If irc.nickcurrent hasn't been set yet, set to irc.nick - if irc.nickcurrent == "" { - irc.nickcurrent = irc.nick - } - - if len(irc.nickcurrent) > 8 { - irc.nickcurrent = "_" + irc.nickcurrent - } else { - irc.nickcurrent = irc.nickcurrent + "_" - } - irc.SendRawf("NICK %s", irc.nickcurrent) - }) - - // 433: ERR_NICKNAMEINUSE " :Nickname is already in use" - // Add a _ to current nick. - irc.AddCallback("433", func(e *Event) { - // If irc.nickcurrent hasn't been set yet, set to irc.nick - if irc.nickcurrent == "" { - irc.nickcurrent = irc.nick - } - - if len(irc.nickcurrent) > 8 { - irc.nickcurrent = "_" + irc.nickcurrent - } else { - irc.nickcurrent = irc.nickcurrent + "_" - } - irc.SendRawf("NICK %s", irc.nickcurrent) - }) - - irc.AddCallback("PONG", func(e *Event) { - ns, _ := strconv.ParseInt(e.Message(), 10, 64) - delta := time.Duration(time.Now().UnixNano() - ns) - if irc.Debug { - irc.Log.Printf("Lag: %vs\n", delta) - } - }) - - // NICK Define a nickname. - // Set irc.nickcurrent to the new nick actually used in this connection. - irc.AddCallback("NICK", func(e *Event) { - if e.Nick == irc.nick { - irc.nickcurrent = e.Message() - } - }) - - // 1: RPL_WELCOME "Welcome to the Internet Relay Network !@" - // Set irc.nickcurrent to the actually used nick in this connection. - irc.AddCallback("001", func(e *Event) { - irc.nickcurrent = e.Arguments[0] - }) -} - -func init() { - rand.Seed(time.Now().UnixNano()) -} diff --git a/src/shuo-irc.com/irc/irc_struct.go b/src/shuo-irc.com/irc/irc_struct.go deleted file mode 100644 index e29f377..0000000 --- a/src/shuo-irc.com/irc/irc_struct.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2009 Thomas Jager All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package irc - -import ( - "crypto/tls" - "log" - "net" - "sync" - "time" -) - -type Connection struct { - sync.WaitGroup - Debug bool - Error chan error - Password string - UseTLS bool - TLSConfig *tls.Config - Version string - Timeout time.Duration - PingFreq time.Duration - KeepAlive time.Duration - Server string - - socket net.Conn - pwrite chan string - end chan struct{} - - nick string //The nickname we want. - nickcurrent string //The nickname we currently have. - user string - registered bool - events map[string]map[string]func(*Event) - - lastMessage time.Time - - VerboseCallbackHandler bool - Log *log.Logger - - stopped bool -} - -// A struct to represent an event. -type Event struct { - Code string - Raw string - Nick string // - Host string //!@ - Source string // - User string // - Arguments []string - Connection *Connection -} - -// Retrieve the last message from Event arguments. -// This function leaves the arguments untouched and -// returns an empty string if there are none. -func (e *Event) Message() string { - if len(e.Arguments) == 0 { - return "" - } - return e.Arguments[len(e.Arguments)-1] -} diff --git a/src/shuo-irc.com/irc/irc_test.go b/src/shuo-irc.com/irc/irc_test.go deleted file mode 100644 index 7b9d856..0000000 --- a/src/shuo-irc.com/irc/irc_test.go +++ /dev/null @@ -1,258 +0,0 @@ -package irc - -import ( - "crypto/tls" - "testing" - "time" -) - -func TestConnectionEmtpyServer(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - err := irccon.Connect("") - if err == nil { - t.Fatal("emtpy server string not detected") - } -} - -func TestConnectionDoubleColon(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - err := irccon.Connect("::") - if err == nil { - t.Fatal("wrong number of ':' not detected") - } -} - -func TestConnectionMissingHost(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - err := irccon.Connect(":6667") - if err == nil { - t.Fatal("missing host not detected") - } -} - -func TestConnectionMissingPort(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - err := irccon.Connect("chat.freenode.net:") - if err == nil { - t.Fatal("missing port not detected") - } -} - -func TestConnectionNegativePort(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - err := irccon.Connect("chat.freenode.net:-1") - if err == nil { - t.Fatal("negative port number not detected") - } -} - -func TestConnectionTooLargePort(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - err := irccon.Connect("chat.freenode.net:65536") - if err == nil { - t.Fatal("too large port number not detected") - } -} - -func TestConnectionMissingLog(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - irccon.Log = nil - err := irccon.Connect("chat.freenode.net:6667") - if err == nil { - t.Fatal("missing 'Log' not detected") - } -} - -func TestConnectionEmptyUser(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - // user may be changed after creation - irccon.user = "" - err := irccon.Connect("chat.freenode.net:6667") - if err == nil { - t.Fatal("empty 'user' not detected") - } -} - -func TestConnectionEmptyNick(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - // nick may be changed after creation - irccon.nick = "" - err := irccon.Connect("chat.freenode.net:6667") - if err == nil { - t.Fatal("empty 'nick' not detected") - } -} - -func TestRemoveCallback(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - irccon.VerboseCallbackHandler = true - irccon.Debug = true - - done := make(chan int, 10) - - irccon.AddCallback("TEST", func(e *Event) { done <- 1 }) - id := irccon.AddCallback("TEST", func(e *Event) { done <- 2 }) - irccon.AddCallback("TEST", func(e *Event) { done <- 3 }) - - // Should remove callback at index 1 - irccon.RemoveCallback("TEST", id) - - irccon.RunCallbacks(&Event{ - Code: "TEST", - }) - - var results []int - - results = append(results, <-done) - results = append(results, <-done) - - if len(results) != 2 || results[0] == 2 || results[1] == 2 { - t.Error("Callback 2 not removed") - } -} - -func TestWildcardCallback(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - irccon.VerboseCallbackHandler = true - irccon.Debug = true - - done := make(chan int, 10) - - irccon.AddCallback("TEST", func(e *Event) { done <- 1 }) - irccon.AddCallback("*", func(e *Event) { done <- 2 }) - - irccon.RunCallbacks(&Event{ - Code: "TEST", - }) - - var results []int - - results = append(results, <-done) - results = append(results, <-done) - - if len(results) != 2 || !(results[0] == 1 && results[1] == 2) { - t.Error("Wildcard callback not called") - } -} - -func TestClearCallback(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - irccon.VerboseCallbackHandler = true - irccon.Debug = true - - done := make(chan int, 10) - - irccon.AddCallback("TEST", func(e *Event) { done <- 0 }) - irccon.AddCallback("TEST", func(e *Event) { done <- 1 }) - irccon.ClearCallback("TEST") - irccon.AddCallback("TEST", func(e *Event) { done <- 2 }) - irccon.AddCallback("TEST", func(e *Event) { done <- 3 }) - - irccon.RunCallbacks(&Event{ - Code: "TEST", - }) - - var results []int - - results = append(results, <-done) - results = append(results, <-done) - - if len(results) != 2 || !(results[0] == 2 && results[1] == 3) { - t.Error("Callbacks not cleared") - } -} - -func TestIRCemptyNick(t *testing.T) { - irccon := IRC("", "go-eventirc") - irccon = nil - if irccon != nil { - t.Error("empty nick didn't result in error") - t.Fail() - } -} - -func TestIRCemptyUser(t *testing.T) { - irccon := IRC("go-eventirc", "") - if irccon != nil { - t.Error("empty user didn't result in error") - } -} -func TestConnection(t *testing.T) { - irccon1 := IRC("go-eventirc1", "go-eventirc1") - irccon1.VerboseCallbackHandler = true - irccon1.Debug = true - irccon2 := IRC("go-eventirc2", "go-eventirc2") - irccon2.VerboseCallbackHandler = true - irccon2.Debug = true - err := irccon1.Connect("irc.freenode.net:6667") - if err != nil { - t.Log(err.Error()) - t.Fatal("Can't connect to freenode.") - } - err = irccon2.Connect("irc.freenode.net:6667") - if err != nil { - t.Log(err.Error()) - t.Fatal("Can't connect to freenode.") - } - irccon1.AddCallback("001", func(e *Event) { irccon1.Join("#go-eventirc") }) - irccon2.AddCallback("001", func(e *Event) { irccon2.Join("#go-eventirc") }) - con2ok := false - irccon1.AddCallback("366", func(e *Event) { - t := time.NewTicker(1 * time.Second) - i := 10 - for { - <-t.C - irccon1.Privmsgf("#go-eventirc", "Test Message%d\n", i) - if con2ok { - i -= 1 - } - if i == 0 { - t.Stop() - irccon1.Quit() - } - } - }) - - irccon2.AddCallback("366", func(e *Event) { - irccon2.Privmsg("#go-eventirc", "Test Message\n") - con2ok = true - irccon2.Nick("go-eventnewnick") - }) - - irccon2.AddCallback("PRIVMSG", func(e *Event) { - t.Log(e.Message()) - if e.Message() == "Test Message5" { - irccon2.Quit() - } - }) - - irccon2.AddCallback("NICK", func(e *Event) { - if irccon2.nickcurrent == "go-eventnewnick" { - t.Fatal("Nick change did not work!") - } - }) - go irccon2.Loop() - irccon1.Loop() -} - -func TestConnectionSSL(t *testing.T) { - irccon := IRC("go-eventirc", "go-eventirc") - irccon.VerboseCallbackHandler = true - irccon.Debug = true - irccon.UseTLS = true - irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true} - err := irccon.Connect("irc.freenode.net:7000") - if err != nil { - t.Log(err.Error()) - t.Fatal("Can't connect to freenode.") - } - irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") }) - - irccon.AddCallback("366", func(e *Event) { - irccon.Privmsg("#go-eventirc", "Test Message\n") - time.Sleep(2 * time.Second) - irccon.Quit() - }) - - irccon.Loop() -} diff --git a/src/shuo-irc.com/irc/irc_test_fuzz.go b/src/shuo-irc.com/irc/irc_test_fuzz.go deleted file mode 100644 index 82202e1..0000000 --- a/src/shuo-irc.com/irc/irc_test_fuzz.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build gofuzz - -package irc - -func Fuzz(data []byte) int { - b := bytes.NewBuffer(data) - event, err := parseToEvent(b.String()) - if err == nil { - irc := IRC("go-eventirc", "go-eventirc") - irc.RunCallbacks(event) - return 1 - } - return 0 -}