Compare commits

..

10 commits

Author SHA1 Message Date
9b016251f2 setup nixos environment 2025-01-21 16:52:47 +01:00
Eva Dengler
2e1890c9f9 add new functionality 2022-12-21 13:38:43 +01:00
Eva Dengler
df2a986286 Update repository 2022-12-21 13:04:36 +01:00
Horscchtey
e5a935a85b backup database file 2022-04-20 10:41:24 +00:00
Horscchtey
7683f9ee03 add correct time 2022-04-19 19:22:56 +00:00
Eva Dengler
e45fd544b5 update timeout 2022-03-06 22:48:28 +01:00
Eva Dengler
f6cf8b46ec kill bot after 10 minutes idling
should prevent 'ping loss' due to weird network setup
2022-03-05 21:39:54 +01:00
Horscchtey
9e09e78ab8 sonderbehandlung fuer kreisi 2022-02-08 09:42:10 +00:00
Horscchtey
7ead746d98 add database backup 2022-02-03 21:23:50 +00:00
Horscchtey
fe7055298a Automatic group adding 2022-02-03 21:08:20 +00:00
14 changed files with 497 additions and 383 deletions

BIN
boddle.db

Binary file not shown.

315
boddle.go
View file

@ -1,83 +1,18 @@
package main package main
import "strings" import (
import "fmt" "strings"
import "regexp" "fmt"
import "database/sql" "regexp"
import _ "github.com/mattn/go-sqlite3" "database/sql"
"math/rand"
_ "github.com/mattn/go-sqlite3"
)
type irc_msg struct { var begin_char = []byte{'-'}
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 db *sql.DB
var err error 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 // function to split advise message correctly
func filter(msg string, foo bot) cmd { func filter(msg string, foo bot) cmd {
@ -125,18 +60,18 @@ func filter(msg string, foo bot) cmd {
LOG_WARN.Printf("invalid query.") LOG_WARN.Printf("invalid query.")
return c return c
} }
group_id := 0
if rows.Next() { if rows.Next() {
group_id := 0
rows.Scan(&group_id) rows.Scan(&group_id)
c.groups = append(c.groups, fmt.Sprintf("%d", group_id)) c.groups = append(c.groups, fmt.Sprintf("%d", group_id))
rows.Close()
} else { } else {
c.valid = false if c.add {
c.error = "Group name " + group + " is invalid." c.groups = append(c.groups, addgroups([]string{group}, nil)...)
rows.Close()
return c
} }
} }
rows.Close()
defer stmt.Close()
}
c.suffix = res[3] c.suffix = res[3]
c.valid = true c.valid = true
} else { } else {
@ -158,6 +93,7 @@ func filter(msg string, foo bot) cmd {
} }
c.cmd = strings.TrimSpace(c.cmd) c.cmd = strings.TrimSpace(c.cmd)
c.suffix = strings.TrimSpace(c.suffix) c.suffix = strings.TrimSpace(c.suffix)
c.groups = unique_str(c.groups)
return c return c
} }
@ -174,65 +110,41 @@ func getRandomEntry(c cmd) string {
return task return task
} }
// line: func addgroups(new_groups []string, msg *irc_msg) []string {
// >befehl <[groups]> <name>
// 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
}
// 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 = ?") stat_sel, err := db.Prepare("select id from groups where name = ?")
checkErr(err) checkErr(err)
stat_ins, err := db.Prepare("insert into groups(name) values (?)") stat_ins, err := db.Prepare("insert into groups(name) values (?)")
checkErr(err) checkErr(err)
var groups_added []string var groups_added []string
var groupids_added []string
for _, group := range new_groups { for _, group := range new_groups {
fmt.Println(group)
ret, err := stat_sel.Query(group) ret, err := stat_sel.Query(group)
if ret.Next() { if ret.Next() {
ret.Close() ret.Close()
continue continue
} }
_, err = stat_ins.Exec(group) groupid_res, err := stat_ins.Exec(group)
checkErr(err) checkErr(err)
defer stat_ins.Close()
groupid, err := groupid_res.LastInsertId()
checkErr(err)
groupids_added = append(groupids_added, fmt.Sprintf("%d", groupid))
groups_added = append(groups_added, group) groups_added = append(groups_added, group)
} }
if msg != nil {
if len(groups_added) > 0 { 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 { } 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) checkErr(err)
if sorter_row.Next() { if sorter_row.Next() {
var sorter_id string var sorter_id string
@ -244,53 +156,72 @@ func parsemsg(msg irc_msg, foo bot) bool {
sorter_row.Close() sorter_row.Close()
if groups_allow != 0 { 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 return false
} }
if name_allow != 0 && !c.add { if name_allow != 0 && !(*c).add {
// warning: not allowed // warning: not allowed
c.suffix = "" (*c).suffix = ""
} }
c.cmd = tag_id (*c).cmd = tag_id
if has_groups == 0 { 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) checkErr(err)
if sorter_groups_row.Next() { if sorter_groups_row.Next() {
var group_id int var group_id int
sorter_groups_row.Scan(&group_id) 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() sorter_groups_row.Close()
if c.add { if (*c).add {
var tag_name string 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) checkErr(err)
if tag_name_row.Next() { if tag_name_row.Next() {
tag_name_row.Scan(&tag_name) tag_name_row.Scan(&tag_name)
} }
tag_name_row.Close() tag_name_row.Close()
LOG_WARN.Printf("Alias used. Tell the user about that.\n") 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 return false
} }
} }
} else { } else {
LOG_WARN.Printf("no sorter entry, no translation possible\n") 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 false
} }
return true
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) 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) checkErr(err)
LOG_WARN.Printf("added line to table.\n") LOG_WARN.Printf("added line to table.\n")
@ -298,48 +229,94 @@ func parsemsg(msg irc_msg, foo bot) bool {
line_id, err := res.LastInsertId(); line_id, err := res.LastInsertId();
checkErr(err) checkErr(err)
LOG_WARN.Printf("line_id: %d, tag_id: %d, groups: %s\n", line_id, c.cmd, strings.Join(c.groups, "-")) LOG_WARN.Printf("line_id: %d, tag_id: %s, groups: %s\n", line_id, cmd, strings.Join(groups, "-"))
// for tag and all groups // for tag and all groups
if len(c.groups) == 0 { if len(groups) == 0 {
stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)") stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)")
checkErr(err) checkErr(err)
_, err = stat.Exec(line_id, c.cmd) _, err = stat.Exec(line_id, cmd)
checkErr(err) checkErr(err)
LOG_INFO.Printf("inserted foo! \n")
defer stat.Close() defer stat.Close()
} else { } else {
stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)") stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)")
checkErr(err) checkErr(err)
for _, group := range c.groups { for _, group := range groups {
_, err = stat.Exec(line_id, c.cmd, group) _, err = stat.Exec(line_id, cmd, group)
checkErr(err) checkErr(err)
} }
LOG_INFO.Printf("inserted foo! \n")
defer stat.Close() defer stat.Close()
} }
sendmsg(foo.conn, msg.channel, fmt.Sprintf("success adding new super funny enjoyable line with ID %d!", line_id)) (*msg).retmsg = 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 fmt.Sprintf("new line: > %s < (ID %d), into groups %s", line, line_id, strings.Join(groups,","))
return true }
} // line:
// >befehl <[groups]> <name>
task := getRandomEntry(c) // befehl ist genau ein wort
func parsemsg(msg *irc_msg, foo bot) bool {
LOG_INFO.Printf(task) if len((*msg).msg) <= 0 {
row, err := db.Query(task) return false
checkErr(err) }
res := "" if (*msg).msg == "<3" {
if row.Next() { (*msg).msg = string(begin_char[0]) + "flirt kreisi"
row.Scan(&res) }
}
row.Close() if !in((*msg).msg[0], begin_char) {
return false
if len(res) <= 0 { }
LOG_WARN.Printf("no entry found\n") (*msg).msg = (*msg).msg[1:]
res = "No matching entry found :("
} else if len(c.suffix) > 0 { c := filter((*msg).msg, foo)
res = fmt.Sprintf("%s... %s", c.suffix, res) if !c.valid {
} LOG_WARN.Printf("non valid input found.\n")
sendmsg(foo.conn, msg.channel, res) 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)
sendmsg(foo.conn, "horscchtey", addLine(msg, c.suffix, c.groups, c.cmd))
} else {
chooseEntry(msg, &c)
}
return true return true
} }

