konn-rupircd 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +21 -0
- data/Rakefile +16 -0
- data/VERSION +1 -0
- data/changes.html +41 -0
- data/changes.ja.html +41 -0
- data/index.html +75 -0
- data/index.ja.html +72 -0
- data/info.txt +54 -0
- data/ircd.rb +26 -0
- data/lib/rupircd/channel.rb +418 -0
- data/lib/rupircd/conf.rb +26 -0
- data/lib/rupircd/message.rb +254 -0
- data/lib/rupircd/server.rb +677 -0
- data/lib/rupircd/user.rb +103 -0
- data/lib/rupircd/utils.rb +32 -0
- data/lib/rupircd.rb +12 -0
- data/mkpassword.rb +3 -0
- data/motd.txt +16 -0
- data/rupircd.gemspec +72 -0
- data/sample.conf +10 -0
- data/usage.html +112 -0
- data/usage.ja.html +112 -0
- metadata +25 -1
@@ -0,0 +1,418 @@
|
|
1
|
+
=begin
|
2
|
+
= rupircd -- Ruby Pseudo IRC Deamon
|
3
|
+
|
4
|
+
ver 0.6 2009-08-11T23:45:52+09:00
|
5
|
+
|
6
|
+
Copyright (c) 2009 Hiromi Ishii
|
7
|
+
|
8
|
+
You can redistribute it and/or modify it under the same term as Ruby.
|
9
|
+
=end
|
10
|
+
|
11
|
+
require 'rupircd/utils'
|
12
|
+
require 'rupircd/message'
|
13
|
+
|
14
|
+
module IRCd
|
15
|
+
|
16
|
+
class ChannelMode
|
17
|
+
include Utils
|
18
|
+
attr_accessor :bans, :topic_op_only, :ops, :invite, :voices, :anony, :moderate, :n,
|
19
|
+
:quiet, :private, :secret, :reops, :key, :user_max, :excepts,
|
20
|
+
:dont_need_invite, :creators
|
21
|
+
|
22
|
+
def initialize(server, chname)
|
23
|
+
@chname = chname
|
24
|
+
@server = server
|
25
|
+
@bans = []
|
26
|
+
@topic_op_only = false
|
27
|
+
@creators = []
|
28
|
+
@ops = []
|
29
|
+
@invite = false
|
30
|
+
@voices = []
|
31
|
+
@anony = false
|
32
|
+
@moderate = false
|
33
|
+
@n = false
|
34
|
+
@quiet = false
|
35
|
+
@private = false
|
36
|
+
@secret = false
|
37
|
+
@reops = []
|
38
|
+
@key = ""
|
39
|
+
@user_max = -1
|
40
|
+
@excepts = []
|
41
|
+
@invite_onlys = []
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_flags(who, flags, param)
|
45
|
+
args = param.dup
|
46
|
+
toggle = flags[0] == ?+
|
47
|
+
rpl = [flags[0,1]]
|
48
|
+
flags = flags[1..3]
|
49
|
+
flags.each_byte{|b|
|
50
|
+
rpl.push b.chr
|
51
|
+
case b
|
52
|
+
when ?n
|
53
|
+
@n = toggle
|
54
|
+
when ?i
|
55
|
+
@invite = toggle
|
56
|
+
when ?a
|
57
|
+
@anony = toggle
|
58
|
+
when ?m
|
59
|
+
@moderate = toggle
|
60
|
+
when ?p
|
61
|
+
@secret = false if toggle
|
62
|
+
@private = toggle
|
63
|
+
when ?s
|
64
|
+
@private = false if toggle
|
65
|
+
@secret = toggle
|
66
|
+
when ?k
|
67
|
+
key = param.shift
|
68
|
+
if toggle
|
69
|
+
@key = key
|
70
|
+
elsif key == @key
|
71
|
+
@key = ""
|
72
|
+
end
|
73
|
+
when ?l
|
74
|
+
@user_max = param.shift.to_i
|
75
|
+
when ?r
|
76
|
+
if toggle
|
77
|
+
@reops << mask_to_regex(param.shift)
|
78
|
+
else
|
79
|
+
@reops.delete(mask_to_regex(param.shift))
|
80
|
+
end
|
81
|
+
when ?t
|
82
|
+
@topic_op_only = toggle
|
83
|
+
when ?o
|
84
|
+
user = @server.user_from_nick(param.shift)
|
85
|
+
if toggle
|
86
|
+
@ops << user
|
87
|
+
@ops.compact!
|
88
|
+
@ops.uniq!
|
89
|
+
else
|
90
|
+
@ops.delete(user)
|
91
|
+
end
|
92
|
+
when ?v
|
93
|
+
user = @server.user_from_nick(param.shift)
|
94
|
+
if toggle
|
95
|
+
@voices << user
|
96
|
+
@voices.uniq!
|
97
|
+
@voices.compact!
|
98
|
+
else
|
99
|
+
@voices.delete(user)
|
100
|
+
end
|
101
|
+
when ?b, ?e, ?I
|
102
|
+
masks = param.shift
|
103
|
+
mask_list = []
|
104
|
+
list_msg = ""
|
105
|
+
endof_msg = ""
|
106
|
+
what = ""
|
107
|
+
case b
|
108
|
+
when ?b
|
109
|
+
mask_list = @bans
|
110
|
+
list_msg = "367"
|
111
|
+
endof_msg = "368"
|
112
|
+
what = "ban"
|
113
|
+
when ?e
|
114
|
+
mask_list = @excepts
|
115
|
+
list_msg = "348"
|
116
|
+
endof_msg = "349"
|
117
|
+
what = "exception"
|
118
|
+
when ?I
|
119
|
+
mask_list = @invite_onlys
|
120
|
+
list_msg = "346"
|
121
|
+
endof_msg = "347"
|
122
|
+
what = "invite"
|
123
|
+
end
|
124
|
+
if masks
|
125
|
+
if toggle
|
126
|
+
mask_list << mask_to_regex(masks)
|
127
|
+
else
|
128
|
+
mask_list.delete(mask_to_regex(masks))
|
129
|
+
end
|
130
|
+
else
|
131
|
+
rpl.pop
|
132
|
+
mask_list.each{|msk|
|
133
|
+
@server.send_server_message(who, list_msg, @chname, msk)
|
134
|
+
}
|
135
|
+
@server.send_server_message(who, endof_msg, @chname, "End of channel #{what} list")
|
136
|
+
end
|
137
|
+
else
|
138
|
+
@server.send_server_message(who, "472", rpl.pop, "is unknown mode char to me for #@chname")
|
139
|
+
end
|
140
|
+
}
|
141
|
+
[rpl.join(""), args].flatten if rpl.size > 1
|
142
|
+
end
|
143
|
+
|
144
|
+
def proc_mask(toggle, rpl, param, mask_list, reply_msg, endof_list, name)
|
145
|
+
masks = param.shift
|
146
|
+
if masks
|
147
|
+
if toggle
|
148
|
+
mask_list << mask_to_regex(masks)
|
149
|
+
else
|
150
|
+
mask_list.delete(mask_to_regex(masks))
|
151
|
+
end
|
152
|
+
else
|
153
|
+
rpl.pop
|
154
|
+
mask_list.each{|msk|
|
155
|
+
@server.send_server_message(who, reply_msg, @chname, msk)
|
156
|
+
}
|
157
|
+
@server.send_server_message(who, endof_list, @chname, "End of channel #{name} list")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
private :proc_mask
|
161
|
+
|
162
|
+
def get_flags
|
163
|
+
params = []
|
164
|
+
flg = "+"
|
165
|
+
flg << "n" if @n
|
166
|
+
flg << "i" if @invite
|
167
|
+
flg << "a" if @anony
|
168
|
+
flg << "m" if @moderate
|
169
|
+
flg << "q" if @quiet
|
170
|
+
flg << "p" if @private
|
171
|
+
flg << "s" if @secret
|
172
|
+
flg << "k" unless @key.empty?
|
173
|
+
flg << "t" if @topic_op_only
|
174
|
+
if @user_max > -1
|
175
|
+
flg << "l"
|
176
|
+
params << @user_max
|
177
|
+
end
|
178
|
+
params.unshift flg
|
179
|
+
end
|
180
|
+
|
181
|
+
def add_op(hoge)
|
182
|
+
@ops.push hoge
|
183
|
+
end
|
184
|
+
|
185
|
+
def unregister(who)
|
186
|
+
@ops.delete(who)
|
187
|
+
@voices.delete(who)
|
188
|
+
end
|
189
|
+
|
190
|
+
def op?(who)
|
191
|
+
@ops.include?(who)
|
192
|
+
end
|
193
|
+
|
194
|
+
def voiced?(who)
|
195
|
+
@voices.include?(who)
|
196
|
+
end
|
197
|
+
|
198
|
+
def can_change_topic?(who)
|
199
|
+
!@topic_op_only || op?(who)
|
200
|
+
end
|
201
|
+
|
202
|
+
def can_talk?(who)
|
203
|
+
!@moderate || op?(who) || @voices.include?(who)
|
204
|
+
end
|
205
|
+
|
206
|
+
def can_invite?(who)
|
207
|
+
!@invite || op?(who)
|
208
|
+
end
|
209
|
+
|
210
|
+
def banned?(who)
|
211
|
+
@bans.any?{|mask|
|
212
|
+
who.to_s =~ mask
|
213
|
+
}
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
class Channel
|
219
|
+
attr_reader :name, :members, :mode
|
220
|
+
|
221
|
+
def initialize(server, who, chname)
|
222
|
+
@server = server
|
223
|
+
@mode = ChannelMode.new(server, chname)
|
224
|
+
@name = chname
|
225
|
+
@topic = ""
|
226
|
+
@members = []
|
227
|
+
@invited = []
|
228
|
+
end
|
229
|
+
|
230
|
+
def join(who, key="")
|
231
|
+
if @mode.banned?(who)
|
232
|
+
["474", @name, "Cannot join channel (+b)"]
|
233
|
+
elsif @mode.invite && !@invited.include?(who)
|
234
|
+
["473", @name, "Cannot join channel (+i)"]
|
235
|
+
elsif !@mode.key.empty? && @mode.key != key
|
236
|
+
["475", @name, "Cannot join channel (+k)"]
|
237
|
+
elsif @mode.user_max >= @members.size
|
238
|
+
["471", @name, "Cannot join channel (+l)"]
|
239
|
+
elsif !joined?(who)
|
240
|
+
who.joined_channels.push self
|
241
|
+
@members.unshift who
|
242
|
+
|
243
|
+
@mode.add_op who if @members.size == 1
|
244
|
+
sends = []
|
245
|
+
sends << get_topic(who)
|
246
|
+
sends += names(who)
|
247
|
+
@server.send_client_message(who, who, Command::JOIN, @name)
|
248
|
+
@server.handle_reply(who, sends)
|
249
|
+
send_to_other_members(who, Command::JOIN, @name)
|
250
|
+
return nil
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def kick(who, by, msg="no reason")
|
255
|
+
if !@members.include?(by)
|
256
|
+
["442", @name, "You're not on that channel"]
|
257
|
+
elsif !@members.include?(who)
|
258
|
+
["441", who.nick, @name, "They aren't on that channel"]
|
259
|
+
elsif @mode.op?(by)
|
260
|
+
send_to_members(by, Command::KICK, @name, who.nick, msg)
|
261
|
+
unregister(who)
|
262
|
+
nil
|
263
|
+
else
|
264
|
+
["482", @name, "You're not channel operator"]
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def send_to_members(user, command, *args)
|
269
|
+
@members.each{|mem|
|
270
|
+
@server.send_client_message(mem, user, command, *args)
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
def send_to_other_members(user, command, *args)
|
275
|
+
(@members-[user]).each{|mem|
|
276
|
+
@server.send_client_message(mem, user, command, *args)
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
def joined?(who)
|
281
|
+
@members.include?(who)
|
282
|
+
end
|
283
|
+
|
284
|
+
def invite(from, who)
|
285
|
+
if !joined?(from)
|
286
|
+
return ["442", @name, "You're not on that channel"]
|
287
|
+
elsif joined?(who)
|
288
|
+
return ["443", who.nick, "is already on channel"]
|
289
|
+
elsif !@mode.can_invite?(from)
|
290
|
+
return ["482", @name, "You're not channel operator"]
|
291
|
+
else
|
292
|
+
@invited.push who
|
293
|
+
@server.send_client_message(who, from, Command::INVITE, who.nick, @name)
|
294
|
+
return ["341", who.nick, @name]
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def unregister(usr)
|
299
|
+
@members.delete(usr)
|
300
|
+
@mode.unregister(usr)
|
301
|
+
usr.joined_channels.delete(self)
|
302
|
+
end
|
303
|
+
|
304
|
+
def handle_mode(who, params)
|
305
|
+
if params.empty?
|
306
|
+
["324", @name, *@mode.get_flags]
|
307
|
+
else
|
308
|
+
flags, *targets = params
|
309
|
+
flags = "+" + flags if flags[0,1] != "+" && flags[0,1] != "-"
|
310
|
+
if @mode.op?(who)
|
311
|
+
rpl = @mode.set_flags(who, flags, targets)
|
312
|
+
send_to_members(who, Command::MODE, @name, *rpl) if rpl
|
313
|
+
nil
|
314
|
+
elsif !joined?(who)
|
315
|
+
return ["482", @name, "You're not channel operator"]
|
316
|
+
else
|
317
|
+
return ["442", @name, "You're not on that channel"]
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def part(who, message="")
|
323
|
+
if joined?(who)
|
324
|
+
send_to_members(who, Command::PART, @name, message)
|
325
|
+
unregister(who)
|
326
|
+
return nil
|
327
|
+
else
|
328
|
+
return ["442", @name, "You're not on that channel"]
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def set_topic(who, str)
|
333
|
+
if @mode.can_change_topic?(who)
|
334
|
+
@topic = str
|
335
|
+
send_to_members(who, Command::TOPIC, @name, @topic)
|
336
|
+
return nil
|
337
|
+
elsif !@members.include?(who)
|
338
|
+
return ["442", @name, "You're not on that channel"]
|
339
|
+
else
|
340
|
+
return ["482", @name, "You're not channel operator"]
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def get_topic(user, text=false)
|
345
|
+
return nil if @mode.secret && !joined?(user)
|
346
|
+
return @topic if text
|
347
|
+
if @topic.empty?
|
348
|
+
["331", @name, "No topic is set"]
|
349
|
+
else
|
350
|
+
["332", @name, @topic]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def privmsg(who, msg)
|
355
|
+
if @mode.n && !@members.include?(who)
|
356
|
+
return ["404", @name, "Cannot send to channel"]
|
357
|
+
elsif @mode.can_talk?(who)
|
358
|
+
send_to_other_members(who, Command::PRIVMSG, @name, msg)
|
359
|
+
nil
|
360
|
+
else
|
361
|
+
return ["404", @name, "Cannot send to channel"]
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def notice(who, msg)
|
366
|
+
if @mode.can_talk?(who)
|
367
|
+
send_to_other_members(who, Command::NOTICE, @name, msg)
|
368
|
+
end
|
369
|
+
return nil
|
370
|
+
end
|
371
|
+
|
372
|
+
def visible?(user)
|
373
|
+
!@mode.secret || joined?(user)
|
374
|
+
end
|
375
|
+
|
376
|
+
def names(user)
|
377
|
+
return nil if @mode.secret && !joined?(user)
|
378
|
+
mems = @members.dup
|
379
|
+
unless @members.include?(user)
|
380
|
+
mems = mems.find_all{|usr|
|
381
|
+
!usr.invisible
|
382
|
+
}
|
383
|
+
end
|
384
|
+
memlist = mems.map{|us|
|
385
|
+
if @mode.op?(us)
|
386
|
+
pr = "@"
|
387
|
+
else
|
388
|
+
pr = ""
|
389
|
+
end
|
390
|
+
pr+us.nick
|
391
|
+
}.join(" ")
|
392
|
+
sends = []
|
393
|
+
unless memlist.empty?
|
394
|
+
prefix = if @mode.secret
|
395
|
+
"@"
|
396
|
+
elsif @mode.private
|
397
|
+
"*"
|
398
|
+
else
|
399
|
+
"="
|
400
|
+
end
|
401
|
+
sends << ["353", prefix, @name, memlist]
|
402
|
+
end
|
403
|
+
sends << ["366", @name, "End of NAMES list"]
|
404
|
+
sends
|
405
|
+
end
|
406
|
+
|
407
|
+
end
|
408
|
+
|
409
|
+
class NoModeChannel < Channel
|
410
|
+
def handle_mode(user, *ar)
|
411
|
+
["477", @name, "Channel doesn't support modes"]
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
class SafeChannel < Channel
|
416
|
+
end # 仕様 がよく分から ない ので実装出来なくても しよう がない
|
417
|
+
|
418
|
+
end
|
data/lib/rupircd/conf.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
=begin
|
2
|
+
= rupircd -- Ruby Pseudo IRC Deamon
|
3
|
+
|
4
|
+
ver 0.6 2009-08-11T23:45:52+09:00
|
5
|
+
|
6
|
+
Copyright (c) 2009 Hiromi Ishii
|
7
|
+
|
8
|
+
You can redistribute it and/or modify it under the same term as Ruby.
|
9
|
+
=end
|
10
|
+
|
11
|
+
module IRCd
|
12
|
+
class FileConf
|
13
|
+
attr_reader :conf
|
14
|
+
attr_accessor :path
|
15
|
+
|
16
|
+
def initialize(path)
|
17
|
+
@path = path
|
18
|
+
@conf = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def load
|
22
|
+
@conf = eval(open(@path){|f| f.read })
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= rice - Ruby Irc interfaCE
|
4
|
+
|
5
|
+
$Id: irc.rb,v 1.9 2001/06/13 10:22:24 akira Exp $
|
6
|
+
|
7
|
+
Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
|
8
|
+
You can redistribute it and/or modify it under the same term as Ruby.
|
9
|
+
|
10
|
+
=end
|
11
|
+
|
12
|
+
module IRCd
|
13
|
+
class Error < StandardError; end
|
14
|
+
class UnknownCommand < Error
|
15
|
+
attr_reader :cmd
|
16
|
+
def initialize(cmd)
|
17
|
+
@cmd = cmd
|
18
|
+
super("Unknown command: #@cmd")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
class NotEnoughParameter < Error; end
|
22
|
+
|
23
|
+
class Message
|
24
|
+
|
25
|
+
def self.parse(msg)
|
26
|
+
prefix = nil
|
27
|
+
command = ""
|
28
|
+
tmp = []
|
29
|
+
if msg[0] == ?:
|
30
|
+
prefix, command, *tmp = msg[1..-1].split(" ")
|
31
|
+
else
|
32
|
+
command, *tmp = msg.split(" ")
|
33
|
+
end
|
34
|
+
command
|
35
|
+
params = []
|
36
|
+
eoc = false
|
37
|
+
tmp.each_with_index{|ar,ind|
|
38
|
+
if eoc
|
39
|
+
params[-1] += ' ' + ar
|
40
|
+
elsif ar[0] == ?:
|
41
|
+
eoc = true
|
42
|
+
params << ar[1..-1]
|
43
|
+
else
|
44
|
+
params << ar
|
45
|
+
end
|
46
|
+
}
|
47
|
+
self.build(prefix, command, params)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.build(prefix, command, params)
|
51
|
+
cmd = command
|
52
|
+
cmd.upcase! if String === cmd
|
53
|
+
if Command::Commands.include?(cmd)
|
54
|
+
Command::Commands[cmd.upcase].new(prefix, cmd, params)
|
55
|
+
elsif Reply::Replies.include?(cmd)
|
56
|
+
Reply::Replies[cmd].new(prefix, cmd, params)
|
57
|
+
else
|
58
|
+
raise UnknownCommand, command
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(prefix, command, params)
|
63
|
+
@prefix = prefix
|
64
|
+
@command = command
|
65
|
+
@params = params
|
66
|
+
end
|
67
|
+
attr_reader :prefix, :command, :params
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
str = ''
|
71
|
+
if @prefix && !@prefix.to_s.empty?
|
72
|
+
str << ':'
|
73
|
+
str << @prefix
|
74
|
+
str << ' '
|
75
|
+
end
|
76
|
+
|
77
|
+
str << @command
|
78
|
+
|
79
|
+
if @params
|
80
|
+
f = false
|
81
|
+
@params.each_with_index do |param, ind|
|
82
|
+
param = param.to_s
|
83
|
+
str << ' '
|
84
|
+
if !f && (param.empty? || /[: ]/ =~ param)
|
85
|
+
str << ':'
|
86
|
+
str << param
|
87
|
+
f = true
|
88
|
+
elsif !f && ind == params.size - 1
|
89
|
+
str << ':'
|
90
|
+
str << param
|
91
|
+
else
|
92
|
+
str << param
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
str << "\x0D\x0A"
|
98
|
+
|
99
|
+
str
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def to_a
|
104
|
+
[@prefix, @command, @params]
|
105
|
+
end
|
106
|
+
|
107
|
+
def inspect
|
108
|
+
sprintf('#<%s:0x%x prefix:%s command:%s params:%s>',
|
109
|
+
self.class, self.object_id, @prefix, @command, @params.inspect)
|
110
|
+
end
|
111
|
+
|
112
|
+
end # Message
|
113
|
+
|
114
|
+
|
115
|
+
module Command
|
116
|
+
class Command < Message
|
117
|
+
end # Command
|
118
|
+
|
119
|
+
Commands = {}
|
120
|
+
%w(PASS NICK USER OPER MODE SERVICE QUIT SQUIT CLOSE
|
121
|
+
JOIN PART TOPIC NAMES LIST INVITE KICK
|
122
|
+
PRIVMSG NOTICE MOTD LUSERS VERSION STATS LINKS
|
123
|
+
TIME CONNECT TRACE ADMIN INFO SERVLIST SQUERY
|
124
|
+
WHO WHOIS WHOWAS KILL PING PONG ERROR
|
125
|
+
AWAY REHASH DIE RESTART SUMMON USERS WALLOPS USERHOST ISON
|
126
|
+
).each do |cmd|
|
127
|
+
eval <<E
|
128
|
+
class #{cmd} < Command
|
129
|
+
end
|
130
|
+
Commands['#{cmd}'] = #{cmd}
|
131
|
+
|
132
|
+
def #{cmd.downcase}(*params)
|
133
|
+
#{cmd}.new(nil, '#{cmd}', params)
|
134
|
+
end
|
135
|
+
module_function :#{cmd.downcase}
|
136
|
+
E
|
137
|
+
end
|
138
|
+
|
139
|
+
# XXX:
|
140
|
+
class PRIVMSG
|
141
|
+
def to_s
|
142
|
+
str = ''
|
143
|
+
if @prefix
|
144
|
+
str << ':'
|
145
|
+
str << @prefix
|
146
|
+
str << ' '
|
147
|
+
end
|
148
|
+
|
149
|
+
str << @command
|
150
|
+
|
151
|
+
str << ' '
|
152
|
+
str << @params[0]
|
153
|
+
|
154
|
+
str << ' :'
|
155
|
+
str << @params[1..-1].join(' ')
|
156
|
+
|
157
|
+
str << "\x0D\x0A"
|
158
|
+
str
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end # Command
|
162
|
+
|
163
|
+
module Reply
|
164
|
+
class Reply < Message
|
165
|
+
end
|
166
|
+
|
167
|
+
class CommandResponse < Reply
|
168
|
+
end
|
169
|
+
|
170
|
+
class ErrorReply < Reply
|
171
|
+
end
|
172
|
+
|
173
|
+
Replies = {}
|
174
|
+
%w(001,RPL_WELCOME 002,RPL_YOURHOST 003,RPL_CREATED
|
175
|
+
004,RPL_MYINFO 005,RPL_BOUNCE
|
176
|
+
302,RPL_USERHOST 303,RPL_ISON 301,RPL_AWAY
|
177
|
+
305,RPL_UNAWAY 306,RPL_NOWAWAY 311,RPL_WHOISUSER
|
178
|
+
312,RPL_WHOISSERVER 313,RPL_WHOISOPERATOR
|
179
|
+
317,RPL_WHOISIDLE 318,RPL_ENDOFWHOIS
|
180
|
+
319,RPL_WHOISCHANNELS 314,RPL_WHOWASUSER
|
181
|
+
369,RPL_ENDOFWHOWAS 321,RPL_LISTSTART
|
182
|
+
322,RPL_LIST 323,RPL_LISTEND 325,RPL_UNIQOPIS
|
183
|
+
324,RPL_CHANNELMODEIS 331,RPL_NOTOPIC
|
184
|
+
332,RPL_TOPIC 341,RPL_INVITING 342,RPL_SUMMONING
|
185
|
+
346,RPL_INVITELIST 347,RPL_ENDOFINVITELIST
|
186
|
+
348,RPL_EXCEPTLIST 349,RPL_ENDOFEXCEPTLIST
|
187
|
+
351,RPL_VERSION 352,RPL_WHOREPLY 315,RPL_ENDOFWHO
|
188
|
+
353,RPL_NAMREPLY 366,RPL_ENDOFNAMES 364,RPL_LINKS
|
189
|
+
365,RPL_ENDOFLINKS 367,RPL_BANLIST 368,RPL_ENDOFBANLIST
|
190
|
+
371,RPL_INFO 374,RPL_ENDOFINFO 375,RPL_MOTDSTART
|
191
|
+
372,RPL_MOTD 376,RPL_ENDOFMOTD 381,RPL_YOUREOPER
|
192
|
+
382,RPL_REHASHING 383,RPL_YOURESERVICE 391,RPL_TIM
|
193
|
+
392,RPL_ 393,RPL_USERS 394,RPL_ENDOFUSERS 395,RPL_NOUSERS
|
194
|
+
200,RPL_TRACELINK 201,RPL_TRACECONNECTING
|
195
|
+
202,RPL_TRACEHANDSHAKE 203,RPL_TRACEUNKNOWN
|
196
|
+
204,RPL_TRACEOPERATOR 205,RPL_TRACEUSER 206,RPL_TRACESERVER
|
197
|
+
207,RPL_TRACESERVICE 208,RPL_TRACENEWTYPE 209,RPL_TRACECLASS
|
198
|
+
210,RPL_TRACERECONNECT 261,RPL_TRACELOG 262,RPL_TRACEEND
|
199
|
+
211,RPL_STATSLINKINFO 212,RPL_STATSCOMMANDS 219,RPL_ENDOFSTATS
|
200
|
+
242,RPL_STATSUPTIME 243,RPL_STATSOLINE 221,RPL_UMODEIS
|
201
|
+
234,RPL_SERVLIST 235,RPL_SERVLISTEND 251,RPL_LUSERCLIENT
|
202
|
+
252,RPL_LUSEROP 253,RPL_LUSERUNKNOWN 254,RPL_LUSERCHANNELS
|
203
|
+
255,RPL_LUSERME 256,RPL_ADMINME 257,RPL_ADMINLOC1
|
204
|
+
258,RPL_ADMINLOC2 259,RPL_ADMINEMAIL 263,RPL_TRYAGAIN
|
205
|
+
401,ERR_NOSUCHNICK 402,ERR_NOSUCHSERVER 403,ERR_NOSUCHCHANNEL
|
206
|
+
404,ERR_CANNOTSENDTOCHAN 405,ERR_TOOMANYCHANNELS
|
207
|
+
406,ERR_WASNOSUCHNICK 407,ERR_TOOMANYTARGETS
|
208
|
+
408,ERR_NOSUCHSERVICE 409,ERR_NOORIGIN 411,ERR_NORECIPIENT
|
209
|
+
412,ERR_NOTEXTTOSEND 413,ERR_NOTOPLEVEL 414,ERR_WILDTOPLEVEL
|
210
|
+
415,ERR_BADMASK 421,ERR_UNKNOWNCOMMAND 422,ERR_NOMOTD
|
211
|
+
423,ERR_NOADMININFO 424,ERR_FILEERROR 431,ERR_NONICKNAMEGIVEN
|
212
|
+
432,ERR_ERRONEUSNICKNAME 433,ERR_NICKNAMEINUSE
|
213
|
+
436,ERR_NICKCOLLISION 437,ERR_UNAVAILRESOURCE
|
214
|
+
441,ERR_USERNOTINCHANNEL 442,ERR_NOTONCHANNEL
|
215
|
+
443,ERR_USERONCHANNEL 444,ERR_NOLOGIN 445,ERR_SUMMONDISABLED
|
216
|
+
446,ERR_USERSDISABLED 451,ERR_NOTREGISTERED
|
217
|
+
461,ERR_NEEDMOREPARAMS 462,ERR_ALREADYREGISTRED
|
218
|
+
463,ERR_NOPERMFORHOST 464,ERR_PASSWDMISMATCH
|
219
|
+
465,ERR_YOUREBANNEDCREEP 466,ERR_YOUWILLBEBANNED
|
220
|
+
467,ERR_KEYSE 471,ERR_CHANNELISFULL 472,ERR_UNKNOWNMODE
|
221
|
+
473,ERR_INVITEONLYCHAN 474,ERR_BANNEDFROMCHAN
|
222
|
+
475,ERR_BADCHANNELKEY 476,ERR_BADCHANMASK 477,ERR_NOCHANMODES
|
223
|
+
478,ERR_BANLISTFULL 481,ERR_NOPRIVILEGES 482,ERR_CHANOPRIVSNEEDED
|
224
|
+
483,ERR_CANTKILLSERVER 484,ERR_RESTRICTED
|
225
|
+
485,ERR_UNIQOPPRIVSNEEDED 491,ERR_NOOPERHOST
|
226
|
+
501,ERR_UMODEUNKNOWNFLAG 502,ERR_USERSDONTMATCH
|
227
|
+
231,RPL_SERVICEINFO 232,RPL_ENDOFSERVICES
|
228
|
+
233,RPL_SERVICE 300,RPL_NONE 316,RPL_WHOISCHANOP
|
229
|
+
361,RPL_KILLDONE 362,RPL_CLOSING 363,RPL_CLOSEEND
|
230
|
+
373,RPL_INFOSTART 384,RPL_MYPORTIS 213,RPL_STATSCLINE
|
231
|
+
214,RPL_STATSNLINE 215,RPL_STATSILINE 216,RPL_STATSKLINE
|
232
|
+
217,RPL_STATSQLINE 218,RPL_STATSYLINE 240,RPL_STATSVLINE
|
233
|
+
241,RPL_STATSLLINE 244,RPL_STATSHLINE 244,RPL_STATSSLINE
|
234
|
+
246,RPL_STATSPING 247,RPL_STATSBLINE 250,RPL_STATSDLINE
|
235
|
+
492,ERR_NOSERVICEHOST
|
236
|
+
).each do |num_cmd|
|
237
|
+
num, cmd = num_cmd.split(',', 2)
|
238
|
+
eval <<E
|
239
|
+
class #{cmd} < #{if num[0] == ?0 || num[0] == ?2 || num[0] == ?3
|
240
|
+
'CommandResponse'
|
241
|
+
elsif num[0] == ?4 || num[0] == ?5
|
242
|
+
'ErrorReply'
|
243
|
+
end}
|
244
|
+
end
|
245
|
+
Replies['#{num}'] = #{cmd}
|
246
|
+
|
247
|
+
def #{cmd.downcase}(*params)
|
248
|
+
#{cmd}.new(nil, '#{cmd}', params)
|
249
|
+
end
|
250
|
+
module_function :#{cmd.downcase}
|
251
|
+
E
|
252
|
+
end
|
253
|
+
end # Reply
|
254
|
+
end # IRCd
|