summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe Bilotta <giuseppe.bilotta@gmail.com>2006-08-03 14:06:15 +0000
committerGiuseppe Bilotta <giuseppe.bilotta@gmail.com>2006-08-03 14:06:15 +0000
commit6bf3094ac4ad043f00a3ef8cc2af48a8c23d114a (patch)
tree2729e8a8480a45b252f89b241250ef2b84dc3163
parent03bb46bbe744034141a3b612da4f0083719ff9a2 (diff)
Lots of fixes all around, in preparation for the new auth coremodule
-rw-r--r--lib/rbot/botuser.rb297
-rw-r--r--lib/rbot/core/config.rb8
-rw-r--r--lib/rbot/irc.rb22
-rw-r--r--lib/rbot/ircbot.rb73
-rw-r--r--lib/rbot/messagemapper.rb13
-rw-r--r--lib/rbot/plugins.rb80
-rw-r--r--lib/rbot/registry.rb2
-rw-r--r--lib/rbot/rfc2812.rb5
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]