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