#!/usr/bin/guile !# (use-modules (ice-9 rdelim) (ice-9 textual-ports) (ice-9 format)) (define +channels+ '("#tildetown" "#bots")) (define (scdr lst) "Safe CDR. Returns CDR of lst, if it is a list. Returns lst otherwise." (if (not (pair? lst)) lst (cdr lst))) (define (scar lst) "Safe CAR, see scdr." (if (not (pair? lst)) lst (car lst))) (define (slist-ref lst index) "Safe list-ref, see scdr." (if (< (length lst) (+ index 1)) '() (list-ref lst index))) (define (slist-tail lst index) "Safe list-tail, see scdr." (if (< (length lst) (+ index 1)) '() (list-tail lst index))) (define (string-tail str index) "List-tail for strings." (list->string (list-tail (string->list str) index))) (define (intersperse sep lst) "Returns a new list with sep between each element of lst." (cond ((or (null? lst) (null? (cdr lst))) lst) (else (cons (car lst) (cons sep (intersperse sep (cdr lst))))))) (define (make-connection host port) "Connect to irc server on host:port, returns a socket for reading and writing." (let* ((sock (socket PF_INET SOCK_STREAM 0)) (con (connect sock AF_INET (car (vector-ref (gethost host) 4)) port))) sock)) (define (pong stream) (format stream "PONG :anna\r\n")) (define (send-nick stream) (format stream "NICK anna\r\n")) (define (send-user stream) (format stream "USER anna 0.0.0.0 anna :Anna\r\n")) (define (join-channels stream) (for-each (lambda (chn) (format stream "JOIN ~a\r\n" chn)) +channels+)) (define (send-message stream chn msg) (format stream "PRIVMSG ~a :~a\r\n" chn msg)) (define (send-action stream chn action) (format stream "PRIVMSG ~a :\x01ACTION ~a\x01\r\n" chn action)) (define (main-loop stream) (let* ((inl (read-line stream)) (data (string-tokenize inl)) (chn (scar (scdr (member "PRIVMSG" data))))) ;; debug print (format #t "~s~%" data) (cond ((equal? (car data) "PING") (pong stream)) ((or (equal? ":!rollcall" (slist-ref data 3)) (equal? ":!anna" (slist-ref data 3))) (send-message stream chn "Hello! I respond to !rollcall, !anna, and !eval .")) ((equal? ":!eval" (slist-ref data 3)) (let* ((expr (string-concatenate (intersperse " " (cdr (member ":!eval" data)))))) (send-message stream chn (eval (read (open-input-string expr)) (interaction-environment))))) ((and (= 7 (length data)) (equal? (list-tail data 4) '("ACTION" "shoots" "anna"))) (send-action stream chn "dies") (close-port stream) (exit))) (main-loop stream))) (let* ((io (make-connection "127.0.0.1" 6667))) (send-nick io) (send-user io) (join-channels io) (main-loop io))