1 |
diff -uNr a/ircbot/INSTALL b/ircbot/INSTALL |
2 |
--- a/ircbot/INSTALL false |
3 |
+++ b/ircbot/INSTALL c4c41d96ddb71db32e8cd54c22e7250abbc52d51f4b25d8092dc094b4a84100949d0a74378fc33131d2d9a5144156a738f5a91d7e949922898993eb4384b4757 |
4 |
@@ -0,0 +1,19 @@ |
5 |
+INSTALL |
6 |
+ |
7 |
+ * Install SBCL (with sb-thread) and Quicklisp. |
8 |
+ |
9 |
+ * From the SBCL REPL: |
10 |
+ (ql:quickload :cl-irc) |
11 |
+ |
12 |
+ * Use V to press `ircbot` |
13 |
+ |
14 |
+mkdir -p ~/src/ircbot |
15 |
+cd ~/src/ircbot |
16 |
+ |
17 |
+mkdir .wot |
18 |
+cd .wot && wget http://trinque.org/trinque.asc && cd .. |
19 |
+ |
20 |
+v.pl init http://trinque.org/src/ircbot |
21 |
+v.pl press ircbot-genesis ircbot-genesis.vpatch |
22 |
+ |
23 |
+ln -s ~/src/ircbot/ircbot-genesis ~/quicklisp/local-projects/ircbot |
24 |
diff -uNr a/ircbot/README b/ircbot/README |
25 |
--- a/ircbot/README false |
26 |
+++ b/ircbot/README 6a76028622c6bb986d68d42b7b133221d3659d56da1bd5d4e8b39f0a6075a17d8b3ee33c8e37c7d4b3ec1f108ad940777d762bab01763a63742733a1445660d4 |
27 |
@@ -0,0 +1,8 @@ |
28 |
+README |
29 |
+ |
30 |
+`ircbot` provides a simple CLOS class, `ircbot`, which will maintain a |
31 |
+connection to a single IRC channel via `cl-irc`. The bot will handle |
32 |
+ping/pong and detect failed connections, and is capable of |
33 |
+authenticating with NickServ (using ghost when necessary to |
34 |
+reacquire nick). |
35 |
+ |
36 |
diff -uNr a/ircbot/USAGE b/ircbot/USAGE |
37 |
--- a/ircbot/USAGE false |
38 |
+++ b/ircbot/USAGE 20d07e6f190f6655a2884e60c1d6a7eccdd76d019797bb165c716a6919fb5161a31b1956b9dda7927839837a924ae6ea3d0c1a833458bbbd5765f76548d637d2 |
39 |
@@ -0,0 +1,14 @@ |
40 |
+USAGE |
41 |
+ |
42 |
+(asdf:load-system :ircbot) |
43 |
+(defvar *bot*) |
44 |
+(setf *bot* |
45 |
+ (ircbot:make-ircbot |
46 |
+ "chat.freenode.net" 6667 "nick" "password" "#channel")) |
47 |
+ |
48 |
+; connect in separate thread, returning thread |
49 |
+(ircbot:ircbot-connect-thread *bot*) |
50 |
+ |
51 |
+; or connect using the current thread |
52 |
+; (ircbot:ircbot-connect *bot*) |
53 |
+ |
54 |
diff -uNr a/ircbot/ircbot.asd b/ircbot/ircbot.asd |
55 |
--- a/ircbot/ircbot.asd false |
56 |
+++ b/ircbot/ircbot.asd 9dfba5c2bd97e5ffc2ab071786b14c05dfda1c898ef58a5d87ea020bde042bf76c0e88b78f6d4a4fbd453aabea58e4710bf717defa023dfe410d19ac01c4e2d9 |
57 |
@@ -0,0 +1,10 @@ |
58 |
+;;;; ircbot.asd |
59 |
+ |
60 |
+(asdf:defsystem #:ircbot |
61 |
+ :description "ircbot" |
62 |
+ :author "Michael Trinque <mike@trinque.org>" |
63 |
+ :license "http://trilema.com/2015/a-new-software-licensing-paradigm/" |
64 |
+ :depends-on (#:cl-irc) |
65 |
+ :components ((:file "package") |
66 |
+ (:file "ircbot"))) |
67 |
+ |
68 |
diff -uNr a/ircbot/ircbot.lisp b/ircbot/ircbot.lisp |
69 |
--- a/ircbot/ircbot.lisp false |
70 |
+++ b/ircbot/ircbot.lisp 738a2c0ca77a69fc7805cbfc668da1b61e25e512d6d9f3bdf200968e39eb201bb87be83c6ae1411c6e6a5c7dd63524a5b5ab71d99a2813ac85fc5ac4360b3b17 |
71 |
@@ -0,0 +1,143 @@ |
72 |
+(in-package #:ircbot) |
73 |
+ |
74 |
+(defvar *max-lag* 60) |
75 |
+(defvar *ping-freq* 30) |
76 |
+ |
77 |
+ |
78 |
+(defclass ircbot () |
79 |
+ ((connection :accessor ircbot-connection :initform nil) |
80 |
+ (channels :reader ircbot-channels :initarg :channels) |
81 |
+ (server :reader ircbot-server :initarg :server) |
82 |
+ (port :reader ircbot-port :initarg :port) |
83 |
+ (nick :reader ircbot-nick :initarg :nick) |
84 |
+ (password :reader ircbot-password :initarg :password) |
85 |
+ (connection-security :reader ircbot-connection-security |
86 |
+ :initarg :connection-security |
87 |
+ :initform :none) |
88 |
+ (run-thread :accessor ircbot-run-thread :initform nil) |
89 |
+ (ping-thread :accessor ircbot-ping-thread :initform nil) |
90 |
+ (lag :accessor ircbot-lag :initform nil) |
91 |
+ (lag-track :accessor ircbot-lag-track :initform nil))) |
92 |
+ |
93 |
+(defmethod ircbot-check-nick ((bot ircbot) message) |
94 |
+ (destructuring-bind (target msgtext) (arguments message) |
95 |
+ (declare (ignore msgtext)) |
96 |
+ (if (string= target (ircbot-nick bot)) |
97 |
+ (ircbot-nickserv-auth bot) |
98 |
+ (ircbot-nickserv-ghost bot)))) |
99 |
+ |
100 |
+(defmethod ircbot-connect :around ((bot ircbot)) |
101 |
+ (let ((conn (connect :nickname (ircbot-nick bot) |
102 |
+ :server (ircbot-server bot) |
103 |
+ :port (ircbot-port bot) |
104 |
+ :connection-security (ircbot-connection-security bot)))) |
105 |
+ (setf (ircbot-connection bot) conn) |
106 |
+ (call-next-method) |
107 |
+ (read-message-loop conn))) |
108 |
+ |
109 |
+(defmethod ircbot-connect ((bot ircbot)) |
110 |
+ (let ((conn (ircbot-connection bot))) |
111 |
+ (add-hook conn 'irc-err_nicknameinuse-message (lambda (message) |
112 |
+ (declare (ignore message)) |
113 |
+ (ircbot-randomize-nick bot))) |
114 |
+ (add-hook conn 'irc-kick-message (lambda (message) |
115 |
+ (declare (ignore message)) |
116 |
+ (map nil |
117 |
+ (lambda (c) (join (ircbot-connection bot) c)) |
118 |
+ (ircbot-channels bot)))) |
119 |
+ (add-hook conn 'irc-notice-message (lambda (message) |
120 |
+ (ircbot-handle-nickserv bot message))) |
121 |
+ (add-hook conn 'irc-pong-message (lambda (message) |
122 |
+ (ircbot-handle-pong bot message))) |
123 |
+ (add-hook conn 'irc-rpl_welcome-message (lambda (message) |
124 |
+ (ircbot-start-ping-thread bot) |
125 |
+ (ircbot-check-nick bot message))))) |
126 |
+ |
127 |
+(defmethod ircbot-connect-thread ((bot ircbot)) |
128 |
+ (setf (ircbot-run-thread bot) |
129 |
+ (sb-thread:make-thread (lambda () (ircbot-connect bot)) |
130 |
+ :name "ircbot-run"))) |
131 |
+ |
132 |
+(defmethod ircbot-disconnect ((bot ircbot) &optional (quit-msg "...")) |
133 |
+ (sb-sys:without-interrupts |
134 |
+ (quit (ircbot-connection bot) quit-msg) |
135 |
+ (setf (ircbot-lag-track bot) nil) |
136 |
+ (setf (ircbot-connection bot) nil) |
137 |
+ (if (not (null (ircbot-run-thread bot))) |
138 |
+ (sb-thread:terminate-thread (ircbot-run-thread bot))) |
139 |
+ (if (not (or (null (ircbot-ping-thread bot)) (equal sb-thread:*current-thread* (ircbot-ping-thread bot)))) |
140 |
+ (sb-thread:terminate-thread (ircbot-ping-thread bot))))) |
141 |
+ |
142 |
+(defmethod ircbot-reconnect ((bot ircbot) &optional (quit-msg "...")) |
143 |
+ (let ((threaded-p (not (null (ircbot-run-thread bot))))) |
144 |
+ (ircbot-disconnect bot quit-msg) |
145 |
+ (if threaded-p |
146 |
+ (ircbot-connect-thread bot) |
147 |
+ (ircbot-connect bot)))) |
148 |
+ |
149 |
+(defmethod ircbot-handle-nickserv ((bot ircbot) message) |
150 |
+ (let ((conn (ircbot-connection bot))) |
151 |
+ (if (string= (host message) "services.") |
152 |
+ (destructuring-bind (target msgtext) (arguments message) |
153 |
+ (declare (ignore target)) |
154 |
+ (cond ((string= msgtext "This nickname is registered. Please choose a different nickname, or identify via /msg NickServ identify <password>.") |
155 |
+ (ircbot-nickserv-auth bot)) |
156 |
+ ((string= msgtext (format nil "~A has been ghosted." (ircbot-nick bot))) |
157 |
+ (nick conn (ircbot-nick bot))) |
158 |
+ ((string= msgtext (format nil "~A is not online." (ircbot-nick bot))) |
159 |
+ (ircbot-nickserv-auth bot)) |
160 |
+ ((string= msgtext (format nil "You are now identified for ~A." (ircbot-nick bot))) |
161 |
+ (map nil (lambda (c) (join conn c)) (ircbot-channels bot)))))))) |
162 |
+ |
163 |
+(defmethod ircbot-handle-pong ((bot ircbot) message) |
164 |
+ (destructuring-bind (server ping) (arguments message) |
165 |
+ (declare (ignore server)) |
166 |
+ (let ((response (ignore-errors (parse-integer ping)))) |
167 |
+ (when response |
168 |
+ (setf (ircbot-lag-track bot) (delete response (ircbot-lag-track bot) :test #'=)) |
169 |
+ (setf (ircbot-lag bot) (- (received-time message) response)))))) |
170 |
+ |
171 |
+(defmethod ircbot-nickserv-auth ((bot ircbot)) |
172 |
+ (privmsg (ircbot-connection bot) "NickServ" |
173 |
+ (format nil "identify ~A" (ircbot-password bot)))) |
174 |
+ |
175 |
+(defmethod ircbot-nickserv-ghost ((bot ircbot)) |
176 |
+ (privmsg (ircbot-connection bot) "NickServ" |
177 |
+ (format nil "ghost ~A ~A" (ircbot-nick bot) (ircbot-password bot)))) |
178 |
+ |
179 |
+(defmethod ircbot-randomize-nick ((bot ircbot)) |
180 |
+ (nick (ircbot-connection bot) |
181 |
+ (format nil "~A-~A" (ircbot-nick bot) (+ (random 90000) 10000)))) |
182 |
+ |
183 |
+(defmethod ircbot-send-message ((bot ircbot) target message-text) |
184 |
+ (privmsg (ircbot-connection bot) target message-text)) |
185 |
+ |
186 |
+(defmethod ircbot-start-ping-thread ((bot ircbot)) |
187 |
+ (let ((conn (ircbot-connection bot))) |
188 |
+ (setf (ircbot-ping-thread bot) |
189 |
+ (sb-thread:make-thread |
190 |
+ (lambda () |
191 |
+ (loop |
192 |
+ do (progn (sleep *ping-freq*) |
193 |
+ (let ((ct (get-universal-time))) |
194 |
+ (push ct (ircbot-lag-track bot)) |
195 |
+ (ping conn (princ-to-string ct)))) |
196 |
+ until (ircbot-timed-out-p bot)) |
197 |
+ (ircbot-reconnect bot)) |
198 |
+ :name "ircbot-ping")))) |
199 |
+ |
200 |
+(defmethod ircbot-timed-out-p ((bot ircbot)) |
201 |
+ (loop |
202 |
+ with ct = (get-universal-time) |
203 |
+ for v in (ircbot-lag-track bot) |
204 |
+ when (> (- ct v) *max-lag*) |
205 |
+ do (return t))) |
206 |
+ |
207 |
+ |
208 |
+(defun make-ircbot (server port nick password channels) |
209 |
+ (make-instance 'ircbot |
210 |
+ :server server |
211 |
+ :port port |
212 |
+ :nick nick |
213 |
+ :password password |
214 |
+ :channels channels)) |
215 |
diff -uNr a/ircbot/manifest b/ircbot/manifest |
216 |
--- a/ircbot/manifest false |
217 |
+++ b/ircbot/manifest 8a535c4a26e5fba0aa52c44bfcd84176de82568ddd7e98e8fb84ab48b5dbc0bc315c09f37c8eb7201a88fb804a18712d1a876f02e06552157ebefc63a123a9c4 |
218 |
@@ -0,0 +1 @@ |
219 |
+658020 ircbot_genesis thimbronion This genesis combines trinque's genesis with ben_vulpes' multi-channel fix and whaack's reconnection fix. Theses patches were generated using differing hash algos and can not be applied by any existing v implementation and I do not see any reason that anyone would find ircbot usable without any of them. |
220 |
diff -uNr a/ircbot/package.lisp b/ircbot/package.lisp |
221 |
--- a/ircbot/package.lisp false |
222 |
+++ b/ircbot/package.lisp d186f3af63443337d23a0bfbaae79246fae2b2781acb53109132b42f84cf46acabf1fe12f2aba00c452e679c721ca955daaf302e1a04a56fccb8125d95e1527c |
223 |
@@ -0,0 +1,18 @@ |
224 |
+;;;; package.lisp |
225 |
+ |
226 |
+(defpackage :ircbot |
227 |
+ (:use :cl |
228 |
+ :cl-irc) |
229 |
+ (:export :make-ircbot |
230 |
+ :ircbot |
231 |
+ :ircbot-connect |
232 |
+ :ircbot-connect-thread |
233 |
+ :ircbot-disconnect |
234 |
+ :ircbot-reconnect |
235 |
+ :ircbot-connection |
236 |
+ :ircbot-channels |
237 |
+ :ircbot-send-message |
238 |
+ :ircbot-server |
239 |
+ :ircbot-port |
240 |
+ :ircbot-nick |
241 |
+ :ircbot-lag)) |
242 |
/ |