diff --git a/boddle.db b/boddle.db index 345a363..f87f152 100644 Binary files a/boddle.db and b/boddle.db differ diff --git a/boddle.go b/boddle.go index 86604cf..11c733a 100644 --- a/boddle.go +++ b/boddle.go @@ -1,83 +1,18 @@ package main -import "strings" -import "fmt" -import "regexp" -import "database/sql" -import _ "github.com/mattn/go-sqlite3" +import ( + "strings" + "fmt" + "regexp" + "database/sql" + "math/rand" + _ "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 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 { @@ -125,17 +60,17 @@ func filter(msg string, foo bot) cmd { LOG_WARN.Printf("invalid query.") return c } - group_id := 0 if rows.Next() { + group_id := 0 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 + if c.add { + c.groups = append(c.groups, addgroups([]string{group}, nil)...) + } } + rows.Close() + defer stmt.Close() } c.suffix = res[3] c.valid = true @@ -158,6 +93,7 @@ func filter(msg string, foo bot) cmd { } c.cmd = strings.TrimSpace(c.cmd) c.suffix = strings.TrimSpace(c.suffix) + c.groups = unique_str(c.groups) return c } @@ -174,65 +110,41 @@ func getRandomEntry(c cmd) string { 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) +func addgroups(new_groups []string, msg *irc_msg) []string { + stat_sel, err := db.Prepare("select id from groups where name = ?") + checkErr(err) + stat_ins, err := db.Prepare("insert into groups(name) values (?)") + checkErr(err) + var groups_added []string + var groupids_added []string + for _, group := range new_groups { + ret, err := stat_sel.Query(group) + if ret.Next() { + ret.Close() + continue } - 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 - } - // hard code 'groups' to add new groups to the groups-table - if c.add && (c.cmd == "groups" || c.cmd == "group") { - if (c.groups != nil) { - sendmsg(foo.conn, msg.channel, "Ignoring groups for the groups-adding. Well, what were you expecting...?") - } - new_groups := strings.Fields(c.suffix) - stat_sel, err := db.Prepare("select id from groups where name = ?") + groupid_res, err := stat_ins.Exec(group) checkErr(err) - stat_ins, err := db.Prepare("insert into groups(name) values (?)") + defer stat_ins.Close() + groupid, err := groupid_res.LastInsertId() checkErr(err) - var groups_added []string - for _, group := range new_groups { - fmt.Println(group) - ret, err := stat_sel.Query(group) - if ret.Next() { - ret.Close() - continue - } - _, err = stat_ins.Exec(group) - checkErr(err) - groups_added = append(groups_added, group) - } + groupids_added = append(groupids_added, fmt.Sprintf("%d", groupid)) + groups_added = append(groups_added, group) + } + if msg != nil { if len(groups_added) > 0 { - sendmsg(foo.conn, msg.channel, "Added " + strings.Join(groups_added, ", ") + " to groups-table!") + (*msg).retmsg = "Added " + strings.Join(groups_added, ", ") + " to groups-table!" } else { - sendmsg(foo.conn, msg.channel, "Added nothing to groups-table! :(") + (*msg).retmsg = "Added nothing to groups-table! :(" } - return false } + return groupids_added +} - sorter_row, err := db.Query(fmt.Sprintf("select id, tag_id, groups_allow, name_allow, has_groups from sorter where name = '%s'", c.cmd)) +func checkSorter(msg *irc_msg, c *cmd) bool { + sorter_row_sel, err := db.Prepare("select id, tag_id, groups_allow, name_allow, has_groups from sorter where name = ?") + checkErr(err) + sorter_row, err := sorter_row_sel.Query((*c).cmd) checkErr(err) if sorter_row.Next() { var sorter_id string @@ -244,102 +156,167 @@ func parsemsg(msg irc_msg, foo bot) bool { sorter_row.Close() if groups_allow != 0 { - sendmsg(foo.conn, msg.channel, "This command does not allow groups. :(") + (*msg).retmsg = "This command does not allow groups. :(" return false } - if name_allow != 0 && !c.add { + if name_allow != 0 && !(*c).add { // warning: not allowed - c.suffix = "" + (*c).suffix = "" } - c.cmd = tag_id + (*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)) + group_sel, err := db.Prepare("select group_id from sorter_groups where sorter_id = ?") + checkErr(err) + sorter_groups_row, err := group_sel.Query(sorter_id) + //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)) + (*c).groups = append((*c).groups, fmt.Sprintf("%d", group_id)) } sorter_groups_row.Close() - if c.add { + if (*c).add { var tag_name string - tag_name_row, err := db.Query(fmt.Sprintf("select name from tag where id = %d", tag_id)) + tag_name_row, err := db.Query(fmt.Sprintf("select name from tag where id = %s", 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!") + (*msg).retmsg = "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...") + (*msg).retmsg = "No entry found, sorry..." + return false + } + return true +} + +func chooseEntry(msg *irc_msg, c *cmd) { + task := getRandomEntry(*c) + + LOG_INFO.Printf(task) + row, err := db.Query(task) + checkErr(err) + if row.Next() { + row.Scan(&((*msg).retmsg)) + } + row.Close() + + if len((*msg).retmsg) <= 0 { + LOG_WARN.Printf("no entry found\n") + (*msg).retmsg = "No matching entry found :(" + } else if len((*c).suffix) > 0 { + (*msg).retmsg = fmt.Sprintf("%s... %s", (*c).suffix, (*msg).retmsg) + } +} + +func addLine(msg *irc_msg, line string, groups []string, cmd string) string { + LOG_WARN.Printf("adding new stuff: %s from %s.\n", line, (*msg).author) + + res, err := db.Exec("insert into line (content, author) values (?,?)", line, (*msg).author) + checkErr(err) + LOG_WARN.Printf("added line to table.\n") + + // get ID of content... + line_id, err := res.LastInsertId(); + checkErr(err) + + LOG_WARN.Printf("line_id: %d, tag_id: %s, groups: %s\n", line_id, cmd, strings.Join(groups, "-")) + // for tag and all groups + if len(groups) == 0 { + stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)") + checkErr(err) + _, err = stat.Exec(line_id, cmd) + checkErr(err) + defer stat.Close() + } else { + stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)") + checkErr(err) + for _, group := range groups { + _, err = stat.Exec(line_id, cmd, group) + checkErr(err) + } + defer stat.Close() + } + (*msg).retmsg = fmt.Sprintf("success adding new super funny enjoyable line with ID %d!", line_id) + return fmt.Sprintf("new line: > %s < (ID %d), into groups %s", line, line_id, strings.Join(groups,",")) +} +// line: +// >befehl <[groups]> +// befehl ist genau ein wort +func parsemsg(msg *irc_msg, foo bot) bool { + if len((*msg).msg) <= 0 { + return false + } + if (*msg).msg == "<3" { + (*msg).msg = string(begin_char[0]) + "flirt kreisi" + } + + 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 != "" { + (*msg).retmsg = "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" { + (*msg).retmsg = "There is no help in this hell..." + return false + } + if c.cmd == "slap" { + who := []string{(*msg).author, "\x01ACTION"} + whom := []string{(*msg).author, foo.Conf.Name} + LOG_WARN.Printf("suffix: " + c.suffix) + if c.suffix != "" { + who = append(who, strings.Split(c.suffix, " ")...) + whom = append(whom, strings.Split(c.suffix, " ")...) + } + (*msg).retmsg = who[rand.Intn(len(who))] + " slaps " + whom[rand.Intn(len(whom))] + " around with a large trout." + return false + } + // hard code 'groups' to add new groups to the groups-table + if c.add && (c.cmd == "groups" || c.cmd == "group") { + if (c.groups != nil) { + (*msg).retmsg = "Ignoring groups for the groups-adding. Well, what were you expecting...?" + } + addgroups(strings.Fields((&c).suffix), msg) return false } + // have a look at sorter table if command is valid + if !checkSorter(msg, &c) { + return false + } + + // new line for database if c.add { // if there is nothing to add, just return. :-) 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... - 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 + sendmsg(foo.conn, "horscchtey", addLine(msg, c.suffix, c.groups, c.cmd)) + } else { + chooseEntry(msg, &c) } - - 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 } diff --git a/bot.go b/bot.go index 19bcce1..c2598df 100644 --- a/bot.go +++ b/bot.go @@ -1,27 +1,152 @@ package main import ( - "os" "log" "fmt" "net" "time" + "bufio" + "strings" + "database/sql" configo "github.com/distributedio/configo" _ "github.com/mattn/go-sqlite3" ) -var dead = true - -type Config struct { - Name string `cfg:"name; boddle; printableascii; IRC nick of bot"` - Channels []string `cfg:"channels; required; printableascii; Channel list to join to"` - Server string `cfg:"server; required; netaddr; Server name to connect to"` - Database string `cfg:"database; ./boddle.db; path; Path to database"` +func sendmsg (conn net.Conn, channel string, msg string) { + mesg := fmt.Sprintf("PRIVMSG %s :%s\r\n", channel, msg) + fmt.Printf(mesg) + conn.Write([]byte(mesg)) } -type bot struct { - Conf Config - conn net.Conn +func scanline_privmsg (msg string, irc *irc_msg) { + LOG_ERR.Printf(msg) + + msg = msg[1:] + t := strings.Split(msg, "!") + (*irc).author, (*irc).channel = t[0], t[1] + t = strings.Split((*irc).channel, "PRIVMSG ") + (*irc).channel = t[1] + t = strings.Split((*irc).channel, " :") + (*irc).channel, (*irc).msg = t[0], t[1] + t = strings.Split((*irc).msg, "\r\n") + (*irc).msg = strings.TrimSpace(t[0]) + if ! strings.HasPrefix((*irc).channel, "#") { + (*irc).channel = (*irc).author + } + (*irc).retmsg = "" +} + +func bot_connect(bot *bot) { + conn, err := net.Dial("tcp", (*bot).Conf.Server) + if err != nil { + LOG_ERR.Printf("Error while dialing server.") + (*bot).conn = nil + return + } + + (*bot).conn = conn + fmt.Fprintf((*bot).conn, "USER %s 1 1 1:%s\r\n", (*bot).Conf.Name, (*bot).Conf.Name) +} + +func bot_register(bot *bot) { + /* connect to irc */ + fmt.Fprintf((*bot).conn, "NICK %s\r\n", (*bot).Conf.Name) + for _, channel := range((*bot).Conf.Channels) { + fmt.Fprintf((*bot).conn, "JOIN %s\r\n", channel) + } +} + +func bot_listen(bot *bot) <-chan string { + c := make(chan string) + bot_register(bot) + + go func(timeoutNormal time.Duration, timeoutVersion time.Duration) { + bufReader := bufio.NewReader((*bot).conn) + + timeoutDuration := timeoutNormal + waitversion := false + + defer func() { + fmt.Println("Closing connection...") + close(c) + (*bot).conn.Close() + }() + + for { + (*bot).conn.SetReadDeadline(time.Now().Add(timeoutDuration)) + + line, err := bufReader.ReadString('\n') + if err != nil { + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + fmt.Printf("Timeout!\n") + if waitversion { + fmt.Println("VERSION command did not return.") + return + } + + n, err := (*bot).conn.Write([]byte("VERSION\n")) + fmt.Printf("n: %d, err: %s\n", n, err) + if err != nil { + fmt.Println("Writing to channel failed.") + return + } + // wait for return value of VERSION + waitversion = true + timeoutDuration = timeoutVersion + } else { + fmt.Println("Some more serious error occured while reading.") + return + } + continue + } + + // not waiting for version answer right now + timeoutDuration = timeoutNormal + waitversion = false + c <- line + + if strings.Contains(line, "PING") { + (*bot).conn.Write([]byte(strings.Replace(line, "PING", "PONG", 1))) + } else if strings.Contains(line, "You have not registered") { + // set nickname + time.Sleep(10 * time.Second) + bot_register(bot) + } else if strings.Contains(line, "PRIVMSG") { + var msg irc_msg + scanline_privmsg(line, &msg) + LOG_ERR.Printf(msg.author) + parsemsg(&msg, (*bot)) + if msg.retmsg != "" { + sendmsg((*bot).conn, msg.channel, msg.retmsg) + } + } + } + } (4 * time.Minute, 1 * time.Minute) + + return c +} + +func bot_run(bot *bot) { + LOG_INFO.Println("Bot ready to run.") + + LOG_INFO.Println("Opening database.") + db, err = sql.Open("sqlite3", (*bot).Conf.Database) + if err != nil { + LOG_ERR.Println("Opening database failed.") + return + } + + for { + bot_connect(bot) + if bot.conn == nil { + LOG_INFO.Printf("Bot is nil. Try to connect again.") + time.Sleep(10 * time.Second) + continue + } + for val := range bot_listen(bot) { + LOG_INFO.Printf("%s", val) + } + } } func main() { @@ -31,33 +156,6 @@ func main() { if err := configo.Load("./boddle.toml", &boddle.Conf); err != nil { log.Fatal(err) } -// boddle := bot { -// name: "boddle", -// channel: []string{"#faui2k16", "#fau", "#sigbike", "#sigfreibad"}, -// port: 6667, -// server: "irc.fau.de", -// } - LOG_INFO.Println("bot started!") - - var botchan <-chan []byte - var line []byte - dead = true - - for { - if dead { - LOG_WARN.Println("died.") - for { - botchan = connect(boddle) - if botchan != nil { - break - } - time.Sleep(10 * time.Second) - } - LOG_INFO.Println("reconnected.") - dead = false - } - line = <-botchan - fmt.Fprintf(os.Stderr, string(line)) - } + bot_run(&boddle) } diff --git a/bot.py b/bot.py index d623236..21ecae9 100644 --- a/bot.py +++ b/bot.py @@ -12,7 +12,7 @@ import sqlite3 as sql updater = Updater(token='935673062:AAH4By1EMqAUaD9wgnV3lZQRRBX6e5Lve6g', use_context=True) # sqlite database -connection = sql.connect("/home/horscchtey/bots/boddle/src/v2/boddle.db", check_same_thread=False) +connection = sql.connect("/home/boddle/boddle/src/v2/boddle.db", check_same_thread=False) cursor = connection.cursor() dispatcher = updater.dispatcher diff --git a/conf.go b/conf.go new file mode 100644 index 0000000..ccccef9 --- /dev/null +++ b/conf.go @@ -0,0 +1,8 @@ +package main + +type Boddle struct { + name string `cfg:"name; boddle; printableascii; IRC nick of bot"` + channels []string `cfg:"channels; required; printableascii; Channel list to join to"` + server string `cfg:"server; required; netaddr; Server name to connect to"` + database string `cfg:"database; ./boddle.db; path; Path to database"` +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a59231c --- /dev/null +++ b/flake.nix @@ -0,0 +1,62 @@ +{ + description = "boddle, in Anlehnung an bottle"; + + outputs = { self, nixpkgs }: let + module = { pkgs, lib, config, ... }: { + options.services.boddle = { + enable = lib.mkEnableOption "enable"; + # TODO: configurability + }; + + config.nixpkgs.overlays = [ self.overlay ]; + + config.systemd.services.boddle = lib.mkIf config.services.boddle.enable { + script = lib.getExe pkgs.boddle; + }; + }; + + per-system = fn: builtins.mapAttrs (_: fn) nixpkgs.legacyPackages; + + package = pkgs: pkgs.buildGoModule { + meta = { + description = "boddle, in Anlehnung an bottle"; + homepage = "https://git.fbs42.ddnss.de/forgejo/fbs42/boddle"; + name = "boddle"; + }; + pname = "boddle"; + version = "v0.0.1"; + vendorHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + src = pkgs.fetchgit { + url = "https://git.fbs42.ddnss.de/forgejo/fbs42/boddle"; + hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + }; + }; + + devshell = pkgs: pkgs.mkShell { + nativeBuildInputs = with pkgs.buildPackages; [ + go + ]; + }; + + in { + nixosModules = { + default = self.nixosModules.boddle; + boddle = module; + }; + + overlay = final: prev: { + boddle = package final; + }; + + packages = per-system (pkgs: { + default = package pkgs; + boddle = package pkgs; + }); + + apps = self.packages; + + devShells = per-system (pkgs: { + default = devshell pkgs; + }); + }; +} diff --git a/forraspidothis b/forraspidothis index 1bc0a64..6239be8 100755 --- a/forraspidothis +++ b/forraspidothis @@ -1,15 +1,10 @@ #!/bin/bash -export GOPATH=/home/horscchtey/go -export CC=arm-linux-gnueabihf-gcc -export CXX=arm-linux-gnueabihf-g++ +export GOPATH=/home/boddle/go export CGO_ENABLED=1 -export GOOS=linux -export GOARCH=arm -export GOARM=7 declare -a src -src+=(bot.go boddle.go logging.go ircfoo.go) +src+=(bot.go boddle.go logging.go helpers.go types.go) declare -i nproc="$(nproc)" -go build -p ${nproc} "${src[@]}" +go build -v -p ${nproc} "${src[@]}" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..72f9306 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module boddle + +go 1.17 + +require ( + github.com/distributedio/configo v0.0.0-20200107073829-efd79b027816 + github.com/mattn/go-sqlite3 v1.14.16 +) + +require ( + github.com/naoina/go-stringutil v0.1.0 // indirect + github.com/shafreeck/toml v0.0.0-20190326060449-44ad86712acc // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cb9d486 --- /dev/null +++ b/go.sum @@ -0,0 +1,20 @@ +github.com/distributedio/configo v0.0.0-20200107073829-efd79b027816 h1:V6TyTUY0vUVUOxLnuH6AIOCIOI8psy5h0n4U+qvO4bo= +github.com/distributedio/configo v0.0.0-20200107073829-efd79b027816/go.mod h1:Jwz2omP6W/T/XlSfu+BMGW7NEJX3tf5/Qv5gwaiQ+uU= +github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= +github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/shafreeck/toml v0.0.0-20190326060449-44ad86712acc h1:BrtrZvICmDsYzv7ECoQFwlC5cS+YWDfz/OBpMlMe9HY= +github.com/shafreeck/toml v0.0.0-20190326060449-44ad86712acc/go.mod h1:C9DYu7Ddz1xnXil/kyvydcdaUggQeJvFA7vzYpm+Cw4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190318195719-6c81ef8f67ca/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190319232107-3f1ed9edd1b4/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..f59c740 --- /dev/null +++ b/helpers.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" +) + +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 +} diff --git a/ircfoo.go b/ircfoo.go deleted file mode 100644 index 2a3e2bd..0000000 --- a/ircfoo.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "fmt" - "net" - "os" - "bufio" - "bytes" - "strings" - "database/sql" - _ "github.com/mattn/go-sqlite3" -) - -func sendmsg (conn net.Conn, channel string, msg string) { - mesg := fmt.Sprintf("PRIVMSG %s :%s\r\n", channel, msg) - fmt.Printf(mesg) - conn.Write([]byte(mesg)) -} - -func scanline_privmsg (msg string) irc_msg { - var irc irc_msg - - msg = msg[1:] - t := strings.Split(msg, "!") - irc.author, irc.channel = t[0], t[1] - t = strings.Split(irc.channel, "PRIVMSG ") - irc.channel = t[1] - t = strings.Split(irc.channel, " :") - irc.channel, irc.msg = t[0], t[1] - t = strings.Split(irc.msg, "\r\n") - irc.msg = strings.TrimSpace(t[0]) - if ! strings.HasPrefix(irc.channel, "#") { - irc.channel = irc.author - } - return irc -} - -func listenToIRC (foo bot) <-chan []byte { - c := make(chan []byte) - reader := bufio.NewReader(foo.conn) - db, err = sql.Open("sqlite3", foo.Conf.Database) - if err != nil { - LOG_ERR.Printf("opening database failed") - return nil - } - - var line []byte - var err error - - go func() { - for { - line, err = reader.ReadBytes('\n') - if err != nil { - LOG_ERR.Printf("Error while reading bytes from connection.\n") - dead = true - c <- []byte("killed it") - return - } - - c <- line - - if bytes.Contains([]byte(line), []byte("PING :")) { - v := []byte(bytes.Replace([]byte(line), []byte("PING"), []byte("PONG"), 1)) - fmt.Printf(string(v[:])) - foo.conn.Write(v) - continue - } - - if !bytes.Contains([]byte(line), []byte("PRIVMSG")) { - continue - } - - parsemsg(scanline_privmsg(string(line)), foo) - } - } () - return c -} - -func connect(boddle bot) <-chan []byte { - conn, err := net.Dial("tcp", boddle.Conf.Server) - - if err != nil { - fmt.Fprintf(os.Stderr, "Error while dialing server.") - LOG_ERR.Printf("Error while connecting to server.") - return nil - } - - boddle.conn = conn - - /* connect to irc */ - fmt.Fprintf(boddle.conn, "NICK %s\r\n", boddle.Conf.Name) - fmt.Fprintf(boddle.conn, "USER %s 1 1 1:%s\r\n", boddle.Conf.Name, boddle.Conf.Name) - for _, channel := range(boddle.Conf.Channels) { - fmt.Fprintf(boddle.conn, "JOIN %s\r\n", channel) - } - - return listenToIRC(boddle) -} diff --git a/logging.go b/logging.go index 02769c6..6c03744 100644 --- a/logging.go +++ b/logging.go @@ -12,9 +12,9 @@ var ( ) func LOG_init() { - file := os.Stdout + file := os.Stdout - LOG_INFO = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) - LOG_WARN = log.New(file, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) - LOG_ERR = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + LOG_INFO = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + LOG_WARN = log.New(file, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) + LOG_ERR = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) } diff --git a/pepe.go b/pepe.go deleted file mode 100644 index 9ba9fd5..0000000 --- a/pepe.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -var pepe = []string{ -"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░░░░░░░░░░░▓▓▒▒▒▒▒▒▓▓▒░░░░░░░░░▓▓░▓▓▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░░░░░░░ ▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░▓▒▒▒▒▒▒▒▒▒▒▒▒▓░░ ░░░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░░░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓░░░░░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░░░░░▓▒▒▒▒▒▒▓▓▓▒▒▒▒▒▒▒▓▓▓▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓ ░░░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░░░▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓░░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓░▓▓▒▒▓▓▓░░▒▒▒▒▒▒▓▓░░░░░▓▓▒▓░░░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░░░░▓▓▒▒▒▒▒▒▒▒▒▒▒▓▓▒▓▓▓▒▒▒▒▒▒▒▒▓▓▓░▓▓▓▓▓▓▒▒▒▒▒▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░░▒▒▒▓▒▒▒▒▒▒▒▒▒▓▒▓▓▓▒▒▒▒▒▒▒▒▓▓▓▒▒▒▒▓▒▒▒▒▓▓▓▒▒▓▓▓▒▒▒▒▓▓░░░░░░░░░░░░░░░░░░", -"░░░░░░░░░▓▒▒▒▓▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▓▓▒░▒█░███░ ▒ ░█▓░████ ░░░░░░░░░░░░░░░░░░", -"░░░░░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓ ░████░ ██░ ▒ ██░██ ░██ ▒░░░░░░░░░░░░░░░░░░", -"░░░░░░ ▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▓▓▒███░███░▓▒▒░▒▒▓▓▓▓░░░▓▓▓▒▒▒▓▒░░░░░░░░░░░░░░░░░░░", -"░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒░░░░░░░░░░░░░░░░░░░░░", -"░░░░░▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▒▒▒▒▓▓▓▒▒▒▒▓▓░▒ ░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░░░░░░░░░░░░░░░░░░░░░░░", -"░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░░░░░░░░░█░░▒▓█▓░█░░░░", -"░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓ ░░░░░░░█▒░█▒▒░▓▒█▒░░", -"░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░▓▒▒▒▓▓░▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░▓░▒░░▓░░▓▓▒░░▒▓█▓▒█░░", -"░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▓░░░░▓▓▓▓▓░░░▓▒▒▒░▒▒░░▒░▓█ ░█▒▒░░▒░▒▓▓░░", -"░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒░▒▒▒▒▒▒▒▒▒▒▓▓▓▓░░░░░▓▓▓█▒█▒▒▒▒▒▒▒█░░░", -"░░░░░▒▓▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▓█░█░▓▒█▓░▒▒▒▒▒▒▒▒▒▓ ░░░░░░▒▒▒▒▒▒▒▒▒▒█░░░░", -"░░░░░░░▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒█▓▓░▒█░█▓▒█░░░▓▓▓▓▒░░░░░▒▒▒▒▒▒▒▒▒▒▒▓█▒░░░░░", -" ░ ░▒▒ ▒▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓██▒█▒▒░▒▓▓▒█▒▓░▓░░▒ ░░░░▒░▒▒▒▒▒▒▒▒▒▒▓█░░░░░░░░░", -" ▒ ░▓▓▒▓▓░▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒█▒█░▒▒▓▒▒█░▓▒▓░█▒▒░░░░░ ░▒▒▒▒▒▒▒▒▓█▒░░░░░░░░░░░", -"▒ ░▓▓▓▒▒▒▒▒▒▓▓▓▓▓▓▓▓░▓▒░▒▒▒▒▒▒▒▒▒░▒▒▒▓░░░░░░░▒▒▒▒▒▒▒▒░ ░░░░░░░░░░░░", -" ░░░▒▒▒▒▒▓█▓▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░▒▓▒▒▒▒▒▒▒░ ░░░░░░░░░░░░", -" ░▒▒▒▒░▓▒▒█▒ ▒░░░░░░░░░█▒▒▒▒▒▒▒▓▒░░░░░░░░░░░░", -" ▓▒▒▒▒▒▒▒▓░ █▒░░░░░▒▒▒▒▒▒▒▒▒█░░░░░░░░░░░░", -" ░▓▒▒▒▒▒▒▒░ ░░░░░░░▓▒▒▒▒▒▒▒▓▓░░░░░░░░░░░"}; - - -func printPepe(channel string, foo bot) { - for _, x := range pepe { - sendmsg(foo.conn, channel, x) - } - LOG_INFO.Printf("Sent pepe to ppl") -} diff --git a/types.go b/types.go new file mode 100644 index 0000000..b2968c4 --- /dev/null +++ b/types.go @@ -0,0 +1,34 @@ +package main + +import ( + "net" +) + +type Config struct { + Name string `cfg:"name; boddle; printableascii; IRC nick of bot"` + Channels []string `cfg:"channels; required; printableascii; Channel list to join to"` + Server string `cfg:"server; required; netaddr; Server name to connect to"` + Database string `cfg:"database; ./boddle.db; path; Path to database"` +} + +type irc_msg struct { + channel string + msg string + author string + retmsg string +} + +type cmd struct { + valid bool + add bool + cmd string + groups []string + suffix string + error string +} + +type bot struct { + Conf Config + conn net.Conn +} +