1 #!/usr/local/bin/ruby
2
3 require "socket"
4
5 # Don't allow use of "tainted" data by potentially dangerous operations
6 $SAFE=1
7
8 # The irc class, which talks to the server and holds the main event loop
9 class IRC
10 def initialize(server, port, nick, channel)
11 @server = server
12 @port = port
13 @nick = nick
14 @channel = channel
15 end
16 def send(s)
17 # Send a message to the irc server and print it to the screen
18 puts "--> #{s}"
19 @irc.send "#{s}\n", 0
20 end
21 def connect()
22 # Connect to the IRC server
23 @irc = TCPSocket.open(@server, @port)
24 send "USER blah blah blah :blah blah"
25 send "NICK #{@nick}"
26 send "JOIN #{@channel}"
27 end
28 def evaluate(s)
29 # Make sure we have a valid expression (for security reasons), and
30 # evaluate it if we do, otherwise return an error message
31 if s =~ /^[-+*\/\d\s\eE.()]*$/ then
32 begin
33 s.untaint
34 return eval(s).to_s
35 rescue Exception => detail
36 puts detail.message()
37 end
38 end
39 return "Error"
40 end
41 def handle_server_input(s)
42 # This isn't at all efficient, but it shows what we can do with Ruby
43 # (Dave Thomas calls this construct "a multiway if on steroids")
44 case s.strip
45 when /^PING :(.+)$/i
46 puts "[ Server ping ]"
47 send "PONG :#{$1}"
48 when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[\001]PING (.+)[\001]$/i
49 puts "[ CTCP PING from #{$1}!#{$2}@#{$3} ]"
50 send "NOTICE #{$1} :\001PING #{$4}\001"
51 when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[\001]VERSION[\001]$/i
52 puts "[ CTCP VERSION from #{$1}!#{$2}@#{$3} ]"
53 send "NOTICE #{$1} :\001VERSION Ruby-irc v0.042\001"
54 when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s(.+)\s:EVAL (.+)$/i
55 puts "[ EVAL #{$5} from #{$1}!#{$2}@#{$3} ]"
56 send "PRIVMSG #{(($4==@nick)?$1:$4)} :#{evaluate($5)}"
57 else
58 puts s
59 end
60 end
61 def main_loop()
62 # Just keep on truckin' until we disconnect
63 while true
64 ready = select([@irc, $stdin], nil, nil, nil)
65 next if !ready
66 for s in ready[0]
67 if s == $stdin then
68 return if $stdin.eof
69 s = $stdin.gets
70 send s
71 elsif s == @irc then
72 return if @irc.eof
73 s = @irc.gets
74 handle_server_input(s)
75 end
76 end
77 end
78 end
79 end
80
81 # The main program
82 # If we get an exception, then print it out and keep going (we do NOT want
83 # to disconnect unexpectedly!)
84 irc = IRC.new('efnet.skynet.be', 6667, 'Alt-255', '#cout')
85 irc.connect()
86 begin
87 irc.main_loop()
88 rescue Interrupt
89 rescue Exception => detail
90 puts detail.message()
91 print detail.backtrace.join("\n")
92 retry
93 end