Skip to content

Instantly share code, notes, and snippets.

@4poc
Last active December 29, 2015 19:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 4poc/7716437 to your computer and use it in GitHub Desktop.
Save 4poc/7716437 to your computer and use it in GitHub Desktop.
Simple Example IRC Bot, my first clojure program!
(ns cljbot
(:use [clojure.string :only (split join)]
[clojure.pprint :only (pprint)])
(:import (javax.net.ssl SSLSocketFactory X509TrustManager SSLContext TrustManager)
(java.io BufferedReader PrintWriter InputStreamReader)
(java.security SecureRandom)
(java.util.regex Pattern)))
(def HOST "irc.teranetworks.de")
(def PORT 6697)
(def CHANNEL "#test")
(def IDENT
{:nick "conjurer"
:username "cljbot"
:realname "Clojure"}
)
(def PREFIX "!")
(defn trust-invalid-manager []
"This allows the ssl socket to connect with invalid/self-signed SSL certs."
(reify X509TrustManager
(getAcceptedIssuers [this] nil)
(checkClientTrusted [this certs authType])
(checkServerTrusted [this certs authType])
)
)
(defn get-irc-conn [host port]
"Connects to host and port and returns input and output streams."
(def ssl-context (SSLContext/getInstance "SSL"))
(.init ssl-context nil (into-array TrustManager [(trust-invalid-manager)])
(new SecureRandom))
(let [socket (.createSocket (.getSocketFactory ssl-context) host port)]
{:in (new BufferedReader (new InputStreamReader (.getInputStream socket)))
:out (new PrintWriter (.getOutputStream socket))}
)
)
(defn parse-raw [line]
"Parses the messages sent from the server into a descriptive hash map."
(let [[_ source command args message] (re-matches
#"^(?:[:](\S+) )?(\S+)(?: (?!:)(.+?))?(?: [:](.+))?$" line)]
{:source source
:command command
:args args
:message message}
)
)
(defn parse-privmsg [params]
"Parses privmsg using a simple command syntax, similar to other irc bots."
(def pattern (re-pattern (str "^(" (Pattern/quote PREFIX) "|"
(Pattern/quote (:nick IDENT)) "[:|,] ?)?([^ ]+) ?(.*)?$"))
)
(if-let [[_ prefix action args] (re-matches pattern (:message params))]
(if (or prefix (and (not prefix) (.equals (:args params) (:nick IDENT))))
{:prefix prefix :action action :args (split args #" ")}
)
)
)
(defn action-ping [sendline reply args params]
(reply "pong")
)
(defn action-version [sendline reply args params]
(reply "clojure irc bot!")
)
(defn action-quit [sendline reply args params]
(sendline (str "QUIT :" (join " " args)))
)
(defn handle-privmsg [params sendline]
(defn reply [message]
(if (= (.indexOf (:args params) "#") 0)
(def dest (:args params))
(def dest (:source params))
)
(sendline (str "PRIVMSG " dest " :" message))
)
(if-let [{action :action args :args} (parse-privmsg params)]
(let [fnk (ns-resolve 'cljbot (symbol (str "action-" action)))]
(if fnk (fnk sendline reply args params))
)
)
)
(defn handle-raw [params sendline]
(when (.equals (:command params) "PING")
(sendline (str "PONG :" (:message params)))
)
(when (.equals (:command params) "376")
(sendline (str "JOIN " CHANNEL))
)
(when (.equals (:command params) "PRIVMSG")
(handle-privmsg params sendline)
)
)
(defn mainloop [in sendline]
(doseq [line (line-seq in)]
(handle-raw (parse-raw line) sendline)
)
)
(defn -main [& args]
(let [{in :in out :out} (get-irc-conn HOST PORT)]
(defn sendline [line]
"Sends a single line to the irc server."
(println "<" line)
(doto out
(.print (str line "\r\n"))
(.flush)
)
)
(println "bot connected, sending nick/user...")
(sendline (str "NICK " (:nick IDENT)))
(sendline (str "USER " (:username IDENT) " 0 * :" (:realname IDENT)))
(mainloop in sendline)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment