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