require 'socket' class IrcClient attr_accessor :host, :port, :nick, :uhost, :ssl def initialize(host, port = 6667) @host = host @port = port @nick = 'irc' @uhost= 'rb rb rb :rb' @done = false @history = [] @ssl = false end def connect @sock = TCPSocket.open @host, @port puts "[*] sock open" if @ssl require 'openssl' @sock = OpenSSL::SSL::SSLSocket.new(@sock, OpenSSL::SSL::SSLContext.new) @sock.sync = true @sock.connect class << @sock def pending @rbuffer.to_s.length + super() end end puts "[*] ssl handshaken" end @sentping = false send "user #@uhost", "nick #@nick" end def run loop do if @ssl and @sock.pending > 0 r = [@sock] else r, w, e = IO.select [@sock, $stdin], nil, nil, 300 end if not r handle_timeout elsif r.include? @sock l = @sock.gets exit if not l handle_sock l.chomp elsif r.include? $stdin l = $stdin.gets exit if not l handle_stdin l.chomp end end end def run_forever begin connect run rescue puts " * #{$!.class} #{$!.message}" @sock.close unless @done sleep 300 retry end end end private def puts(*str) @history.concat str @history.shift while @history.length > 128 $stdout.puts(*str) end def send(*l) puts l.map { |ll| '> ' + ll } @sock.write l.map { |ll| ll + "\r\n" }.join end def handle_timeout raise 'server ping timeout' if @sentping send 'ping :stillalive' @sentping = true end def handle_sock l case l when /^ping (.*)/i @sock.write "pong #$1\r\n" when /^:([^!]+)(?:![^@]+@[^ ]+)? privmsg ([^ ]+) :?(.*)/i puts " #{Time.now.strftime '%H:%M:%S'} #$2 <#$1> #$3" else puts l end end def handle_stdin l case l when /^:/ send "privmsg #@curtg #{l}" when /^!reload/i load $0 when /^join (.+)/i @curtg = $1 send l when /^quit\b/i send l @done = true when /\w/ send l end end end if $0 == __FILE__ and not $run $run = true abort 'usage: ircclt sv:port nick' if ARGV.length < 2 ssl = true if ARGV.delete '--ssl' a0 = ARGV.shift if a0[0] == ?[ h = a0[/\[(.*)\]/, 1] p = a0[/\]:(.*)/, 1] else h, p = a0.split(':') end c = IrcClient.new(*[h, p].compact) c.ssl = true if ssl c.nick = ARGV.shift || 'x' c.run_forever end