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 (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 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 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 channelSay(conn *irc.Conn, channel string, text string) { if debug { fmt.Printf("Channel Say fired:\n") } conn.Privmsg(channel, text) }
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 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 connected(conn *irc.Conn, line *irc.Line) { println("Connected!") conn.Pass(config.Password) conn.Join(config.Channel) conn.Privmsg(config.Channel, "¡Saludos!") constantlyReadTwitter(conn) }
// 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() }
// 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 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 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 respond(conn *irc.Conn, line *irc.Line) { if strings.EqualFold(line.Args[0], "#candlepin") { msg := strings.ToLower(line.Args[1]) if strings.Contains(msg, "over 9000") || strings.Contains(msg, "over nine thousand") { conn.Privmsg("#candlepin", "WHAT?! NINE THOUSAND?!") } } }
func (m *Privmsg) respond(includeToNick bool, conn *irc.Conn, format string, args ...interface{}) { msg := fmt.Sprintf(format, args...) if m.Public() { if includeToNick { msg = fmt.Sprintf("%s: %s", m.Nick, msg) } conn.Privmsg(m.Channel, msg) } else { conn.Privmsg(m.Nick, msg) } }
func say(conn *irc.Conn, target, message string, a ...interface{}) { if len(a) > 0 { message = fmt.Sprintf(message, a...) } text := strings.Replace(message, "\n", " ", -1) if isChannel(target) { conn.Privmsg(target, text) } else { conn.Notice(target, text) } }
func plusOneScores(c *irc.Conn, channel string) { plusOneLock.Lock() defer plusOneLock.Unlock() var buf bytes.Buffer for nick, score := range plusOneMap { if buf.Len() > 0 { fmt.Fprint(&buf, ", ") } fmt.Fprintf(&buf, "%s %d", nick, score) } c.Privmsg(channel, buf.String()) }
func CatMsgSender(ch chan CatMsg, client *irc.Conn) { defaultChan := "#rjtest" for { cm := <-ch if len(cm.To) == 0 { client.Privmsg(defaultChan, cm.Msg) } else { for _, to := range cm.To { client.Privmsg(to, cm.Msg) } } } }
func doTheBreak(conn *irc.Conn, myCommand *exec.Cmd, stdoutPipe io.ReadCloser, urlToUse string) { thisFlag := new(Flag) // grab stdout var err error stdout := bufio.NewReader(stdoutPipe) if err != nil { log.Printf("Hit a snag whilst getting the stdoutpipe: %s\n", err.Error()) conn.Privmsg("lukegb", "Oops - something went wrong finding the flag. Maybe some other time. Error getting pipe: "+err.Error()) conn.Privmsg("#level8-bonus", "!leave") return } // now we just keep reading for { lineComplete := false lineStr := "" for !lineComplete { lineBytes, isPrefix, err := stdout.ReadLine() if err == io.EOF { return } lineStr += string(lineBytes) lineComplete = !isPrefix } log.Printf("%s: REPORTED %s\n", urlToUse, lineStr) if strings.HasPrefix(lineStr, "STARTED") { thisFlag.BeganAt = time.Now() } else if strings.HasPrefix(lineStr, "BROKE ") { // now we tell them, but not much :) lineBits := strings.Split(lineStr, " ") //actualNumberInt64, err := strconv.ParseInt(lineBits[2], 10, 0) // tell luke conn.Privmsg("lukegb", "Broke chunk: "+lineBits[1]) } else if strings.HasPrefix(lineStr, "BROKE_ALL ") { lineBits := strings.Split(lineStr, " ") //sendPublicMessage(conn, replyTo, theirNick, serverId, userId, "All your flag are belong to me! My badly optimized code did it in "+strconv.FormatInt(int64(thisFlag.Duration.Seconds()), 10)+"s, too.") conn.Privmsg(flagServ, lineBits[1]) break } else if strings.HasPrefix(lineStr, "INVALID_URL") { //sendPublicMessage(conn, replyTo, theirNick, serverId, userId, "'"+urlToUse+"' doesn't seem like a valid flag URL.") conn.Privmsg("lukegb", "I think FlagServ sent me an invalid URL: "+urlToUse) break } } myCommand.Wait() stdoutPipe.Close() }
func ui(con *irc.Conn, in chan string) { curr_chan := "" for input := range in { if input[0] == '/' { // is a command var cmd string cmdend := strings.Index(input, " ") if cmdend > 0 { cmd = input[:cmdend] } else { cmd = input } switch cmd { case "/join": if len(input) > cmdend { channel := input[cmdend+1:] if channel[0] != '#' { channel = "#" + channel } curr_chan = channel con.Join(channel) } else { fmt.Println("Please specify the channel") } case "/quit": fmt.Println("Bye!") con.Quit() case "/goto": curr_chan = input[cmdend+1:] case "/list": break case "/nick": if cmdend > 0 { con.Nick(input[cmdend+1:]) } else { fmt.Println("Too few arguments") } default: fmt.Println("Unknown command") } fmt.Printf("\n%s: ", curr_chan) } else { con.Privmsg(curr_chan, input) fmt.Printf("%s: ", curr_chan) } } fmt.Println("Closing connection. kthxbai!") con.Quit() }
// Called when somebody writes some message to the IRC channel. func handleMessage(conn *irc.Conn, line *irc.Line) { msg := line.Args[1] if line.Args[0] != *irc_channel { log.Printf(`Ignoring private message to me: "%s"`, msg) return } log.Printf("Received: *%s* says: \n", line.Nick) // Ignore messages from bots. if isBot(line.Nick) { log.Printf("Ignoring message, %s is a bot", line.Nick) return } // Count every line as activity. my_histogram.LogActivity(line.Nick) // Check for greetings and say hello. if len(msg) < 10 && containsGreeting(msg) { if (time.Now().Unix() - lastGreetingTime.Unix()) < 30 { log.Printf("Not replying, 30 seconds have not passed yet") return } log.Printf(`Replying to line "%s"`, msg) lastGreetingTime = time.Now() go func() { // Reply after a random time, at least 1s after the // original line, at most 5s after the original line. fuzz := rand.Int63n(4000) time.Sleep((time.Duration)(1000+fuzz) * time.Millisecond) conn.Privmsg(*irc_channel, "hello!") }() return } // Otherwise, see if that was a question. if !strings.HasSuffix(strings.TrimSpace(msg), "?") { return } log.Printf(`Got question "%s" from "%s"`, msg, line.Nick) // See if we have enough data points about the activity of this channel for // this day and hour. if my_histogram.IsActive() { return } log.Printf("Telling user to be patient\n") }
// Try and grab the title for any URL's posted in the channel func sendUrl(channel, postedUrl string, conn *irc.Conn) { log.Println("Fetching title for " + postedUrl + " In channel " + channel) if !httpRegex.MatchString(postedUrl) { postedUrl = "http://" + postedUrl } resp, err := http.Get(postedUrl) if err != nil { log.Println(err) return } defer resp.Body.Close() if resp.StatusCode >= 400 { log.Println("http server return error.") return } // This is necessary because if you do an ioutil.ReadAll() it will // block until the entire thing is read... which could be painful buf := make([]byte, 1024) respbody := []byte{} for i := 0; i < 30; i++ { n, err := resp.Body.Read(buf) if err != nil && err != io.EOF { return } if n == 0 { break } respbody = append(respbody, buf[:n]...) } stringbody := string(respbody) titlestart := strings.Index(stringbody, "<title>") titleend := strings.Index(stringbody, "</title>") if titlestart != -1 && titlestart != -1 { title := string(respbody[titlestart+7 : titleend]) title = strings.TrimSpace(title) if title != "" { parsedurl, err := url.Parse(postedUrl) if err == nil { // This should only be the google.com in google.com/search&q=blah postedUrl = parsedurl.Host } // Example: // Title: sadbox . org (at sadbox.org) title = "Title: " + html.UnescapeString(title) + " (at " + postedUrl + ")" log.Println(title) conn.Privmsg(channel, title) } } }
// Fetch a random picture from one of Haata's keyboard sets func haata(channel string, conn *irc.Conn) { flickrUrl, err := url.Parse(flickrApiUrl) if err != nil { log.Println(err) return } v := flickrUrl.Query() v.Set("method", "flickr.collections.getTree") v.Set("api_key", config.FlickrAPIKey) // triplehaata's user_id v.Set("user_id", "57321699@N06") // Only the keyboard pics v.Set("collection_id", "57276377-72157635417889224") flickrUrl.RawQuery = v.Encode() sets, err := htmlfetch(flickrUrl.String()) if err != nil { log.Println(err) return } var setresp Setresp xml.Unmarshal(sets, &setresp) randsetindex := random(len(setresp.Sets)) randset := setresp.Sets[randsetindex].Id flickrUrl, err = url.Parse(flickrApiUrl) if err != nil { log.Println(err) return } v = flickrUrl.Query() v.Set("method", "flickr.photosets.getPhotos") v.Set("api_key", config.FlickrAPIKey) v.Set("photoset_id", randset) flickrUrl.RawQuery = v.Encode() pics, err := htmlfetch(flickrUrl.String()) if err != nil { log.Println(err) return } var photoresp Photoresp xml.Unmarshal(pics, &photoresp) randpic := random(len(photoresp.Photos)) // flickr's short url's are encoded using base58... this seems messy // Maybe use the proper long url? photostring := string(base58.EncodeBig([]byte{}, big.NewInt(photoresp.Photos[randpic].Id))) conn.Privmsg(channel, strings.TrimSpace(setresp.Sets[randsetindex].Title)+`: http://flic.kr/p/`+photostring) }
func handle_command(conn *irc.Conn, line *irc.Line, args []string) { command := args[0][len(RC.CmdPrefix):] args = args[1:] st := conn.StateTracker() authed := RC.Authed[line.Nick] if line.Nick == RC.Owner && authed { // Owner-only commands if command == "mock" { for _, n := range args { _, is_on := st.IsOn(RC.Channel, n) if is_on { RC.Mocking[n] = true conn.Privmsg(RC.Channel, "Now mocking "+n) } } } else if command == "unmock" { for _, n := range args { if RC.Mocking[n] { RC.Mocking[n] = false conn.Privmsg(RC.Channel, "No longer mocking "+n) } } } else if command == "shorten" { fmt.Println("unimplemented") } else if command == "snoop" { fmt.Println("unimplemented") } } else if (RC.Ops[line.Nick] || line.Nick == RC.Owner) && authed { // Ops-level commands if command == "poop" { conn.Privmsg(RC.Channel, "poop") } } else if command == "identify" && !line.Public() { fmt.Println("User " + line.Nick + " attempting to auth...") h := sha256.New() h.Write([]byte(args[0])) pwd_hash := hex.EncodeToString(h.Sum(nil)) if (line.Nick == RC.Owner || RC.Ops[line.Nick]) && RC.Password == pwd_hash { fmt.Println("Auth succeeded for " + line.Nick) RC.Authed[line.Nick] = true conn.Privmsg(line.Nick, "You're authenticated now.") } else { fmt.Println("WARNING: Auth failed for " + line.Nick + "!") conn.Privmsg(line.Nick, "You f****d up.") } } }
func constantlyReadTwitter(conn *irc.Conn) { twitter, err := readTwitter() // twitter.go defer constantlyReadTwitter(conn) defer time.Sleep(10 * time.Second) if err != nil { println(err) return } for _, tweet := range twitter.Results { if tweet.New { conn.Privmsg(config.Channel, "@"+tweet.From_user+": \""+tweet.Text+"\"") conn.Privmsg(config.Channel, tweet.URL) } } }
func Lmgtfy(conn *irc.Conn, line *irc.Line) { tgt := line.Args[0] msg := line.Args[1] if tgt[0:1] != "#" { // only answer to this in channels return } post := extractPost(msg) if post != "" { conn.Privmsg(tgt, post) } }
// listen on a zmq SUB socket and forward messages // to the IRC connection func zmqToIrcLoop(conn *irc.Conn, subsocket zmq.Socket) { var m Message for { err := receiveZmqMessage(subsocket, &m) if err != nil { // just ignore any invalid messages continue } if m.MessageType != "message" { conn.Privmsg(CHANNEL, "["+m.Content+"]") } else { ircmessage := fmt.Sprintf("%s: %s", m.Nick, m.Content) conn.Privmsg(CHANNEL, ircmessage) } } }
func googSearch(channel, query string, conn *irc.Conn) { query = strings.TrimSpace(query[7:]) if query == "" { conn.Privmsg(channel, "Example: !search stuff and junk") return } searchUrl, err := url.Parse("https://google.com/search") if err != nil { panic(err) } v := searchUrl.Query() v.Set("q", query) v.Set("btnI", "1") searchUrl.RawQuery = v.Encode() conn.Privmsg(channel, searchUrl.String()) }
func (m *NickMap) IgnoreNick(irc *client.Conn, target, nick string) (err error) { log.Println("Adding", nick, "to ignored list") identified := checkIdentified(irc, nick) if !identified { irc.Privmsg(target, fmt.Sprintf("%s: you must be identified with NickServ to use this command", nick)) log.Println("Nick", nick, "is not identified, and identity verification is enabled") e := NickMapError("nick is not identified") return &e } m.Lock() m.setUser(nick, "") saveNickMap() m.Unlock() r := fmt.Sprintf("[%s] is now ignored by last.fm commands; use %sdeluser to be unignored", nick, *cmdPrefix) log.Println(r) irc.Privmsg(target, r) return nil }
func (m *NickMap) ListAllNicks(irc *client.Conn, target, asker, user string) { if user == "" { return } r := "" if nicks, ok := m.reverseMap[strings.ToLower(user)]; !ok || len(nicks) == 0 { r = fmt.Sprintf("%s: %s has no associated IRC nick", asker, user) } else { plural := "s are" if len(nicks) == 1 { plural = " is" } r = fmt.Sprintf("%s: %s's known IRC nick%s %s", asker, user, plural, strings.Join(sort.StringSlice(nicks), ", ")) } log.Println(r) irc.Privmsg(target, r) return }