]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - lib/rbot/irc.rb
always log to stdout with debug flag
[user/henk/code/ruby/rbot.git] / lib / rbot / irc.rb
index 9a9998e7f391ce6c12a48b2c892d03063bc61c6f..17b7bc3e4b0cee684e9f44a37d1701b10666c744 100644 (file)
@@ -24,6 +24,7 @@ require 'singleton'
 # The following monkeypatch is to fix a bug in Singleton where marshaling would
 # fail when trying to restore a marshaled Singleton due to _load being declared
 # private.
+if RUBY_VERSION < '1.9'
 module ::Singleton
   public :_dump
 end
@@ -33,6 +34,7 @@ class << Singleton
     public :_load
   end
 end
+end
 
 class Object
 
@@ -129,7 +131,7 @@ module Irc
       if self == other
         return true
       else
-        warn "Casemap mismatch (#{self.inspect} != #{other.inspect})"
+        warning "Casemap mismatch (#{self.inspect} != #{other.inspect})"
         return false
       end
     end
@@ -194,6 +196,7 @@ module Irc
           @casemap = nil
         end
       else
+        warning 'casemap fallback to rfc1459 without hints, correct?'
         @casemap = (@casemap || 'rfc1459').to_irc_casemap
       end
     end
@@ -271,7 +274,13 @@ class String
   # This method returns the Irc::Casemap whose name is the receiver
   #
   def to_irc_casemap
-    Irc::Casemap.get(self) rescue raise TypeError, "Unkown Irc::Casemap #{self.inspect}"
+    begin
+      Irc::Casemap.get(self)
+    rescue
+      # raise TypeError, "Unkown Irc::Casemap #{self.inspect}"
+      error "Unkown Irc::Casemap #{self.inspect} requested, defaulting to rfc1459"
+      Irc::Casemap.get('rfc1459')
+    end
   end
 
   # This method returns a string which is the downcased version of the
@@ -538,7 +547,7 @@ class Regexp
     RFC_CHAN = /#{CHAN_FIRST}#{CHAN_ANY}{1,49}|#{CHAN_SAFE}#{CHAN_ANY}{1,44}/
 
     # Nick-matching regexps
