]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/commitdiff
Thu Aug 04 23:03:30 BST 2005 Tom Gilbert <tom@linuxbrit.co.uk>
authorTom Gilbert <tom@linuxbrit.co.uk>
Thu, 4 Aug 2005 22:44:35 +0000 (22:44 +0000)
committerTom Gilbert <tom@linuxbrit.co.uk>
Thu, 4 Aug 2005 22:44:35 +0000 (22:44 +0000)
  * Improved ircd recognition of rfc2812.rb
* de-string'd, de-cap'd rfc2812.rb, looks less shouty now
* moved the Q auth stuff (for quakenet) into a new qauth plugin (untested!)
* finish fixing the httputil

ChangeLog
data/rbot/plugins/quakeauth.rb [new file with mode: 0644]
lib/rbot/config.rb
lib/rbot/httputil.rb
lib/rbot/ircbot.rb
lib/rbot/plugins.rb
lib/rbot/rfc2812.rb

index 923962983099bfd04717c6a6b776dac61549d2da..bdd6c10dbf1e4521a75d9c69e539515db65bbe01 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu Aug 04 23:03:30 BST 2005  Tom Gilbert <tom@linuxbrit.co.uk>
+
+  * Improved ircd recognition of rfc2812.rb
+       * de-string'd, de-cap'd rfc2812.rb, looks less shouty now
+       * moved the Q auth stuff (for quakenet) into a new qauth plugin (untested!)
+       * finish fixing the httputil
+
 Thu Aug 04 00:11:52 BST 2005  Tom Gilbert <tom@linuxbrit.co.uk>
 
   * Tweaked the debug() stuff a bit. Need to do this more cleanly really
diff --git a/data/rbot/plugins/quakeauth.rb b/data/rbot/plugins/quakeauth.rb
new file mode 100644 (file)
index 0000000..8f412f1
--- /dev/null
@@ -0,0 +1,51 @@
+# automatically auths with Q on quakenet servers
+
+class QPlugin < Plugin
+  
+  def help(plugin, topic="")
+    case topic
+    when ""
+      return "quath plugin: handles Q auths. topics set, identify"
+    when "set"
+      return "nickserv set <user> <passwd>: set the Q user and password and use it to identify in future"
+    when "identify"
+      return "quath identify: identify with Q (if user and auth are set)"
+    end
+  end
+  
+  def initialize
+    super
+    # this plugin only wants to store strings!
+    class << @registry
+      def store(val)
+        val
+      end
+      def restore(val)
+        val
+      end
+    end
+  end
+
+  def set(m, params)
+    @registry['quakenet.user'] = params[:user]
+    @registry['quakenet.auth'] = params[:passwd]
+    m.okay
+  end
+  
+  def connect
+    identify(nil, nil)
+  end
+  def identify(m, params)
+    if @registry.has_key?('quakenet.user') && @registry.has_key?('quakenet.auth')
+      debug "authing with Q using  #{@registry['quakenet.user']} #{@registry['quakenet.auth']}"
+      @bot.sendmsg "PRIVMSG", "Q@CServe.quakenet.org", "auth #{@registry['quakenet.user']} #{@registry['quakenet.auth']}"                                                    
+      m.okay if m
+    else
+      m.reply "not configured, try 'qauth set :nick :passwd'" if m
+    end
+  end
+
+end
+plugin = QPlugin.new
+plugin.map 'qauth set :nick :passwd', :action => "set"
+plugin.map 'quath identify', :action => "identify"
index e4237e81439059570cb9c6b98a54250610ae519a..957c63a3fd68966bef5f40d5667e52d3a475f602 100644 (file)
@@ -134,7 +134,7 @@ module Irc
       string
     end
     def desc
-      "#{@desc} [valid values are: " + @values.join(", ") + "]"
+      "#{@desc} [valid values are: " + values.join(", ") + "]"
     end
   end
 
