]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/commitdiff
bunch of changes.
authorTom Gilbert <tom@linuxbrit.co.uk>
Sat, 21 Jan 2006 21:22:41 +0000 (21:22 +0000)
committerTom Gilbert <tom@linuxbrit.co.uk>
Sat, 21 Jan 2006 21:22:41 +0000 (21:22 +0000)
Another of Chris' plugins. A contributed russian.lang from ruskie (honest,
that's his nick!). Some tweaks to error handling. Some modified user/auth
handling (from DevRandom) still a bit more to do on that tho..

bin/rbot
data/rbot/languages/russian.lang [new file with mode: 0644]
data/rbot/plugins/tinyurl.rb [new file with mode: 0644]
lib/rbot/auth.rb
lib/rbot/ircbot.rb
lib/rbot/plugins.rb

index 442617892ba1874a262c62fbd2d1c53b6989fb20..bbe2c9ea5b43bf69c15a3bd2ebcf30d957acb299 100755 (executable)
--- a/bin/rbot
+++ b/bin/rbot
@@ -56,7 +56,8 @@ end
 begin
   require 'rbot/ircbot'
 rescue LoadError => e
-  puts "Error: couldn't find the rbot/ircbot module for loading\n - did you install rbot using setup.rb?"
+  puts "Error: couldn't find the rbot/ircbot module (or one of its dependencies)\n - did you install rbot using setup.rb?"
+  puts e
   exit 2
 end
 