-    SPECIAL_CHAR = /[\x5b-\x60\x7b-\x7d]/
+    SPECIAL_CHAR = /[\[-\`\{-\}]/
     NICK_FIRST = /#{SPECIAL_CHAR}|[[:alpha:]]/
     NICK_ANY = /#{SPECIAL_CHAR}|[[:alnum:]]|-/
     GEN_NICK = /#{NICK_FIRST}#{NICK_ANY}+/
@@ -631,6 +640,12 @@ module Irc
     def initialize(str="", opts={})
       # First of all, check for server/casemap option
       #
+      debug 'new netmask "%s" casemap=%s server=%s server#casemap=%s' % [
+        str,
+        (opts[:casemap].class.to_s rescue 'null'),
+        (opts[:server].hostname.to_s rescue 'null'),
+        (opts[:server].casemap.class.to_s rescue 'null')
+      ]
       init_server_or_casemap(opts)
 
       # Now we can see if the given string _str_ is an actual Netmask
@@ -825,7 +840,7 @@ module Irc
         them = cmp.send(component).irc_downcase(casemap)
         if us.has_irc_glob? && them.has_irc_glob?
           next if us == them
-          warn NotImplementedError
+          warning NotImplementedError
           return false
         end
         return false if us.has_irc_glob? && !them.has_irc_glob?
@@ -1321,6 +1336,13 @@ module Irc
   #
   class Channel
 
+    # Return the non-prefixed part of a channel name.
+    # Also works with ## channels found on some networks
+    # (e.g. FreeNode)
+    def self.npname(str)
+      return str.to_s.sub(/^[&#+!]+/,'')
+    end
+
     include ServerOrCasemap
     attr_reader :name, :topic, :mode, :users
     alias :to_s :name
@@ -1365,7 +1387,7 @@ module Irc
     def add_user(user, opts={})
       silent = opts.fetch(:silent, false)
       if has_user?(user)
-        warn "Trying to add user #{user} to channel #{self} again" unless silent
+        warning "Trying to add user #{user} to channel #{self} again" unless silent
       else
         @users << user.to_irc_user(server_and_casemap)
       end
@@ -1379,7 +1401,7 @@ module Irc
     #
     def initialize(name, topic=nil, users=[], opts={})
       raise ArgumentError, "Channel name cannot be empty" if name.to_s.empty?
-      warn "Unknown channel prefix #{name[0].chr}" if name !~ /^[&#+!]/
+      warning "Unknown channel prefix #{name[0,1]}" if name !~ /^[&#+!]/
       raise ArgumentError, "Invalid character in #{name.inspect}" if name =~ /[ \x07,]/
 
       init_server_or_casemap(opts)
@@ -1416,31 +1438,31 @@ module Irc
     # The channel prefix
     #
     def prefix
-      name[0].chr
+      name[0,1]
     end
 
     # A channel is local to a server if it has the '&' prefix
     #
     def local?
-      name[0] == 0x26
+      name[0,1] == '&'
     end
 
     # A channel is modeless if it has the '+' prefix
     #
     def modeless?
-      name[0] == 0x2b
+      name[0,1] == '+'
     end
 
     # A channel is safe if it has the '!' prefix
     #
     def safe?
-      name[0] == 0x21
+      name[0,1] == '!'
     end
 
     # A channel is normal if it has the '#' prefix
     #
     def normal?
-      name[0] == 0x23
+      name[0,1] == '#'
     end
 
     # Create a new mode
@@ -1510,7 +1532,6 @@ module Irc
   class Server
 
     attr_reader :hostname, :version, :usermodes, :chanmodes
-    alias :to_s :hostname
     attr_reader :supports, :capabilities
 
     attr_reader :channels, :users
@@ -1541,6 +1562,10 @@ module Irc
       str << ">"
     end
 
+    def to_s
+      hostname.nil? ? "<no hostname>" : hostname
+    end
+
     # Create a new Server, with all instance variables reset to nil (for
     # scalar variables), empty channel and user lists and @supports
     # initialized to the default values for all known supported features.
@@ -1639,7 +1664,7 @@ module Irc
       if val
         yield if block_given?
       else
-        warn "No #{key.to_s.upcase} value"
+        warning "No #{key.to_s.upcase} value"
       end
     end
 
@@ -1647,7 +1672,7 @@ module Irc
       if val == true or val == false or val.nil?
         yield if block_given?
       else
-        warn "No #{key.to_s.upcase} value must be specified, got #{val}"
+        warning "No #{key.to_s.upcase} value must be specified, got #{val}"
       end
     end
     private :noval_warn, :val_warn
@@ -1659,7 +1684,7 @@ module Irc
     def parse_isupport(line)
       debug "Parsing ISUPPORT #{line.inspect}"
       ar = line.split(' ')
-      reparse = ""
+      reparse = []
       ar.each { |en|
         prekey, val = en.split('=', 2)
         if prekey =~ /^-(.*)/
@@ -1671,7 +1696,15 @@ module Irc
         case key
         when :casemapping
           noval_warn(key, val) {
-            @supports[key] = val.to_irc_casemap
+            if val == 'charset'
+              reparse << "CASEMAPPING=(charset)"
+            else
+              # TODO some servers offer non-standard CASEMAPPINGs in the form
+              # locale.charset[-options], which indicate an extended set of
+              # allowed characters (mostly for nicks). This might be supported
+              # with hooks for the unicode core module
+              @supports[key] = val.to_irc_casemap
+            end
           }
         when :chanlimit, :idchan, :maxlist, :targmax
           noval_warn(key, val) {
@@ -1680,7 +1713,8 @@ module Irc
               k, v = g.split(':')
               @supports[key][k] = v.to_i || 0
               if @supports[key][k] == 0
-                warn "Deleting #{key} limit of 0 for #{k}"
+                # If no argument is given for a particular command (e.g. "WHOIS:"),
+                #  that command does not have a limit on the number of targets.)
                 @supports[key].delete(k)
               end
             }
@@ -1709,7 +1743,7 @@ module Irc
           @supports[key] = val
         when :maxchannels
           noval_warn(key, val) {
-            reparse += "CHANLIMIT=(chantypes):#{val} "
+            reparse << "CHANLIMIT=(chantypes):#{val} "
           }
         when :maxtargets
           noval_warn(key, val) {
@@ -1750,8 +1784,12 @@ module Irc
           @supports[key] =  val.nil? ? true : val
         end
       }
-      reparse.gsub!("(chantypes)",@supports[:chantypes])
-      parse_isupport(reparse) unless reparse.empty?
+      unless reparse.empty?
+        reparse_str = reparse.join(" ")
+        reparse_str.gsub!("(chantypes)",@supports[:chantypes])
+        reparse_str.gsub!("(charset)",@supports[:charset] || 'rfc1459')
+        parse_isupport(reparse_str)
+      end
     end
 
     # Returns the casemap of the server.
@@ -1816,14 +1854,14 @@ module Irc
         return ex
       else
 
-        prefix = name[0].chr
+        prefix = name[0,1]
 
         # Give a warning if the new Channel goes over some server limits.
         #
         # FIXME might need to raise an exception
         #
-        warn "#{self} doesn't support channel prefix #{prefix}" unless @supports[:chantypes].include?(prefix)
-        warn "#{self} doesn't support channel names this long (#{name.length} > #{@supports[:channellen]})" unless name.length <= @supports[:channellen]
+        warning "#{self} doesn't support channel prefix #{prefix}" unless @supports[:chantypes].include?(prefix)
+        warning "#{self} doesn't support channel names this long (#{name.length} > #{@supports[:channellen]})" unless name.length <= @supports[:channellen]
 
         # Next, we check if we hit the limit for channels of type +prefix+
         # if the server supports +chanlimit+
@@ -1835,7 +1873,7 @@ module Irc
             count += 1 if k.include?(n[0])
           }
           # raise IndexError, "Already joined #{count} channels with prefix #{k}" if count == @supports[:chanlimit][k]
-          warn "Already joined #{count}/#{@supports[:chanlimit][k]} channels with prefix #{k}, we may be going over server limits" if count >= @supports[:chanlimit][k]
+          warning "Already joined #{count}/#{@supports[:chanlimit][k]} channels with prefix #{k}, we may be going over server limits" if count >= @supports[:chanlimit][k]
         }
 
         # So far, everything is fine. Now create the actual Channel
@@ -1940,7 +1978,7 @@ module Irc
         end
         return old
       else
-        warn "#{self} doesn't support nicknames this long (#{tmp.nick.length} > #{@supports[:nicklen]})" unless tmp.nick.length <= @supports[:nicklen]
+        warning "#{self} doesn't support nicknames this long (#{tmp.nick.length} > #{@supports[:nicklen]})" unless tmp.nick.length <= @supports[:nicklen]
         @users << tmp
         return @users.last
       end