index e234dc101d32450e88c381a68d92bc4e9c15b70b..b4f25c95e77aa6de7ac5e4689d7f11c9e4a928f8 100644 (file)
@@ -23,6 +23,7 @@ class HttpUtil
       :default => [],
       :desc => "List of regexps to check against a URI's hostname/ip to see if we should use the proxy to access this URI. All URIs are proxied by default if the proxy is set, so this is only required to re-include URIs that might have been excluded by the exclude list. e.g. exclude /.*\.foo\.com/, include bar\.foo\.com")
     BotConfig.register BotConfigArrayValue.new('http.proxy_exclude',
+      :default => [],
       :desc => "List of regexps to check against a URI's hostname/ip to see if we should use avoid the proxy to access this URI and access it directly")
 
   def initialize(bot)
index f99dd940d5207794d00c486eeb7e9fb13dd38427..24ee6de3f6cf407bbb31108b6fe9995cb8ed9c6f 100644 (file)
@@ -159,35 +159,36 @@ class IrcBot
     end
     
     @client = IrcClient.new
-    @client["PRIVMSG"] = proc { |data|
-      message = PrivMessage.new(self, data["SOURCE"], data["TARGET"], data["MESSAGE"])
+    @client[:privmsg] = proc { |data|
+      message = PrivMessage.new(self, data[:source], data[:target], data[:message])
       onprivmsg(message)
     }
-    @client["NOTICE"] = proc { |data|
-      message = NoticeMessage.new(self, data["SOURCE"], data["TARGET"], data["MESSAGE"])
+    @client[:notice] = proc { |data|
+      message = NoticeMessage.new(self, data[:source], data[:target], data[:message])
       # pass it off to plugins that want to hear everything
       @plugins.delegate "listen", message
     }
-    @client["MOTD"] = proc { |data|
-      data['MOTD'].each_line { |line|
+    @client[:motd] = proc { |data|
+      data[:motd].each_line { |line|
         log "MOTD: #{line}", "server"
       }
     }
-    @client["NICKTAKEN"] = proc { |data| 
-      nickchg "#{@nick}_"
+    @client[:nicktaken] = proc { |data| 
+      nickchg "#{data[:nick]}_"
     }
-    @client["BADNICK"] = proc {|data| 
-      puts "WARNING, bad nick (#{data['NICK']})"
+    @client[:badnick] = proc {|data| 
+      puts "WARNING, bad nick (#{data[:nick]})"
     }
-    @client["PING"] = proc {|data|
+    @client[:ping] = proc {|data|
       # (jump the queue for pongs)
-      @socket.puts "PONG #{data['PINGID']}"
+      @socket.puts "PONG #{data[:pingid]}"
     }
-    @client["NICK"] = proc {|data|
-      sourcenick = data["SOURCENICK"]
-      nick = data["NICK"]
-      m = NickMessage.new(self, data["SOURCE"], data["SOURCENICK"], data["NICK"])
+    @client[:nick] = proc {|data|
+      sourcenick = data[:sourcenick]
+      nick = data[:nick]
+      m = NickMessage.new(self, data[:source], data[:sourcenick], data[:nick])
       if(sourcenick == @nick)
+        debug "my nick is now #{nick}"
         @nick = nick
       end
       @channels.each {|k,v|
@@ -200,13 +201,13 @@ class IrcBot
       @plugins.delegate("listen", m)
       @plugins.delegate("nick", m)
     }
-    @client["QUIT"] = proc {|data|
-      source = data["SOURCE"]
-      sourcenick = data["SOURCENICK"]
-      sourceurl = data["SOURCEADDRESS"]
-      message = data["MESSAGE"]
-      m = QuitMessage.new(self, data["SOURCE"], data["SOURCENICK"], data["MESSAGE"])
-      if(data["SOURCENICK"] =~ /#{@nick}/i)
+    @client[:quit] = proc {|data|
+      source = data[:source]
+      sourcenick = data[:sourcenick]
+      sourceurl = data[:sourceaddress]
+      message = data[:message]
+      m = QuitMessage.new(self, data[:source], data[:sourcenick], data[:message])
+      if(data[:sourcenick] =~ /#{@nick}/i)
       else
         @channels.each {|k,v|
           if(v.users.has_key?(sourcenick))
@@ -218,27 +219,24 @@ class IrcBot
       @plugins.delegate("listen", m)
       @plugins.delegate("quit", m)
     }
-    @client["MODE"] = proc {|data|
-      source = data["SOURCE"]
-      sourcenick = data["SOURCENICK"]
-      sourceurl = data["SOURCEADDRESS"]
-      channel = data["CHANNEL"]
-      targets = data["TARGETS"]
-      modestring = data["MODESTRING"]
+    @client[:mode] = proc {|data|
+      source = data[:source]
+      sourcenick = data[:sourcenick]
+      sourceurl = data[:sourceaddress]
+      channel = data[:channel]
+      targets = data[:targets]
+      modestring = data[:modestring]
       log "@ Mode #{modestring} #{targets} by #{sourcenick}", channel
     }
-    @client["WELCOME"] = proc {|data|
-      log "joined server #{data['SOURCE']} as #{data['NICK']}", "server"
-      debug "I think my nick is #{@nick}, server thinks #{data['NICK']}"
-      if data['NICK'] && data['NICK'].length > 0
-        @nick = data['NICK']
-      end
-      if(@config['irc.quser'])
-        # TODO move this to a plugin
-        debug "authing with Q using  #{@config['quakenet.user']} #{@config['quakenet.auth']}"
-        @socket.puts "PRIVMSG Q@CServe.quakenet.org :auth #{@config['quakenet.user']} #{@config['quakenet.auth']}"
+    @client[:welcome] = proc {|data|
+      log "joined server #{data[:source]} as #{data[:nick]}", "server"
+      debug "I think my nick is #{@nick}, server thinks #{data[:nick]}"
+      if data[:nick] && data[:nick].length > 0
+        @nick = data[:nick]
       end
 
+      @plugins.delegate("connect")
+
       @config['irc.join_channels'].each {|c|
         debug "autojoining channel #{c}"
         if(c =~ /^(\S+)\s+(\S+)$/i)
@@ -248,47 +246,47 @@ class IrcBot
         end
       }
     }
-    @client["JOIN"] = proc {|data|
-      m = JoinMessage.new(self, data["SOURCE"], data["CHANNEL"], data["MESSAGE"])
+    @client[:join] = proc {|data|
+      m = JoinMessage.new(self, data[:source], data[:channel], data[:message])
       onjoin(m)
     }
-    @client["PART"] = proc {|data|
-      m = PartMessage.new(self, data["SOURCE"], data["CHANNEL"], data["MESSAGE"])
+    @client[:part] = proc {|data|
+      m = PartMessage.new(self, data[:source], data[:channel], data[:message])
       onpart(m)
     }
-    @client["KICK"] = proc {|data|
-      m = KickMessage.new(self, data["SOURCE"], data["TARGET"],data["CHANNEL"],data["MESSAGE"]) 
+    @client[:kick] = proc {|data|
+      m = KickMessage.new(self, data[:source], data[:target],data[:channel],data[:message]) 
       onkick(m)
     }
-    @client["INVITE"] = proc {|data|
-      if(data["TARGET"] =~ /^#{@nick}$/i)
-        join data["CHANNEL"] if (@auth.allow?("join", data["SOURCE"], data["SOURCENICK"]))
+    @client[:invite] = proc {|data|
+      if(data[:target] =~ /^#{@nick}$/i)
+        join data[:channel] if (@auth.allow?("join", data[:source], data[:sourcenick]))
       end
     }
-    @client["CHANGETOPIC"] = proc {|data|
-      channel = data["CHANNEL"]
-      sourcenick = data["SOURCENICK"]
-      topic = data["TOPIC"]
-      timestamp = data["UNIXTIME"] || Time.now.to_i
+    @client[:changetopic] = proc {|data|
+      channel = data[:channel]
+      sourcenick = data[:sourcenick]
+      topic = data[:topic]
+      timestamp = data[:unixtime] || Time.now.to_i
       if(sourcenick == @nick)
         log "@ I set topic \"#{topic}\"", channel
       else
         log "@ #{sourcenick} set topic \"#{topic}\"", channel
       end
-      m = TopicMessage.new(self, data["SOURCE"], data["CHANNEL"], timestamp, data["TOPIC"])
+      m = TopicMessage.new(self, data[:source], data[:channel], timestamp, data[:topic])
 
       ontopic(m)
       @plugins.delegate("listen", m)
       @plugins.delegate("topic", m)
     }
-    @client["TOPIC"] = @client["TOPICINFO"] = proc {|data|
-      channel = data["CHANNEL"]
-      m = TopicMessage.new(self, data["SOURCE"], data["CHANNEL"], data["UNIXTIME"], data["TOPIC"])
+    @client[:topic] = @client[:topicinfo] = proc {|data|
+      channel = data[:channel]
+      m = TopicMessage.new(self, data[:source], data[:channel], data[:unixtime], data[:topic])
         ontopic(m)
     }
-    @client["NAMES"] = proc {|data|
-      channel = data["CHANNEL"]
-      users = data["USERS"]
+    @client[:names] = proc {|data|
+      channel = data[:channel]
+      users = data[:users]
       unless(@channels[channel])
         puts "bug: got names for channel '#{channel}' I didn't think I was in\n"
         exit 2
@@ -298,8 +296,9 @@ class IrcBot
         @channels[channel].users[u[0].sub(/^[@&~+]/, '')] = ["mode", u[1]]
       }
     }
-    @client["UNKNOWN"] = proc {|data|
-      debug "UNKNOWN: #{data['SERVERSTRING']}"
+    @client[:unknown] = proc {|data|
+      #debug "UNKNOWN: #{data[:serverstring]}"
+      log data[:serverstring], ":unknown"
     }
   end
 
index 4e618f61df0b554b513dc7943e9f39e260f41106..bffba2273994e98d658bee176583c54c080f3509 100644 (file)
@@ -78,6 +78,9 @@ module Plugins
   # topic(TopicMessage)::
   #                        Called when a user (or the bot) changes a channel
   #                        topic
+  #
+  # connect()::            Called when a server is joined successfully, but
+  #                        before autojoin channels are joined (no params)
   # 
   # save::                 Called when you are required to save your plugin's
   #                        state, if you maintain data between sessions
index 6f459c80fbb540b9772abe764839c5bd5b189c84..df9b9bb6a3ef14b0ed3039d7944b749936be3a8e 100644 (file)
@@ -15,8 +15,10 @@ module Irc
   # - The server sends Replies 001 to 004 to a user upon
   # successful registration.
   # 
-  RPL_BOUNCE=005
-  # "Try server <server name>, port <port number>"
+  # RPL_BOUNCE=005
+  # # "Try server <server name>, port <port number>"
+  RPL_ISUPPORT=005
+  # "005 nick PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
   # 
   # - Sent by the server to a user to suggest an alternative
   # server.  This is often used when the connection is
@@ -354,6 +356,13 @@ module Irc
   # being displayed anyway.
   # RPL_TRACEEND is sent to indicate the end of the list.
   # 
+  RPL_LOCALUSERS=265
+  # ":Current local  users: 3  Max: 4"
+  RPL_GLOBALUSERS=266
+  # ":Current global users: 3  Max: 4"
+  RPL_STATSCONN=250
+  # "::Highest connection count: 4 (4 clients) (251 since server was
+  # (re)started)"
   RPL_STATSLINKINFO=211
   # "<linkname> <sendq> <sent messages>
   # <sent Kbytes> <received messages>
@@ -799,7 +808,6 @@ module Irc
   RPL_STATSSLINE=244
   RPL_STATSPING=246  
   RPL_STATSBLINE=247
-  RPL_STATSDLINE=250
   ERR_NOSERVICEHOST=492
   
   # implements RFC 2812 and prior IRC RFCs.
@@ -818,29 +826,31 @@ module Irc
     #
     # ==server events currently supported:
     #
-    # PING::        server pings you (default handler returns a pong)
-    # NICKTAKEN::   you tried to change nick to one that's in use
-    # BADNICK::     you tried to change nick to one that's invalid
-    # TOPIC::       someone changed the topic of a channel
-    # TOPICINFO::   on joining a channel or asking for the topic, tells you
-    #               who set it and when
-    # NAMES::       server sends list of channel members when you join
-    # WELCOME::     server welcome message on connect
-    # MOTD::        server message of the day
-    # PRIVMSG::     privmsg, the core of IRC, a message to you from someone
-    # PUBLIC::      optionally instead of getting privmsg you can hook to only
-    #               the public ones...
-    # MSG::         or only the private ones, or both
-    # KICK::        someone got kicked from a channel
-    # PART::        someone left a channel
-    # QUIT::        someone quit IRC
-    # JOIN::        someone joined a channel
-    # CHANGETOPIC:: the topic of a channel changed
-    # INVITE::      you are invited to a channel
-    # NICK::        someone changed their nick
-    # MODE::        a mode change
-    # NOTICE::      someone sends you a notice
-    # UNKNOWN::     any other message not handled by the above
+    # :created       when the server was started
+    # :yourhost      your host details (on connection)
+    # :ping::        server pings you (default handler returns a pong)
+    # :nicktaken::   you tried to change nick to one that's in use
+    # :badnick::     you tried to change nick to one that's invalid
+    # :topic::       someone changed the topic of a channel
+    # :topicinfo::   on joining a channel or asking for the topic, tells you
+    #                who set it and when
+    # :names::       server sends list of channel members when you join
+    # :welcome::     server welcome message on connect
+    # :motd::        server message of the day
+    # :privmsg::     privmsg, the core of IRC, a message to you from someone
+    # :public::      optionally instead of getting privmsg you can hook to only
+    #                the public ones...
+    # :msg::         or only the private ones, or both
+    # :kick::        someone got kicked from a channel
+    # :part::        someone left a channel
+    # :quit::        someone quit IRC
+    # :join::        someone joined a channel
+    # :changetopic:: the topic of a channel changed
+    # :invite::      you are invited to a channel
+    # :nick::        someone changed their nick
+    # :mode::        a mode change
+    # :notice::      someone sends you a notice
+    # :unknown::     any other message not handled by the above
     def []=(key, value)
       @handlers[key] = value
     end
@@ -856,7 +866,7 @@ module Irc
     # sending it a hash containing the data from the server
     def process(serverstring)
       data = Hash.new
-      data["SERVERSTRING"] = serverstring
+      data[:serverstring] = serverstring
       
       unless serverstring =~ /^(:(\S+)\s)?(\S+)(\s(.*))?/
              raise "Unparseable Server Message!!!: #{serverstring}"
@@ -865,10 +875,10 @@ module Irc
       prefix, command, params = $2, $3, $5
       
       if prefix != nil
-        data['SOURCE'] = prefix
+        data[:source] = prefix
         if prefix =~ /^(\S+)!(\S+)$/
-          data['SOURCENICK'] = $1
-          data['SOURCEADDRESS'] = $2
+          data[:sourcenick] = $1
+          data[:sourceaddress] = $2
         end
       end
 
@@ -878,31 +888,47 @@ module Irc
       
       case command
       when 'PING'
-        data['PINGID'] = argv[0]
-        handle('PING', data)
+        data[:pingid] = argv[0]
+        handle(:ping, data)
       when /^(\d+)$/           # numeric server message
         num=command.to_i
         case num
+        when RPL_YOURHOST
+          # "Your host is <servername>, running version <ver>"
+          # TODO how standard is this "version <ver>? should i parse it?
+          data[:message] = argv[1]
+          handle(:yourhost, data)
+        when RPL_CREATED
+          # "This server was created <date>"
+          data[:message] = argv[1]
+          handle(:created, data)
+        when RPL_MYINFO
+          # "<servername> <version> <available user modes>
+          # <available channel modes>"
+          data[:servername] = argv[1]
+          data[:version] = argv[2]
+          data[:usermodes] = argv[3]
+          data[:chanmodes] = argv[4]
         when ERR_NICKNAMEINUSE
           # "* <nick> :Nickname is already in use"
-          data['NICK'] = argv[1]
-          data['MESSAGE'] = argv[2]
-          handle('NICKTAKEN', data)
+          data[:nick] = argv[1]
+          data[:message] = argv[2]
+          handle(:nicktaken, data)
         when ERR_ERRONEUSNICKNAME
           # "* <nick> :Erroneous nickname"
-          data['NICK'] = argv[1]
-          data['MESSAGE'] = argv[2]
-          handle('BADNICK', data)
+          data[:nick] = argv[1]
+          data[:message] = argv[2]
+          handle(:badnick, data)
         when RPL_TOPIC
-          data['CHANNEL'] = argv[1]
-          data['TOPIC'] = argv[2]
-          handle('TOPIC', data)
+          data[:channel] = argv[1]
+          data[:topic] = argv[2]
+          handle(:topic, data)
         when RPL_TOPIC_INFO
-          data['NICK'] = argv[0]
-          data['CHANNEL'] = argv[1]
-          data['SOURCE'] = argv[2]
-          data['UNIXTIME'] = argv[3]
-          handle('TOPICINFO', data)
+          data[:nick] = argv[0]
+          data[:channel] = argv[1]
+          data[:source] = argv[2]
+          data[:unixtime] = argv[3]
+          handle(:topicinfo, data)
         when RPL_NAMREPLY
           # "( "=" / "*" / "@" ) <channel>
           # :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
@@ -916,26 +942,77 @@ module Irc
             end
           }
         when RPL_ENDOFNAMES
-          data['CHANNEL'] = argv[1]
-          data['USERS'] = @users
-          handle('NAMES', data)
+          data[:channel] = argv[1]
+          data[:users] = @users
+          handle(:names, data)
           @users = Array.new
+        when RPL_ISUPPORT
+          # "PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
+          # "MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63
+          # TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=#
+          # PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer :are available
+          # on this server"
+          # 
+          argv.each {|a|
+            if a =~ /^(.*)=(.*)$/
+              data[$1.downcase.to_sym] = $2
+            end
+          }
+          handle(:isupport, data)
+        when RPL_LUSERCLIENT
+          # ":There are <integer> users and <integer>
+          # services on <integer> servers"
+          data[:message] = argv[1]
+          handle(:luserclient, data)
+        when RPL_LUSEROP
+          # "<integer> :operator(s) online"
+          data[:ops] = argv[1].to_i
+          handle(:luserop, data)
+        when RPL_LUSERUNKNOWN
+          # "<integer> :unknown connection(s)"
+          data[:unknown] = argv[1].to_i
+          handle(:luserunknown, data)
+        when RPL_LUSERCHANNELS
+          # "<integer> :channels formed"
+          data[:channels] = argv[1].to_i
+          handle(:luserchannels, data)
+        when RPL_LUSERME
+          # ":I have <integer> clients and <integer> servers"
+          data[:message] = argv[1]
+          handle(:luserme, data)
+        when ERR_NOMOTD
+          # ":MOTD File is missing"
+          data[:message] = argv[1]
+          handle(:motd_missing, data)
+        when RPL_LOCALUSERS
+          # ":Current local  users: 3  Max: 4"
+          data[:message] = argv[1]
+          handle(:localusers, data)
+        when RPL_GLOBALUSERS
+          # ":Current global users: 3  Max: 4"
+          data[:message] = argv[1]
+          handle(:globalusers, data)
+        when RPL_STATSCONN
+          # ":Highest connection count: 4 (4 clients) (251 since server was
+          # (re)started)"
+          data[:message] = argv[1]
+          handle(:statsconn, data)
         when RPL_WELCOME
           # "Welcome to the Internet Relay Network
           # <nick>!<user>@<host>"
           case argv[1]
           when /((\S+)!(\S+))/
-            data['NETMASK'] = $1
-            data['NICK'] = $2
-            data['ADDRESS'] = $3
+            data[:netmask] = $1
+            data[:nick] = $2
+            data[:address] = $3
           when /Welcome to the Internet Relay Network\s(\S+)/
-            data['NICK'] = $1
+            data[:nick] = $1
           when /Welcome.*\s+(\S+)$/
-            data['NICK'] = $1
+            data[:nick] = $1
           when /^(\S+)$/
-            data['NICK'] = $1
+            data[:nick] = $1
           end
-          handle('WELCOME', data)
+          handle(:welcome, data)
         when RPL_MOTDSTART
           # "<nick> :- <server> Message of the Day -"
           if argv[1] =~ /^-\s+(\S+)\s/
@@ -948,68 +1025,68 @@ module Irc
             @motd << "\n"
           end
         when RPL_ENDOFMOTD
-          data['MOTD'] = @motd
-          handle('MOTD', data)
+          data[:motd] = @motd
+          handle(:motd, data)
         else
-          handle('UNKNOWN', data)
+          handle(:unknown, data)
         end
       # end of numeric replies
       when 'PRIVMSG'
         # you can either bind to 'PRIVMSG', to get every one and
         # parse it yourself, or you can bind to 'MSG', 'PUBLIC',
         # etc and get it all nicely split up for you.
-        data['TARGET'] = argv[0]
-        data['MESSAGE'] = argv[1]
-        handle('PRIVMSG', data)
+        data[:target] = argv[0]
+        data[:message] = argv[1]
+        handle(:privmsg, data)
         
         # Now we split it
-        if(data['TARGET'] =~ /^(#|&).*/)
-          handle('PUBLIC', data)
+        if(data[:target] =~ /^(#|&).*/)
+          handle(:public, data)
         else
-          handle('MSG', data)
+          handle(:msg, data)
         end
       when 'KICK'
-        data['CHANNEL'] = argv[0]
-        data['TARGET'] = argv[1]
-        data['MESSAGE'] = argv[2]
-        handle('KICK', data)
+        data[:channel] = argv[0]
+        data[:target] = argv[1]
+        data[:message] = argv[2]
+        handle(:kick, data)
       when 'PART'
-        data['CHANNEL'] = argv[0]
-        data['MESSAGE'] = argv[1]
-        handle('PART', data)
+        data[:channel] = argv[0]
+        data[:message] = argv[1]
+        handle(:part, data)
       when 'QUIT'
-        data['MESSAGE'] = argv[0]
-        handle('QUIT', data)
+        data[:message] = argv[0]
+        handle(:quit, data)
       when 'JOIN'
-        data['CHANNEL'] = argv[0]
-        handle('JOIN', data)
+        data[:channel] = argv[0]
+        handle(:join, data)
       when 'TOPIC'
-        data['CHANNEL'] = argv[0]
-        data['TOPIC'] = argv[1]
-        handle('CHANGETOPIC', data)
+        data[:channel] = argv[0]
+        data[:topic] = argv[1]
+        handle(:changetopic, data)
       when 'INVITE'
-        data['TARGET'] = argv[0]
-        data['CHANNEL'] = argv[1]
-        handle('INVITE', data)
+        data[:target] = argv[0]
+        data[:channel] = argv[1]
+        handle(:invite, data)
       when 'NICK'
-        data['NICK'] = argv[0]
-        handle('NICK', data)
+        data[:nick] = argv[0]
+        handle(:nick, data)
       when 'MODE'
-        data['CHANNEL'] = argv[0]
-        data['MODESTRING'] = argv[1]
-        data['TARGETS'] = argv[2]
-        handle('MODE', data)
+        data[:channel] = argv[0]
+        data[:modestring] = argv[1]
+        data[:targets] = argv[2]
+        handle(:mode, data)
       when 'NOTICE'
-        data['TARGET'] = argv[0]
-        data['MESSAGE'] = argv[1]
-        if data['SOURCENICK']
-          handle('NOTICE', data)
+        data[:target] = argv[0]
+        data[:message] = argv[1]
+        if data[:sourcenick]
+          handle(:notice, data)
         else
           # "server notice" (not from user, noone to reply to
-          handle('SNOTICE', data)
+          handle(:snotice, data)
         end
       else
-        handle('UNKNOWN', data)
+        handle(:unknown, data)
       end
     end