1
0
Fork 0
forked from fun/fun
fun/examples/net/irc_echo_bot.fun

102 lines
2.6 KiB
Standard ML

#!/usr/bin/env fun
/*
* IRC Echo Bot example using lib/net/irc.fun
*
* Connects to an IRC server, registers, joins #funlang, and listens for
* messages. If a message contains "!echo <text>", the bot replies with <text>.
*
* Notes:
* - Works over plain TCP. For TLS, point host/port to a local TLS tunnel
* (e.g., stunnel) and set use_tls=1.
*/
#include <net/irc.fun>
#include <strings.fun>
#include <io/console.fun>
#include <utils/datetime.fun>
// --- Configuration ---
// freenode (plain): host="chat.freenode.net", port=6667, use_tls=0
// For TLS via a local tunnel to remote 6697: host="127.0.0.1", port=<local>, use_tls=1
host = "chat.freenode.net"
port = 6667
use_tls = 0
bot_nick = "FunEchoBot" // Choose an unused nickname
bot_user = "funecho"
bot_real = "Fun Echo Bot"
bot_pass = "" // Optional network password (not NickServ)
channel = "#fun-lang"
// Globals used by the callback
g_client = nil
g_dt = DateTime()
// Extract nick from a prefix of form "nick!user@host" or just "nick"
fun prefix_nick(prefix)
p = to_string(prefix)
ex = find(p, "!")
if (ex >= 0)
return substr(p, 0, ex)
at = find(p, "@")
if (at >= 0)
return substr(p, 0, at)
return p
// Callback for IRCClient.pump(line, msg)
fun on_line(line, msg)
// Print all received lines to console
print(line)
cmd = msg["command"]
if (cmd == "PRIVMSG")
params = msg["params"]
trg = ""
if (len(params) > 0)
trg = params[0]
txt = msg["trailing"]
// Decide reply target: channel or private
reply_to = trg
if (str_to_upper(trg) == str_to_upper(bot_nick))
reply_to = prefix_nick(msg["prefix"]) // PM -> reply to user
// Detect command pattern: !echo <text>
if (len(txt) >= 6)
if (substr(txt, 0, 6) == "!echo ")
echo_text = substr(txt, 6, len(txt) - 6)
if (g_client != nil)
g_client.privmsg(reply_to, echo_text)
// --- Main flow ---
mode = " (plain)"
if (use_tls == 1)
mode = " (TLS via tunnel)"
print("Connecting to " + host + ":" + to_string(port) + mode)
c = IRCClient(host, port, use_tls)
if (!c.connect())
print("Failed to connect.")
exit(1)
g_client = c
c.register(bot_nick, bot_user, bot_real, bot_pass)
// Process greetings and auto-respond to PINGs via pump()
start = g_dt.now_ms()
while (g_dt.now_ms() - start < 3000)
c.pump(on_line)
// Join the channel and announce
c.join(channel)
g_dt.sleep_ms(500)
c.privmsg(channel, "FunEchoBot online. Say: !echo <your text>")
// Stay connected and keep handling messages until interrupted
print("Listening (press Ctrl-C to quit)...")
while (true)
c.pump(on_line)
// avoid busy loop when there's no data
g_dt.sleep_ms(50)