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 *irc_msg) { LOG_ERR.Printf(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 = "" } 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") { var msg irc_msg scanline_privmsg(line, &msg) LOG_ERR.Printf(msg.author) 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) }