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.
@@ -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
@@ -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