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,677 @@
|
|
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 'webrick/server'
|
12
|
+
require 'monitor'
|
13
|
+
require 'thread'
|
14
|
+
require 'resolv'
|
15
|
+
require 'digest/md5'
|
16
|
+
|
17
|
+
require 'rupircd/channel.rb'
|
18
|
+
require 'rupircd/user'
|
19
|
+
require 'rupircd/utils.rb'
|
20
|
+
require 'rupircd/message.rb'
|
21
|
+
require 'rupircd/charcode'
|
22
|
+
require 'rupircd/conf'
|
23
|
+
|
24
|
+
module IRCd
|
25
|
+
class IRCServer < WEBrick::GenericServer
|
26
|
+
include Utils
|
27
|
+
include Reply
|
28
|
+
include Command
|
29
|
+
|
30
|
+
include MonitorMixin
|
31
|
+
|
32
|
+
def initialize(fconf, *args)
|
33
|
+
@_init_args = [fconf, *args]
|
34
|
+
@fconf = fconf
|
35
|
+
super(fconf.load, *args)
|
36
|
+
@used = Hash.new{|h, k| h[k.upcase] = [0,0,0]}
|
37
|
+
init
|
38
|
+
end
|
39
|
+
|
40
|
+
def init
|
41
|
+
@operators = []
|
42
|
+
@channels = {}
|
43
|
+
@users = []
|
44
|
+
@users.extend(MonitorMixin)
|
45
|
+
@ping_threads = {}
|
46
|
+
@ping_threads.extend(MonitorMixin)
|
47
|
+
@old_nicks = Hash.new{|h, k| h[k] = []}
|
48
|
+
config.replace(@fconf.load)
|
49
|
+
cf = {}
|
50
|
+
config.fetch(:Opers,{}).each{|nick, pass|
|
51
|
+
cf[mask_to_regex(nick)] = pass
|
52
|
+
}
|
53
|
+
config[:Opers] = cf
|
54
|
+
config[:ServerName] = "127.0.0.1"
|
55
|
+
end
|
56
|
+
|
57
|
+
def user_from_nick(nick)
|
58
|
+
u = @users.find{|u| u.nick == nick}
|
59
|
+
end
|
60
|
+
|
61
|
+
def start_ping(user)
|
62
|
+
@ping_threads[user] = Thread.new{
|
63
|
+
sleep(config[:PINGInterval])
|
64
|
+
send_client_message(user, nil, PING, config[:ServerName])
|
65
|
+
sleep(config[:PINGLimit])
|
66
|
+
unregister(user, "PING Timeout")
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def run(socket)
|
71
|
+
socket.extend(MonitorMixin)
|
72
|
+
user = nil
|
73
|
+
nick = nil
|
74
|
+
pass = nil
|
75
|
+
begin
|
76
|
+
first = true
|
77
|
+
while line = socket.gets
|
78
|
+
line.chomp!
|
79
|
+
next if line.empty?
|
80
|
+
case msg = Message.parse(line)
|
81
|
+
when PASS
|
82
|
+
if first
|
83
|
+
pass = msg.params[-1]
|
84
|
+
first = false
|
85
|
+
else
|
86
|
+
end
|
87
|
+
when USER
|
88
|
+
user = msg.params
|
89
|
+
if msg.params.size < 4
|
90
|
+
socket.puts err_needmoreparams(msg.command, "Not enough parameters")
|
91
|
+
user = nil
|
92
|
+
end
|
93
|
+
when NICK
|
94
|
+
nick = msg.params[0]
|
95
|
+
if us = @users.find{|us| us.nick == nick}
|
96
|
+
socket.puts ERR_NICKNAMEINUSE.new(config[:ServerName], "433", [nick, "Nickname is already in use"])
|
97
|
+
nick = nil
|
98
|
+
else
|
99
|
+
end
|
100
|
+
end
|
101
|
+
break if nick && user
|
102
|
+
end
|
103
|
+
end
|
104
|
+
return unless nick && user
|
105
|
+
start_ping(user)
|
106
|
+
begin
|
107
|
+
host = Resolv.getname(socket.addr[-1])
|
108
|
+
rescue
|
109
|
+
host = socket.addr[-1]
|
110
|
+
end
|
111
|
+
user = User.new(nick, "~"+user[0].split("@")[0], host, user[-1], socket, user[1])
|
112
|
+
@old_nicks[nick].unshift user.to_a
|
113
|
+
@users << user
|
114
|
+
send_server_message(user, "001", "Welcome to the Internet Relay Network #{user}")
|
115
|
+
send_server_message(user, "002", "Your host is #{config[:ServerName]}, running version 0.1b")
|
116
|
+
send_server_message(user, "003", "This server was created #{Time.now}")
|
117
|
+
send_server_message(user, "004", "#{config[:ServerName]} 0.1b aiwroOs oavimnqsrtklObeI")
|
118
|
+
print_motd(user)
|
119
|
+
while !socket.closed? && line = socket.gets
|
120
|
+
recv_message(user, line)
|
121
|
+
end
|
122
|
+
unregister(user)
|
123
|
+
end
|
124
|
+
|
125
|
+
def unregister(user, msg="EOF From client")
|
126
|
+
synchronize do
|
127
|
+
socket = user.socket
|
128
|
+
@ping_threads[user].kill if @ping_threads.has_key?(socket)
|
129
|
+
sent = []
|
130
|
+
if @users.include?(user)
|
131
|
+
user.joined_channels.each{|ch|
|
132
|
+
ch.unregister(user)
|
133
|
+
ch.members.each{|mem|
|
134
|
+
unless sent.include?(mem)
|
135
|
+
sent << mem
|
136
|
+
send_client_message(mem, user, QUIT, msg)
|
137
|
+
end
|
138
|
+
}
|
139
|
+
@channels.reject!{|k,v|v==ch} if ch.members.empty?
|
140
|
+
}
|
141
|
+
@users.delete(user)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
user.socket.close unless user.socket.closed?
|
145
|
+
end
|
146
|
+
|
147
|
+
def print_motd(user)
|
148
|
+
send_server_message(user, "375", "- #{config[:ServerName]} Message of the day - ")
|
149
|
+
config[:Motd].each_line{|line|
|
150
|
+
line.chomp!
|
151
|
+
send_server_message(user, "372", "- " + line)
|
152
|
+
}
|
153
|
+
send_server_message(user, "376", "End of MOTD command")
|
154
|
+
end
|
155
|
+
|
156
|
+
def oper_proc(usr, &pr)
|
157
|
+
if usr.operator || usr.local_operator
|
158
|
+
pr.call(usr)
|
159
|
+
else
|
160
|
+
send_server_message(usr, "481", "Permission Denied - You're not an IRC operator")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def recv_message(user, line)
|
165
|
+
line.chomp!
|
166
|
+
return if line.empty?
|
167
|
+
begin
|
168
|
+
msg = Message.parse(line)
|
169
|
+
params = msg.params
|
170
|
+
@used[msg.command.upcase][0] += 1
|
171
|
+
case msg
|
172
|
+
when MOTD
|
173
|
+
print_motd(user)
|
174
|
+
when LUSERS
|
175
|
+
send_server_message(user, "251", "There are #{@users.size} users and 0 services on 1 servers")
|
176
|
+
unless @operators.empty?
|
177
|
+
send_server_message(user, "252", @operators.size, "operator(s) online")
|
178
|
+
end
|
179
|
+
unless @channels.empty?
|
180
|
+
send_server_message(user, "254", @channels.size, "channels formed")
|
181
|
+
end
|
182
|
+
send_server_message(user, "255", "I have #{@users.size} clients and 0 servers")
|
183
|
+
when OPER
|
184
|
+
raise NotEnoughParameter if params.size < 2
|
185
|
+
nick, pass = params
|
186
|
+
unless opdic = config.fetch(:Opers,{}).find{|k, v| k =~ nick}
|
187
|
+
send_server_message(user, "491", "No O-lines for your host")
|
188
|
+
return
|
189
|
+
end
|
190
|
+
if Digest::MD5.hexdigest(pass) == opdic[1]
|
191
|
+
user.operator = true
|
192
|
+
user.local_operator = true
|
193
|
+
@operators.push user
|
194
|
+
send_server_message(user, "381", "You are now an IRC operator")
|
195
|
+
else
|
196
|
+
send_server_message(user, "464", "Password incorrect")
|
197
|
+
end
|
198
|
+
when CLOSE
|
199
|
+
@users.synchronize do
|
200
|
+
oper_proc(user) do
|
201
|
+
@users.each{|s| unregister(s) }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
when DIE
|
205
|
+
oper_proc(user) do
|
206
|
+
shutdown
|
207
|
+
exit!
|
208
|
+
end
|
209
|
+
when REHASH
|
210
|
+
oper_proc(user) do |usr|
|
211
|
+
cnf = @fconf.load
|
212
|
+
if Hash === cnf
|
213
|
+
config.replace(cnf)
|
214
|
+
send_server_message(usr, "382", "#{@fconf.path} :Rehashing")
|
215
|
+
else
|
216
|
+
raise "Invalid Conf file"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
when RESTART
|
220
|
+
oper_proc(user) do |usr|
|
221
|
+
@users.each{|s| unregister(s) }
|
222
|
+
init
|
223
|
+
end
|
224
|
+
when VERSION
|
225
|
+
send_server_message(user, "351", "rupircd-01b.0 #{config[:ServerName]} :Ruby Pseudo IRCD 0.1b")
|
226
|
+
when STATS
|
227
|
+
if params.empty?
|
228
|
+
raise NotEnoughParameter
|
229
|
+
return
|
230
|
+
end
|
231
|
+
c = params[0][0]
|
232
|
+
case c
|
233
|
+
when ?l
|
234
|
+
|
235
|
+
when ?m
|
236
|
+
@used.each_pair{|cmd, val|
|
237
|
+
send_server_message(user, "212", cmd, val[0])
|
238
|
+
}
|
239
|
+
when ?o
|
240
|
+
|
241
|
+
when ?u
|
242
|
+
vs = Time.now.to_i - @started.to_i
|
243
|
+
days = vs / (3600*24)
|
244
|
+
vs -= days * 3600 * 24
|
245
|
+
hours = vs / 3600
|
246
|
+
vs -= hours * 3600
|
247
|
+
minutes = vs/60
|
248
|
+
vs -= minutes * 60
|
249
|
+
send_server_message(user, "242", format("Server Up %d days %d:%02d:%02d",days,hours,minutes,vs))
|
250
|
+
end
|
251
|
+
send_server_message(user, "219", c.chr, "End of STATS report")
|
252
|
+
when JOIN
|
253
|
+
if params[0] == "0"
|
254
|
+
user.joined_channels.each{|ch|
|
255
|
+
channel(ch).part(user, "")
|
256
|
+
}
|
257
|
+
user.joined_channels = []
|
258
|
+
else
|
259
|
+
chs = params[0].split(",")
|
260
|
+
keys = msg.params[1].split(",") if params.size >= 2
|
261
|
+
keys ||= []
|
262
|
+
chs.each_with_index{|ch, i|
|
263
|
+
unless channame?(ch)
|
264
|
+
send_server_message(user, "403", ch, "No such channel")
|
265
|
+
next
|
266
|
+
end
|
267
|
+
|
268
|
+
chclass = case ch
|
269
|
+
when /^\+/
|
270
|
+
NoModeChannel
|
271
|
+
when /^#/
|
272
|
+
Channel
|
273
|
+
when /^!#/
|
274
|
+
SafeChannel
|
275
|
+
end
|
276
|
+
unless @channels.has_key?(ch.downcase)
|
277
|
+
set_channel(ch, chclass.new(self, user, ch) )
|
278
|
+
handle_reply(user, channel(ch).join(user, keys[i]))
|
279
|
+
else
|
280
|
+
rpl = channel(ch).join(user, keys[i])
|
281
|
+
handle_reply(user, rpl)
|
282
|
+
end
|
283
|
+
}
|
284
|
+
end
|
285
|
+
when PART
|
286
|
+
ch, msg = params
|
287
|
+
msg ||= ""
|
288
|
+
chs = ch.split(",")
|
289
|
+
chs.each{|chname|
|
290
|
+
ch = channel(chname)
|
291
|
+
ch.part(user, msg)
|
292
|
+
if ch.members.empty?
|
293
|
+
@channels.delete(chname.downcase)
|
294
|
+
end
|
295
|
+
user.joined_channels.delete(ch)
|
296
|
+
}
|
297
|
+
when PING
|
298
|
+
send_client_message(user, config[:ServerName], PONG, config[:ServerName], *params)
|
299
|
+
when INFO
|
300
|
+
config[:Info].each_line{|line|
|
301
|
+
line.chomp!
|
302
|
+
send_server_message(user, "371", line)
|
303
|
+
}
|
304
|
+
send_server_message(user, "374", "End of INFO list")
|
305
|
+
when LINKS
|
306
|
+
send_server_message(user, "365")
|
307
|
+
when TIME
|
308
|
+
send_server_message(user, "391", config[:ServerName], Time.now.to_s)
|
309
|
+
when PONG
|
310
|
+
@ping_threads[user].kill
|
311
|
+
start_ping(user)
|
312
|
+
when INVITE
|
313
|
+
if params.size < 2
|
314
|
+
raise NotEnoughParameter
|
315
|
+
else
|
316
|
+
who, to = params
|
317
|
+
if target = @users.find{|v| v.nick == who}
|
318
|
+
if target.away?
|
319
|
+
msg = target.away
|
320
|
+
send_server_message(user, "301", who, msg)
|
321
|
+
return
|
322
|
+
end
|
323
|
+
if ch = channel(to)
|
324
|
+
handle_reply(user, ch.invite(user, target))
|
325
|
+
else
|
326
|
+
send_server_message(user, "401", who, "No such nick/channel")
|
327
|
+
end
|
328
|
+
else
|
329
|
+
send_server_message(user, "401", who, "No such nick/channel")
|
330
|
+
end
|
331
|
+
end
|
332
|
+
when LIST
|
333
|
+
if params.empty?
|
334
|
+
chs = @channels.find_all{|k, v| v.visible?(nil)}
|
335
|
+
chs.each{|k, v|
|
336
|
+
case (tpc = v.get_topic(user, true))[0]
|
337
|
+
when "331"
|
338
|
+
tpc = ""
|
339
|
+
else
|
340
|
+
tpc = tpc[-1]
|
341
|
+
end
|
342
|
+
send_server_message(user, "322", k, v.members.size.to_s, tpc)
|
343
|
+
}
|
344
|
+
else
|
345
|
+
chs = params[0].split(",").find_all{|name| channel(name) && channel(n).visible?(user)}
|
346
|
+
chs.each{|k|
|
347
|
+
v = channel(k)
|
348
|
+
uss = v.members.find_all{|m| !m.invisible}
|
349
|
+
case (tpc = v.get_topic(user, true))[0]
|
350
|
+
when "331"
|
351
|
+
tpc = ""
|
352
|
+
else
|
353
|
+
tpc = tpc[-1]
|
354
|
+
end
|
355
|
+
send_server_message(user, "322", k, v.members.size.to_s, tpc)
|
356
|
+
}
|
357
|
+
end
|
358
|
+
send_server_message(user, "323", "End of LIST")
|
359
|
+
when TOPIC
|
360
|
+
chn, topic = params
|
361
|
+
unless ch = channel(chn)
|
362
|
+
send_server_message(user, "403", chn, "No such channel")
|
363
|
+
return
|
364
|
+
end
|
365
|
+
if params.size < 1
|
366
|
+
raise NotEnoughParameter
|
367
|
+
elsif params.size == 1
|
368
|
+
send_server_message(user, *ch.get_topic(user))
|
369
|
+
else
|
370
|
+
handle_reply(user, ch.set_topic(user, topic))
|
371
|
+
end
|
372
|
+
when PRIVMSG
|
373
|
+
if params.size < 2
|
374
|
+
raise NotEnoughParameter
|
375
|
+
end
|
376
|
+
to, msg = params
|
377
|
+
if ch = channel(to)
|
378
|
+
if msg.empty?
|
379
|
+
send_server_message(user, "412", "No text to send")
|
380
|
+
else
|
381
|
+
handle_reply(user, ch.privmsg(user, msg))
|
382
|
+
end
|
383
|
+
elsif who = @users.find{|v| v.nick == to}
|
384
|
+
if who.away?
|
385
|
+
away = who.away
|
386
|
+
send_server_message(user, "301", to, away)
|
387
|
+
else
|
388
|
+
send_client_message(who, user, PRIVMSG, who.nick, msg)
|
389
|
+
end
|
390
|
+
else
|
391
|
+
send_server_message(user, "401", to, "No such nick/channel")
|
392
|
+
end
|
393
|
+
when NAMES
|
394
|
+
if params.size < 1
|
395
|
+
raise NotEnoughParameter
|
396
|
+
else
|
397
|
+
chs = params[0].split(",")
|
398
|
+
chs.each{|ch|
|
399
|
+
handle_reply(user, channel(ch).names(user))
|
400
|
+
}
|
401
|
+
end
|
402
|
+
when NOTICE
|
403
|
+
if params.size < 2
|
404
|
+
raise NotEnoughParameter
|
405
|
+
return
|
406
|
+
end
|
407
|
+
to, msg = params
|
408
|
+
if ch = channel(to)
|
409
|
+
if msg.empty?
|
410
|
+
send_server_message(user, "412", "No text to send")
|
411
|
+
else
|
412
|
+
handle_reply(user, ch.notice(user, msg))
|
413
|
+
end
|
414
|
+
elsif who = @users.find{|v| v.nick == to}
|
415
|
+
send_client_message(who, user, NOTICE, user.nick, msg)
|
416
|
+
else
|
417
|
+
send_server_message(user, "401", to, "No such nick/channel")
|
418
|
+
end
|
419
|
+
when AWAY
|
420
|
+
if params.empty? || params[0].empty?
|
421
|
+
user.away = ""
|
422
|
+
send_server_message(user, "305", "You are no longer marked as being away")
|
423
|
+
else
|
424
|
+
user.away = params.shift
|
425
|
+
send_server_message(user, "306", "You have been marked as being away")
|
426
|
+
end
|
427
|
+
when MODE
|
428
|
+
if params.size < 1
|
429
|
+
raise NotEnoughParameter
|
430
|
+
return
|
431
|
+
end
|
432
|
+
to = params.shift
|
433
|
+
if ch = channel(to)
|
434
|
+
handle_reply(user, ch.handle_mode(user, params))
|
435
|
+
elsif who = @users.find{|v| v.nick == to}
|
436
|
+
if who == user
|
437
|
+
if params.empty?
|
438
|
+
send_server_message(user, "221", who.get_mode_flags)
|
439
|
+
else
|
440
|
+
rls = who.set_flags(params[0])
|
441
|
+
send_client_message(user, user, MODE, user.nick, rls.join(" "))
|
442
|
+
end
|
443
|
+
else
|
444
|
+
send_server_message(user, "502", "Cannot change mode for other users")
|
445
|
+
end
|
446
|
+
else
|
447
|
+
send_server_message(user, "401", to, "No such nick/channel")
|
448
|
+
end
|
449
|
+
when NICK
|
450
|
+
if params.empty?
|
451
|
+
send_server_message(user, "431", "No nickname given")
|
452
|
+
else
|
453
|
+
nick = params[0]
|
454
|
+
if nick == "0"
|
455
|
+
nick = user.identifier.to_s
|
456
|
+
elsif !correct_nick?(nick)
|
457
|
+
send_server_message(user, "432", nick, "Erroneous nickname")
|
458
|
+
return
|
459
|
+
end
|
460
|
+
if us = user_from_nick(nick)
|
461
|
+
return if us == user
|
462
|
+
send_server_message(user, "433", nick, "Nickname is already in use")
|
463
|
+
elsif user.restriction
|
464
|
+
send_server_message(user, "484", "Your connection is restricted!")
|
465
|
+
else
|
466
|
+
send_client_message(user, user, NICK, nick)
|
467
|
+
sent = []
|
468
|
+
user.joined_channels.each{|ch|
|
469
|
+
ch.members.each{|mem|
|
470
|
+
if !sent.include?(mem) && mem != user
|
471
|
+
sent << mem
|
472
|
+
send_client_message(mem, user, NICK, nick)
|
473
|
+
end
|
474
|
+
}
|
475
|
+
}
|
476
|
+
@old_nicks[nick].unshift user.to_a
|
477
|
+
user.nick = nick
|
478
|
+
end
|
479
|
+
end
|
480
|
+
when USER, PASS
|
481
|
+
puts_socket(user, ERR_ALREADYREGISTRED.new(config[:ServerName], "462", [user.nick, "Unauthorized command (already registered)"]))
|
482
|
+
when WHOIS
|
483
|
+
raise NotEnoughParameter if params.empty?
|
484
|
+
params[0].split(",").each{|mask|
|
485
|
+
reg = mask_to_regex(mask)
|
486
|
+
matched = @users.find_all{|usr| usr.nick =~ reg}
|
487
|
+
if matched.empty?
|
488
|
+
send_server_message(user, "401", mask, "No such nick/channel")
|
489
|
+
else
|
490
|
+
matched.each{|target|
|
491
|
+
sc = target.socket
|
492
|
+
send_server_message(user, "311", target.nick, target.user, target.host, "*", target.real)
|
493
|
+
send_server_message(user, "312", target.nick, config[:ServerName], "this server.")
|
494
|
+
send_server_message(user, "313", target.nick, "is an IRC operator") if @operators.include?(target)
|
495
|
+
chs = []
|
496
|
+
target.joined_channels.each{|ch|
|
497
|
+
if ch.visible?(user)
|
498
|
+
pr = ""
|
499
|
+
if ch.mode.op?(target)
|
500
|
+
pr = "@"
|
501
|
+
else ch.mode.voiced?(target)
|
502
|
+
pr = "+"
|
503
|
+
end
|
504
|
+
chs << pr+ch.name
|
505
|
+
end
|
506
|
+
}
|
507
|
+
send_server_message(user, "319", target.nick, chs.join(" "))
|
508
|
+
if target.away?
|
509
|
+
away = target.away
|
510
|
+
send_server_message(user, "301", target.nick, away)
|
511
|
+
end
|
512
|
+
send_server_message(user, "318", target.nick, "End of WHOIS list")
|
513
|
+
}
|
514
|
+
end
|
515
|
+
}
|
516
|
+
when WHOWAS
|
517
|
+
raise NotEnoughParameter if params.empty?
|
518
|
+
params[0].split(",").each{|nick|
|
519
|
+
if @users.any?{|us| us.nick == nick}
|
520
|
+
send_server_message(user, "312", nick, config[:ServerName], "this server.")
|
521
|
+
elsif @old_nicks[nick].empty?
|
522
|
+
send_server_message(user, "406", nick, "There was no such nickname")
|
523
|
+
else
|
524
|
+
@old_nicks[nick].each{|nms|
|
525
|
+
send_server_message(user, "314", *nms)
|
526
|
+
}
|
527
|
+
end
|
528
|
+
send_server_message(user, "369", nick, "End of WHOWAS")
|
529
|
+
}
|
530
|
+
when WHO
|
531
|
+
raise NotEnoughParameter if params.empty?
|
532
|
+
mask = mask_to_regex(params[0])
|
533
|
+
chs = @channels.find_all{|name, ch| name =~ mask && ch.visible?(user)}
|
534
|
+
unless chs.empty?
|
535
|
+
chs.each{|name, ch|
|
536
|
+
ch.members.each{|usr|
|
537
|
+
sym = usr.away? ? "G" : "H"
|
538
|
+
sym += @operators.include?(usr) ? "*" : ""
|
539
|
+
sym += ch.mode.op?(usr) ? "@" : (ch.mode.voiced?(usr) ? "+" : "")
|
540
|
+
send_server_message(user, "352", usr.name, usr.user, usr.host, config[:ServerName], usr.nick, sym, "0 #{real}")
|
541
|
+
}
|
542
|
+
send_server_message(user, "315", name, "End of WHO list")
|
543
|
+
}
|
544
|
+
else
|
545
|
+
usrs = @users.find_all{|us| us.nick =~ mask || us.user =~ mask || us.host =~ mask}
|
546
|
+
usrs.each{|usr|
|
547
|
+
send_server_message(user, "352", "*", usr.user, usr.host, config[:ServerName], usr.nick, "H", "0 #{usr.real}")
|
548
|
+
send_server_message(user, "315", usr.nick, "End of WHO list")
|
549
|
+
}
|
550
|
+
end
|
551
|
+
when KICK
|
552
|
+
raise NotEnoughParameter if params.size < 2
|
553
|
+
chs = params[0].split(",")
|
554
|
+
whos = params[1].split(",")
|
555
|
+
msg = params[2].to_s
|
556
|
+
if chs.size == 1
|
557
|
+
if ch = channel(chs[0])
|
558
|
+
whos.each{|who|
|
559
|
+
if usr = @users.find{|us|us.nick==who}
|
560
|
+
handle_reply user, ch.kick(usr, user, msg)
|
561
|
+
else
|
562
|
+
send_server_message(user, "401", who, "No such nick/channel")
|
563
|
+
end
|
564
|
+
}
|
565
|
+
else
|
566
|
+
send_server_message(user, "403", chs[0], "No such channel")
|
567
|
+
end
|
568
|
+
elsif chs.size == whos.size
|
569
|
+
chs.each_with_index{|chn, i|
|
570
|
+
if chn = channel(chn)
|
571
|
+
if usr = user_from_nick[whos[i]]
|
572
|
+
handle_reply user, ch.kick(usr, user, msg)
|
573
|
+
else
|
574
|
+
send_server_message(user, "401", whos[i], "No such nick/channel")
|
575
|
+
end
|
576
|
+
else
|
577
|
+
send_server_message(user, "403", chn, "No such channel")
|
578
|
+
end
|
579
|
+
}
|
580
|
+
end
|
581
|
+
when ISON
|
582
|
+
raise NotEnoughParameter if params.empty?
|
583
|
+
a = params.find_all{|nick| @users.any?{|us| us.nick == nick}}
|
584
|
+
send_server_message(user, "303", a.join(" "))
|
585
|
+
when USERHOST
|
586
|
+
raise NotEnoughParameter if params.empty?
|
587
|
+
targs = params[0..4]
|
588
|
+
targs.map!{|nick|
|
589
|
+
if tg = @users.find{|u| u.nick == nick}
|
590
|
+
suf = @operators.include?(tg.socket) ? "*" : ""
|
591
|
+
pre = tg.away? ? "-" : "+"
|
592
|
+
usr = tg.user
|
593
|
+
host = tg.host
|
594
|
+
nick + suf + "=" + pre + usr + "@" + host + " "
|
595
|
+
else
|
596
|
+
""
|
597
|
+
end
|
598
|
+
}
|
599
|
+
send_server_message(user, "302", targs.join(" "))
|
600
|
+
when QUIT
|
601
|
+
send_client_message(user, nil, ERROR, "Closing", "Link:", "#{user.nick}[#{user.user}@#{user.host}]", %Q!("#{params[0]}")!)
|
602
|
+
unregister(user, params[0])
|
603
|
+
else
|
604
|
+
raise UnknownCommand.new(msg.command)
|
605
|
+
end
|
606
|
+
rescue NotEnoughParameter => e
|
607
|
+
send_server_message(user, "461", msg.command, "Not enough parameters")
|
608
|
+
rescue UnknownCommand => e
|
609
|
+
send_server_message(user, "421", e.cmd, "Unknown command")
|
610
|
+
rescue
|
611
|
+
puts $!, $@
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
def handle_reply(user, rpl)
|
616
|
+
return unless rpl
|
617
|
+
case rpl[0]
|
618
|
+
when Array
|
619
|
+
rpl.each{|rp|
|
620
|
+
handle_reply(user, rp)
|
621
|
+
}
|
622
|
+
when Command
|
623
|
+
send_client_message(user, user, *rpl)
|
624
|
+
else
|
625
|
+
send_server_message(user, *rpl)
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
def send_message(to, from, msg, *args)
|
630
|
+
case msg
|
631
|
+
when Command
|
632
|
+
send_client_message(to, from, msg, *args)
|
633
|
+
when Reply
|
634
|
+
send_server_message(to, msg, *args)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
def puts_socket(user, *args)
|
639
|
+
user.socket.synchronize do
|
640
|
+
if user.socket.closed?
|
641
|
+
unregister(user, "Connection reset by peer")
|
642
|
+
else
|
643
|
+
begin
|
644
|
+
args.map!{|a| a.to_s.encode config().fetch(:Encoding, "ISO-2022-JP")}
|
645
|
+
user.socket.puts(*args)
|
646
|
+
rescue Errno::EPIPE => e
|
647
|
+
unregister(user, "Connection reset by peer")
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
def send_client_message(to, from, cmd, *args)
|
654
|
+
msg = cmd.new(from.to_s, cmd.name.split('::').last, args)
|
655
|
+
puts_socket(to, msg)
|
656
|
+
end
|
657
|
+
|
658
|
+
def send_server_message(to, msg, *args)
|
659
|
+
args.unshift to.nick
|
660
|
+
puts_socket(to, Message.build(config[:ServerName], msg, args) )
|
661
|
+
end
|
662
|
+
|
663
|
+
def channel(chname)
|
664
|
+
@channels[chname.downcase]
|
665
|
+
end
|
666
|
+
|
667
|
+
def set_channel(cn, val)
|
668
|
+
@channels[cn.downcase] = val
|
669
|
+
end
|
670
|
+
|
671
|
+
def start(*args)
|
672
|
+
@started = Time.now
|
673
|
+
super
|
674
|
+
end
|
675
|
+
|
676
|
+
end
|
677
|
+
end
|