2016-01-17 18:00:44 +00:00
|
|
|
// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors.
|
2013-12-10 23:37:07 +00:00
|
|
|
|
2012-08-17 20:38:15 +00:00
|
|
|
package bot
|
|
|
|
|
|
|
|
import (
|
2016-01-15 06:12:26 +00:00
|
|
|
"database/sql"
|
2012-10-11 20:28:00 +00:00
|
|
|
"errors"
|
2012-08-17 20:38:15 +00:00
|
|
|
"fmt"
|
2016-01-15 06:12:26 +00:00
|
|
|
"log"
|
2012-08-26 19:14:09 +00:00
|
|
|
"math/rand"
|
2019-02-05 20:13:32 +00:00
|
|
|
"reflect"
|
2013-03-04 15:43:23 +00:00
|
|
|
"regexp"
|
2012-08-26 19:14:09 +00:00
|
|
|
"strconv"
|
2012-08-17 22:09:29 +00:00
|
|
|
"strings"
|
2012-08-26 19:14:09 +00:00
|
|
|
"time"
|
2016-04-01 14:20:03 +00:00
|
|
|
|
|
|
|
"github.com/velour/catbase/bot/msg"
|
2012-08-17 20:38:15 +00:00
|
|
|
)
|
|
|
|
|
2019-02-06 03:52:49 +00:00
|
|
|
func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool {
|
2019-02-05 18:33:18 +00:00
|
|
|
log.Println("Received event: ", msg)
|
2016-01-15 13:59:26 +00:00
|
|
|
|
2016-03-10 18:37:07 +00:00
|
|
|
// msg := b.buildMessage(client, inMsg)
|
|
|
|
// do need to look up user and fix it
|
2019-02-12 17:26:27 +00:00
|
|
|
if kind == Message && strings.HasPrefix(msg.Body, "help") && msg.Command {
|
2016-01-15 13:59:26 +00:00
|
|
|
parts := strings.Fields(strings.ToLower(msg.Body))
|
|
|
|
b.checkHelp(msg.Channel, parts)
|
2019-02-15 18:22:54 +00:00
|
|
|
log.Println("Handled a help, returning")
|
2016-01-15 13:59:26 +00:00
|
|
|
goto RET
|
|
|
|
}
|
|
|
|
|
2016-03-30 14:00:20 +00:00
|
|
|
for _, name := range b.pluginOrdering {
|
2019-02-05 20:24:49 +00:00
|
|
|
if b.runCallback(b.plugins[name], kind, msg, args...) {
|
2019-02-05 15:54:13 +00:00
|
|
|
goto RET
|
2016-01-15 13:59:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RET:
|
|
|
|
b.logIn <- msg
|
2019-02-06 03:52:49 +00:00
|
|
|
return true
|
2016-01-15 13:59:26 +00:00
|
|
|
}
|
|
|
|
|
2019-02-05 18:58:12 +00:00
|
|
|
func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
|
2019-02-15 18:22:54 +00:00
|
|
|
t := reflect.TypeOf(plugin).String()
|
2019-02-05 20:13:32 +00:00
|
|
|
for _, cb := range b.callbacks[t][evt] {
|
2019-02-05 20:24:49 +00:00
|
|
|
if cb(evt, message, args...) {
|
2019-02-05 15:54:13 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-02-05 18:33:18 +00:00
|
|
|
// Send a message to the connection
|
|
|
|
func (b *bot) Send(kind Kind, args ...interface{}) (string, error) {
|
|
|
|
return b.conn.Send(kind, args...)
|
2017-10-31 10:22:36 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 19:09:27 +00:00
|
|
|
func (b *bot) GetEmojiList() map[string]string {
|
|
|
|
return b.conn.GetEmojiList()
|
|
|
|
}
|
|
|
|
|
2012-08-18 01:39:26 +00:00
|
|
|
// Checks to see if the user is asking for help, returns true if so and handles the situation.
|
2016-03-30 14:00:20 +00:00
|
|
|
func (b *bot) checkHelp(channel string, parts []string) {
|
2012-08-18 02:30:04 +00:00
|
|
|
if len(parts) == 1 {
|
2012-08-18 01:39:26 +00:00
|
|
|
// just print out a list of help topics
|
2012-08-27 00:30:23 +00:00
|
|
|
topics := "Help topics: about variables"
|
2016-03-30 14:00:20 +00:00
|
|
|
for name, _ := range b.plugins {
|
2019-02-12 17:26:27 +00:00
|
|
|
name = strings.Split(strings.TrimPrefix(name, "*"), ".")[0]
|
2012-08-18 01:39:26 +00:00
|
|
|
topics = fmt.Sprintf("%s, %s", topics, name)
|
|
|
|
}
|
2019-02-05 18:33:18 +00:00
|
|
|
b.Send(Message, channel, topics)
|
2012-08-18 01:39:26 +00:00
|
|
|
} else {
|
|
|
|
// trigger the proper plugin's help response
|
|
|
|
if parts[1] == "about" {
|
|
|
|
b.Help(channel, parts)
|
|
|
|
return
|
|
|
|
}
|
2012-08-27 00:30:23 +00:00
|
|
|
if parts[1] == "variables" {
|
|
|
|
b.listVars(channel, parts)
|
|
|
|
return
|
|
|
|
}
|
2019-02-12 17:26:27 +00:00
|
|
|
for name, plugin := range b.plugins {
|
|
|
|
if strings.HasPrefix(name, "*"+parts[1]) {
|
|
|
|
if b.runCallback(plugin, Help, msg.Message{Channel: channel}, channel, parts) {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
msg := fmt.Sprintf("I'm sorry, I don't know how to help you with %s.", parts[1])
|
|
|
|
b.Send(Message, channel, msg)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2012-08-18 01:39:26 +00:00
|
|
|
}
|
2019-02-12 17:26:27 +00:00
|
|
|
msg := fmt.Sprintf("I'm sorry, I don't know what %s is!", strings.Join(parts, " "))
|
|
|
|
b.Send(Message, channel, msg)
|
2012-08-18 01:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-01 14:20:03 +00:00
|
|
|
func (b *bot) LastMessage(channel string) (msg.Message, error) {
|
2012-10-11 20:28:00 +00:00
|
|
|
log := <-b.logOut
|
|
|
|
if len(log) == 0 {
|
2016-04-01 14:20:03 +00:00
|
|
|
return msg.Message{}, errors.New("No messages found.")
|
2012-10-11 20:28:00 +00:00
|
|
|
}
|
2013-06-17 02:40:30 +00:00
|
|
|
for i := len(log) - 1; i >= 0; i-- {
|
|
|
|
msg := log[i]
|
|
|
|
if strings.ToLower(msg.Channel) == strings.ToLower(channel) {
|
|
|
|
return msg, nil
|
2013-06-17 01:03:43 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-01 14:20:03 +00:00
|
|
|
return msg.Message{}, errors.New("No messages found.")
|
2012-10-11 20:28:00 +00:00
|
|
|
}
|
|
|
|
|
2012-08-17 20:38:15 +00:00
|
|
|
// Take an input string and mutate it based on $vars in the string
|
2016-04-01 14:20:03 +00:00
|
|
|
func (b *bot) Filter(message msg.Message, input string) string {
|
2012-08-17 22:09:29 +00:00
|
|
|
if strings.Contains(input, "$NICK") {
|
|
|
|
nick := strings.ToUpper(message.User.Name)
|
|
|
|
input = strings.Replace(input, "$NICK", nick, -1)
|
2012-08-26 19:14:09 +00:00
|
|
|
}
|
|
|
|
|
2012-08-26 23:23:51 +00:00
|
|
|
// Let's be bucket compatible for this var
|
2012-08-27 00:33:33 +00:00
|
|
|
input = strings.Replace(input, "$who", "$nick", -1)
|
2012-08-26 19:14:09 +00:00
|
|
|
if strings.Contains(input, "$nick") {
|
2012-08-17 22:09:29 +00:00
|
|
|
nick := message.User.Name
|
|
|
|
input = strings.Replace(input, "$nick", nick, -1)
|
|
|
|
}
|
2012-08-26 19:14:09 +00:00
|
|
|
|
2013-08-31 02:09:45 +00:00
|
|
|
for strings.Contains(input, "$someone") {
|
2013-06-02 01:59:55 +00:00
|
|
|
nicks := b.Who(message.Channel)
|
|
|
|
someone := nicks[rand.Intn(len(nicks))].Name
|
2013-08-31 02:09:45 +00:00
|
|
|
input = strings.Replace(input, "$someone", someone, 1)
|
2012-08-26 19:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for strings.Contains(input, "$digit") {
|
|
|
|
num := strconv.Itoa(rand.Intn(9))
|
|
|
|
input = strings.Replace(input, "$digit", num, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
for strings.Contains(input, "$nonzero") {
|
|
|
|
num := strconv.Itoa(rand.Intn(8) + 1)
|
|
|
|
input = strings.Replace(input, "$nonzero", num, 1)
|
|
|
|
}
|
|
|
|
|
2012-08-26 23:23:51 +00:00
|
|
|
r, err := regexp.Compile("\\$[A-z]+")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2017-09-29 04:58:21 +00:00
|
|
|
for _, f := range b.filters {
|
|
|
|
input = f(input)
|
|
|
|
}
|
|
|
|
|
2012-08-26 23:23:51 +00:00
|
|
|
varname := r.FindString(input)
|
|
|
|
blacklist := make(map[string]bool)
|
|
|
|
blacklist["$and"] = true
|
|
|
|
for len(varname) > 0 && !blacklist[varname] {
|
2016-01-15 06:12:26 +00:00
|
|
|
text, err := b.getVar(varname)
|
|
|
|
if err != nil {
|
2012-08-26 23:23:51 +00:00
|
|
|
blacklist[varname] = true
|
|
|
|
continue
|
|
|
|
}
|
2016-01-15 06:12:26 +00:00
|
|
|
input = strings.Replace(input, varname, text, 1)
|
2012-08-26 23:23:51 +00:00
|
|
|
varname = r.FindString(input)
|
|
|
|
}
|
|
|
|
|
2012-08-17 20:38:15 +00:00
|
|
|
return input
|
|
|
|
}
|
|
|
|
|
2016-03-30 14:00:20 +00:00
|
|
|
func (b *bot) getVar(varName string) (string, error) {
|
2016-01-15 06:12:26 +00:00
|
|
|
var text string
|
2019-01-20 20:21:26 +00:00
|
|
|
err := b.DB().Get(&text, `select value from variables where name=? order by random() limit 1`, varName)
|
2016-01-15 06:12:26 +00:00
|
|
|
switch {
|
|
|
|
case err == sql.ErrNoRows:
|
|
|
|
return "", fmt.Errorf("No factoid found")
|
|
|
|
case err != nil:
|
2016-01-15 13:59:26 +00:00
|
|
|
log.Fatal("getVar error: ", err)
|
2016-01-15 06:12:26 +00:00
|
|
|
}
|
|
|
|
return text, nil
|
|
|
|
}
|
|
|
|
|
2016-03-30 14:00:20 +00:00
|
|
|
func (b *bot) listVars(channel string, parts []string) {
|
2016-05-20 20:28:48 +00:00
|
|
|
var variables []string
|
2019-01-20 20:21:26 +00:00
|
|
|
err := b.DB().Select(&variables, `select name from variables group by name`)
|
2012-08-27 00:30:23 +00:00
|
|
|
if err != nil {
|
2016-01-15 06:12:26 +00:00
|
|
|
log.Fatal(err)
|
2012-08-27 00:30:23 +00:00
|
|
|
}
|
|
|
|
msg := "I know: $who, $someone, $digit, $nonzero"
|
2016-05-20 20:28:48 +00:00
|
|
|
if len(variables) > 0 {
|
|
|
|
msg += ", " + strings.Join(variables, ", ")
|
2012-08-27 00:30:23 +00:00
|
|
|
}
|
2019-02-05 18:33:18 +00:00
|
|
|
b.Send(Message, channel, msg)
|
2012-08-27 00:30:23 +00:00
|
|
|
}
|
|
|
|
|
2016-03-30 14:00:20 +00:00
|
|
|
func (b *bot) Help(channel string, parts []string) {
|
2012-08-17 22:56:44 +00:00
|
|
|
msg := fmt.Sprintf("Hi, I'm based on godeepintir version %s. I'm written in Go, and you "+
|
|
|
|
"can find my source code on the internet here: "+
|
2016-03-30 14:00:20 +00:00
|
|
|
"http://github.com/velour/catbase", b.version)
|
2019-02-05 18:33:18 +00:00
|
|
|
b.Send(Message, channel, msg)
|
2012-08-17 22:56:44 +00:00
|
|
|
}
|
2012-08-25 04:46:13 +00:00
|
|
|
|
2013-05-08 00:08:18 +00:00
|
|
|
// Send our own musings to the plugins
|
2016-03-30 14:00:20 +00:00
|
|
|
func (b *bot) selfSaid(channel, message string, action bool) {
|
2016-04-01 14:20:03 +00:00
|
|
|
msg := msg.Message{
|
2016-03-30 14:00:20 +00:00
|
|
|
User: &b.me, // hack
|
2013-05-08 00:08:18 +00:00
|
|
|
Channel: channel,
|
|
|
|
Body: message,
|
|
|
|
Raw: message, // hack
|
2013-06-17 04:04:10 +00:00
|
|
|
Action: action,
|
2013-05-08 00:08:18 +00:00
|
|
|
Command: false,
|
|
|
|
Time: time.Now(),
|
|
|
|
Host: "0.0.0.0", // hack
|
|
|
|
}
|
|
|
|
|
2016-03-30 14:00:20 +00:00
|
|
|
for _, name := range b.pluginOrdering {
|
2019-02-05 18:58:12 +00:00
|
|
|
if b.runCallback(b.plugins[name], SelfMessage, msg) {
|
2019-02-05 15:54:13 +00:00
|
|
|
return
|
2013-05-08 00:08:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|