nadoka 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/ChangeLog.old +1553 -0
- data/Gemfile +4 -0
- data/README.org +31 -0
- data/Rakefile +1 -0
- data/bin/nadoka +13 -0
- data/lib/rss_check.rb +206 -0
- data/lib/tagparts.rb +206 -0
- data/nadoka.gemspec +29 -0
- data/nadoka.rb +123 -0
- data/nadokarc +267 -0
- data/ndk/bot.rb +241 -0
- data/ndk/client.rb +288 -0
- data/ndk/config.rb +571 -0
- data/ndk/error.rb +61 -0
- data/ndk/logger.rb +311 -0
- data/ndk/server.rb +784 -0
- data/ndk/server_state.rb +324 -0
- data/ndk/version.rb +44 -0
- data/plugins/autoawaybot.nb +66 -0
- data/plugins/autodumpbot.nb +227 -0
- data/plugins/autoop.nb +56 -0
- data/plugins/backlogbot.nb +88 -0
- data/plugins/checkbot.nb +64 -0
- data/plugins/cronbot.nb +20 -0
- data/plugins/dictbot.nb +53 -0
- data/plugins/drbcl.rb +39 -0
- data/plugins/drbot.nb +93 -0
- data/plugins/evalbot.nb +49 -0
- data/plugins/gonzuibot.nb +41 -0
- data/plugins/googlebot.nb +345 -0
- data/plugins/identifynickserv.nb +43 -0
- data/plugins/mailcheckbot.nb +0 -0
- data/plugins/marldiabot.nb +99 -0
- data/plugins/messagebot.nb +96 -0
- data/plugins/modemanager.nb +150 -0
- data/plugins/opensearchbot.nb +156 -0
- data/plugins/opshop.nb +23 -0
- data/plugins/pastebot.nb +46 -0
- data/plugins/roulettebot.nb +33 -0
- data/plugins/rss_checkbot.nb +121 -0
- data/plugins/samplebot.nb +24 -0
- data/plugins/sendpingbot.nb +17 -0
- data/plugins/shellbot.nb +59 -0
- data/plugins/sixamobot.nb +77 -0
- data/plugins/tenkibot.nb +111 -0
- data/plugins/timestampbot.nb +62 -0
- data/plugins/titlebot.nb +226 -0
- data/plugins/translatebot.nb +301 -0
- data/plugins/twitterbot.nb +138 -0
- data/plugins/weba.nb +209 -0
- data/plugins/xibot.nb +113 -0
- data/rice/irc.rb +780 -0
- metadata +102 -0
data/rice/irc.rb
ADDED
@@ -0,0 +1,780 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= rice - Ruby Irc interfaCE
|
4
|
+
|
5
|
+
Original Credit:
|
6
|
+
|
7
|
+
Original Id: irc.rb,v 1.9 2001/06/13 10:22:24 akira Exp
|
8
|
+
|
9
|
+
Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
|
10
|
+
You can redistribute it and/or modify it under the same term as Ruby.
|
11
|
+
|
12
|
+
== Modified
|
13
|
+
|
14
|
+
Modified by K.Sasada.
|
15
|
+
$Id$
|
16
|
+
|
17
|
+
=end
|
18
|
+
|
19
|
+
require 'socket'
|
20
|
+
require 'thread'
|
21
|
+
require 'monitor'
|
22
|
+
begin
|
23
|
+
require "openssl"
|
24
|
+
rescue LoadError
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
module RICE
|
29
|
+
class Error < StandardError; end
|
30
|
+
class InvalidMessage < Error; end
|
31
|
+
class UnknownCommand < Error; end
|
32
|
+
|
33
|
+
=begin
|
34
|
+
|
35
|
+
== RICE::Connection
|
36
|
+
|
37
|
+
=end
|
38
|
+
|
39
|
+
class Connection
|
40
|
+
class Error < StandardError; end
|
41
|
+
class Closed < Error; end
|
42
|
+
|
43
|
+
=begin
|
44
|
+
|
45
|
+
--- RICE::Connection::new
|
46
|
+
|
47
|
+
=end
|
48
|
+
|
49
|
+
def initialize(server, port, eol = "\r\n", ssl_params = nil)
|
50
|
+
@conn = []
|
51
|
+
@conn.extend(MonitorMixin)
|
52
|
+
@main_th = nil
|
53
|
+
|
54
|
+
self.server = server
|
55
|
+
self.port = port
|
56
|
+
self.eol = eol
|
57
|
+
self.ssl_params = ssl_params
|
58
|
+
|
59
|
+
@read_q = Queue.new
|
60
|
+
|
61
|
+
@read_th = Thread.new(@read_q, @eol) do |read_q, eol|
|
62
|
+
read_thread(read_q, eol)
|
63
|
+
end
|
64
|
+
|
65
|
+
@threads = {}
|
66
|
+
@threads.extend(MonitorMixin)
|
67
|
+
|
68
|
+
@dispatcher = Thread.new(@read_q) do |read_q|
|
69
|
+
loop do
|
70
|
+
x = read_q.pop
|
71
|
+
|
72
|
+
ths = @threads.synchronize do
|
73
|
+
@threads.keys
|
74
|
+
end
|
75
|
+
ths.each do |th|
|
76
|
+
if th.status
|
77
|
+
@threads[th].q.push(x)
|
78
|
+
else
|
79
|
+
@threads.delete(th)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end # loop
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
@delay = 0.3
|
87
|
+
@prev_send_time = Time.now
|
88
|
+
end
|
89
|
+
attr :delay, true
|
90
|
+
attr_reader :server, :port, :ssl_params
|
91
|
+
|
92
|
+
=begin
|
93
|
+
|
94
|
+
--- RICE::Connection#server=(server)
|
95
|
+
|
96
|
+
=end
|
97
|
+
|
98
|
+
def server=(server)
|
99
|
+
raise RuntimeError,
|
100
|
+
"Already connected to #{@server}:#{@port}" unless @conn.empty?
|
101
|
+
@server = server
|
102
|
+
end
|
103
|
+
|
104
|
+
=begin
|
105
|
+
|
106
|
+
--- RICE::Connection#port=(port)
|
107
|
+
|
108
|
+
=end
|
109
|
+
|
110
|
+
def port=(port)
|
111
|
+
raise RuntimeError,
|
112
|
+
"Already connected to #{@server}:#{@port}" unless @conn.empty?
|
113
|
+
@port = port
|
114
|
+
end
|
115
|
+
|
116
|
+
=begin
|
117
|
+
|
118
|
+
--- RICE::Connection#eol=(eol)
|
119
|
+
|
120
|
+
=end
|
121
|
+
|
122
|
+
def eol=(eol)
|
123
|
+
raise RuntimeError,
|
124
|
+
"Already connected to #{@server}:#{@port}" unless @conn.empty?
|
125
|
+
@eol = eol
|
126
|
+
end
|
127
|
+
|
128
|
+
=begin
|
129
|
+
|
130
|
+
--- RICE::Connection#ssl_params=(ssl_params)
|
131
|
+
|
132
|
+
=end
|
133
|
+
|
134
|
+
def ssl_params=(ssl_params)
|
135
|
+
raise RuntimeError,
|
136
|
+
"Already connected to #{@server}:#{@port}" unless @conn.empty?
|
137
|
+
unless ssl_params
|
138
|
+
@ssl_params = false
|
139
|
+
return
|
140
|
+
end
|
141
|
+
raise 'openssl library not installed' unless defined?(OpenSSL)
|
142
|
+
ssl_params = ssl_params.to_hash
|
143
|
+
ssl_params[:verify_mode] ||= OpenSSL::SSL::VERIFY_PEER
|
144
|
+
store = OpenSSL::X509::Store.new
|
145
|
+
if ssl_params.key?(:ca_cert)
|
146
|
+
ca_cert = ssl_params.delete(:ca_cert)
|
147
|
+
if ca_cert
|
148
|
+
# auto setting ca_path or ca_file like open-uri.rb
|
149
|
+
if File.directory? ca_cert
|
150
|
+
store.add_path ca_cert
|
151
|
+
else
|
152
|
+
store.add_file ca_cert
|
153
|
+
end
|
154
|
+
else
|
155
|
+
# use ssl_params={:ca_cert=>nil} if you want to disable auto setting
|
156
|
+
store = nil
|
157
|
+
end
|
158
|
+
else
|
159
|
+
# use default of openssl
|
160
|
+
store.set_default_paths
|
161
|
+
end
|
162
|
+
if store
|
163
|
+
ssl_params[:cert_store] = store
|
164
|
+
end
|
165
|
+
@ssl_params = ssl_params
|
166
|
+
end
|
167
|
+
|
168
|
+
=begin
|
169
|
+
|
170
|
+
--- RICE::Connection#start(max_retry = 3, retry_wait = 30)
|
171
|
+
|
172
|
+
=end
|
173
|
+
|
174
|
+
def start(max_retry = 3, retry_wait = 30)
|
175
|
+
@client_th = Thread.current # caller thread
|
176
|
+
if alive?
|
177
|
+
#sleep retry_wait
|
178
|
+
return nil
|
179
|
+
end
|
180
|
+
|
181
|
+
@main_th = Thread.new do
|
182
|
+
begin
|
183
|
+
Thread.stop
|
184
|
+
ensure
|
185
|
+
yield(self) if block_given?
|
186
|
+
|
187
|
+
@read_th.raise(Closed) if @read_th.status
|
188
|
+
close(true)
|
189
|
+
@client_th.raise(Closed)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
begin
|
194
|
+
open_conn
|
195
|
+
rescue SystemCallError
|
196
|
+
max_retry -= 1
|
197
|
+
if max_retry == 0
|
198
|
+
@main_th.kill
|
199
|
+
raise
|
200
|
+
end
|
201
|
+
sleep retry_wait
|
202
|
+
retry
|
203
|
+
ensure
|
204
|
+
@main_th.join
|
205
|
+
nil
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
def open_conn
|
211
|
+
@conn.synchronize do
|
212
|
+
conn = TCPSocket.new(@server, @port)
|
213
|
+
if ssl_params
|
214
|
+
context = OpenSSL::SSL::SSLContext.new
|
215
|
+
context.set_params(ssl_params)
|
216
|
+
conn = OpenSSL::SSL::SSLSocket.new(conn, context)
|
217
|
+
conn.sync_close = true
|
218
|
+
conn.connect
|
219
|
+
if context.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
220
|
+
conn.post_connection_check(@server)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
@conn[0] = conn
|
224
|
+
end
|
225
|
+
@conn[0].extend(MonitorMixin)
|
226
|
+
|
227
|
+
@read_th.run
|
228
|
+
|
229
|
+
ths = @threads.synchronize do
|
230
|
+
@threads.keys
|
231
|
+
end
|
232
|
+
ths.each do |th|
|
233
|
+
th.run if th.status && th.stop?
|
234
|
+
end
|
235
|
+
end
|
236
|
+
private :open_conn
|
237
|
+
|
238
|
+
=begin
|
239
|
+
|
240
|
+
--- RICE::Connection#regist(raise_on_close, *args) {...}
|
241
|
+
|
242
|
+
=end
|
243
|
+
|
244
|
+
USER_THREAD = Struct.new('User_Thread', :q, :raise_on_close)
|
245
|
+
def regist(raise_on_close = false, *args)
|
246
|
+
read_q = Queue.new
|
247
|
+
th = Thread.new(read_q, self, *args) do |read_q, conn, *args|
|
248
|
+
yield(read_q, conn, *args)
|
249
|
+
end
|
250
|
+
@threads.synchronize do
|
251
|
+
@threads[th] = USER_THREAD.new(read_q, raise_on_close)
|
252
|
+
end
|
253
|
+
th
|
254
|
+
end
|
255
|
+
|
256
|
+
=begin
|
257
|
+
|
258
|
+
--- RICE::Connection#unregist(thread)
|
259
|
+
|
260
|
+
=end
|
261
|
+
|
262
|
+
def unregist(thread)
|
263
|
+
th = nil
|
264
|
+
@threads.synchronize do
|
265
|
+
th = @threads.delete(th)
|
266
|
+
end
|
267
|
+
th.exit
|
268
|
+
th
|
269
|
+
end
|
270
|
+
|
271
|
+
def read_thread(read_q, eol)
|
272
|
+
begin
|
273
|
+
read_q.clear
|
274
|
+
Thread.stop
|
275
|
+
|
276
|
+
begin
|
277
|
+
conn = @conn[0]
|
278
|
+
while l = conn.gets(eol)
|
279
|
+
begin
|
280
|
+
read_q.push(Message.parse(l))
|
281
|
+
rescue UnknownCommand
|
282
|
+
$stderr.print l.inspect if $DEBUG
|
283
|
+
rescue InvalidMessage
|
284
|
+
begin
|
285
|
+
read_q.push(Message.parse(l.sub(/\s*#{eol}\z/o, eol)))
|
286
|
+
rescue
|
287
|
+
$stderr.print l.inspect if $DEBUG
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
rescue IOError#, SystemCallError
|
293
|
+
$stderr.print "#{self.inspect}: read_th get error #{$!}" if $DEBUG
|
294
|
+
|
295
|
+
ensure
|
296
|
+
raise Closed
|
297
|
+
end
|
298
|
+
|
299
|
+
rescue Closed
|
300
|
+
begin
|
301
|
+
@main_th.run if @main_th.alive?
|
302
|
+
rescue Closed
|
303
|
+
end
|
304
|
+
retry
|
305
|
+
end
|
306
|
+
end
|
307
|
+
private :read_thread
|
308
|
+
|
309
|
+
=begin
|
310
|
+
|
311
|
+
--- RICE::Connection#close(restart = false)
|
312
|
+
|
313
|
+
=end
|
314
|
+
|
315
|
+
def close(restart = false)
|
316
|
+
begin
|
317
|
+
unless restart
|
318
|
+
@main_th.exit if @main_th.alive?
|
319
|
+
@read_th.exit if @read_th.alive?
|
320
|
+
end
|
321
|
+
|
322
|
+
conn = nil
|
323
|
+
@conn.synchronize do
|
324
|
+
conn = @conn.shift
|
325
|
+
end
|
326
|
+
conn.close if conn
|
327
|
+
|
328
|
+
@threads.synchronize do
|
329
|
+
@threads.each_key do |th|
|
330
|
+
if restart
|
331
|
+
if @threads[th].raise_on_close
|
332
|
+
if @threads[th].raise_on_close.kind_of?(Exception)
|
333
|
+
th.raise(@threads[th].raise_on_close)
|
334
|
+
else
|
335
|
+
th.raise(Closed)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
else
|
340
|
+
th.exit
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
=begin
|
349
|
+
|
350
|
+
--- RICE::Connection#alive?
|
351
|
+
|
352
|
+
=end
|
353
|
+
|
354
|
+
def alive?
|
355
|
+
@main_th && @main_th.alive?
|
356
|
+
end
|
357
|
+
|
358
|
+
=begin
|
359
|
+
|
360
|
+
--- RICE::Connection#push(message)
|
361
|
+
|
362
|
+
=end
|
363
|
+
|
364
|
+
def push(message)
|
365
|
+
conn = @conn[0]
|
366
|
+
if conn
|
367
|
+
conn.synchronize do
|
368
|
+
cmd = message.command
|
369
|
+
if cmd == 'PRIVMSG' || cmd == 'NOTICE'
|
370
|
+
# flood control
|
371
|
+
t = Time.now
|
372
|
+
if t.to_i <= @prev_send_time.to_i + 2
|
373
|
+
sleep 1
|
374
|
+
end
|
375
|
+
@prev_send_time = t
|
376
|
+
end
|
377
|
+
conn.print message.to_s unless conn.closed?
|
378
|
+
end
|
379
|
+
else
|
380
|
+
nil
|
381
|
+
end
|
382
|
+
end
|
383
|
+
alias << push
|
384
|
+
end # Connection
|
385
|
+
|
386
|
+
=begin
|
387
|
+
|
388
|
+
== RICE::Message
|
389
|
+
|
390
|
+
=end
|
391
|
+
|
392
|
+
class Message
|
393
|
+
module PATTERN
|
394
|
+
# letter = %x41-5A / %x61-7A ; A-Z / a-z
|
395
|
+
# digit = %x30-39 ; 0-9
|
396
|
+
# hexdigit = digit / "A" / "B" / "C" / "D" / "E" / "F"
|
397
|
+
# special = %x5B-60 / %x7B-7D
|
398
|
+
# ; "[", "]", "\", "`", "_", "^", "{", "|", "}"
|
399
|
+
LETTER = 'A-Za-z'
|
400
|
+
DIGIT = '\d'
|
401
|
+
HEXDIGIT = "#{DIGIT}A-Fa-f"
|
402
|
+
SPECIAL = '\x5B-\x60\x7B-\x7D'
|
403
|
+
|
404
|
+
# shortname = ( letter / digit ) *( letter / digit / "-" )
|
405
|
+
# *( letter / digit )
|
406
|
+
# ; as specified in RFC 1123 [HNAME]
|
407
|
+
# hostname = shortname *( "." shortname )
|
408
|
+
SHORTNAME = "[#{LETTER}#{DIGIT}](?:[-#{LETTER}#{DIGIT}\/]*[#{LETTER}#{DIGIT}])?"
|
409
|
+
HOSTNAME = "#{SHORTNAME}(?:\\.#{SHORTNAME})*\\.?"
|
410
|
+
|
411
|
+
# servername = hostname
|
412
|
+
SERVERNAME = HOSTNAME
|
413
|
+
|
414
|
+
# nickname = ( letter / special ) *8( letter / digit / special / "-" )
|
415
|
+
# (nickname starts with DIGIT may occur in split mode)
|
416
|
+
NICKNAME = "[#{LETTER}#{DIGIT}#{SPECIAL}][\-#{LETTER}#{DIGIT}#{SPECIAL}]*"
|
417
|
+
|
418
|
+
# user = 1*( %x01-09 / %x0B-0C / %x0E-1F / %x21-3F / %x41-FF )
|
419
|
+
# ; any octet except NUL, CR, LF, " " and "@"
|
420
|
+
USER = '[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x3F\x41-\xFF]+'
|
421
|
+
|
422
|
+
# ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
|
423
|
+
IP4ADDR = "[#{DIGIT}]{1,3}(?:\\.[#{DIGIT}]{1,3}){3}"
|
424
|
+
|
425
|
+
H16 = "[#{HEXDIGIT}]{1,4}" # :nodoc:
|
426
|
+
LS32 = "(?:#{H16}:#{H16})|#{IP4ADDR}" # :nodoc:
|
427
|
+
# ip6addr from RFC3986
|
428
|
+
IP6ADDR = "(?:#{H16}:){6}#{LS32}|" \
|
429
|
+
"::(?:#{H16}:){5}#{LS32}|" \
|
430
|
+
"(?:#{H16})?::(?:#{H16}:){4}#{LS32}|" \
|
431
|
+
"(?:(?:#{H16}:)?#{H16})?::(?:#{H16}:){3}#{LS32}|" \
|
432
|
+
"(?:(?:#{H16}:){0,2}#{H16})?::(?:#{H16}:){2}#{LS32}|" \
|
433
|
+
"(?:(?:#{H16}:){0,3}#{H16})?::#{H16}:#{LS32}|" \
|
434
|
+
"(?:(?:#{H16}:){0,4}#{H16})?::#{LS32}|" \
|
435
|
+
"(?:(?:#{H16}:){0,5}#{H16})?::#{H16}|" \
|
436
|
+
"(?:(?:#{H16}:){0,6}#{H16})?::"
|
437
|
+
|
438
|
+
# hostaddr = ip4addr / ip6addr
|
439
|
+
HOSTADDR = "(?:#{IP4ADDR}|#{IP6ADDR})"
|
440
|
+
|
441
|
+
# host = hostname / hostaddr
|
442
|
+
HOST = "(?:#{HOSTNAME}|#{HOSTADDR})"
|
443
|
+
|
444
|
+
# prefix = servername / ( nickname [ [ "!" user ] "@" host ] )
|
445
|
+
PREFIX = "(?:#{NICKNAME}(?:(?:!#{USER})?@#{HOST})?|#{SERVERNAME})"
|
446
|
+
|
447
|
+
# nospcrlfcl = %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B-FF
|
448
|
+
# ; any octet except NUL, CR, LF, " " and ":"
|
449
|
+
NOSPCRLFCL = '\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B-\xFF'
|
450
|
+
|
451
|
+
# command = 1*letter / 3digit
|
452
|
+
COMMAND = "(?:[#{LETTER}]+|[#{DIGIT}]{3})"
|
453
|
+
|
454
|
+
# SPACE = %x20 ; space character
|
455
|
+
# middle = nospcrlfcl *( ":" / nospcrlfcl )
|
456
|
+
# trailing = *( ":" / " " / nospcrlfcl )
|
457
|
+
# params = *14( SPACE middle ) [ SPACE ":" trailing ]
|
458
|
+
# =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ]
|
459
|
+
MIDDLE = "[#{NOSPCRLFCL}][:#{NOSPCRLFCL}]*"
|
460
|
+
TRAILING = "[: #{NOSPCRLFCL}]*"
|
461
|
+
PARAMS = "(?:((?: +#{MIDDLE}){0,14})(?: +:(#{TRAILING}))?|((?: +#{MIDDLE}){14}):?(#{TRAILING}))"
|
462
|
+
|
463
|
+
# crlf = %x0D %x0A ; "carriage return" "linefeed"
|
464
|
+
# message = [ ":" prefix SPACE ] command [ params ] crlf
|
465
|
+
CRLF = '\x0D\x0A'
|
466
|
+
MESSAGE = "(?::(#{PREFIX}) +)?(#{COMMAND})#{PARAMS}\s*(#{CRLF}|\n|\r)"
|
467
|
+
|
468
|
+
CLIENT_PATTERN = /\A#{NICKNAME}(?:(?:!#{USER})?@#{HOST})\z/on
|
469
|
+
MESSAGE_PATTERN = /\A#{MESSAGE}\z/on
|
470
|
+
end # PATTERN
|
471
|
+
|
472
|
+
=begin
|
473
|
+
|
474
|
+
--- RICE::Message::parse(str)
|
475
|
+
|
476
|
+
=end
|
477
|
+
|
478
|
+
def self.parse(str)
|
479
|
+
unless PATTERN::MESSAGE_PATTERN =~ str
|
480
|
+
raise InvalidMessage, "Invalid message: #{str.inspect}"
|
481
|
+
|
482
|
+
else
|
483
|
+
prefix = $1
|
484
|
+
command = $2
|
485
|
+
if $3 && $3.size > 0
|
486
|
+
middle = $3
|
487
|
+
trailer = $4
|
488
|
+
elsif $5 && $5.size > 0
|
489
|
+
middle = $5
|
490
|
+
trailer = $6
|
491
|
+
elsif $4
|
492
|
+
params = []
|
493
|
+
trailer = $4
|
494
|
+
elsif $6
|
495
|
+
params = []
|
496
|
+
trailer = $6
|
497
|
+
else
|
498
|
+
params = []
|
499
|
+
end
|
500
|
+
end
|
501
|
+
params ||= middle.split(/ /)[1..-1]
|
502
|
+
params << trailer if trailer
|
503
|
+
|
504
|
+
self.build(prefix, command.upcase, params)
|
505
|
+
end
|
506
|
+
|
507
|
+
=begin
|
508
|
+
|
509
|
+
--- RICE::Message::build(prefix, command, params)
|
510
|
+
|
511
|
+
=end
|
512
|
+
|
513
|
+
def self.build(prefix, command, params)
|
514
|
+
if Command::Commands.include?(command)
|
515
|
+
Command::Commands[command].new(prefix, command, params)
|
516
|
+
elsif Reply::Replies.include?(command)
|
517
|
+
Reply::Replies[command].new(prefix, command, params)
|
518
|
+
else
|
519
|
+
raise UnknownCommand, "unknown command: #{command}"
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
=begin
|
524
|
+
|
525
|
+
--- RICE::Message#prefix
|
526
|
+
|
527
|
+
--- RICE::Message#command
|
528
|
+
|
529
|
+
--- RICE::Message#params
|
530
|
+
|
531
|
+
=end
|
532
|
+
|
533
|
+
def initialize(prefix, command, params)
|
534
|
+
@prefix = prefix
|
535
|
+
@command = command
|
536
|
+
@params = params
|
537
|
+
end
|
538
|
+
attr_accessor :prefix
|
539
|
+
attr_reader :command, :params
|
540
|
+
|
541
|
+
=begin
|
542
|
+
|
543
|
+
--- RICE::Message::#to_s
|
544
|
+
|
545
|
+
=end
|
546
|
+
|
547
|
+
def to_s
|
548
|
+
str = ''
|
549
|
+
if @prefix
|
550
|
+
str << ':'
|
551
|
+
str << @prefix
|
552
|
+
str << ' '
|
553
|
+
end
|
554
|
+
|
555
|
+
str << @command
|
556
|
+
|
557
|
+
if @params
|
558
|
+
f = false
|
559
|
+
@params.each do |param|
|
560
|
+
str << ' '
|
561
|
+
if (param == @params[-1]) && (param.size == 0 || /(^:)|(\s)/ =~ param)
|
562
|
+
str << ':'
|
563
|
+
str << param.to_s
|
564
|
+
f = true
|
565
|
+
else
|
566
|
+
str << param.to_s
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
str << "\x0D\x0A"
|
572
|
+
|
573
|
+
str
|
574
|
+
end
|
575
|
+
|
576
|
+
=begin
|
577
|
+
|
578
|
+
--- RICE::Message::#to_a
|
579
|
+
|
580
|
+
=end
|
581
|
+
|
582
|
+
def to_a
|
583
|
+
[@prefix, @command, @params]
|
584
|
+
end
|
585
|
+
|
586
|
+
def inspect
|
587
|
+
sprintf('#<%s:0x%x prefix:%s command:%s params:%s>',
|
588
|
+
self.class, self.object_id, @prefix, @command, @params.inspect)
|
589
|
+
end
|
590
|
+
|
591
|
+
end # Message
|
592
|
+
|
593
|
+
=begin
|
594
|
+
|
595
|
+
== RICE::Command
|
596
|
+
|
597
|
+
=end
|
598
|
+
|
599
|
+
module Command
|
600
|
+
class Command < Message
|
601
|
+
end # Command
|
602
|
+
|
603
|
+
def self.regist_command cmd
|
604
|
+
eval <<E
|
605
|
+
class #{cmd} < Command
|
606
|
+
end
|
607
|
+
Commands['#{cmd}'] = #{cmd}
|
608
|
+
|
609
|
+
def #{cmd.downcase}(*params)
|
610
|
+
#{cmd}.new(nil, '#{cmd}', params)
|
611
|
+
end
|
612
|
+
module_function :#{cmd.downcase}
|
613
|
+
E
|
614
|
+
end
|
615
|
+
Commands = {}
|
616
|
+
%w(PASS NICK USER OPER MODE SERVICE QUIT SQUIT
|
617
|
+
JOIN PART TOPIC NAMES LIST INVITE KICK
|
618
|
+
PRIVMSG NOTICE MOTD LUSERS VERSION STATS LINKS
|
619
|
+
TIME CONNECT TRACE ADMIN INFO SERVLIST SQUERY
|
620
|
+
WHO WHOIS WHOWAS KILL PING PONG ERROR
|
621
|
+
AWAY REHASH DIE RESTART SUMMON USERS WALLOPS USERHOST ISON
|
622
|
+
).each do |cmd|
|
623
|
+
self.regist_command cmd
|
624
|
+
end
|
625
|
+
|
626
|
+
class NICK
|
627
|
+
def to_s
|
628
|
+
str = ''
|
629
|
+
if @prefix
|
630
|
+
str << ':'
|
631
|
+
str << @prefix
|
632
|
+
str << ' '
|
633
|
+
end
|
634
|
+
|
635
|
+
str << @command
|
636
|
+
|
637
|
+
str << ' '
|
638
|
+
str << ":#{@params[0]}"
|
639
|
+
|
640
|
+
str << "\x0D\x0A"
|
641
|
+
str
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
# XXX:
|
646
|
+
class PRIVMSG
|
647
|
+
def to_s
|
648
|
+
str = ''
|
649
|
+
if @prefix
|
650
|
+
str << ':'
|
651
|
+
str << @prefix
|
652
|
+
str << ' '
|
653
|
+
end
|
654
|
+
|
655
|
+
str << @command
|
656
|
+
|
657
|
+
str << ' '
|
658
|
+
str << @params[0]
|
659
|
+
|
660
|
+
str << ' :'
|
661
|
+
str << @params[1..-1].join(' ')
|
662
|
+
|
663
|
+
str << "\x0D\x0A"
|
664
|
+
str
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
end # Command
|
669
|
+
|
670
|
+
=begin
|
671
|
+
|
672
|
+
== RICE::Reply
|
673
|
+
|
674
|
+
== RICE::CommandResponse
|
675
|
+
|
676
|
+
== RICE::ErrorReply
|
677
|
+
|
678
|
+
=end
|
679
|
+
|
680
|
+
module Reply
|
681
|
+
class Reply < Message
|
682
|
+
end
|
683
|
+
|
684
|
+
class CommandResponse < Reply
|
685
|
+
end
|
686
|
+
|
687
|
+
class ErrorReply < Reply
|
688
|
+
end
|
689
|
+
|
690
|
+
Replies = {}
|
691
|
+
Replies_num_to_name = {}
|
692
|
+
|
693
|
+
%w(001,RPL_WELCOME
|
694
|
+
002,RPL_YOURHOST
|
695
|
+
003,RPL_CREATED
|
696
|
+
004,RPL_MYINFO
|
697
|
+
005,RPL_BOUNCE
|
698
|
+
302,RPL_USERHOST 303,RPL_ISON 301,RPL_AWAY
|
699
|
+
305,RPL_UNAWAY 306,RPL_NOWAWAY 311,RPL_WHOISUSER
|
700
|
+
312,RPL_WHOISSERVER 313,RPL_WHOISOPERATOR
|
701
|
+
317,RPL_WHOISIDLE 318,RPL_ENDOFWHOIS
|
702
|
+
319,RPL_WHOISCHANNELS 314,RPL_WHOWASUSER
|
703
|
+
369,RPL_ENDOFWHOWAS 321,RPL_LISTSTART
|
704
|
+
322,RPL_LIST 323,RPL_LISTEND 325,RPL_UNIQOPIS
|
705
|
+
324,RPL_CHANNELMODEIS 331,RPL_NOTOPIC
|
706
|
+
332,RPL_TOPIC 341,RPL_INVITING 342,RPL_SUMMONING
|
707
|
+
344,RPL_REOPLIST 345,RPL_ENDOFREOPLIST
|
708
|
+
346,RPL_INVITELIST 347,RPL_ENDOFINVITELIST
|
709
|
+
348,RPL_EXCEPTLIST 349,RPL_ENDOFEXCEPTLIST
|
710
|
+
351,RPL_VERSION 352,RPL_WHOREPLY 315,RPL_ENDOFWHO
|
711
|
+
353,RPL_NAMREPLY 366,RPL_ENDOFNAMES 364,RPL_LINKS
|
712
|
+
365,RPL_ENDOFLINKS 367,RPL_BANLIST 368,RPL_ENDOFBANLIST
|
713
|
+
371,RPL_INFO 374,RPL_ENDOFINFO 375,RPL_MOTDSTART
|
714
|
+
372,RPL_MOTD 376,RPL_ENDOFMOTD 381,RPL_YOUREOPER
|
715
|
+
382,RPL_REHASHING 383,RPL_YOURESERVICE 391,RPL_TIM
|
716
|
+
392,RPL_ 393,RPL_USERS 394,RPL_ENDOFUSERS 395,RPL_NOUSERS
|
717
|
+
200,RPL_TRACELINK 201,RPL_TRACECONNECTING
|
718
|
+
202,RPL_TRACEHANDSHAKE 203,RPL_TRACEUNKNOWN
|
719
|
+
204,RPL_TRACEOPERATOR 205,RPL_TRACEUSER 206,RPL_TRACESERVER
|
720
|
+
207,RPL_TRACESERVICE 208,RPL_TRACENEWTYPE 209,RPL_TRACECLASS
|
721
|
+
210,RPL_TRACERECONNECT 261,RPL_TRACELOG 262,RPL_TRACEEND
|
722
|
+
211,RPL_STATSLINKINFO 212,RPL_STATSCOMMANDS 219,RPL_ENDOFSTATS
|
723
|
+
242,RPL_STATSUPTIME 243,RPL_STATSOLINE 221,RPL_UMODEIS
|
724
|
+
234,RPL_SERVLIST 235,RPL_SERVLISTEND 251,RPL_LUSERCLIENT
|
725
|
+
252,RPL_LUSEROP 253,RPL_LUSERUNKNOWN 254,RPL_LUSERCHANNELS
|
726
|
+
255,RPL_LUSERME 256,RPL_ADMINME 257,RPL_ADMINLOC1
|
727
|
+
258,RPL_ADMINLOC2 259,RPL_ADMINEMAIL 263,RPL_TRYAGAIN
|
728
|
+
401,ERR_NOSUCHNICK 402,ERR_NOSUCHSERVER 403,ERR_NOSUCHCHANNEL
|
729
|
+
404,ERR_CANNOTSENDTOCHAN 405,ERR_TOOMANYCHANNELS
|
730
|
+
406,ERR_WASNOSUCHNICK 407,ERR_TOOMANYTARGETS
|
731
|
+
408,ERR_NOSUCHSERVICE 409,ERR_NOORIGIN 411,ERR_NORECIPIENT
|
732
|
+
412,ERR_NOTEXTTOSEND 413,ERR_NOTOPLEVEL 414,ERR_WILDTOPLEVEL
|
733
|
+
415,ERR_BADMASK 421,ERR_UNKNOWNCOMMAND 422,ERR_NOMOTD
|
734
|
+
423,ERR_NOADMININFO 424,ERR_FILEERROR 431,ERR_NONICKNAMEGIVEN
|
735
|
+
432,ERR_ERRONEUSNICKNAME 433,ERR_NICKNAMEINUSE
|
736
|
+
436,ERR_NICKCOLLISION 437,ERR_UNAVAILRESOURCE
|
737
|
+
441,ERR_USERNOTINCHANNEL 442,ERR_NOTONCHANNEL
|
738
|
+
443,ERR_USERONCHANNEL 444,ERR_NOLOGIN 445,ERR_SUMMONDISABLED
|
739
|
+
446,ERR_USERSDISABLED 451,ERR_NOTREGISTERED
|
740
|
+
461,ERR_NEEDMOREPARAMS 462,ERR_ALREADYREGISTRED
|
741
|
+
463,ERR_NOPERMFORHOST 464,ERR_PASSWDMISMATCH
|
742
|
+
465,ERR_YOUREBANNEDCREEP 466,ERR_YOUWILLBEBANNED
|
743
|
+
467,ERR_KEYSE 471,ERR_CHANNELISFULL 472,ERR_UNKNOWNMODE
|
744
|
+
473,ERR_INVITEONLYCHAN 474,ERR_BANNEDFROMCHAN
|
745
|
+
475,ERR_BADCHANNELKEY 476,ERR_BADCHANMASK 477,ERR_NOCHANMODES
|
746
|
+
478,ERR_BANLISTFULL 481,ERR_NOPRIVILEGES 482,ERR_CHANOPRIVSNEEDED
|
747
|
+
483,ERR_CANTKILLSERVER 484,ERR_RESTRICTED
|
748
|
+
485,ERR_UNIQOPPRIVSNEEDED 491,ERR_NOOPERHOST
|
749
|
+
501,ERR_UMODEUNKNOWNFLAG 502,ERR_USERSDONTMATCH
|
750
|
+
231,RPL_SERVICEINFO 232,RPL_ENDOFSERVICES
|
751
|
+
233,RPL_SERVICE 300,RPL_NONE 316,RPL_WHOISCHANOP
|
752
|
+
361,RPL_KILLDONE 362,RPL_CLOSING 363,RPL_CLOSEEND
|
753
|
+
373,RPL_INFOSTART 384,RPL_MYPORTIS 213,RPL_STATSCLINE
|
754
|
+
214,RPL_STATSNLINE 215,RPL_STATSILINE 216,RPL_STATSKLINE
|
755
|
+
217,RPL_STATSQLINE 218,RPL_STATSYLINE 240,RPL_STATSVLINE
|
756
|
+
241,RPL_STATSLLINE 244,RPL_STATSHLINE 244,RPL_STATSSLINE
|
757
|
+
246,RPL_STATSPING 247,RPL_STATSBLINE 250,RPL_STATSDLINE
|
758
|
+
492,ERR_NOSERVICEHOST
|
759
|
+
).each do |num_cmd|
|
760
|
+
num, cmd = num_cmd.split(',', 2)
|
761
|
+
eval <<E
|
762
|
+
class #{cmd} < #{if num[0] == ?0 || num[0] == ?2 || num[0] == ?3
|
763
|
+
'CommandResponse'
|
764
|
+
elsif num[0] == ?4 || num[0] == ?5
|
765
|
+
'ErrorReply'
|
766
|
+
end}
|
767
|
+
end
|
768
|
+
Replies['#{num}'] = #{cmd}
|
769
|
+
Replies_num_to_name['#{num}'] = '#{cmd.downcase}'
|
770
|
+
|
771
|
+
def #{cmd.downcase}(*params)
|
772
|
+
#{cmd}.new(nil, '#{num}', params)
|
773
|
+
end
|
774
|
+
module_function :#{cmd.downcase}
|
775
|
+
E
|
776
|
+
end
|
777
|
+
|
778
|
+
end # Reply
|
779
|
+
end # RICE
|
780
|
+
|