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