anna/anna.scm

113 lines
3.1 KiB
Scheme

#!/usr/bin/guile
!#
(use-modules (ice-9 rdelim)
(ice-9 textual-ports)
(ice-9 format)
(ice-9 control)
(ice-9 sandbox)
(rnrs exceptions))
(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 (evaluate str)
(guard (ex
(else (begin (display "error encountered!\n")
'error)))
(eval-in-sandbox (read (open-input-string str)))))
(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 <s-expr>."))
((equal? ":!eval" (slist-ref data 3))
(let* ((expr (string-concatenate (intersperse " " (cdr (member ":!eval" data))))))
(send-message stream chn (evaluate expr))))
((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))