X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=lib%2Frbot%2Fcore%2Fconfig.rb;h=43d08829884a5606c64206129f5b36494f7c6061;hb=7b35acadbd3726d46db8a691036217c336b11058;hp=dfbaaab66d05fb5da16c4ba3ac2d202aff60f59c;hpb=f1c6f0ba07e5abcd980f1e12e8823ce865bfeeed;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/lib/rbot/core/config.rb b/lib/rbot/core/config.rb index dfbaaab6..43d08829 100644 --- a/lib/rbot/core/config.rb +++ b/lib/rbot/core/config.rb @@ -1,256 +1,357 @@ -#-- vim:sw=2:et -#++ - - -class ConfigModule < CoreBotModule - - def save - @bot.config.save - end - - def handle_list(m, params) - modules = [] - if params[:module] - @bot.config.items.each_key do |key| - mod, name = key.to_s.split('.') - next unless mod == params[:module] - modules.push key unless modules.include?(name) - end - if modules.empty? - m.reply "no such module #{params[:module]}" - else - m.reply modules.join(", ") - end - else - @bot.config.items.each_key do |key| - name = key.to_s.split('.').first - modules.push name unless modules.include?(name) - end - m.reply "modules: " + modules.join(", ") - end - end - - def handle_get(m, params) - key = params[:key].to_s.intern - unless @bot.config.items.has_key?(key) - m.reply "no such config key #{key}" - return - end - value = @bot.config.items[key].to_s - m.reply "#{key}: #{value}" - end - - def handle_desc(m, params) - key = params[:key].to_s.intern - unless @bot.config.items.has_key?(key) - m.reply "no such config key #{key}" - end - puts @bot.config.items[key].inspect - m.reply "#{key}: #{@bot.config.items[key].desc}" - end - - def handle_unset(m, params) - key = params[:key].to_s.intern - unless @bot.config.items.has_key?(key) - m.reply "no such config key #{key}" - end - @bot.config.items[key].unset - handle_get(m, params) - m.reply "this config change will take effect on the next restart" if @bot.config.items[key].requires_restart - m.reply "this config change will take effect on the next rescan" if @bot.config.items[key].requires_rescan - end - - def handle_set(m, params) - key = params[:key].to_s.intern - value = params[:value].join(" ") - unless @bot.config.items.has_key?(key) - m.reply "no such config key #{key}" - return - end - begin - @bot.config.items[key].set_string(value) - rescue ArgumentError => e - m.reply "failed to set #{key}: #{e.message}" - return - end - if @bot.config.items[key].requires_restart - m.reply "this config change will take effect on the next restart" - elsif @bot.config.items[key].requires_rescan - m.reply "this config change will take effect on the next rescan" - else - m.okay - end - end - - def handle_add(m, params) - key = params[:key].to_s.intern - value = params[:value] - unless @bot.config.items.has_key?(key) - m.reply "no such config key #{key}" - return - end - unless @bot.config.items[key].kind_of?(BotConfigArrayValue) - m.reply "config key #{key} is not an array" - return - end - begin - @bot.config.items[key].add(value) - rescue ArgumentError => e - m.reply "failed to add #{value} to #{key}: #{e.message}" - return - end - handle_get(m,{:key => key}) - m.reply "this config change will take effect on the next restart" if @bot.config.items[key].requires_restart - m.reply "this config change will take effect on the next rescan" if @bot.config.items[key].requires_rescan - end - - def handle_rm(m, params) - key = params[:key].to_s.intern - value = params[:value] - unless @bot.config.items.has_key?(key) - m.reply "no such config key #{key}" - return - end - unless @bot.config.items[key].kind_of?(BotConfigArrayValue) - m.reply "config key #{key} is not an array" - return - end - begin - @bot.config.items[key].rm(value) - rescue ArgumentError => e - m.reply "failed to remove #{value} from #{key}: #{e.message}" - return - end - handle_get(m,{:key => key}) - m.reply "this config change will take effect on the next restart" if @bot.config.items[key].requires_restart - m.reply "this config change will take effect on the next rescan" if @bot.config.items[key].requires_rescan - end - - def bot_save(m, param) - @bot.save - m.okay - end - - def bot_rescan(m, param) - m.reply "saving ..." - @bot.save - m.reply "rescanning ..." - @bot.rescan - m.reply "done. #{@bot.plugins.status(true)}" - end - - def bot_nick(m, param) - @bot.nickchg(param[:nick]) - end - - def bot_status(m, param) - m.reply @bot.status - end - - # TODO is this one of the methods that disappeared when the bot was moved - # from the single-file to the multi-file registry? - # - # def bot_reg_stat(m, param) - # m.reply @registry.stat.inspect - # end - - def bot_version(m, param) - m.reply "I'm a v. #{$version} rubybot, (c) Tom Gilbert - http://linuxbrit.co.uk/rbot/" - end - - def handle_help(m, params) - m.reply help(params[:topic]) - end - - def help(plugin, topic="") - case topic - when "list" - "config list => list configuration modules, config list => list configuration keys for module " - when "get" - "config get => get configuration value for key " - when "unset" - "reset key to the default" - when "set" - "config set => set configuration value for key to " - when "desc" - "config desc => describe what key configures" - when "add" - "config add to => add value to key if is an array" - when "rm" - "config rm from => remove value from key if is an array" - else - "config module - bot configuration. usage: list, desc, get, set, unset, add, rm" - # else - # "no help for config #{topic}" - end - end - -end - -conf = ConfigModule.new - -conf.map 'config list :module', - :action => 'handle_list', - :defaults => {:module => false}, - :auth_path => 'show' -# TODO this one is presently a security risk, since the bot -# stores the master password in the config. Do we need auth levels -# on the BotConfig keys too? -conf.map 'config get :key', - :action => 'handle_get', - :auth_path => 'show' -conf.map 'config desc :key', - :action => 'handle_desc', - :auth_path => 'show' -conf.map 'config describe :key', - :action => 'handle_desc', - :auth_path => 'show' - -conf.map "save", - :action => 'bot_save' -conf.map "rescan", - :action => 'bot_rescan' -conf.map "nick :nick", - :action => 'bot_nick' -conf.map "status", - :action => 'bot_status', - :auth_path => 'show::status' -# TODO see above -# -# conf.map "registry stats", -# :action => 'bot_reg_stat', -# :auth_path => '!config::status' -conf.map "version", - :action => 'bot_version', - :auth_path => 'show::status' - -conf.map 'config set :key *value', - :action => 'handle_set', - :auth_path => 'edit' -conf.map 'config add :value to :key', - :action => 'handle_add', - :auth_path => 'edit' -conf.map 'config rm :value from :key', - :action => 'handle_rm', - :auth_path => 'edit' -conf.map 'config del :value from :key', - :action => 'handle_rm', - :auth_path => 'edit' -conf.map 'config delete :value from :key', - :action => 'handle_rm', - :auth_path => 'edit' -conf.map 'config unset :key', - :action => 'handle_unset', - :auth_path => 'edit' -conf.map 'config reset :key', - :action => 'handle_unset', - :auth_path => 'edit' - -conf.map 'config help :topic', - :action => 'handle_help', - :defaults => {:topic => false}, - :auth_path => '!help!' - -conf.default_auth('*', false) -conf.default_auth('show::status', true) - +#-- vim:sw=2:et +#++ +# +# :title: rbot config management from IRC +# +# Author:: Giuseppe "Oblomov" Bilotta + +class ConfigModule < CoreBotModule + + def version_string + if $version_timestamp.to_i > 0 + ago = _(" [%{secs} ago]") % { + :secs => Utils.secs_to_string(Time.now.to_i - $version_timestamp.to_i) + } + else + ago = '' + end + _("I'm a v. %{version}%{ago} rubybot%{copyright}%{url}") % { + :version => $version, + :ago => ago, + :copyright => ", #{Irc::Bot::COPYRIGHT_NOTICE}", + :url => " - #{Irc::Bot::SOURCE_URL}" + } + end + + def save + @bot.config.save + end + + def handle_list(m, params) + modules = [] + if params[:module] + @bot.config.items.each_key do |key| + mod, name = key.to_s.split('.') + next unless mod == params[:module] + modules.push key unless modules.include?(name) + end + if modules.empty? + m.reply _("no such module %{module}") % {:module => params[:module]} + else + m.reply modules.join(", ") + end + else + @bot.config.items.each_key do |key| + name = key.to_s.split('.').first + modules.push name unless modules.include?(name) + end + m.reply "modules: " + modules.join(", ") + end + end + + def handle_get(m, params) + key = params[:key].to_s.intern + unless @bot.config.items.has_key?(key) + m.reply _("no such config key %{key}") % {:key => key} + return + end + return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto) + value = @bot.config.items[key].to_s + m.reply "#{key}: #{value}" + end + + def handle_desc(m, params) + key = params[:key].to_s.intern + unless @bot.config.items.has_key?(key) + m.reply _("no such config key %{key}") % {:key => key} + end + m.reply "#{key}: #{@bot.config.items[key].desc}" + end + + def handle_search(m, params) + rx = Regexp.new(params[:rx].to_s, true) + cfs = [] + @bot.config.items.each do |k, v| + cfs << [Bold + k.to_s + Bold, v.desc] if k.to_s.match(rx) or (v.desc.match(rx) rescue false) + end + if cfs.empty? + m.reply _("no config key found matching %{r}") % { :r => params[:rx].to_s} + else + m.reply _("possible keys: %{kl}") % { :kl => cfs.map { |c| c.first}.sort.join(', ') } if cfs.length > 1 + m.reply cfs.map { |c| c.join(': ') }.join("\n") + end + end + + def handle_unset(m, params) + key = params[:key].to_s.intern + unless @bot.config.items.has_key?(key) + m.reply _("no such config key %{key}") % {:key => key} + end + return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto) + @bot.config.items[key].unset + handle_get(m, params) + m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart + m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan + end + + def handle_set(m, params) + key = params[:key].to_s.intern + value = params[:value].join(" ") + unless @bot.config.items.has_key?(key) + m.reply _("no such config key %{key}") % {:key => key} unless params[:silent] + return false + end + return false if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto) + begin + @bot.config.items[key].set_string(value) + rescue ArgumentError => e + m.reply _("failed to set %{key}: %{error}") % {:key => key, :error => e.message} unless params[:silent] + return false + end + if @bot.config.items[key].requires_restart + m.reply _("this config change will take effect on the next restart") unless params[:silent] + return :restart + elsif @bot.config.items[key].requires_rescan + m.reply _("this config change will take effect on the next rescan") unless params[:silent] + return :rescan + else + m.okay unless params[:silent] + return true + end + end + + def handle_add(m, params) + key = params[:key].to_s.intern + values = params[:value].to_s.split(/,\s+/) + unless @bot.config.items.has_key?(key) + m.reply _("no such config key %{key}") % {:key => key} + return + end + unless @bot.config.items[key].kind_of?(Config::ArrayValue) + m.reply _("config key %{key} is not an array") % {:key => key} + return + end + return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto) + values.each do |value| + begin + @bot.config.items[key].add(value) + rescue ArgumentError => e + m.reply _("failed to add %{value} to %{key}: %{error}") % {:value => value, :key => key, :error => e.message} + next + end + end + handle_get(m,{:key => key}) + m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart + m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan + end + + def handle_rm(m, params) + key = params[:key].to_s.intern + values = params[:value].to_s.split(/,\s+/) + unless @bot.config.items.has_key?(key) + m.reply _("no such config key %{key}") % {:key => key} + return + end + unless @bot.config.items[key].kind_of?(Config::ArrayValue) + m.reply _("config key %{key} is not an array") % {:key => key} + return + end + return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto) + values.each do |value| + begin + @bot.config.items[key].rm(value) + rescue ArgumentError => e + m.reply _("failed to remove %{value} from %{key}: %{error}") % {:value => value, :key => key, :error => e.message} + next + end + end + handle_get(m,{:key => key}) + m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart + m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan + end + + def bot_save(m, param) + @bot.save + m.okay + end + + def bot_rescan(m, param) + if param[:botmodule] + name = param[:botmodule] + if not @bot.plugins.has_key? name + m.reply _("botmodule not found") + return # error + else + botmodule = @bot.plugins[name] + m.reply _("botmodule %s... saving... rescanning...") % [name] + end + else + m.reply _("saving... rescanning...") + end + + @bot.rescan(botmodule) + m.reply _("done. %{plugin_status}") % { + :plugin_status => @bot.plugins.status(true)} + failure = @bot.plugins.botmodule_failure(name) if botmodule + if failure + m.reply _("plugin failed to load, %{failure}") % { + :failure => failure} + end + end + + def bot_nick(m, param) + @bot.nickchg(param[:nick]) + @bot.wanted_nick = param[:nick] + end + + def bot_status(m, param) + m.reply @bot.status + end + + # TODO is this one of the methods that disappeared when the bot was moved + # from the single-file to the multi-file registry? + # + # def bot_reg_stat(m, param) + # m.reply @registry.stat.inspect + # end + + def bot_version(m, param) + m.reply version_string + end + + def ctcp_listen(m) + who = m.private? ? "me" : m.target + case m.ctcp.intern + when :VERSION + m.ctcp_reply version_string + when :SOURCE + m.ctcp_reply Irc::Bot::SOURCE_URL + end + end + + def handle_help(m, params) + m.reply help(params[:topic]) + end + + def help(plugin, topic="") + case plugin + when "config" + case topic + when "list" + _("config list => list configuration modules, config list => list configuration keys for module ") + when "get" + _("config get => get configuration value for key ") + when "unset" + _("reset key to the default") + when "set" + _("config set => set configuration value for key to ") + when "desc" + _("config desc => describe what key configures") + when "add" + _("config add to => add values to key if is an array") + when "rm" + _("config rm from => remove value from key if is an array") + else + _("config module - bot configuration. usage: list, desc, get, set, unset, add, rm") + # else + # "no help for config #{topic}" + end + when "nick" + _("nick => change the bot nick to , if possible") + when "status" + _("status => display some information on the bot's status") + when "save" + _("save => save current dynamic data and configuration") + when "rescan" + _("rescan [] => reload specified or all botmodules and static facts") + when "reload" + _("reload [] => reload specified or all botmodules and static facts") + when "version" + _("version => describes software version") + else + _("config-related tasks: config, save, rescan(/reload), version, nick, status") + end + end + +end + +conf = ConfigModule.new + +conf.map 'config list :module', + :action => 'handle_list', + :defaults => {:module => false}, + :auth_path => 'show' +# TODO this one is presently a security risk, since the bot +# stores the master password in the config. Do we need auth levels +# on the Bot::Config keys too? +conf.map 'config get :key', + :action => 'handle_get', + :auth_path => 'show' +conf.map 'config desc :key', + :action => 'handle_desc', + :auth_path => 'show' +conf.map 'config describe :key', + :action => 'handle_desc', + :auth_path => 'show::desc!' +conf.map 'config search *rx', + :action => 'handle_search', + :auth_path => 'show' + +conf.map "save", + :action => 'bot_save' +conf.map "rescan [:botmodule]", + :action => 'bot_rescan' +conf.map "reload [:botmodule]", + :action => 'bot_rescan' +conf.map "nick :nick", + :action => 'bot_nick' +conf.map "status", + :action => 'bot_status', + :auth_path => 'show::status' +# TODO see above +# +# conf.map "registry stats", +# :action => 'bot_reg_stat', +# :auth_path => '!config::status' +conf.map "version", + :action => 'bot_version', + :auth_path => 'show::status' + +conf.map 'config set :key *value', + :action => 'handle_set', + :auth_path => 'edit' +conf.map 'config add *value to :key', + :action => 'handle_add', + :auth_path => 'edit' +conf.map 'config rm *value from :key', + :action => 'handle_rm', + :auth_path => 'edit' +conf.map 'config remove *value from :key', + :action => 'handle_rm', + :auth_path => 'edit' +conf.map 'config del *value from :key', + :action => 'handle_rm', + :auth_path => 'edit' +conf.map 'config delete *value from :key', + :action => 'handle_rm', + :auth_path => 'edit' +conf.map 'config unset :key', + :action => 'handle_unset', + :auth_path => 'edit' +conf.map 'config reset :key', + :action => 'handle_unset', + :auth_path => 'edit' + +conf.map 'config help :topic', + :action => 'handle_help', + :defaults => {:topic => false}, + :auth_path => '!help!' + +conf.default_auth('*', false) +conf.default_auth('show', true) +conf.default_auth('show::get', false) +# TODO these shouldn't be set here, we need a way to let the default +# permission be specified together with the ConfigValue +conf.default_auth('key', true) +conf.default_auth('key::auth::password', false) +