func PlusOne(conn *irc.Conn, channel string) { AutoJoin(conn, channel) conn.AddHandler("PRIVMSG", func(c *irc.Conn, l *irc.Line) { if l.Args[0] != channel { return } m := l.Args[1] if m == ".scores" { plusOneScores(c, channel) return } if !plusOneRe.MatchString(m) { return } nick := strings.Split(m, ":", 2)[0] if c.GetNick(nick) == nil { return } nick = Canonical(nick) if len(nick) == 0 { return } n := 1 if m[len(m)-2] == '-' { n = -1 } plusOneCount(nick, n) }) }
func postTitle(conn *irc.Conn, line *irc.Line, title string, prefix string) { tgt := line.Args[0] secondsAgo := cacheGetSecondsToLastPost(title) if secondsAgo <= noRepostWithinSeconds { log.Printf("Skipping, because posted %d seconds ago (“%s”)", secondsAgo, title) return } if frankconf.Verbose { log.Printf("Title was last posted: %#v (“%s”)", secondsAgo, title) } log.Printf("nick=%s, target=%s, title=%s", line.Nick, tgt, title) // if target is our current nick, it was a private message. // Answer the users in this case. if tgt == conn.Me().Nick { tgt = line.Nick } if prefix == "" { prefix = "Link Info" } else { prefix = clean(prefix) } title = clean(title) // the IRC spec states that notice should be used instead of msg // and that bots should not react to notice at all. However, no // real world bot adheres to this. Furthermore, people who can’t // configure their client to not highlight them on notices will // complain. conn.Privmsg(tgt, "["+prefix+"] "+title) }
func ban(conn *irc.Conn, nick *irc.Nick, args, target string) { channel, args := parseAccess(conn, nick, target, args, "oh") if channel == "" || args == "" { return } bans := strings.TrimSpace(args) split := strings.Fields(bans) // turn nicks into *!*@host for i, ban := range split { if strings.Index(ban, "@") != -1 { // already a host continue } n := conn.GetNick(ban) if n == nil { //couldn't find the nick, so just cross our fingers continue } split[i] = "*!*@" + n.Host } bans = strings.Join(split, " ") modestring := "+" + strings.Repeat("b", len(bans)) + " " + bans conn.Mode(channel, modestring) }
func SendMessage(conn *irc.Conn, msg string, handler UrlHandler) { if &handler != nil { conn.Privmsg(RC.Channel, fmt.Sprintf("[%s] %s", handler.Name(), msg)) } else { conn.Privmsg(RC.Channel, msg) } }
func bot_connected(irc *client.Conn, line *client.Line) { bot := getState(irc) for _, c := range bot.channels { bot.l.Info("Joining %s on startup.\n", c) irc.Join(c) } }
func Tail(conn *irc.Conn, channel, filename string, fn func(string) bool) { AutoJoin(conn, channel) f, err := os.Open(filename, 0, 0) if err != nil { log.Println(err) return } _, err = f.Seek(0, 2) if err != nil { log.Println(err) return } b := bufio.NewReader(f) go func() { for { l, err := b.ReadBytes('\n') if err != nil { if err == os.EOF { time.Sleep(1e9) b = bufio.NewReader(f) continue } log.Println(err) break } s := string(l[:len(l)-1]) if fn(s) { conn.Privmsg(channel, s) } } }() }
func RaumBang(conn *irc.Conn, line *irc.Line) { defer func() { if r := recover(); r != nil { log.Printf("MEGA-WTF:pkg: %v", r) } }() tgt := line.Args[0] msg := line.Args[1] if tgt != bangRaumChannel || !bangRaumRegex.MatchString(msg) { return } dur := time.Since(bangRaumLast) if dur.Seconds() <= 10 { log.Printf("WTF: last room stat request was %v seconds ago, skipping", dur) return } log.Printf("Received room stat request from %s\n", line.Nick) bangRaumLast = time.Now() err := exec.Command("ping", "-q", "-l 3", "-c 3", "-w 1", hostToPing).Run() if err != nil { conn.Privmsg(tgt, "Raumstatus: Die Weltnetzanfrage wurde nicht erwidert.") } else { conn.Privmsg(tgt, "Raumstatus: Ein Gerät innerhalb des Raumes beantwortet Weltnetzanfragen.") } }
func addAccess(conn *irc.Conn, channel, nick, flags string) (string, string) { n := conn.GetNick(nick) if n == nil { return "", "" } section := conn.Network + " " + channel user := user(n) cflags, _ := auth.String(section, user) nflags := cflags for _, flag := range flags { if strings.IndexRune(cflags, flag) > -1 { // already has the flag continue } nflags += string(flag) } auth.AddOption(section, user, nflags) if updateAuth() != nil { say(conn, channel, "Error while writing to %s", authFile) } return user, nflags }
func ItsAlive(conn *irc.Conn, line *irc.Line) { if line.Args[0] != conn.Me().Nick { // no private query, ignore return } msg := line.Args[1] if !strings.HasPrefix(msg, "msg ") { //~ log.Printf("unknown prefix for: %s", msg) // only accept valid commands return } if line.Nick != frankconf.Master { // only answer to master log.Printf("only answering to master %s, but was %s", frankconf.Master, line.Nick) return } cmd := strings.SplitN(msg, " ", 3) channel := cmd[1] msg = cmd[2] log.Printf("master command: posting “%s” to %s", msg, channel) conn.Privmsg(channel, msg) }
func flags(conn *irc.Conn, nick *irc.Nick, args, target string) { channel, args := parseAccess(conn, nick, target, args, "") if channel == "" { return } query := strings.TrimSpace(args) if query == "" { query = nick.Nick } n := conn.GetNick(query) if n == nil { say(conn, target, "Could not find nick %s", query) return } user := user(n) if owner, _ := auth.String(conn.Network, "owner"); owner == user { say(conn, target, "%s is the owner", user) return } flags, _ := auth.String(conn.Network+" "+channel, user) if flags == "" { say(conn, target, "%s has no flags", user) } else { say(conn, target, "%s: %s", user, flags) } }
func ignore(conn *irc.Conn, nick *irc.Nick, args, target string) { channel, args := parseAccess(conn, nick, target, args, "a") if channel == "" { return } n := conn.GetNick(strings.TrimSpace(args)) if n == nil { say(conn, target, "Could not find nick %s", args) return } if nick == n { say(conn, target, "%s: you cannot ignore yourself", nick.Nick) } owner, _ := auth.String(conn.Network, "owner") if owner == user(n) { return } if addIgnore(conn, channel, n) { say(conn, target, "Ignoring %s", n.Host) } else { say(conn, target, "%s is already ignored", n.Host) } }
// This is what generates the actual markov chain func markov(channel string, conn *irc.Conn) { markovData.mutex.RLock() var markovchain string messageLength := random(50) + 10 for i := 0; i < messageLength; i++ { splitchain := strings.Split(markovchain, " ") if len(splitchain) < 2 { s := []rune(markovData.keys[random(len(markovData.keys))]) s[0] = unicode.ToUpper(s[0]) markovchain = string(s) continue } chainlength := len(splitchain) searchfor := strings.ToLower(splitchain[chainlength-2] + " " + splitchain[chainlength-1]) if len(markovData.bigmap[searchfor]) == 0 || strings.LastIndex(markovchain, ".") < len(markovchain)-50 { s := []rune(markovData.keys[random(len(markovData.keys))]) s[0] = unicode.ToUpper(s[0]) markovchain = markovchain + ". " + string(s) continue } randnext := random(len(markovData.bigmap[searchfor])) markovchain = markovchain + " " + markovData.bigmap[searchfor][randnext] } conn.Privmsg(channel, markovchain+".") markovData.mutex.RUnlock() }
func (m *RSSModule) Init(c *irc.Conn, config json.RawMessage) { db.AutoMigrate(&RSSLastSeen{}) err := json.Unmarshal(config, &m.config) if err != nil { panic(err) } c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { // Wait a bit to lets things settle. This should be rewritten // to check for channel memebership <-time.After(30 * time.Second) for _, feed := range m.config.Feeds { if feed.URL == "" { log.WithFields(logrus.Fields{ "feed": feed, }).Error("RSS: Feed has no URL") } timeout := feed.Timeout if timeout < 1 { if m.config.Timeout < 1 { log.WithFields(logrus.Fields{ "feed": feed, }).Error("RSS: Feed has no timeout or global timeout") } timeout = m.config.Timeout } go pollFeed(c, feed, timeout) } }) }
func sendHelp(irc *client.Conn, nick string) { helpStr := ` Last.fm commands: ` + *cmdPrefix + `np ($user)?: Shows your now playing song. If you give $user, queries for that $user. ` + *cmdPrefix + `compare ($user1) ($user2)?: Runs a tasteometer compare between you and $user1, or between $user1 and $user2 if present. ` + *cmdPrefix + `top5 ((overall|year|month|week) ($user)?)?: Shows the top5 artists in the chosen period for you or the $user. ` + *cmdPrefix + `whois ($nick)?: Shows your associated last.fm username, or the username associated with $nick. ` + *cmdPrefix + `aka ($username): Shows the nicks that have been associated with $username. A nick can be used in place of a username if it's associated with a last.fm account. ` if *requireAuth { helpStr += `Commands that require that you be authenticated with NickServ:` } // There's also *cmdPrefix + "wp", but we don't document it to not encourage abuse. helpStr += ` ` + *cmdPrefix + `ignore: Makes the bot ignore you for most commands. Use ` + *cmdPrefix + `setuser or ` + *cmdPrefix + `deluser to be unignored. ` + *cmdPrefix + `setuser ($username): Associates your nick with the given last.fm $username. ` + *cmdPrefix + `deluser: Removes your nick's association, if any. ` // + *cmdPrefix + `wp: Shows what's playing for everyone in the channel.` // uncomment this at your peril :) for _, line := range helpSplit.Split(helpStr, -1) { if line != "" { irc.Notice(nick, line) } } }
func Auth(conn *irc.Conn, channel, secret string) { conn.AddHandler("353", func(c *irc.Conn, l *irc.Line) { // NAMES if l.Args[2] != channel { return } for _, nick := range strings.Split(l.Args[3], " ", -1) { if !strings.HasPrefix(nick, "@") { continue } nick = nick[1:] hash := makeHash(channel, c.Me.Nick, nick, secret) c.Privmsg(nick, ".authop "+channel+" "+hash) } }) conn.AddHandler("PRIVMSG", func(c *irc.Conn, l *irc.Line) { if strings.HasPrefix(l.Args[0], "#") { return } p := strings.Split(l.Args[1], " ", -1) if len(p) != 3 || p[0] != ".authop" || p[1] != channel { return } if p[2] != makeHash(channel, l.Nick, c.Me.Nick, secret) { return } c.Mode(channel, l.Nick+" +o") }) }
func reportIgnored(irc *client.Conn, asker, who string) { if asker == who { irc.Notice(asker, "You asked to be ignored by last.fm commands") } else { irc.Notice(asker, fmt.Sprintf("%s asked to be ignored by last.fm commands", who)) } }
func removeAccess(conn *irc.Conn, channel, nick, flags string) (string, string) { n := conn.GetNick(nick) if n == nil { return "", "" } section := conn.Network + " " + channel user := user(n) cflags, _ := auth.String(section, user) nflags := "" for _, flag := range cflags { if strings.IndexRune(flags, flag) < 0 { // we're not removing this flag nflags += string(flag) } } auth.AddOption(section, user, nflags) if updateAuth() != nil { say(conn, channel, "Error while writing to %s", authFile) } return user, nflags }
func (m *NickMap) QueryNick(irc *client.Conn, target, asker, nick string) { r := "" if user, ok := m.GetUser(nick); ok { if asker == nick { if user == "" { r = fmt.Sprintf("%s: you asked to be ignored by last.fm commands", asker) } else { r = fmt.Sprintf("%s: your ", asker) } } else { if user == "" { r = fmt.Sprintf("%s: %s has asked to be ignored by last.fm commands", asker, nick) } else { r = fmt.Sprintf("%s: %s's ", asker, nick) } } if user != "" { r += fmt.Sprintf("last.fm username is %s (http://last.fm/user/%s)", user, user) } } else { if asker == nick { r = fmt.Sprintf("%s: you ", asker) } else { r = fmt.Sprintf("%s: %s ", asker, nick) } r += fmt.Sprintf("didn't associate an username") } irc.Privmsg(target, r) return }
func channelSay(conn *irc.Conn, channel string, text string) { if debug { fmt.Printf("Channel Say fired:\n") } conn.Privmsg(channel, text) }
// Called when incoming privmsg // channel boolean evaluates true for channel privmsgs, false for bot privmsgs func eventPrivmsg(conn *irc.Conn, line *irc.Line, channel bool) { if debug { fmt.Printf("Event PrivMSG fired: [%s] [%b]\n", line, channel) } // Determine what type of privmsg it is (channel||to bot) if channel { if debug { fmt.Printf("Line args: [%s]\n", line.Args[1]) } var lastLine = strings.Split(line.Args[1], " ") if lastLine[0] == strings.ToLower("!say") { triggerSay(conn, lastLine, line.Args[0]) // why can't we pass line.Args? } if lastLine[0] == strings.ToLower("!ll") { var temp = findNickLastLine("testfile.txt", lastLine[1]) fmt.Println("line:" + temp) conn.Privmsg(line.Args[0], temp) } // Silence Bot if lastLine[0] == strings.ToLower("!muzzle") { if muzzle == false { muzzle = true channelSay(conn, line.Args[0], "Muzzle enabled") } else { muzzle = false channelSay(conn, line.Args[0], "Muzzle disabled") } fmt.Printf("Muzzle set to: [%s]\n", muzzle) } if lastLine[0] == strings.ToLower("!op") { if line.Nick != botName && line.Nick == "arti" { //TODO do op conn.Mode(line.Args[0], "+o") // do we need to add a key arg? } //TODO do unauthorized message? } /*select { case strings.ToLower("!say"): triggerSay(conn, lastLine, line.Args[0]) // why can't we pass line.Args? fallthrough default: fmt.Println("No match.") }*/ } else { // PrivMSG is to bot. if debug { fmt.Printf("Line args: [%s]\n", line.Args[1]) } //TODO bot privmsg handling } }
func (m *JNetModule) Init(c *irc.Conn, config json.RawMessage) { c.HandleBG("PRIVMSG", NewMatchAllHandler(prRegexp, m.prHandler)) err := json.Unmarshal(config, &m.config) if err != nil { panic(err) } }
func triggerSay(conn *irc.Conn, lastLine []string, channel string) { if debug { fmt.Printf("Trigger Say fired: [%s]\n", lastLine) } //TODO ponder if sanity checking is better per function or @higher level conn.Privmsg(channel, strings.Join(lastLine[1:len(lastLine)], " ")) }
func saySomething(conn *irc.Conn, channel string, ns *nonsentence.Nonsentence) { sentence, err := ns.Make() if err != nil { log.Printf("Error while making sentence: %v", err) } else { conn.Privmsg(channel, sentence) } }
func addWhoHandlers(irc *client.Conn) { if !flag.Parsed() { flag.Parse() } irc.HandleFunc("352", whoHandler) irc.HandleFunc("315", whoHandler) return }
func nick(conn *irc.Conn, nick *irc.Nick, args, target string) { if len(args) == 0 { return } owner, _ := auth.String(conn.Network, "owner") if owner == user(nick) { conn.Nick(args) } }
func eventJoin(conn *irc.Conn, line *irc.Line) { if debug { fmt.Printf("Event Join fired: [%s]\n", line) } if botName != line.Nick { conn.Notice(line.Src, line.Nick+", welcome") } }
func MessageHandler(conn *irc.Conn, line *irc.Line) { var googleRegexp = regexp.MustCompile(`\](.+?)\[`) if googleRegexp.MatchString(line.Args[1]) { for _, match := range googleRegexp.FindAllStringSubmatch(line.Args[1], -1) { conn.Notice(channel, match[1]) } } }
func printMetadataForKey(c *irc.Conn, channel string, key string) { r, _, _ := http.Get("http://gdata.youtube.com/feeds/api/videos/" + key) if r.StatusCode != http.StatusOK { return } var m Video = Video{xml.Name{}, ""} xml.Unmarshal(r.Body, &m) c.Privmsg(channel, " -> "+m.Title) }
func (m *RFCModule) Init(c *irc.Conn, config json.RawMessage) { err := json.Unmarshal(config, &m.config) if err != nil { panic(err) } go rfcFetchLoop(m.config.FetchInterval) c.HandleBG("PRIVMSG", NewMatchAllHandler(rfcRegexp, m.rfcHandler)) }
func part(conn *irc.Conn, nick *irc.Nick, args, target string) { channel, _ := parseChannel(target, args) if channel == "" { return } user := user(nick) if owner, _ := auth.String(conn.Network, "owner"); owner == user { conn.Part(channel, "") } }