2009-11-18 15:03:14 +00:00
|
|
|
// Copyright 2009 Thomas Jager <mail@jager.no> All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2009-11-18 00:28:12 +00:00
|
|
|
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 {
|
2009-11-21 23:05:12 +00:00
|
|
|
fmt.Printf("%s\n", err);
|
2009-11-18 00:28:12 +00:00
|
|
|
irc.perror <- err;
|
2009-11-22 21:01:47 +00:00
|
|
|
return;
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
irc.pread <- msg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func writer(irc *IRCConnection) {
|
|
|
|
for {
|
|
|
|
b := strings.Bytes(<-irc.pwrite);
|
|
|
|
_, err := irc.socket.Write(b);
|
|
|
|
if err != nil {
|
2009-11-21 23:05:12 +00:00
|
|
|
fmt.Printf("%s\n", err);
|
|
|
|
irc.perror <- err;
|
2009-11-22 21:01:47 +00:00
|
|
|
return;
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-25 19:21:47 +00:00
|
|
|
func reconnector(i *IRCConnection) {
|
|
|
|
fmt.Printf("Reconnecting\n");
|
|
|
|
for {
|
|
|
|
i.Error = connect(i);
|
|
|
|
if i.Error == nil {
|
2009-11-25 19:22:06 +00:00
|
|
|
return
|
2009-11-25 19:21:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-18 00:28:12 +00:00
|
|
|
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")
|
2009-11-18 15:26:23 +00:00
|
|
|
var rx_server_cmd = regexp.MustCompile("^([^:]+) :(.*)\r\n") //AUTH NOTICE, PING, ERROR
|
2009-11-18 00:28:12 +00:00
|
|
|
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":
|
2009-11-18 15:26:23 +00:00
|
|
|
e.Code = IRC_JOIN
|
2009-11-18 00:28:12 +00:00
|
|
|
case "MODE":
|
2009-11-18 15:26:23 +00:00
|
|
|
e.Code = IRC_CHAN_MODE
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
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":
|
2009-11-18 15:26:23 +00:00
|
|
|
e.Code = IRC_CHAN_NICKLIST
|
2009-11-18 00:28:12 +00:00
|
|
|
case "332":
|
2009-11-18 15:26:23 +00:00
|
|
|
e.Code = IRC_CHAN_TOPIC
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
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 {
|
2009-11-18 15:26:23 +00:00
|
|
|
switch matches[1] {
|
|
|
|
case "NOTICE AUTH":
|
2009-11-18 00:28:12 +00:00
|
|
|
e.Code = IRC_NOTICE_AUTH;
|
|
|
|
e.Message = matches[2];
|
2009-11-18 15:26:23 +00:00
|
|
|
case "PING":
|
|
|
|
e.Code = IRC_PING;
|
|
|
|
e.Message = matches[2];
|
2009-11-25 19:22:06 +00:00
|
|
|
// case "ERROR":
|
|
|
|
// e.Code = IRC_PING;
|
|
|
|
// e.Message = matches[2];
|
|
|
|
// e.Error = os.ErrorString(matches[2]);
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
2009-11-18 15:26:23 +00:00
|
|
|
return e;
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
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_PING:
|
|
|
|
irc.pwrite <- fmt.Sprintf("PONG %s\r\n", e.Message)
|
|
|
|
case IRC_PRIVMSG:
|
|
|
|
if e.Message == "\x01VERSION\x01" {
|
2009-11-18 15:26:23 +00:00
|
|
|
irc.pwrite <- fmt.Sprintf("NOTICE %s :\x01VERSION GolangBOT (tj)\x01\r\n", e.Sender)
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-18 15:26:23 +00:00
|
|
|
|
2009-11-18 00:28:12 +00:00
|
|
|
irc.EventChan <- e;
|
|
|
|
case error := <-irc.perror:
|
2009-11-21 23:05:12 +00:00
|
|
|
fmt.Printf("Piped error: %s\n", error);
|
2009-11-18 00:28:12 +00:00
|
|
|
ee := new(IRCEvent);
|
|
|
|
ee.Error = error;
|
|
|
|
ee.Code = ERROR;
|
|
|
|
irc.EventChan <- ee;
|
2009-11-27 10:57:42 +00:00
|
|
|
reconnector(irc);
|
2009-11-18 00:28:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (irc *IRCConnection) Join(channel string) {
|
|
|
|
irc.pwrite <- fmt.Sprintf("JOIN %s\r\n", channel)
|
|
|
|
}
|
|
|
|
|
2009-11-18 15:26:23 +00:00
|
|
|
func (irc *IRCConnection) Notice(target, message string) {
|
|
|
|
irc.pwrite <- fmt.Sprintf("NOTICE %s :%s\r\n", target, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (irc *IRCConnection) Privmsg(target, message string) {
|
|
|
|
irc.pwrite <- fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message)
|
|
|
|
}
|
|
|
|
|
2009-11-25 18:17:08 +00:00
|
|
|
//Try to reconnect
|
|
|
|
func (irc *IRCConnection) Reconnect() os.Error {
|
|
|
|
irc.socket, irc.Error = net.Dial("tcp", "", irc.server);
|
|
|
|
if irc.Error != nil {
|
|
|
|
return irc.Error
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2009-11-25 19:21:47 +00:00
|
|
|
func connect(i *IRCConnection) os.Error {
|
|
|
|
fmt.Printf("Connecting to %s\n", i.server);
|
|
|
|
i.socket, i.Error = net.Dial("tcp", "", i.server);
|
|
|
|
if i.Error != nil {
|
|
|
|
return i.Error
|
|
|
|
}
|
|
|
|
fmt.Printf("Connected to %s (%s)\n", i.server, i.socket.RemoteAddr());
|
2009-11-27 10:57:42 +00:00
|
|
|
i.pread = make(chan string, 100);
|
|
|
|
i.pwrite = make(chan string, 100);
|
|
|
|
i.perror = make(chan os.Error, 10);
|
|
|
|
go reader(i);
|
|
|
|
go writer(i);
|
2009-11-25 19:21:47 +00:00
|
|
|
i.pwrite <- fmt.Sprintf("NICK %s\r\n", i.nick);
|
|
|
|
i.pwrite <- fmt.Sprintf("USER %s 0.0.0.0 0.0.0.0 :GolangBOT\r\n", i.user);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2009-11-18 00:28:12 +00:00
|
|
|
func IRC(server string, nick string, user string, events chan *IRCEvent) (*IRCConnection, os.Error) {
|
|
|
|
irc := new(IRCConnection);
|
2009-11-25 18:17:08 +00:00
|
|
|
irc.server = server;
|
2009-11-18 00:28:12 +00:00
|
|
|
irc.registered = false;
|
|
|
|
irc.pread = make(chan string, 100);
|
|
|
|
irc.pwrite = make(chan string, 100);
|
2009-11-21 23:05:12 +00:00
|
|
|
irc.perror = make(chan os.Error, 10);
|
2009-11-18 00:28:12 +00:00
|
|
|
irc.EventChan = events;
|
|
|
|
irc.nick = nick;
|
|
|
|
irc.user = user;
|
2009-11-25 19:21:47 +00:00
|
|
|
connect(irc);
|
2009-11-18 00:28:12 +00:00
|
|
|
go handler(irc);
|
|
|
|
return irc, nil;
|
|
|
|
}
|