func tellCheck(ctx *bot.Context) { nick := ctx.Nick if ctx.Cmd == client.NICK { // We want the destination nick, not the source. nick = ctx.Target() } r := rc.TellsFor(nick) for i := range r { if ctx.Cmd == client.NICK { if r[i].Chan != "" { ctx.Privmsg(string(r[i].Chan), nick+": "+r[i].Reply()) } ctx.Reply("%s", r[i].Reply()) } else { ctx.Privmsg(ctx.Nick, r[i].Reply()) if r[i].Chan != "" { ctx.ReplyN("%s", r[i].Reply()) } } rc.RemoveId(r[i].Id) } if len(r) > 0 { delete(listed, ctx.Nick) } }
func randomCmd(ctx *bot.Context) { if len(ctx.Text()) == 0 { ctx.ReplyN("Be who? Your mum?") return } whom := strings.ToLower(strings.Fields(ctx.Text())[0]) if whom == strings.ToLower(ctx.Me()) { ctx.ReplyN("Ha, you're funny. No, wait. Retarded... I meant retarded.") return } if !shouldMarkov(whom) { if whom == strings.ToLower(ctx.Nick) { ctx.ReplyN("You're not recording markov data. " + "Use 'markov me' to enable collection.") } else { ctx.ReplyN("Not recording markov data for %s.", ctx.Text()) } return } source := mc.Source("user:"******"%s would say: %s", ctx.Text(), out) } else { ctx.ReplyN("markov error: %v", err) } }
func recordKick(ctx *bot.Context) { n, c := ctx.Storable() kn := bot.Nick(ctx.Text()) // seenNickFromLine doesn't work with the hacks for KICKING and KICKED // First, handle KICKING kr := sc.LastSeenDoing(ctx.Nick, "KICKING") if kr == nil { kr = seen.SawNick(n, c, "KICKING", ctx.Args[2]) } else { kr.Nick, kr.Chan = n, c kr.Timestamp, kr.Text = time.Now(), ctx.Args[2] } kr.OtherNick = kn _, err := sc.Upsert(kr.Id(), kr) if err != nil { ctx.Reply("Failed to store seen data: %v", err) } // Now, handle KICKED ke := sc.LastSeenDoing(ctx.Text(), "KICKED") if ke == nil { ke = seen.SawNick(kn, c, "KICKED", ctx.Args[2]) } else { ke.Nick, ke.Chan = kn, c ke.Timestamp, ke.Text = time.Now(), ctx.Args[2] } ke.OtherNick = n _, err = sc.Upsert(ke.Id(), ke) if err != nil { ctx.Reply("Failed to store seen data: %v", err) } }
func urlScan(ctx *bot.Context) { words := strings.Split(ctx.Text(), " ") n, c := ctx.Storable() for _, w := range words { if util.LooksURLish(w) { if u := uc.GetByUrl(w); u != nil { if u.Nick != bot.Nick(ctx.Nick) && time.Since(u.Timestamp) > 2*time.Hour { ctx.Reply("that URL first mentioned by %s %s ago", u.Nick, util.TimeSince(u.Timestamp)) } continue } u := urls.NewUrl(w, n, c) if len(w) > autoShortenLimit && ctx.Public() { u.Shortened = Encode(w) } if err := uc.Insert(u); err != nil { ctx.ReplyN("Couldn't insert url '%s': %s", w, err) continue } if u.Shortened != "" { ctx.Reply("%s's URL shortened as %s%s%s", ctx.Nick, bot.HttpHost(), shortenPath, u.Shortened) } lastseen[ctx.Target()] = u.Id } } }
func topten(ctx *bot.Context) { top := sc.TopTen(ctx.Target()) s := make([]string, 0, 10) for i, n := range top { s = append(s, fmt.Sprintf("#%d: %s - %d", i+1, n.Nick, n.Lines)) } ctx.Reply("%s", strings.Join(s, ", ")) }
func recordJoin(ctx *bot.Context) { sn := seenNickFromLine(ctx) if len(ctx.Args) > 1 { // If we have a PART message sn.Text = ctx.Text() } if _, err := sc.Upsert(sn.Id(), sn); err != nil { ctx.Reply("Failed to store seen data: %v", err) } }
func recordPrivmsg(ctx *bot.Context) { if !ctx.Public() { return } sn := seenNickFromLine(ctx) sn.Text = ctx.Text() if _, err := sc.Upsert(sn.Id(), sn); err != nil { ctx.Reply("Failed to store seen data: %v", err) } }
func fetch(ctx *bot.Context) { if RateLimit(ctx.Nick) { return } qid, err := strconv.Atoi(ctx.Text()) if err != nil { ctx.ReplyN("'%s' doesn't look like a quote id.", ctx.Text()) return } quote := qc.GetByQID(qid) if quote != nil { ctx.Reply("#%d: %s", quote.QID, quote.Quote) } else { ctx.ReplyN("No quote found for id %d", qid) } }
func lookup(ctx *bot.Context) { if RateLimit(ctx.Nick) { return } quote := qc.GetPseudoRand(ctx.Text()) if quote == nil { ctx.ReplyN("No quotes matching '%s' found.", ctx.Text()) return } // TODO(fluffle): qd should take care of updating Accessed internally quote.Accessed++ if err := qc.Update(bson.M{"_id": quote.Id}, quote); err != nil { ctx.ReplyN("I failed to update quote #%d: %s", quote.QID, err) } ctx.Reply("#%d: %s", quote.QID, quote.Quote) }
func recordStats(ctx *bot.Context) { ns := sc.StatsFor(ctx.Nick, ctx.Target()) if ns == nil { n, c := ctx.Storable() ns = stats.NewStat(n, c) } ns.Update(ctx.Text()) if ns.Lines%10000 == 0 { ctx.Reply("%s has said %d lines in this channel and "+ "should now shut the f**k up and do something useful", ctx.Nick, ns.Lines) } if _, err := sc.Upsert(ns.Id(), ns); err != nil { ctx.Reply("Failed to store stats data: %v", err) } }
func lookup(ctx *bot.Context) { // Only perform extra prefix removal if we weren't addressed directly key := ToKey(ctx.Text(), !ctx.Addressed) var fact *factoids.Factoid if fact = fc.GetPseudoRand(key); fact == nil && ctx.Cmd == client.ACTION { // Support sp0rkle's habit of stripping off it's own nick // but only for actions, not privmsgs. if strings.HasSuffix(key, ctx.Me()) { key = strings.TrimSpace(key[:len(key)-len(ctx.Me())]) fact = fc.GetPseudoRand(key) } } if fact == nil { return } // Chance is used to limit the rate of factoid replies for things // people say a lot, like smilies, or 'lol', or 'i love the peen'. chance := fact.Chance if key == "" { // This is doing a "random" lookup, triggered by someone typing in // something entirely composed of the chars stripped by ToKey(). // To avoid making this too spammy, forcibly limit the chance to 40%. chance = 0.4 } if rand.Float64() < chance { // Store this as the last seen factoid LastSeen(ctx.Target(), fact.Id) // Update the Accessed field // TODO(fluffle): fd should take care of updating Accessed internally fact.Access(ctx.Storable()) // And store the new factoid data if err := fc.Update(bson.M{"_id": fact.Id}, fact); err != nil { ctx.ReplyN("I failed to update '%s' (%s): %s ", fact.Key, fact.Id, err) } recurse(fact, map[string]bool{key: true}) switch fact.Type { case factoids.F_ACTION: ctx.Do("%s", fact.Value) default: ctx.Reply("%s", fact.Value) } } }
func smoke(ctx *bot.Context) { if !smokeRx.MatchString(ctx.Text()) { return } sn := sc.LastSeenDoing(ctx.Nick, "SMOKE") n, c := ctx.Storable() if sn != nil { ctx.ReplyN("You last went for a smoke %s ago...", util.TimeSince(sn.Timestamp)) sn.Nick, sn.Chan = n, c sn.Timestamp = time.Now() } else { sn = seen.SawNick(n, c, "SMOKE", "") } if _, err := sc.Upsert(sn.Id(), sn); err != nil { ctx.Reply("Failed to store smoke data: %v", err) } }
func recordKarma(ctx *bot.Context) { // Karma can look like some.text.string++ or (text with spaces)-- // and there could be multiple occurrences of it in a string. nick, _ := ctx.Storable() for _, kt := range karmaThings(ctx.Text()) { k := kc.KarmaFor(kt.thing) if k == nil { k = karma.New(kt.thing) } if kt.plus { k.Plus(nick) } else { k.Minus(nick) } if _, err := kc.Upsert(k.Id(), k); err != nil { ctx.Reply("Failed to insert Karma: %s", err) } } }
func insult(ctx *bot.Context) { source := mc.Source("tag:insult") whom, lc := ctx.Text(), strings.ToLower(ctx.Text()) if lc == strings.ToLower(ctx.Me()) || lc == "yourself" { ctx.ReplyN("Ha, you're funny. No, wait. Retarded... I meant retarded.") return } if lc == "me" { whom = ctx.Nick } if out, err := chain.Sentence(source); err == nil { if len(whom) > 0 { ctx.Reply("%s: %s", whom, out) } else { ctx.Reply("%s", out) } } else { ctx.ReplyN("markov error: %v", err) } }
// remind list func list(ctx *bot.Context) { r := rc.RemindersFor(ctx.Nick) c := len(r) if c == 0 { ctx.ReplyN("You have no reminders set.") return } if c > 5 && ctx.Public() { ctx.ReplyN("You've got lots of reminders, ask me privately.") return } // Save an ordered list of ObjectIds for easy reminder deletion ctx.ReplyN("You have %d reminders set:", c) list := make([]bson.ObjectId, c) for i := range r { ctx.Reply("%d: %s", i+1, r[i].List(ctx.Nick)) list[i] = r[i].Id } listed[ctx.Nick] = list }
func urbanDictionary(ctx *bot.Context) { entry, ok, err := cache.fetch(strings.ToLower(ctx.Text())) if err != nil { ctx.ReplyN("ud request failed: %s", err) return } cached, r := "", entry.result if ok { cached = fmt.Sprintf(", result cached at %s", datetime.Format(entry.stamp)) } if r.Total == 0 || r.Type == "no_results" { ctx.ReplyN("%s isn't defined yet%s.", ctx.Text(), cached) return } // Cycle through all the definitions on repeated calls for the same term r.Pages = (r.Pages + 1) % r.Total def := r.List[r.Pages] ctx.Reply("[%d/%d] %s (%d up, %d down%s)", r.Pages+1, r.Total, strings.Replace(def.Definition, "\r\n", " ", -1), def.Upvotes, def.Downvotes, cached) }