160 lines
3.5 KiB
Go
160 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
"bufio"
|
|
"strings"
|
|
"database/sql"
|
|
configo "github.com/distributedio/configo"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
func sendmsg (conn net.Conn, channel string, msg string) {
|
|
mesg := fmt.Sprintf("PRIVMSG %s :%s\r\n", channel, msg)
|
|
fmt.Printf(mesg)
|
|
conn.Write([]byte(mesg))
|
|
}
|
|
|
|
func scanline_privmsg (msg string) irc_msg {
|
|
var irc irc_msg
|
|
|
|
msg = msg[1:]
|
|
t := strings.Split(msg, "!")
|
|
irc.author, irc.channel = t[0], t[1]
|
|
t = strings.Split(irc.channel, "PRIVMSG ")
|
|
irc.channel = t[1]
|
|
t = strings.Split(irc.channel, " :")
|
|
irc.channel, irc.msg = t[0], t[1]
|
|
t = strings.Split(irc.msg, "\r\n")
|
|
irc.msg = strings.TrimSpace(t[0])
|
|
if ! strings.HasPrefix(irc.channel, "#") {
|
|
irc.channel = irc.author
|
|
}
|
|
irc.retmsg = ""
|
|
return irc
|
|
}
|
|
|
|
func bot_connect(bot *bot) {
|
|
conn, err := net.Dial("tcp", (*bot).Conf.Server)
|
|
if err != nil {
|
|
LOG_ERR.Printf("Error while dialing server.")
|
|
(*bot).conn = nil
|
|
return
|
|
}
|
|
|
|
(*bot).conn = conn
|
|
fmt.Fprintf((*bot).conn, "USER %s 1 1 1:%s\r\n", (*bot).Conf.Name, (*bot).Conf.Name)
|
|
}
|
|
|
|
func bot_register(bot *bot) {
|
|
/* connect to irc */
|
|
fmt.Fprintf((*bot).conn, "NICK %s\r\n", (*bot).Conf.Name)
|
|
for _, channel := range((*bot).Conf.Channels) {
|
|
fmt.Fprintf((*bot).conn, "JOIN %s\r\n", channel)
|
|
}
|
|
}
|
|
|
|
func bot_listen(bot *bot) <-chan string {
|
|
c := make(chan string)
|
|
bot_register(bot)
|
|
|
|
go func(timeoutNormal time.Duration, timeoutVersion time.Duration) {
|
|
bufReader := bufio.NewReader((*bot).conn)
|
|
|
|
timeoutDuration := timeoutNormal
|
|
waitversion := false
|
|
|
|
defer func() {
|
|
fmt.Println("Closing connection...")
|
|
close(c)
|
|
(*bot).conn.Close()
|
|
}()
|
|
|
|
for {
|
|
(*bot).conn.SetReadDeadline(time.Now().Add(timeoutDuration))
|
|
|
|
line, err := bufReader.ReadString('\n')
|
|
if err != nil {
|
|
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
|
fmt.Printf("Timeout!\n")
|
|
if waitversion {
|
|
fmt.Println("VERSION command did not return.")
|
|
return
|
|
}
|
|
|
|
n, err := (*bot).conn.Write([]byte("VERSION\n"))
|
|
fmt.Printf("n: %d, err: %s\n", n, err)
|
|
if err != nil {
|
|
fmt.Println("Writing to channel failed.")
|
|
return
|
|
}
|
|
// wait for return value of VERSION
|
|
waitversion = true
|
|
timeoutDuration = timeoutVersion
|
|
} else {
|
|
fmt.Println("Some more serious error occured while reading.")
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
|
|
// not waiting for version answer right now
|
|
timeoutDuration = timeoutNormal
|
|
waitversion = false
|
|
c <- line
|
|
|
|
if strings.Contains(line, "PING") {
|
|
(*bot).conn.Write([]byte(strings.Replace(line, "PING", "PONG", 1)))
|
|
} else if strings.Contains(line, "You have not registered") {
|
|
// set nickname
|
|
time.Sleep(10 * time.Second)
|
|
bot_register(bot)
|
|
} else if strings.Contains(line, "PRIVMSG") {
|
|
msg := scanline_privmsg(line)
|
|
parsemsg(&msg, (*bot))
|
|
if msg.retmsg != "" {
|
|
sendmsg((*bot).conn, msg.channel, msg.retmsg)
|
|
}
|
|
}
|
|
}
|
|
} (4 * time.Minute, 1 * time.Minute)
|
|
|
|
return c
|
|
}
|
|
|
|
func bot_run(bot *bot) {
|
|
LOG_INFO.Println("Bot ready to run.")
|
|
|
|
LOG_INFO.Println("Opening database.")
|
|
db, err = sql.Open("sqlite3", (*bot).Conf.Database)
|
|
if err != nil {
|
|
LOG_ERR.Println("Opening database failed.")
|
|
return
|
|
}
|
|
|
|
for {
|
|
bot_connect(bot)
|
|
if bot.conn == nil {
|
|
LOG_INFO.Printf("Bot is nil. Try to connect again.")
|
|
time.Sleep(10 * time.Second)
|
|
continue
|
|
}
|
|
for val := range bot_listen(bot) {
|
|
LOG_INFO.Printf("%s", val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
LOG_init()
|
|
|
|
var boddle bot
|
|
if err := configo.Load("./boddle.toml", &boddle.Conf); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
bot_run(&boddle)
|
|
}
|