1
0
tiger-bot/tiger-bot.tig

261 lines
7.4 KiB
Plaintext
Raw Permalink Normal View History

2024-09-24 21:25:49 +00:00
/*
# Tiger-bot
Attempt at writing an IRC bot in Tiger. Actually mostly worked,
by wrapping the call in a specifically designed script to handle SSL
and the connection. The Tiger implementation only needed to respond to
messages on input, by writing to output.
Design started on 6. Marts 2019.
## Usage
Run using `run.sh`.
Requires `openssl` utility.
*/
2019-03-06 20:50:36 +00:00
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 wait_for_msg (cmd: string): message =
2019-03-06 20:50:36 +00:00
let var msg := read_next_message()
in if msg.command <> cmd
then wait_for_msg(cmd)
else msg
end
2019-03-06 20:50:36 +00:00
function ping_respond () =
let var msg := wait_for_msg("PING")
in send_msg(cmd1("PONG", msg.parameters[0]))
2019-03-06 20:50:36 +00:00
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 */
/* At this point, we can register */
; print("USER tiger-bot * * : yo\n")
2024-09-24 20:18:44 +00:00
; print("NICK TigerBot\n")
2019-03-06 20:50:36 +00:00
; flush()
/* Wait for first PING, and respond to it */
2019-03-06 20:50:36 +00:00
; ping_respond()
/* Wait for 001; so we know that we have been connected and
* registered */
2019-03-06 20:50:36 +00:00
; have_registered := 1
; wait_for_msg("001")
2019-03-06 20:50:36 +00:00
/* Connect to channel and greet */
; send_msg(cmd1("JOIN", "#bot-test"))
2024-09-24 20:18:44 +00:00
; send_msg(cmd2("PRIVMSG", "#bot-test", "Hello, how's it going?"))
2019-03-06 20:50:36 +00:00
/* Start normal connection */
; main_loop()
/* Exit! */
; quit("Nothing more to say")
end