diff --git a/data/rbot/languages/russian.lang b/data/rbot/languages/russian.lang
new file mode 100644 (file)
index 0000000..bd01f0d
--- /dev/null
@@ -0,0 +1,75 @@
+okay:
+         ÈÏÒÏÛÏ 
+         ÐÏÎÑÔÎÏ 
+         ÄÁ ËÏÎÅÞÎÏ 
+         ÒÁÚ ÐÌÀÎÕÔØ 
+         ÚÄÅÌÁÎÏ
+         ÍÏÖÎÏ
+         ÓÅËÕÎÄÏÞËÕ 
+         ÄÁ ÄÁ 
+         ÓÅËÕÎÄÕ 
+         ÂÅÚ ÐÒÏÂÌÅÍ 
+dunno:
+         ÎÅÚÎÁÀ 
+         ÐÏÎÑÔÉÑ ÎÅ ÉÍÅÀ 
+         ÂÅÚ ÐÏÎÑÔÉÊ 
+         Ñ ÎÅ ÍÏÇÕ ×ÁÍ ÐÏÍÏÞØ 
+         ÞÔÏ?
+         ÅÓÌÉ ÂÙ Ñ ÚÎÁÌ 
+         ÎÅ ÓÐÒÁÛÉ×ÁÊ 
+         Á ËÔÏ ÅÇÏ ÚÎÁÅÔ
+         Á ×Ù Õ×ÅÒÅÎÙ?
+         ÄÁ ÎÅÔ!
+dunno_about_X:
+         ÎÅÚÎÁÀ Ï %s
+         ÎÉËÏÇÄÁ ÎÅ ÓÌÙÛÁÌ %s :(
+         %s? Á ÞÔÏ ÜÔÏ ÔÁËÏÅ ?
+         ÎÏ ÞÔÏ ÚÎÁÞÉÔ %s?
+insult:
+         %s: Ñ ×ÁÓ ÎÅÎÁ×ÉÖÕ!
+         %s: :(
+         %s: Õ ×ÁÓ ÎÅÔ ÓÏ×ÅÓÔÉ :(
+         %s: ÕÍÒÉ!
+         %s: Ñ ÂÕÄÕ ÖÁÌÏ×ÁÔÓÑ
+         %s: Á ×Ù ÍÅÎÑ ÏÂÉÄÅÌÉ
+hello:
+         ÐÒÉ×ÅÔ :)
+         ËÁË ÄÅÌÁ :)
+         ÄÒÁÓÔÉ
+         ÜÊ ÔÁÍ!
+         ÂÕÄØ ÚÄÏÒÏ× 
+         ÄÏÂÒÏÅ ÕÔÒÏ 
+         ÄÏÂÒÙÊ ÄÅÎØ 
+         ËÁË ÄÅÌÁ?
+hello_X:
+         ÐÒÉ×ÅÔ %s :)
+         %s: ÄÒÁÓÔÉ
+         %s: ÂÕÄØ ÚÄÏÒÏ× 
+         %s: ÄÏÂÒÏÅ ÕÔÒÏ 
+         hey %s :)
+         %s: ÜÊ ÔÁÍ!
+         %s: ËÁË ÔÙ ÔÁÍ
+         ÒÁÄ ×ÓÔÒÅÞ  %s!
+         %s: ÈÅÊ!
+         ÐÒÉ×ÅÔÓÔ×ÕÀ %s?
+welcome:
+         ÂÅÚ ÐÒÏÂÌÅÍ
+         ×ÓÅÇÄÁ ÒÁÄ
+         ÍÎÅ ÂÙÌÏ ÐÒÉÑÔÎÏ
+         ÒÁÄ ÐÏÍÏÞÉ 
+          :)
+thanks:
+         ÐÁÓÉÂÁ :)
+         ÏÊ ËÁË ÈÏÒÏÛÏ!
+         ÓÐÁÓÉÂÏ :)
+         =D
+         Á ÍÙ ÄÒÕÚØÑ!
+thanks_X:
+         %s: ÓÐÁÓÉÂÏ :)
+         %s: ÏÊ ËÁË ÈÏÒÏÛÏ!!
+         %s: =D
+         %s: ÐÁÓÉÂÁ :)
+         %s: Á ÍÙ ÄÒÕÚØÑ
+quit:
+         ÄÏ Ó×ÉÄÁÎØÑ 
+         ÎÕ Ñ ÐÏÛÅÌ 
diff --git a/data/rbot/plugins/tinyurl.rb b/data/rbot/plugins/tinyurl.rb
new file mode 100644 (file)
index 0000000..b74969d
--- /dev/null
@@ -0,0 +1,39 @@
+require "rubygems"
+require "shorturl"
+
+class TinyURL < Plugin
+  include WWW
+
+  # return a help string when the bot is asked for help on this plugin
+  def help(plugin, topic="")
+    return "tinyurl <your long url>"
+  end
+
+  # reply to a private message that we've registered for
+  def privmsg(m)
+
+    # m.params contains the rest of the message, m.plugin contains the first
+    # word (useful because it's possible to register for multiple commands)
+    unless(m.params)
+      m.reply "incorrect usage. " + help(m.plugin)
+    end
+
+    # TODO: might want to add a check here to validate the url
+    # if they call 'rubyurl help' backwards, don't return a lame link
+
+    if (m.params == "help")
+      m.reply "Try again. Correct usage is: " + help(m.plugin)
+      return false
+    end
+
+    # call the ShortURL library with the value of the url
+    url = ShortURL.shorten(m.params, :tinyurl)
+
+    m.reply "tinyurl: #{url}"
+
+  end
+end
+
+# create an instance of the RubyURL class and register it as a plugin
+tinyurl = TinyURL.new
+tinyurl.register("tinyurl")
index 16f092a5f67227724ee23e8e1394f3dc126ef97f..9868e6eaae0e7496fb75c33cf3ad5482d5b7e06d 100644 (file)
@@ -4,39 +4,45 @@ module Irc
   # netmask::  netmask to test against
   # Compare a netmask with a standard IRC glob, e.g foo!bar@baz.com would
   # match *!*@baz.com, foo!*@*, *!bar@*, etc.
