package main import "strings" import "fmt" import "regexp" import "database/sql" import _ "github.com/mattn/go-sqlite3" type irc_msg struct { channel string msg string author string } type cmd struct { valid bool add bool cmd string groups []int suffix string } var begin_char = []byte{'<'} var db *sql.DB var err error func checkErr(err error) { if err != nil { panic(err) } } func in (a byte, arr []byte) bool { for _, x := range arr { if x == a { return true } } return false } func unique(intSlice []int) []int { keys := make(map[int]bool) list := []int{} for _, entry := range intSlice { if _, value := keys[entry]; !value { keys[entry] = true list = append(list, entry) } } return list } // function to split advise message correctly func filter(msg string) cmd { var c cmd if len(msg) <= 0 { c.valid = false return c } c.cmd = "" c.valid = false if strings.HasPrefix(msg, "add ") { c.add = true msg = msg[4:] } else { c.add = false } if (strings.Contains(msg, "[") && strings.Contains(msg, "]")) { re, _ := regexp.Compile(`\s*(\w*)\s*\[(.*)\]\s*(.*)\s*`) res := re.FindStringSubmatch(msg) if len(res) < 4 { return c } c.cmd = res[1] if c.cmd == "" { LOG_WARN.Printf("empty cmd\n") return c } // TODO: substitute group names with ids groups := strings.Fields(res[2]) for _, i := range groups { task := fmt.Sprintf("select id from groups where name = '%s'", i) row, err := db.Query(task) if err != nil { LOG_WARN.Printf("no such column: %s\n", i) return c } group_id := 0 if row.Next() { row.Scan(&group_id) } row.Close() if (group_id != 0) { c.groups = append(c.groups, group_id) } } c.suffix = res[3] c.valid = true } else { c.groups = nil re, _ := regexp.Compile(`\s*(\w*)\s*(.*)\s*`) res := re.FindStringSubmatch(msg) if len(res) < 3 { return c } c.cmd = res[1] if c.cmd == "" { return c } c.suffix = res[2] c.valid = true } c.cmd = strings.TrimSpace(c.cmd) c.suffix = strings.TrimSpace(c.suffix) return c } func getRandomEntry(c cmd) string { // TODO: increment counter // if database entry exists: set tag / group and run query task := "select distinct l.content from line l, brain b, tag t" if len(c.groups) > 0 { task = fmt.Sprintf("%s, groups g", task) } task = fmt.Sprintf("%s where l.id = b.line_id and t.id = b.tag_id", task) task = fmt.Sprintf("%s and t.id = %s", task, c.cmd) if len(c.groups) > 0 { task = fmt.Sprintf("%s and g.id = b.group_id and (", task) for i, group := range c.groups { task = fmt.Sprintf("%sg.id = %d", task, group) if i < (len(c.groups) - 1) { task = fmt.Sprintf("%s or ", task) } else { task = fmt.Sprintf("%s)", task) } } } return fmt.Sprintf("%s ORDER BY RANDOM() LIMIT 1", task) } // line: // >befehl <[groups]> // befehl ist genau ein wort func parsemsg(msg irc_msg, foo bot) bool { if len(msg.msg) <= 0 { return false } if !in(msg.msg[0], begin_char) { return false } msg.msg = msg.msg[1:] c := filter(msg.msg) if !c.valid { LOG_WARN.Printf("non valid input found.\n") return false } if c.cmd == "" { LOG_WARN.Printf("no command provided.\n") return false } sorter_row, err := db.Query(fmt.Sprintf("select id, tag_id, groups_allow, name_allow, has_groups from sorter where name = '%s'", c.cmd)) checkErr(err) if sorter_row.Next() { var sorter_id string var tag_id string var groups_allow int var name_allow int var has_groups int sorter_row.Scan(&sorter_id, &tag_id, &groups_allow, &name_allow, &has_groups) if groups_allow != 0 { // warning: not allowed c.groups = nil // use c.groups[:0] to keep allocated space } if name_allow != 0 && !c.add { // warning: not allowed c.suffix = "" } c.cmd = tag_id if has_groups == 0 { sorter_groups_row, err := db.Query(fmt.Sprintf("select group_id from sorter_groups where sorter_id = '%s'", sorter_id)) checkErr(err) if sorter_groups_row.Next() { var group_id int sorter_groups_row.Scan(&group_id) c.groups = append(c.groups, group_id) } sorter_groups_row.Close() } c.groups = unique(c.groups) sorter_row.Close() } else { LOG_WARN.Printf("no sorter entry, no translation possible\n") return false } if c.add { if (len(c.suffix) <= 0) { return false; } // insert into database statement, err := db.Prepare("insert into line (content, author) values (?,?)") checkErr(err) _, err = statement.Exec(c.suffix, msg.author) checkErr(err) defer statement.Close() // get ID of content... task := fmt.Sprintf("select l.id from line l where l.content = '%s'", c.suffix) row, err := db.Query(task) checkErr(err) line_id := 0 if row.Next() { row.Scan(&line_id) } row.Close() LOG_INFO.Printf(c.cmd) if line_id == 0 { LOG_WARN.Printf("no entry for adding") return false } // for tag and all groups if len(c.groups) == 0 { stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)") checkErr(err) _, err = stat.Exec(line_id, c.cmd) checkErr(err) LOG_INFO.Printf("inserted foo! \n") defer stat.Close() } else { stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)") checkErr(err) for _, group := range c.groups { _, err = stat.Exec(line_id, c.cmd, group) checkErr(err) } LOG_INFO.Printf("inserted foo! \n") defer stat.Close() } return true } task := getRandomEntry(c) LOG_INFO.Printf(task) row, err := db.Query(task) checkErr(err) res := "" if row.Next() { row.Scan(&res) } row.Close() if len(res) <= 0 { LOG_WARN.Printf("no entry found\n") res = "No matching entry found :(" } else if len(c.suffix) > 0 { res = fmt.Sprintf("%s... %s", c.suffix, res) } sendmsg(foo.conn, msg.channel, res) return true } /* func test() { db, err = sql.Open("sqlite3", "./boddle.db") checkErr(err) var msg irc_msg msg.channel = "testchannel" msg.author = "max mustermann" // == invalid commands == // empty cmd msg.msg = ">add [test me bro hahahaha] blob" parsemsg(msg) msg.msg = "> [test me bro hahahaha]" parsemsg(msg) msg.msg = ">[test me bro hahahaha] meow " parsemsg(msg) msg.msg = ">add [test me bro hahahaha] meow " parsemsg(msg) // non-existent groups msg.msg = ">ohai [test me bro hahahaha]" parsemsg(msg) // add command...? not implemented yet! msg.msg = ">add jokes blob" parsemsg(msg) msg.msg = ">add test [test me bro hahahaha] meow " parsemsg(msg) // ok command \o/ msg.msg = ">flirt [sweet] meow " parsemsg(msg) msg.msg = ">jokes [flach] meow " parsemsg(msg) msg.msg = ">hate [sweet] blobfisch " parsemsg(msg) msg.msg = ">radschlag [science]" parsemsg(msg) } */