]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - lib/rbot/rfc2812.rb
* make the daemonization thing to suck less (wrt standard io channels)
[user/henk/code/ruby/rbot.git] / lib / rbot / rfc2812.rb
index 9de781a8276845763e8b3a311d041ff7a686961b..ab9d28565a4306caaadb4d54bd39fc32c8ea15e2 100644 (file)
@@ -4,7 +4,7 @@
 # :title: RFC 2821 Client Protocol module
 #
 # This module defines the Irc::Client class, a class that can handle and
-# dispatch messages based on RFC 2821i (Internet Relay Chat: Client Protocol)
+# dispatch messages based on RFC 2821 (Internet Relay Chat: Client Protocol)
 
 module Irc
   # - The server sends Replies 001 to 004 to a user upon
@@ -954,7 +954,7 @@ module Irc
     # Create a new Client instance
     def initialize
       @server = Server.new         # The Server
-      @user = @server.user("")     # The User representing the client on this Server
+      @user = @server.user("*!*@*")     # The User representing the client on this Server
 
       @handlers = Hash.new
 
@@ -966,7 +966,7 @@ module Irc
     # Clear the server and reset the user
     def reset
       @server.clear
-      @user = @server.user("")
+      @user = @server.user("*!*@*")
     end
 
     # key::   server event to handle
@@ -1069,13 +1069,14 @@ module Irc
         num=command.to_i
         case num
         when RPL_WELCOME
+          data[:message] = argv[1]
           # "Welcome to the Internet Relay Network
           # <nick>!<user>@<host>"
           if not_us
             warning "Server thinks client (#{@user.inspect}) has a different nick"
             @user.nick = data[:target]
           end
-          if argv[1] =~ /([^@!\s]+)(?:!([^@!\s]+?))?@(\S+)/
+          if data[:message] =~ /([^@!\s]+)(?:!([^@!\s]+?))?@(\S+)/
             nick = $1
             user = $2
             host = $3
@@ -1178,8 +1179,7 @@ module Irc
             chan.add_user(u, :silent => true)
             debug "Adding user #{u}"
             if ar[1]
-              m = @server.supports[:prefix][:prefixes].index(ar[1].to_sym)
-              ms = @server.supports[:prefix][:modes][m]
+              ms = @server.mode_for_prefix(ar[1].to_sym)
               debug "\twith mode #{ar[1]} (#{ms})"
               chan.mode[ms].set(u)
             end
@@ -1407,18 +1407,40 @@ module Irc
         # be able to consume parameters for all
         # but Type D modes
 
-        data[:channel] = @server.user_or_channel(argv[0])
+        data[:target] = @server.user_or_channel(argv[0])
         data[:modestring] = argv[1..-1].join(" ")
-        case data[:channel]
+        # data[:modes] is an array where each element
+        # is an array with two elements, the first of which
+        # is either :set or :reset, and the second symbol
+        # is the mode letter. An optional third element
+        # is present e.g. for channel modes that need
+        # a parameter
+        data[:modes] = []
+        case data[:target]
         when User
-          # TODO
+          # User modes aren't currently handled internally,
+          # but we still parse them and delegate to the client
           warning "Unhandled user mode message '#{serverstring}'"
+          argv[1..-1].each { |arg|
+            setting = arg[0].chr
+            if "+-".include?(setting)
+              setting = setting == "+" ? :set : :reset
+              arg[1..-1].each_byte { |b|
+                m = b.chr.intern
+                data[:modes] << [setting, m]
+              }
+            else
+              # Although typically User modes don't take an argument,
+              # this is not true for all modes on all servers. Since
+              # we have no knowledge of which modes take parameters
+              # and which don't we just assign it to the last
+              # mode. This is not going to do strange things often,
+              # as usually User modes are only set one at a time
+              warning "Unhandled user mode parameter #{arg} found"
+              data[:modes].last << arg
+            end
+          }
         else
-          # data[:modes] is an array where each element
-          # is either a flag which doesn't need parameters
-          # or an array with a flag which needs parameters
-          # and the corresponding parameter
-          data[:modes] = []
           # array of indices in data[:modes] where parameters
           # are needed
           who_wants_params = []
@@ -1426,26 +1448,22 @@ module Irc
           argv[1..-1].each { |arg|
             setting = arg[0].chr
             if "+-".include?(setting)
+              setting = setting == "+" ? :set : :reset
               arg[1..-1].each_byte { |b|
-                m = b.chr
-                case m.to_sym
+                m = b.chr.intern
+                data[:modes] << [setting, m]
+                case m
                 when *@server.supports[:chanmodes][:typea]
-                  data[:modes] << [setting + m]
                   who_wants_params << data[:modes].length - 1
                 when *@server.supports[:chanmodes][:typeb]
-                  data[:modes] << [setting + m]
                   who_wants_params << data[:modes].length - 1
                 when *@server.supports[:chanmodes][:typec]
-                  if setting == "+"
-                    data[:modes] << [setting + m]
+                  if setting == :set
                     who_wants_params << data[:modes].length - 1
-                  else
-                    data[:modes] << setting + m
                   end
                 when *@server.supports[:chanmodes][:typed]
-                  data[:modes] << setting + m
+                  # Nothing to do
                 when *@server.supports[:prefix][:modes]
-                  data[:modes] << [setting + m]
                   who_wants_params << data[:modes].length - 1
                 else
                   warning "Unknown mode #{m} in #{serverstring.inspect}"
@@ -1460,21 +1478,16 @@ module Irc
               data[:modes][idx] << arg
             end
           }
-        end
 
-        data[:modes].each { |mode|
-          case mode
-          when Array
-            set = mode[0][0].chr == "+" ? :set : :reset
-            key = mode[0][1].chr.to_sym
-            val = mode[1]
-            data[:channel].mode[key].send(set, val)
-          else
-            set = mode[0].chr == "+" ? :set : :reset
-            key = mode[1].chr.to_sym
-            data[:channel].mode[key].send(set)
-          end
-        } if data[:modes]
+          data[:modes].each { |mode|
+            set, key, val = mode
+            if val
+              data[:target].mode[key].send(set, val)
+            else
+              data[:target].mode[key].send(set)
+            end
+          }
+        end
 
         handle(:mode, data)
       else