package main import ( "container/ring" "flag" "fmt" "log" "sort" "strings" "time" "dim13.org/rss" "dim13.org/theo" irc "github.com/fluffle/goirc/client" ) var ( server = flag.String("server", "irc.rusnet.org.ru:6660", "IRC Server") room = flag.String("room", "#lor", "IRC Channel") name = flag.String("name", "mincom", "Bots Name") ) const ( lor = `https://www.linux.org.ru/section-rss.jsp?section=1` undeadly = `http://undeadly.org/cgi?action=rss` ) type Commander interface { irc.Handler fmt.Stringer } type ( Last string News string BSD string Theo string Help string Metar string ) var ( commands = make(map[string]Commander) buffer = ring.New(10) ) func Register(cmd string, f Commander) { commands[cmd] = f } func (v Last) String() string { return string(v) } func (_ Last) Handle(conn *irc.Conn, line *irc.Line) { buffer.Do(func(v interface{}) { if v != nil { l := v.(*irc.Line) s := fmt.Sprintf("%v <%v> %v", l.Time.Format(time.Kitchen), l.Nick, l.Text()) conn.Privmsg(line.Nick, s) } }) } func (v Theo) String() string { return string(v) } func (_ Theo) Handle(conn *irc.Conn, line *irc.Line) { conn.Privmsg(line.Target(), theo.Theo()) } func (v News) String() string { return string(v) } func (_ News) Handle(conn *irc.Conn, line *irc.Line) { news, err := rss.Fetch(lor) if err != nil { conn.Privmsg(line.Target(), err.Error()) return } if line.Public() { news.Channel.Items = news.Channel.Items[:3] } for n, i := range news.Channel.Items { s := fmt.Sprintf("%2d. %v", n+1, i.Title) conn.Privmsg(line.Target(), s) } } func (v BSD) String() string { return string(v) } func (_ BSD) Handle(conn *irc.Conn, line *irc.Line) { news, err := rss.Fetch(undeadly) if err != nil { conn.Privmsg(line.Target(), err.Error()) return } if line.Public() { news.Channel.Items = news.Channel.Items[:3] } for n, i := range news.Channel.Items { s := fmt.Sprintf("%2d. %v", n+1, i.Title) conn.Privmsg(line.Target(), s) } } func (v Help) String() string { return string(v) } func (_ Help) Handle(conn *irc.Conn, line *irc.Line) { var msg []string for k, v := range commands { msg = append(msg, fmt.Sprintf("%-8s%v", k, v)) } sort.Sort(sort.StringSlice(msg)) for _, s := range msg { conn.Privmsg(line.Target(), s) } } func (v Metar) String() string { return string(v) } func (_ Metar) Handle(conn *irc.Conn, line *irc.Line) { f := strings.Fields(line.Text()) if len(f) > 1 { var m []string var err error if line.Public() { m, err = MetarStation(f[1]) } else { m, err = MetarDecoded(f[1]) } if err != nil { conn.Privmsg(line.Target(), err.Error()) return } for _, s := range m { conn.Privmsg(line.Target(), s) } } } func privmsg(conn *irc.Conn, line *irc.Line) { log.Println(line) f := strings.Fields(line.Text()) if line.Public() && line.Nick != conn.Me().Nick { buffer.Value = line buffer = buffer.Next() } // lookup command if len(f) > 0 { if c, ok := commands[f[0]]; ok { c.Handle(conn, line) } } // extract single link and fetch title for _, v := range f { if strings.HasPrefix(v, "http") { if t, err := FetchTitle(v); err == nil { conn.Privmsg(line.Target(), t) } } } } func init() { flag.Parse() Register("last", Last("return last 10 messages")) Register("theo", Theo("Quote Theo De Raadt")) Register("news", News("LOR news (msg private to see all)")) Register("bsd", BSD("Undeadly news (msg private to see all)")) Register("help", Help("This help")) Register("metar", Metar("Weather (argument: ICAO-Code, msg private for verbose output)")) } func main() { c := irc.SimpleClient(*name) c.EnableStateTracking() quit := make(chan bool) c.HandleFunc(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) { quit <- true }) c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { conn.Join(*room) }) c.HandleFunc(irc.PRIVMSG, privmsg) if err := c.ConnectTo(*server); err != nil { log.Fatal(err) } <-quit }