diff options
author | Giuseppe Bilotta <giuseppe.bilotta@gmail.com> | 2006-08-03 14:06:15 +0000 |
---|---|---|
committer | Giuseppe Bilotta <giuseppe.bilotta@gmail.com> | 2006-08-03 14:06:15 +0000 |
commit | 6bf3094ac4ad043f00a3ef8cc2af48a8c23d114a (patch) | |
tree | 2729e8a8480a45b252f89b241250ef2b84dc3163 /lib | |
parent | 03bb46bbe744034141a3b612da4f0083719ff9a2 (diff) |
Lots of fixes all around, in preparation for the new auth coremodule
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rbot/botuser.rb | 297 | ||||
-rw-r--r-- | lib/rbot/core/config.rb | 8 | ||||
-rw-r--r-- | lib/rbot/irc.rb | 22 | ||||
-rw-r--r-- | lib/rbot/ircbot.rb | 73 | ||||
-rw-r--r-- | lib/rbot/messagemapper.rb | 13 | ||||
-rw-r--r-- | lib/rbot/plugins.rb | 80 | ||||
-rw-r--r-- | lib/rbot/registry.rb | 2 | ||||
-rw-r--r-- | lib/rbot/rfc2812.rb | 5 |
8 files changed, 210 insertions, 290 deletions
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
-##
-#
-# <tango_> a. do we want user groups together with users?
-# <markey> hmm
-# <markey> let me think about it
-# <markey> generally I would say: as simple as possible while keeping it as flexible as need be
-# <tango_> I think we can put user groups in place afterwards if we build the structure right
-# <markey> prolly, yes
-# <tango_> so
-# <tango_> each plugin registers a name
-# <tango_> so rather than auth level we have +name -name
-# <markey> yes
-# <markey> much better
-# <tango_> the default is +name for every plugin, except when the plugin tells otherwise
-# <markey> although..
-# <markey> if I only want to allow you access to one plugin
-# <markey> I have lots of typing to do
-# <tango_> nope
-# <tango_> we allow things like -*
-# <markey> ok
-# <tango_> and + has precedence
-# <tango_> hm no, not good either
-# <tango_> because we want bot -* +onething and +* -onething to work
-# <markey> but then: one plugin currently can have several levels, no?
-# <tango_> of course
-# <markey> commandedit, commanddel, commandfoo
-# <tango_> name.command ?
-# <markey> yep
-# <tango_> (then you can't have dots in commands
-# <tango_> maybe name:command
-# <markey> or name::comand
-# <markey> like a namespace
-# <tango_> ehehehe yeah I like it :)
-# <tango_> tel
-# <tango_> brb
-# <markey> usermod setcaps eean -*
-# <markey> usermod setcaps eean +quiz::edit
-# <markey> great
-# <markey> or even
-# <markey> auth eean -*, +quiz::edit
-# <markey> awesome
-# <markey> auth eean -*, +quiz::edit, +command, -command::del
-# <tango_> yes
-# <markey> you know, the default should be -*
-# <markey> because
-# <markey> in the time between adding the user and changing auth
-# <markey> it's insecure
-# <markey> user could do havoc
-# <markey> useradd eean, then eean does "~quit", before I change auth
-# <tango_> nope
-# <markey> perhaps we should allow combining useradd with auth
-# <tango_> the default should be +* -important stuff
-# <markey> ok
-# <tango_> how to specify channel stuff?
-# <markey> for one, when you issue the command on the channel itself
-# <markey> then it's channel relative
-# <markey> perhaps
-# <markey> or
-# <tango_> yes but I was thinking more about the syntax
-# <markey> auth eean #rbot -quiz
-# <tango_> hm
-# <markey> or maybe: treat channels like users: auth #rbot -quiz
-# <markey> would shut up quiz in #rbot
-# <markey> hm
-# <markey> heh
-# <tango_> auth * #rbot -quiz
-# <markey> not sure I'm making sense here ;)
-# <tango_> I think syntax should be auth [usermask] [channelmask] [modes]
-# <markey> yes
-# <markey> modes separated by comma?
-# <tango_> where channelmask is implied to be *
-# <tango_> no we can have it spacesplit
-# <markey> great
-# <markey> ok
-# <tango_> modes are detected by +-
-# <tango_> so you can do something like auth markey #rbot -quiz #amarok -chuck
-# <markey> also I like "auth" a lot more than "usermod foo"
-# <markey> yep
-# <tango_> I don't understand why the 'mod'
-# <tango_> we could have all auth commands start with use
-# <tango_> user
-# <tango_> user add
-# <tango_> user list
-# <tango_> user del
-# <markey> yes
-# <tango_> user auth
-# <tango_> hm
-# <tango_> and maybe auth as a synonym for user auth
-# <markey> this is also uncomfortable: usermod wants the full user mask
-# <markey> you have to copy/paste it
-# <tango_> no
-# <tango_> can't you use *?
-# <markey> sorry not sure
-# <markey> but this shows, it's not inuitive
-# <markey> I've read the docs
-# <markey> but didn't know how to use it really
-# <tango_> markey!*@*
-# <markey> that's not very intuitive
-# <tango_> we could use nick as a synonym for nick!*@* if it's too much for you :D
-# <markey> usermod markey foo should suffice
-# <markey> rememember: you're a hacker. when rbot gets many new users, they will often be noobs
-# <markey> gotta make things simple to use
-# <tango_> but the hostmask is only needed for the user creation
-# <markey> really? then forget what I said, sorry
-# <tango_> I think so
-# <tango_> ,help auth
-# <testbot> Auth module (User authentication) topics: setlevel, useradd, userdel, usermod, auth, levels, users, whoami, identify
-# <tango_> ,help usermod
-# <testbot> no help for topic usermod
-# <tango_> ,help auth usermod
-# <testbot> usermod <username> <item> <value> => Modify <username>s settings. Valid <item>s are: hostmask, (+|-)hostmask, password, level (private addressing only)
-# <tango_> see? it's username, not nick :D
-# <markey> btw, help usermod should also work
-# <tango_> ,help auth useradd
-# <testbot> useradd <username> => Add user <mask>, you still need to set him up correctly (private addressing only)
-# <markey> instead of help auth usermode
-# <markey> when it's not ambiguous
-# <tango_> and the help for useradd is wrong
-# <markey> for the website, we could make a logo contest :) the current logo looks like giblet made it in 5 minutes ;)
-# <markey> ah well, for 1.0 maybe
-# <tango_> so a user on rbot is given by
-# <tango_> username, password, hostmasks, permissions
-# <markey> yup
-# <tango_> the default permission is +* -importantstuff
-# <markey> how defines importantstuff?
-# <markey> you mean like core and auth?
-# <tango_> yes
-# <markey> ok
-# <tango_> but we can decide about this :)
-# <markey> some plugins are dangerous by default
-# <markey> like command plugin
-# <markey> you can do all sorts of nasty shit with it
-# <tango_> then command plugin will do something like: command.defaultperm("-command")
-# <markey> yes, good point
-# <tango_> this is then added to the default permissions (user * channel *)
-# <tango_> when checking for auth, we go like this:
-# <tango_> hm
-# <tango_> check user * channel *
-# <tango_> then user name channel *
-# <tango_> then user * channel name
-# <tango_> then user name channel name
-# <tango_> for each of these combinations we match against * first, then against command, and then against command::subcommand
-# <markey> yup
-# <tango_> setting or resetting it depending on wether it's + or -
-# <tango_> the final result gives us the permission
-# <tango_> implementation detail
-# <tango_> username and passwords are strings
-# <markey> (I might rename the command plugin, the name is somewhat confusing)
-# <tango_> yeah
-# <tango_> hostmasks are hostmasks
-# <markey> also I'm pondering to restrict it more: disallow access to @bot
-# <tango_> 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 <code>User</code>s.
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 <servername>, running version <ver>" @@ -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] |