commit 1c060814f37c594419a233f1d0d828157e921dda Author: tj Date: Wed Nov 18 01:28:12 2009 +0100 first diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5ced1cf --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all: + 8g irc.go irc_struct.go + 8g test.go + 8l -o test test.8 + +clean: + rm *.8 *.6 test diff --git a/irc.go b/irc.go new file mode 100644 index 0000000..c5ce5ff --- /dev/null +++ b/irc.go @@ -0,0 +1,207 @@ +package irc + +import ( + "fmt"; + "net"; + "os"; + "bufio"; + "regexp"; + "strings"; +) + + +func reader(irc *IRCConnection) { + br := bufio.NewReader(irc.socket); + for { + msg, err := br.ReadString('\n'); + if err != nil { + irc.perror <- err; + return; + } + irc.pread <- msg; + } +} + +func writer(irc *IRCConnection) { + for { + b := strings.Bytes(<-irc.pwrite); + _, err := irc.socket.Write(b); + fmt.Printf("<-- %s", b); + if err != nil { + irc.perror <- err + } + } +} + +var rx_server_msg = regexp.MustCompile("^:([^ ]+) ([^ ]+) ([^ ]+) :(.*)\r\n") +var rx_server_msg_c = regexp.MustCompile("^:([^ ]+) ([^ ]+) ([^ ]+) [@]* ([^ ]+) :(.*)\r\n") +var rx_server_msg_p = regexp.MustCompile("^:([^ ]+) ([^ ]+) ([^ ]+) (.*)\r\n") +var rx_server_cmd = regexp.MustCompile("^([^:]+) :(.*)\r\n") //AUTH NOTICE, PING +var rx_user_action = regexp.MustCompile("^:([^!]+)!([^@]+)@([^ ]+) ([^ ]+) [:]*(.*)\r\n") +var rx_user_msg = regexp.MustCompile("^:([^!]+)!([^@]+)@([^ ]+) ([^ ]+) ([^ ]+) :(.*)\r\n") + +func (irc *IRCConnection) handle_command(msg string) *IRCEvent { + e := new(IRCEvent); + e.RawMessage = msg; + if matches := rx_user_msg.MatchStrings(msg); len(matches) == 7 { + e.Sender = matches[1]; + e.SenderUser = matches[2]; + e.SenderHost = matches[3]; + e.Message = matches[6]; + e.Target = matches[5]; + switch matches[4] { + case "PRIVMSG": + e.Code = IRC_PRIVMSG + case "ACTION": + e.Code = IRC_ACTION + } + return e; + } else if matches := rx_user_action.MatchStrings(msg); len(matches) == 6 { + e.Sender = matches[1]; + e.SenderUser = matches[2]; + e.SenderHost = matches[3]; + e.Message = matches[5]; + e.Target = matches[5]; + e.Channel = matches[5]; + switch matches[4] { + case "JOIN": + e.Code = IRC_JOIN; + case "MODE": + e.Code = IRC_CHAN_MODE; + } + return e; + } else if matches := rx_server_msg_c.MatchStrings(msg); len(matches) == 6 { + e.Sender = matches[1]; + e.Target = matches[3]; + e.Channel = matches[4]; + e.Message = matches[5]; + switch matches[2] { + case "366": + e.Code = IRC_CHAN_NICKLIST; + case "332": + e.Code = IRC_CHAN_TOPIC; + } + return e; + } else if matches := rx_server_msg.MatchStrings(msg); len(matches) == 5 { + e.Sender = matches[1]; + e.Target = matches[3]; + e.Message = matches[4]; + switch matches[2] { + case "001": + e.Code = IRC_WELCOME + case "002": + e.Code = IRC_SERVER_INFO + case "003": + e.Code = IRC_SERVER_UPTIME + case "250": + e.Code = IRC_STAT_USERS + case "251": + e.Code = IRC_STAT_USERS + case "255": + e.Code = IRC_STAT_USERS + case "372": + e.Code = IRC_MOTD + case "375": + e.Code = IRC_START_MOTD + case "376": + e.Code = IRC_END_MOTD + case "MODE": + e.Code = IRC_MODE + } + return e; + } else if matches := rx_server_msg_p.MatchStrings(msg); len(matches) == 5 { + e.Sender = matches[1]; + e.Target = matches[3]; + e.Message = matches[4]; + switch matches[2] { + case "252": + e.Code = IRC_STAT_OPERS + case "253": + e.Code = IRC_STAT_UNKN + case "254": + e.Code = IRC_STAT_CONNS + case "265": + e.Code = IRC_STAT_USERS + case "266": + e.Code = IRC_STAT_USERS + case "004": + e.Code = IRC_SERVER_VERSION + case "005": + e.Code = IRC_CHANINFO + case "332": + e.Code = IRC_CHAN_TIMESTAMP + case "353": + e.Code = IRC_CHAN_NICKLIST + } + return e; + } else if matches := rx_server_cmd.MatchStrings(msg); len(matches) == 3 { + if matches[1] == "NOTICE AUTH" { + e.Code = IRC_NOTICE_AUTH; + e.Message = matches[2]; + return e; + } else if matches[1] == "PING" { + e.Code = IRC_PING; + e.Message = matches[2]; + return e; + } + } + e.Message = msg; + e.Code = UNKNOWN; + return e; +} + +func handler(irc *IRCConnection) { + go reader(irc); + go writer(irc); + for { + select { + case msg := <-irc.pread: + e := irc.handle_command(msg); + switch e.Code { + case IRC_NOTICE_AUTH: + if irc.registered == false { + irc.pwrite <- fmt.Sprintf("NICK %s\r\n", irc.nick); + irc.pwrite <- fmt.Sprintf("USER %s 0.0.0.0 0.0.0.0 :GolangBOT\r\n", irc.user); + irc.registered = true; + } + case IRC_PING: + irc.pwrite <- fmt.Sprintf("PONG %s\r\n", e.Message) + case IRC_PRIVMSG: + if e.Message == "\x01VERSION\x01" { + irc.pwrite <- fmt.Sprintf("NOTICE %s :\x01VERSION GolangBOT (tj)\x01\r\n", e.Sender); + } + } + + irc.EventChan <- e; + case error := <-irc.perror: + ee := new(IRCEvent); + ee.Error = error; + ee.Code = ERROR; + irc.EventChan <- ee; + } + } +} + +func (irc *IRCConnection) Join(channel string) { + irc.pwrite <- fmt.Sprintf("JOIN %s\r\n", channel) +} + +func IRC(server string, nick string, user string, events chan *IRCEvent) (*IRCConnection, os.Error) { + irc := new(IRCConnection); + + irc.socket, irc.Error = net.Dial("tcp", "", server); + if irc.Error != nil { + return nil, irc.Error + } + irc.registered = false; + irc.pread = make(chan string, 100); + irc.pwrite = make(chan string, 100); + irc.perror = make(chan os.Error); + irc.EventChan = events; + irc.nick = nick; + irc.user = user; + go handler(irc); + return irc, nil; +} + + diff --git a/irc_struct.go b/irc_struct.go new file mode 100644 index 0000000..2d68d32 --- /dev/null +++ b/irc_struct.go @@ -0,0 +1,63 @@ +package irc + +import ( + "os"; + "net"; +) + +type IRCEventCode int +const ( + IRC_NOTICE_AUTH IRCEventCode = 1 << iota; + IRC_PING; + IRC_QUIT; + IRC_WELCOME; + IRC_SERVER_INFO; + IRC_SERVER_UPTIME; + IRC_SERVER_VERSION; + IRC_START_MOTD; + IRC_MOTD; + IRC_END_MOTD; + IRC_CHANINFO; + + IRC_STAT_USERS; + IRC_STAT_OPERS; + IRC_STAT_UNKN; + IRC_STAT_CONNS; + + IRC_CHAN_TIMESTAMP; + IRC_CHAN_NICKLIST; + IRC_CHAN_TOPIC; + IRC_CHAN_MODE; + + IRC_PRIVMSG; + IRC_ACTION; + IRC_JOIN; + + IRC_MODE; + + ERROR; + UNKNOWN; +) + +type IRCConnection struct { + socket net.Conn; + pread, pwrite chan string; + perror chan os.Error; + EventChan chan *IRCEvent; + Error os.Error; + nick string; + user string; + registered bool; +} + +type IRCEvent struct { + Message string; + RawMessage string; + Sender string; + SenderHost string; + SenderUser string; + Target string; + Channel string; + Code IRCEventCode; + Error os.Error; +} diff --git a/test.go b/test.go new file mode 100644 index 0000000..e25ff14 --- /dev/null +++ b/test.go @@ -0,0 +1,40 @@ +package main + +import ( + "./irc"; + "fmt"; + "os"; +) + +func main() { + events := make(chan *irc.IRCEvent, 100); + irccon, err := irc.IRC("irc.efnet.net:6667", "testgo", "testgo", events); + if err != nil { + fmt.Printf("%s\n", err); + fmt.Printf("%#v\n", irccon); + os.Exit(1); + } + for { + event := <-events; +/* switch event.Code { + case UNKNOWN: + fmt.Printf("%#v\n", event) + case 0: + fmt.Printf("%#v\n", event) + case IRC_PRIVMSG: + fmt.Printf("%#v\n", event) + case IRC_CHAN_TOPIC: + fmt.Printf("%#v\n", event) + case IRC_CHAN_MODE: + fmt.Printf("%#v\n", event) + case IRC_ACTION: + fmt.Printf("%#v\n", event) + case IRC_WELCOME: + irc.Join("#ggpre") + }*/ + if event.Code == irc.IRC_WELCOME { + irccon.Join("#ggpre") + } + fmt.Printf("%#v\n", event); + } +}