From d1a9ed6bbed18695c0e62abbbfdfa151ca142729 Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Wed, 6 Mar 2019 21:50:36 +0100 Subject: [PATCH] First generation tiger-bot. --- Makefile | 14 +++ run.sh | 25 ++++++ tiger-bot.tig | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 Makefile create mode 100644 run.sh create mode 100644 tiger-bot.tig diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..afcdbe2 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ + +TIGERC=~jmaa/Git/simba/src/tigerc + +build: tiger-bot.bin + +run: build + bash ./run.sh + +tiger-bot.bin: tiger-bot.tig + $(TIGERC) --out ./tiger-bot.bin tiger-bot.tig + +clean: + rm -f *.log *.bin + diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..0660a0f --- /dev/null +++ b/run.sh @@ -0,0 +1,25 @@ + +LOG_SERVER_TO_CLIENT=./log_s2c.log +LOG_CLIENT_TO_SERVER=./log_c2s.log + +CLIENT_RUNTIME="./tiger-bot.bin" +COMMS_RUNTIME="openssl s_client -connect irc.guava.space:6697" + +# Ensure logs are new +rm -f "$LOG_CLIENT_TO_SERVER" +rm -f "$LOG_SERVER_TO_CLIENT" +touch "$LOG_CLIENT_TO_SERVER" +touch "$LOG_SERVER_TO_CLIENT" + +# Begin communication +echo "Beginning connection..." +tail -f -n 0 "$LOG_CLIENT_TO_SERVER" | eval $COMMS_RUNTIME >> "$LOG_SERVER_TO_CLIENT" & + +echo "Waiting for SSL handshake to complete..." +sleep 1 + +echo "Starting bot..." +tail -f -n 0 "$LOG_SERVER_TO_CLIENT" | eval $CLIENT_RUNTIME >> "$LOG_CLIENT_TO_SERVER" + +#echo "Bot started!..." + diff --git a/tiger-bot.tig b/tiger-bot.tig new file mode 100644 index 0000000..2c893ba --- /dev/null +++ b/tiger-bot.tig @@ -0,0 +1,234 @@ + +let /* Parsing util */ + + var seen_char := 0 + var next_char := "IS NOT A CHAR; SHOULD NOT EVER BE VISIBLE!" + + function peak_char (): string = + ( if not(seen_char) + then ( next_char := getchar() + ; seen_char := 1 ) + ; next_char ) + + function pop_char (): string = + let var char := peak_char() + in seen_char := 0 + ; char + end + + /* String and number util */ + + function max (a:int, b:int): int = + if a > b + then a + else b + + function min (a:int, b:int): int = + if a < b + then a + else b + + function safe_substring (str: string, i_start: int, i_end: int): string = + ( i_start := max(0, i_start) + ; i_end := min(size(str) - 1, i_end) + ; if i_start > i_end + then "" + else substring(str, i_start, i_end - i_start + 1) ) + + /* Messages */ + + type str_arr = array of string + type message = { /* TODO: @tags, :source, */ + command: string + , parameters: str_arr + , num_parameters: int } + + function parse_message (plain_msg: string): message = + let var msg := message + { command = "NO CMD" + , parameters = str_arr[16] of "NO PARAM" /* TODO: Support any number of paramters */ + , num_parameters = -1 } + + var word_start_i := 0 + + function skip_ws () = + while substring(plain_msg, word_start_i, 1) = " " + do word_start_i := word_start_i + 1 + + function skip_to_ws () = + while substring(plain_msg, word_start_i, 1) <> " " + do word_start_i := word_start_i + 1 + + in skip_ws() + + /* Skip @tags */ + ; if substring(plain_msg, word_start_i, 1) = "@" + then skip_to_ws() + + ; skip_ws() + + /* Skip :source */ + ; if substring(plain_msg, word_start_i, 1) = ":" + then skip_to_ws() + + ; skip_ws() + + ; for i := word_start_i to size(plain_msg) + do let var char := if i < size(plain_msg) + then ord(substring(plain_msg, i, 1)) + else ord(" ") /* Ensures that msg parsing + always ends on a space character */ + + in if char = ord(" ") + then (if word_start_i < i + then ( if msg.num_parameters < 0 + then msg.command := safe_substring(plain_msg, word_start_i, i-1) + else msg.parameters[msg.num_parameters] := safe_substring(plain_msg, word_start_i, i-1) + ; msg.num_parameters := msg.num_parameters + 1) + ; word_start_i := i + 1) + + else if char = ord(":") + then ( msg.parameters[msg.num_parameters] := safe_substring(plain_msg, i+1, size(plain_msg)) + ; msg.num_parameters := msg.num_parameters + 1 + ; break ) + + end + + /* Rather return nil than an incorrect message */ + ; if msg.command <> "NO CMD" & msg.num_parameters >= 0 + then msg + else nil + end + + function format_message (msg: message): string = + let var str := msg.command + in for i := 0 to msg.num_parameters-2 + do str := concat(concat(str, " "), msg.parameters[i]) + + /* Last parameter */ + ; if msg.num_parameters + then str := concat(concat(str, " :"), msg.parameters[msg.num_parameters-1]) + + ; str + end + + /* Main loop */ + + var have_registered := 0 + + function read_next_message(): message = + let var msg := "" + function is_eoc(c: string): int = + c = "\n" | c = "\013" + + /* Concat until newline */ + in while peak_char() <> "\013" + do ( msg := concat(msg, pop_char()) + ; /*log_info(msg)*/ () ) + + /* Ignore newline */ + ; pop_char(); pop_char() + + /* Parse message */ + ; parse_message(msg) + end + + function send_msg (msg: message) = + ( print(format_message(msg)) + ; print("\n") + ; flush() ) + + function cmd0 (cmd: string): message = + message { command = cmd + , parameters = str_arr[0] of "" + , num_parameters = 0 } + function cmd1 (cmd: string, param1: string): message = + message { command = cmd + , parameters = str_arr[1] of param1 + , num_parameters = 1 } + function cmd2 (cmd: string, param1: string, param2:string): message = + let var params := str_arr[2] of param1 + in params[1] := param2 + ; message { command = cmd + , parameters = params + , num_parameters = 2 } + end + + function ping_respond () = + let var msg := read_next_message() + + in if msg.command = "PING" + then send_msg(cmd1("PONG", msg.parameters[0])) + end + + function quit(quit_msg: string) = + ( log_info(concat("Quitting: ", quit_msg)) + ; send_msg(cmd1("QUIT", quit_msg)) + ; exit(0) ) + + function log_info(info: string) = + if have_registered + then send_msg(cmd2("PRIVMSG", "Jmaa", info)) + + function is_char_digit(c: int): int = + ord("0") <= c & c <= ord("9") + + function is_number_string(c: string): int = + let var derp := 1 + in for i := 0 to size(c) - 1 + do if not(is_char_digit(ord(substring(c, i, 1)))) + then ( derp := 0 + ; break ) + ; derp + end + + function main_loop () = + let var msg := read_next_message() + + in if msg = nil + then log_info("Could not parse message!") + /*; quit("Could not parse message") )*/ + + /* Handle number messages */ + else if is_number_string(msg.command) + then () /* Ignore */ + + /* Handle pings */ + else if msg.command = "PING" + then send_msg(cmd1("PONG", msg.parameters[0])) + + /* Handle yo */ + else if msg.command = "PRIVMSG" & msg.parameters[1] = "yo" + then send_msg(cmd2("PRIVMSG", msg.parameters[0], "Yo yourself")) + + /* Handle ERROR messages */ + else if msg.command = "ERROR" + then quit("Got ERROR message") + + /* Do nothing */ + else () /*log_info(concat("Got message, but did nothing: ", format_message(msg)))*/ + + /* THE RIDE NEVER ENDS */ + ; main_loop() + end + +in /* Establish connection */ + print("USER tiger-bot * * : yo\n") + ; print("NICK bot-fucker\n") + ; flush() + + /* Respond to PING */ + ; ping_respond() + ; have_registered := 1 + + /* Connect to channel and greet */ + ; send_msg(cmd1("JOIN", "#bot-test")) + ; send_msg(cmd2("PRIVMSG", "#bot-test", "Whatup motherfuckers?")) + + /* Start normal connection */ + ; main_loop() + + /* Exit! */ + ; quit("Nothing more to say") +end +