Exemple #1
0
// Associates an already known nick with an already known channel.
func (st *stateTracker) Associate(ch *Channel, nk *Nick) *ChanPrivs {
	if ch == nil || nk == nil {
		logging.Error("Tracker.Associate(): passed nil values :-(")
		return nil
	} else if _ch, ok := st.chans[ch.Name]; !ok || ch != _ch {
		// As we can implicitly delete both nicks and channels from being
		// tracked by dissociating one from the other, we should verify that
		// we're not being passed an old Nick or Channel.
		logging.Error("Tracker.Associate(): channel %s not found in "+
			"(or differs from) internal state.", ch.Name)
		return nil
	} else if _nk, ok := st.nicks[nk.Nick]; !ok || nk != _nk {
		logging.Error("Tracker.Associate(): nick %s not found in "+
			"(or differs from) internal state.", nk.Nick)
		return nil
	} else if _, ok := nk.IsOn(ch); ok {
		logging.Warn("Tracker.Associate(): %s already on %s.",
			nk.Nick, ch.Name)
		return nil
	}
	cp := new(ChanPrivs)
	ch.addNick(nk, cp)
	nk.addChannel(ch, cp)
	return cp
}
Exemple #2
0
// Dissociates an already known nick from an already known channel.
// Does some tidying up to stop tracking nicks we're no longer on
// any common channels with, and channels we're no longer on.
func (st *stateTracker) Dissociate(ch *Channel, nk *Nick) {
	if ch == nil || nk == nil {
		logging.Error("Tracker.Dissociate(): passed nil values :-(")
	} else if _ch, ok := st.chans[ch.Name]; !ok || ch != _ch {
		// As we can implicitly delete both nicks and channels from being
		// tracked by dissociating one from the other, we should verify that
		// we're not being passed an old Nick or Channel.
		logging.Error("Tracker.Dissociate(): channel %s not found in "+
			"(or differs from) internal state.", ch.Name)
	} else if _nk, ok := st.nicks[nk.Nick]; !ok || nk != _nk {
		logging.Error("Tracker.Dissociate(): nick %s not found in "+
			"(or differs from) internal state.", nk.Nick)
	} else if _, ok := nk.IsOn(ch); !ok {
		logging.Warn("Tracker.Dissociate(): %s not on %s.",
			nk.Nick, ch.Name)
	} else if nk == st.me {
		// I'm leaving the channel for some reason, so it won't be tracked.
		st.delChannel(ch)
	} else {
		// Remove the nick from the channel and the channel from the nick.
		ch.delNick(nk)
		nk.delChannel(ch)
		if len(nk.chans) == 0 {
			// We're no longer in any channels with this nick.
			st.delNick(nk)
		}
	}
}
Exemple #3
0
func githubWatcher(ctx *bot.Context) {
	// Watch #sp0rklf for IRC messages about issues coming from github.
	if ctx.Nick != "fluffle\\sp0rkle" || ctx.Target() != "#sp0rklf" ||
		!strings.Contains(ctx.Text(), "issue #") {
		return
	}

	text := util.RemoveColours(ctx.Text()) // srsly github why colours :(
	l := &util.Lexer{Input: text}
	l.Find(' ')
	text = text[l.Pos()+1:]
	l.Find('#')
	l.Next()
	issue := int(l.Number())

	labels, _, err := gh.Issues.ListLabelsByIssue(
		githubUser, githubRepo, issue, &github.ListOptions{})
	if err != nil {
		logging.Error("Error getting labels for issue %d: %v", issue, err)
		return
	}
	for _, l := range labels {
		kv := strings.Split(*l.Name, ":")
		if len(kv) == 2 && kv[0] == "nick" {
			logging.Debug("Recording tell for %s about issue %d.", kv[1], issue)
			r := reminders.NewTell("that "+text, bot.Nick(kv[1]), "github", "")
			if err := rc.Insert(r); err != nil {
				logging.Error("Error inserting github tell: %v", err)
			}
		}
	}
}
Exemple #4
0
func (cs *commandSet) Add(cmd Command, prefix string) {
	if cmd == nil || prefix == "" {
		logging.Error("Can't handle prefix '%s' with command.", prefix)
		return
	}
	cs.Lock()
	defer cs.Unlock()
	if _, ok := cs.set[prefix]; ok {
		logging.Error("Prefix '%s' already registered.", prefix)
		return
	}
	cs.set[prefix] = cmd
}
Exemple #5
0
func (cs *commandSet) Add(r Runner, prefix string) {
	if r == nil || prefix == "" {
		logging.Error("Prefix or runner empty when adding command.", prefix)
		return
	}
	cs.Lock()
	defer cs.Unlock()
	if _, ok := cs.set[prefix]; ok {
		logging.Error("Prefix '%s' already registered.", prefix)
		return
	}
	cs.set[prefix] = r
}
Exemple #6
0
func Init() *Collection {
	uc := &Collection{db.Init().C(collection)}
	err := uc.EnsureIndex(mgo.Index{Key: []string{"url"}, Unique: true})
	if err != nil {
		logging.Error("Couldn't create url index on sp0rkle.urls: %s", err)
	}
	for _, idx := range []string{"cachedas", "shortened"} {
		err := uc.EnsureIndex(mgo.Index{Key: []string{idx}})
		if err != nil {
			logging.Error("Couldn't create %s index on sp0rkle.urls: %s", idx, err)
		}
	}
	return uc
}
Exemple #7
0
func Init() *Collection {
	kc := &Collection{db.Init().C(COLLECTION)}
	if err := kc.EnsureIndex(mgo.Index{
		Key:    []string{"key"},
		Unique: true,
	}); err != nil {
		logging.Error("Couldn't create index on karma.key: %s", err)
	}
	for _, key := range []string{"score", "votes"} {
		if err := kc.EnsureIndexKey(key); err != nil {
			logging.Error("Couldn't create index on karma.%s: %s", key, err)
		}
	}
	return kc
}
Exemple #8
0
func (m *Module) checkMatchers(regexes map[*regexp.Regexp]v8.V8Function, target string, line string, from string) (responded bool) {
	// Activate callback on any matches
	for regex, fn := range regexes {
		matches := regex.FindStringSubmatch(line)
		match, _ := json.Marshal(matches)

		if len(matches) > 0 {
			responded = true

			go func(match string, fn v8.V8Function) {
				// Clone a response object
				m.response++
				m.Context.Eval(`var response` + strconv.Itoa(m.response) + ` = clone(response);`)

				// Set response parameters
				m.Context.Eval(`response` + strconv.Itoa(m.response) + `.match = ` + match)
				m.Context.Eval(`response` + strconv.Itoa(m.response) + `.target = "` + target + `";`)
				m.Context.Eval(`response` + strconv.Itoa(m.response) + `.nick = "` + m.Client.Me().Nick + `"; 
								response` + strconv.Itoa(m.response) + `.message = {}; 
								response` + strconv.Itoa(m.response) + `.message.nick = "` + from + `"; 
								response` + strconv.Itoa(m.response) + `.message.text = "` + line + `"`)

				_, err := fn.Call(v8.V8Object{`response` + strconv.Itoa(m.response)})
				if err != nil {
					log.Error("%s\n%s", err, fn)
				}
			}(string(match), fn)
		}
	}

	return
}
Exemple #9
0
func (hs *hSet) remove(hn *hNode) {
	hs.Lock()
	defer hs.Unlock()
	l, ok := hs.set[hn.event]
	if !ok {
		logging.Error("Removing node for unknown event '%s'", hn.event)
		return
	}
	if hn.next == nil {
		l.end = hn.prev
	} else {
		hn.next.prev = hn.prev
	}
	if hn.prev == nil {
		l.start = hn.next
	} else {
		hn.prev.next = hn.next
	}
	hn.next = nil
	hn.prev = nil
	hn.set = nil
	if l.start == nil || l.end == nil {
		delete(hs.set, hn.event)
	}
}
Exemple #10
0
func Init() {
	lock.Lock()
	defer lock.Unlock()
	if irc != nil {
		return
	}

	if *server == "" {
		// Don't call logging.Fatal as we don't want a backtrace in this case
		logging.Error("--server option required. \nOptions are:\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	// Configure IRC client
	irc = client.SimpleClient(*nick, "boing", "not really sp0rkle")
	irc.SSL = *ssl
	irc.Flood = true

	HandleFunc(bot_connected, "connected")
	HandleFunc(bot_disconnected, "disconnected")

	// This is a special handler that dispatches commands from the command set
	HandleFunc(bot_command, "privmsg")
	// This is a special handler that triggers a rebuild and re-exec
	HandleFunc(bot_rebuild, "notice")
	// This is a special handler that triggers a shutdown and disconnect
	HandleFunc(bot_shutdown, "notice")

	CommandFunc(bot_help, "help", "If you need to ask, you're beyond help.")
}
Exemple #11
0
func (sc *Collection) TopTen(ch string) []*NickStat {
	var res []*NickStat
	q := sc.Find(bson.M{"chan": ch}).Sort("-lines").Limit(10)
	if err := q.All(&res); err != nil {
		logging.Error("TopTen Find error for channel %s: %v", ch, err)
	}
	return res
}
Exemple #12
0
func Init() {
	bot.Command(urbanDictionary, "ud", "ud <term>  -- "+
		"Look up <term> on UrbanDictionary.")

	mcConf = conf.Ns("mc")
	srv := mcConf.String(mcServer)
	if srv != "" {
		if st, err := pollServer(srv); err == nil {
			logging.Info("Starting MC poller for '%s'", srv)
			bot.Poll(st)
			bot.Handle(func(ctx *bot.Context) {
				st.Topic(ctx)
			}, "332")
		} else {
			logging.Error("Not starting MC poller: %v", err)
		}
	}
	bot.Command(mcSet, "mc set", "mc set <key> <value>  -- "+
		"Set minecraft server polling config vars.")
	// TODO(fluffle): Polling can only be en/disabled at reconnect.
	//	bot.Command(mcPoll, "mc poll", "mc poll start|stop  -- "+
	//		"Enable or disable minecraft server polling.")

	if *githubToken != "" {
		rc = reminders.Init()
		gh = githubClient()

		bot.Handle(githubWatcher, client.PRIVMSG)

		bot.Command(githubCreateIssue, "file bug:", "file bug: <title>. "+
			"<descriptive body>  -- Files a bug on GitHub. Abusers will be hurt.")
		bot.Command(githubCreateIssue, "file bug", "file bug <title>. "+
			"<descriptive body>  -- Files a bug on GitHub. Abusers will be hurt.")
		bot.Command(githubCreateIssue, "report bug", "report bug <title>. "+
			"<descriptive body>  -- Files a bug on GitHub. Abusers will be hurt.")
		bot.Command(githubUpdateIssue, "update bug #", "update bug #<number> "+
			"<comment>  -- Adds a comment to bug <number>. Abusers will be hurt.")
	}

	if push.Enabled() {
		pc = pushes.Init()
		bot.Command(pushEnable, "push enable", "push enable  -- "+
			"Start the OAuth flow to enable pushbullet notifications.")
		bot.Command(pushDisable, "push disable", "push disable  -- "+
			"Disable pushbullet notifications and delete tokens.")
		bot.Command(pushConfirm, "push auth", "push auth <pin>  -- "+
			"Confirm pushed PIN to finish pushbullet auth dance.")
		bot.Command(pushAddAlias, "push add alias", "push add alias  -- "+
			"Add a push alias for your nick.")
		bot.Command(pushDelAlias, "push del alias", "push del alias  -- "+
			"Delete a push alias for your nick.")

		http.HandleFunc("/oauth/auth", pushAuthHTTP)
		http.HandleFunc("/oauth/device", pushDeviceHTTP)
		http.HandleFunc("/oauth/success", pushSuccessHTTP)
		http.HandleFunc("/oauth/failure", pushFailureHTTP)
	}
}
Exemple #13
0
func (st *stateTracker) delNick(nk *Nick) {
	if nk == st.me {
		// Shouldn't get here => internal state tracking code is fubar.
		logging.Error("Tracker.DelNick(): TRYING TO DELETE ME :-(")
		return
	}
	delete(st.nicks, nk.Nick)
	for ch, _ := range nk.chans {
		nk.delChannel(ch)
		ch.delNick(nk)
		if len(ch.nicks) == 0 {
			// Deleting a nick from tracking shouldn't empty any channels as
			// *we* should be on the channel with them to be tracking them.
			logging.Error("Tracker.delNick(): deleting nick %s emptied "+
				"channel %s, this shouldn't happen!", nk.Nick, ch.Name)
		}
	}
}
Exemple #14
0
// Wrapper to get hold of a factoid collection handle
func Init() *Collection {
	mc := &Collection{db.Mongo.C(COLLECTION).Mongo()}
	if err := mc.EnsureIndex(mgo.Index{
		Key: []string{"tag", "source", "dest"},
	}); err != nil {
		logging.Error("Couldn't create an index on markov: %s", err)
	}
	return mc
}
Exemple #15
0
func (rc *Collection) TellsFor(nick string) []*Reminder {
	nick = strings.ToLower(nick)
	q := rc.Find(bson.M{"$and": []bson.M{{"tell": true}, {"to": nick}}})
	ret := make([]*Reminder, 0)
	if err := q.All(&ret); err != nil {
		logging.Error("Loading tells for %s returned error: %v", nick, err)
		return nil
	}
	return ret
}
Exemple #16
0
func (rc *Collection) RemindersFor(nick string) []*Reminder {
	nick = strings.ToLower(nick)
	q := rc.Find(bson.M{"$or": []bson.M{{"from": nick}, {"to": nick}}})
	q.Sort("remindat")
	ret := make([]*Reminder, 0)
	if err := q.All(&ret); err != nil {
		logging.Error("Loading reminders for %s returned error: %v", nick, err)
		return nil
	}
	return ret
}
Exemple #17
0
// Wrapper to get hold of a factoid collection handle
func Init() *Collection {
	fc := &Collection{
		Collection: db.Mongo.C(COLLECTION).Mongo(),
		seen:       make(map[string][]bson.ObjectId),
	}
	err := fc.EnsureIndex(mgo.Index{Key: []string{"key"}})
	if err != nil {
		logging.Error("Couldn't create index on sp0rkle.factoids: %v", err)
	}
	return fc
}
Exemple #18
0
func Init() *Collection {
	rc := &Collection{
		Collection: db.Init().C(COLLECTION),
	}
	for _, k := range []string{"remindat", "from", "to", "tell"} {
		if err := rc.EnsureIndexKey(k); err != nil {
			logging.Error("Couldn't create %s index on sp0rkle.reminders: %v", k, err)
		}
	}
	return rc
}
Exemple #19
0
func (b *boltDatabase) doBackup() {
	fn := path.Join(b.dir, fmt.Sprintf("sp0rkle.boltdb.%s.gz",
		time.Now().Format("2006-01-02.15:04")))
	fh, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		logging.Error("Could not create backup file %q: %v", fn, err)
		return
	}
	fz := gzip.NewWriter(fh)
	defer fz.Close()
	err = b.db.View(func(tx *bolt.Tx) error {
		return tx.Copy(fz)
	})
	if err != nil {
		logging.Error("Could not write backup file %q: %v", fn, err)
		os.Remove(fn)
		return
	}
	logging.Info("Wrote backup to %q.", fn)
}
Exemple #20
0
func _httpclient_get(args ...interface{}) interface{} {
	url := strings.Trim(args[0].(string), `"`)

	// Initialize client
	client := &http.Client{}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	// Set request headers
	var headers map[string]string
	err = json.Unmarshal([]byte(args[1].(string)), &headers)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	for header, value := range headers {
		req.Header.Add(header, value)
	}

	// Send request
	resp, err := client.Do(req)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	// Get response
	defer resp.Body.Close()
	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	return string(bytes)
}
Exemple #21
0
func Ns(ns string) namespace {
	lock.Lock()
	defer lock.Unlock()
	if conf == nil {
		conf = db.Init().C(COLLECTION)
		err := conf.EnsureIndex(mgo.Index{Key: []string{"ns", "key"}, Unique: true})
		if err != nil {
			logging.Error("Couldn't create index on sp0rkle.conf: %s", err)
		}
	}
	return namespace(ns)
}
Exemple #22
0
func connect(c *irc.Conn, server string, password string, exiting chan bool) {
	err := c.ConnectTo(server, password)
	if err != nil {
		log.Error(err.Error())

		log.Info("Unable to connect to server")

		exiting <- true
	} else {
		log.Info(c.String())
	}
}
Exemple #23
0
func (mc *Collection) incUses(source, dest, tag string) {
	link := mc.Get(source, dest, tag)
	if link == nil {
		link = New(source, dest, tag)
	}
	link.Uses++

	if _, err := mc.UpsertId(link.Id, link); err != nil {
		logging.Error("Failed to insert MarkovLink %s(%s->%s): %s",
			tag, source, dest, err)
	}
}
Exemple #24
0
func (rc *Collection) LoadAndPrune() []*Reminder {
	// First, drop any reminders where RemindAt < time.Now()
	ci, err := rc.RemoveAll(bson.M{"$and": []bson.M{
		{"remindat": bson.M{"$lt": time.Now()}},
		{"tell": false},
	}})
	if err != nil {
		logging.Error("Pruning reminders returned error: %v", err)
	}
	if ci.Removed > 0 {
		logging.Info("Removed %d old reminders", ci.Removed)
	}
	// Now, load the remainder; the db is just used for persistence
	q := rc.Find(bson.M{"tell": false})
	ret := make([]*Reminder, 0)
	if err := q.All(&ret); err != nil {
		logging.Error("Loading reminders returned error: %v", err)
		return nil
	}
	return ret
}
Exemple #25
0
func Init() *Collection {
	sc := &Collection{db.Init().C(COLLECTION)}
	indexes := [][]string{
		{"key", "action"}, // For searching ...
		{"timestamp"},     // ... and ordering seen entries.
	}
	for _, key := range indexes {
		if err := sc.EnsureIndex(mgo.Index{Key: key}); err != nil {
			logging.Error("Couldn't create %v index on sp0rkle.seen: %v", key, err)
		}
	}
	return sc
}
Exemple #26
0
func Forget(id bson.ObjectId, stop bool) {
	c, ok := running[id]
	if ok {
		// If it's *not* in running, it's probably a Tell.
		delete(running, id)
		if stop {
			c <- struct{}{}
		}
	}
	if err := rc.RemoveId(id); err != nil {
		logging.Error("Failure removing reminder %s: %v", id, err)
	}
}
Exemple #27
0
func Init() *Collection {
	sc := &Collection{db.Init().C(COLLECTION)}
	indexes := [][]string{
		{"chan", "key"},
		{"lines"},
	}
	for _, key := range indexes {
		if err := sc.EnsureIndex(mgo.Index{Key: key}); err != nil {
			logging.Error("Couldn't create %v index on sp0rkle.stats: %v", key, err)
		}
	}
	return sc
}
Exemple #28
0
// Write a \r\n terminated line of output to the connected server,
// using Hybrid's algorithm to rate limit if conn.cfg.Flood is false.
func (conn *Conn) write(line string) {
	if !conn.cfg.Flood {
		if t := conn.rateLimit(len(line)); t != 0 {
			// sleep for the current line's time value before sending it
			logging.Debug("irc.rateLimit(): Flood! Sleeping for %.2f secs.",
				t.Seconds())
			<-time.After(t)
		}
	}

	if _, err := conn.io.WriteString(line + "\r\n"); err != nil {
		logging.Error("irc.send(): %s", err.Error())
		conn.shutdown()
		return
	}
	if err := conn.io.Flush(); err != nil {
		logging.Error("irc.send(): %s", err.Error())
		conn.shutdown()
		return
	}
	logging.Debug("-> %s", line)
}
Exemple #29
0
func Forget(id bson.ObjectId, stop bool) {
	c, ok := running[id]
	if !ok {
		return
	}
	delete(running, id)
	if stop {
		c <- true
	}
	if err := rc.RemoveId(id); err != nil {
		logging.Error("Failure removing reminder %s: %v", id, err)
	}
}
Exemple #30
0
func connectLoop() bool {
	var retries uint32
	for {
		if err := irc.Connect(*server); err != nil {
			logging.Error("Connection error: %s", err)
			retries++
			if retries > 10 {
				logging.Error("Giving up connection after 10 failed retries.")
				return false
			}
			<-time.After(time.Second * 1 << retries)
		} else {
			retries, shutdown, reexec = 0, false, false
			// Wait here for a signal from bot_disconnected
			<-disconnected
			if shutdown {
				return reexec
			}
		}
	}
	panic("unreachable")
}