-  def Irc.netmaskmatch(globmask, netmask)
-    regmask = globmask.gsub(/\*/, ".*?")
+  def Irc.netmaskmatch( globmask, netmask )
+    regmask = Regexp.escape( globmask )
+    regmask.gsub!( /\\\*/, '.*' )
     return true if(netmask =~ /#{regmask}/i)
     return false
   end
 
   # check if a string is an actual IRC hostmask
-  def Irc.ismask(mask)
+  def Irc.ismask?(mask)
     mask =~ /^.+!.+@.+$/
   end
 
-  
+  Struct.new( 'UserData', :level, :password, :hostmasks )
+
   # User-level authentication to allow/disallow access to bot commands based
   # on hostmask and userlevel.
   class IrcAuth
-    BotConfig.register BotConfigStringValue.new('auth.password',
-      :default => "rbotauth", :wizard => true,
-      :desc => "Your password for maxing your auth with the bot (used to associate new hostmasks with your owner-status etc)")
-    
+    BotConfig.register BotConfigStringValue.new( 'auth.password',
+      :default => 'rbotauth', :wizard => true,
+      :desc => 'Your password for maxing your auth with the bot (used to associate new hostmasks with your owner-status etc)' )
+    BotConfig.register BotConfigIntegerValue.new( 'auth.default_level',
+      :default => 10, :wizard => true,
+      :desc => 'The default level for new/unknown users' )
+
     # create a new IrcAuth instance.
     # bot:: associated bot class
     def initialize(bot)
       @bot = bot
-      @users = Hash.new(0)
+      @users = Hash.new do
+        Struct::UserData.new(@bot.config['auth.default_level'], '', [])
+      end
       @levels = Hash.new(0)
-      if(File.exist?("#{@bot.botclass}/users.rbot"))
-        IO.foreach("#{@bot.botclass}/users.rbot") do |line|
-          if(line =~ /\s*(\d+)\s*(\S+)/)
-            level = $1.to_i
-            mask = $2
-            @users[mask] = level
-          end
-        end
+      @currentUsers = Hash.new( nil )
+      if( File.exist?( "#{@bot.botclass}/users.yaml" ) )
+        File.open( "#{@bot.botclass}/users.yaml" ) { |file|
+          # work around YAML not maintaining the default proc
+          @loadedusers = YAML::parse(file).transform
+          @users.merge(@loadedusers)
+        }
       end
       if(File.exist?("#{@bot.botclass}/levels.rbot"))
         IO.foreach("#{@bot.botclass}/levels.rbot") do |line|
@@ -51,15 +57,13 @@ module Irc
 
     # save current users and levels to files.
     # levels are written to #{botclass}/levels.rbot
-    # users are written to #{botclass}/users.rbot
+    # users are written to #{botclass}/users.yaml
     def save
       Dir.mkdir("#{@bot.botclass}") if(!File.exist?("#{@bot.botclass}"))
-      File.open("#{@bot.botclass}/users.rbot", "w") do |file|
-        @users.each do |key, value|
-          file.puts "#{value} #{key}"
-        end
+      File.open("#{@bot.botclass}/users.yaml", 'w') do |file|
+        file.puts @users.to_yaml
       end
-      File.open("#{@bot.botclass}/levels.rbot", "w") do |file|
+      File.open("#{@bot.botclass}/levels.rbot", 'w') do |file|
         @levels.each do |key, value|
           file.puts "#{value} #{key}"
         end
@@ -73,30 +77,58 @@ module Irc
     # returns true if user with hostmask +mask+ is permitted to perform
     # +command+ optionally pass tell as the target for the "insufficient auth"
     # message, if the user is not authorised
-    def allow?(command, mask, tell=nil)
-      auth = userlevel(mask)
-      if(auth >= @levels[command])
-        return true
-      else
-        debug "#{mask} is not allowed to perform #{command}"
-        @bot.say tell, "insufficient \"#{command}\" auth (have #{auth}, need #{@levels[command]})" if tell
-        return false
-      end
+    def allow?( command, mask, tell=nil )
+      auth = @users[matchingUser(mask)].level # Directly using @users[] is possible, because UserData has a default setting
+        if( auth >= @levels[command] )
+          return true
+        else
+          debug "#{mask} is not allowed to perform #{command}"
+          @bot.say tell, "insufficient \"#{command}\" auth (have #{auth}, need #{@levels[command]})" if tell
+          return false
+        end
     end
 
     # add user with hostmask matching +mask+ with initial auth level +level+
-    def useradd(mask, level)
-      if(Irc.ismask(mask))
-        @users[mask] = level
-      end
+    def useradd( username, level=@bot.config['auth.default_level'], password='', hostmask='*!*@*' )
+      @users[username] = Struct::UserData.new( level, password, [hostmask] ) if ! @users.has_key? username
     end
-    
+
     # mask:: mask of user to remove
     # remove user with mask +mask+
-    def userdel(mask)
-      if(Irc.ismask(mask))
-        @users.delete(mask)
+    def userdel( username )
+      @users.delete( username ) if @users.has_key? username
+    end
+
+    def usermod( username, item, value=nil )
+      if @users.has_key?( username )
+        case item
+          when 'hostmask'
+            if Irc.ismask?( value )
+              @users[username].hostmasks = [ value ]
+              return true
+            end
+          when '+hostmask'
+            if Irc.ismask?( value )
+              @users[username].hostmasks += [ value ]
+              return true
+            end
+          when '-hostmask'
+            if Irc.ismask?( value )
+              @users[username].hostmasks -= [ value ]
+              return true
+            end
+          when 'password'
+              @users[username].password = value
+              return true
+          when 'level'
+              @users[username].level = value.to_i
+              return true
+          else
+            debug "usermod: Tried to modify unknown item #{item}"
+            @bot.say tell, "Unknown item #{item}" if tell
+        end
       end
+      return false
     end
 
     # command:: command to adjust
@@ -106,30 +138,32 @@ module Irc
       @levels[command] = level
     end
 
-    # specific users.
-    # mask:: mask of user
-    # returns the authlevel of user with mask +mask+
-    # finds the matching user which has the highest authlevel (so you can have
-    # a default level of 5 for *!*@*, and yet still give higher levels to
-    def userlevel(mask)
-      # go through hostmask list, find match with _highest_ level (all users
-      # will match *!*@*)
-      level = 0
-      @users.each {|user,userlevel|
-        if(Irc.netmaskmatch(user, mask))
-          level = userlevel if userlevel > level
+    def matchingUser( mask )
+      currentUser = nil
+      currentLevel = 0
+      @users.each { |user, data| # TODO Will get easier if YPaths are used...
+        if data.level > currentLevel
+          data.hostmasks.each { |hostmask|
+            if Irc.netmaskmatch( hostmask, mask )
+              currentUser = user
+              currentLevel = data.level
+            end
+          }
         end
       }
-      level
+      currentUser
+    end
+
+    def identify( mask, username, password )
+      usermod( username, '+hostmask', mask ) if @users.has_key? username && @users[username].password == password
+      debug "User identified: #{username}"
     end
 
     # return all currently defined commands (for which auth is required) and
     # their required authlevels
     def showlevels
-      reply = "Current levels are:"
-      @levels.sort.each {|a|
-        key = a[0]
-        value = a[1]
+      reply = 'Current levels are:'
+      @levels.sort.each { |key, value|
         reply += " #{key}(#{value})"
       }
       reply
@@ -137,32 +171,46 @@ module Irc
 
     # return all currently defined users and their authlevels
     def showusers
-      reply = "Current users are:"
-      @users.sort.each {|a|
-        key = a[0]
-        value = a[1]
-        reply += " #{key}(#{value})"
+      reply = 'Current users are:'
+      @users.sort.each { |key, value|
+        reply += " #{key}(#{value.level})"
       }
       reply
     end
-    
+
+    def showdetails( username )
+      if @users.has_key? username
+        reply = "#{username}(#{@users[username].level}):"
+        @users[username].hostmasks.each { |hostmask|
+          reply += " #{hostmask}"
+        }
+      end
+      reply
+    end
+
     # module help
-    def help(topic="")
+    def help(topic='')
       case topic
-        when "setlevel"
-          return "setlevel <command> <level> => Sets required level for <command> to <level> (private addressing only)"
-        when "useradd"
-          return "useradd <mask> <level> => Add user <mask> at level <level> (private addressing only)"
-        when "userdel"
-          return "userdel <mask> => Remove user <mask> (private addressing only)"
-        when "auth"
-          return "auth <masterpw> => Recognise your hostmask as bot master (private addressing only)"
-        when "levels"
-          return "levels => list commands and their required levels (private addressing only)"
-        when "users"
-          return "users => list users and their levels (private addressing only)"
+        when 'setlevel'
+          return 'setlevel <command> <level> => Sets required level for <command> to <level> (private addressing only)'
+        when 'useradd'
+          return 'useradd <username> => Add user <mask>, you still need to set him up correctly (private addressing only)'
+        when 'userdel'
+          return 'userdel <username> => Remove user <username> (private addressing only)'
+        when 'usermod'
+          return 'usermod <username> <item> <value> => Modify <username>s settings. Valid <item>s are: hostmask, (+|-)hostmask, password, level (private addressing only)'
+        when 'auth'
+          return 'auth <masterpw> => Create a user with your hostmask and master password as bot master (private addressing only)'
+        when 'levels'
+          return 'levels => list commands and their required levels (private addressing only)'
+        when 'users'
+          return 'users [<username>]=> list users and their levels or details about <username> (private addressing only)'
+        when 'whoami'
+          return 'whoami => Show as whom you are recognized (private addressing only)'
+        when 'identify'
+          return 'identify <username> <password> => Identify your hostmask as belonging to <username> (private addressing only)'
         else
-          return "Auth module (User authentication) topics: setlevel, useradd, userdel, auth, levels, users"
+          return 'Auth module (User authentication) topics: setlevel, useradd, userdel, usermod, auth, levels, users, whoami, identify'
       end
     end
 
@@ -171,31 +219,58 @@ module Irc
      if(m.address? && m.private?)
       case m.message
         when (/^setlevel\s+(\S+)\s+(\d+)$/)
-          if(@bot.auth.allow?("auth", m.source, m.replyto))
-            @bot.auth.setlevel($1, $2.to_i)
+          if( @bot.auth.allow?( 'auth', m.source, m.replyto ) )
+            @bot.auth.setlevel( $1, $2.to_i )
             m.reply "level for #$1 set to #$2"
           end
-        when (/^useradd\s+(\S+)\s+(\d+)/)
-          if(@bot.auth.allow?("auth", m.source, m.replyto))
-            @bot.auth.useradd($1, $2.to_i)
-            m.reply "added user #$1 at level #$2"
+        when( /^useradd\s+(\S+)/ ) # FIXME Needs review!!! (\s+(\S+)(\s+(\S+)(\s+(\S+))?)?)? Should this part be added to make complete useradds possible?
+          if( @bot.auth.allow?( 'auth', m.source, m.replyto ) )
+            @bot.auth.useradd( $1 )
+            m.reply "added user #$1, please set him up correctly"
           end
-        when (/^userdel\s+(\S+)/)
-          if(@bot.auth.allow?("auth", m.source, m.replyto))
-            @bot.auth.userdel($1)
+        when( /^userdel\s+(\S+)/ )
+          if( @bot.auth.allow?( 'auth', m.source, m.replyto ) )
+            @bot.auth.userdel( $1 )
             m.reply "user #$1 is gone"
           end
+        when( /^usermod\s+(\S+)\s+(\S+)\s+(\S+)/ )
+          if( @bot.auth.allow?('auth', m.source, m.replyto ) )
+            if( @bot.auth.usermod( $1, $2, $3 ) )
+              m.reply "Set #$2 of #$1 to #$3"
+            else
+              m.reply "Failed to set #$2 of #$1 to #$3"
+            end
+          end
         when (/^auth\s+(\S+)/)
-          if($1 == @bot.config["auth.password"])
-            @bot.auth.useradd(Regexp.escape(m.source), 1000)
-            m.reply "Identified, security level maxed out"
+          if( $1 == @bot.config['auth.password'] )
+            if ! @users.has_key? 'master'
+              @bot.auth.useradd( 'master', 1000, @bot.config['auth.password'], m.source )
+            else
+              @bot.usermod( 'master', '+hostmask', m.source )
+            end
+            m.reply 'Identified, security level maxed out'
+          else
+            m.reply 'Incorrect password'
+          end
+        when( /^identify\s+(\S+)\s+(\S+)/ )
+          if( @bot.auth.identify( m.source, $1, $2 ) )
+            m.reply "Identified as #$1(#{@users[$1].level($1)}"
+          else
+            m.reply 'Incorrect username/password'
+          end
+        when( 'whoami' )
+          user = @bot.auth.matchingUser( m.source )
+          if user
+            m.reply "I recognize you as #{user}(#{@users[user].level})"
           else
-            m.reply "incorrect password"
+            m.reply 'You don\'t belong to any user.'
           end
-        when ("levels")
-          m.reply @bot.auth.showlevels if(@bot.auth.allow?("config", m.source, m.replyto))
-        when ("users")
-          m.reply @bot.auth.showusers if(@bot.auth.allow?("config", m.source, m.replyto))
+        when( /^users\s+(\S+)/ )
+          m.reply @bot.auth.showdetails( $1 ) if( @bot.auth.allow?( 'auth', m.source, m.replyto ) )
+        when ( 'levels' )
+          m.reply @bot.auth.showlevels if( @bot.auth.allow?( 'config', m.source, m.replyto ) )
+        when ( 'users' )
+          m.reply @bot.auth.showusers if( @bot.auth.allow?( 'users', m.source, m.replyto ) )
       end
      end
     end
index 271d0d70ea358d9590872fed932c377bfa37b119..435c6284945896d032d0b7bd6abe9f9c7d13980e 100644 (file)
@@ -329,8 +329,8 @@ class IrcBot
   def mainloop
     while true
       begin
-      connect
-      @timer.start
+        connect
+        @timer.start
       
         while true
           if @socket.select
index 893bb4142650da70c11f6f3137db7314a8c6e9d3..f45e44f48d97bda5669ac2d718547785c20493ba 100644 (file)
@@ -200,7 +200,8 @@ module Plugins
               debug "loading plugin #{tmpfilename}"
               plugin_module.module_eval(plugin_string)
               processed << file
-            rescue TimeoutError, StandardError, NameError, LoadError, SyntaxError => err
+            rescue Exception => err
+              # rescue TimeoutError, StandardError, NameError, LoadError, SyntaxError => err
               puts "warning: plugin #{tmpfilename} load failed: " + err
               puts err.backtrace.join("\n")
             end
@@ -250,7 +251,8 @@ module Plugins
         if(@@plugins.has_key?(key))
           begin
             return @@plugins[key].help(key, params)
-          rescue TimeoutError, StandardError, NameError, SyntaxError => err
+          rescue Exception => err
+          #rescue TimeoutError, StandardError, NameError, SyntaxError => err
             puts "plugin #{@@plugins[key].name} help() failed: " + err
             puts err.backtrace.join("\n")
           end
@@ -267,7 +269,8 @@ module Plugins
         if(p.respond_to? method)
           begin
             p.send method, *args
-          rescue TimeoutError, StandardError, NameError, SyntaxError => err
+          rescue Exception => err
+            #rescue TimeoutError, StandardError, NameError, SyntaxError => err
             puts "plugin #{p.name} #{method}() failed: " + err
             puts err.backtrace.join("\n")
           end
@@ -284,7 +287,8 @@ module Plugins
           @@bot.auth.allow?(m.plugin, m.source, m.replyto))
         begin
           @@plugins[m.plugin].privmsg(m)
-        rescue TimeoutError, StandardError, NameError, SyntaxError => err
+        rescue Exception => err
+          #rescue TimeoutError, StandardError, NameError, SyntaxError => err
           puts "plugin #{@@plugins[m.plugin].name} privmsg() failed: " + err
           puts err.backtrace.join("\n")
         end