From 6bf3094ac4ad043f00a3ef8cc2af48a8c23d114a Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 3 Aug 2006 14:06:15 +0000 Subject: Lots of fixes all around, in preparation for the new auth coremodule --- lib/rbot/botuser.rb | 297 ++++++++++++++++------------------------------ lib/rbot/core/config.rb | 8 +- lib/rbot/irc.rb | 22 ++-- lib/rbot/ircbot.rb | 73 ++++++------ lib/rbot/messagemapper.rb | 13 +- lib/rbot/plugins.rb | 80 ++++++------- lib/rbot/registry.rb | 2 + lib/rbot/rfc2812.rb | 5 +- 8 files changed, 210 insertions(+), 290 deletions(-) (limited to 'lib') diff --git a/lib/rbot/botuser.rb b/lib/rbot/botuser.rb index 6c84a93b..ea47fcbd 100644 --- a/lib/rbot/botuser.rb +++ b/lib/rbot/botuser.rb @@ -7,164 +7,6 @@ # Copyright:: Copyright (c) 2006 Giuseppe Bilotta # License:: GPLv2 -#-- -##### -#### -### Discussion on IRC on how to implement it -## -# -# a. do we want user groups together with users? -# hmm -# let me think about it -# generally I would say: as simple as possible while keeping it as flexible as need be -# I think we can put user groups in place afterwards if we build the structure right -# prolly, yes -# so -# each plugin registers a name -# so rather than auth level we have +name -name -# yes -# much better -# the default is +name for every plugin, except when the plugin tells otherwise -# although.. -# if I only want to allow you access to one plugin -# I have lots of typing to do -# nope -# we allow things like -* -# ok -# and + has precedence -# hm no, not good either -# because we want bot -* +onething and +* -onething to work -# but then: one plugin currently can have several levels, no? -# of course -# commandedit, commanddel, commandfoo -# name.command ? -# yep -# (then you can't have dots in commands -# maybe name:command -# or name::comand -# like a namespace -# ehehehe yeah I like it :) -# tel -# brb -# usermod setcaps eean -* -# usermod setcaps eean +quiz::edit -# great -# or even -# auth eean -*, +quiz::edit -# awesome -# auth eean -*, +quiz::edit, +command, -command::del -# yes -# you know, the default should be -* -# because -# in the time between adding the user and changing auth -# it's insecure -# user could do havoc -# useradd eean, then eean does "~quit", before I change auth -# nope -# perhaps we should allow combining useradd with auth -# the default should be +* -important stuff -# ok -# how to specify channel stuff? -# for one, when you issue the command on the channel itself -# then it's channel relative -# perhaps -# or -# yes but I was thinking more about the syntax -# auth eean #rbot -quiz -# hm -# or maybe: treat channels like users: auth #rbot -quiz -# would shut up quiz in #rbot -# hm -# heh -# auth * #rbot -quiz -# not sure I'm making sense here ;) -# I think syntax should be auth [usermask] [channelmask] [modes] -# yes -# modes separated by comma? -# where channelmask is implied to be * -# no we can have it spacesplit -# great -# ok -# modes are detected by +- -# so you can do something like auth markey #rbot -quiz #amarok -chuck -# also I like "auth" a lot more than "usermod foo" -# yep -# I don't understand why the 'mod' -# we could have all auth commands start with use -# user -# user add -# user list -# user del -# yes -# user auth -# hm -# and maybe auth as a synonym for user auth -# this is also uncomfortable: usermod wants the full user mask -# you have to copy/paste it -# no -# can't you use *? -# sorry not sure -# but this shows, it's not inuitive -# I've read the docs -# but didn't know how to use it really -# markey!*@* -# that's not very intuitive -# we could use nick as a synonym for nick!*@* if it's too much for you :D -# usermod markey foo should suffice -# rememember: you're a hacker. when rbot gets many new users, they will often be noobs -# gotta make things simple to use -# but the hostmask is only needed for the user creation -# really? then forget what I said, sorry -# I think so -# ,help auth -# Auth module (User authentication) topics: setlevel, useradd, userdel, usermod, auth, levels, users, whoami, identify -# ,help usermod -# no help for topic usermod -# ,help auth usermod -# usermod => Modify s settings. Valid s are: hostmask, (+|-)hostmask, password, level (private addressing only) -# see? it's username, not nick :D -# btw, help usermod should also work -# ,help auth useradd -# useradd => Add user , you still need to set him up correctly (private addressing only) -# instead of help auth usermode -# when it's not ambiguous -# and the help for useradd is wrong -# for the website, we could make a logo contest :) the current logo looks like giblet made it in 5 minutes ;) -# ah well, for 1.0 maybe -# so a user on rbot is given by -# username, password, hostmasks, permissions -# yup -# the default permission is +* -importantstuff -# how defines importantstuff? -# you mean like core and auth? -# yes -# ok -# but we can decide about this :) -# some plugins are dangerous by default -# like command plugin -# you can do all sorts of nasty shit with it -# then command plugin will do something like: command.defaultperm("-command") -# yes, good point -# this is then added to the default permissions (user * channel *) -# when checking for auth, we go like this: -# hm -# check user * channel * -# then user name channel * -# then user * channel name -# then user name channel name -# for each of these combinations we match against * first, then against command, and then against command::subcommand -# yup -# setting or resetting it depending on wether it's + or - -# the final result gives us the permission -# implementation detail -# username and passwords are strings -# (I might rename the command plugin, the name is somewhat confusing) -# yeah -# hostmasks are hostmasks -# also I'm pondering to restrict it more: disallow access to @bot -# permissions are in the form [ [channel, {command => bool, ...}] ...] -#++ - require 'singleton' module Irc @@ -186,6 +28,13 @@ module Irc # module Auth + BotConfig.register BotConfigStringValue.new( 'auth.password', + :default => 'rbotauth', :wizard => true, + :desc => 'Password for the bot owner' ) + # BotConfig.register BotConfigIntegerValue.new( 'auth.default_level', + # :default => 10, :wizard => true, + # :desc => 'The default level for new/unknown users' ) + # Generate a random password of length _l_ # def random_password(l=8) @@ -234,6 +83,7 @@ module Irc @command = path.last debug "Created command #{@command.inspect} with path #{@path.join(', ')}" end + end # This method raises a TypeError if _user_ is not of class User @@ -291,6 +141,7 @@ module Irc } return allow end + end @@ -311,6 +162,51 @@ module Irc @perm = {} end + # Inspection + def inspect + str = "<#{self.class}:#{'0x%08x' % self.object_id}:" + str << " @username=#{@username.inspect}" + str << " @netmasks=#{@netmasks.inspect}" + str << " @perm=#{@perm.inspect}" + str + end + + # Convert into a hash + def to_hash + { + :username => @username, + :password => @password, + :netmasks => @netmasks, + :perm => @perm + } + end + + # Restore from hash + def from_hash(h) + @username = h[:username] if h.has_key?(:username) + @password = h[:password] if h.has_key?(:password) + @netmasks = h[:netmasks] if h.has_key?(:netmasks) + @perm = h[:perm] if h.has_key?(:perm) + end + + # This method sets the password if the proposed new password + # is valid + def password=(pwd=nil) + if pwd + begin + raise InvalidPassword, "#{pwd} contains invalid characters" if pwd !~ /^[A-Za-z0-9]+$/ + raise InvalidPassword, "#{pwd} too short" if pwd.length < 4 + @password = pwd + rescue InvalidPassword => e + raise e + rescue => e + raise InvalidPassword, "Exception #{e.inspect} while checking #{pwd}" + end + else + reset_password + end + end + # Resets the password by creating a new onw def reset_password @password = random_password @@ -358,7 +254,7 @@ module Irc when Netmask @netmasks << mask else - @netmasks << Netmask(mask) + @netmasks << Netmask.new(mask) end end @@ -369,7 +265,7 @@ module Irc when Netmask m = mask else - m << Netmask(mask) + m << Netmask.new(mask) end @netmasks.delete(m) end @@ -399,6 +295,7 @@ module Irc def login(user, password) if password == @password add_netmask(user) unless knows?(user) + debug "#{user} logged in as #{self.inspect}" return true else return false @@ -417,23 +314,6 @@ module Irc return name.to_s.chomp.downcase.gsub(/[^a-z0-9]/,"_") end - # This method sets the password if the proposed new password - # is valid - def password=(pwd=nil) - if pwd - begin - raise InvalidPassword, "#{pwd} contains invalid characters" if pwd !~ /^[A-Za-z0-9]+$/ - raise InvalidPassword, "#{pwd} too short" if pwd.length < 4 - @password = pwd - rescue InvalidPassword => e - raise e - rescue => e - raise InvalidPassword, "Exception #{e.inspect} while checking #{pwd}" - end - else - reset_password - end - end end @@ -441,12 +321,15 @@ module Irc # identified with the bot # class DefaultBotUserClass < BotUser + + private :login, :add_netmask, :delete_netmask + include Singleton + def initialize super("everyone") @default_perm = PermissionSet.new end - private :login, :add_netmask, :delete_netmask # Sets the default permission for the default user (i.e. the ones # set by the BotModule writers) on all channels @@ -480,6 +363,7 @@ module Irc end return allow end + end # Returns the only instance of DefaultBotUserClass @@ -491,7 +375,9 @@ module Irc # This is the BotOwner: he can do everything # class BotOwnerClass < BotUser + include Singleton + def initialize super("owner") end @@ -499,6 +385,7 @@ module Irc def permit?(cmd, chan=nil) return true end + end # Returns the only instance of BotOwnerClass @@ -512,6 +399,7 @@ module Irc # everything # class AuthManagerClass + include Singleton attr_reader :everyone @@ -539,6 +427,18 @@ module Irc @has_changes = false end + def set_changed + @has_changes = true + end + + def reset_changed + @has_changes = false + end + + def changed? + @has_changes + end + # resets the hashes def reset_hashes @botusers = Hash.new @@ -548,23 +448,24 @@ module Irc } end - # load botlist from userfile - def load_merge(filename=nil) - # TODO - raise NotImplementedError - @has_changes = true - end - - def load(filename=nil) + def load_array(ary, forced) + raise "Won't load with unsaved changes" if @has_changes and not forced reset_hashes - load_merge(filename) + ary.each { |x| + raise TypeError, "#{x} should be a Hash" unless x.class <= Hash + u = x[:username] + unless include?(u) + create_botuser(u) + end + get_botuser(u).from_hash(x) + } + @has_changes=false end - # save botlist to userfile - def save(filename=nil) - return unless @has_changes - # TODO - raise NotImplementedError + def save_array + @allbotusers.values.map { |x| + x.to_hash + } end # checks if we know about a certain BotUser username @@ -589,6 +490,11 @@ module Irc @allbotusers[k] = bu end + # returns the botuser with name _name_ + def get_botuser(name) + @allbotusers.fetch(BotUser.sanitize_username(name).to_sym) + end + # Logs Irc::User _ircuser_ in to BotUser _botusername_ with password _pwd_ # # raises an error if _botusername_ is not a known BotUser username @@ -597,7 +503,7 @@ module Irc # def login(ircuser, botusername, pwd, bymask = false) Irc::error_if_not_user(ircuser) - n = BotUser.sanitize_username(name) + n = BotUser.sanitize_username(botusername) k = n.to_sym raise "No such BotUser #{n}" unless include?(k) if @botusers.has_key?(ircuser) @@ -605,7 +511,7 @@ module Irc # @botusers[ircuser].logout(ircuser) end bu = @allbotusers[k] - if bymask && bu.knows?(user) + if bymask && bu.knows?(ircuser) @botusers[ircuser] = bu return true elsif bu.login(ircuser, pwd) @@ -656,6 +562,7 @@ module Irc def allow?(cmdtxt, user, chan=nil) permit?(user, cmdtxt, chan) end + end # Returns the only instance of AuthManagerClass @@ -663,5 +570,7 @@ module Irc def Auth.authmanager return AuthManagerClass.instance end + end + end diff --git a/lib/rbot/core/config.rb b/lib/rbot/core/config.rb index 7eda780f..3099a00a 100644 --- a/lib/rbot/core/config.rb +++ b/lib/rbot/core/config.rb @@ -4,6 +4,10 @@ class ConfigModule < CoreBotModule + def save + @bot.config.save + end + def handle_list(m, params) modules = [] if params[:module] @@ -18,7 +22,7 @@ class ConfigModule < CoreBotModule m.reply modules.join(", ") end else - @bot.configitems.each_key do |key| + @bot.config.items.each_key do |key| name = key.to_s.split('.').first modules.push name unless modules.include?(name) end @@ -132,7 +136,7 @@ class ConfigModule < CoreBotModule @bot.save m.reply "rescanning ..." @bot.rescan - m.reply "done. #{@plugins.status(true)}" + m.reply "done. #{@bot.plugins.status(true)}" end def bot_nick(m, param) diff --git a/lib/rbot/irc.rb b/lib/rbot/irc.rb index ffc2be71..74db8e85 100644 --- a/lib/rbot/irc.rb +++ b/lib/rbot/irc.rb @@ -373,12 +373,12 @@ module Irc # globs is not handled yet. # def matches?(arg) - cmp = Netmask(arg) + cmp = Netmask.new(arg) raise TypeError, "#{arg} and #{self} have different casemaps" if @casemap != cmp.casemap raise TypeError, "#{arg} is not a valid Netmask" unless cmp.class <= Netmask [:nick, :user, :host].each { |component| - us = self.send(:component) - them = cmp.send(:component) + us = self.send(component) + them = cmp.send(component) raise NotImplementedError if us.has_irc_glob? && them.has_irc_glob? return false if us.has_irc_glob? && !them.has_irc_glob? return false unless us =~ them.to_irc_regexp @@ -389,7 +389,7 @@ module Irc # Case equality. Checks if arg matches self # def ===(arg) - Netmask(arg).matches?(self) + Netmask.new(arg).matches?(self) end end @@ -951,7 +951,7 @@ module Irc # a name of # def user_or_channel?(name) - if supports[:chantypes].include?(name[0].chr) + if supports[:chantypes].include?(name[0]) return Channel else return User @@ -961,7 +961,7 @@ module Irc # Returns the actual User or Channel object matching _name_ # def user_or_channel(name) - if supports[:chantypes].include?(name[0].chr) + if supports[:chantypes].include?(name[0]) return channel(name) else return user(name) @@ -1132,15 +1132,7 @@ module Irc # new_user(_str_, +false+) # def user(str) - # This method can get called before server has been initialized (e.g. on - # Freenode there is a NOTICE from AUTH on connect). In this case we just - # return the string - # - if defined?(@supports) - new_user(str, false) - else - str - end + new_user(str, false) end # Remove User _someuser_ from the list of Users. diff --git a/lib/rbot/ircbot.rb b/lib/rbot/ircbot.rb index f765668d..df0659b5 100644 --- a/lib/rbot/ircbot.rb +++ b/lib/rbot/ircbot.rb @@ -104,17 +104,13 @@ class IrcBot # by default) attr_reader :timer + # synchronize with this mutex while touching permanent data files: + # saving, flushing, cleaning up ... + attr_reader :save_mutex + # bot's Language data attr_reader :lang - # server the bot is connected to - # TODO multiserver - attr_reader :server - - # the client personality of the bot - # TODO multiserver - attr_reader :client - # bot's irc socket # TODO multiserver attr_reader :socket @@ -131,8 +127,17 @@ class IrcBot # proxies etc as defined by the bot configuration/environment attr_reader :httputil + # server we are connected to + # TODO multiserver + def server + @client.server + end + # bot User in the client/server connection - attr_reader :myself + # TODO multiserver + def myself + @client.client + end # bot User in the client/server connection def nick @@ -335,6 +340,7 @@ class IrcBot @registry = BotRegistry.new self @timer = Timer::Timer.new(1.0) # only need per-second granularity + @save_mutex = Mutex.new @timer.add(@config['core.save_every']) { save } if @config['core.save_every'] @logs = Hash.new @@ -356,6 +362,7 @@ class IrcBot exit 2 end @auth.everyone.set_default_permission("*", true) + @auth.botowner.password= @config['auth.password'] Dir.mkdir("#{botclass}/plugins") unless File.exist?("#{botclass}/plugins") @plugins = Plugins::pluginmanager @@ -367,9 +374,7 @@ class IrcBot @socket = IrcSocket.new(@config['server.name'], @config['server.port'], @config['server.bindhost'], @config['server.sendq_delay'], @config['server.sendq_burst']) @client = IrcClient.new - @server = @client.server - @myself = @client.client - @myself.nick = @config['irc.nick'] + myself.nick = @config['irc.nick'] # Channels where we are quiet # It's nil when we are not quiet, an empty list when we are quiet @@ -394,18 +399,20 @@ class IrcBot # TODO this needs to go into rfc2812.rb # Since capabs are two-steps processes, server.supports[:capab] # should be a three-state: nil, [], [....] - sendq "CAPAB IDENTIFY-MSG" if @server.supports[:capab] + sendq "CAPAB IDENTIFY-MSG" if server.supports[:capab] } @client[:datastr] = proc { |data| # TODO this needs to go into rfc2812.rb if data[:text] == "IDENTIFY-MSG" - @server.capabilities["identify-msg".to_sym] = true + server.capabilities["identify-msg".to_sym] = true else debug "Not handling RPL_DATASTR #{data[:servermessage]}" end } @client[:privmsg] = proc { |data| - m = PrivMessage.new(self, @server, data[:source], data[:target], data[:message]) + m = PrivMessage.new(self, server, data[:source], data[:target], data[:message]) + debug "Message target is #{data[:target].inspect}" + debug "Bot is #{myself.inspect}" # TODO use the new Netmask class # @config['irc.ignore_users'].each { |mask| return if Irc.netmaskmatch(mask,m.source) } @@ -416,7 +423,7 @@ class IrcBot @plugins.privmsg(m) if m.address? } @client[:notice] = proc { |data| - message = NoticeMessage.new(self, @server, data[:source], data[:target], data[:message]) + message = NoticeMessage.new(self, server, data[:source], data[:target], data[:message]) # pass it off to plugins that want to hear everything @plugins.delegate "listen", message } @@ -442,7 +449,7 @@ class IrcBot source = data[:source] old = data[:oldnick] new = data[:newnick] - m = NickMessage.new(self, @server, source, old, new) + m = NickMessage.new(self, server, source, old, new) if source == myself debug "my nick is now #{new}" end @@ -455,7 +462,7 @@ class IrcBot @client[:quit] = proc {|data| source = data[:source] message = data[:message] - m = QuitMessage.new(self, @server, source, source, message) + m = QuitMessage.new(self, server, source, source, message) data[:was_on].each { |ch| irclog "@ Quit: #{source}: #{message}", ch } @@ -466,21 +473,21 @@ class IrcBot irclog "@ Mode #{data[:modestring]} by #{data[:source]}", data[:channel] } @client[:join] = proc {|data| - m = JoinMessage.new(self, @server, data[:source], data[:channel], data[:message]) + m = JoinMessage.new(self, server, data[:source], data[:channel], data[:message]) irclogjoin(m) @plugins.delegate("listen", m) @plugins.delegate("join", m) } @client[:part] = proc {|data| - m = PartMessage.new(self, @server, data[:source], data[:channel], data[:message]) + m = PartMessage.new(self, server, data[:source], data[:channel], data[:message]) irclogpart(m) @plugins.delegate("listen", m) @plugins.delegate("part", m) } @client[:kick] = proc {|data| - m = KickMessage.new(self, @server, data[:source], data[:target], data[:channel],data[:message]) + m = KickMessage.new(self, server, data[:source], data[:target], data[:channel],data[:message]) irclogkick(m) @plugins.delegate("listen", m) @@ -492,7 +499,7 @@ class IrcBot end } @client[:changetopic] = proc {|data| - m = TopicMessage.new(self, @server, data[:source], data[:channel], data[:topic]) + m = TopicMessage.new(self, server, data[:source], data[:channel], data[:topic]) irclogtopic(m) @plugins.delegate("listen", m) @@ -505,7 +512,7 @@ class IrcBot channel = data[:channel] topic = channel.topic irclog "@ Topic set by #{topic.set_by} on #{topic.set_on}", channel - m = TopicMessage.new(self, @server, data[:source], channel, topic) + m = TopicMessage.new(self, server, data[:source], channel, topic) @plugins.delegate("listen", m) @plugins.delegate("topic", m) @@ -623,7 +630,7 @@ class IrcBot end stop_server_pings - @server.clear + server.clear if @socket.connected? @socket.clearq @socket.shutdown @@ -798,7 +805,7 @@ class IrcBot @socket.shutdown end debug "Logging quits" - @server.channels.each { |ch| + server.channels.each { |ch| irclog "@ quit (#{message})", ch } debug "Saving" @@ -834,11 +841,13 @@ class IrcBot # call the save method for bot's config, keywords, auth and all plugins def save - @config.save - # @keywords.save - @auth.save - @plugins.save - DBTree.cleanup_logs + @save_mutex.synchronize do + # @config.save + # @keywords.save + # @auth.save + @plugins.save + DBTree.cleanup_logs + end end # call the rescan method for the bot's lang, keywords and all plugins @@ -965,8 +974,6 @@ class IrcBot case where when Channel irclog "-=#{myself}=- #{message}", where - when User - irclog "[-=#{where}=-] #{message}", $1 else irclog "[-=#{where}=-] #{message}", where end @@ -974,8 +981,6 @@ class IrcBot case where when Channel irclog "<#{myself}> #{message}", where - when User - irclog "[msg(#{where})] #{message}", $1 else irclog "[msg(#{where})] #{message}", where end diff --git a/lib/rbot/messagemapper.rb b/lib/rbot/messagemapper.rb index 2214780b..193804fe 100644 --- a/lib/rbot/messagemapper.rb +++ b/lib/rbot/messagemapper.rb @@ -178,16 +178,23 @@ module Irc else raise ArgumentError, "Can't find auth base in #{botmodule.inspect}" end - post = items.reject{ |x| + words = items.reject{ |x| x == pre || x.kind_of?(Symbol) } - if post.empty? + if words.empty? post = nil else - post = post.first + post = words.first end if hash.has_key?(:auth_path) extra = hash[:auth_path] + if extra.sub!(/^:/, "") + pre += post + post = nil + end + if extra.sub!(/:$/, "") + post = [post,words[1]].compact.join("::") if words.length > 1 + end pre = nil if extra.sub!(/^!/, "") post = nil if extra.sub!(/!$/, "") else diff --git a/lib/rbot/plugins.rb b/lib/rbot/plugins.rb index f8eddd6e..43793e99 100644 --- a/lib/rbot/plugins.rb +++ b/lib/rbot/plugins.rb @@ -2,7 +2,7 @@ require 'singleton' module Irc BotConfig.register BotConfigArrayValue.new('plugins.blacklist', - :default => [], :wizard => false, :requires_restart => true, + :default => [], :wizard => false, :requires_rescan => true, :desc => "Plugins that should not be loaded") module Plugins require 'rbot/messagemapper' @@ -417,7 +417,9 @@ module Plugins # call the cleanup method for each active plugin def cleanup - delegate 'cleanup' + @bot.save_mutex.synchronize do + delegate 'cleanup' + end reset_botmodule_lists end @@ -540,6 +542,7 @@ module Plugins # debug "#{p.botmodule_class} #{p.name} responds" p.send method, *args rescue Exception => err + raise if err.class <= SystemExit error report_error("#{p.botmodule_class} #{p.name} #{method}() failed:", err) raise if err.class <= BDB::Fatal end @@ -554,49 +557,46 @@ module Plugins def privmsg(m) # debug "Delegating privmsg #{m.message.inspect} from #{m.source} to #{m.replyto} with pluginkey #{m.plugin.inspect}" return unless m.plugin - begin - [core_commands, plugin_commands].each { |pl| - # We do it this way to skip creating spurious keys - # FIXME use fetch? - k = m.plugin.to_sym - if pl.has_key?(k) - p = pl[k][:botmodule] - a = pl[k][:auth] - else - p = nil - a = nil - end - if p - # We check here for things that don't check themselves - # (e.g. mapped things) - # debug "Checking auth ..." - if a.nil? || @bot.auth.allow?(a, m.source, m.replyto) - # debug "Checking response ..." - if p.respond_to?("privmsg") - begin - # debug "#{p.botmodule_class} #{p.name} responds" - p.privmsg(m) - rescue Exception => err - error report_error("#{p.botmodule_class} #{p.name} privmsg() failed:", err) - raise if err.class <= BDB::Fatal - end - # debug "Successfully delegated #{m.message}" - return true - else - # debug "#{p.botmodule_class} #{p.name} is registered, but it doesn't respond to privmsg()" + [core_commands, plugin_commands].each { |pl| + # We do it this way to skip creating spurious keys + # FIXME use fetch? + k = m.plugin.to_sym + if pl.has_key?(k) + p = pl[k][:botmodule] + a = pl[k][:auth] + else + p = nil + a = nil + end + if p + # We check here for things that don't check themselves + # (e.g. mapped things) + # debug "Checking auth ..." + if a.nil? || @bot.auth.allow?(a, m.source, m.replyto) + # debug "Checking response ..." + if p.respond_to?("privmsg") + begin + # debug "#{p.botmodule_class} #{p.name} responds" + p.privmsg(m) + rescue Exception => err + raise if err.class <= SystemExit + error report_error("#{p.botmodule_class} #{p.name} privmsg() failed:", err) + raise if err.class <= BDB::Fatal end + # debug "Successfully delegated #{m.message}" + return true else - # debug "#{p.botmodule_class} #{p.name} is registered, but #{m.source} isn't allowed to call #{m.plugin.inspect} on #{m.replyto}" + # debug "#{p.botmodule_class} #{p.name} is registered, but it doesn't respond to privmsg()" end else - # debug "No #{pl.values.first[:botmodule].botmodule_class} registered #{m.plugin.inspect}" unless pl.empty? + # debug "#{p.botmodule_class} #{p.name} is registered, but #{m.source} isn't allowed to call #{m.plugin.inspect} on #{m.replyto}" end - # debug "Finished delegating privmsg with key #{m.plugin.inspect}" + ( pl.empty? ? "" : " to #{pl.values.first[:botmodule].botmodule_class}s" ) - } - return false - rescue Exception => e - error report_error("couldn't delegate #{m.message.inspect}", e) - end + else + # debug "No #{pl.values.first[:botmodule].botmodule_class} registered #{m.plugin.inspect}" unless pl.empty? + end + # debug "Finished delegating privmsg with key #{m.plugin.inspect}" + ( pl.empty? ? "" : " to #{pl.values.first[:botmodule].botmodule_class}s" ) + } + return false # debug "Finished delegating privmsg with key #{m.plugin.inspect}" end end diff --git a/lib/rbot/registry.rb b/lib/rbot/registry.rb index d86850d4..e679722a 100644 --- a/lib/rbot/registry.rb +++ b/lib/rbot/registry.rb @@ -137,11 +137,13 @@ module Irc end def flush + # debug "fushing registry #{@registry}" @registry.flush @registry.sync end def close + # debug "closing registry #{@registry}" @registry.close end diff --git a/lib/rbot/rfc2812.rb b/lib/rbot/rfc2812.rb index e2438210..697c13e9 100644 --- a/lib/rbot/rfc2812.rb +++ b/lib/rbot/rfc2812.rb @@ -922,6 +922,7 @@ module Irc data[:nick] = $2 data[:address] = $3 @client = @server.user(data[:netmask]) + set = true when /Welcome to the Internet Relay Network\s(\S+)/ data[:nick] = $1 when /Welcome.*\s+(\S+)$/ @@ -929,7 +930,7 @@ module Irc when /^(\S+)$/ data[:nick] = $1 end - @user ||= @server.user(data[:nick]) + @client = @server.user(data[:nick]) unless set handle(:welcome, data) when RPL_YOURHOST # "Your host is , running version " @@ -1016,7 +1017,7 @@ module Irc users.each { |ar| u = @server.user(ar[0]) - chan.users << u + chan.users << u unless chan.users.include?(u) if ar[1] m = @server.supports[:prefix][:prefixes].index(ar[1].to_sym) m = @server.supports[:prefix][:modes][m] -- cgit v1.2.3