;; Botbot: Very basic IRC bot (import (chicken io) (chicken port) (chicken file) (chicken string) (chicken pathname) (chicken process-context) (chicken irregex) matchable srfi-13 srfi-1 uri-common tcp6 openssl) ;; Globals (define nick "botbot") (define username "#phloggersgarage bot") (tcp-read-timeout #f) ;disable read timeout (define (launch-bot host port) (let-values (((in-port out-port) (tcp-connect host port))) ;; Connect to server (if (establish-connection in-port out-port) ;; (bot-loop in-port out-port) (begin (print "Successfully connected!") (bot-loop in-port out-port)) (print "Failed to establish connection. Aborting...")))) (define (establish-connection in-port out-port) (write-msg `(#f #f "NICK" (,nick)) out-port) (write-msg `(#f #f "USER" (,nick "0" "*" ,username)) out-port) (let ((msg (read-msg in-port))) (print msg) (string=? (msg-command msg) "001"))) (define (bot-loop in-port out-port) (let loop ((msg (read-msg in-port))) (match (cons (msg-source msg) (cons (msg-command msg) (msg-args msg))) ((_ "PING" token) (write-msg `(#f #f "PONG" (,token)) out-port)) ((source "PRIVMSG" target args ...) (when (string=? target nick) (print "Someone sent me this message: " args) (write-msg `(#f #f "PRIVMSG" (,source "Message received!")) out-port))) (_ ; Do nothing )) (loop (read-msg in-port)))) (define (read-msg in-port) (let ((msg (string->msg (read-line in-port)))) (print "Received message: " msg) msg)) (define (write-msg msg out-port) (with-output-to-port out-port (lambda () (write-string (conc (msg->string msg) "\r\n")))) (print "Sent message: " msg)) (define msg-regex (irregex '(: (? (: "@" (submatch (+ (~ " "))) (* " "))) (? (: ":" (submatch (+ (~ " " "!" "@"))) (* (~ " ")) ;discard non-nick portion (* " "))) (submatch (+ (~ " "))) (* " ") (? (submatch (+ any)))))) (define (string->msg string) (let ((match (irregex-match msg-regex string))) (list (irregex-match-substring match 1) ; Tags (irregex-match-substring match 2) ; Source (string-upcase (irregex-match-substring match 3)) ; command (parse-message-args (irregex-match-substring match 4))))) ;args (define (msg->string msg) (conc (msg-command msg) (let ((args (msg-args msg))) (if args (conc " " (make-arg-string args)) "")))) (define (make-arg-string args) (let* ((revargs (reverse args)) (final-arg (car revargs)) (first-args (reverse (cdr revargs)))) (conc (string-join first-args " ") " :" final-arg))) (define (parse-message-args argstr) (if argstr (let ((first-split (string-split argstr ":"))) (if (null? first-split) #f (append (string-split (car first-split) " ") (cdr first-split)))))) (define (msg-tags msg) (list-ref msg 0)) (define (msg-source msg) (list-ref msg 1)) (define (msg-command msg) (list-ref msg 2)) (define (msg-args msg) (list-ref msg 3)) (define (print-usage progname) (print "Usage: " progname " host port")) (define (main) (let ((progname (pathname-file (car (argv))))) (match (command-line-arguments) ((host port) (launch-bot host (string->number port))) (_ (print-usage progname))))) (main) .