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 []string suffix string error string } var begin_char = []byte{'-', '<'} var db *sql.DB var err error func checkErr(err error) { if err != nil { fmt.Printf("::::ERROR:::: %s\n", err) panic(err) } } func in (a byte, arr []byte) bool { for _, x := range arr { if x == a { return true } } return false } func unique_str(stringSlice []string) []string { keys := make(map[string]bool) list := []string{} for _, entry := range stringSlice { if _, value := keys[entry]; !value { keys[entry] = true list = append(list, entry) } } return list } func unique_int(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 } /* func unique[T any](tSlice []T) []T { keys := make(map[T]bool) list := []T{} for _, entry := range tSlice { if _, value := keys[entry]; !value { keys[entry] = true list = append(list, entry) } } return list } */ // function to split advise message correctly func filter(msg string, foo bot) cmd { var c cmd if len(msg) <= 0 { c.error = "Message is too short." 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 { c.error = "You entered weird stuff, please try again." return c } c.cmd = res[1] if c.cmd == "" { LOG_WARN.Printf("empty cmd\n") c.error = "The command was empty. A non-empty command is needed." return c } // substitute group names with ids groups := strings.Fields(res[2]) stmt, err := db.Prepare("select id from groups where name = ?") checkErr(err) for _, group := range groups { rows, err := stmt.Query(group) if err != nil { LOG_WARN.Printf("invalid query.") return c } group_id := 0 if rows.Next() { rows.Scan(&group_id) c.groups = append(c.groups, fmt.Sprintf("%d", group_id)) rows.Close() } else { c.valid = false c.error = "Group name " + group + " is invalid." rows.Close() return c } } 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 { c.error = "You entered weird stuff, please try again." return c } c.cmd = res[1] if c.cmd == "" { c.error = "The command was empty. A non-empty command is needed." 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" task += " where l.id = b.line_id and t.id = b.tag_id and t.id = " + c.cmd if len(c.groups) > 0 { task += " and l.id in (select line_id from brain where group_id = " + strings.Join(c.groups," intersect select line_id from brain where group_id = ") + ")" } task += " ORDER BY RANDOM() LIMIT 1" return 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, foo) if !c.valid { LOG_WARN.Printf("non valid input found.\n") if c.error != "" { sendmsg(foo.conn, msg.channel, "Falscher input du SP-Ersti... " + c.error) } return false } LOG_WARN.Printf("line was parsed, continue with evaluation.\n") if c.cmd == "" { LOG_WARN.Printf("no command provided.\n") return false } if c.cmd == "help" { 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) sorter_row.Close() if groups_allow != 0 { sendmsg(foo.conn, msg.channel, "This command does not allow groups. :(") return false } 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, fmt.Sprintf("%d", group_id)) } sorter_groups_row.Close() if c.add { var tag_name string tag_name_row, err := db.Query(fmt.Sprintf("select name from tag where id = %d", tag_id)) checkErr(err) if tag_name_row.Next() { tag_name_row.Scan(&tag_name) } tag_name_row.Close() LOG_WARN.Printf("Alias used. Tell the user about that.\n") sendmsg(foo.conn, msg.channel, "You're using an alias. Please try again with 'add " + tag_name + " [" + strings.Join(c.groups, " ") + "]. Thanks!") return false } } } else { LOG_WARN.Printf("no sorter entry, no translation possible\n") sendmsg(foo.conn, msg.channel, "No entry found, sorry...") return false } if c.add { if (len(c.suffix) <= 0) { return false; } c.suffix = strings.Replace(c.suffix,"\"","'", -1) LOG_WARN.Printf("adding new stuff: %s from %s.\n", c.suffix, msg.author) res, err := db.Exec("insert into line (content, author) values (?,?)", c.suffix, msg.author) checkErr(err) LOG_WARN.Printf("added line to table.\n") // get ID of content... /* task := fmt.Sprintf("select l.id from line l where l.content = \"%s\"", c.suffix) // strings.Replace(c.suffix, "'", "''", -1)) fmt.Printf(task) row, err := db.Query(task) checkErr(err) line_id := 0 if row.Next() { row.Scan(&line_id) } row.Close() LOG_WARN.Printf(c.cmd) if line_id == 0 { LOG_WARN.Printf("no entry for adding") sendmsg(foo.conn, msg.channel, "internal server error.") return false } */ line_id, err := res.LastInsertId(); checkErr(err) LOG_WARN.Printf("line_id: %d, tag_id: %d, groups: %s\n", line_id, c.cmd, strings.Join(c.groups, "-")) // 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() } sendmsg(foo.conn, msg.channel, fmt.Sprintf("success adding new super funny enjoyable line with ID %d!", line_id)) sendmsg(foo.conn, "horscchtey", fmt.Sprintf("new line: > %s < (ID %d), into groups %s", c.suffix, line_id, strings.Join(c.groups,","))) 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 }