konn-rupircd 0.6.0 → 0.6.1

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