176
bot.go
View file

@ -1,27 +1,152 @@
package main package main
import ( import (
"os"
"log" "log"
"fmt" "fmt"
"net" "net"
"time" "time"
"bufio"
"strings"
"database/sql"
configo "github.com/distributedio/configo" configo "github.com/distributedio/configo"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
var dead = true func sendmsg (conn net.Conn, channel string, msg string) {
mesg := fmt.Sprintf("PRIVMSG %s :%s\r\n", channel, msg)
type Config struct { fmt.Printf(mesg)
Name string `cfg:"name; boddle; printableascii; IRC nick of bot"` conn.Write([]byte(mesg))
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 bot struct { func scanline_privmsg (msg string, irc *irc_msg) {
Conf Config LOG_ERR.Printf(msg)
conn net.Conn
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() { func main() {
@ -31,33 +156,6 @@ func main() {
if err := configo.Load("./boddle.toml", &boddle.Conf); err != nil { if err := configo.Load("./boddle.toml", &boddle.Conf); err != nil {
log.Fatal(err) log.Fatal(err)
} }
// boddle := bot {
// name: "boddle",
// channel: []string{"#faui2k16", "#fau", "#sigbike", "#sigfreibad"},
// port: 6667,
// server: "irc.fau.de",
// }
LOG_INFO.Println("bot started!") bot_run(&boddle)
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))
}
} }

2
bot.py
View file

@ -12,7 +12,7 @@ import sqlite3 as sql
updater = Updater(token='935673062:AAH4By1EMqAUaD9wgnV3lZQRRBX6e5Lve6g', use_context=True) updater = Updater(token='935673062:AAH4By1EMqAUaD9wgnV3lZQRRBX6e5Lve6g', use_context=True)
# sqlite database # 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() cursor = connection.cursor()
dispatcher = updater.dispatcher dispatcher = updater.dispatcher

8
conf.go Normal file
View file

@ -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"`
}

62
flake.nix Normal file
View file

@ -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;
});
};
}

View file

@ -1,15 +1,10 @@
#!/bin/bash #!/bin/bash
export GOPATH=/home/horscchtey/go export GOPATH=/home/boddle/go
export CC=arm-linux-gnueabihf-gcc
export CXX=arm-linux-gnueabihf-g++
export CGO_ENABLED=1 export CGO_ENABLED=1
export GOOS=linux
export GOARCH=arm
export GOARM=7
declare -a src 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)" declare -i nproc="$(nproc)"
go build -p ${nproc} "${src[@]}" go build -v -p ${nproc} "${src[@]}"

13
go.mod Normal file
View file

@ -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
)

20
go.sum Normal file
View file

@ -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=

45
helpers.go Normal file
View file

@ -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
}

View file

@ -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)
}

40
pepe.go
View file

@ -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")
}

34
types.go Normal file
View file

@ -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
}